summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2014-11-03 22:41:55 -0800
committerLi Haoyi <haoyi@dropbox.com>2014-11-03 22:41:55 -0800
commit25d3233bae4ca89ba3a3916dfa9b45ee42d66435 (patch)
treed7cefbcc72cb7eb8e8a0abb120b375208bd4fd15
parented923d3445e1f304949eee2ee414987d98756a86 (diff)
downloadhands-on-scala-js-25d3233bae4ca89ba3a3916dfa9b45ee42d66435.tar.gz
hands-on-scala-js-25d3233bae4ca89ba3a3916dfa9b45ee42d66435.tar.bz2
hands-on-scala-js-25d3233bae4ca89ba3a3916dfa9b45ee42d66435.zip
Enabled a bunch more tests...
-rw-r--r--scalatexApi/src/main/scala/scalatex/package.scala8
-rw-r--r--scalatexApi/src/main/scala/scalatex/stages/Compiler.scala6
-rw-r--r--scalatexApi/src/main/scala/scalatex/stages/Parser.scala46
-rw-r--r--scalatexApi/src/main/scala/scalatex/stages/Trim.scala23
-rw-r--r--scalatexApi/src/test/scala/scalatex/BasicTests.scala256
-rw-r--r--scalatexApi/src/test/scala/scalatex/ParserTests.scala66
6 files changed, 243 insertions, 162 deletions
diff --git a/scalatexApi/src/main/scala/scalatex/package.scala b/scalatexApi/src/main/scala/scalatex/package.scala
index eb3ba6e..e2566cf 100644
--- a/scalatexApi/src/main/scala/scalatex/package.scala
+++ b/scalatexApi/src/main/scala/scalatex/package.scala
@@ -78,13 +78,9 @@ package object scalatex {
def compile(s: String): c.Tree = {
val realPos = new OffsetPosition(source, point).asInstanceOf[c.universe.Position]
- Compiler(c)(realPos, new Parser(s).Body.run().get)
- }
- def normalize(str: String) = {
- val lines = str.split("\n")
- val offset = lines.iterator.map(_.takeWhile(_ == ' ').length).min
- lines.iterator.map(_.drop(offset)).mkString("\n")
+ Compiler(c)(realPos, Parser(stages.Trim(s)))
}
+
import c.Position
try {
diff --git a/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala b/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala
index a305199..19cec10 100644
--- a/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala
+++ b/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala
@@ -6,9 +6,7 @@ import scala.reflect.macros.whitebox.Context
import scala.reflect.internal.util.{Position, OffsetPosition}
/**
- * Walks the parsed AST, converting it into an un-structured Scala source-blob
- * which when compiled results in a function that can be used to generate the
- * given Frag at runtime.
+ * Walks the parsed AST, converting it into a structured Scala c.Tree
*/
object Compiler{
@@ -17,7 +15,7 @@ object Compiler{
import c.universe._
def fragType = tq"scalatags.Text.all.Frag"
-
+ println(template)
def compileChain(code: String, parts: Seq[Ast.Chain.Sub], offset: Int): c.Tree = {
parts.foldLeft(c.parse(code)){
case (curr, Ast.Chain.Prop(str, offset2)) => q"$curr.${TermName(str)}"
diff --git a/scalatexApi/src/main/scala/scalatex/stages/Parser.scala b/scalatexApi/src/main/scala/scalatex/stages/Parser.scala
index d8878de..0bba713 100644
--- a/scalatexApi/src/main/scala/scalatex/stages/Parser.scala
+++ b/scalatexApi/src/main/scala/scalatex/stages/Parser.scala
@@ -4,26 +4,15 @@ package stages
import org.parboiled2._
import torimatomeru.ScalaSyntax
import Util._
-trait Ast{
- def offset: Int
-}
-object Ast{
- case class Block(parts: Seq[Block.Sub], offset: Int = 0) extends Chain.Sub
- object Block{
- trait Sub extends Ast
- case class Text(txt: String, offset: Int = 0) extends Block.Sub
- }
- case class Chain(lhs: String, 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 TypeArgs(str: String, offset: Int = 0) extends Sub
- case class Args(str: String, offset: Int = 0) extends Sub
- }
-}
-object Parser{
- def parse(input: String): Ast.Block = {
+/**
+ * Parses the input text into a roughly-structured AST. This AST
+ * is much simpler than the real Scala AST, but serves us well
+ * enough until we stuff the code-strings into the real Scala
+ * parser later
+ */
+object Parser extends (String => Ast.Block){
+ def apply(input: String): Ast.Block = {
new Parser(input).Body.run().get
}
}
@@ -95,3 +84,22 @@ class Parser(input: ParserInput, indent: Int = 0) extends ScalaSyntax(input) {
}
}
}
+
+trait Ast{
+ def offset: Int
+}
+object Ast{
+ case class Block(parts: Seq[Block.Sub], offset: Int = 0) extends Chain.Sub
+ object Block{
+ trait Sub extends Ast
+ case class Text(txt: String, offset: Int = 0) extends Block.Sub
+ }
+
+ case class Chain(lhs: String, 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 TypeArgs(str: String, offset: Int = 0) extends Sub
+ case class Args(str: String, offset: Int = 0) extends Sub
+ }
+} \ No newline at end of file
diff --git a/scalatexApi/src/main/scala/scalatex/stages/Trim.scala b/scalatexApi/src/main/scala/scalatex/stages/Trim.scala
new file mode 100644
index 0000000..02d9cc4
--- /dev/null
+++ b/scalatexApi/src/main/scala/scalatex/stages/Trim.scala
@@ -0,0 +1,23 @@
+package scalatex.stages
+
+/**
+ * Preprocesses the input string to normalize things related to whitespace
+ *
+ * Find the "first" non-whitespace-line of the text and remove the front
+ * of every line to align that first line with the left margin.
+ *
+ * Remove all trailing whitespace from each line.
+ */
+object Trim extends (String => String){
+ def apply(str: String) = {
+ val lines = str.split("\n")
+ val offset = lines.iterator
+ .filter(_.length > 0)
+ .next()
+ .takeWhile(_ == ' ')
+ .length
+ lines.iterator
+ .map(_.drop(offset).replaceFirst("\\s+$", ""))
+ .mkString("\n")
+ }
+}
diff --git a/scalatexApi/src/test/scala/scalatex/BasicTests.scala b/scalatexApi/src/test/scala/scalatex/BasicTests.scala
index 91291dd..c7e2d6a 100644
--- a/scalatexApi/src/test/scala/scalatex/BasicTests.scala
+++ b/scalatexApi/src/test/scala/scalatex/BasicTests.scala
@@ -11,42 +11,42 @@ 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|"
-// )
-// }
+
+ '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
-// """
-// )
+ '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{
@@ -70,20 +70,20 @@ object BasicTests extends TestSuite{
// """
// )
// }
-// 'parenArgumentLists{
-// 'attributes{
-// check(
-// tw("""
-// @div(id:="my-id"){ omg }
-// @div(id:="my-id")
-// omg
-// """),
-// """
-// <divid="my-id">omg</div>
-// <divid="my-id">omg</div>
-// """
-// )
-// }
+ '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(
@@ -101,51 +101,51 @@ object BasicTests extends TestSuite{
// """
// )
// }
-// }
-// '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>
-// """
-// )
-// }
+ }
+ '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("""
@@ -162,39 +162,39 @@ object BasicTests extends TestSuite{
// """
// )
// }
-// '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>
-// """
-// )
-// }
-// }
+ '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("""
@@ -420,6 +420,6 @@ object BasicTests extends TestSuite{
// "<p>lols2</p>"
// )
// }
-// }
+ }
}
}
diff --git a/scalatexApi/src/test/scala/scalatex/ParserTests.scala b/scalatexApi/src/test/scala/scalatex/ParserTests.scala
index b6e64ec..45d6b50 100644
--- a/scalatexApi/src/test/scala/scalatex/ParserTests.scala
+++ b/scalatexApi/src/test/scala/scalatex/ParserTests.scala
@@ -16,7 +16,63 @@ object ParserTests extends utest.TestSuite{
assert(parsed.get == expected)
}
def tests = TestSuite{
- 'Test {
+ 'Trim{
+ def wrap(s: String) = "|" + s + "|"
+ * - {
+ val trimmed = wrap(stages.Trim("""
+ i am cow
+ hear me moo
+ i weigh twice as much as you
+ """))
+ val expected = wrap("""
+ |i am cow
+ | hear me moo
+ | i weigh twice as much as you
+ |""".stripMargin)
+ assert(trimmed == expected)
+
+ }
+ * - {
+ val trimmed = wrap(stages.Trim(
+ """
+ @{"lol" * 3}
+ @{
+ val omg = "omg"
+ omg * 2
+ }
+ """
+ ))
+ val expected = wrap(
+ """
+ |@{"lol" * 3}
+ |@{
+ | val omg = "omg"
+ | omg * 2
+ |}
+ |""".stripMargin
+ )
+ assert(trimmed == expected)
+ }
+ 'dropTrailingWhitespace - {
+
+ val trimmed = wrap(stages.Trim(
+ Seq(
+ " i am a cow ",
+ " hear me moo ",
+ " i weigh twice as much as you"
+ ).mkString("\n")
+ ))
+ val expected = wrap(
+ Seq(
+ "i am a cow",
+ " hear me moo",
+ " i weigh twice as much as you"
+ ).mkString("\n")
+ )
+ assert(trimmed == expected)
+ }
+ }
+ 'Text {
* - 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"))
@@ -63,7 +119,7 @@ object ParserTests extends utest.TestSuite{
)
}
'Body{
- * - check(
+ 'indents - check(
"""
|@omg
| @wtf
@@ -84,7 +140,7 @@ object ParserTests extends utest.TestSuite{
))))
))
)
- * - check(
+ 'dedents - check(
"""
|@omg
| @wtf
@@ -101,7 +157,7 @@ object ParserTests extends utest.TestSuite{
Chain("bbq", Seq())
))
)
- * - check(
+ 'dedentText - check(
"""
|@omg("lol", 1, 2)
| @wtf
@@ -139,7 +195,7 @@ object ParserTests extends utest.TestSuite{
// Text("bbq")
// ))
// )
- * - check(
+ 'codeBlocks - check(
"""
|@{"lol" * 3}
|@{