diff options
author | Li Haoyi <haoyi@dropbox.com> | 2014-11-02 20:31:39 -0800 |
---|---|---|
committer | Li Haoyi <haoyi@dropbox.com> | 2014-11-02 20:31:39 -0800 |
commit | 5dbe9747db34b1aea95df002270e9634df533805 (patch) | |
tree | 4bc93e3ebec777c285e2141bee56f769f098bd17 /scalatexApi/src | |
parent | 7c8f1a9fcc5638976ba9b310a54b810fe437bb2d (diff) | |
download | hands-on-scala-js-5dbe9747db34b1aea95df002270e9634df533805.tar.gz hands-on-scala-js-5dbe9747db34b1aea95df002270e9634df533805.tar.bz2 hands-on-scala-js-5dbe9747db34b1aea95df002270e9634df533805.zip |
Moved `examples` into `examples/demos`, sketched out a simple example cross-module
Diffstat (limited to 'scalatexApi/src')
-rw-r--r-- | scalatexApi/src/test/scala/scalatex/AdvancedTests.scala | 240 | ||||
-rw-r--r-- | scalatexApi/src/test/scala/scalatex/BasicTests.scala | 850 | ||||
-rw-r--r-- | scalatexApi/src/test/scala/scalatex/ErrorTests.scala | 714 | ||||
-rw-r--r-- | scalatexApi/src/test/scala/scalatex/Main.scala | 88 | ||||
-rw-r--r-- | scalatexApi/src/test/scala/scalatex/ParserTests.scala | 50 | ||||
-rw-r--r-- | scalatexApi/src/test/scala/torimatomeru/ScalaSyntax.scala | 246 |
6 files changed, 1236 insertions, 952 deletions
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 } +} |