From 04a1483c131da376a085c63fc02954f21d3d7a1b Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sun, 16 Nov 2014 14:23:02 -0800 Subject: WIP --- .../src/main/scala/scalatex/stages/Parser.scala | 6 +- .../src/main/scala/torimatomeru/ScalaSyntax.scala | 189 ++--- .../src/test/scala/scalatex/BasicTests.scala | 868 ++++++++++----------- .../src/test/scala/scalatex/ErrorTests.scala | 720 ++++++++--------- .../src/test/scala/scalatex/ParserTests.scala | 40 +- .../src/test/scala/torimatomeru/SyntaxTest.scala | 34 +- 6 files changed, 944 insertions(+), 913 deletions(-) diff --git a/scalatexApi/src/main/scala/scalatex/stages/Parser.scala b/scalatexApi/src/main/scala/scalatex/stages/Parser.scala index 1b67446..8647264 100644 --- a/scalatexApi/src/main/scala/scalatex/stages/Parser.scala +++ b/scalatexApi/src/main/scala/scalatex/stages/Parser.scala @@ -41,7 +41,7 @@ class Parser(input: ParserInput, indent: Int = 0, offset: Int = 0) extends Scala "@" ~ capture(Id | BlockExpr2 | ('(' ~ optional(Exprs) ~ ')')) } def Header = rule { - "@" ~ capture(Def | Import) + "@" ~ capture(Def(false) | Import) } def HeaderBlock: Rule1[Ast.Header] = rule{ @@ -65,7 +65,7 @@ class Parser(input: ParserInput, indent: Int = 0, offset: Int = 0) extends Scala test(cursorNextIndent() > indent) ~ runSubParser(new Parser(_, cursorNextIndent(), cursor).Body) } - def IfHead = rule{ "@" ~ capture("if" ~ "(" ~ Expr ~ ")") } + def IfHead = rule{ "@" ~ capture("if" ~ "(" ~ Expr() ~ ")") } def IfElse1 = rule{ push(offsetCursor) ~ IfHead ~ BraceBlock ~ optional("else" ~ (BraceBlock | IndentBlock)) } @@ -104,7 +104,7 @@ class Parser(input: ParserInput, indent: Int = 0, offset: Int = 0) extends Scala def TypeArgs2 = rule { '[' ~ Ws ~ Types ~ ']' } def ArgumentExprs2 = rule { '(' ~ Ws ~ - (optional(Exprs ~ ',' ~ Ws) ~ PostfixExpr ~ ':' ~ Ws ~ '_' ~ Ws ~ '*' ~ Ws | optional(Exprs) ) ~ + (optional(Exprs ~ ',' ~ Ws) ~ PostfixExpr() ~ ':' ~ Ws ~ '_' ~ Ws ~ '*' ~ Ws | optional(Exprs) ) ~ ')' } def BlockExpr2: Rule0 = rule { '{' ~ Ws ~ (CaseClauses | Block) ~ '}' } diff --git a/scalatexApi/src/main/scala/torimatomeru/ScalaSyntax.scala b/scalatexApi/src/main/scala/torimatomeru/ScalaSyntax.scala index af8495c..4fdef16 100644 --- a/scalatexApi/src/main/scala/torimatomeru/ScalaSyntax.scala +++ b/scalatexApi/src/main/scala/torimatomeru/ScalaSyntax.scala @@ -7,16 +7,24 @@ import org.parboiled2._ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identifiers with Literals { def Whitespace = rule { zeroOrMore(WhitespaceChar | Comment) } + def WhiteLines = rule{ zeroOrMore(WhitespaceChar | Comment | Newline) } + def White(greedy: Boolean = true) = + if (greedy) WhiteLines + else Whitespace /** * Every token handles space at the end. * Don't let it propagate to mixins */ implicit private[this] def wspStr(s: String): Rule0 = rule { - str(s) ~ Whitespace + str(s) ~ WhiteLines } + def wspStrG(s: String, greedy: Boolean): Rule0 = rule { + str(s) ~ White(greedy) + } + implicit private[this] def wspChar(s: Char): Rule0 = rule { - ch(s) ~ Whitespace + ch(s) ~ WhiteLines } def pos = cursor -> cursorChar @@ -33,27 +41,27 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif // only capture super.rule and not the whitespace ////////////////////////////////////////////////// - def IdS = rule { super.Id ~ Whitespace } - def VarIdS = rule { super.VarId ~ Whitespace } - def LiteralS = rule { super.Literal ~ Whitespace } - def SemiS = rule { super.Semi ~ Whitespace } - def NewlineS = rule { super.Newline ~ Whitespace } + def IdS(greedy: Boolean = true) = rule { super.Id ~ White(greedy)} + def VarIdS(greedy: Boolean = true) = rule { super.VarId ~ White(greedy) } + def LiteralS(greedy: Boolean = true) = rule { super.Literal ~ White(greedy) } + def SemiS = rule { super.Semi ~ WhiteLines } + def NewlineS = rule { super.Newline ~ WhiteLines } /////////////////////////////////////////// // Qualifiers and Ids /////////////////////////////////////////// - def QualId = rule { oneOrMore(IdS) separatedBy '.' } - def Ids = rule { oneOrMore(IdS) separatedBy ',' } + def QualId = rule { oneOrMore(IdS()) separatedBy '.' } + def Ids = rule { oneOrMore(IdS()) separatedBy ',' } //path and stableId were refactored (wrt spec) to avoid recursiveness and be more specific - def Path: Rule0 = rule { zeroOrMore(IdS ~ '.') ~ "this" ~ zeroOrMore(IdS).separatedBy('.') | StableId } + def Path: Rule0 = rule { zeroOrMore(IdS() ~ '.') ~ "this" ~ zeroOrMore(IdS()).separatedBy('.') | StableId } def StableId: Rule0 = rule { - zeroOrMore(IdS ~ '.') ~ ("this" | "super" ~ optional(ClassQualifier)) ~ '.' ~ oneOrMore(IdS).separatedBy('.') | - IdS ~ zeroOrMore('.' ~ IdS) + zeroOrMore(IdS() ~ '.') ~ ("this" | "super" ~ optional(ClassQualifier)) ~ '.' ~ oneOrMore(IdS()).separatedBy('.') | + IdS() ~ zeroOrMore('.' ~ IdS()) } // def StableId: Rule0 = rule { zeroOrMore(Id ~ '.') ~ optional("this" | "super" ~ optional(ClassQualifier)) ~ oneOrMore(Id).separatedBy('.') } - def ClassQualifier = rule { '[' ~ IdS ~ ']' } + def ClassQualifier = rule { '[' ~ IdS() ~ ']' } /////////////////////////////////////////// // Types and more Types @@ -65,11 +73,11 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def ExistentialClause = rule { "forSome" ~ '{' ~ oneOrMore(ExistentialDcl).separatedBy(SemiS) } def ExistentialDcl = rule { "type" ~ TypeDcl | "val" ~ ValDcl } - def InfixType = rule { CompoundType ~ zeroOrMore(IdS ~ optional(NewlineS) ~ CompoundType) } + def InfixType = rule { CompoundType ~ zeroOrMore(IdS() ~ optional(NewlineS) ~ CompoundType) } def CompoundType = rule { oneOrMore(AnnotType).separatedBy("with") ~ optional(Refinement) } def AnnotType = rule { SimpleType ~ zeroOrMore(Annotation) } def SimpleType: Rule0 = rule { - BasicType ~ optional('#' ~ IdS) ~ optional(TypeArgs) + BasicType ~ optional('#' ~ IdS()) ~ optional(TypeArgs) } def BasicType: Rule0 = rule { '(' ~ Types ~ ')' | @@ -89,73 +97,73 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif // Declarations, Expressions and Pattern Matching ///////////////////////////////////////////////// - def Expr: Rule0 = rule { (Bindings | optional("implicit") ~ IdS | "_") ~ "=>" ~ Expr | Expr1 } - def Expr1: Rule0 = rule { - IfCFlow | - WhileCFlow | - TryCFlow | - DoWhileCFlow | - ForCFlow | - "throw" ~ Expr | - "return" ~ optional(Expr) | - SimpleExpr ~ ArgumentExprs ~ '=' ~ Expr | - optional(SimpleExpr ~ '.') ~ IdS ~ '=' ~ Expr | - PostfixExpr ~ optional("match" ~ '{' ~ CaseClauses ~ '}' | Ascription) + def Expr(greedy: Boolean = true): Rule0 = rule { (Bindings | optional("implicit") ~ IdS() | "_") ~ "=>" ~ Expr(greedy) | Expr1(greedy) } + def Expr1(greedy: Boolean = true): Rule0 = rule { + IfCFlow(greedy) | + WhileCFlow(greedy) | + TryCFlow(greedy) | + DoWhileCFlow(greedy) | + ForCFlow(greedy) | + "throw" ~ Expr(greedy) | + "return" ~ optional(Expr(greedy)) | + SimpleExpr() ~ ArgumentExprs() ~ '=' ~ Expr(greedy) | + optional(SimpleExpr() ~ '.') ~ IdS() ~ '=' ~ Expr(greedy) | + PostfixExpr(greedy) ~ optional("match" ~ '{' ~ CaseClauses ~ '}' | Ascription) } - def IfCFlow = rule { "if" ~ '(' ~ Expr ~ ')' ~ zeroOrMore(NewlineS) ~ Expr ~ optional(optional(SemiS) ~ "else" ~ Expr) } - def WhileCFlow = rule { "while" ~ '(' ~ Expr ~ ')' ~ zeroOrMore(NewlineS) ~ Expr } - def TryCFlow = rule { "try" ~ '{' ~ Block ~ '}' ~ optional("catch" ~ '{' ~ CaseClauses ~ '}') ~ optional("finally" ~ Expr) } - def DoWhileCFlow = rule { "do" ~ Expr ~ optional(SemiS) ~ "while" ~ '(' ~ Expr ~ ')' } - def ForCFlow = rule { "for" ~ ('(' ~ Enumerators ~ ')' | '{' ~ Enumerators ~ '}') ~ zeroOrMore(NewlineS) ~ optional("yield") ~ Expr } - def PostfixExpr: Rule0 = rule { InfixExpr ~ optional(IdS ~ optional(NewlineS)) } - def InfixExpr: Rule0 = rule { PrefixExpr ~ zeroOrMore(IdS ~ optional(NewlineS) ~ PrefixExpr) } - def PrefixExpr = rule { optional(anyOf("-+~!")) ~ SimpleExpr } - - def SimpleExpr: Rule0 = rule { - SimpleExpr1 ~ zeroOrMore('.' ~ IdS | TypeArgs | ArgumentExprs) ~ optional('_') + def IfCFlow(greedy: Boolean = true) = rule { "if" ~ '(' ~ Expr() ~ ')' ~ zeroOrMore(NewlineS) ~ Expr(greedy) ~ optional(optional(SemiS) ~ "else" ~ Expr(greedy)) } + def WhileCFlow(greedy: Boolean = true) = rule { "while" ~ '(' ~ Expr() ~ ')' ~ zeroOrMore(NewlineS) ~ Expr(greedy) } + def TryCFlow(greedy: Boolean = true) = rule { "try" ~ '{' ~ Block ~ wspStrG("}", greedy) ~ optional("catch" ~ '{' ~ CaseClauses ~ wspStrG("}", greedy)) ~ optional("finally" ~ Expr(greedy)) } + def DoWhileCFlow(greedy: Boolean = true) = rule { "do" ~ Expr() ~ optional(SemiS) ~ "while" ~ '(' ~ Expr() ~ wspStrG(")", greedy) } + def ForCFlow(greedy: Boolean = true) = rule { "for" ~ ('(' ~ Enumerators ~ ')' | '{' ~ Enumerators ~ '}') ~ zeroOrMore(NewlineS) ~ optional("yield") ~ Expr(greedy) } + def PostfixExpr(greedy: Boolean = true): Rule0 = rule { InfixExpr(greedy) ~ optional(IdS() ~ optional(NewlineS)) } + def InfixExpr(greedy: Boolean = true): Rule0 = rule { PrefixExpr(greedy) ~ zeroOrMore(IdS() ~ optional(NewlineS) ~ PrefixExpr(greedy)) } + def PrefixExpr(greedy: Boolean = true) = rule { optional(anyOf("-+~!")) ~ SimpleExpr(greedy) } + + def SimpleExpr(greedy: Boolean = true): Rule0 = rule { + SimpleExpr1(greedy) ~ zeroOrMore('.' ~ IdS() | TypeArgs | ArgumentExprs(greedy)) ~ optional('_') } - def SimpleExpr1 = rule{ + def SimpleExpr1(greedy: Boolean = true) = rule{ "new" ~ (ClassTemplate | TemplateBody) | - BlockExpr | - LiteralS ~ drop[String] | + BlockExpr(greedy) | + LiteralS() ~ drop[String] | Path | '_' | - '(' ~ optional(Exprs) ~ ')' + '(' ~ optional(Exprs) ~ wspStrG(")", greedy) } - def Exprs: Rule0 = rule { oneOrMore(Expr).separatedBy(',') } - def ArgumentExprs: Rule0 = rule { - '(' ~ (optional(Exprs ~ ',') ~ PostfixExpr ~ ':' ~ '_' ~ '*' | optional(Exprs)) ~ ')' | - optional(NewlineS) ~ BlockExpr + def Exprs: Rule0 = rule { oneOrMore(Expr()).separatedBy(',') } + def ArgumentExprs(greedy: Boolean = true): Rule0 = rule { + '(' ~ (optional(Exprs ~ ',') ~ PostfixExpr() ~ ':' ~ '_' ~ '*' | optional(Exprs)) ~ ')' | + optional(NewlineS) ~ BlockExpr(greedy) } - def BlockExpr: Rule0 = rule { '{' ~ (CaseClauses | Block) ~ '}' } - def Block: Rule0 = rule { zeroOrMore(BlockStat ~ SemiS) ~ optional(ResultExpr) } + def BlockExpr(greedy: Boolean = true): Rule0 = rule { '{' ~ (CaseClauses | Block) ~ wspStrG("}", greedy) } + def Block: Rule0 = rule { zeroOrMore(BlockStat ~ SemiS) ~ optional(ResultExpr()) } def BlockStat: Rule0 = rule { &(SemiS) ~ MATCH | //shortcircuit when Semi is found Import | - zeroOrMore(Annotation) ~ (optional("implicit" | "lazy") ~ Def | zeroOrMore(LocalModifier) ~ TmplDef) | - Expr1 + zeroOrMore(Annotation) ~ (optional("implicit" | "lazy") ~ Def(false) | zeroOrMore(LocalModifier) ~ TmplDef) | + Expr1(false) } - def ResultExpr: Rule0 = rule { (Bindings | optional("implicit") ~ IdS | "_") ~ "=>" ~ Block | Expr1 } + def ResultExpr(greedy: Boolean = true): Rule0 = rule { (Bindings | optional("implicit") ~ IdS() | "_") ~ "=>" ~ Block | Expr1(true) } def Enumerators: Rule0 = rule { Generator ~ zeroOrMore(SemiS ~ Enumerator) } - def Enumerator: Rule0 = rule { Generator | Guard | Pattern1 ~ '=' ~ Expr } - def Generator: Rule0 = rule { Pattern1 ~ "<-" ~ Expr ~ optional(Guard) } + def Enumerator: Rule0 = rule { Generator | Guard | Pattern1 ~ '=' ~ Expr() } + def Generator: Rule0 = rule { Pattern1 ~ "<-" ~ Expr() ~ optional(Guard) } def CaseClauses: Rule0 = rule { oneOrMore(CaseClause) } def CaseClause: Rule0 = rule { "case" ~ Pattern ~ optional(Guard) ~ "=>" ~ Block } - def Guard: Rule0 = rule { "if" ~ PostfixExpr } + def Guard: Rule0 = rule { "if" ~ PostfixExpr() } def Pattern: Rule0 = rule { oneOrMore(Pattern1) separatedBy '|' } - def Pattern1: Rule0 = rule { '_' ~ ':' ~ TypePat | VarIdS ~ ':' ~ TypePat | Pattern2 } - def Pattern2: Rule0 = rule { VarIdS ~ optional("@" ~ Pattern3) | Pattern3 } - def Pattern3: Rule0 = rule { SimplePattern ~ zeroOrMore(IdS ~ optional(NewlineS) ~ SimplePattern) } // this pattern doesn't make sense to me... + def Pattern1: Rule0 = rule { '_' ~ ':' ~ TypePat | VarIdS() ~ ':' ~ TypePat | Pattern2 } + def Pattern2: Rule0 = rule { VarIdS() ~ optional("@" ~ Pattern3) | Pattern3 } + def Pattern3: Rule0 = rule { SimplePattern ~ zeroOrMore(IdS() ~ optional(NewlineS) ~ SimplePattern) } // this pattern doesn't make sense to me... def SimplePattern: Rule0 = rule { '_' | - LiteralS ~ drop[String] | //literal currently captures, so it can be used outside. but since all our rules lack AST, we drop its value in order to be able to compose them + LiteralS() ~ drop[String] | //literal currently captures, so it can be used outside. but since all our rules lack AST, we drop its value in order to be able to compose them '(' ~ optional(Patterns) ~ ')' | - StableId ~ '(' ~ (optional(Patterns ~ ',') ~ optional(VarIdS ~ '@') ~ '_' ~ '*' | optional(Patterns)) ~ ')' | - VarIdS /*| + StableId ~ '(' ~ (optional(Patterns ~ ',') ~ optional(VarIdS() ~ '@') ~ '_' ~ '*' | optional(Patterns)) ~ ')' | + VarIdS() /*| XmlPattern*/ } def Patterns: Rule0 = rule { '_' ~ '*' | oneOrMore(Pattern).separatedBy(',') } @@ -163,44 +171,43 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def TypeParamClause: Rule0 = rule { '[' ~ oneOrMore(VariantTypeParam).separatedBy(',') ~ ']' } def FunTypeParamClause: Rule0 = rule { '[' ~ oneOrMore(TypeParam).separatedBy(',') ~ ']' } def VariantTypeParam: Rule0 = rule { zeroOrMore(Annotation) ~ optional(anyOf("+-")) ~ TypeParam } - def TypeParam: Rule0 = rule { (IdS | '_') ~ optional(TypeParamClause) ~ optional(">:" ~ Type) ~ optional("<:" ~ Type) ~ zeroOrMore("<%" ~ Type) ~ zeroOrMore(':' ~ Type) } + def TypeParam: Rule0 = rule { (IdS() | '_') ~ optional(TypeParamClause) ~ optional(">:" ~ Type) ~ optional("<:" ~ Type) ~ zeroOrMore("<%" ~ Type) ~ zeroOrMore(':' ~ Type) } def ParamClauses: Rule0 = rule { zeroOrMore(ParamClause) ~ optional(optional(NewlineS) ~ '(' ~ "implicit" ~ Params ~ ')') } def ParamClause: Rule0 = rule { optional(NewlineS) ~ '(' ~ optional(Params) ~ ')' } def Params: Rule0 = rule { zeroOrMore(Param).separatedBy(',') } - def Param: Rule0 = rule { zeroOrMore(Annotation) ~ IdS ~ optional(':' ~ ParamType) ~ optional('=' ~ Expr) } + def Param: Rule0 = rule { zeroOrMore(Annotation) ~ IdS() ~ optional(':' ~ ParamType) ~ optional('=' ~ Expr()) } def ClassParamClauses: Rule0 = rule { zeroOrMore(ClassParamClause) ~ optional(optional(NewlineS) ~ '(' ~ "implicit" ~ ClassParam ~ ')') } def ClassParamClause: Rule0 = rule { optional(NewlineS) ~ '(' ~ optional(ClassParams) ~ ')' } def ClassParams: Rule0 = rule { oneOrMore(ClassParam).separatedBy(',') } - def ClassParam: Rule0 = rule { zeroOrMore(Annotation) ~ optional(zeroOrMore(Modifier) ~ ("val" | "var")) ~ IdS ~ ":" ~ ParamType ~ optional("=" ~ Expr) } + def ClassParam: Rule0 = rule { zeroOrMore(Annotation) ~ optional(zeroOrMore(Modifier) ~ ("val" | "var")) ~ IdS() ~ ":" ~ ParamType ~ optional("=" ~ Expr()) } def Bindings: Rule0 = rule { '(' ~ oneOrMore(Binding).separatedBy(',') ~ ')' } - def Binding: Rule0 = rule { (IdS | '_') ~ optional(':' ~ Type) } + def Binding: Rule0 = rule { (IdS() | '_') ~ optional(':' ~ Type) } def Modifier: Rule0 = rule { LocalModifier | AccessModifier | "override" } def LocalModifier: Rule0 = rule { "abstract" | "final" | "sealed" | "implicit" | "lazy" } def AccessModifier: Rule0 = rule { ("private" | "protected") ~ optional(AccessQualifier) } - def AccessQualifier: Rule0 = rule { '[' ~ ("this" ~ IdS) ~ ']' } + def AccessQualifier: Rule0 = rule { '[' ~ ("this" ~ IdS()) ~ ']' } - def Annotation: Rule0 = rule { '@' ~ SimpleType ~ zeroOrMore(ArgumentExprs) } - def ConstrAnnotation: Rule0 = rule { '@' ~ SimpleType ~ ArgumentExprs } - def NameValuePair: Rule0 = rule { "val" ~ IdS ~ '=' ~ PrefixExpr } + def Annotation: Rule0 = rule { '@' ~ SimpleType ~ zeroOrMore(ArgumentExprs()) } + def ConstrAnnotation: Rule0 = rule { '@' ~ SimpleType ~ ArgumentExprs() } - def TemplateBody: Rule0 = rule { optional(NewlineS) ~ '{' ~ optional(SelfType) ~ TemplateStat ~ zeroOrMore(SemiS ~ TemplateStat) ~ '}' } - def TemplateStat: Rule0 = rule { + def TemplateBody: Rule0 = rule { optional(NewlineS) ~ '{' ~ optional(SelfType) ~ TemplateStat(false) ~ zeroOrMore(SemiS ~ TemplateStat(false)) ~ '}' } + def TemplateStat(greedy: Boolean = true): Rule0 = rule { Import | - zeroOrMore(Annotation ~ optional(NewlineS)) ~ zeroOrMore(Modifier) ~ (Def | Dcl) | - Expr | - MATCH + zeroOrMore(Annotation ~ optional(NewlineS)) ~ zeroOrMore(Modifier) ~ (Def(greedy) | Dcl) | + Expr(false) | + MATCH } - def SelfType: Rule0 = rule { "this" ~ ':' ~ Type ~ "=>" | IdS ~ optional(':' ~ Type) ~ "=>" } + def SelfType: Rule0 = rule { "this" ~ ':' ~ Type ~ "=>" | IdS() ~ optional(':' ~ Type) ~ "=>" } def Import: Rule0 = rule { "import" ~ oneOrMore(ImportExpr).separatedBy(',') } //ImportExpr is slightly changed wrt spec because StableId always consumes all the Ids possible, so there is no need to one at the end def ImportExpr: Rule0 = rule { StableId ~ optional('.' ~ ('_' | ImportSelectors)) } def ImportSelectors: Rule0 = rule { '{' ~ zeroOrMore(ImportSelector ~ ',') ~ (ImportSelector | '_') ~ '}' } - def ImportSelector: Rule0 = rule { IdS ~ optional("=>" ~ (IdS | '_')) } + def ImportSelector: Rule0 = rule { IdS() ~ optional("=>" ~ (IdS() | '_')) } def Dcl: Rule0 = rule { "val" ~ ValDcl | @@ -211,35 +218,35 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def ValDcl: Rule0 = rule { Ids ~ ':' ~ Type } def VarDcl: Rule0 = rule { Ids ~ ':' ~ Type } def FunDcl: Rule0 = rule { FunSig ~ optional(':' ~ Type) } - def FunSig: Rule0 = rule { IdS ~ optional(FunTypeParamClause) ~ ParamClauses } - def TypeDcl: Rule0 = rule { IdS ~ optional(TypeParamClause) ~ optional(">:" ~ Type) ~ optional("<:" ~ Type) } - - def PatVarDef: Rule0 = rule { "val" ~ PatDef | "var" ~ VarDef } - def Def: Rule0 = rule { "def" ~ FunDef | "type" ~ zeroOrMore(NewlineS) ~ TypeDef | PatVarDef | TmplDef } - def PatDef: Rule0 = rule { oneOrMore(Pattern2).separatedBy(',') ~ optional(':' ~ Type) ~ '=' ~ Expr } - def VarDef: Rule0 = rule { Ids ~ ':' ~ Type ~ '=' ~ '_' | PatDef } - def FunDef: Rule0 = rule { + def FunSig: Rule0 = rule { IdS() ~ optional(FunTypeParamClause) ~ ParamClauses } + def TypeDcl: Rule0 = rule { IdS() ~ optional(TypeParamClause) ~ optional(">:" ~ Type) ~ optional("<:" ~ Type) } + + def PatVarDef(greedy: Boolean = true): Rule0 = rule { "val" ~ PatDef(greedy) | "var" ~ VarDef(greedy) } + def Def(greedy: Boolean = true): Rule0 = rule { "def" ~ FunDef(greedy) | "type" ~ zeroOrMore(NewlineS) ~ TypeDef | PatVarDef(greedy) | TmplDef } + def PatDef(greedy: Boolean = true): Rule0 = rule { oneOrMore(Pattern2).separatedBy(',') ~ optional(':' ~ Type) ~ '=' ~ Expr(greedy) } + def VarDef(greedy: Boolean = true): Rule0 = rule { Ids ~ ':' ~ Type ~ '=' ~ '_' | PatDef(greedy) } + def FunDef(greedy: Boolean = true): Rule0 = rule { "this" ~ ParamClause ~ ParamClauses ~ ('=' ~ ConstrExpr | optional(NewlineS) ~ ConstrBlock) | - FunSig ~ (optional(':' ~ Type) ~ '=' ~ Expr | optional(NewlineS) ~ '{' ~ Block ~ '}') + FunSig ~ (optional(':' ~ Type) ~ '=' ~ Expr(greedy) | optional(NewlineS) ~ '{' ~ Block ~ '}') } - def TypeDef: Rule0 = rule { IdS ~ optional(TypeParamClause) ~ '=' ~ Type } + def TypeDef: Rule0 = rule { IdS() ~ optional(TypeParamClause) ~ '=' ~ Type } def TmplDef: Rule0 = rule { "trait" ~ TraitDef | optional("case") ~ ("class" ~ ClassDef | "object" ~ ObjectDef) } - def ClassDef: Rule0 = rule { IdS ~ optional(TypeParamClause) ~ zeroOrMore(ConstrAnnotation) ~ optional(AccessModifier) ~ ClassParamClauses ~ ClassTemplateOpt } - def TraitDef: Rule0 = rule { IdS ~ optional(TypeParamClause) ~ TraitTemplateOpt } - def ObjectDef: Rule0 = rule { IdS ~ ClassTemplateOpt } + def ClassDef: Rule0 = rule { IdS() ~ optional(TypeParamClause) ~ zeroOrMore(ConstrAnnotation) ~ optional(AccessModifier) ~ ClassParamClauses ~ ClassTemplateOpt } + def TraitDef: Rule0 = rule { IdS() ~ optional(TypeParamClause) ~ TraitTemplateOpt } + def ObjectDef: Rule0 = rule { IdS() ~ ClassTemplateOpt } def ClassTemplateOpt: Rule0 = rule { "extends" ~ ClassTemplate | optional(optional("extends") ~ TemplateBody) } def TraitTemplateOpt: Rule0 = rule { "extends" ~ TraitTemplate | optional(optional("extends") ~ TemplateBody) } def ClassTemplate: Rule0 = rule { optional(EarlyDefs) ~ ClassParents ~ optional(TemplateBody) } def TraitTemplate: Rule0 = rule { optional(EarlyDefs) ~ TraitParents ~ optional(TemplateBody) } def ClassParents: Rule0 = rule { Constr ~ zeroOrMore("with" ~ AnnotType) } def TraitParents: Rule0 = rule { AnnotType ~ zeroOrMore("with" ~ AnnotType) } - def Constr: Rule0 = rule { AnnotType ~ zeroOrMore(ArgumentExprs) } + def Constr: Rule0 = rule { AnnotType ~ zeroOrMore(ArgumentExprs()) } def EarlyDefs: Rule0 = rule { '{' ~ optional(oneOrMore(EarlyDef).separatedBy(SemiS)) ~ '}' ~ "with" } - def EarlyDef: Rule0 = rule { zeroOrMore(Annotation ~ optional(NewlineS)) ~ zeroOrMore(Modifier) ~ PatVarDef } + def EarlyDef: Rule0 = rule { zeroOrMore(Annotation ~ optional(NewlineS)) ~ zeroOrMore(Modifier) ~ PatVarDef(false) } def ConstrExpr: Rule0 = rule { ConstrBlock | SelfInvocation } def ConstrBlock: Rule0 = rule { '{' ~ SelfInvocation ~ zeroOrMore(SemiS ~ BlockStat) ~ '}' } - def SelfInvocation: Rule0 = rule { "this" ~ oneOrMore(ArgumentExprs) } + def SelfInvocation: Rule0 = rule { "this" ~ oneOrMore(ArgumentExprs()) } def TopStatSeq: Rule0 = rule { oneOrMore(TopStat).separatedBy(SemiS) } def TopStat: Rule0 = rule { Packaging | PackageObject | Import | zeroOrMore(Annotation ~ optional(NewlineS)) ~ zeroOrMore(Modifier) ~ TmplDef | MATCH } diff --git a/scalatexApi/src/test/scala/scalatex/BasicTests.scala b/scalatexApi/src/test/scala/scalatex/BasicTests.scala index 4bc362c..fc4bff8 100644 --- a/scalatexApi/src/test/scala/scalatex/BasicTests.scala +++ b/scalatexApi/src/test/scala/scalatex/BasicTests.scala @@ -1,468 +1,468 @@ -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 - """), - "|iamcowhearmemoo|" - ) - } - '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 -

- 2 - 4 -

- """ - ) - } - '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 - """), - """ - omg - omg - """ - ) - } -// 'multiline{ +//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 +// """), +// "|iamcowhearmemoo|" +// ) +// } +// '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(""" -// @div( -// h1("Hello World"), -// p("I am a ", b{"cow"}) -// ) +// @import math._ +// @import Whee.func +// @abs(-10) +// @p +// @max(1, 2) +// @func(2) +// """), +// """ +// 10 +//

