From c7d96c649cf2b2832a597df405f3c1afcd674009 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Wed, 5 Nov 2014 20:42:42 -0800 Subject: A bunch of error tests work, trimming is causing problems with multi-line error messages --- .../src/main/scala/scalatex/stages/Compiler.scala | 28 +++++- .../src/main/scala/scalatex/stages/Parser.scala | 19 ++-- .../src/test/scala/scalatex/ErrorTests.scala | 104 ++++++++++++--------- .../src/test/scala/scalatex/ParserTests.scala | 54 +++++------ 4 files changed, 122 insertions(+), 83 deletions(-) (limited to 'scalatexApi/src') diff --git a/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala b/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala index 7d1492c..9c1c3c4 100644 --- a/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala +++ b/scalatexApi/src/main/scala/scalatex/stages/Compiler.scala @@ -15,23 +15,43 @@ object Compiler{ import c.universe._ def fragType = tq"scalatags.Text.all.Frag" + def incPosRec(trees: c.Tree, offset: Int): trees.type = { + println(s"incPosRec\t$offset\t$trees") + trees.foreach(incPos(_, offset)) + trees + } + def incPos(tree: c.Tree, offset: Int): tree.type = { + println(s"incPos\t$offset\t$tree") + 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 + } + println(template) def compileChain(code: String, parts: Seq[Ast.Chain.Sub], offset: Int): c.Tree = { println("CODE " + code) - parts.foldLeft(c.parse(code)){ - case (curr, Ast.Chain.Prop(str, offset2)) => q"$curr.${TermName(str)}" + 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") - Apply(curr, args) + 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") - TypeApply(curr, args) + incPos(TypeApply(curr, args.map(incPosRec(_, offset2 - 2))), offset2) case (curr, Ast.Block(parts, offset)) => q"$curr(..${compileBlock(parts, offset)})" case (curr, Ast.Header(header, block, offset)) => q"$curr(${compileHeader(header, block, offset)})" } + out.foreach(o => println(o.pos + "\t" + o)) + out } def compileBlock(parts: Seq[Ast.Block.Sub], offset: Int): Seq[c.Tree] = { parts.map{ diff --git a/scalatexApi/src/main/scala/scalatex/stages/Parser.scala b/scalatexApi/src/main/scala/scalatex/stages/Parser.scala index 7b694da..45f82e0 100644 --- a/scalatexApi/src/main/scala/scalatex/stages/Parser.scala +++ b/scalatexApi/src/main/scala/scalatex/stages/Parser.scala @@ -11,12 +11,13 @@ import Util._ * 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 = { +object Parser extends ((String, Int) => Ast.Block){ + def apply(input: String, offset: Int = 0): Ast.Block = { new Parser(input).Body.run().get } } -class Parser(input: ParserInput, indent: Int = 0) extends ScalaSyntax(input) { +class Parser(input: ParserInput, indent: Int = 0, offset: Int = 0) extends ScalaSyntax(input) { + def offsetCursor = offset + cursor val txt = input.sliceString(0, input.length) val indentTable = txt.split('\n').map{ s => if (s.trim == "") -1 @@ -45,7 +46,7 @@ class Parser(input: ParserInput, indent: Int = 0) extends ScalaSyntax(input) { } def HeaderBlock: Rule1[Ast.Header] = rule{ - Header ~ zeroOrMore(capture(NewlineS) ~ Header ~> (_ + _)) ~ runSubParser{new Parser(_, indent).Body0} ~> { + Header ~ zeroOrMore(capture(NewlineS) ~ Header ~> (_ + _)) ~ runSubParser{new Parser(_, indent, cursor).Body0} ~> { (start: String, heads: Seq[String], body: Ast.Block) => Ast.Header(start + heads.mkString, body) } } @@ -63,7 +64,7 @@ class Parser(input: ParserInput, indent: Int = 0) extends ScalaSyntax(input) { def IndentBlock = rule{ &("\n") ~ test(cursorNextIndent() > indent) ~ - runSubParser(new Parser(_, cursorNextIndent()).Body) + runSubParser(new Parser(_, cursorNextIndent(), cursor).Body) } def IfHead = rule{ "@" ~ capture("if" ~ "(" ~ Expr ~ ")") } def IfElse1 = rule{ @@ -91,12 +92,12 @@ class Parser(input: ParserInput, indent: Int = 0) extends ScalaSyntax(input) { } def ScalaChain = rule { - Code ~ zeroOrMore(Extension) ~> {Ast.Chain(_, _)} + push(offsetCursor) ~ Code ~ zeroOrMore(Extension) ~> { (a, b, c) => Ast.Chain(b, c, a)} } def Extension: Rule1[Ast.Chain.Sub] = rule { - ('.' ~ capture(Id) ~> (Ast.Chain.Prop(_))) | - (capture(TypeArgs2) ~> (Ast.Chain.TypeArgs(_))) | - (capture(ArgumentExprs2) ~> (Ast.Chain.Args(_))) | + (push(offsetCursor) ~ '.' ~ capture(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 = Whitespace diff --git a/scalatexApi/src/test/scala/scalatex/ErrorTests.scala b/scalatexApi/src/test/scala/scalatex/ErrorTests.scala index 4a2b5c8..7b40c40 100644 --- a/scalatexApi/src/test/scala/scalatex/ErrorTests.scala +++ b/scalatexApi/src/test/scala/scalatex/ErrorTests.scala @@ -1,35 +1,35 @@ -//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{ -// -// +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""", @@ -40,7 +40,7 @@ // ) // // 'chained{ -// 'properties { + 'properties { // * - check( // twRuntimeErrors("omg @math.lol lol"), // """object lol is not a member of package math""", @@ -133,18 +133,34 @@ // """ // ) // * - 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", +// twRuntimeErrors("@scala.math.cos('omg)"), +// "type mismatch", // """ -// @scala.math.abs(-10).tdo(10).sum.z -// ^ +// 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)}"), @@ -353,5 +369,5 @@ // """ // ) // } -// } -//} + } +} diff --git a/scalatexApi/src/test/scala/scalatex/ParserTests.scala b/scalatexApi/src/test/scala/scalatex/ParserTests.scala index 150f766..401cfae 100644 --- a/scalatexApi/src/test/scala/scalatex/ParserTests.scala +++ b/scalatexApi/src/test/scala/scalatex/ParserTests.scala @@ -123,28 +123,28 @@ object ParserTests extends utest.TestSuite{ * - check("{i @am a @cow}", _.BraceBlock.run(), Block(Seq( Block.Text("i "), - Chain("am",Seq()), + Chain("am",Seq(), 3), Block.Text(" a "), - Chain("cow",Seq()) + Chain("cow",Seq(), 9) )) ) } 'Chain{ * - check("@omg.bbq[omg].fff[fff](123) ", _.ScalaChain.run(), Chain("omg",Seq( - Chain.Prop("bbq"), - Chain.TypeArgs("[omg]"), - Chain.Prop("fff"), - Chain.TypeArgs("[fff]"), - Chain.Args("(123)") + 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(Block.Text("bbq"))), - Chain.Prop("cow"), - Chain.Args("(moo)"), - Block(Seq(Block.Text("a "), Chain("b", Nil))) + Chain.Prop("cow", 9), + Chain.Args("(moo)", 13), + Block(Seq(Block.Text("a "), Chain("b", Nil, 21))) )) ) } @@ -240,7 +240,7 @@ object ParserTests extends utest.TestSuite{ Text("\n "), Text("Hello"), Text("\n "))), Some(Block(Vector( Text("\n "), Text("lols"), Text("\n ")))) - ))))), + )))), 1), Text("\n") )) assert(res == expected) @@ -276,10 +276,10 @@ object ParserTests extends utest.TestSuite{ Text("\n "), Chain("bbq",Seq(Block(Seq( Text("\n "), - Chain("lol",Seq()) - )))) - )))) - )))) + Chain("lol",Seq(), 16) + ))), 12) + ))), 8) + ))), 1) )) ) 'dedents - check( @@ -293,11 +293,11 @@ object ParserTests extends utest.TestSuite{ Chain("omg",Seq(Block( Seq( Text("\n "), - Chain("wtf",Seq()) + Chain("wtf",Seq(), 8) ) - ))), + )), 1), Text("\n"), - Chain("bbq", Seq()) + Chain("bbq", Seq(), 13) )) ) 'braces - check( @@ -312,12 +312,12 @@ object ParserTests extends utest.TestSuite{ Chain("omg",Seq(Block( Seq( Text("\n "), - Chain("wtf",Seq()), + Chain("wtf",Seq(), 9), Text("\n") ) - ))), + )), 1), Text("\n"), - Chain("bbq", Seq()) + Chain("bbq", Seq(), 16) )) ) 'dedentText - check( @@ -329,11 +329,12 @@ object ParserTests extends utest.TestSuite{ Block(Seq( Text("\n"), Chain("omg",Seq( - Args("""("lol", 1, 2)"""), + Args("""("lol", 1, 2)""", 5), Block(Seq( Text("\n "), - Chain("wtf",Seq()))) - )), + Chain("wtf",Seq(), 21) + )) + ), 1), Text("\n"), Text("bbq") )) @@ -368,13 +369,14 @@ object ParserTests extends utest.TestSuite{ _.Body.run(), Block(Seq( Text("\n"), - Chain("{\"lol\" * 3}", Seq()), + Chain("{\"lol\" * 3}", Seq(), 1), Text("\n"), Chain("""{ | val omg = "omg" | omg * 2 |}""".stripMargin, - Seq() + Seq(), + 14 ) )) ) -- cgit v1.2.3