From 83f9ded6d01e4044b979a4cf840132d6202268bb Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Tue, 2 Dec 2014 04:07:37 -0800 Subject: improved perf a bunch --- book/src/main/resources/css/side-menu.css | 10 +- book/src/main/scala/book/Book.scala | 5 +- build.sbt | 7 +- .../src/main/scala/scrollmenu/ScrollMenu.scala | 61 +- .../src/main/scala/scalaParser/ScalaSyntax.scala | 679 +++++------ .../scala/scalaParser/syntax/Identifiers.scala | 39 +- .../main/scala/scalaParser/syntax/Literals.scala | 27 +- scalaParser/src/test/resources/test.scala | 2 - .../src/test/scala/scalaParser/SyntaxTest.scala | 1226 +++++++------------- 9 files changed, 749 insertions(+), 1307 deletions(-) delete mode 100644 scalaParser/src/test/resources/test.scala diff --git a/book/src/main/resources/css/side-menu.css b/book/src/main/resources/css/side-menu.css index 074da25..6439a28 100755 --- a/book/src/main/resources/css/side-menu.css +++ b/book/src/main/resources/css/side-menu.css @@ -322,11 +322,11 @@ code{ } .menu-item-list ul, .menu-item-list a{ - -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - -ms-transition: all 0.2s ease-in-out; - -o-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; + -webkit-transition: max-height 0.2s ease; + -moz-transition: max-height 0.2s ease; + -ms-transition: max-height 0.2s ease; + -o-transition: max-height 0.2s ease; + transition: max-height 0.2s ease; overflow: hidden } diff --git a/book/src/main/scala/book/Book.scala b/book/src/main/scala/book/Book.scala index 09be8ee..d023d56 100644 --- a/book/src/main/scala/book/Book.scala +++ b/book/src/main/scala/book/Book.scala @@ -25,6 +25,7 @@ object Book { "META-INF/resources/webjars/font-awesome/4.2.0/fonts/fontawesome-webfont.woff", "css/side-menu.css", "example-opt.js", + "example-opt.js.map", "webpage/weather.js", "favicon.svg", "favicon.png" @@ -71,7 +72,6 @@ object Book { script(raw(googleAnalytics)) ), body( - onload:=s"Controller().main($data)", div(id:="layout")( a(href:="#menu", id:="menuLink", cls:="menu-link")( span @@ -83,7 +83,8 @@ object Book { div(id:="main-box")( txt ) - ) + ), + script(raw(s"Controller().main($data)")) ) ) ).render diff --git a/build.sbt b/build.sbt index 3a314e9..1b095e2 100644 --- a/build.sbt +++ b/build.sbt @@ -56,9 +56,12 @@ lazy val book = Project( "org.webjars" % "font-awesome" % "4.2.0", "com.lihaoyi" %%% "upickle" % "0.2.5" ), - (resources in Compile) += { + (resources in Compile) ++= { (fullOptJS in (demos, Compile)).value - (artifactPath in (demos, Compile, fullOptJS)).value + Seq( + (artifactPath in (demos, Compile, fullOptJS)).value, + new java.io.File((artifactPath in (demos, Compile, fullOptJS)).value.getPath + ".map") + ) }, (unmanagedResourceDirectories in Compile) ++= (unmanagedResourceDirectories in (demos, Compile)).value, diff --git a/examples/demos/src/main/scala/scrollmenu/ScrollMenu.scala b/examples/demos/src/main/scala/scrollmenu/ScrollMenu.scala index 6378451..b35ed2e 100644 --- a/examples/demos/src/main/scala/scrollmenu/ScrollMenu.scala +++ b/examples/demos/src/main/scala/scrollmenu/ScrollMenu.scala @@ -1,7 +1,7 @@ package scrollmenu import org.scalajs.dom - +import org.scalajs.dom.extensions._ import scala.scalajs.js import scalatags.JsDom.all._ @@ -32,7 +32,7 @@ class ScrollSpy(structure: Tree[String], val children = t.children.map(recurse(_, depth + 1)) Tree( MenuNode( - curr(ul(marginLeft := "15px",children.map(_.value.frag))).render, + curr(ul(paddingLeft := "15px",children.map(_.value.frag))).render, Controller.munge(t.value), originalI, if (children.length > 0) children.map(_.value.end).max else originalI + 1 @@ -84,16 +84,23 @@ class ScrollSpy(structure: Tree[String], .maxHeight = (mn.end - mn.start + 1) * 44 + "px" } private[this] var scrolling = false - def apply() = { + private[this] var scrollTop = -1 + def apply(): Unit = { if (!scrolling) { - println("Scroll...") scrolling = true - dom.requestAnimationFrame((d: Double) => start()) + scrollTop = main.scrollTop + dom.setTimeout({() => + scrolling = false + if (scrollTop == main.scrollTop) start() + else apply() + }, + 75 + ) } } private[this] var previousWin: MenuNode = null private[this] def start(force: Boolean = false) = { - scrolling = false + def scroll(el: dom.Element) = { val rect = el.getBoundingClientRect() if (rect.top <= 0) @@ -119,36 +126,40 @@ class ScrollSpy(structure: Tree[String], val winPath = walkIndex(domTrees) val winItem = winPath.last.value - def walkTree(tree: Tree[MenuNode], indices: List[Tree[MenuNode]]): Unit = { - println("WalkTree") - for(Tree(mn, children) <- indices){ + def walkTree(indices: List[Tree[MenuNode]]): Int = indices match { + case Nil => 0 + case (Tree(mn, children) :: rest) => + mn.frag.classList.remove("hide") mn.frag.classList.remove("selected") - setFullHeight(mn) - mn.frag.children(0).classList.add("pure-menu-selected") - for(child <- children if child.value.frag != indices(1).value.frag){ - val childFrag = child.value.frag - childFrag.children(0).classList.remove("pure-menu-selected") - childFrag.classList.add("hide") - if(!open) - childFrag.children(1).asInstanceOf[dom.HTMLElement].style.maxHeight = "0px" + mn.frag.children(0).classList.add("pure-menu-selected") + for { + child <- children + if !indices.headOption.exists(_.value.frag == child.value.frag) + } walkHide(child) + + val size = walkTree(rest) + children.length + mn.frag.children(1).asInstanceOf[dom.HTMLElement].style.maxHeight = size * 44 + "px" + size + } - if (child.value.start < winItem.start) childFrag.classList.add("selected") - else childFrag.classList.remove("selected") - } - } + def walkHide(tree: Tree[MenuNode]): Unit = { + val frag = tree.value.frag + frag.children(0).classList.remove("pure-menu-selected") + frag.classList.add("hide") + frag.children(1).asInstanceOf[dom.HTMLElement].style.maxHeight = "0px" + if (tree.value.start < winItem.start) frag.classList.add("selected") + else frag.classList.remove("selected") + tree.children.foreach(walkHide) } if (winItem != previousWin || force){ scroll(winItem.frag.children(0)) dom.history.replaceState(null, null, "#" + winItem.id) previousWin = winItem - walkTree(domTrees, winPath) + walkTree(winPath) } - } - - } \ No newline at end of file diff --git a/scalaParser/src/main/scala/scalaParser/ScalaSyntax.scala b/scalaParser/src/main/scala/scalaParser/ScalaSyntax.scala index 0421c60..de9f039 100644 --- a/scalaParser/src/main/scala/scalaParser/ScalaSyntax.scala +++ b/scalaParser/src/main/scala/scalaParser/ScalaSyntax.scala @@ -6,10 +6,26 @@ import org.parboiled2._ /** * Parser for Scala syntax. + * + * The `G` parameter that gets passed in to each rule stands for + * "Greedy", and determines whether or not that rule is to consume + * newlines after the last terminal in that rule. We need to pass it + * everywhere so it can go all the way to the last terminal deep + * inside the parse tree, which can then decide whether or not to + * consume whitespace. + * + * The vast majority of terminals will consume newlines; only rules + * 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. */ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identifiers with Literals { // Aliases for common things. These things are used in almost every parser // in the file, so it makes sense to keep them short. + type B = Boolean + val t = true type R0 = Rule0 /** * Parses all whitespace, excluding newlines. This is only @@ -25,9 +41,10 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def WL = rule{ zeroOrMore(Basic.WhitespaceChar | Literals.Comment | Basic.Newline) } + /** * By default, all strings and characters greedily - * capture all whitespace immediately before the token. + * capture all whitespace immediately after the token. */ implicit private[this] def wspStr(s: String): R0 = rule { WL ~ str(s) } implicit private[this] def wspChar(s: Char): R0 = rule { WL ~ ch(s) } @@ -39,28 +56,17 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif * (W) and key-operators (O) which have different non-match criteria. */ object K { - def W(s: String) = rule{ WL ~ Key.W(s) } - def O(s: String) = rule{ WL ~ Key.O(s) } - } - - def `=>` = rule{ K.O("=>") | K.O("⇒") } - def `:` = rule{ K.O(":") } - def `=` = rule{ K.O("=") } - - def `_` = rule{ K.W("_") } - def `this` = rule{ K.W("this") } - def `type` = rule{ K.W("type") } - def `val` = rule{ K.W("val") } - def `var` = rule{ K.W("var") } - def `def` = rule{ K.W("def") } - def `with` = rule{ K.W("with") } - def `package` = rule{ K.W("package") } - def `object` = rule{ K.W("object") } - def `class` = rule{ K.W("class") } - def `case` = rule{ K.W("case") } - def `trait` = rule{ K.W("trait") } - def `extends` = rule{ K.W("extends") } - def `implicit` = rule{ K.W("implicit") } + def W(s: String) = rule { + WL ~ Key.W(s) + } + + def O(s: String) = rule { + WL ~ Key.O(s) + } + } + + + def pos = cursor -> cursorChar /** * helper printing function @@ -77,445 +83,334 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def QualId = rule { WL ~ oneOrMore(Id).separatedBy('.') } def Ids = rule { oneOrMore(Id) separatedBy ',' } - def NotNewline: R0 = rule{ &( WS ~ noneOf("\n") )} - def OneNewlineMax: R0 = rule{ - WS ~ - optional(Basic.Newline) ~ - zeroOrMore( - zeroOrMore(Basic.WhitespaceChar) ~ - Literals.Comment ~ - zeroOrMore(Basic.WhitespaceChar) ~ - Basic.Newline - ) ~ - NotNewline - } - def StableId: R0 = { - def ClassQualifier = rule { '[' ~ Id ~ ']' } - rule { - zeroOrMore(Id ~ '.') ~ (`this` | K.W("super") ~ optional(ClassQualifier)) ~ zeroOrMore('.' ~ Id) | - Id ~ zeroOrMore('.' ~ Id) - } + def Path: R0 = rule { + zeroOrMore(Id ~ '.') ~ K.W("this") ~ zeroOrMore(Id).separatedBy('.') | + StableId } - def ExistentialDcl = rule { `type` ~ TypeDcl | `val` ~ ValDcl } - def ExistentialClause = rule { - "forSome" ~ '{' ~ oneOrMore(ExistentialDcl).separatedBy(Semi) ~ '}' + def StableId: R0 = rule { + zeroOrMore(Id ~ '.') ~ (K.W("this") | K.W("super") ~ optional(ClassQualifier)) ~ '.' ~ oneOrMore(Id).separatedBy('.') | + Id ~ zeroOrMore(WL ~ '.' ~ WL ~ Id) } - def Type: R0 = { - def FunctionArgTypes = rule { - '(' ~ optional(oneOrMore(ParamType) separatedBy ',') ~ ')' - } - rule { - ( - `_` | - FunctionArgTypes ~ `=>` ~ Type | - InfixType ~ ( - `=>` ~ Type | - optional(ExistentialClause) - ) - ) ~ TypeBounds - } + + def ClassQualifier = rule { '[' ~ Id ~ ']' } + + def Type: R0 = rule { + FunctionArgTypes ~ K.O("=>") ~ Type | InfixType ~ optional(WL ~ ExistentialClause) } + def FunctionArgTypes = rule { + InfixType | '(' ~ optional(oneOrMore(ParamType) separatedBy ',') ~ ')' + } + + def ExistentialClause = rule { "forSome" ~ '{' ~ oneOrMore(ExistentialDcl).separatedBy(Semi) } + def ExistentialDcl = rule { K.W("type") ~ TypeDcl | K.W("val") ~ ValDcl } def InfixType = rule { - CompoundType ~ zeroOrMore(NotNewline ~ Id ~ OneNewlineMax ~ CompoundType) + CompoundType ~ zeroOrMore(WL ~ Id ~ optional(Newline) ~ CompoundType) } - def CompoundType = { - def RefineStat = rule { `type` ~ TypeDef | Dcl | MATCH } - def Refinement = rule { - OneNewlineMax ~ '{' ~ oneOrMore(RefineStat).separatedBy(Semi) ~ "}" - } - rule { - oneOrMore(AnnotType).separatedBy(`with`) ~ optional(Refinement) | - Refinement - } + def CompoundType = rule { + oneOrMore(AnnotType).separatedBy(WL ~ K.W("with")) ~ optional(Refinement) } def AnnotType = rule { - SimpleType ~ optional(NotNewline ~ oneOrMore(NotNewline ~ Annotation)) + SimpleType ~ zeroOrMore(WL ~ Annotation) } - def SimpleType: R0 = { - def BasicType: R0 = rule { - '(' ~ Types ~ ')' | StableId ~ '.' ~ `type` | StableId - } - rule{ BasicType ~ zeroOrMore(TypeArgs | '#' ~ Id) } + def SimpleType: R0 = rule { + BasicType ~ + optional(WL ~ '#' ~ Id) ~ + optional(WL ~ TypeArgs) + } + def BasicType: R0 = rule { + '(' ~ Types ~ ')' | + Path ~ '.' ~ K.W("type") | + StableId } - def TypeArgs = rule { '[' ~ Types ~ "]" } def Types = rule { oneOrMore(Type).separatedBy(',') } - - + def Refinement = rule { + optional(Newline) ~ '{' ~ oneOrMore(RefineStat).separatedBy(Semi) ~ "}" + } + def RefineStat = rule { "type" ~ TypeDef | Dcl | MATCH } def TypePat = rule { CompoundType } - def Ascription = rule { - ":" ~ ("_" ~ "*" | Type | oneOrMore(Annotation)) - } - - def ParamType = rule { `=>` ~ Type | Type ~ "*" | Type } - - def LambdaHead: R0 = { - def Bindings: R0 = { - def Binding: R0 = rule { (Id | `_`) ~ optional(`:` ~ Type) } - rule { '(' ~ zeroOrMore(Binding).separatedBy(',') ~ ')' } - } - rule{ - ( - Bindings | - optional(`implicit`) ~ Id ~ optional(":" ~ CompoundType) | - `_` ~ optional(Ascription) - ) ~ - `=>` - } - } - def Enumerators(G: Boolean = false): R0 = { - def Generator: R0 = rule { - Pattern1 ~ (K.O("<-") | K.O("←"))~ Expr0(G) ~ optional(Guard(G)) - } - def Enumerator: R0 = rule { Generator | Guard(G) | Pattern1 ~ `=` ~ Expr0(G) } - rule { Generator ~ zeroOrMore(Semis ~ Enumerator) ~ WL } - } - def Expr = Expr0() - def ExprSensitive = Expr0(true) - def Expr0(G: Boolean = false): R0 = { - def IfCFlow = rule { - "if" ~ '(' ~ Expr ~ ')' ~ Expr0(G) ~ optional(optional(Semi) ~ K.W("else") ~ Expr0(G)) - } - def WhileCFlow = rule { "while" ~ '(' ~ Expr ~ ')' ~ Expr0(G) } - def TryCFlow = rule { - K.W("try") ~ Expr0(G) ~ - optional(K.W("catch") ~ Expr0(G)) ~ - optional(K.W("finally") ~ Expr0(G)) - } - - def DoWhileCFlow = rule { - K.W("do") ~ Expr0(G) ~ optional(Semi) ~ "while" ~ '(' ~ Expr ~ ")" - } - def ForCFlow = { - - rule { - "for" ~ - ('(' ~ Enumerators() ~ ')' | '{' ~ Enumerators(true) ~ '}') ~ - optional(K.W("yield")) ~ - Expr0(G) - } - } - rule { - zeroOrMore(LambdaHead) ~ ( - IfCFlow | - WhileCFlow | - TryCFlow | - DoWhileCFlow | - ForCFlow | - K.W("throw") ~ Expr0(G) | - K.W("return") ~ optional(Expr0(G)) | - SimpleExpr() ~ `=` ~ Expr0(G) | - PostfixExpr(G) ~ optional("match" ~ '{' ~ CaseClauses ~ "}" | Ascription) - ) - } + ":" ~ ("_" ~ "*" | InfixType | oneOrMore(Annotation)) + } + + def ParamType = rule { K.O("=>") ~ Type | Type ~ "*" | Type } + + def Expr: R0 = rule { + (Bindings | optional(K.W("implicit")) ~ Id | "_") ~ K.O("=>") ~ Expr | + Expr1 + } + def Expr1: R0 = rule { + IfCFlow | + WhileCFlow | + TryCFlow | + DoWhileCFlow | + ForCFlow | + K.W("throw") ~ Expr | + K.W("return") ~ optional(Expr) | + SimpleExpr ~ K.O("=") ~ Expr | + PostfixExpr ~ optional("match" ~ '{' ~ CaseClauses ~ "}" | Ascription) + + } + def IfCFlow = rule { "if" ~ '(' ~ Expr ~ ')' ~ zeroOrMore(Newline) ~ Expr ~ optional(optional(Semi) ~ K.W("else") ~ Expr) } + def WhileCFlow = rule { "while" ~ '(' ~ Expr ~ ')' ~ zeroOrMore(Newline) ~ Expr } + def TryCFlow = rule { + K.W("try") ~ Expr ~ + optional(WL ~ K.W("catch") ~ Expr) ~ + optional(WL ~ K.W("finally") ~ Expr) + } + + def DoWhileCFlow = rule { K.W("do") ~ Expr ~ optional(Semi) ~ "while" ~ '(' ~ Expr ~ ")" } + def ForCFlow = rule { + "for" ~ + ('(' ~ Enumerators ~ ')' | '{' ~ Enumerators ~ '}') ~ + zeroOrMore(Newline) ~ + optional(K.W("yield")) ~ + Expr } + def NotNewline: R0 = rule{ &( WS ~ noneOf("\n") )} + def PostfixExpr: R0 = rule { InfixExpr ~ optional(NotNewline ~ Id ~ optional(Newline)) } + def InfixExpr: R0 = rule { + PrefixExpr ~ + zeroOrMore( + NotNewline ~ + Id ~ + optional(Newline) ~ + PrefixExpr + ) } + def PrefixExpr = rule { optional(WL ~ anyOf("-+~!")) ~ SimpleExpr } - def PostfixExpr(G: Boolean = false): R0 = { - def PrefixExpr = rule { - optional(WL ~ anyOf("-+~!") ~ WS ~ !(Basic.OperatorChar)) ~ SimpleExpr(G) - } - def Check = if (G) OneNewlineMax else MATCH - def Check0 = if (G) NotNewline else MATCH - def InfixExpr: R0 = rule { - PrefixExpr ~ - zeroOrMore( - Check0 ~ - Id ~ - optional(TypeArgs) ~ - Check ~ - PrefixExpr - ) - } - rule { InfixExpr ~ optional(NotNewline ~ Id ~ optional(Newline)) } + def SimpleExpr: R0 = rule { + SimpleExpr1 ~ + zeroOrMore(WL ~ ('.' ~ Id | TypeArgs | ArgumentExprs)) ~ + optional(WL ~ "_") } - def SimpleExpr(G: Boolean = false): R0 = { - def Path: R0 = rule { - zeroOrMore(Id ~ '.') ~ `this` ~ zeroOrMore('.' ~ Id) | - StableId - } - def Check0 = if (G) NotNewline else MATCH - def SimpleExpr1 = rule{ - K.W("new") ~ (ClassTemplate | TemplateBody) | + def SimpleExpr1 = rule{ + K.W("new") ~ (ClassTemplate | TemplateBody) | BlockExpr | Literal | Path | - `_` | + K.W("_") | '(' ~ optional(Exprs) ~ ")" - } - rule { - SimpleExpr1 ~ - zeroOrMore('.' ~ Id | TypeArgs | NotNewline ~ ArgumentExprs) ~ - optional(Check0 ~ `_`) - } } - def Exprs: R0 = rule { oneOrMore(Expr).separatedBy(',') } - def ArgumentExprs: R0 = rule { - '(' ~ optional(Exprs ~ optional(`:` ~ `_` ~ '*')) ~ ")" | - OneNewlineMax ~ BlockExpr - } - def BlockExpr: R0 = rule { '{' ~ (CaseClauses | Block) ~ optional(Semis) ~ "}" } - def BlockStats: R0 = { - def Template: R0 = rule{ - zeroOrMore(Annotation) ~ - (optional(`implicit`) ~ optional(K.W("lazy")) ~ Def | zeroOrMore(LocalModifier) ~ TmplDef) - } - def BlockStat: R0 = rule { - Import | - Template | - Expr0(true) - } - rule{ oneOrMore(BlockStat).separatedBy(Semis) } + def Exprs: R0 = rule { oneOrMore(Expr).separatedBy(',') } + def ArgumentExprs: R0 = rule { + '(' ~ optional(Exprs ~ optional(K.O(":") ~ K.W("_") ~ '*')) ~ ")" | + optional(Newline) ~ BlockExpr } - def Block: R0 = { - def BlockEnd: R0 = rule{ optional(Semis) ~ &("}" | `case`) } - def ResultExpr: R0 = Expr0(true) - rule { - zeroOrMore(LambdaHead) ~ - optional(Semis) ~ - ( - ResultExpr ~ BlockEnd | - BlockStats ~ optional(Semis ~ ResultExpr) ~ BlockEnd | - MATCH ~ BlockEnd - ) - } + def BlockExpr: R0 = rule { '{' ~ (CaseClauses | Block) ~ "}" } + def BlockEnd: R0 = rule{ optional(Semis) ~ &("}" | "case") } + def Block: R0 = rule { + optional(Semis) ~ + ( + BlockStats ~ optional(Semis ~ ResultExpr) ~ BlockEnd | + ResultExpr ~ BlockEnd | + MATCH ~ BlockEnd + ) } - - def CaseClauses: R0 = { - def CaseClause: R0 = rule { `case` ~ Pattern ~ optional(Guard()) ~ `=>` ~ Block } - rule { oneOrMore(CaseClause) } + def BlockStats: R0 = rule{ + oneOrMore(BlockStat).separatedBy(Semis) } - - def Guard(G: Boolean = false): R0 = rule { K.W("if") ~ PostfixExpr(G) } + def BlockStat: R0 = rule { + Import | + zeroOrMore(Annotation) ~ (optional(K.W("implicit") | K.W("lazy")) ~ Def | zeroOrMore(LocalModifier) ~ TmplDef) | + Expr1 + } + def ResultExpr: R0 = rule { + (Bindings | optional(K.W("implicit")) ~ Id | "_") ~ K.W("=>") ~ Block | Expr1 + } + def Enumerators: R0 = rule { Generator ~ zeroOrMore(Semi ~ Enumerator) ~ WL } + def Enumerator: R0 = rule { Generator | Guard | Pattern1 ~ K.O("=") ~ Expr } + def Generator: R0 = rule { Pattern1 ~ K.O("<-") ~ Expr ~ optional(WL ~ Guard) } + def CaseClauses: R0 = rule { oneOrMore(CaseClause) } + def CaseClause: R0 = rule { K.W("case") ~ Pattern ~ optional(Guard) ~ K.O("=>") ~ Block } + def Guard: R0 = rule { K.W("if") ~ PostfixExpr } def Pattern: R0 = rule { oneOrMore(Pattern1).separatedBy('|') } - def Pattern1: R0 = rule { `_` ~ `:` ~ TypePat | VarId ~ `:` ~ TypePat | Pattern2 } - def Pattern2: R0 = { - def Pattern3: R0 = rule { - `_` ~ '*' | SimplePattern ~ zeroOrMore(Id ~ SimplePattern) - } - rule{ VarId ~ "@" ~ Pattern3 | Pattern3 | VarId } + def Pattern1: R0 = rule { + K.W("_") ~ K.O(":") ~ TypePat | VarId ~ K.O(":") ~ TypePat | Pattern2 } - - def SimplePattern: R0 = { - - def ExtractorArgs = rule{ zeroOrMore(Pattern).separatedBy(',') } - def Extractor: R0 = rule{ StableId ~ optional('(' ~ ExtractorArgs ~ ')') } - rule { - `_` ~ optional(`:` ~ TypePat) ~ !("*") | - Literal | - '(' ~ optional(ExtractorArgs) ~ ')' | - Extractor | - VarId - } + def Pattern2: R0 = rule { + VarId ~ "@" ~ Pattern3 | Pattern3 | VarId } - - - def TypeParamClause: R0 = { - def VariantTypeParam: R0 = rule { zeroOrMore(Annotation) ~ optional(WL ~ anyOf("+-")) ~ TypeParam } - rule { '[' ~ oneOrMore(VariantTypeParam).separatedBy(',') ~ ']' } + def Pattern3: R0 = rule { + SimplePattern ~ zeroOrMore(Id ~ SimplePattern) } - def FunTypeParamClause: R0 = rule { - '[' ~ oneOrMore(zeroOrMore(Annotation) ~ TypeParam).separatedBy(',') ~ ']' - } - def TypeBounds: R0 = rule{ optional(K.O(">:") ~ Type) ~ optional(K.O("<:") ~ Type) } - def TypeParam: R0 = rule { - (Id | `_`) ~ - optional(TypeParamClause) ~ - TypeBounds ~ - zeroOrMore(K.O("<%") ~ Type) ~ - zeroOrMore(`:` ~ Type) - } - def ParamClauses: R0 = rule { - zeroOrMore(ParamClause) ~ optional(OneNewlineMax ~ '(' ~ `implicit` ~ Params ~ ')') - } - def ParamClause: R0 = rule { OneNewlineMax ~ '(' ~ optional(Params) ~ ')' } - def Params: R0 = { - def Param: R0 = rule { - zeroOrMore(Annotation) ~ Id ~ optional(`:` ~ ParamType) ~ optional(`=` ~ Expr) - } - rule { zeroOrMore(Param).separatedBy(',') } + def SimplePattern: R0 = rule { + K.W("_") | + Literal | + '(' ~ optional(Patterns) ~ ')' | + ( + StableId ~ + optional( + '(' ~ + (optional(Patterns ~ ',') ~ optional(VarId ~ '@') ~ K.W("_") ~ '*' | optional(Patterns)) ~ + ')' + ) + ) | + VarId } + def Patterns: R0 = rule { K.W("_") ~ '*' | oneOrMore(Pattern).separatedBy(',') } - def ClassParam: R0 = rule { - zeroOrMore(Annotation) ~ - optional(zeroOrMore(Modifier) ~ (`val` | `var`)) ~ - Id ~ - `:` ~ - ParamType ~ - optional(`=` ~ Expr) - } + def TypeParamClause: R0 = rule { '[' ~ oneOrMore(VariantTypeParam).separatedBy(',') ~ ']' } + def FunTypeParamClause: R0 = rule { '[' ~ oneOrMore(TypeParam).separatedBy(',') ~ ']' } + def VariantTypeParam: R0 = rule { zeroOrMore(Annotation) ~ optional(anyOf("+-")) ~ TypeParam } + def TypeParam: R0 = rule { + (Id | K.W("_")) ~ + optional(TypeParamClause) ~ + optional(K.O(">:") ~ Type) ~ + optional(K.O("<:") ~ Type) ~ + zeroOrMore(K.O("<%") ~ Type) ~ + zeroOrMore(K.O(":") ~ Type) + } + def ParamClauses: R0 = rule { zeroOrMore(ParamClause) ~ optional(optional(Newline) ~ '(' ~ K.W("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(K.O(":") ~ ParamType) ~ optional(K.O("=") ~ Expr) } + def ClassParamClauses: R0 = rule { zeroOrMore(ClassParamClause) ~ optional(optional(Newline) ~ '(' ~ K.W("implicit") ~ ClassParam ~ ")") } + def ClassParamClause: R0 = rule { optional(Newline) ~ '(' ~ optional(ClassParams) ~ ")" } + def ClassParams: R0 = rule { oneOrMore(ClassParam).separatedBy(',') } + def ClassParam: R0 = rule { zeroOrMore(Annotation) ~ optional(zeroOrMore(Modifier) ~ (K.W("val") | K.W("var"))) ~ Id ~ K.O(":") ~ ParamType ~ optional(K.O("=") ~ Expr) } + + def Bindings: R0 = rule { '(' ~ zeroOrMore(Binding).separatedBy(',') ~ ')' } + def Binding: R0 = rule { (Id | K.W("_")) ~ optional(K.O(":") ~ Type) } def Modifier: R0 = rule { LocalModifier | AccessModifier | K.W("override") } - def LocalModifier: R0 = rule { K.W("abstract") | K.W("final") | K.W("sealed") | `implicit` | K.W("lazy") } - def AccessModifier: R0 = { - def AccessQualifier: R0 = rule { '[' ~ (`this` | Id) ~ ']' } - rule { (K.W("private") | K.W("protected")) ~ optional(AccessQualifier) } - } + def LocalModifier: R0 = rule { K.W("abstract") | K.W("final") | K.W("sealed") | K.W("implicit") | K.W("lazy") } + def AccessModifier: R0 = rule { (K.W("private") | K.W("protected")) ~ optional(AccessQualifier) } + def AccessQualifier: R0 = rule { '[' ~ (K.W("this") | Id) ~ ']' } - def Annotation: R0 = rule { '@' ~ SimpleType ~ zeroOrMore(ArgumentExprs) } + def Annotation: R0 = rule { '@' ~ SimpleType ~ zeroOrMore(WL ~ ArgumentExprs) } + def ConstrAnnotation: R0 = rule { '@' ~ SimpleType ~ ArgumentExprs } def TemplateBody: R0 = rule { '{' ~ optional(SelfType) ~ - optional(Semis) ~ zeroOrMore(TemplateStat).separatedBy(Semis) ~ - optional(Semis) ~ '}' } def TemplateStat: R0 = rule { Import | - zeroOrMore(Annotation ~ OneNewlineMax) ~ zeroOrMore(Modifier) ~ (Def | Dcl) | - Expr0(true) + zeroOrMore(Annotation ~ optional(Newline)) ~ zeroOrMore(Modifier) ~ (Def | Dcl) | + Expr } - def SelfType: R0 = rule { - `this` ~ `:` ~ InfixType ~ `=>` | (Id | `_`) ~ optional(`:` ~ InfixType) ~ `=>` - } + def SelfType: R0 = rule { K.W("this") ~ K.O(":") ~ Type ~ K.O("=>") | Id ~ optional(K.O(":") ~ Type) ~ K.O("=>") } - def Import: R0 = { - def ImportExpr: R0 = rule { - StableId ~ optional('.' ~ (`_` | ImportSelectors)) - } - def ImportSelectors: R0 = rule { - '{' ~ zeroOrMore(ImportSelector ~ ',') ~ (ImportSelector | `_`) ~ "}" - } - def ImportSelector: R0 = rule { Id ~ optional(`=>` ~ (Id | `_`)) } - rule { K.W("import") ~ oneOrMore(ImportExpr).separatedBy(',') } + def Import: R0 = rule { K.W("import") ~ oneOrMore(ImportExpr).separatedBy(',') } + + def ImportExpr: R0 = rule { + StableId ~ optional('.' ~ ("_" | ImportSelectors)) } + def ImportSelectors: R0 = rule { '{' ~ zeroOrMore(ImportSelector ~ ',') ~ (ImportSelector | K.W("_")) ~ "}" } + def ImportSelector: R0 = rule { Id ~ optional(K.O("=>") ~ (Id | K.W("_"))) } - def Dcl: R0 = { - def VarDcl: R0 = rule { Ids ~ `:` ~ Type } - def FunDcl: R0 = rule { FunSig ~ optional(`:` ~ Type) } - rule{ `val` ~ ValDcl | `var` ~ VarDcl | `def` ~ FunDcl | `type` ~ TypeDcl } + def Dcl: R0 = rule { + K.W("val") ~ ValDcl | + K.W("var") ~ VarDcl | + K.W("def") ~ FunDcl | + K.W("type") ~ zeroOrMore(Newline) ~ TypeDcl } + def ValDcl: R0 = rule { Ids ~ K.O(":") ~ Type } + def VarDcl: R0 = rule { Ids ~ K.O(":") ~ Type } + def FunDcl: R0 = rule { FunSig ~ optional(WL ~ K.O(":") ~ Type) } def FunSig: R0 = rule { Id ~ optional(FunTypeParamClause) ~ ParamClauses } - def ValDcl: R0 = rule { Ids ~ `:` ~ Type } - def TypeDcl: R0 = rule { Id ~ optional(TypeParamClause) ~ TypeBounds } - - def PatVarDef: R0 = { - def PatDef: R0 = rule { oneOrMore(Pattern2).separatedBy(',') ~ optional(`:` ~ Type) ~ `=` ~ Expr0(true) } - def VarDef: R0 = rule { Ids ~ `:` ~ Type ~ `=` ~ `_` | PatDef } - rule { `val` ~ PatDef | `var` ~ VarDef } - } - def Def: R0 = { - def ConstrExpr: R0 = rule { ConstrBlock | SelfInvocation } - def FunDef: R0 = rule { - `this` ~ ParamClause ~ ParamClauses ~ (`=` ~ ConstrExpr | OneNewlineMax ~ ConstrBlock) | - FunSig ~ optional(`:` ~ Type) ~ ( - `=` ~ optional(K.W("macro")) ~ Expr0(true) | - OneNewlineMax ~ '{' ~ Block ~ "}" - ) - } - rule { `def` ~ FunDef | `type` ~ TypeDef | PatVarDef | TmplDef } - } - - def TypeDef: R0 = rule { Id ~ optional(TypeParamClause) ~ `=` ~ Type } - - def TmplDef: R0 = { - def TraitTemplate: R0 = { - def TraitParents: R0 = rule { AnnotType ~ zeroOrMore(`with` ~ AnnotType) } - rule{ optional(EarlyDefs) ~ TraitParents ~ optional(TemplateBody) } - } - def ClassParamClauses: R0 = { - def Implicit: R0 = rule{ - OneNewlineMax ~ - '(' ~ - `implicit` ~ - oneOrMore(ClassParam).separatedBy(",") ~ - ")" - } - - def ClassParamClause: R0 = { - def ClassParams: R0 = rule { oneOrMore(ClassParam).separatedBy(',') } - rule { OneNewlineMax ~'(' ~ optional(ClassParams) ~ ")" } - } - rule { - oneOrMore(ClassParamClause) ~ optional(Implicit) | Implicit - } - } - def ConstrPrelude: R0 = { - def Annot: R0 = rule { '@' ~ SimpleType ~ ArgumentExprs } - rule{ - NotNewline ~ ( - oneOrMore(Annot) ~ optional(AccessModifier) | - zeroOrMore(Annot) ~ AccessModifier - ) - } - } - def ClassDef: R0 = rule { - Id ~ + def TypeDcl: R0 = rule { + Id ~ + optional(WL ~ TypeParamClause) ~ + optional(WL ~ K.O(">:") ~ Type) ~ + optional(WL ~ K.O("<:") ~ Type) + } + + def PatVarDef: R0 = rule { K.W("val") ~ PatDef | K.W("var") ~ VarDef } + def Def: R0 = rule { K.W("def") ~ FunDef | K.W("type") ~ zeroOrMore(Newline) ~ TypeDef | PatVarDef | TmplDef } + def PatDef: R0 = rule { oneOrMore(Pattern2).separatedBy(',') ~ optional(K.O(":") ~ Type) ~ K.O("=") ~ Expr } + def VarDef: R0 = rule { Ids ~ K.O(":") ~ Type ~ K.O("=") ~ K.W("_") | PatDef } + def FunDef: R0 = rule { + K.W("this") ~ ParamClause ~ ParamClauses ~ (K.O("=") ~ ConstrExpr | optional(Newline) ~ ConstrBlock) | + FunSig ~ + ( + optional(K.O(":") ~ Type) ~ K.O("=") ~ optional(K.W("macro")) ~ Expr | + optional(Newline) ~ '{' ~ Block ~ "}" + ) + } + def TypeDef: R0 = rule { Id ~ optional(TypeParamClause) ~ K.O("=") ~ Type } + + def TmplDef: R0 = rule { + K.W("trait") ~ TraitDef | + optional(K.W("case")) ~ (K.W("class") ~ ClassDef | + K.W("object") ~ ObjectDef) + } + def ClassDef: R0 = rule { + Id ~ optional(TypeParamClause) ~ - optional(ConstrPrelude) ~ - optional(ClassParamClauses) ~ + zeroOrMore(ConstrAnnotation) ~ + optional(AccessModifier) ~ + ClassParamClauses ~ ClassTemplateOpt - } - def TraitTemplateOpt: R0 = rule { - `extends` ~ TraitTemplate | optional(optional(`extends`) ~ TemplateBody) - } - def TraitDef: R0 = rule { Id ~ optional(TypeParamClause) ~ TraitTemplateOpt } - rule { - `trait` ~ TraitDef | - optional(`case`) ~ (`class` ~ ClassDef | `object` ~ ObjectDef) - } } - - + def TraitDef: R0 = rule { Id ~ optional(TypeParamClause) ~ TraitTemplateOpt } def ObjectDef: R0 = rule { Id ~ ClassTemplateOpt } def ClassTemplateOpt: R0 = rule { - `extends` ~ ClassTemplate | optional(optional(`extends`) ~ TemplateBody) + WL ~ K.W("extends") ~ ClassTemplate | + optional(WL ~ optional(K.W("extends")) ~ TemplateBody) } - - def ClassTemplate: R0 = { - def ClassParents: R0 = { - def Constr: R0 = rule{ AnnotType ~ zeroOrMore(NotNewline ~ ArgumentExprs) } - rule{ Constr ~ zeroOrMore(`with` ~ AnnotType) } - } - rule{ optional(EarlyDefs) ~ ClassParents ~ optional(TemplateBody) } + def TraitTemplateOpt: R0 = rule { K.W("extends") ~ TraitTemplate | optional(optional(K.W("extends")) ~ TemplateBody) } + def ClassTemplate: R0 = rule { + optional(EarlyDefs) ~ + ClassParents ~ + optional(WL ~ TemplateBody) } - def EarlyDefs: R0 = { - def EarlyDef: R0 = rule { - zeroOrMore(Annotation ~ OneNewlineMax) ~ zeroOrMore(Modifier) ~ PatVarDef - } - rule{ '{' ~ optional(oneOrMore(EarlyDef).separatedBy(Semis)) ~ '}' ~ `with` } + def TraitTemplate: R0 = rule { + optional(EarlyDefs) ~ TraitParents ~ optional(TemplateBody) } + def ClassParents: R0 = rule { + Constr ~ zeroOrMore(WL ~ K.W("with") ~ AnnotType) + } + def TraitParents: R0 = rule { + AnnotType ~ zeroOrMore(WL ~ K.W("with") ~ AnnotType) + } + def Constr: R0 = rule { + AnnotType ~ zeroOrMore(WL ~ ArgumentExprs) + } + def EarlyDefs: R0 = rule { + '{' ~ optional(oneOrMore(EarlyDef).separatedBy(Semis)) ~ '}' ~ K.W("with") + } + def EarlyDef: R0 = rule { + zeroOrMore(Annotation ~ optional(Newline)) ~ zeroOrMore(Modifier) ~ PatVarDef + } + def ConstrExpr: R0 = rule { ConstrBlock | SelfInvocation } + def ConstrBlock: R0 = rule { '{' ~ SelfInvocation ~ zeroOrMore(Semis ~ BlockStat) ~ '}' } + def SelfInvocation: R0 = rule { K.W("this") ~ oneOrMore(ArgumentExprs) } - def ConstrBlock: R0 = rule { '{' ~ SelfInvocation ~ optional(Semis ~ BlockStats) ~ optional(Semis) ~ '}' } - def SelfInvocation: R0 = rule { `this` ~ oneOrMore(ArgumentExprs) } - - def TopStatSeq: R0 = { - def PackageObject: R0 = rule { `package` ~ `object` ~ ObjectDef } - def Packaging: R0 = rule { - `package` ~ QualId ~ '{' ~ optional(TopStatSeq) ~ WL ~ '}' - } - def TopStat: R0 = rule { - Packaging | + def TopStatSeq: R0 = rule { oneOrMore(TopStat).separatedBy(Semis) } + def TopStat: R0 = rule { + Packaging | PackageObject | Import | - zeroOrMore(Annotation ~ OneNewlineMax) ~ zeroOrMore(Modifier) ~ TmplDef - } - rule { oneOrMore(TopStat).separatedBy(Semis) } + zeroOrMore(Annotation ~ optional(Newline)) ~ zeroOrMore(Modifier) ~ TmplDef + } + def Packaging: R0 = rule { K.W("package") ~ QualId ~ '{' ~ TopStatSeq ~ '}' } + def PackageObject: R0 = rule { K.W("package") ~ K.W("object") ~ ObjectDef } + def TopPackageSeq: R0 = rule{ + oneOrMore(K.W("package") ~ QualId).separatedBy(Semis) } + def CompilationUnit: Rule1[String] = rule { + capture( + pr("CompulationUnit 0") ~ + optional(Semis) ~ + pr("CompulationUnit 1") ~ + (TopPackageSeq ~ optional(Semis ~ TopStatSeq) | TopStatSeq) ~ + optional(Semis) ~ + WL - def CompilationUnit: Rule1[String] = { - def TopPackageSeq: R0 = rule{ - oneOrMore(`package` ~ QualId ~ !(WS ~ "{")).separatedBy(Semis) - } - rule { - capture( - optional(Semis) ~ - (TopPackageSeq ~ optional(Semis ~ TopStatSeq) | TopStatSeq | MATCH) ~ - optional(Semis) ~ - WL - ) - } + ) } } diff --git a/scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala b/scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala index a95afac..4bc972f 100644 --- a/scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala +++ b/scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala @@ -6,39 +6,30 @@ import org.parboiled2._ trait Identifiers { self: Parser with Basic => object Identifiers{ import Basic._ - def Operator = rule{!Keywords ~ oneOrMore(OperatorChar)} + def Operator = rule(oneOrMore(OperatorChar)) - def VarId = VarId0(true) - def VarId0(dollar: Boolean) = rule { !Keywords ~ Lower ~ IdRest(dollar) } - def PlainId = rule { !Keywords ~ Upper ~ IdRest(true) | VarId | Operator } - def PlainIdNoDollar = rule { !Keywords ~ Upper ~ IdRest(false) | VarId0(false) | Operator } - def Id = rule { !Keywords ~ PlainId | ("`" ~ oneOrMore(noneOf("`")) ~ "`") } - def IdRest(dollar: Boolean) = { - if (!dollar) rule { - zeroOrMore(zeroOrMore("_") ~ oneOrMore(!anyOf("_$") ~ Letter | Digit)) ~ - optional(oneOrMore("_") ~ zeroOrMore(OperatorChar)) - } else rule{ - zeroOrMore(zeroOrMore("_") ~ oneOrMore(!"_" ~ Letter | Digit)) ~ - optional(oneOrMore("_") ~ zeroOrMore(OperatorChar)) - } + def VarId = rule { + !(Keywords ~ (WhitespaceChar | Newline | "//" | "/*")) ~ Lower ~ IdRest } + def PlainId = rule { Upper ~ IdRest | VarId | !(Keywords ~ (WhitespaceChar | Newline | "//" | "/*")) ~ Operator } + def Id = rule { PlainId | ("`" ~ oneOrMore(noneOf("`")) ~ "`") } + def IdRest = rule { + zeroOrMore(zeroOrMore("_") ~ oneOrMore(!"_" ~ Letter | Digit)) ~ + optional(oneOrMore("_") ~ optional(Operator)) + } + def AlphabetKeywords = rule { - ( - "abstract" | "case" | "catch" | "class" | "def" | "do" | "else" | "extends" | "false" | "finally" | "final" | "finally" | "forSome" | "for" | "if" | - "implicit" | "import" | "lazy" | "match" | "new" | "null" | "object" | "override" | "package" | "private" | "protected" | "return" | - "sealed" | "super" | "this" | "throw" | "trait" | "try" | "true" | "type" | "val" | "var" | "while" | "with" | "yield" | "_" - ) ~ !Letter + "abstract" | "case" | "catch" | "class" | "def" | "do" | "else" | "extends" | "false" | "finally" | "final" | "finally" | "forSome" | "for" | "if" | + "implicit" | "import" | "lazy" | "match" | "new" | "null" | "object" | "override" | "package" | "private" | "protected" | "return" | + "sealed" | "super" | "this" | "throw" | "trait" | "try" | "true" | "type" | "val" | "var" | "while" | "with" | "yield" | "_" } def SymbolicKeywords = rule{ - ( - ":" | ";" | "=>" | "=" | "<-" | "<:" | "<%" | ">:" | "#" | "@" | "\u21d2" | "\u2190" - ) ~ !OperatorChar + ":" | ";" | "=>" | "=" | "<-" | "<:" | "<%" | ">:" | "#" | "@" | "\u21d2" | "\u2190" } def Keywords = rule { - AlphabetKeywords | SymbolicKeywords + AlphabetKeywords ~ !Letter | SymbolicKeywords ~ !OperatorChar } - } } diff --git a/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala b/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala index e6dd54d..9fd9d5b 100644 --- a/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala +++ b/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala @@ -4,8 +4,6 @@ import acyclic.file import org.parboiled2._ trait Literals { self: Parser with Basic with Identifiers => - def Block: Rule0 - def WL: Rule0 object Literals{ import Basic._ def FloatingPointLiteral = rule { @@ -18,14 +16,14 @@ trait Literals { self: Parser with Basic with Identifiers => ) } - def IntegerLiteral = rule { (HexNumeral | DecimalNumeral) ~ optional(anyOf("Ll")) } + def IntegerLiteral = rule { (DecimalNumeral | HexNumeral) ~ optional(anyOf("Ll")) } def BooleanLiteral = rule { Key.W("true") | Key.W("false") } def MultilineComment: Rule0 = rule { "/*" ~ zeroOrMore(MultilineComment | !"*/" ~ ANY) ~ "*/" } def Comment: Rule0 = rule { MultilineComment | - "//" ~ zeroOrMore(!Basic.Newline ~ ANY) ~ &(Basic.Newline | EOI) + "//" ~ zeroOrMore(!Basic.Newline ~ ANY) ~ &(Basic.Newline | EOI) } def Literal = rule { @@ -37,27 +35,18 @@ trait Literals { self: Parser with Basic with Identifiers => (Key.W("null") ~ !(Basic.Letter | Basic.Digit)) } - def EscapedChars = rule { '\\' ~ anyOf("btnfr'\\\"") } + + def EscapedChars = rule { '\\' ~ anyOf("rnt\\\"") } // Note that symbols can take on the same values as keywords! def SymbolLiteral = rule { ''' ~ (Identifiers.PlainId | Identifiers.Keywords) } - def CharacterLiteral = rule { - ''' ~ (UnicodeExcape | EscapedChars | !'\\' ~ CharPredicate.from(isPrintableChar)) ~ ''' - } + def CharacterLiteral = rule { ''' ~ (UnicodeExcape | EscapedChars | !'\\' ~ CharPredicate.from(isPrintableChar)) ~ ''' } - def MultiLineChars = rule { - zeroOrMore(Interpolation | optional('"') ~ optional('"') ~ noneOf("\"")) - } - def pr(s: String) = rule { run(println(s"LOGGING $cursor: $s")) } - def Interpolation = rule{ - "$" ~ Identifiers.PlainIdNoDollar | "${" ~ Block ~ WL ~ "}" | "$$" - } + def MultiLineChars = rule { zeroOrMore(optional('"') ~ optional('"') ~ noneOf("\"")) } def StringLiteral = rule { - (Identifiers.Id ~ "\"\"\"" ~ MultiLineChars ~ ("\"\"\"" ~ zeroOrMore('"'))) | - (Identifiers.Id ~ '"' ~ zeroOrMore(Interpolation | "\\\"" | "\\\\" | noneOf("\n\"")) ~ '"') | - ("\"\"\"" ~ MultiLineChars ~ ("\"\"\"" ~ zeroOrMore('"'))) | - ('"' ~ zeroOrMore("\\\"" | "\\\\" | noneOf("\n\"")) ~ '"') + (optional(Identifiers.Id) ~ "\"\"\"" ~ MultiLineChars ~ ("\"\"\"" ~ zeroOrMore('"'))) | + (optional(Identifiers.Id) ~ '"' ~ zeroOrMore("\\\"" | noneOf("\n\"")) ~ '"') } def isPrintableChar(c: Char): Boolean = { diff --git a/scalaParser/src/test/resources/test.scala b/scalaParser/src/test/resources/test.scala deleted file mode 100644 index b56b7c6..0000000 --- a/scalaParser/src/test/resources/test.scala +++ /dev/null @@ -1,2 +0,0 @@ - -object Test extends { type T = Int } with App diff --git a/scalaParser/src/test/scala/scalaParser/SyntaxTest.scala b/scalaParser/src/test/scala/scalaParser/SyntaxTest.scala index a1e4fe4..fe5fc2c 100644 --- a/scalaParser/src/test/scala/scalaParser/SyntaxTest.scala +++ b/scalaParser/src/test/scala/scalaParser/SyntaxTest.scala @@ -8,13 +8,6 @@ import utest.util.Tree import scala.util.{Failure, Success} object SyntaxTest extends TestSuite{ - def checkNeg[T](input: String) = { - println("Checking...") - new ScalaSyntax(input).CompilationUnit.run() match{ - case Failure(f: ParseError) => () // yay - case Success(parsed) => assert(parsed.length != input.length) - } - } def check[T](input: String) = { println("Checking...") new ScalaSyntax(input).CompilationUnit.run() match{ @@ -24,820 +17,401 @@ object SyntaxTest extends TestSuite{ println(f.formatTraces) throw new Exception(f.position + "\t" + f.formatTraces) case Success(parsed) => - if(parsed != input) - - throw new Exception( - "Parsing Failed at " + parsed.length + "\n" + input.drop(parsed.length).take(50) - ) + assert(parsed == input) } } println("running") def tests = TestSuite{ 'unit { - 'pos { - * - check( - "package torimatomeru" + * - check( + "package torimatomeru" - ) - * - check( - """package torimatomeru - | - |package lols - """.stripMargin - ) - * - check( - """package torimatomeru - |import a - |import b - """.stripMargin - ) - * - check( - """ - |package torimatomeru - | - |import org.parboiled2.ParseError - |import utest._ - |import utest.framework.Test - |import utest.util.Tree - | - |import scala.util.{Failure, Success} - | - |object SyntaxTest extends TestSuite - """.stripMargin - ) - * - check( - """ - |object SyntaxTest extends TestSuite{ - | def check[T](input: String) = { - | - | } - |} - """.stripMargin - ) - * - check( - """ - |object SyntaxTest{ - | a() - | throw 1 - |} - """.stripMargin - ) - * - check( - """ - |object SyntaxTest extends TestSuite{ - | { - | println - | throw 1 - | } - |} - """.stripMargin - ) - * - check( - """package scalatex - | - | - |import org.parboiled2._ - |import torimatomeru.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{} - |} - """.stripMargin - ) - * - check( - """ - |object Moo{ - | a - | .b - | - | c - |} - """.stripMargin - ) - * - check( - """ - |object Moo{ - | filename - | .asInstanceOf[Literal] - |10 - |} - """.stripMargin - ) - * - check( - """ - |object Cow{ - | ().mkString - | - | 1 - |} - """.stripMargin - ) - * - check( - """ - |object O{ - | private[this] val applyMacroFull = 1 - |} - """.stripMargin - ) - * - check( - """ - |object O{ - | private[this] def applyMacroFull(c: Context) - | (expr: c.Expr[String], - | runtimeErrors: Boolean, - | debug: Boolean) - | : c.Expr[Frag] = { - | } - |} - """.stripMargin - ) - * - check( - """ - |object O{ - | class DebugFailure extends Exception - | - | 1 - |} - """.stripMargin - ) - * - check( - """ - |package torimatomeru - | - |package syntax - | - |import org.parboiled2._ - | - """.stripMargin - ) - * - check( - """ - |object Foo{ - | 0 match { - | case A | B => 0 - | } - |} - """.stripMargin - ) - * - check( - """ - |object Compiler{ + ) + * - check( + """package torimatomeru | - | def apply = { - | def rec = t match { - | case 0 => 0 - | } + |package lols + """.stripMargin + ) + * - check( + """package torimatomeru + |import a + |import b + """.stripMargin + ) + * - check( + """ + |package torimatomeru + | + |import org.parboiled2.ParseError + |import utest._ + |import utest.framework.Test + |import utest.util.Tree + | + |import scala.util.{Failure, Success} + | + |object SyntaxTest extends TestSuite + """.stripMargin + ) + * - check( + """ + |object SyntaxTest extends TestSuite{ + | def check[T](input: String) = { | - | rec(tree) | } |} + """.stripMargin + ) + * - check( + """ + |object SyntaxTest{ + | a() + | throw 1 + |} + """.stripMargin + ) + * - check( + """ + |object SyntaxTest extends TestSuite{ + | { + | println + | throw 1 + | } + |} + """.stripMargin + ) + * - check( + """package scalatex | - """. - stripMargin - ) - * - check( - """ - |object O { - | A(A(A(A(A(A(A(A()))))))) - |} - | - """.stripMargin - ) - * - check( - """ - |object O{ - | A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A()))))))))))))))) - |} - """.stripMargin - ) - * - check( - """ - |object L{ - | a.b = c - | a().b = c - |} - """.stripMargin - ) - * - check( - """ - |object L{ - | a b c - | d = 1 - |} - """.stripMargin - ) - - * - check( - """/* __ *\ - |** ________ ___ / / ___ __ ____ Scala.js CLI ** - |** / __/ __// _ | / / / _ | __ / // __/ (c) 2013-2014, LAMP/EPFL ** - |** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** - |** /____/\___/_/ |_/____/_/ | |__/ /____/ ** - |** |/____/ ** - |\* */ - | - |package scala.scalajs.cli - | - """.stripMargin - ) - * - check( - """ - |object O{ - | for { - | a <- b - | c <- d - | } { - | 1 - | } - |} - """.stripMargin - ) - * - check( - """ - |object O{ - | val jarFile = - | try { 1 } - | catch { case _: F => G } - |} - """.stripMargin - ) - * - check( - """ - |object F{ - | func{ case _: F => fail } - |} - """.stripMargin - ) - * - check( - """ - |object Foo{ - | val a = d // g - | val b = e // h - | val c = f - |} - """.stripMargin - ) - * - check( - """ - |object L{ - | x match{ - | case y.Y(z) => z - | } - |} - """.stripMargin - ) - * - check( - """object K{ - | val a: B { - | val c: D - | } - | - | 1 - |} - """.stripMargin - ) - * - check( - """ - |object LOLS{ - | def run() {} - | - | def apply() {} - |} - """.stripMargin - ) - * - check( - """ - |object O{ - | a =:= b.c - |} - """.stripMargin - ) - * - check( - """ - |object K{ - | a( - | 1: _* - | ) - |} - """.stripMargin - ) - * - check( - """ - |object P{ - | tree match { - | case stats :+ expr => 1 - | } - |} - """.stripMargin - ) - * - check( - """ - |object K{ - | val trueA = 1 - |} - """.stripMargin - ) - * - check( - """ - |object K{ - | val nullo :: cow = 1 - |} - """.stripMargin - ) - * - check( - """ - |object K{ - | val omg_+ = 1 - |} - """.stripMargin - ) - * - check( - """ - |object K{ - | val + = 1 - | var * = 2 - |} - """.stripMargin - ) - * - check( - """ - |object O{ - | c match { - | case b_ => 1 - | } - |} - """.stripMargin - ) - * - check( - """ - |trait Basic { - | b match { - | case C => true; case _ => false - | } - |} - """.stripMargin - ) - * - check( - """trait Basic { - | !a.b - |} - """.stripMargin - ) - * - check( - """ - |class Parser { - | {() => } - |} - | - """.stripMargin - ) - * - check( - """ - | - | - | - |package omg - |; - | - |; - | - |; - |class Parser - |; - | - |; - | - |; - """.stripMargin - ) - * - check( - """ - | - |object GenJSCode { - | code: @switch - |} - """.stripMargin - ) - * - check( - """object B { - | { a: L => } - |} - """.stripMargin - ) - * - check( - """object O{ - | { - | val index = 0 - | i: Int => 10 - | 0 - | } - |} - """.stripMargin - ) - * - check( - """object GenJSCode{ - | val g: G.this.g.type - |} - | - """.stripMargin - ) - * - check( - """object K{ - | class RTTypeTest - | private object O - |} - """.stripMargin - ) - * - check( - """object O{ - | if (eqeq && - | - | false) 1 - |} - """.stripMargin - ) - * - check( - """ - |object O{ - | for( - | x <- Nil map - | - | (x => x) - | ) yield x - |} - """.stripMargin - ) - * - check( - """ - |object O{ - | for{ - | x <- Nil - | if - | - | 1 == 2 - | } yield x - |} - """.stripMargin - ) - * - check( - """ - |object ScopedVar { - | def withScopedVars(ass: Seq[_]) = 1 - |} - | - """.stripMargin - ) - * - check( - """ - |abstract class JSASTTest extends DirectTest { - | def show: this.type = () - |} - | - """.stripMargin - ) - * - check( - """object Traversers { - | { - | 1 - | cases foreach nil - | } - |} - """.stripMargin - ) - * - check( - """object Utils { - | "\\" - |} - | - """.stripMargin - ) - * - check( - """object F{ - | this eq that.asInstanceOf[AnyRef] - |} - """.stripMargin - ) - * - check( - """class C{ - | 0x00 <= 2 && 1 - |} - | - """.stripMargin - ) - * - check( - """class Runtime private - """.stripMargin - ) - * - check( - """ - |object System { - | def a[@b T[@b V]] = 1 - |} - | - """.stripMargin - ) - * - check( - """object U{ - | private val _fragment = fld(Fragment) - | _fld = null - |} - """.stripMargin - ) - * - check( - """class Array{ - | def length_= = 1 - |} - """.stripMargin - ) - * - check( - """object K{ - | def newBuilder = - | new B - | - | @inline def a = 1 - |} - """.stripMargin - ) - * - check( - """trait Function12[-T1, +R] - """.stripMargin - ) - * - check( - """@a // Don't do this at home! - |trait B - """.stripMargin - ) - * - check( - """object T{ - | type B = { def F: S } - |} - | - """.stripMargin - ) - * - check( - """ - |object ScalaJSBuild{ - | ( - | 1 / 2 - | / 3 - | ) - |} - | - """.stripMargin - ) - * - check( - """trait Writer{ - | '\f' - |} - """.stripMargin - ) - * - check( - """object CyclicDependencyException { - | def str(info: ResolutionInfo) = - | s"${info.resourceName} from: ${info.origins.mkString(", ")}" - |} - """.stripMargin - ) - * - check( - """object OptimizerCore { - | tpe match { - | case NothingType | _:RecordType=> 1 - | } - |} - """.stripMargin - ) - * - check( - """class A{ - | 1 - | () => 1 - |} - """.stripMargin - ) - * - check( - """trait ReactorCanReply { - | _: InternalReplyReactor => - |} - """.stripMargin - ) - - * - check( - """object G{ - | def isBefore(pd: SubComponent) = settings.stopBefore - | phaseDescriptors sliding 2 collectFirst () - |} - """.stripMargin - ) - * - check( - """class SymbolLoaders { - | type T = ClassPath[AbstractFile]#ClassRep - |} - """.stripMargin - ) - * - check( - """trait ContextErrors { - | def isUnaffiliatedExpr = expanded.isInstanceOf[scala.reflect.api.Exprs#Expr[_]] - |} - """.stripMargin - ) - * - check( - """trait Typers{ - | s"nested ${ if (1) "trait" else "class" }" - |} - """.stripMargin - ) - * - check( - """trait ReflectSetup { this: Global => - | phase = 1 - |} - """.stripMargin - ) - * - check( - """trait Predef { - | @x - | // a - | type T - |} - """.stripMargin - ) - * - check( - """ - object StringContext { - - s"${ - require(index >= 0 && index < str.length) - val ok = "[\b, \t, \n, \f, \r, \\, \", \']" - if (index == str.length - 1) "at terminal" else s"'\\${str(index + 1)}' not one of $ok at" - }" - - } - """.stripMargin - ) - * - check( - """trait Growable { - | += - |} - """.stripMargin - ) - * - check( - """package immutable { - | object O - |} - """.stripMargin - ) - * - check( - """import java.util.concurrent.TimeUnit.{ NANOSECONDS => NANOS, MILLISECONDS ⇒ MILLIS } - """.stripMargin - ) - * - check( - """class FunFinder{ - | val targetName = s"$name${ if (isModule) "$" else "" }" - |} - """.stripMargin - ) - * - check( - """class AkkaException{ - | for (i ← 0 until trace.length) - | () - |} - """.stripMargin - ) - * - check( - """class FiniteDuration{ - | 1000. - |} - """.stripMargin - ) - * - check( - """object Test4 { - | type T = F @field - | @BeanProperty val x = 1 - |} - """.stripMargin - ) - * - check( - """package `dmacro` { - |} - """.stripMargin - ) - * - check( - """class A { - | def fn1 = List apply 1 - | def fn2 = List apply[Int] 2 - |} - """.stripMargin - ) - * - check( - """class C { - | def this(x: Int) = { - | this(); - | class D; - | } - |} - """.stripMargin - ) - * - check( - """trait B[T] { - | def f1(a: T): Unit { } - |} - """.stripMargin - ) - * - check( - """object test { - | case object Int16 extends SampleFormat1 - | (1) match { - | case _ => 1 - | } - |} - """.stripMargin - ) - * - check( - """object A { - | def x { - | implicit lazy val e: Int = 0 - | } - |} - """.stripMargin - ) - * - check( - """object test { - | for { - | n <- A - | a <- B - | _ <- C - | } yield n - |} - """.stripMargin - ) - * - check( - """object Test { - | def t1: M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[Inty @unchecked]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] = x - |} - """.stripMargin - ) - * - check( - """abstract class Mix___eFoo___wBar_I_ extends Foo___ with Bar_I_ { ; ; f; } - """.stripMargin - ) - } - 'neg{ - * - checkNeg( - """ - |object O{ - | for{ - | x <- Nil map - | - | (x => x) - | } yield x - |} - """.stripMargin - ) - * - checkNeg( - """object O{ - | for{ - | x <- Nil - | if 1 == - | - | 2 - | } yield x - |} - """.stripMargin - ) - * - checkNeg( - """object O{ - | for{ - | x <- Nil - | _ = 1 == - | - | 2 - | } yield x - |} - """.stripMargin - ) - * - checkNeg( - """ - |object System { - | def a[@b T[V @b]] = 1 - |} - | - """.stripMargin - ) + | + |import org.parboiled2._ + |import torimatomeru.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{} + |} + """.stripMargin + ) + * - check( + """ + |object Moo{ + | a + | .b + | + | c + |} + """.stripMargin + ) + * - check( + """ + |object Moo{ + | filename + | .asInstanceOf[Literal] + |10 + |} + """.stripMargin + ) + * - check( + """ + |object Cow{ + | ().mkString + | + | 1 + |} + """.stripMargin + ) + * - check( + """ + |object O{ + | private[this] val applyMacroFull = 1 + |} + """.stripMargin + ) + * - check( + """ + |object O{ + | private[this] def applyMacroFull(c: Context) + | (expr: c.Expr[String], + | runtimeErrors: Boolean, + | debug: Boolean) + | : c.Expr[Frag] = { + | } + |} + """.stripMargin + ) + * - check( + """ + |object O{ + | class DebugFailure extends Exception + | + | 1 + |} + """.stripMargin + ) + * - check( + """ + |package torimatomeru + | + |package syntax + | + |import org.parboiled2._ + | + """.stripMargin + ) + * - check( + """ + |object Foo{ + | 0 match { + | case A | B => 0 + | } + |} + """.stripMargin + ) + * - check( + """ + |object Compiler{ + | + | def apply = { + | def rec = t match { + | case 0 => 0 + | } + | + | rec(tree) + | } + |} + | + """.stripMargin + ) + * - check( + """ + |object O { + | A(A(A(A(A(A(A(A()))))))) + |} + | + """.stripMargin + ) + * - check( + """ + |object O{ + | A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A()))))))))))))))) + |} + """.stripMargin + ) + * - check( + """ + |object L{ + | a.b = c + | a().b = c + |} + """.stripMargin + ) + * - check( + """ + |object L{ + | a b c + | d = 1 + |} + """.stripMargin + ) - } + * - check( + """/* __ *\ + |** ________ ___ / / ___ __ ____ Scala.js CLI ** + |** / __/ __// _ | / / / _ | __ / // __/ (c) 2013-2014, LAMP/EPFL ** + |** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** + |** /____/\___/_/ |_/____/_/ | |__/ /____/ ** + |** |/____/ ** + |\* */ + | + |package scala.scalajs.cli + | + """.stripMargin + ) + * - check( + """ + |object O{ + | for { + | a <- b + | c <- d + | } { + | 1 + | } + |} + """.stripMargin + ) + * - check( + """ + |object O{ + | val jarFile = + | try { 1 } + | catch { case _: F => G } + |} + """.stripMargin + ) + * - check( + """ + |object F{ + | func{ case _: F => fail } + |} + """.stripMargin + ) + * - check( + """ + |object Foo{ + | val a = d // g + | val b = e // h + | val c = f + |} + """.stripMargin + ) + * - check( + """ + |object L{ + | x match{ + | case y.Y(z) => z + | } + |} + """.stripMargin + ) + * - check( + """object K{ + | val a: B { + | val c: D + | } + | + | 1 + |} + """.stripMargin + ) + * - check( + """ + |object LOLS{ + | def run() {} + | + | def apply() {} + |} + """.stripMargin + ) + * - check( + """ + |object O{ + | a =:= b.c + |} + """.stripMargin + ) + * - check( + """ + |object K{ + | a( + | 1: _* + | ) + |} + """.stripMargin + ) + * - check( + """ + |object P{ + | tree match { + | case stats :+ expr => 1 + | } + |} + """.stripMargin + ) + * - check( + """ + |object K{ + | val trueA = 1 + |} + """.stripMargin + ) + * - check( + """ + |object K{ + | val nullo :: cow = 1 + |} + """.stripMargin + ) + * - check( + """ + |object K{ + | val omg_+ = 1 + |} + """.stripMargin + ) + * - check( + """ + |object K{ + | val + = 1 + | var * = 2 + |} + """.stripMargin + ) + * - check( + """ + |object O{ + | c match { + | case b_ => 1 + | } + |} + """.stripMargin + ) + * - check( + """ + |trait Basic { + | b match { + | case C => true; case _ => false + | } + |} + """.stripMargin + ) + * - check( + """trait Basic { + | !a.b + |} + """.stripMargin + ) + * - check( + """ + |class Parser { + | {() => } + |} + | + """.stripMargin + ) + * - check( + """ + | + | + | + |package omg + |; + | + |; + | + |; + |class Parser + |; + | + |; + | + |; + """.stripMargin + ) } def checkFile(path: String) = check(io.Source.fromFile(path).mkString) 'file{ - * - checkFile("scalaParser/src/test/resources/test.scala") + * - checkFile("test.txt") * - checkFile("scalaParser/src/main/scala/scalaParser/syntax/Basic.scala") * - checkFile("scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala") * - checkFile("scalaParser/src/main/scala/scalaParser/syntax/Literals.scala") @@ -859,36 +433,16 @@ object SyntaxTest extends TestSuite{ * - checkFile("scalatexPlugin/src/main/scala/scalatex/ScalaTexPlugin.scala") } - 'omg{ -// val root = new java.io.File("book/target/clones/scala-js/") - val root = new java.io.File("../scala") - def listFiles(s: java.io.File): Iterator[String] = { - val (dirs, files) = s.listFiles().toIterator.partition(_.isDirectory) - files.map(_.getPath) ++ dirs.flatMap(listFiles) - } - // Things that we won't bother parsing, mainly because they use XML literals - val blacklist = Seq( - "dbuild-meta-json-gen.scala", - "genprod.scala", - "doc/html/HtmlPage.scala", - "scala/src/scaladoc/scala/tools/nsc/doc/html", - "jvm/interpreter.scala", - "disabled", // don't bother parsing disabled tests - "neg", // or neg tests - "deprecate-early-type-defs.scala", // or deprecated tests - // Lots of guys in these folders seem - // to be borked, skip all of them - "test/files/positions", - "test/files/presentation" - ) - for{ - f <- listFiles(root) - if f.endsWith(".scala") - if !blacklist.exists(f.contains) - }{ - println("CHECKING " + f) - checkFile(f) - } - } +// 'omg{ +// val root = new java.io.File("../scala-js/") +// def listFiles(s: java.io.File): Iterator[String] = { +// val (dirs, files) = s.listFiles().toIterator.partition(_.isDirectory) +// files.map(_.getPath) ++ dirs.flatMap(listFiles) +// } +// for(f <- listFiles(root).filter(_.endsWith(".scala"))){ +// println("CHECKING " + f) +// checkFile(f) +// } +// } } } \ No newline at end of file -- cgit v1.2.3