+// 2 +// 4 +//

+// """ +// ) +// } +// 'valDefVar{ +// check( +// tw(""" +// Hello +// @val x = 1 +// World @x +// @def y = "omg" +// mooo +// @y // """), // """ -//
-//

Hello World

-//

I am a cow

-//
+// Hello +// World 1 +// mooo +// omg // """ // ) // } - } - '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 - """), - """ -

HelloWorld

-

helloWorld2

-

Cow

- """ - ) - } - 'linearNested{ - check( - tw(""" - @h1 @span @a Hello World - @h2 @span @a hello - @b world - @h3 @i - @div Cow - """), - """ -

HelloWorld -

helloworld -

Cow - """ - ) - } - 'crasher{ - tw(""" -@html - @head - @meta - @div - @a - @span - """) - } - } - 'curlies{ - 'simple{ - val world = "World2" - - check( - tw("""@div{Hello World}"""), - """
HelloWorld
""" - ) - } - 'multiline{ - check( - tw(""" - @div{ - Hello - } - """), - """ -
Hello
- """ - ) - } - } - 'mixed{ - check( - tw(""" - @div{ - Hello - @div - @h1 - WORLD @b{!!!} - lol - @p{ - @h2{Header 2} - } - } - """), - """ -
- Hello -
-

WORLD!!!lol

