From 52373d64b86ed514998ff5e6a128bf26b77e9f2e Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 3 Nov 2014 01:01:00 -0800 Subject: WIP --- .../src/main/scala/scalatex/ScalatexParser.scala | 63 +++++++++++++++++--- scalatexApi/src/test/scala/scalatex/Main.scala | 58 ------------------ .../src/test/scala/scalatex/ParserTests.scala | 69 ++++++++++++++++++++++ 3 files changed, 123 insertions(+), 67 deletions(-) delete mode 100644 scalatexApi/src/test/scala/scalatex/Main.scala create mode 100644 scalatexApi/src/test/scala/scalatex/ParserTests.scala (limited to 'scalatexApi') diff --git a/scalatexApi/src/main/scala/scalatex/ScalatexParser.scala b/scalatexApi/src/main/scala/scalatex/ScalatexParser.scala index 406f4cd..721af40 100644 --- a/scalatexApi/src/main/scala/scalatex/ScalatexParser.scala +++ b/scalatexApi/src/main/scala/scalatex/ScalatexParser.scala @@ -7,31 +7,76 @@ trait Ast{ def offset: Int } object Ast{ - case class Block(parts: Seq[Block.Sub], offset: Int = 0) extends Chain.Sub + case class Block(parts: Seq[Block.Sub], offset: Int = 0) extends Chain.Sub{ + println("Init Block") + } object Block{ trait Sub - case class Text(txt: String, offset: Int = 0) extends Block.Sub + case class Text(txt: String, offset: Int = 0) extends Block.Sub{ + println("Init Text " + txt) + } } case class Code(code: String, offset: Int = 0) - case class Chain(lhs: Code, parts: Seq[Chain.Sub], offset: Int = 0) extends Block.Sub + case class Chain(lhs: Code, parts: Seq[Chain.Sub], offset: Int = 0) extends Block.Sub{ + println("Init Chain " + lhs) + } object Chain{ trait Sub 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("@@", "@"))) } +class ScalatexParser(input: ParserInput, indent: Int = 0) extends ScalaSyntax(input) { + println("INDENT " + indent) + def TextNot(chars: String) = rule { + capture(oneOrMore(noneOf(chars + "\n"))) ~> { + 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 BlankLine = rule{ run(println("BL A " + (cursorChar.toInt, '\n'.toInt))) ~ '\n' ~ run(println("BL B")) ~ zeroOrMore(' ') ~ run(println("BL C")) ~ &('\n') ~ run(println("BL D")) } + def Indent = rule{ run(println("Indent A " + cursorChar.toInt)) ~ '\n' ~ run(println("Indent A")) ~ indent.times(' ') ~ run(println("Indent A")) ~ zeroOrMore(' ') } + def LoneScalaChain: Rule1[Ast.Chain] = rule { + run(println("LSC Indent")) ~ Indent ~ + run(println("LSC SC")) ~ ScalaChain ~ + zeroOrMore(BlankLine) ~ + run(println("LSC NewLine")) ~ + runSubParser { + new ScalatexParser(_, indent + 2).Body + } ~> { (chain: Ast.Chain, body: Ast.Block) => + println("chain.copy " + body) + chain.copy(parts = chain.parts :+ body) + } + } + + def newInput(s: String, x: ParserInput): String = { + def newInput = '\n' + s + x.sliceString(0, x.length) + println(newInput.split("\n").map("|" + _ + "|").mkString("\n")) + newInput + } + 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 + (capture(!BlockExpr ~ ArgumentExprs) ~> (Ast.Chain.Args(_))) | + TBlock } def TBlock = rule{ '{' ~ Body ~ '}' } - def Body = rule{ zeroOrMore(TextNot("@}") | ScalaChain) ~> (x => Ast.Block(x)) } + def Body = rule{ + run(println("BODY")) ~ + zeroOrMore( + run(println("Body LSC")) ~ LoneScalaChain | + run(println("Body TextNot")) ~ TextNot("@}") | + run(println("Body Indent")) ~ (capture(Indent) ~> (Ast.Block.Text(_))) | + run(println("Body BlankLine")) ~ (capture(BlankLine) ~> (Ast.Block.Text(_))) +// | ScalaChain + ) ~> {x => + println("BODY ENDED: " + x) + Ast.Block(x) + } + } } diff --git a/scalatexApi/src/test/scala/scalatex/Main.scala b/scalatexApi/src/test/scala/scalatex/Main.scala deleted file mode 100644 index fa0d213..0000000 --- a/scalatexApi/src/test/scala/scalatex/Main.scala +++ /dev/null @@ -1,58 +0,0 @@ -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))) - )) - ) - } - } - -} - - diff --git a/scalatexApi/src/test/scala/scalatex/ParserTests.scala b/scalatexApi/src/test/scala/scalatex/ParserTests.scala new file mode 100644 index 0000000..34c6fdb --- /dev/null +++ b/scalatexApi/src/test/scala/scalatex/ParserTests.scala @@ -0,0 +1,69 @@ +package scalatex + + +import org.parboiled2._ +import torimatomeru.ScalaSyntax + +object ParserTests 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))) + )) + ) + } + 'Body{ + + val str = + """ + |@omg + | @wtf + | @bbq + | @lol + """.stripMargin + new ScalatexParser(str).Body.run() + } + } + +} + + -- cgit v1.2.3