summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt3
-rw-r--r--scalatexApi/src/test/scala/scalatex/AdvancedTests.scala240
-rw-r--r--scalatexApi/src/test/scala/scalatex/BasicTests.scala850
-rw-r--r--scalatexApi/src/test/scala/scalatex/ErrorTests.scala714
-rw-r--r--scalatexApi/src/test/scala/scalatex/Main.scala88
-rw-r--r--scalatexApi/src/test/scala/scalatex/ParserTests.scala50
-rw-r--r--scalatexApi/src/test/scala/torimatomeru/ScalaSyntax.scala246
7 files changed, 1238 insertions, 953 deletions
diff --git a/build.sbt b/build.sbt
index 5aacd9a..a6d87ed 100644
--- a/build.sbt
+++ b/build.sbt
@@ -8,7 +8,8 @@ lazy val scalatexApi = project.in(file("scalatexApi"))
"com.lihaoyi" %% "utest" % "0.2.4",
"com.scalatags" %% "scalatags" % "0.4.2",
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
- "com.lihaoyi" %% "acyclic" % "0.1.2" % "provided"
+ "com.lihaoyi" %% "acyclic" % "0.1.2" % "provided",
+ "org.parboiled" %% "parboiled" % "2.0.1"
),
addCompilerPlugin("com.lihaoyi" %% "acyclic" % "0.1.2"),
testFrameworks += new TestFramework("utest.runner.JvmFramework")
diff --git a/scalatexApi/src/test/scala/scalatex/AdvancedTests.scala b/scalatexApi/src/test/scala/scalatex/AdvancedTests.scala
index 4315735..cbca40a 100644
--- a/scalatexApi/src/test/scala/scalatex/AdvancedTests.scala
+++ b/scalatexApi/src/test/scala/scalatex/AdvancedTests.scala
@@ -1,120 +1,120 @@
-package scalatex
-
-import utest._
-import scalatex.stages._
-import scalatags.Text.all._
-
-
-/**
-* Created by haoyi on 7/14/14.
-*/
-object AdvancedTests extends TestSuite{
- import TestUtil._
-
- val tests = TestSuite{
- 'localDef{
- check(
- tw("""
- @lol(n: Int) = @{
- "omg" * n
- }
-
- @lol(2)
- """),
- "omgomg"
- )
- }
- 'innerTemplate{
- check(
- tw("""
- @lol(f: Int) =
- omg @f
-
- @lol(1)
- @lol(2: Int)
- @lol(3 + 1)
- """),
- tw("""
- @lol(f: Int) ={
- omg @f
- }
- @lol(1)
- @lol(2: Int)
- @lol(3 + 1)
- """),
- tw("""
- @lol(f: Int) = {
- omg @f
- }
- @lol(1)
- @lol(2: Int)
- @lol(3 + 1)
- """),
- """
- omg1omg2omg4
- """
- )
- }
- 'innerInnerTemplate{
- check(
- tw("""
- @lol(f: Int) =
- @wtf(g: Int) =
- wtf @g
-
- @wtf(1 + 2 + 3)
- @wtf(f)
-
- @lol(1)
- @lol(2: Int)
- @lol(3 + 1)
- """),
- tw("""
- @lol(f: Int) = {
- @wtf(g: Int) = {
- wtf @g
- }
- @wtf(1 + 2 + 3)
- @wtf(f)
- }
- @lol(1)
- @lol(2: Int)
- @lol(3 + 1)
- """),
- tw("""
- @lol(f: Int) = {
- @wtf(g: Int) =
- wtf @g
-
- @wtf(1 + 2 + 3)
- @wtf(f)
- }
- @lol(1)
- @lol(2: Int)
- @lol(3 + 1)
- """),
- tw("""
- @lol(f: Int) =
- @wtf(g: Int) = {
- wtf @g
- }
- @wtf(1 + 2 + 3)
- @wtf(f)
-
- @lol(1)
- @lol(2: Int)
- @lol(3 + 1)
- """),
- """
- wtf6
- wtf1
- wtf6
- wtf2
- wtf6
- wtf4
- """
- )
- }
-
- }
-}
+//package scalatex
+//
+//import utest._
+//import scalatex.stages._
+//import scalatags.Text.all._
+//
+//
+///**
+//* Created by haoyi on 7/14/14.
+//*/
+//object AdvancedTests extends TestSuite{
+// import TestUtil._
+//
+// val tests = TestSuite{
+// 'localDef{
+// check(
+// tw("""
+// @lol(n: Int) = @{
+// "omg" * n
+// }
+//
+// @lol(2)
+// """),
+// "omgomg"
+// )
+// }
+// 'innerTemplate{
+// check(
+// tw("""
+// @lol(f: Int) =
+// omg @f
+//
+// @lol(1)
+// @lol(2: Int)
+// @lol(3 + 1)
+// """),
+// tw("""
+// @lol(f: Int) ={
+// omg @f
+// }
+// @lol(1)
+// @lol(2: Int)
+// @lol(3 + 1)
+// """),
+// tw("""
+// @lol(f: Int) = {
+// omg @f
+// }
+// @lol(1)
+// @lol(2: Int)
+// @lol(3 + 1)
+// """),
+// """
+// omg1omg2omg4
+// """
+// )
+// }
+// 'innerInnerTemplate{
+// check(
+// tw("""
+// @lol(f: Int) =
+// @wtf(g: Int) =
+// wtf @g
+//
+// @wtf(1 + 2 + 3)
+// @wtf(f)
+//
+// @lol(1)
+// @lol(2: Int)
+// @lol(3 + 1)
+// """),
+// tw("""
+// @lol(f: Int) = {
+// @wtf(g: Int) = {
+// wtf @g
+// }
+// @wtf(1 + 2 + 3)
+// @wtf(f)
+// }
+// @lol(1)
+// @lol(2: Int)
+// @lol(3 + 1)
+// """),
+// tw("""
+// @lol(f: Int) = {
+// @wtf(g: Int) =
+// wtf @g
+//
+// @wtf(1 + 2 + 3)
+// @wtf(f)
+// }
+// @lol(1)
+// @lol(2: Int)
+// @lol(3 + 1)
+// """),
+// tw("""
+// @lol(f: Int) =
+// @wtf(g: Int) = {
+// wtf @g
+// }
+// @wtf(1 + 2 + 3)
+// @wtf(f)
+//
+// @lol(1)
+// @lol(2: Int)
+// @lol(3 + 1)
+// """),
+// """
+// wtf6
+// wtf1
+// wtf6
+// wtf2
+// wtf6
+// wtf4
+// """
+// )
+// }
+//
+// }
+//}
diff --git a/scalatexApi/src/test/scala/scalatex/BasicTests.scala b/scalatexApi/src/test/scala/scalatex/BasicTests.scala
index 617841e..2ecf9c4 100644
--- a/scalatexApi/src/test/scala/scalatex/BasicTests.scala
+++ b/scalatexApi/src/test/scala/scalatex/BasicTests.scala
@@ -1,425 +1,425 @@
-package scalatex
-import utest._
-import scalatex.stages._
-import scalatags.Text.all._
-
-
-/**
-* Created by haoyi on 7/14/14.
-*/
-object BasicTests extends TestSuite{
- import TestUtil._
-
- val tests = TestSuite{
-
- 'helloWorld{
- object omg {
- def wtf(s: Frag*): Frag = Seq[Frag]("|", s, "|")
- }
- def str = "hear me moo"
- check(
- tw("""
- @omg.wtf
- i @b{am} cow @str
- """),
- "|i<b>am</b>cowhearmemoo|"
- )
- }
- 'interpolation{
- 'chained-check(
- tw("omg @scala.math.pow(0.5, 3) wtf"),
- "omg 0.125 wtf"
- )
- 'parens-check(
- tw("omg @(1 + 2 + 3 + 4) wtf"),
- "omg 10 wtf"
- )
- 'block-check(
- tw("""
- @{"lol" * 3}
- @{
- val omg = "omg"
- omg * 2
- }
- """),
- """
- lollollol
- omgomg
- """
- )
- }
- 'imports{
- object Whee{
- def func(x: Int) = x * 2
- }
- check(
- tw("""
- @import math._
- @import Whee.func
- @abs(-10)
- @p
- @max(1, 2)
- @func(2)
- """),
- """
- 10
- <p>
- 2
- 4
- </p>
- """
- )
- }
- 'parenArgumentLists{
- 'attributes{
- check(
- tw("""
- @div(id:="my-id"){ omg }
- @div(id:="my-id")
- omg
- """),
- """
- <divid="my-id">omg</div>
- <divid="my-id">omg</div>
- """
- )
- }
- 'multiline{
-
- check(
- tw("""
- @div(
- h1("Hello World"),
- p("I am a ", b{"cow"})
- )
- """),
- """
- <div>
- <h1>Hello World</h1>
- <p>I am a <b>cow</b></p>
- </div>
- """
- )
- }
- }
- 'grouping{
- 'negative{
- // The indentation for "normal" text is ignored; we only
- // create blocks from the indentation following a scala
- // @xxx expression
- check(
- tw("""
- I am cow hear me moo
- I weigh twice as much as you
- And I look good on the barbecue
- Yoghurt curds cream cheese and butter
- Comes from liquids from my udder
- I am cow I am cow hear me moooooo
- """),
- """
- I am cow hear me moo
- I weigh twice as much as you
- And I look good on the barbecue
- Yoghurt curds cream cheese and butter
- Comes from liquids from my udder
- I am cow I am cow hear me moooooo
- """
- )
- }
- 'indentation{
- 'simple{
- val world = "World2"
-
- check(
- tw("""
- @h1
- Hello World
- @h2
- hello @world
- @h3
- Cow
- """),
- """
- <h1>HelloWorld</h1>
- <h2>helloWorld2</h2>
- <h3>Cow</h3>
- """
- )
- }
- 'linearNested{
- check(
- tw("""
- @h1 @span @a Hello World
- @h2 @span @a hello
- @b world
- @h3 @i
- @div Cow
- """),
- """
- <h1></h1><span></span><a></a>HelloWorld
- <h2></h2><span></span><a></a>hello<b></b>world
- <h3></h3><i></i><div></div>Cow
- """
- )
- }
- 'crasher{
- tw("""
-@html
- @head
- @meta
- @div
- @a
- @span
- """)
- }
- }
- 'curlies{
- 'simple{
- val world = "World2"
-
- check(
- tw("""@div{Hello World}"""),
- """<div>HelloWorld</div>"""
- )
- }
- 'multiline{
- check(
- tw("""
- @div{
- Hello
- }
- """),
- """
- <div>Hello</div>
- """
- )
- }
- }
- 'mixed{
- check(
- tw("""
- @div{
- Hello
- @div
- @h1 WORLD @b{!!!}
- lol
- @p{
- @h2{Header 2}
- }
- }
- """),
- """
- <div>
- Hello
- <div>
- <h1></h1>WORLD<b>!!!</b>lol
- <p><h2>Header2</h2></p>
- </div>
- </div>
- """
- )
- }
-
- 'args{
- val things = Seq(1, 2, 3)
- check(
- tw("""
- @ul
- @things.map { x =>
- @li
- @x
- }
- """),
- tw("""
- @ul
- @things.map x =>
- @li
- @x
-
- """),
- """
- <ul>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- </ul>
- """
- )
- }
- }
-
- 'loops {
-
- * - check(
- tw("""
- @for(x <- 0 until 3)
- lol
- """),
- tw("""
- @for(x <- 0 until 3){
- lol
- }
- """),
- tw(
- """
- @for(x <- 0 until 3) {
- lol
- }
- """),
- "lollollol"
- )
-
-
- * - check(
- tw("""
- @p
- @for(x <- 0 until 2)
- @for(y <- 0 until 2)
- lol@x@y
- """),
- tw( """
- @p
- @for(x <- 0 until 2) {
- @for(y <- 0 until 2)
- lol@x@y
- }
- """),
- tw("""
- @p
- @for(x <- 0 until 2)
- @for(y <- 0 until 2){
- lol@x@y
- }
- """),
- "<p>lol00lol01lol10lol11</p>"
- )
- check(
- tw("""
- @p
- @for(x <- 0 until 2)
- @for(y <- 0 until 2)
- lol@x@y
- """),
- "<p>lol00lol01lol10lol11</p>"
- )
-
- * - check(
- tw(
- """
- @for(x <- 0 until 2; y <- 0 until 2)
- @div{@x@y}
-
- """),
- """<div>00</div><div>01</div><div>10</div><div>11</div>"""
- )
- }
-
- 'ifElse{
- 'basicExamples{
- * - check(
- tw("""
- @if(false)
- Hello
- @else
- lols
- @p
- """),
- "lols<p></p>"
- )
-
- * - check(
- tw("""
- @div
- @if(true)
- Hello
- @else
- lols
- """),
- "<div>Hello</div>"
- )
-
- * - check(
- tw("""
- @div
- @if(true)
- Hello
- @else
- lols
- """),
- "<div>Hello</div>"
- )
- * - check(
- tw("""
- @if(false)
- Hello
- @else
- lols
- """),
- "lols"
- )
- * - check(
- tw("""
- @if(false)
- Hello
- @else
- lols
- @img
- """),
- "lols<img/>"
- )
- * - check(
- tw("""
- @p
- @if(true)
- Hello
- @else
- lols
- """),
- tw("""
- @p
- @if(true) {
- Hello
- } else {
- lols
- }
- """),
- "<p>Hello</p>"
- )
- }
- 'funkyExpressions{
- * - check(
- tw("""
- @p
- @if(true == false == (true.==(false)))
- @if(true == false == (true.==(false)))
- Hello1
- @else
- lols1
- @else
- @if(true == false == (true.==(false)))
- Hello2
- @else
- lols2
- """),
- "<p>Hello1</p>"
- )
- * - check(
- tw("""
- @p
- @if(true == false != (true.==(false)))
- @if(true == false != (true.==(false)))
- Hello1
- @else
- lols1
- @else
- @if(true == false != (true.==(false)))
- Hello2
- @else
- lols2
- """),
- "<p>lols2</p>"
- )
- }
- }
- }
-}
+//package scalatex
+//import utest._
+//import scalatex.stages._
+//import scalatags.Text.all._
+//
+//
+///**
+//* Created by haoyi on 7/14/14.
+//*/
+//object BasicTests extends TestSuite{
+// import TestUtil._
+//
+// val tests = TestSuite{
+//
+// 'helloWorld{
+// object omg {
+// def wtf(s: Frag*): Frag = Seq[Frag]("|", s, "|")
+// }
+// def str = "hear me moo"
+// check(
+// tw("""
+// @omg.wtf
+// i @b{am} cow @str
+// """),
+// "|i<b>am</b>cowhearmemoo|"
+// )
+// }
+// 'interpolation{
+// 'chained-check(
+// tw("omg @scala.math.pow(0.5, 3) wtf"),
+// "omg 0.125 wtf"
+// )
+// 'parens-check(
+// tw("omg @(1 + 2 + 3 + 4) wtf"),
+// "omg 10 wtf"
+// )
+// 'block-check(
+// tw("""
+// @{"lol" * 3}
+// @{
+// val omg = "omg"
+// omg * 2
+// }
+// """),
+// """
+// lollollol
+// omgomg
+// """
+// )
+// }
+// 'imports{
+// object Whee{
+// def func(x: Int) = x * 2
+// }
+// check(
+// tw("""
+// @import math._
+// @import Whee.func
+// @abs(-10)
+// @p
+// @max(1, 2)
+// @func(2)
+// """),
+// """
+// 10
+// <p>
+// 2
+// 4
+// </p>
+// """
+// )
+// }
+// 'parenArgumentLists{
+// 'attributes{
+// check(
+// tw("""
+// @div(id:="my-id"){ omg }
+// @div(id:="my-id")
+// omg
+// """),
+// """
+// <divid="my-id">omg</div>
+// <divid="my-id">omg</div>
+// """
+// )
+// }
+// 'multiline{
+//
+// check(
+// tw("""
+// @div(
+// h1("Hello World"),
+// p("I am a ", b{"cow"})
+// )
+// """),
+// """
+// <div>
+// <h1>Hello World</h1>
+// <p>I am a <b>cow</b></p>
+// </div>
+// """
+// )
+// }
+// }
+// 'grouping{
+// 'negative{
+// // The indentation for "normal" text is ignored; we only
+// // create blocks from the indentation following a scala
+// // @xxx expression
+// check(
+// tw("""
+// I am cow hear me moo
+// I weigh twice as much as you
+// And I look good on the barbecue
+// Yoghurt curds cream cheese and butter
+// Comes from liquids from my udder
+// I am cow I am cow hear me moooooo
+// """),
+// """
+// I am cow hear me moo
+// I weigh twice as much as you
+// And I look good on the barbecue
+// Yoghurt curds cream cheese and butter
+// Comes from liquids from my udder
+// I am cow I am cow hear me moooooo
+// """
+// )
+// }
+// 'indentation{
+// 'simple{
+// val world = "World2"
+//
+// check(
+// tw("""
+// @h1
+// Hello World
+// @h2
+// hello @world
+// @h3
+// Cow
+// """),
+// """
+// <h1>HelloWorld</h1>
+// <h2>helloWorld2</h2>
+// <h3>Cow</h3>
+// """
+// )
+// }
+// 'linearNested{
+// check(
+// tw("""
+// @h1 @span @a Hello World
+// @h2 @span @a hello
+// @b world
+// @h3 @i
+// @div Cow
+// """),
+// """
+// <h1></h1><span></span><a></a>HelloWorld
+// <h2></h2><span></span><a></a>hello<b></b>world
+// <h3></h3><i></i><div></div>Cow
+// """
+// )
+// }
+// 'crasher{
+// tw("""
+//@html
+// @head
+// @meta
+// @div
+// @a
+// @span
+// """)
+// }
+// }
+// 'curlies{
+// 'simple{
+// val world = "World2"
+//
+// check(
+// tw("""@div{Hello World}"""),
+// """<div>HelloWorld</div>"""
+// )
+// }
+// 'multiline{
+// check(
+// tw("""
+// @div{
+// Hello
+// }
+// """),
+// """
+// <div>Hello</div>
+// """
+// )
+// }
+// }
+// 'mixed{
+// check(
+// tw("""
+// @div{
+// Hello
+// @div
+// @h1 WORLD @b{!!!}
+// lol
+// @p{
+// @h2{Header 2}
+// }
+// }
+// """),
+// """
+// <div>
+// Hello
+// <div>
+// <h1></h1>WORLD<b>!!!</b>lol
+// <p><h2>Header2</h2></p>
+// </div>
+// </div>
+// """
+// )
+// }
+//
+// 'args{
+// val things = Seq(1, 2, 3)
+// check(
+// tw("""
+// @ul
+// @things.map { x =>
+// @li
+// @x
+// }
+// """),
+// tw("""
+// @ul
+// @things.map x =>
+// @li
+// @x
+//
+// """),
+// """
+// <ul>
+// <li>1</li>
+// <li>2</li>
+// <li>3</li>
+// </ul>
+// """
+// )
+// }
+// }
+//
+// 'loops {
+//
+// * - check(
+// tw("""
+// @for(x <- 0 until 3)
+// lol
+// """),
+// tw("""
+// @for(x <- 0 until 3){
+// lol
+// }
+// """),
+// tw(
+// """
+// @for(x <- 0 until 3) {
+// lol
+// }
+// """),
+// "lollollol"
+// )
+//
+//
+// * - check(
+// tw("""
+// @p
+// @for(x <- 0 until 2)
+// @for(y <- 0 until 2)
+// lol@x@y
+// """),
+// tw( """
+// @p
+// @for(x <- 0 until 2) {
+// @for(y <- 0 until 2)
+// lol@x@y
+// }
+// """),
+// tw("""
+// @p
+// @for(x <- 0 until 2)
+// @for(y <- 0 until 2){
+// lol@x@y
+// }
+// """),
+// "<p>lol00lol01lol10lol11</p>"
+// )
+// check(
+// tw("""
+// @p
+// @for(x <- 0 until 2)
+// @for(y <- 0 until 2)
+// lol@x@y
+// """),
+// "<p>lol00lol01lol10lol11</p>"
+// )
+//
+// * - check(
+// tw(
+// """
+// @for(x <- 0 until 2; y <- 0 until 2)
+// @div{@x@y}
+//
+// """),
+// """<div>00</div><div>01</div><div>10</div><div>11</div>"""
+// )
+// }
+//
+// 'ifElse{
+// 'basicExamples{
+// * - check(
+// tw("""
+// @if(false)
+// Hello
+// @else
+// lols
+// @p
+// """),
+// "lols<p></p>"
+// )
+//
+// * - check(
+// tw("""
+// @div
+// @if(true)
+// Hello
+// @else
+// lols
+// """),
+// "<div>Hello</div>"
+// )
+//
+// * - check(
+// tw("""
+// @div
+// @if(true)
+// Hello
+// @else
+// lols
+// """),
+// "<div>Hello</div>"
+// )
+// * - check(
+// tw("""
+// @if(false)
+// Hello
+// @else
+// lols
+// """),
+// "lols"
+// )
+// * - check(
+// tw("""
+// @if(false)
+// Hello
+// @else
+// lols
+// @img
+// """),
+// "lols<img/>"
+// )
+// * - check(
+// tw("""
+// @p
+// @if(true)
+// Hello
+// @else
+// lols
+// """),
+// tw("""
+// @p
+// @if(true) {
+// Hello
+// } else {
+// lols
+// }
+// """),
+// "<p>Hello</p>"
+// )
+// }
+// 'funkyExpressions{
+// * - check(
+// tw("""
+// @p
+// @if(true == false == (true.==(false)))
+// @if(true == false == (true.==(false)))
+// Hello1
+// @else
+// lols1
+// @else
+// @if(true == false == (true.==(false)))
+// Hello2
+// @else
+// lols2
+// """),
+// "<p>Hello1</p>"
+// )
+// * - check(
+// tw("""
+// @p
+// @if(true == false != (true.==(false)))
+// @if(true == false != (true.==(false)))
+// Hello1
+// @else
+// lols1
+// @else
+// @if(true == false != (true.==(false)))
+// Hello2
+// @else
+// lols2
+// """),
+// "<p>lols2</p>"
+// )
+// }
+// }
+// }
+//}
diff --git a/scalatexApi/src/test/scala/scalatex/ErrorTests.scala b/scalatexApi/src/test/scala/scalatex/ErrorTests.scala
index 480d849..4a2b5c8 100644
--- a/scalatexApi/src/test/scala/scalatex/ErrorTests.scala
+++ b/scalatexApi/src/test/scala/scalatex/ErrorTests.scala
@@ -1,357 +1,357 @@
-package scalatex
-
-import utest._
-import scalatex.stages._
-import scalatags.Text.all._
-import scalatex.Internals.{DebugFailure, twRuntimeErrors}
-
-/**
-* Created by haoyi on 7/14/14.
-*/
-object ErrorTests extends TestSuite{
- def check(x: => Unit, expectedMsg: String, expectedError: String) = {
- val DebugFailure(msg, pos) = intercept[DebugFailure](x)
- def format(str: String) = {
- val whitespace = " \t\n".toSet
- "\n" + str.dropWhile(_ == '\n')
- .reverse
- .dropWhile(whitespace.contains)
- .reverse
- }
- // Format these guys nicely to normalize them and make them
- // display nicely in the assert error message if it blows up
- val formattedPos = format(pos)
- val formattedExpectedPos = format(expectedError)
-
- assert(msg.contains(expectedMsg))
- assert(formattedPos == formattedExpectedPos)
-
- }
- val tests = TestSuite{
-
-
- 'simple - check(
- twRuntimeErrors("omg @notInScope lol"),
- """not found: value notInScope""",
- """
- twRuntimeErrors("omg @notInScope lol"),
- ^
- """
- )
-
- 'chained{
- 'properties {
- * - check(
- twRuntimeErrors("omg @math.lol lol"),
- """object lol is not a member of package math""",
- """
- twRuntimeErrors("omg @math.lol lol"),
- ^
- """
- )
-
- * - check(
- twRuntimeErrors("omg @math.E.lol lol"),
- """value lol is not a member of Double""",
- """
- twRuntimeErrors("omg @math.E.lol lol"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("omg @_root_.scala.math.lol lol"),
- """object lol is not a member of package math""",
- """
- twRuntimeErrors("omg @_root_.scala.math.lol lol"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("omg @_root_.scala.gg.lol lol"),
- """object gg is not a member of package scala""",
- """
- twRuntimeErrors("omg @_root_.scala.gg.lol lol"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("omg @_root_.ggnore.math.lol lol"),
- """object ggnore is not a member of package <root>""",
- """
- twRuntimeErrors("omg @_root_.ggnore.math.lol lol"),
- ^
- """
- )
- }
- 'calls{
- * - check(
- twRuntimeErrors("@scala.QQ.abs(-10).tdo(10).sum.z"),
- """object QQ is not a member of package scala""",
- """
- twRuntimeErrors("@scala.QQ.abs(-10).tdo(10).sum.z"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("@scala.math.abs(-10).tdo(10).sum.z"),
- "value tdo is not a member of Int",
- """
- twRuntimeErrors("@scala.math.abs(-10).tdo(10).sum.z"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("@scala.math.abs(-10).to(10).sum.z"),
- "value z is not a member of Int",
- """
- twRuntimeErrors("@scala.math.abs(-10).to(10).sum.z"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("@scala.math.abs(-10).to(10).sum.z()"),
- "value z is not a member of Int",
- """
- twRuntimeErrors("@scala.math.abs(-10).to(10).sum.z()"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("@scala.math.abs(-10).cow.sum.z"),
- "value cow is not a member of Int",
- """
- twRuntimeErrors("@scala.math.abs(-10).cow.sum.z"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("@scala.smath.abs.cow.sum.z"),
- "object smath is not a member of package scala",
- """
- twRuntimeErrors("@scala.smath.abs.cow.sum.z"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("""
- I am cow hear me moo
- @scala.math.abs(-10).tdo(10).sum.z
- I weigh twice as much as you
- """),
- "value tdo is not a member of Int",
- """
- @scala.math.abs(-10).tdo(10).sum.z
- ^
- """
- )
- }
- 'curlies{
- * - check(
- twRuntimeErrors("@p{@Seq(1, 2, 3).foldLeft(0)}"),
- "missing arguments for method foldLeft",
- """
- twRuntimeErrors("@p{@Seq(1, 2, 3).foldLeft(0)}"),
- ^
- """
- )
-
- * - check(
- twRuntimeErrors("@Nil.foldLeft{XY}"),
- "missing arguments for method foldLeft",
- """
- twRuntimeErrors("@Nil.foldLeft{XY}"),
- ^
- """
- )
-
- * - check(
- twRuntimeErrors("@Nil.map{(x: Int, y: String) => omg}"),
- "type mismatch",
- """
- twRuntimeErrors("@Nil.map{(x: Int, y: String) => omg}"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("@Nil.map{ omg}"),
- "too many arguments for method map",
- """
- twRuntimeErrors("@Nil.map{ omg}"),
- ^
- """
- )
- }
- 'callContents{
- * - check(
- twRuntimeErrors("@scala.math.abs((1, 2).wtf)"),
- "value wtf is not a member of (Int, Int)",
- """
- twRuntimeErrors("@scala.math.abs((1, 2).wtf)"),
- ^
- """
- )
-
- * - check(
- twRuntimeErrors("@scala.math.abs((1, 2).swap._1.toString().map(_.toString.wtf))"),
- "value wtf is not a member of String",
- """
- twRuntimeErrors("@scala.math.abs((1, 2).swap._1.toString().map(_.toString.wtf))"),
- ^
- """
- )
- }
- }
- 'ifElse{
- 'oneLine {
- * - check(
- twRuntimeErrors("@if(math > 10){ 1 }else{ 2 }"),
- "object > is not a member of package math",
- """
- twRuntimeErrors("@if(math > 10){ 1 }else{ 2 }"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("@if(true){ (@math.pow(10)) * 10 }else{ 2 }"),
- "Unspecified value parameter y",
- """
- twRuntimeErrors("@if(true){ (@math.pow(10)) * 10 }else{ 2 }"),
- ^
- """
- )
- * - check(
- twRuntimeErrors("@if(true){ * 10 }else{ @math.sin(3, 4, 5) }"),
- "too many arguments for method sin: (x: Double)Double",
- """
- twRuntimeErrors("@if(true){ * 10 }else{ @math.sin(3, 4, 5) }"),
- ^
- """
- )
- }
- 'multiLine{
- * - check(
- twRuntimeErrors("""
- Ho Ho Ho
-
- @if(math != 10)
- I am a cow
- @else
- You are a cow
- GG
- """),
- "object != is not a member of package math",
- """
- @if(math != 10)
- ^
- """
- )
- * - check(
- twRuntimeErrors("""
- Ho Ho Ho
-
- @if(4 != 10)
- I am a cow @math.lols
- @else
- You are a cow
- GG
- """),
- "object lols is not a member of package math",
- """
- I am a cow @math.lols
- ^
- """
- )
- * - check(
- twRuntimeErrors("""
- Ho Ho Ho
-
- @if(12 != 10)
- I am a cow
- @else
- @math.E.toString.gog(1)
- GG
- """),
- "value gog is not a member of String",
- """
- @math.E.toString.gog(1)
- ^
- """
- )
- }
- }
- 'forLoop{
- 'oneLine{
- 'header - check(
- twRuntimeErrors("omg @for(x <- (0 + 1 + 2) omglolol (10 + 11 + 2)){ hello }"),
- """value omglolol is not a member of Int""",
- """
- twRuntimeErrors("omg @for(x <- (0 + 1 + 2) omglolol (10 + 11 + 2)){ hello }"),
- ^
- """
- )
-
- 'body - check(
- twRuntimeErrors("omg @for(x <- 0 until 10){ @((x, 2) + (1, 2)) }"),
- """too many arguments for method +""",
- """
- twRuntimeErrors("omg @for(x <- 0 until 10){ @((x, 2) + (1, 2)) }"),
- ^
- """
- )
- }
- 'multiLine{
- 'body - check(
- twRuntimeErrors("""
- omg
- @for(x <- 0 until 10)
- I am cow hear me moo
- I weigh twice as much as @x.kkk
- """),
- """value kkk is not a member of Int""",
- """
- I weigh twice as much as @x.kkk
- ^
- """
- )
- }
- }
- 'multiLine{
- 'missingVar - check(
- twRuntimeErrors("""
- omg @notInScope lol
- """),
- """not found: value notInScope""",
- """
- omg @notInScope lol
- ^
- """
- )
- 'wrongType - check(
- twRuntimeErrors("""
- omg @{() => ()} lol
- """),
- """type mismatch""",
- """
- omg @{() => ()} lol
- ^
- """
- )
-
- 'bigExpression - check(
- twRuntimeErrors("""
- @{
- val x = 1 + 2
- val y = new Object()
- val z = y * x
- x
- }
- """),
- "value * is not a member of Object",
- """
- val z = y * x
- ^
- """
- )
- }
- }
-}
+//package scalatex
+//
+//import utest._
+//import scalatex.stages._
+//import scalatags.Text.all._
+//import scalatex.Internals.{DebugFailure, twRuntimeErrors}
+//
+///**
+//* Created by haoyi on 7/14/14.
+//*/
+//object ErrorTests extends TestSuite{
+// def check(x: => Unit, expectedMsg: String, expectedError: String) = {
+// val DebugFailure(msg, pos) = intercept[DebugFailure](x)
+// def format(str: String) = {
+// val whitespace = " \t\n".toSet
+// "\n" + str.dropWhile(_ == '\n')
+// .reverse
+// .dropWhile(whitespace.contains)
+// .reverse
+// }
+// // Format these guys nicely to normalize them and make them
+// // display nicely in the assert error message if it blows up
+// val formattedPos = format(pos)
+// val formattedExpectedPos = format(expectedError)
+//
+// assert(msg.contains(expectedMsg))
+// assert(formattedPos == formattedExpectedPos)
+//
+// }
+// val tests = TestSuite{
+//
+//
+// 'simple - check(
+// twRuntimeErrors("omg @notInScope lol"),
+// """not found: value notInScope""",
+// """
+// twRuntimeErrors("omg @notInScope lol"),
+// ^
+// """
+// )
+//
+// 'chained{
+// 'properties {
+// * - check(
+// twRuntimeErrors("omg @math.lol lol"),
+// """object lol is not a member of package math""",
+// """
+// twRuntimeErrors("omg @math.lol lol"),
+// ^
+// """
+// )
+//
+// * - check(
+// twRuntimeErrors("omg @math.E.lol lol"),
+// """value lol is not a member of Double""",
+// """
+// twRuntimeErrors("omg @math.E.lol lol"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("omg @_root_.scala.math.lol lol"),
+// """object lol is not a member of package math""",
+// """
+// twRuntimeErrors("omg @_root_.scala.math.lol lol"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("omg @_root_.scala.gg.lol lol"),
+// """object gg is not a member of package scala""",
+// """
+// twRuntimeErrors("omg @_root_.scala.gg.lol lol"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("omg @_root_.ggnore.math.lol lol"),
+// """object ggnore is not a member of package <root>""",
+// """
+// twRuntimeErrors("omg @_root_.ggnore.math.lol lol"),
+// ^
+// """
+// )
+// }
+// 'calls{
+// * - check(
+// twRuntimeErrors("@scala.QQ.abs(-10).tdo(10).sum.z"),
+// """object QQ is not a member of package scala""",
+// """
+// twRuntimeErrors("@scala.QQ.abs(-10).tdo(10).sum.z"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("@scala.math.abs(-10).tdo(10).sum.z"),
+// "value tdo is not a member of Int",
+// """
+// twRuntimeErrors("@scala.math.abs(-10).tdo(10).sum.z"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("@scala.math.abs(-10).to(10).sum.z"),
+// "value z is not a member of Int",
+// """
+// twRuntimeErrors("@scala.math.abs(-10).to(10).sum.z"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("@scala.math.abs(-10).to(10).sum.z()"),
+// "value z is not a member of Int",
+// """
+// twRuntimeErrors("@scala.math.abs(-10).to(10).sum.z()"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("@scala.math.abs(-10).cow.sum.z"),
+// "value cow is not a member of Int",
+// """
+// twRuntimeErrors("@scala.math.abs(-10).cow.sum.z"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("@scala.smath.abs.cow.sum.z"),
+// "object smath is not a member of package scala",
+// """
+// twRuntimeErrors("@scala.smath.abs.cow.sum.z"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("""
+// I am cow hear me moo
+// @scala.math.abs(-10).tdo(10).sum.z
+// I weigh twice as much as you
+// """),
+// "value tdo is not a member of Int",
+// """
+// @scala.math.abs(-10).tdo(10).sum.z
+// ^
+// """
+// )
+// }
+// 'curlies{
+// * - check(
+// twRuntimeErrors("@p{@Seq(1, 2, 3).foldLeft(0)}"),
+// "missing arguments for method foldLeft",
+// """
+// twRuntimeErrors("@p{@Seq(1, 2, 3).foldLeft(0)}"),
+// ^
+// """
+// )
+//
+// * - check(
+// twRuntimeErrors("@Nil.foldLeft{XY}"),
+// "missing arguments for method foldLeft",
+// """
+// twRuntimeErrors("@Nil.foldLeft{XY}"),
+// ^
+// """
+// )
+//
+// * - check(
+// twRuntimeErrors("@Nil.map{(x: Int, y: String) => omg}"),
+// "type mismatch",
+// """
+// twRuntimeErrors("@Nil.map{(x: Int, y: String) => omg}"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("@Nil.map{ omg}"),
+// "too many arguments for method map",
+// """
+// twRuntimeErrors("@Nil.map{ omg}"),
+// ^
+// """
+// )
+// }
+// 'callContents{
+// * - check(
+// twRuntimeErrors("@scala.math.abs((1, 2).wtf)"),
+// "value wtf is not a member of (Int, Int)",
+// """
+// twRuntimeErrors("@scala.math.abs((1, 2).wtf)"),
+// ^
+// """
+// )
+//
+// * - check(
+// twRuntimeErrors("@scala.math.abs((1, 2).swap._1.toString().map(_.toString.wtf))"),
+// "value wtf is not a member of String",
+// """
+// twRuntimeErrors("@scala.math.abs((1, 2).swap._1.toString().map(_.toString.wtf))"),
+// ^
+// """
+// )
+// }
+// }
+// 'ifElse{
+// 'oneLine {
+// * - check(
+// twRuntimeErrors("@if(math > 10){ 1 }else{ 2 }"),
+// "object > is not a member of package math",
+// """
+// twRuntimeErrors("@if(math > 10){ 1 }else{ 2 }"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("@if(true){ (@math.pow(10)) * 10 }else{ 2 }"),
+// "Unspecified value parameter y",
+// """
+// twRuntimeErrors("@if(true){ (@math.pow(10)) * 10 }else{ 2 }"),
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("@if(true){ * 10 }else{ @math.sin(3, 4, 5) }"),
+// "too many arguments for method sin: (x: Double)Double",
+// """
+// twRuntimeErrors("@if(true){ * 10 }else{ @math.sin(3, 4, 5) }"),
+// ^
+// """
+// )
+// }
+// 'multiLine{
+// * - check(
+// twRuntimeErrors("""
+// Ho Ho Ho
+//
+// @if(math != 10)
+// I am a cow
+// @else
+// You are a cow
+// GG
+// """),
+// "object != is not a member of package math",
+// """
+// @if(math != 10)
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("""
+// Ho Ho Ho
+//
+// @if(4 != 10)
+// I am a cow @math.lols
+// @else
+// You are a cow
+// GG
+// """),
+// "object lols is not a member of package math",
+// """
+// I am a cow @math.lols
+// ^
+// """
+// )
+// * - check(
+// twRuntimeErrors("""
+// Ho Ho Ho
+//
+// @if(12 != 10)
+// I am a cow
+// @else
+// @math.E.toString.gog(1)
+// GG
+// """),
+// "value gog is not a member of String",
+// """
+// @math.E.toString.gog(1)
+// ^
+// """
+// )
+// }
+// }
+// 'forLoop{
+// 'oneLine{
+// 'header - check(
+// twRuntimeErrors("omg @for(x <- (0 + 1 + 2) omglolol (10 + 11 + 2)){ hello }"),
+// """value omglolol is not a member of Int""",
+// """
+// twRuntimeErrors("omg @for(x <- (0 + 1 + 2) omglolol (10 + 11 + 2)){ hello }"),
+// ^
+// """
+// )
+//
+// 'body - check(
+// twRuntimeErrors("omg @for(x <- 0 until 10){ @((x, 2) + (1, 2)) }"),
+// """too many arguments for method +""",
+// """
+// twRuntimeErrors("omg @for(x <- 0 until 10){ @((x, 2) + (1, 2)) }"),
+// ^
+// """
+// )
+// }
+// 'multiLine{
+// 'body - check(
+// twRuntimeErrors("""
+// omg
+// @for(x <- 0 until 10)
+// I am cow hear me moo
+// I weigh twice as much as @x.kkk
+// """),
+// """value kkk is not a member of Int""",
+// """
+// I weigh twice as much as @x.kkk
+// ^
+// """
+// )
+// }
+// }
+// 'multiLine{
+// 'missingVar - check(
+// twRuntimeErrors("""
+// omg @notInScope lol
+// """),
+// """not found: value notInScope""",
+// """
+// omg @notInScope lol
+// ^
+// """
+// )
+// 'wrongType - check(
+// twRuntimeErrors("""
+// omg @{() => ()} lol
+// """),
+// """type mismatch""",
+// """
+// omg @{() => ()} lol
+// ^
+// """
+// )
+//
+// 'bigExpression - check(
+// twRuntimeErrors("""
+// @{
+// val x = 1 + 2
+// val y = new Object()
+// val z = y * x
+// x
+// }
+// """),
+// "value * is not a member of Object",
+// """
+// val z = y * x
+// ^
+// """
+// )
+// }
+// }
+//}
diff --git a/scalatexApi/src/test/scala/scalatex/Main.scala b/scalatexApi/src/test/scala/scalatex/Main.scala
new file mode 100644
index 0000000..968e34c
--- /dev/null
+++ b/scalatexApi/src/test/scala/scalatex/Main.scala
@@ -0,0 +1,88 @@
+package scalatex
+
+
+import org.parboiled2._
+import torimatomeru.ScalaSyntax
+
+object Main extends utest.TestSuite{
+ import Ast._
+ import utest._
+ def check[T](input: String, parse: ScalatexParser => scala.util.Try[T], expected: T) = {
+ val parsed = parse(new ScalatexParser(input))
+ assert(parsed.get == expected)
+ }
+ def tests = TestSuite{
+ 'Test {
+ * - check("i am a cow", _.Text.run(), Block.Text("i am a cow"))
+ * - check("i am a @cow", _.Text.run(), Block.Text("i am a "))
+ * - check("i am a @@cow", _.Text.run(), Block.Text("i am a @cow"))
+ * - check("i am a @@@cow", _.Text.run(), Block.Text("i am a @"))
+ * - check("i am a @@@@cow", _.Text.run(), Block.Text("i am a @@cow"))
+
+ }
+ 'Code{
+ * - check("@(1 + 1)", _.Code.run(), Code("(1 + 1)"))
+ * - check("@{{1} + (1)}", _.Code.run(), Code("{{1} + (1)}"))
+ * - check("@{val x = 1; 1}", _.Code.run(), Code("{val x = 1; 1}"))
+ * - check("@{`{}}{()@`}", _.Code.run(), Code("{`{}}{()@`}"))
+ }
+
+ 'Block{
+ * - check("{i am a cow}", _.TBlock.run(), Block(Seq(Block.Text("i am a cow"))))
+ * - check("{i @am a @cow}", _.TBlock.run(),
+ Block(Seq(Block.Text("i "), Chain(Code("am"),Seq()), Block.Text(" a "), Chain(Code("cow"),Seq())))
+ )
+ }
+ 'Chain{
+ * - check("@omg.bbq[omg].fff[fff](123)", _.ScalaChain.run(),
+ Chain(Code("omg"),Seq(Chain.Prop(".bbq[omg]"), Chain.Prop(".fff[fff]"), Chain.Args("(123)")))
+ )
+ * - check("@omg{bbq}.cow(moo){a @b}", _.ScalaChain.run(),
+ Chain(Code("omg"),Seq(
+ Block(Seq(Block.Text("bbq"))),
+ Chain.Prop(".cow"),
+ Chain.Args("(moo)"),
+ Block(Seq(Block.Text("a "), Chain(Code("b"), Nil)))
+ ))
+ )
+ }
+
+ }
+ def p(input: String) = {
+ new ScalatexParser(input)
+ }
+}
+trait Ast{
+ def offset: Int
+}
+object Ast{
+ case class Code(code: String, offset: Int = 0) extends Ast
+ case class Block(parts: Seq[Block.Sub], offset: Int = 0) extends Chain.Sub
+ object Block{
+ trait Sub
+ case class Text(txt: String, offset: Int = 0) extends Block.Sub
+ }
+ case class Chain(lhs: Code, parts: Seq[Chain.Sub], offset: Int = 0) extends Block.Sub
+ object Chain{
+ trait Sub extends Ast
+ case class Prop(str: String, offset: Int = 0) extends Sub
+ case class Args(str: String, offset: Int = 0) extends Sub
+ }
+}
+class ScalatexParser(input: ParserInput) extends ScalaSyntax(input) {
+ def TextNot(chars: String) = rule { capture(oneOrMore(noneOf(chars) | "@@")) ~> (x => Ast.Block.Text(x.replace("@@", "@"))) }
+ def Text = TextNot("@")
+ def Code = rule {
+ "@" ~ capture(Id | BlockExpr | ('(' ~ optional(Exprs) ~ ')')) ~> (Ast.Code(_))
+ }
+ def ScalaChain = rule { Code ~ zeroOrMore(Extension) ~> (Ast.Chain(_, _)) }
+ def Extension: Rule1[Ast.Chain.Sub] = rule {
+ (capture(('.' ~ Id) ~ optional(TypeArgs)) ~> (Ast.Chain.Prop(_))) |
+ (capture(!BlockExpr ~ ArgumentExprs) ~> (Ast.Chain.Args(_))) |
+ TBlock
+ }
+ def TBlock = rule{ '{' ~ Body ~ '}' }
+ def Body = rule{ zeroOrMore(TextNot("@}") | ScalaChain) ~> (x => Ast.Block(x)) }
+}
+
+
diff --git a/scalatexApi/src/test/scala/scalatex/ParserTests.scala b/scalatexApi/src/test/scala/scalatex/ParserTests.scala
deleted file mode 100644
index 619bb3a..0000000
--- a/scalatexApi/src/test/scala/scalatex/ParserTests.scala
+++ /dev/null
@@ -1,50 +0,0 @@
-package scalatex
-import utest._
-import scalatex.stages.{TwistNodes, Parser}
-
-/**
- * Created by haoyi on 8/2/14.
- */
-object ParserTests extends TestSuite{
- val WN = TwistNodes
- val WP = Parser
- def check[T](s: String, f: Parser => T, expected: Option[T]){
- val parsed = WP.parse(s, f).toOption
- assert(parsed == expected)
- }
- val tests = TestSuite{
-// 'chainedExpressions {
-// check("", _.expression(), None)
-// check("asd", _.expression(), None)
-// check("@asd", _.expression(), Some(
-// WN.Display(WN.ScalaExp(Seq(WN.Simple("asd"))))
-// ))
-//
-// check("@asd{", _.expression(), None)
-// check("@asd(", _.expression(), None)
-// check("@asd()", _.expression(), Some(
-// WN.Display(WN.ScalaExp(Seq(WN.Simple("asd()"))))
-// ))
-// check("@asd(ggnore)", _.expression(), Some(
-// WN.Display(WN.ScalaExp(Seq(WN.Simple("asd(ggnore)"))))
-// ))
-// check("@asd.wtf(ggnore).bbq.lol", _.expression(), Some(
-// WN.Display(WN.ScalaExp(Seq(WN.Simple("asd"), WN.Simple(".wtf(ggnore).bbq.lol"))))
-// ))
-// check("@asd{}", _.expression(), Some(
-// WN.Display(WN.ScalaExp(Seq(WN.Simple("asd"), WN.Block("", None, Seq()))))
-// ))
-// check("@asd{lol}", _.expression(), Some(
-// WN.Display(WN.ScalaExp(Seq(WN.Simple("asd"), WN.Block("", None, Seq(WN.Plain("lol"))))))
-// ))
-// check("@asd{lol}.wtf('l'){gg}", _.expression(), Some(
-// WN.Display(WN.ScalaExp(Seq(
-// WN.Simple("asd"),
-// WN.Block("", None, Seq(WN.Plain("lol"))),
-// WN.Simple(".wtf('l')"),
-// WN.Block("", None, Seq(WN.Plain("gg")))
-// )))
-// ))
-// }
- }
-}
diff --git a/scalatexApi/src/test/scala/torimatomeru/ScalaSyntax.scala b/scalatexApi/src/test/scala/torimatomeru/ScalaSyntax.scala
new file mode 100644
index 0000000..5bbd0af
--- /dev/null
+++ b/scalatexApi/src/test/scala/torimatomeru/ScalaSyntax.scala
@@ -0,0 +1,246 @@
+package torimatomeru
+
+import language.implicitConversions
+import syntax._
+import org.parboiled2._
+
+class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identifiers with Literals {
+
+ def Whitespace = rule { zeroOrMore(WhitespaceChar | Comment) }
+
+ /**
+ * Every token handles space at the end.
+ * Don't let it propagate to mixins
+ */
+ implicit private[this] def wspStr(s: String): Rule0 = rule {
+ str(s) ~ Whitespace
+ }
+ implicit private[this] def wspChar(s: Char): Rule0 = rule {
+ ch(s) ~ Whitespace
+ }
+
+ def pos = cursor -> cursorChar
+
+ /**
+ * helper printing function
+ */
+ def pr(s: String) = rule { run(print(s)) }
+
+ //////////////////////////////////////////////////
+ // Override rules from dependencies
+ // in order to handle white spaces
+ // Note: when you add your AST, make sure to
+ // only capture super.rule and not the whitespace
+ //////////////////////////////////////////////////
+
+ def IdS = rule { super.Id ~ Whitespace }
+ def VarIdS = rule { super.VarId ~ Whitespace }
+ def LiteralS = rule { super.Literal ~ Whitespace }
+ def SemiS = rule { super.Semi ~ Whitespace }
+ def NewlineS = rule { super.Newline ~ Whitespace }
+
+ ///////////////////////////////////////////
+ // Qualifiers and Ids
+ ///////////////////////////////////////////
+
+ def QualId = rule { oneOrMore(IdS) separatedBy '.' }
+ def Ids = rule { oneOrMore(IdS) separatedBy ',' }
+
+ //path and stableId were refactored (wrt spec) to avoid recursiveness and be more specific
+ def Path: Rule0 = rule { zeroOrMore(IdS ~ '.') ~ "this" ~ zeroOrMore(IdS).separatedBy('.') | StableId }
+ def StableId: Rule0 = rule {
+ zeroOrMore(IdS ~ '.') ~ ("this" | "super" ~ optional(ClassQualifier)) ~ '.' ~ oneOrMore(IdS).separatedBy('.') |
+ IdS ~ zeroOrMore('.' ~ IdS)
+ }
+// def StableId: Rule0 = rule { zeroOrMore(Id ~ '.') ~ optional("this" | "super" ~ optional(ClassQualifier)) ~ oneOrMore(Id).separatedBy('.') }
+ def ClassQualifier = rule { '[' ~ IdS ~ ']' }
+
+ ///////////////////////////////////////////
+ // Types and more Types
+ ///////////////////////////////////////////
+
+ def Type: Rule0 = rule { FunctionArgTypes ~ "=>" ~ Type | InfixType ~ optional(ExistentialClause) }
+ def FunctionArgTypes = rule { InfixType | '(' ~ optional(oneOrMore(ParamType) separatedBy ',') ~ ')' }
+
+ def ExistentialClause = rule { "forSome" ~ '{' ~ oneOrMore(ExistentialDcl).separatedBy(SemiS) }
+ def ExistentialDcl = rule { "type" ~ TypeDcl | "val" ~ ValDcl }
+
+ def InfixType = rule { CompoundType ~ zeroOrMore(IdS ~ optional(NewlineS) ~ CompoundType) }
+ def CompoundType = rule { oneOrMore(AnnotType).separatedBy("with") ~ optional(Refinement) }
+ def AnnotType = rule { SimpleType ~ zeroOrMore(Annotation) }
+ def SimpleType: Rule0 = rule {
+ BasicType ~ optional('#' ~ IdS) ~ optional(TypeArgs)
+ }
+ def BasicType: Rule0 = rule {
+ '(' ~ Types ~ ')' |
+ Path ~ '.' ~ "type" |
+ StableId
+ }
+ def TypeArgs = rule { '[' ~ Types ~ ']' }
+ def Types = rule { oneOrMore(Type).separatedBy(',') }
+ def Refinement = rule { optional(NewlineS) ~ '{' ~ oneOrMore(RefineStat).separatedBy(SemiS) ~ '}' }
+ def RefineStat = rule { "type" ~ TypeDef | Dcl | MATCH }
+ def TypePat = rule { Type }
+ def Ascription = rule { ":" ~ (InfixType | oneOrMore(Annotation) | "_" ~ "*") }
+
+ def ParamType = rule { "=>" ~ Type | Type ~ "*" | Type }
+
+ /////////////////////////////////////////////////
+ // Declarations, Expressions and Pattern Matching
+ /////////////////////////////////////////////////
+
+ def Expr: Rule0 = rule { (Bindings | optional("implicit") ~ IdS | "_") ~ "=>" ~ Expr | Expr1 }
+ def Expr1: Rule0 = rule {
+ IfCFlow |
+ WhileCFlow |
+ TryCFlow |
+ DoWhileCFlow |
+ ForCFlow |
+ "throw" ~ Expr |
+ "return" ~ optional(Expr) |
+ SimpleExpr1 ~ ArgumentExprs ~ '=' ~ Expr |
+ optional(SimpleExpr ~ '.') ~ IdS ~ '=' ~ Expr |
+ PostfixExpr ~ optional("match" ~ '{' ~ CaseClauses ~ '}' | Ascription)
+ }
+
+ def IfCFlow = rule { "if" ~ '(' ~ Expr ~ ')' ~ zeroOrMore(NewlineS) ~ Expr ~ optional(optional(SemiS) ~ "else" ~ Expr) }
+ def WhileCFlow = rule { "while" ~ '(' ~ Expr ~ ')' ~ zeroOrMore(NewlineS) ~ Expr }
+ def TryCFlow = rule { "try" ~ '{' ~ Block ~ '}' ~ optional("catch" ~ '{' ~ CaseClauses ~ '}') ~ optional("finally" ~ Expr) }
+ def DoWhileCFlow = rule { "do" ~ Expr ~ optional(SemiS) ~ "while" ~ '(' ~ Expr ~ ')' }
+ def ForCFlow = rule { "for" ~ ('(' ~ Enumerators ~ ')' | '{' ~ Enumerators ~ '}') ~ zeroOrMore(NewlineS) ~ optional("yield") ~ Expr }
+ def PostfixExpr: Rule0 = rule { InfixExpr ~ optional(IdS ~ optional(NewlineS)) }
+ def InfixExpr: Rule0 = rule { PrefixExpr ~ zeroOrMore(IdS ~ optional(NewlineS) ~ PrefixExpr) }
+ def PrefixExpr = rule { optional(anyOf("-+~!")) ~ SimpleExpr }
+ def SimpleExpr: Rule0 = rule { SimpleExprNoLiteral | SimpleExpr1 ~ optional(ArgumentExprs) ~ optional('_') }
+ def SimpleExprNoLiteral: Rule0 = rule { "new" ~ (ClassTemplate | TemplateBody) | BlockExpr }
+ def SimpleExpr1: Rule0 = rule {
+ // run(println("SimpleExpr1 matching on " + pos)) ~
+ LiteralS ~ drop[String] | //literal currently captures, so it can be used outside. but since all our rules lack AST, we drop its value in order to be able to compose them
+ Path |
+ '_' |
+ '(' ~ optional(Exprs) ~ ')' |
+ SimpleExprNoLiteral ~ '.' ~ IdS |
+ SimpleExprNoLiteral ~ TypeArgs /*|
+ XmlExpr*/
+ }
+ def Exprs: Rule0 = rule { oneOrMore(Expr) separatedBy ',' }
+ def ArgumentExprs: Rule0 = rule {
+ '(' ~ (optional(Exprs ~ ',') ~ PostfixExpr ~ ':' ~ '_' ~ '*' | optional(Exprs)) ~ ')' |
+ optional(NewlineS) ~ BlockExpr
+ }
+ def BlockExpr: Rule0 = rule { '{' ~ (CaseClauses | Block) ~ '}' }
+ def Block: Rule0 = rule { zeroOrMore(BlockStat ~ SemiS) ~ optional(ResultExpr) }
+ def BlockStat: Rule0 = rule {
+ &(SemiS) ~ MATCH | //shortcircuit when Semi is found
+ Import |
+ zeroOrMore(Annotation) ~ (optional("implicit" | "lazy") ~ Def | zeroOrMore(LocalModifier) ~ TmplDef) |
+ Expr1
+ }
+ def ResultExpr: Rule0 = rule { (Bindings | optional("implicit") ~ IdS | "_") ~ "=>" ~ Block | Expr1 }
+ def Enumerators: Rule0 = rule { Generator ~ zeroOrMore(SemiS ~ Enumerator) }
+ def Enumerator: Rule0 = rule { Generator | Guard | Pattern1 ~ '=' ~ Expr }
+ def Generator: Rule0 = rule { Pattern1 ~ "<-" ~ Expr ~ optional(Guard) }
+ def CaseClauses: Rule0 = rule { oneOrMore(CaseClause) }
+ def CaseClause: Rule0 = rule { "case" ~ Pattern ~ optional(Guard) ~ "=>" ~ Block }
+ def Guard: Rule0 = rule { "if" ~ PostfixExpr }
+ def Pattern: Rule0 = rule { oneOrMore(Pattern1) separatedBy '|' }
+ def Pattern1: Rule0 = rule { '_' ~ ':' ~ TypePat | VarIdS ~ ':' ~ TypePat | Pattern2 }
+ def Pattern2: Rule0 = rule { VarIdS ~ optional("@" ~ Pattern3) | Pattern3 }
+ def Pattern3: Rule0 = rule { SimplePattern ~ zeroOrMore(IdS ~ optional(NewlineS) ~ SimplePattern) } // this pattern doesn't make sense to me...
+ def SimplePattern: Rule0 = rule {
+ '_' |
+ LiteralS ~ drop[String] | //literal currently captures, so it can be used outside. but since all our rules lack AST, we drop its value in order to be able to compose them
+ '(' ~ optional(Patterns) ~ ')' |
+ StableId ~ '(' ~ (optional(Patterns ~ ',') ~ optional(VarIdS ~ '@') ~ '_' ~ '*' | optional(Patterns)) ~ ')' |
+ VarIdS /*|
+ XmlPattern*/
+ }
+ def Patterns: Rule0 = rule { '_' ~ '*' | oneOrMore(Pattern).separatedBy(',') }
+
+ def TypeParamClause: Rule0 = rule { '[' ~ oneOrMore(VariantTypeParam).separatedBy(',') ~ ']' }
+ def FunTypeParamClause: Rule0 = rule { '[' ~ oneOrMore(TypeParam).separatedBy(',') ~ ']' }
+ def VariantTypeParam: Rule0 = rule { zeroOrMore(Annotation) ~ optional(anyOf("+-")) ~ TypeParam }
+ def TypeParam: Rule0 = rule { (IdS | '_') ~ optional(TypeParamClause) ~ optional(">:" ~ Type) ~ optional("<:" ~ Type) ~ zeroOrMore("<%" ~ Type) ~ zeroOrMore(':' ~ Type) }
+ def ParamClauses: Rule0 = rule { zeroOrMore(ParamClause) ~ optional(optional(NewlineS) ~ '(' ~ "implicit" ~ Params ~ ')') }
+ def ParamClause: Rule0 = rule { optional(NewlineS) ~ '(' ~ optional(Params) ~ ')' }
+ def Params: Rule0 = rule { zeroOrMore(Param).separatedBy(',') }
+ def Param: Rule0 = rule { zeroOrMore(Annotation) ~ IdS ~ optional(':' ~ ParamType) ~ optional('=' ~ Expr) }
+ def ClassParamClauses: Rule0 = rule { zeroOrMore(ClassParamClause) ~ optional(optional(NewlineS) ~ '(' ~ "implicit" ~ ClassParam ~ ')') }
+ def ClassParamClause: Rule0 = rule { optional(NewlineS) ~ '(' ~ optional(ClassParam) ~ ')' }
+ def ClassParams: Rule0 = rule { oneOrMore(ClassParam).separatedBy(',') }
+ def ClassParam: Rule0 = rule { zeroOrMore(Annotation) ~ optional(zeroOrMore(Modifier) ~ ("val" | "var")) ~ IdS ~ ":" ~ ParamType ~ optional("=" ~ Expr) }
+
+ def Bindings: Rule0 = rule { '(' ~ oneOrMore(Binding).separatedBy(',') ~ ')' }
+ def Binding: Rule0 = rule { (IdS | '_') ~ optional(':' ~ Type) }
+
+ def Modifier: Rule0 = rule { LocalModifier | AccessModifier | "override" }
+ def LocalModifier: Rule0 = rule { "abstract" | "final" | "sealed" | "implicit" | "lazy" }
+ def AccessModifier: Rule0 = rule { ("private" | "protected") ~ optional(AccessQualifier) }
+ def AccessQualifier: Rule0 = rule { '[' ~ ("this" ~ IdS) ~ ']' }
+
+ def Annotation: Rule0 = rule { '@' ~ SimpleType ~ zeroOrMore(ArgumentExprs) }
+ def ConstrAnnotation: Rule0 = rule { '@' ~ SimpleType ~ ArgumentExprs }
+ def NameValuePair: Rule0 = rule { "val" ~ IdS ~ '=' ~ PrefixExpr }
+
+ def TemplateBody: Rule0 = rule { optional(NewlineS) ~ '{' ~ optional(SelfType) ~ TemplateStat ~ zeroOrMore(SemiS ~ TemplateStat) ~ '}' }
+ def TemplateStat: Rule0 = rule {
+ Import |
+ zeroOrMore(Annotation ~ optional(NewlineS)) ~ zeroOrMore(Modifier) ~ (Def | Dcl) |
+ Expr |
+ MATCH
+ }
+
+ def SelfType: Rule0 = rule { "this" ~ ':' ~ Type ~ "=>" | IdS ~ optional(':' ~ Type) ~ "=>" }
+
+ def Import: Rule0 = rule { "import" ~ oneOrMore(ImportExpr).separatedBy(',') }
+
+ //ImportExpr is slightly changed wrt spec because StableId always consumes all the Ids possible, so there is no need to one at the end
+ def ImportExpr: Rule0 = rule { StableId ~ optional('.' ~ ('_' | ImportSelectors)) }
+ def ImportSelectors: Rule0 = rule { '{' ~ zeroOrMore(ImportSelector ~ ',') ~ (ImportSelector | '_') ~ '}' }
+ def ImportSelector: Rule0 = rule { IdS ~ optional("=>" ~ (IdS | '_')) }
+
+ def Dcl: Rule0 = rule {
+ "val" ~ ValDcl |
+ "var" ~ VarDcl |
+ "def" ~ FunDcl |
+ "type" ~ zeroOrMore(NewlineS) ~ TypeDcl
+ }
+ def ValDcl: Rule0 = rule { Ids ~ ':' ~ Type }
+ def VarDcl: Rule0 = rule { Ids ~ ':' ~ Type }
+ def FunDcl: Rule0 = rule { FunSig ~ optional(':' ~ Type) }
+ def FunSig: Rule0 = rule { IdS ~ optional(FunTypeParamClause) ~ ParamClauses }
+ def TypeDcl: Rule0 = rule { IdS ~ optional(TypeParamClause) ~ optional(">:" ~ Type) ~ optional("<:" ~ Type) }
+
+ def PatVarDef: Rule0 = rule { "val" ~ PatDef | "var" ~ VarDef }
+ def Def: Rule0 = rule { "def" ~ FunDef | "type" ~ zeroOrMore(NewlineS) ~ TypeDef | PatVarDef | TmplDef }
+ def PatDef: Rule0 = rule { oneOrMore(Pattern2).separatedBy(',') ~ optional(':' ~ Type) ~ '=' ~ Expr }
+ def VarDef: Rule0 = rule { Ids ~ ':' ~ Type ~ '=' ~ '_' | PatDef }
+ def FunDef: Rule0 = rule {
+ "this" ~ ParamClause ~ ParamClauses ~ ('=' ~ ConstrExpr | optional(NewlineS) ~ ConstrBlock) |
+ FunSig ~ (optional(':' ~ Type) ~ '=' ~ Expr | optional(NewlineS) ~ '{' ~ Block ~ '}')
+ }
+ def TypeDef: Rule0 = rule { IdS ~ optional(TypeParamClause) ~ '=' ~ Type }
+
+ def TmplDef: Rule0 = rule { "trait" ~ TraitDef | optional("case") ~ ("class" ~ ClassDef | "object" ~ ObjectDef) }
+ def ClassDef: Rule0 = rule { IdS ~ optional(TypeParamClause) ~ zeroOrMore(ConstrAnnotation) ~ optional(AccessModifier) ~ ClassParamClauses ~ ClassTemplateOpt }
+ def TraitDef: Rule0 = rule { IdS ~ optional(TypeParamClause) ~ TraitTemplateOpt }
+ def ObjectDef: Rule0 = rule { IdS ~ ClassTemplateOpt }
+ def ClassTemplateOpt: Rule0 = rule { "extends" ~ ClassTemplate | optional(optional("extends") ~ TemplateBody) }
+ def TraitTemplateOpt: Rule0 = rule { "extends" ~ TraitTemplate | optional(optional("extends") ~ TemplateBody) }
+ def ClassTemplate: Rule0 = rule { optional(EarlyDefs) ~ ClassParents ~ optional(TemplateBody) }
+ def TraitTemplate: Rule0 = rule { optional(EarlyDefs) ~ TraitParents ~ optional(TemplateBody) }
+ def ClassParents: Rule0 = rule { Constr ~ zeroOrMore("with" ~ AnnotType) }
+ def TraitParents: Rule0 = rule { AnnotType ~ zeroOrMore("with" ~ AnnotType) }
+ def Constr: Rule0 = rule { AnnotType ~ zeroOrMore(ArgumentExprs) }
+ def EarlyDefs: Rule0 = rule { '{' ~ optional(oneOrMore(EarlyDef).separatedBy(SemiS)) ~ '}' ~ "with" }
+ def EarlyDef: Rule0 = rule { zeroOrMore(Annotation ~ optional(NewlineS)) ~ zeroOrMore(Modifier) ~ PatVarDef }
+ def ConstrExpr: Rule0 = rule { ConstrBlock | SelfInvocation }
+ def ConstrBlock: Rule0 = rule { '{' ~ SelfInvocation ~ zeroOrMore(SemiS ~ BlockStat) ~ '}' }
+ def SelfInvocation: Rule0 = rule { "this" ~ oneOrMore(ArgumentExprs) }
+
+ def TopStatSeq: Rule0 = rule { oneOrMore(TopStat).separatedBy(SemiS) }
+ def TopStat: Rule0 = rule { Packaging | PackageObject | Import | zeroOrMore(Annotation ~ optional(NewlineS)) ~ zeroOrMore(Modifier) ~ TmplDef | MATCH }
+ def Packaging: Rule0 = rule { "package" ~ QualId ~ optional(NewlineS) ~ '{' ~ TopStatSeq ~ '}' }
+ def PackageObject: Rule0 = rule { "package" ~ "object" ~ ObjectDef }
+ def CompilationUnit: Rule0 = rule { zeroOrMore("package" ~ QualId ~ SemiS) ~ TopStatSeq }
+}