-

Header2

-
-
- """ - ) - } +// 'classObjectTrait{ +// check( +// tw(""" +// @trait Trait{ +// def tt = 2 +// } +// Hello +// @case object moo extends Trait{ +// val omg = "wtf" +// } // -// 'args{ -// val things = Seq(1, 2, 3) +// @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(""" -// @ul -// @things.map { x => -// @li -// @x -// } +// @div(id:="my-id"){ omg } +// @div(id:="my-id") +// omg +// """), +// """ +// omg +// omg +// """ +// ) +// } +//// 'multiline{ +//// +//// check( +//// tw(""" +//// @div( +//// h1("Hello World"), +//// p("I am a ", b{"cow"}) +//// ) +//// """), +//// """ +////
+////

Hello World

+////

I am a cow

+////
+//// """ +//// ) +//// } +// } +// '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 +// """), +// """ +//

HelloWorld

+//

helloWorld2

+//

Cow

+// """ +// ) +// } +// 'linearNested{ +// check( +// tw(""" +// @h1 @span @a Hello World +// @h2 @span @a hello +// @b world +// @h3 @i +// @div Cow +// """), +// """ +//

HelloWorld +//

helloworld +//

Cow +// """ +// ) +// } +// 'crasher{ // tw(""" -// @ul -// @things.map x => -// @li -// @x +//@html +// @head +// @meta +// @div +// @a +// @span +// """) +// } +// } +// 'curlies{ +// 'simple{ +// val world = "World2" // +// check( +// tw("""@div{Hello World}"""), +// """
HelloWorld
""" +// ) +// } +// 'multiline{ +// check( +// tw(""" +// @div{ +// Hello +// } +// """), +// """ +//
Hello
+// """ +// ) +// } +// } +// 'mixed{ +// check( +// tw(""" +// @div{ +// Hello +// @div +// @h1 +// WORLD @b{!!!} +// lol +// @p{ +// @h2{Header 2} +// } +// } // """), // """ -//
    -//
  • 1
  • -//
  • 2
  • -//
  • 3
  • -//
