From 6576d6a6e74e3807db951450d56434a5d0cf25c3 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 17 Nov 2014 02:16:11 -0800 Subject: operators which start with `:` will no longer be mistaken for type ascriptions, since now we're using `TypeColon` which checks for trailing operators before succeeding --- .../src/main/scala/scalaparser/ScalaSyntax.scala | 38 +++++++++++++--------- .../src/test/scala/scalaparser/SyntaxTest.scala | 21 +++++++++++- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/scalatexApi/src/main/scala/scalaparser/ScalaSyntax.scala b/scalatexApi/src/main/scala/scalaparser/ScalaSyntax.scala index 9349a28..bac7cc3 100644 --- a/scalatexApi/src/main/scala/scalaparser/ScalaSyntax.scala +++ b/scalatexApi/src/main/scala/scalaparser/ScalaSyntax.scala @@ -15,7 +15,8 @@ import org.parboiled2._ * consume whitespace. * * The vast majority of terminals will consume newlines; only rules - * which occur in {} blocks won't have their terminals consume newlines. + * which occur in {} blocks won't have their terminals consume newlines, + * and only the *last* terminal in the rule will be affected. * That's why the parser does terminals-consume-newlines-by-default, * and leaves it up to the dev to thread the `G` variable where-ever * we want the opposite behavior. @@ -61,7 +62,7 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif */ def StrW(s: String, G: B): R0 = rule { str(s) ~ W(G) } - + def TypeColon = rule{ ":" ~ !Basic.OperatorChar } def pos = cursor -> cursorChar @@ -127,7 +128,9 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif } def RefineStat = rule { "type" ~ TypeDef(false) | Dcl(false) | MATCH } def TypePat = rule { CompoundType() } - def Ascription(G: B = t) = rule { ":" ~ (InfixType(G) | oneOrMore(Annotation(G)) | "_" ~ StrW("*", G)) } + def Ascription(G: B = t) = rule { + ":" ~ ("_" ~ StrW("*", G) | InfixType(G) | oneOrMore(Annotation(G))) + } def ParamType = rule { "=>" ~ Type() | Type() ~ "*" | Type() } @@ -175,6 +178,7 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif } + def Exprs: R0 = rule { oneOrMore(Expr()).separatedBy(',') } def ArgumentExprs(G: B = t): R0 = rule { '(' ~ optional(Exprs ~ optional(':' ~ '_' ~ '*')) ~ StrW(")", G) | @@ -202,9 +206,11 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def Pattern: R0 = rule { oneOrMore(Pattern1).separatedBy('|') } - def Pattern1: R0 = rule { '_' ~ ':' ~ TypePat | VarId() ~ ':' ~ TypePat | Pattern2 } + def Pattern1: R0 = rule { + '_' ~ TypeColon ~ TypePat |VarId() ~ TypeColon ~ TypePat | Pattern2 + } def Pattern2: R0 = rule { - VarId() ~ "@" ~ Pattern3 | Pattern3 | VarId() + VarId() ~ "@" ~ Pattern3 | Pattern3 | VarId() } def Pattern3: R0 = rule { SimplePattern ~ zeroOrMore(Id() ~ SimplePattern) @@ -234,19 +240,19 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif optional(">:" ~ Type()) ~ optional("<:" ~ Type()) ~ zeroOrMore("<%" ~ Type()) ~ - zeroOrMore(':' ~ Type()) + zeroOrMore(TypeColon ~ Type()) } def ParamClauses: R0 = rule { zeroOrMore(ParamClause) ~ optional(optional(Newline) ~ '(' ~ "implicit" ~ Params ~ ')') } def ParamClause: R0 = rule { optional(Newline) ~ '(' ~ optional(Params) ~ ')' } def Params: R0 = rule { zeroOrMore(Param).separatedBy(',') } - def Param: R0 = rule { zeroOrMore(Annotation()) ~ Id() ~ optional(':' ~ ParamType) ~ optional('=' ~ Expr()) } + def Param: R0 = rule { zeroOrMore(Annotation()) ~ Id() ~ optional(TypeColon ~ ParamType) ~ optional('=' ~ Expr()) } def ClassParamClauses(G: B = t): R0 = rule { zeroOrMore(ClassParamClause(G)) ~ optional(optional(Newline) ~ '(' ~ "implicit" ~ ClassParam ~ StrW(")", G)) } def ClassParamClause(G: B = t): R0 = rule { optional(Newline) ~ '(' ~ optional(ClassParams) ~ StrW(")", G) } def ClassParams: R0 = rule { oneOrMore(ClassParam).separatedBy(',') } - def ClassParam: R0 = rule { zeroOrMore(Annotation()) ~ optional(zeroOrMore(Modifier) ~ ("val" | "var")) ~ Id() ~ ":" ~ ParamType ~ optional("=" ~ Expr()) } + def ClassParam: R0 = rule { zeroOrMore(Annotation()) ~ optional(zeroOrMore(Modifier) ~ ("val" | "var")) ~ Id() ~ TypeColon ~ ParamType ~ optional("=" ~ Expr()) } def Bindings: R0 = rule { '(' ~ oneOrMore(Binding).separatedBy(',') ~ ')' } - def Binding: R0 = rule { (Id() | '_') ~ optional(':' ~ Type()) } + def Binding: R0 = rule { (Id() | '_') ~ optional(TypeColon ~ Type()) } def Modifier: R0 = rule { LocalModifier | AccessModifier | "override" } def LocalModifier: R0 = rule { "abstract" | "final" | "sealed" | "implicit" | "lazy" } @@ -272,7 +278,7 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif MATCH } - def SelfType: R0 = rule { "this" ~ ':' ~ Type() ~ "=>" | Id() ~ optional(':' ~ Type()) ~ "=>" } + def SelfType: R0 = rule { "this" ~ TypeColon ~ Type() ~ "=>" | Id() ~ optional(TypeColon ~ Type()) ~ "=>" } def Import(G: B = t): R0 = rule { "import" ~ oneOrMore(ImportExpr(G)).separatedBy(',') } @@ -286,9 +292,9 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif "def" ~ FunDcl(G) | "type" ~ zeroOrMore(Newline) ~ TypeDcl(G) } - def ValDcl(G: B = t): R0 = rule { Ids ~ ':' ~ Type(G) } - def VarDcl(G: B = t): R0 = rule { Ids ~ ':' ~ Type(G) } - def FunDcl(G: B = t): R0 = rule { FunSig(false) ~ optional(WL ~ ':' ~ Type(G)) } + def ValDcl(G: B = t): R0 = rule { Ids ~ TypeColon ~ Type(G) } + def VarDcl(G: B = t): R0 = rule { Ids ~ TypeColon ~ Type(G) } + def FunDcl(G: B = t): R0 = rule { FunSig(false) ~ optional(WL ~ TypeColon ~ Type(G)) } def FunSig(G: B = t): R0 = rule { Id() ~ optional(FunTypeParamClause) ~ ParamClauses } def TypeDcl(G: B = t): R0 = rule { Id(false) ~ @@ -300,13 +306,13 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def PatVarDef(G: B = t): R0 = rule { "val" ~ PatDef(G) | "var" ~ VarDef(G) } def Def(G: B = t): R0 = rule { "def" ~ FunDef(G) | "type" ~ zeroOrMore(Newline) ~ TypeDef(G) | PatVarDef(G) | TmplDef(G) } - def PatDef(G: B = t): R0 = rule { oneOrMore(Pattern2).separatedBy(',') ~ optional(':' ~ Type()) ~ '=' ~ Expr(G) } - def VarDef(G: B = t): R0 = rule { Ids ~ ':' ~ Type() ~ '=' ~ '_' | PatDef(G) } + def PatDef(G: B = t): R0 = rule { oneOrMore(Pattern2).separatedBy(',') ~ optional(TypeColon ~ Type()) ~ '=' ~ Expr(G) } + def VarDef(G: B = t): R0 = rule { Ids ~ TypeColon ~ Type() ~ '=' ~ '_' | PatDef(G) } def FunDef(G: B = t): R0 = rule { "this" ~ ParamClause ~ ParamClauses ~ ('=' ~ ConstrExpr | optional(Newline) ~ ConstrBlock) | FunSig() ~ ( - optional(':' ~ Type()) ~ '=' ~ optional("macro") ~ Expr(G) | + optional(TypeColon ~ Type()) ~ '=' ~ optional("macro") ~ Expr(G) | optional(Newline) ~ '{' ~ Block ~ StrW("}", G) ) } diff --git a/scalatexApi/src/test/scala/scalaparser/SyntaxTest.scala b/scalatexApi/src/test/scala/scalaparser/SyntaxTest.scala index 607bb55..1f3bf02 100644 --- a/scalatexApi/src/test/scala/scalaparser/SyntaxTest.scala +++ b/scalatexApi/src/test/scala/scalaparser/SyntaxTest.scala @@ -13,12 +13,13 @@ object SyntaxTest extends TestSuite{ case Failure(f: ParseError) => println(f.position) println(f.formatExpectedAsString) - println(f.formatTraces) +// println(f.formatTraces) throw new Exception(f.position + "\t" + f.formatTraces) case Success(parsed) => assert(parsed == input) } } + println("running") def tests = TestSuite{ 'unit { * - check( @@ -303,6 +304,24 @@ object SyntaxTest extends TestSuite{ |} """.stripMargin ) + * - check( + """ + |object K{ + | a( + | 1: _* + | ) + |} + """.stripMargin + ) + * - check( + """ + |object P{ + | tree match { + | case stats :+ expr => 1 + | } + |} + """.stripMargin + ) } def checkFile(path: String) = check(io.Source.fromFile(path).mkString) 'file{ -- cgit v1.2.3