diff options
Diffstat (limited to 'scalatex/api')
-rw-r--r-- | scalatex/api/src/main/scala/scalatex/package.scala | 98 | ||||
-rw-r--r-- | scalatex/api/src/main/scala/scalatex/stages/Compiler.scala | 103 | ||||
-rw-r--r-- | scalatex/api/src/main/scala/scalatex/stages/Parser.scala | 170 | ||||
-rw-r--r-- | scalatex/api/src/main/scala/scalatex/stages/Trim.scala | 29 | ||||
-rw-r--r-- | scalatex/api/src/test/scala/scalatex/BasicTests.scala | 468 | ||||
-rw-r--r-- | scalatex/api/src/test/scala/scalatex/ErrorTests.scala | 373 | ||||
-rw-r--r-- | scalatex/api/src/test/scala/scalatex/ParserTests.scala | 424 | ||||
-rw-r--r-- | scalatex/api/src/test/scala/scalatex/TestUtil.scala | 16 |
8 files changed, 0 insertions, 1681 deletions
diff --git a/scalatex/api/src/main/scala/scalatex/package.scala b/scalatex/api/src/main/scala/scalatex/package.scala deleted file mode 100644 index 1f13e63..0000000 --- a/scalatex/api/src/main/scala/scalatex/package.scala +++ /dev/null @@ -1,98 +0,0 @@ -import scala.reflect.internal.util.{BatchSourceFile, SourceFile, OffsetPosition} -import scala.reflect.io.{PlainFile, AbstractFile} -import scala.reflect.macros.{TypecheckException, Context} -import scalatags.Text.all._ -import scalatex.stages.{Parser, Compiler} -import scala.language.experimental.macros -import acyclic.file - -package object scalatex { - /** - * Wraps the given string as a twist fragment. - */ - def tw(expr: String): Frag = macro Internals.applyMacro - def twf(filename: String): Frag = macro Internals.applyMacroFile - object Internals { - - def twRuntimeErrors(expr: String): Frag = macro applyMacroRuntimeErrors - def twDebug(expr: String): Frag = macro applyMacroDebug - - def applyMacro(c: Context)(expr: c.Expr[String]): c.Expr[Frag] = applyMacroFull(c)(expr, false, false) - def applyMacroDebug(c: Context)(expr: c.Expr[String]): c.Expr[Frag] = applyMacroFull(c)(expr, false, true) - - def applyMacroRuntimeErrors(c: Context)(expr: c.Expr[String]): c.Expr[Frag] = applyMacroFull(c)(expr, true, false) - - def applyMacroFile(c: Context)(filename: c.Expr[String]): c.Expr[Frag] = { - import c.universe._ - val fileName = filename.tree - .asInstanceOf[Literal] - .value - .value - .asInstanceOf[String] - val txt = io.Source.fromFile(fileName).mkString - val sourceFile = new BatchSourceFile( - new PlainFile(fileName), - txt.toCharArray - ) - - compileThing(c)(txt, sourceFile, 0, false, false) - } - - case class DebugFailure(msg: String, pos: String) extends Exception(msg) - - private[this] def applyMacroFull(c: Context) - (expr: c.Expr[String], - runtimeErrors: Boolean, - debug: Boolean) - : c.Expr[Frag] = { - import c.universe._ - val scalatexFragment = expr.tree - .asInstanceOf[Literal] - .value - .value - .asInstanceOf[String] - val stringStart = - expr.tree - .pos - .lineContent - .drop(expr.tree.pos.column) - .take(2) - compileThing(c)( - scalatexFragment, - expr.tree.pos.source, - expr.tree.pos.point + (if (stringStart == "\"\"") 1 else -1), - runtimeErrors, - debug - ) - } - } - - def compileThing(c: Context) - (scalatexSource: String, - source: SourceFile, - point: Int, - runtimeErrors: Boolean, - debug: Boolean) = { - import c.universe._ - def compile(s: String): c.Tree = { - val realPos = new OffsetPosition(source, point).asInstanceOf[c.universe.Position] - - Compiler(c)(realPos, Parser.tupled(stages.Trim(s))) - } - - - import c.Position - try { - val compiled = compile(scalatexSource) - if (debug) println(compiled) - c.Expr[Frag](c.typeCheck(compiled)) - } catch { - case e@TypecheckException(pos: Position, msg) => - if (!runtimeErrors) c.abort(pos, msg) - else { - val posMsg = pos.lineContent + "\n" + (" " * pos.column) + "^" - c.Expr( q"""throw scalatex.Internals.DebugFailure($msg, $posMsg)""") - } - } - } -} diff --git a/scalatex/api/src/main/scala/scalatex/stages/Compiler.scala b/scalatex/api/src/main/scala/scalatex/stages/Compiler.scala deleted file mode 100644 index 3df8da7..0000000 --- a/scalatex/api/src/main/scala/scalatex/stages/Compiler.scala +++ /dev/null @@ -1,103 +0,0 @@ -package scalatex -package stages - -import acyclic.file - -import scala.reflect.macros.whitebox.Context -import scala.reflect.internal.util.{Position, OffsetPosition} - -/** - * Walks the parsed AST, converting it into a structured Scala c.Tree - */ -object Compiler{ - - def apply(c: Context)(fragPos: c.Position, template: Ast.Block): c.Tree = { - - import c.universe._ - def fragType = tq"scalatags.Text.all.Frag" - - def incPosRec(trees: c.Tree, offset: Int): trees.type = { - - trees.foreach(incPos(_, offset)) - trees - } - def incPos(tree: c.Tree, offset: Int): tree.type = { - - val current = if (tree.pos == NoPosition) 0 else tree.pos.point - c.internal.setPos(tree, - new OffsetPosition( - fragPos.source, - offset + current + fragPos.point - ).asInstanceOf[c.universe.Position] - ) - tree - } - - def compileChain(code: String, parts: Seq[Ast.Chain.Sub], offset: Int): c.Tree = { - - val out = parts.foldLeft(incPosRec(c.parse(code), offset + 1)){ - case (curr, Ast.Chain.Prop(str, offset2)) => - incPos(q"$curr.${TermName(str)}", offset2 + 1) - case (curr, Ast.Chain.Args(str, offset2)) => - val Apply(fun, args) = c.parse(s"omg$str") - incPos(Apply(curr, args.map(incPosRec(_, offset2 - 2))), offset2) - case (curr, Ast.Chain.TypeArgs(str, offset2)) => - val TypeApply(fun, args) = c.parse(s"omg$str") - incPos(TypeApply(curr, args.map(incPosRec(_, offset2 - 2))), offset2) - case (curr, Ast.Block(parts, offset1)) => - incPos(q"$curr(..${compileBlock(parts, offset1)})", offset1) - case (curr, Ast.Header(header, block, offset1)) => - incPos(q"$curr(${compileHeader(header, block, offset1)})", offset1) - } - - out - } - def compileBlock(parts: Seq[Ast.Block.Sub], offset: Int): Seq[c.Tree] = { - val res = parts.map{ - case Ast.Block.Text(str, offset1) => - incPos(q"$str", offset1) - case Ast.Chain(code, parts, offset1) => - compileChain(code, parts, offset1) - case Ast.Header(header, block, offset1) => - compileHeader(header, block, offset1) - case Ast.Block.IfElse(condString, Ast.Block(parts2, offset2), elseBlock, offset1) => - val If(cond, _, _) = c.parse(condString + "{}") - val elseCompiled = elseBlock match{ - case Some(Ast.Block(parts3, offset3)) => compileBlockWrapped(parts3, offset3) - case None => EmptyTree - } - - val res = If(incPosRec(cond, offset1 + 2), compileBlockWrapped(parts2, offset2), elseCompiled) - - incPos(res, offset1) - res - case Ast.Block.For(generators, Ast.Block(parts2, offset2), offset1) => - val fresh = c.fresh() - - val tree = incPosRec(c.parse(s"$generators yield $fresh"), offset1 + 2) - - def rec(t: Tree): Tree = t match { - case a @ Apply(fun, List(f @ Function(vparams, body))) => - val f2 = Function(vparams, rec(body)) - val a2 = Apply(fun, List(f2)) - a2 - case Ident(x: TermName) if x.decoded == fresh => - compileBlockWrapped(parts2, offset2) - } - - rec(tree) - } - res - } - def compileBlockWrapped(parts: Seq[Ast.Block.Sub], offset: Int): c.Tree = { - incPos(q"Seq[$fragType](..${compileBlock(parts, offset)})", offset) - } - def compileHeader(header: String, block: Ast.Block, offset: Int): c.Tree = { - val Block(stmts, expr) = c.parse(s"{$header\n ()}") - Block(stmts, compileBlockWrapped(block.parts, block.offset)) - } - - val res = compileBlockWrapped(template.parts, template.offset) - res - } -}
\ No newline at end of file diff --git a/scalatex/api/src/main/scala/scalatex/stages/Parser.scala b/scalatex/api/src/main/scala/scalatex/stages/Parser.scala deleted file mode 100644 index 0b87d97..0000000 --- a/scalatex/api/src/main/scala/scalatex/stages/Parser.scala +++ /dev/null @@ -1,170 +0,0 @@ -package scalatex -package stages -import acyclic.file -import org.parboiled2._ -import scalaParser.ScalaSyntax - -/** - * 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, Int) => Ast.Block){ - def apply(input: String, offset: Int = 0): Ast.Block = { - new Parser(input, offset).Body.run().get - } -} -class Parser(input: ParserInput, indent: Int = 0, offset: Int = 0) extends scalaParser.ScalaSyntax(input) { - def offsetCursor = offset + cursor - val txt = input.sliceString(0, input.length) - val indentTable = txt.split('\n').map{ s => - if (s.trim == "") -1 - else s.takeWhile(_ == ' ').length - } - val nextIndentTable = (0 until indentTable.length).map { i => - val index = indentTable.indexWhere(_ != -1, i + 1) - if (index == -1) 100000 - else indentTable(index) - } - def cursorNextIndent() = { - nextIndentTable(txt.take(cursor).count(_ == '\n')) - } - - def TextNot(chars: String) = rule { - push(offsetCursor) ~ capture(oneOrMore(noneOf(chars + "\n") | "@@")) ~> { - (i, x) => Ast.Block.Text(x.replace("@@", "@"), i) - } - } - def Text = TextNot("@") - def Code = rule { - "@" ~ capture(Identifiers.Id | BlockExpr2 | ('(' ~ optional(Exprs) ~ ')')) - } - def Header = rule { - "@" ~ capture(Def | Import) - } - - def HeaderBlock: Rule1[Ast.Header] = rule{ - Header ~ zeroOrMore(capture(WL) ~ Header ~> (_ + _)) ~ runSubParser{new Parser(_, indent, cursor).Body0} ~> { - (start: String, heads: Seq[String], body: Ast.Block) => Ast.Header(start + heads.mkString, body) - } - } - - def BlankLine = rule{ '\n' ~ zeroOrMore(' ') ~ &('\n') } - def IndentSpaces = rule{ indent.times(' ') ~ zeroOrMore(' ') } - def Indent = rule{ '\n' ~ IndentSpaces } - def LoneScalaChain: Rule2[Ast.Block.Text, Ast.Chain] = rule { - (push(offsetCursor) ~ capture(Indent) ~> ((i, x) => Ast.Block.Text(x, i))) ~ - ScalaChain ~ - IndentBlock ~> { - (chain: Ast.Chain, body: Ast.Block) => chain.copy(parts = chain.parts :+ body) - } - } - def IndentBlock = rule{ - &("\n") ~ - test(cursorNextIndent() > indent) ~ - runSubParser(new Parser(_, cursorNextIndent(), cursor).Body) - } - def IfHead = rule{ "@" ~ capture("if" ~ "(" ~ Expr ~ ")") } - def IfElse1 = rule{ - push(offsetCursor) ~ IfHead ~ BraceBlock ~ optional("else" ~ (BraceBlock | IndentBlock)) - } - def IfElse2 = rule{ - Indent ~ push(offsetCursor) ~ IfHead ~ IndentBlock ~ optional(Indent ~ "@else" ~ (BraceBlock | IndentBlock)) - } - def IfElse = rule{ - (IfElse1 | IfElse2) ~> ((a, b, c, d) => Ast.Block.IfElse(b, c, d, a)) - } - - def ForHead = rule{ - push(offsetCursor) ~ "@" ~ capture("for" ~ '(' ~ Enumerators ~ ')') - } - def ForLoop = rule{ - ForHead ~ - BraceBlock ~> ((a, b, c) => Ast.Block.For(b, c, a)) - } - def LoneForLoop = rule{ - (push(offsetCursor) ~ capture(Indent) ~> ((i, t) => Ast.Block.Text(t, i))) ~ - ForHead ~ - IndentBlock ~> - ((a, b, c) => Ast.Block.For(b, c, a)) - } - - def ScalaChain = rule { - push(offsetCursor) ~ Code ~ zeroOrMore(Extension) ~> { (a, b, c) => Ast.Chain(b, c, a)} - } - def Extension: Rule1[Ast.Chain.Sub] = rule { - (push(offsetCursor) ~ '.' ~ capture(Identifiers.Id) ~> ((x, y) => Ast.Chain.Prop(y, x))) | - (push(offsetCursor) ~ capture(TypeArgs2) ~> ((x, y) => Ast.Chain.TypeArgs(y, x))) | - (push(offsetCursor) ~ capture(ArgumentExprs2) ~> ((x, y) => Ast.Chain.Args(y, x))) | - BraceBlock - } - def Ws = WL - // clones of the version in ScalaSyntax, but without tailing whitespace or newlines - def TypeArgs2 = rule { '[' ~ Ws ~ Types ~ ']' } - def ArgumentExprs2 = rule { - '(' ~ Ws ~ - (optional(Exprs ~ ',' ~ Ws) ~ PostfixExpr ~ ':' ~ Ws ~ '_' ~ Ws ~ '*' ~ Ws | optional(Exprs) ) ~ - ')' - } - def BlockExpr2: Rule0 = rule { '{' ~ Ws ~ (CaseClauses | Block) ~ Ws ~ '}' } - def BraceBlock: Rule1[Ast.Block] = rule{ '{' ~ BodyNoBrace ~ '}' } - - def BodyItem(exclusions: String): Rule1[Seq[Ast.Block.Sub]] = rule{ - ForLoop ~> (Seq(_)) | - LoneForLoop ~> (Seq(_, _)) | - IfElse ~> (Seq(_)) | - LoneScalaChain ~> (Seq(_, _)) | - HeaderBlock ~> (Seq(_)) | - TextNot("@" + exclusions) ~> (Seq(_)) | - (push(offsetCursor) ~ capture(Indent) ~> ((i, x) => Seq(Ast.Block.Text(x, i)))) | - (push(offsetCursor) ~ capture(BlankLine) ~> ((i, x) => Seq(Ast.Block.Text(x, i)))) | - ScalaChain ~> (Seq(_: Ast.Block.Sub)) - } - def Body = rule{ BodyEx() } - def BodyNoBrace = rule{ BodyEx("}") } - def BodyEx(exclusions: String = "") = rule{ - push(offsetCursor) ~ oneOrMore(BodyItem(exclusions)) ~> {(i, x) => - Ast.Block(x.flatten, i) - } - } - def Body0 = rule{ - push(offsetCursor) ~ zeroOrMore(BodyItem("")) ~> {(i, x) => - Ast.Block(x.flatten, i) - } - } -} - -trait Ast{ - def offset: Int -} -object Ast{ - - /** - * @param parts The various bits of text and other things which make up this block - * @param offset - */ - case class Block(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 - case class For(generators: String, block: Block, offset: Int = 0) extends Block.Sub - case class IfElse(condition: String, block: Block, elseBlock: Option[Block], offset: Int = 0) extends Block.Sub - } - case class Header(front: String, block: Block, offset: Int = 0) extends Block.Sub with Chain.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 - 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 - } -} diff --git a/scalatex/api/src/main/scala/scalatex/stages/Trim.scala b/scalatex/api/src/main/scala/scalatex/stages/Trim.scala deleted file mode 100644 index 8993734..0000000 --- a/scalatex/api/src/main/scala/scalatex/stages/Trim.scala +++ /dev/null @@ -1,29 +0,0 @@ -package scalatex.stages -import acyclic.file - -/** - * 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, Int)){ - def apply(str: String) = { - val lines = str.split("\n", -1) - val offset = lines.iterator - .filter(_.length > 0) - .next() - .takeWhile(_ == ' ') - .length - val res = lines.iterator - .map(_.replaceFirst("\\s+$", "")) - .mkString("\n") - (res, offset) - } - def old(str: String) = { - val (res, offset) = this.apply(str) - res.split("\n", -1).map(_.drop(offset)).mkString("\n") - } -} diff --git a/scalatex/api/src/test/scala/scalatex/BasicTests.scala b/scalatex/api/src/test/scala/scalatex/BasicTests.scala deleted file mode 100644 index 4bc362c..0000000 --- a/scalatex/api/src/test/scala/scalatex/BasicTests.scala +++ /dev/null @@ -1,468 +0,0 @@ -package scalatex -import utest._ -import scala.collection.mutable.ArrayBuffer -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 - """ - ) - } - 'definitions{ - '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> - """ - ) - } - 'valDefVar{ - check( - tw(""" - Hello - @val x = 1 - World @x - @def y = "omg" - mooo - @y - """), - """ - Hello - World 1 - mooo - omg - """ - ) - } - 'classObjectTrait{ - check( - tw(""" - @trait Trait{ - def tt = 2 - } - Hello - @case object moo extends Trait{ - val omg = "wtf" - } - - @moo.toString - @moo.omg - @case class Foo(i: Int, s: String, b: Boolean) - TT is @moo.tt - @Foo(10, "10", true).toString - """), - """ - Hello - moo - wtf - TT is 2 - Foo(10, 10, true) - """ - ) - } - } - '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>WORLD<b>!!!</b>lol</h1> - <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 - } - """), - "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/scalatex/api/src/test/scala/scalatex/ErrorTests.scala b/scalatex/api/src/test/scala/scalatex/ErrorTests.scala deleted file mode 100644 index d8cd4f5..0000000 --- a/scalatex/api/src/test/scala/scalatex/ErrorTests.scala +++ /dev/null @@ -1,373 +0,0 @@ -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("@scala.math.cos('omg)"), - "type mismatch", - """ - twRuntimeErrors("@scala.math.cos('omg)"), - ^ - """ - ) - * - check( - twRuntimeErrors("@scala.math.cos[omg]('omg)"), - "not found: type omg", - """ - twRuntimeErrors("@scala.math.cos[omg]('omg)"), - ^ - """ - ) - * - 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("@Seq(1).map{(y: String) => omg}"), -// "type mismatch", -// """ -// twRuntimeErrors("@Seq(1).map{(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/scalatex/api/src/test/scala/scalatex/ParserTests.scala b/scalatex/api/src/test/scala/scalatex/ParserTests.scala deleted file mode 100644 index 9a4ee63..0000000 --- a/scalatex/api/src/test/scala/scalatex/ParserTests.scala +++ /dev/null @@ -1,424 +0,0 @@ -package scalatex - - -import org.parboiled2._ -import scalaParser.ScalaSyntax - -import scalatex.stages.{Trim, Parser, Ast} -import scalatex.stages.Ast.Block.{IfElse, For, Text} -import Ast.Chain.Args - -object ParserTests extends utest.TestSuite{ - import Ast._ - import utest._ - def check[T](input: String, parse: Parser => scala.util.Try[T], expected: T) = { - val parsed = parse(new Parser(input)).get - assert(parsed == expected) - } - def tests = TestSuite{ - 'Trim{ - def wrap(s: String) = "|" + s + "|" - * - { - val trimmed = wrap(stages.Trim.old(""" - 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.old( - """ - @{"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.old( - 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")) - * - 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{ - '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.Header( - "import math.abs\nimport math.sin", - Ast.Block( - Seq(Text("\n", 33), Text("\n", 34), Text("hello world", 35), Text("\n", 46)), - 33 - ) - ) - ) - } - 'caseclass{ - check( - """@case class Foo(i: Int, s: String) - """.stripMargin, - _.Header.run(), - "case class Foo(i: Int, s: String)" - ) - } - - } - 'Block{ - * - check("{i am a cow}", _.BraceBlock.run(), Block(Seq(Block.Text("i am a cow", 1)), 1)) - * - check("{i @am a @cow}", _.BraceBlock.run(), - Block(Seq( - Block.Text("i ", 1), - Chain("am",Seq(), 3), - Block.Text(" a ", 6), - Chain("cow",Seq(), 9) - ), 1) - ) - } - 'Chain{ - * - check("@omg.bbq[omg].fff[fff](123) ", _.ScalaChain.run(), - Chain("omg",Seq( - Chain.Prop("bbq", 4), - Chain.TypeArgs("[omg]", 8), - Chain.Prop("fff", 13), - Chain.TypeArgs("[fff]", 17), - Chain.Args("(123)", 22) - )) - ) - * - check("@omg{bbq}.cow(moo){a @b}\n", _.ScalaChain.run(), - Chain("omg",Seq( - Block(Seq(Text("bbq", 5)), 5), - Chain.Prop("cow", 9), - Chain.Args("(moo)", 13), - Block(Seq(Text("a ", 19), Chain("b", Nil, 21)), 19) - )) - ) - } - 'ControlFlow{ - 'for { - 'for - check( - "@for(x <- 0 until 3){lol}", - _.ForLoop.run(), - For("for(x <- 0 until 3)", Block(Seq(Text("lol", 21)), 21)) - ) - 'forBlock - check( - """ - |@for(x <- 0 until 3) - | lol""".stripMargin, - _.Body.run(), - Block(Seq( - Text("\n"), - For( - "for(x <- 0 until 3)", - Block(Seq(Text("\n ", 21), Text("lol", 24)), 21), - 1 - ) - )) - ) - 'forBlockBraces - check( - """ - |@for(x <- 0 until 3){ - | lol - |}""".stripMargin, - _.Body.run(), - Block(Seq( - Text("\n"), - For( - "for(x <- 0 until 3)", - Block(Seq(Text("\n ", 22), Text("lol", 25), Text("\n", 28)), 22), - 1 - ) - )) - ) - } - 'ifElse { - 'if - check( - "@if(true){lol}", - _.IfElse.run(), - IfElse("if(true)", Block(Seq(Text("lol", 10)), 10), None) - ) - 'ifElse - check( - "@if(true){lol}else{ omg }", - _.IfElse.run(), - IfElse("if(true)", Block(Seq(Text("lol", 10)), 10), Some(Block(Seq(Text(" omg ", 19)), 19))) - ) - 'ifBlock - check( - """ - |@if(true) - | omg""".stripMargin, - _.IfElse.run(), - IfElse("if(true)", Block(Seq(Text("\n ", 10), Text("omg", 13)), 10), None, 1) - ) - 'ifBlockElseBlock - check( - """ - |@if(true) - | omg - |@else - | wtf""".stripMargin, - _.IfElse.run(), - IfElse( - "if(true)", - Block(Seq(Text("\n ", 10), Text("omg", 13)), 10), - Some(Block(Seq(Text("\n ", 22), Text("wtf", 25)), 22)), - 1 - ) - ) - 'ifBlockElseBraceBlock - check( - """@if(true){ - | omg - |}else{ - | wtf - |}""".stripMargin, - _.IfElse.run(), - IfElse( - "if(true)", - Block(Seq(Text("\n ", 10), Text("omg", 13), Text("\n", 16)), 10), - Some(Block(Seq(Text("\n ", 23), Text("wtf", 26), Text("\n", 29)), 23)), - 0 - ) - ) - 'ifBlockElseBraceBlockNested - { - val res = Parser(Trim.old( - """ - @p - @if(true){ - Hello - }else{ - lols - } - """)) - val expected = - Block(Vector( - Text("\n"), - Chain("p",Vector(Block(Vector( - Text("\n ", 3), - IfElse("if(true)", - Block(Vector( - Text("\n ", 16), Text("Hello", 21), Text("\n ", 26) - ), 16), - Some(Block(Vector( - Text("\n ", 35), Text("lols", 40), Text("\n ", 44) - ), 35)), - 6 - )), 3)), 1), - Text("\n", 48) - )) - assert(res == expected) - } - 'ifElseBlock - check( - """@if(true){ - | omg - |}else - | wtf""".stripMargin, - _.IfElse.run(), - IfElse( - "if(true)", - Block(Seq(Text("\n ", 10), Text("omg", 13), Text("\n", 16)), 10), - Some(Block(Seq(Text("\n ", 22), Text("wtf", 25)), 22)) - ) - ) - } - - } - 'Body{ - 'indents - check( - """ - |@omg - | @wtf - | @bbq - | @lol""".stripMargin, - _.Body.run(), - Block(Seq( - Text("\n"), - Chain("omg",Seq(Block(Seq( - Text("\n ", 5), - Chain("wtf",Seq(Block(Seq( - Text("\n ", 7), - Chain("bbq",Seq(Block(Seq( - Text("\n ", 9), - Chain("lol",Seq(), 16) - ), 9)), 12) - ), 7)), 8) - ), 5)), 1) - )) - ) - 'dedents - check( - """ - |@omg - | @wtf - |@bbq""".stripMargin, - _.Body.run(), - Block(Seq( - Text("\n"), - Chain("omg",Seq(Block( - Seq( - Text("\n ", 5), - Chain("wtf",Seq(), 8) - ), - 5 - )), 1), - Text("\n", 12), - Chain("bbq", Seq(), 13) - )) - ) - 'braces - check( - """ - |@omg{ - | @wtf - |} - |@bbq""".stripMargin, - _.Body.run(), - Block(Seq( - Text("\n"), - Chain("omg",Seq(Block( - Seq( - Text("\n ", 6), - Chain("wtf",Seq(), 9), - Text("\n", 13) - ), - 6 - )), 1), - Text("\n", 15), - Chain("bbq", Seq(), 16) - )) - ) - 'dedentText - check( - """ - |@omg("lol", 1, 2) - | @wtf - |bbq""".stripMargin, - _.Body.run(), - Block(Seq( - Text("\n"), - Chain("omg",Seq( - Args("""("lol", 1, 2)""", 5), - Block(Seq( - Text("\n ", 18), - Chain("wtf",Seq(), 21) - ), 18) - ), 1), - Text("\n", 25), - Text("bbq", 26) - )) - ) - * - check( - """ - |@omg("lol", - |1, - | 2 - | ) - | wtf - |bbq""".stripMargin, - _.Body.run(), - Block(Seq( - Text("\n", 0), - Chain("omg",Seq( - Args("(\"lol\",\n1,\n 2\n )", 5), - Block(Seq( - Text("\n ", 30), Text("wtf", 33) - ), 30) - ), 1), - Text("\n", 36), - Text("bbq", 37) - ), 0) - ) - 'codeBlock - check( - """@{ - | val omg = "omg" - | omg * 2 - |}""".stripMargin, - _.Code.run(), - """{ - | val omg = "omg" - | omg * 2 - |}""".stripMargin - ) - 'codeBlocks - check( - """ - |@{"lol" * 3} - |@{ - | val omg = "omg" - | omg * 2 - |}""".stripMargin, - _.Body.run(), - Block(Seq( - Text("\n"), - Chain("{\"lol\" * 3}", Seq(), 1), - Text("\n", 13), - Chain("""{ - | val omg = "omg" - | omg * 2 - |}""".stripMargin, - Seq(), - 14 - ) - )) - ) - } -// 'Test{ -// check( -// "@{() => ()}", -// _.Code.run(), -// "" -// ) -// } - } -} - - - diff --git a/scalatex/api/src/test/scala/scalatex/TestUtil.scala b/scalatex/api/src/test/scala/scalatex/TestUtil.scala deleted file mode 100644 index 5a72677..0000000 --- a/scalatex/api/src/test/scala/scalatex/TestUtil.scala +++ /dev/null @@ -1,16 +0,0 @@ -package scalatex - -import utest._ - - -object TestUtil { - implicit def stringify(f: scalatags.Text.all.Frag) = f.render - def check(rendered: String*) = { - val collapsed = rendered.map(collapse) - val first = collapsed(0) - assert(collapsed.forall(_ == first)) - } - def collapse(s: String): String = { - s.replaceAll("[ \n]", "") - } -} |