+//
+// Hello +//
+//

WORLD!!!lol

+//

Header2

+//
+//
// """ // ) // } - } +//// +//// 'args{ +//// val things = Seq(1, 2, 3) +//// check( +//// tw(""" +//// @ul +//// @things.map { x => +//// @li +//// @x +//// } +//// """), +//// tw(""" +//// @ul +//// @things.map x => +//// @li +//// @x +//// +//// """), +//// """ +////
    +////
  • 1
  • +////
  • 2
  • +////
  • 3
  • +////
+//// """ +//// ) +//// } +// } +//// +// 'loops { +//// +// * - check( +// tw(""" +// @for(x <- 0 until 3) +// lol +// """), +// tw(""" +// @for(x <- 0 until 3){ +// lol +// } +// """), +// "lollollol" +// ) // - '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 - } - """), - "

lol00lol01lol10lol11

" - ) - check( - tw(""" - @p - @for(x <- 0 until 2) - @for(y <- 0 until 2) - lol@x@y - """), - "

lol00lol01lol10lol11

" - ) - - * - check( - tw( - """ - @for(x <- 0 until 2; y <- 0 until 2) - @div{@x@y} - - """), - """
00
01
10
11
""" - ) - } - - 'ifElse{ - 'basicExamples{ - * - check( - tw(""" - @if(false) - Hello - @else - lols - @p - """), - "lols

" - ) - - * - check( - tw(""" - @div - @if(true) - Hello - @else - lols - """), - "
Hello
" - ) - - * - check( - tw(""" - @div - @if(true) - Hello - @else - lols - """), - "
Hello
" - ) - * - check( - tw(""" - @if(false) - Hello - @else - lols - """), - "lols" - ) - * - check( - tw(""" - @if(false) - Hello - @else - lols - @img - """), - "lols" - ) - * - check( - tw(""" - @p - @if(true) - Hello - @else - lols - """), - tw(""" - @p - @if(true){ - Hello - }else{ - lols - } - """), - "

Hello

" - ) - } -// 'funkyExpressions{ +// * - 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 +// } +// """), +// "

