summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2014-11-03 23:26:05 -0800
committerLi Haoyi <haoyi@dropbox.com>2014-11-03 23:26:05 -0800
commit9d9cd46a6ccc5bbe8b22dc38f615b532e526774c (patch)
tree88e2c8c72209bcbe298b88a5bca5cd8e2bb986c7
parent25d3233bae4ca89ba3a3916dfa9b45ee42d66435 (diff)
downloadhands-on-scala-js-9d9cd46a6ccc5bbe8b22dc38f615b532e526774c.tar.gz
hands-on-scala-js-9d9cd46a6ccc5bbe8b22dc38f615b532e526774c.tar.bz2
hands-on-scala-js-9d9cd46a6ccc5bbe8b22dc38f615b532e526774c.zip
Header blocks kinda implemented
-rw-r--r--scalatexApi/src/main/scala/scalatex/stages/Compiler.scala9
-rw-r--r--scalatexApi/src/main/scala/scalatex/stages/Parser.scala45
-rw-r--r--scalatexApi/src/test/scala/scalatex/ParserTests.scala56
3 files changed, 82 insertions, 28 deletions
diff --git a/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala b/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala
index 19cec10..5704b2c 100644
--- a/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala
+++ b/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala
@@ -25,17 +25,18 @@ object Compiler{
case (curr, Ast.Chain.TypeArgs(str, offset2)) =>
val TypeApply(fun, args) = c.parse(s"omg$str")
TypeApply(curr, args)
- case (curr, Ast.Block(parts, offset)) =>
- q"$curr(..${compileBlock(parts, offset)})"
+ case (curr, Ast.Block(front, parts, offset)) =>
+ q"$curr(..${compileBlock(front, parts, offset)})"
}
}
- def compileBlock(parts: Seq[Ast.Block.Sub], offset: Int): Seq[c.Tree] = {
+ def compileBlock(front: Option[String], parts: Seq[Ast.Block.Sub], offset: Int): Seq[c.Tree] = {
parts.map{
case Ast.Block.Text(str, offset2) => q"$str"
case Ast.Chain(code, parts, offset) => compileChain(code, parts, offset)
+
}
}
- val res = q"Seq[$fragType](..${compileBlock(template.parts, template.offset)})"
+ val res = q"Seq[$fragType](..${compileBlock(None, template.parts, template.offset)})"
println("::::::::::::::::::::::::::::::::::::::::::::::::")
println(res)
println("::::::::::::::::::::::::::::::::::::::::::::::::")
diff --git a/scalatexApi/src/main/scala/scalatex/stages/Parser.scala b/scalatexApi/src/main/scala/scalatex/stages/Parser.scala
index 0bba713..91738a7 100644
--- a/scalatexApi/src/main/scala/scalatex/stages/Parser.scala
+++ b/scalatexApi/src/main/scala/scalatex/stages/Parser.scala
@@ -40,6 +40,16 @@ class Parser(input: ParserInput, indent: Int = 0) extends ScalaSyntax(input) {
def Code = rule {
"@" ~ capture(Id | BlockExpr2 | ('(' ~ optional(Exprs) ~ ')'))
}
+ def Header = rule {
+ "@" ~ capture(Def | Import)
+ }
+
+ def HeaderBlock: Rule1[Ast.Block] = rule{
+ oneOrMore(Header ~ NewlineS) ~ runSubParser{new Parser(_, indent).Body0} ~> {
+ (head: Seq[String], body: Ast.Block) => body.copy(front = Some(head.mkString("\n")))
+ }
+ }
+
def BlankLine = rule{ '\n' ~ zeroOrMore(' ') ~ &('\n') }
def Indent = rule{ '\n' ~ indent.times(' ') ~ zeroOrMore(' ') }
def LoneScalaChain: Rule2[Ast.Block.Text, Ast.Chain] = rule {
@@ -72,15 +82,22 @@ class Parser(input: ParserInput, indent: Int = 0) extends ScalaSyntax(input) {
def BlockExpr2: Rule0 = rule { '{' ~ Ws ~ (CaseClauses | Block) ~ '}' }
def TBlock = rule{ '{' ~ Body ~ '}' }
- def Body = rule{
- oneOrMore(
- LoneScalaChain ~> (Seq(_, _)) |
+ def BodyItem = rule{
+ LoneScalaChain ~> (Seq(_, _)) |
+ HeaderBlock ~> (Seq(_)) |
TextNot("@}") ~> (Seq(_)) |
(capture(Indent) ~> (x => Seq(Ast.Block.Text(x)))) |
(capture(BlankLine) ~> (x => Seq(Ast.Block.Text(x)))) |
ScalaChain ~> (Seq(_))
- ) ~> {x =>
- Ast.Block(x.flatten)
+ }
+ def Body = rule{
+ oneOrMore(BodyItem) ~> {x =>
+ Ast.Block(None, x.flatten)
+ }
+ }
+ def Body0 = rule{
+ zeroOrMore(BodyItem) ~> {x =>
+ Ast.Block(None, x.flatten)
}
}
}
@@ -89,12 +106,28 @@ trait Ast{
def offset: Int
}
object Ast{
- case class Block(parts: Seq[Block.Sub], offset: Int = 0) extends Chain.Sub
+
+ /**
+ * @param front Any parameter lists (if it's a lambda), imports, val/def/lazy-val,
+ * class/object/trait declarations that occur before the parts of this
+ * block, and must be in scope within those parts
+ * @param parts The various bits of text and other things which make up this block
+ * @param offset
+ */
+ case class Block(front: Option[String],
+ parts: Seq[Block.Sub],
+ offset: Int = 0)
+ extends Chain.Sub with Block.Sub
object Block{
trait Sub extends Ast
case class Text(txt: String, offset: Int = 0) extends Block.Sub
}
+ /**
+ * @param lhs The first expression in this method-chain
+ * @param parts A list of follow-on items chained to the first
+ * @param offset
+ */
case class Chain(lhs: String, parts: Seq[Chain.Sub], offset: Int = 0) extends Block.Sub
object Chain{
trait Sub extends Ast
diff --git a/scalatexApi/src/test/scala/scalatex/ParserTests.scala b/scalatexApi/src/test/scala/scalatex/ParserTests.scala
index 45d6b50..f6d443f 100644
--- a/scalatexApi/src/test/scala/scalatex/ParserTests.scala
+++ b/scalatexApi/src/test/scala/scalatex/ParserTests.scala
@@ -81,17 +81,37 @@ object ParserTests extends utest.TestSuite{
}
'Code{
- * - check("@(1 + 1)lolsss\n", _.Code.run(), "(1 + 1)")
- * - check("@{{1} + (1)} ", _.Code.run(), "{{1} + (1)}")
- * - check("@{val x = 1; 1} ", _.Code.run(), "{val x = 1; 1}")
- * - check("@{`{}}{()@`}\n", _.Code.run(), "{`{}}{()@`}")
- * - check("@gggg ", _.Code.run(), "gggg")
+ 'identifier - check("@gggg ", _.Code.run(), "gggg")
+ 'parens - check("@(1 + 1)lolsss\n", _.Code.run(), "(1 + 1)")
+ 'curlies - check("@{{1} + (1)} ", _.Code.run(), "{{1} + (1)}")
+ 'blocks - check("@{val x = 1; 1} ", _.Code.run(), "{val x = 1; 1}")
+ 'weirdBackticks - check("@{`{}}{()@`}\n", _.Code.run(), "{`{}}{()@`}")
}
+ 'MiscCode{
+ 'imports{
+ * - check("@import math.abs", _.Header.run(), "import math.abs")
+ * - check("@import math.{abs, sin}", _.Header.run(), "import math.{abs, sin}")
+ }
+ 'headerblocks{
+ check(
+ """@import math.abs
+ |@import math.sin
+ |
+ |hello world
+ |""".stripMargin,
+ _.HeaderBlock.run(),
+ Ast.Block(
+ Some("import math.abs\nimport math.sin"),
+ Seq(Text("\n"), Text("hello world"), Text("\n"))
+ )
+ )
+ }
+ }
'Block{
- * - check("{i am a cow}", _.TBlock.run(), Block(Seq(Block.Text("i am a cow"))))
+ * - check("{i am a cow}", _.TBlock.run(), Block(None, Seq(Block.Text("i am a cow"))))
* - check("{i @am a @cow}", _.TBlock.run(),
- Block(Seq(
+ Block(None, Seq(
Block.Text("i "),
Chain("am",Seq()),
Block.Text(" a "),
@@ -111,10 +131,10 @@ object ParserTests extends utest.TestSuite{
)
* - check("@omg{bbq}.cow(moo){a @b}\n", _.ScalaChain.run(),
Chain("omg",Seq(
- Block(Seq(Block.Text("bbq"))),
+ Block(None, Seq(Block.Text("bbq"))),
Chain.Prop("cow"),
Chain.Args("(moo)"),
- Block(Seq(Block.Text("a "), Chain("b", Nil)))
+ Block(None, Seq(Block.Text("a "), Chain("b", Nil)))
))
)
}
@@ -126,13 +146,13 @@ object ParserTests extends utest.TestSuite{
| @bbq
| @lol""".stripMargin,
_.Body.run(),
- Block(Seq(
+ Block(None, Seq(
Text("\n"),
- Chain("omg",Seq(Block(Seq(
+ Chain("omg",Seq(Block(None, Seq(
Text("\n "),
- Chain("wtf",Seq(Block(Seq(
+ Chain("wtf",Seq(Block(None, Seq(
Text("\n "),
- Chain("bbq",Seq(Block(Seq(
+ Chain("bbq",Seq(Block(None, Seq(
Text("\n "),
Chain("lol",Seq())
))))
@@ -146,9 +166,10 @@ object ParserTests extends utest.TestSuite{
| @wtf
|@bbq""".stripMargin,
_.Body.run(),
- Block(Seq(
+ Block(None, Seq(
Text("\n"),
Chain("omg",Seq(Block(
+ None,
Seq(
Text("\n "),
Chain("wtf",Seq()))
@@ -163,11 +184,11 @@ object ParserTests extends utest.TestSuite{
| @wtf
|bbq""".stripMargin,
_.Body.run(),
- Block(Seq(
+ Block(None, Seq(
Text("\n"),
Chain("omg",Seq(
Args("""("lol", 1, 2)"""),
- Block(Seq(
+ Block(None, Seq(
Text("\n "),
Chain("wtf",Seq())))
)),
@@ -203,7 +224,7 @@ object ParserTests extends utest.TestSuite{
| omg * 2
|}""".stripMargin,
_.Body.run(),
- Block(Seq(
+ Block(None, Seq(
Text("\n"),
Chain("{\"lol\" * 3}", Seq()),
Text("\n"),
@@ -217,7 +238,6 @@ object ParserTests extends utest.TestSuite{
)
}
}
-
}