lol00lol01lol10lol11

" +// ) +// check( +// tw(""" +// @p +// @for(x <- 0 until 2) +// @for(y <- 0 until 2) +// lol@x@y +// """), +// "

lol00lol01lol10lol11

" +// ) +// +// * - check( +// tw( +// """ +// @for(x <- 0 until 2; y <- 0 until 2) +// @div{@x@y} +// +// """), +// """
00
01
10
11
""" +// ) +// } +// +// 'ifElse{ +// 'basicExamples{ // * - check( // tw(""" +// @if(false) +// Hello +// @else +// lols // @p -// @if(true == false == (true.==(false))) -// @if(true == false == (true.==(false))) -// Hello1 -// @else -// lols1 +// """), +// "lols

" +// ) +// +// * - check( +// tw(""" +// @div +// @if(true) +// Hello // @else -// @if(true == false == (true.==(false))) -// Hello2 -// @else -// lols2 +// lols // """), -// "

Hello1

" +// "
Hello
" +// ) +// +// * - check( +// tw(""" +// @div +// @if(true) +// Hello +// @else +// lols +// """), +// "
Hello
" +// ) +// * - check( +// tw(""" +// @if(false) +// Hello +// @else +// lols +// """), +// "lols" +// ) +// * - check( +// tw(""" +// @if(false) +// Hello +// @else +// lols +// @img +// """), +// "lols" // ) // * - check( // tw(""" // @p -// @if(true == false != (true.==(false))) -// @if(true == false != (true.==(false))) -// Hello1 -// @else -// lols1 +// @if(true) +// Hello // @else -// @if(true == false != (true.==(false))) -// Hello2 -// @else -// lols2 +// lols // """), -// "

lols2

" +// tw(""" +// @p +// @if(true){ +// Hello +// }else{ +// lols +// } +// """), +// "

Hello

" // ) // } - } - } - -} +//// '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 +//// """), +//// "

Hello1

" +//// ) +//// * - 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 +//// """), +//// "

lols2

" +//// ) +//// } +// } +// } +// +//} diff --git a/scalatexApi/src/test/scala/scalatex/ErrorTests.scala b/scalatexApi/src/test/scala/scalatex/ErrorTests.scala index d8cd4f5..a7e6155 100644 --- a/scalatexApi/src/test/scala/scalatex/ErrorTests.scala +++ b/scalatexApi/src/test/scala/scalatex/ErrorTests.scala @@ -1,373 +1,373 @@ -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 """, - """ - 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}"), - ^ - """ - ) - +//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("@Seq(1).map{(y: String) => omg}"), -// "type mismatch", -// """ -// twRuntimeErrors("@Seq(1).map{(y: String) => omg}"), -// ^ +// 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 """, +// """ +// 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("@Nil.map{ omg}"), -// "too many arguments for method map", +// 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))"), +// ^ // """ -// twRuntimeErrors("@Nil.map{ omg}"), +// ) +// } +// } +// '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 }"), // ^ // """ // ) - } - '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( +// * - 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(""" -// omg @{() => ()} lol +// @{ +// val x = 1 + 2 +// val y = new Object() +// val z = y * x +// x +// } // """), -// """type mismatch""", +// "value * is not a member of Object", // """ -// omg @{() => ()} lol -// ^ +// val z = y * x +// ^ // """ // ) - - '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/scalatexApi/src/test/scala/scalatex/ParserTests.scala b/scalatexApi/src/test/scala/scalatex/ParserTests.scala index b2e0b74..016ff37 100644 --- a/scalatexApi/src/test/scala/scalatex/ParserTests.scala +++ b/scalatexApi/src/test/scala/scalatex/ParserTests.scala @@ -356,26 +356,26 @@ object ParserTests extends utest.TestSuite{ Text("bbq", 26) )) ) -// * - check( -// """ -// |@omg("lol", -// |1, -// | 2 -// | ) -// | wtf -// |bbq""".stripMargin, -// _.Body.run(), -// Block(Seq( -// Chain("omg",Seq( -// Args("(\"lol\",\n1,\n 2\n )"), -// Block(Seq( -// Text("\n "), Text("wtf") -// )) -// )), -// Text("\n"), -// Text("bbq") -// )) -// ) + * - check( + """ + |@omg("lol", + |1, + | 2 + | ) + | wtf + |bbq""".stripMargin, + _.Body.run(), + Block(Seq( + Chain("omg",Seq( + Args("(\"lol\",\n1,\n 2\n )"), + Block(Seq( + Text("\n "), Text("wtf") + )) + )), + Text("\n"), + Text("bbq") + )) + ) 'codeBlocks - check( """ |@{"lol" * 3} diff --git a/scalatexApi/src/test/scala/torimatomeru/SyntaxTest.scala b/scalatexApi/src/test/scala/torimatomeru/SyntaxTest.scala index 8d5a0d8..c0cbcfa 100644 --- a/scalatexApi/src/test/scala/torimatomeru/SyntaxTest.scala +++ b/scalatexApi/src/test/scala/torimatomeru/SyntaxTest.scala @@ -1,18 +1,42 @@ 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{ def check[T](input: String, parse: ScalaSyntax => scala.util.Try[T], expected: T) = { - val parsed = parse(new ScalaSyntax(input)).get - assert(parsed == expected) + parse(new ScalaSyntax(input)) match{ + case Failure(f: ParseError) => + println(f.formatTraces) + throw new Exception(f.formatTraces) + case Success(parsed) => + assert(parsed == expected) + } + } def tests = TestSuite{ - "omg" - check( - """if (true) () else ()""", - _.IfCFlow.run(), () + * - check( + """(1 + |)""".stripMargin, + _.ArgumentExprs().run(), () + ) + * - check( + """(1, + |)""".stripMargin, + _.ArgumentExprs().run(), () ) +// * - check( +// """(1, 2, +// |3 +// |, +// |4 +// |)""".stripMargin, +// _.ArgumentExprs().run(), () +// ) } } -- cgit v1.2.3