From 5ef6a1dd630764a1ffa6c3b68fff1649c9d89934 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Fri, 28 Nov 2014 04:56:22 -0800 Subject: Removed a bunch of unnecessary `WL`s --- .../src/main/scala/scalaParser/ScalaSyntax.scala | 158 ++-- .../main/scala/scalaParser/syntax/Literals.scala | 7 +- scalaParser/src/test/resources/test.scala | 751 +--------------- .../src/test/scala/scalaParser/SyntaxTest.scala | 956 ++++++++++++--------- 4 files changed, 631 insertions(+), 1241 deletions(-) diff --git a/scalaParser/src/main/scala/scalaParser/ScalaSyntax.scala b/scalaParser/src/main/scala/scalaParser/ScalaSyntax.scala index 8dfe6e7..fe30606 100644 --- a/scalaParser/src/main/scala/scalaParser/ScalaSyntax.scala +++ b/scalaParser/src/main/scala/scalaParser/ScalaSyntax.scala @@ -78,24 +78,27 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def StableId: R0 = { def ClassQualifier = rule { '[' ~ Id ~ ']' } rule { - zeroOrMore(Id ~ '.') ~ (K.W("this") | K.W("super") ~ optional(ClassQualifier)) ~ '.' ~ oneOrMore(Id).separatedBy('.') | - Id ~ zeroOrMore(WL ~ '.' ~ WL ~ Id) + zeroOrMore(Id ~ '.') ~ (K.W("this") | K.W("super") ~ optional(ClassQualifier)) ~ zeroOrMore('.' ~ Id) | + Id ~ zeroOrMore('.' ~ Id) } } def Type: R0 = { + def WildcardType: R0 = rule{ K.W("_") } def ExistentialDcl = rule { K.W("type") ~ TypeDcl | K.W("val") ~ ValDcl } def ExistentialClause = rule { "forSome" ~ '{' ~ oneOrMore(ExistentialDcl).separatedBy(Semi) } def FunctionArgTypes = rule { InfixType | '(' ~ optional(oneOrMore(ParamType) separatedBy ',') ~ ')' } rule { - FunctionArgTypes ~ K.O("=>") ~ Type | InfixType ~ optional(WL ~ ExistentialClause) + (WildcardType | + FunctionArgTypes ~ K.O("=>") ~ Type | + InfixType ~ optional(ExistentialClause)) ~ TypeBounds } } def InfixType = rule { - CompoundType ~ zeroOrMore(WL ~ Id ~ OneNewlineMax ~ CompoundType) + CompoundType ~ zeroOrMore(Id ~ OneNewlineMax ~ CompoundType) } def CompoundType = { def RefineStat = rule { "type" ~ TypeDef | Dcl | MATCH } @@ -103,11 +106,11 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif OneNewlineMax ~ '{' ~ oneOrMore(RefineStat).separatedBy(Semi) ~ "}" } rule { - oneOrMore(AnnotType).separatedBy(WL ~ K.W("with")) ~ optional(Refinement) + oneOrMore(AnnotType).separatedBy(K.W("with")) ~ optional(Refinement) } } def AnnotType = rule { - SimpleType ~ zeroOrMore(WL ~ Annotation) + SimpleType ~ zeroOrMore(Annotation) } def SimpleType: R0 = { def BasicType: R0 = rule { @@ -117,8 +120,8 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif } rule { BasicType ~ - optional(WL ~ '#' ~ Id) ~ - optional(WL ~ TypeArgs) + optional('#' ~ Id) ~ + optional(TypeArgs) } } @@ -147,53 +150,56 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif K.O("=>") } } - def Enumerators: R0 = { - def Generator: R0 = rule { Pattern1 ~ K.O("<-") ~ Expr ~ optional(WL ~ Guard) } - def Enumerator: R0 = rule { Generator | Guard | Pattern1 ~ K.O("=") ~ Expr } - rule { Generator ~ zeroOrMore(Semi ~ Enumerator) ~ WL } + def Enumerators(G: Boolean = false): R0 = { + def Generator: R0 = rule { Pattern1 ~ K.O("<-") ~ Expr0(G) ~ optional(Guard(G)) } + def Enumerator: R0 = rule { Generator | Guard(G) | Pattern1 ~ K.O("=") ~ Expr0(G) } + rule { Generator ~ zeroOrMore(Semis ~ Enumerator) ~ WL } } - def Expr: R0 = { - def IfCFlow = rule { "if" ~ '(' ~ Expr ~ ')' ~ Expr ~ optional(optional(Semi) ~ K.W("else") ~ Expr) } - def WhileCFlow = rule { "while" ~ '(' ~ Expr ~ ')' ~ Expr } + 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") ~ Expr ~ - optional(WL ~ K.W("catch") ~ Expr) ~ - optional(WL ~ K.W("finally") ~ Expr) + K.W("try") ~ Expr0(G) ~ + optional(K.W("catch") ~ Expr0(G)) ~ + optional(K.W("finally") ~ Expr0(G)) } - def DoWhileCFlow = rule { K.W("do") ~ Expr ~ optional(Semi) ~ "while" ~ '(' ~ Expr ~ ")" } + def DoWhileCFlow = rule { K.W("do") ~ Expr0(G) ~ optional(Semi) ~ "while" ~ '(' ~ Expr ~ ")" } def ForCFlow = { rule { "for" ~ - ('(' ~ Enumerators ~ ')' | '{' ~ Enumerators ~ '}') ~ + ('(' ~ Enumerators() ~ ')' | '{' ~ Enumerators(G = true) ~ '}') ~ optional(K.W("yield")) ~ - Expr + Expr0(G) } } rule { zeroOrMore(LambdaHead) ~ ( IfCFlow | - WhileCFlow | - TryCFlow | - DoWhileCFlow | - ForCFlow | - K.W("throw") ~ Expr | - K.W("return") ~ optional(Expr) | - SimpleExpr ~ K.O("=") ~ Expr | - PostfixExpr ~ optional("match" ~ '{' ~ CaseClauses ~ "}" | Ascription) - ) + WhileCFlow | + TryCFlow | + DoWhileCFlow | + ForCFlow | + K.W("throw") ~ Expr0(G) | + K.W("return") ~ optional(Expr0(G)) | + SimpleExpr ~ K.O("=") ~ Expr0(G) | + PostfixExpr(G) ~ optional("match" ~ '{' ~ CaseClauses ~ "}" | Ascription) + ) } } - def PostfixExpr: R0 = { + def PostfixExpr(G: Boolean = false): R0 = { def PrefixExpr = rule { optional(WL ~ anyOf("-+~!")) ~ SimpleExpr } + def Check = if (G) OneNewlineMax else MATCH def InfixExpr: R0 = rule { PrefixExpr ~ zeroOrMore( NotNewline ~ Id ~ - OneNewlineMax ~ + Check ~ PrefixExpr ) } @@ -202,21 +208,21 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def SimpleExpr: R0 = { def Path: R0 = rule { - zeroOrMore(Id ~ '.') ~ K.W("this") ~ zeroOrMore(Id).separatedBy('.') | - StableId + zeroOrMore(Id ~ '.') ~ K.W("this") ~ zeroOrMore('.' ~ Id) | + StableId } def SimpleExpr1 = rule{ K.W("new") ~ (ClassTemplate | TemplateBody) | - BlockExpr | - Literal | - Path | - K.W("_") | - '(' ~ optional(Exprs) ~ ")" + BlockExpr | + Literal | + Path | + K.W("_") | + '(' ~ optional(Exprs) ~ ")" } rule { SimpleExpr1 ~ - zeroOrMore(WL ~ ('.' ~ Id | TypeArgs | ArgumentExprs)) ~ - optional(WL ~ "_") + zeroOrMore('.' ~ Id | TypeArgs | ArgumentExprs) ~ + optional( "_") } } @@ -232,14 +238,15 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def BlockStat: R0 = rule { Import | - zeroOrMore(Annotation) ~ (optional(K.W("implicit") | K.W("lazy")) ~ Def | zeroOrMore(LocalModifier) ~ TmplDef) | - Expr + zeroOrMore(Annotation) ~ (optional(K.W("implicit") | K.W("lazy")) ~ Def | zeroOrMore(LocalModifier) ~ TmplDef) | + Expr0(true) } rule{ oneOrMore(BlockStat).separatedBy(Semis) } } def Block: R0 = { - def BlockEnd: R0 = rule{ optional(Semis) ~ &("}" | "case") } + def BlockEnd: R0 = rule{ optional(Semis) ~ &("}" | K.W("case")) } + def ResultExpr: R0 = Expr0(true) rule { zeroOrMore(LambdaHead) ~ optional(Semis) ~ @@ -251,14 +258,14 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif } } - def ResultExpr: R0 = Expr + def CaseClauses: R0 = { - def CaseClause: R0 = rule { K.W("case") ~ Pattern ~ optional(Guard) ~ K.O("=>") ~ Block } + def CaseClause: R0 = rule { K.W("case") ~ Pattern ~ optional(Guard()) ~ K.O("=>") ~ Block } rule { oneOrMore(CaseClause) } } - def Guard: R0 = rule { K.W("if") ~ PostfixExpr } + def Guard(G: Boolean = false): R0 = rule { K.W("if") ~ PostfixExpr(G) } def Pattern: R0 = rule { oneOrMore(Pattern1).separatedBy('|') } @@ -296,14 +303,16 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif rule { '[' ~ oneOrMore(VariantTypeParam).separatedBy(',') ~ ']' } } def FunTypeParamClause: R0 = rule { '[' ~ oneOrMore(TypeParam).separatedBy(',') ~ ']' } - + def TypeBounds: R0 = rule{ + optional(K.O(">:") ~ Type) ~ + optional(K.O("<:") ~ Type) + } 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) + optional(TypeParamClause) ~ + TypeBounds ~ + zeroOrMore(K.O("<%") ~ Type) ~ + zeroOrMore(K.O(":") ~ Type) } def ParamClauses: R0 = rule { zeroOrMore(ParamClause) ~ optional(OneNewlineMax ~ '(' ~ K.W("implicit") ~ Params ~ ')') @@ -330,7 +339,7 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif rule { (K.W("private") | K.W("protected")) ~ optional(AccessQualifier) } } - def Annotation: R0 = rule { '@' ~ SimpleType ~ zeroOrMore(WL ~ ArgumentExprs) } + def Annotation: R0 = rule { '@' ~ SimpleType ~ zeroOrMore(ArgumentExprs) } def TemplateBody: R0 = rule { '{' ~ @@ -358,7 +367,7 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def Dcl: R0 = { def VarDcl: R0 = rule { Ids ~ K.O(":") ~ Type } - def FunDcl: R0 = rule { FunSig ~ optional(WL ~ K.O(":") ~ Type) } + def FunDcl: R0 = rule { FunSig ~ optional(K.O(":") ~ Type) } rule { K.W("val") ~ ValDcl | @@ -371,9 +380,8 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def ValDcl: R0 = rule { Ids ~ K.O(":") ~ Type } def TypeDcl: R0 = rule { Id ~ - optional(WL ~ TypeParamClause) ~ - optional(WL ~ K.O(">:") ~ Type) ~ - optional(WL ~ K.O("<:") ~ Type) + optional(TypeParamClause) ~ + TypeBounds } def PatVarDef: R0 = { @@ -399,7 +407,7 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def TmplDef: R0 = { def TraitTemplate: R0 = { def TraitParents: R0 = rule { - AnnotType ~ zeroOrMore(WL ~ K.W("with") ~ AnnotType) + AnnotType ~ zeroOrMore(K.W("with") ~ AnnotType) } rule{ optional(EarlyDefs) ~ TraitParents ~ optional(TemplateBody) } } @@ -411,24 +419,28 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif ClassParam ~ ")" } - def ConstrPrelude: R0 = { - def Annot: R0 = rule { '@' ~ SimpleType ~ ArgumentExprs } - rule{ zeroOrMore(Annot) ~ optional(AccessModifier) } - } + def ClassParamClause: R0 = { def ClassParams: R0 = rule { oneOrMore(ClassParam).separatedBy(',') } rule { OneNewlineMax ~'(' ~ optional(ClassParams) ~ ")" } } rule { - ConstrPrelude ~ ( - oneOrMore(ClassParamClause) ~ optional(Implicit) | - Implicit - ) + 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 ~ optional(TypeParamClause) ~ + optional(ConstrPrelude) ~ optional(ClassParamClauses) ~ ClassTemplateOpt } @@ -448,16 +460,16 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif def ObjectDef: R0 = rule { Id ~ ClassTemplateOpt } def ClassTemplateOpt: R0 = rule { - WL ~ K.W("extends") ~ ClassTemplate | - optional(WL ~ optional(K.W("extends")) ~ TemplateBody) + K.W("extends") ~ ClassTemplate | + optional(optional(K.W("extends")) ~ TemplateBody) } def ClassTemplate: R0 = { def ClassParents: R0 = { - def Constr: R0 = rule{ AnnotType ~ zeroOrMore(WL ~ ArgumentExprs) } - rule{ Constr ~ zeroOrMore(WL ~ K.W("with") ~ AnnotType) } + def Constr: R0 = rule{ AnnotType ~ zeroOrMore(ArgumentExprs) } + rule{ Constr ~ zeroOrMore(K.W("with") ~ AnnotType) } } - rule{ optional(EarlyDefs) ~ ClassParents ~ optional(WL ~ TemplateBody) } + rule{ optional(EarlyDefs) ~ ClassParents ~ optional(TemplateBody) } } def EarlyDefs: R0 = { @@ -491,7 +503,7 @@ class ScalaSyntax(val input: ParserInput) extends Parser with Basic with Identif optional(Semis) ~ (TopPackageSeq ~ optional(Semis ~ TopStatSeq) | TopStatSeq) ~ optional(Semis) ~ - WL ~ EOI + WL ) } } diff --git a/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala b/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala index 9fd9d5b..4e3d119 100644 --- a/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala +++ b/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala @@ -16,7 +16,7 @@ trait Literals { self: Parser with Basic with Identifiers => ) } - def IntegerLiteral = rule { (DecimalNumeral | HexNumeral) ~ optional(anyOf("Ll")) } + def IntegerLiteral = rule { (HexNumeral | DecimalNumeral) ~ optional(anyOf("Ll")) } def BooleanLiteral = rule { Key.W("true") | Key.W("false") } @@ -36,7 +36,7 @@ trait Literals { self: Parser with Basic with Identifiers => } - def EscapedChars = rule { '\\' ~ anyOf("rnt\\\"") } + def EscapedChars = rule { '\\' ~ anyOf("rnt\\\"") } // Note that symbols can take on the same values as keywords! def SymbolLiteral = rule { ''' ~ (Identifiers.PlainId | Identifiers.Keywords) } @@ -44,9 +44,10 @@ trait Literals { self: Parser with Basic with Identifiers => def CharacterLiteral = rule { ''' ~ (UnicodeExcape | EscapedChars | !'\\' ~ CharPredicate.from(isPrintableChar)) ~ ''' } def MultiLineChars = rule { zeroOrMore(optional('"') ~ optional('"') ~ noneOf("\"")) } + def pr(s: String) = rule { run(println(s"LOGGING $cursor: $s")) } def StringLiteral = rule { (optional(Identifiers.Id) ~ "\"\"\"" ~ MultiLineChars ~ ("\"\"\"" ~ zeroOrMore('"'))) | - (optional(Identifiers.Id) ~ '"' ~ zeroOrMore("\\\"" | noneOf("\n\"")) ~ '"') + (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 index d560736..a0e847e 100644 --- a/scalaParser/src/test/resources/test.scala +++ b/scalaParser/src/test/resources/test.scala @@ -1,751 +1,4 @@ -/* Scala.js compiler - * Copyright 2013 LAMP/EPFL - * @author Sébastien Doeraene - */ - -package scala.scalajs.compiler - -import scala.collection.mutable - -import scala.tools.nsc._ -import scala.math.PartialOrdering -import scala.reflect.internal.Flags - -import scala.scalajs.ir -import ir.{Trees => js, Types => jstpe} - -import util.ScopedVar -import ScopedVar.withScopedVars - -/** Generation of exports for JavaScript - * - * @author Sébastien Doeraene - */ -trait GenJSExports extends SubComponent { self: GenJSCode => - import global._ - import jsAddons._ - import definitions._ - import jsDefinitions._ - - trait JSExportsPhase { this: JSCodePhase => - - /** - * Generate exporter methods for a class - * @param classSym symbol of class we export for - * @param decldExports symbols exporter methods that have been encountered in - * the class' tree. This is not the same as classSym.info.delcs since - * inherited concrete methods from traits should be in this param, too - */ - def genMemberExports( - classSym: Symbol, - decldExports: List[Symbol]): List[js.Tree] = { - - val newlyDecldExports = decldExports.filterNot { isOverridingExport _ } - val newlyDecldExportNames = - newlyDecldExports.map(_.name.toTermName).toList.distinct - - newlyDecldExportNames map { genMemberExport(classSym, _) } - } - - def genConstructorExports(classSym: Symbol): List[js.ConstructorExportDef] = { - val constructors = classSym.tpe.member(nme.CONSTRUCTOR).alternatives - - // Generate exports from constructors and their annotations - val ctorExports = for { - ctor <- constructors - exp <- jsInterop.exportsOf(ctor) - } yield (exp, ctor) - - val exports = for { - (jsName, specs) <- ctorExports.groupBy(_._1.jsName) // group by exported name - } yield { - val (namedExports, normalExports) = specs.partition(_._1.isNamed) - - val normalCtors = normalExports.map(s => ExportedSymbol(s._2)) - val namedCtors = for { - (exp, ctor) <- namedExports - } yield { - implicit val pos = exp.pos - ExportedBody(List(JSAnyTpe), - genNamedExporterBody(ctor, genFormalArg(1).ref), - nme.CONSTRUCTOR.toString, pos) - } - - val ctors = normalCtors ++ namedCtors - - implicit val pos = ctors.head.pos - - val js.MethodDef(_, args, _, body) = - withNewLocalNameScope(genExportMethod(ctors, jsName)) - - js.ConstructorExportDef(jsName, args, body) - } - - exports.toList - } - - def genModuleAccessorExports(classSym: Symbol): List[js.ModuleExportDef] = { - for { - exp <- jsInterop.exportsOf(classSym) - } yield { - implicit val pos = exp.pos - - if (exp.isNamed) - reporter.error(pos, "You may not use @JSNamedExport on an object") - - js.ModuleExportDef(exp.jsName) - } - } - - /** Generate the exporter proxy for a named export */ - def genNamedExporterDef(dd: DefDef): js.MethodDef = { - implicit val pos = dd.pos - - val sym = dd.symbol - - val Block(Apply(fun, _) :: Nil, _) = dd.rhs - val trgSym = fun.symbol - - val inArg = - js.ParamDef(js.Ident("namedParams"), jstpe.AnyType, mutable = false) - val inArgRef = inArg.ref - - val methodIdent = encodeMethodSym(sym) - - withScopedVars( - currentMethodInfoBuilder := - currentClassInfoBuilder.addMethod(methodIdent.name) - ) { - js.MethodDef(methodIdent, List(inArg), toIRType(sym.tpe.resultType), - genNamedExporterBody(trgSym, inArg.ref))(None) - } - } - - private def genNamedExporterBody(trgSym: Symbol, inArg: js.Tree)( - implicit pos: Position) = { - - if (hasRepeatedParam(trgSym)) { - reporter.error(pos, - "You may not name-export a method with a *-parameter") - } - - val jsArgs = for { - (pSym, index) <- trgSym.info.params.zipWithIndex - } yield { - val rhs = js.JSBracketSelect(inArg, - js.StringLiteral(pSym.name.decoded)) - js.VarDef(js.Ident("namedArg$" + index), jstpe.AnyType, - mutable = false, rhs = rhs) - } - - val jsArgRefs = jsArgs.map(_.ref) - - // Generate JS code to prepare arguments (default getters and unboxes) - val jsArgPrep = genPrepareArgs(jsArgRefs, trgSym) - val jsResult = genResult(trgSym, jsArgPrep.map(_.ref)) - - js.Block(jsArgs ++ jsArgPrep :+ jsResult) - } - - private def genMemberExport(classSym: Symbol, name: TermName): js.Tree = { - val alts = classSym.info.member(name).alternatives - - assert(!alts.isEmpty, - s"Ended up with no alternatives for ${classSym.fullName}::$name. " + - s"Original set was ${alts} with types ${alts.map(_.tpe)}") - - val (jsName, isProp) = jsInterop.jsExportInfo(name) - - // Check if we have a conflicting export of the other kind - val conflicting = - classSym.info.member(jsInterop.scalaExportName(jsName, !isProp)) - - if (conflicting != NoSymbol) { - val kind = if (isProp) "property" else "method" - val alts = conflicting.alternatives - - reporter.error(alts.head.pos, - s"Exported $kind $jsName conflicts with ${alts.head.fullName}") - } - - withNewLocalNameScope { - if (isProp) - genExportProperty(alts, jsName) - else - genExportMethod(alts.map(ExportedSymbol), jsName) - } - } - - private def genExportProperty(alts: List[Symbol], jsName: String) = { - assert(!alts.isEmpty) - implicit val pos = alts.head.pos - - // Separate getters and setters. Somehow isJSGetter doesn't work here. Hence - // we just check the parameter list length. - val (getter, setters) = alts.partition(_.tpe.params.isEmpty) - - // if we have more than one getter, something went horribly wrong - assert(getter.size <= 1, - s"Found more than one getter to export for name ${jsName}.") - - val getTree = - if (getter.isEmpty) js.EmptyTree - else genApplyForSym(getter.head) - - val setTree = - if (setters.isEmpty) js.EmptyTree - else genExportSameArgc(setters.map(ExportedSymbol), 0) // we only have 1 argument - - js.PropertyDef(js.StringLiteral(jsName), getTree, genFormalArg(1), setTree) - } - - /** generates the exporter function (i.e. exporter for non-properties) for - * a given name */ - private def genExportMethod(alts0: List[Exported], jsName: String) = { - assert(alts0.nonEmpty, - "need at least one alternative to generate exporter method") - - implicit val pos = alts0.head.pos - - val alts = { - // toString() is always exported. We might need to add it here - // to get correct overloading. - if (jsName == "toString" && alts0.forall(_.params.nonEmpty)) - ExportedSymbol(Object_toString) :: alts0 - else - alts0 - } - - // Factor out methods with variable argument lists. Note that they can - // only be at the end of the lists as enforced by PrepJSExports - val (varArgMeths, normalMeths) = alts.partition(_.hasRepeatedParam) - - // Highest non-repeated argument count - val maxArgc = ( - // We have argc - 1, since a repeated parameter list may also be empty - // (unlike a normal parameter) - varArgMeths.map(_.params.size - 1) ++ - normalMeths.map(_.params.size) - ).max - - val formalArgs = genFormalArgs(maxArgc) - - // Calculates possible arg counts for normal method - def argCounts(ex: Exported) = ex match { - case ExportedSymbol(sym) => - val params = sym.tpe.params - // Find default param - val dParam = params.indexWhere { _.hasFlag(Flags.DEFAULTPARAM) } - if (dParam == -1) Seq(params.size) - else dParam to params.size - case ex: ExportedBody => - List(ex.params.size) - } - - // Generate tuples (argc, method) - val methodArgCounts = { - // Normal methods - for { - method <- normalMeths - argc <- argCounts(method) - } yield (argc, method) - } ++ { - // Repeated parameter methods - for { - method <- varArgMeths - argc <- method.params.size - 1 to maxArgc - } yield (argc, method) - } - - // Create a map: argCount -> methods (methods may appear multiple times) - val methodByArgCount = - methodArgCounts.groupBy(_._1).mapValues(_.map(_._2).toSet) - - // Create tuples: (methods, argCounts). This will be the cases we generate - val caseDefinitions = - methodByArgCount.groupBy(_._2).mapValues(_.keySet) - - // Verify stuff about caseDefinitions - assert({ - val argcs = caseDefinitions.values.flatten.toList - argcs == argcs.distinct && - argcs.forall(_ <= maxArgc) - }, "every argc should appear only once and be lower than max") - - // Generate a case block for each (methods, argCounts) tuple - val cases = for { - (methods, argcs) <- caseDefinitions - if methods.nonEmpty && argcs.nonEmpty - - // exclude default case we're generating anyways for varargs - if methods != varArgMeths.toSet - - // body of case to disambiguates methods with current count - caseBody = - genExportSameArgc(methods.toList, 0, Some(argcs.min)) - - // argc in reverse order - argcList = argcs.toList.sortBy(- _) - } yield (argcList.map(js.IntLiteral(_)), caseBody) - - val hasVarArg = varArgMeths.nonEmpty - - def defaultCase = { - if (!hasVarArg) - genThrowTypeError() - else - genExportSameArgc(varArgMeths, 0) - } - - val body = { - if (cases.isEmpty) - defaultCase - else if (cases.size == 1 && !hasVarArg) - cases.head._2 - else { - js.Match( - js.Unbox(js.JSBracketSelect( - js.VarRef(js.Ident("arguments"), false)(jstpe.AnyType), - js.StringLiteral("length")), - 'I'), - cases.toList, defaultCase)(jstpe.AnyType) - } - } - - js.MethodDef(js.StringLiteral(jsName), formalArgs, jstpe.AnyType, body)(None) - } - - /** - * Resolve method calls to [[alts]] while assuming they have the same - * parameter count. - * @param alts Alternative methods - * @param paramIndex Index where to start disambiguation - * @param maxArgc only use that many arguments - */ - private def genExportSameArgc(alts: List[Exported], - paramIndex: Int, maxArgc: Option[Int] = None): js.Tree = { - - implicit val pos = alts.head.pos - - if (alts.size == 1) - alts.head.body - else if (maxArgc.exists(_ <= paramIndex) || - !alts.exists(_.params.size > paramIndex)) { - // We reach here in three cases: - // 1. The parameter list has been exhausted - // 2. The optional argument count restriction has triggered - // 3. We only have (more than once) repeated parameters left - // Therefore, we should fail - reporter.error(pos, - s"""Cannot disambiguate overloads for exported method ${alts.head.name} with types - | ${alts.map(_.typeInfo).mkString("\n ")}""".stripMargin) - js.Undefined() - } else { - - val altsByTypeTest = groupByWithoutHashCode(alts) { - case ExportedSymbol(alt) => - // get parameter type while resolving repeated params - val tpe = enteringPhase(currentRun.uncurryPhase) { - val ps = alt.paramss.flatten - if (ps.size <= paramIndex || isRepeated(ps(paramIndex))) { - assert(isRepeated(ps.last)) - repeatedToSingle(ps.last.tpe) - } else { - enteringPhase(currentRun.posterasurePhase) { - ps(paramIndex).tpe - } - } - } - - typeTestForTpe(tpe) - - case ex: ExportedBody => - typeTestForTpe(ex.params(paramIndex)) - } - - if (altsByTypeTest.size == 1) { - // Testing this parameter is not doing any us good - genExportSameArgc(alts, paramIndex+1, maxArgc) - } else { - // Sort them so that, e.g., isInstanceOf[String] - // comes before isInstanceOf[Object] - val sortedAltsByTypeTest = topoSortDistinctsBy( - altsByTypeTest)(_._1)(RTTypeTest.Ordering) - - val defaultCase = genThrowTypeError() - - sortedAltsByTypeTest.foldRight[js.Tree](defaultCase) { (elem, elsep) => - val (typeTest, subAlts) = elem - implicit val pos = subAlts.head.pos - - val param = genFormalArg(paramIndex+1) - val genSubAlts = genExportSameArgc(subAlts, paramIndex+1, maxArgc) - - def hasDefaultParam = subAlts.exists { - case ExportedSymbol(p) => - val params = p.tpe.params - params.size > paramIndex && - params(paramIndex).hasFlag(Flags.DEFAULTPARAM) - case _: ExportedBody => false - } - - val optCond = typeTest match { - case HijackedTypeTest(boxedClassName, _) => - Some(js.IsInstanceOf(param.ref, jstpe.ClassType(boxedClassName))) - - case InstanceOfTypeTest(tpe) => - Some(genIsInstanceOf(param.ref, tpe)) - - case NoTypeTest => - None - } - - optCond.fold[js.Tree] { - genSubAlts // note: elsep is discarded, obviously - } { cond => - val condOrUndef = if (!hasDefaultParam) cond else { - js.If(cond, js.BooleanLiteral(true), - js.BinaryOp(js.BinaryOp.===, param.ref, js.Undefined()))( - jstpe.BooleanType) - } - js.If(condOrUndef, genSubAlts, elsep)(jstpe.AnyType) - } - } - } - } - } - - /** - * Generate a call to the method [[sym]] while using the formalArguments - * and potentially the argument array. Also inserts default parameters if - * required. - */ - private def genApplyForSym(sym: Symbol): js.Tree = { - implicit val pos = sym.pos - - // the (single) type of the repeated parameter if any - val repeatedTpe = enteringPhase(currentRun.uncurryPhase) { - for { - param <- sym.paramss.flatten.lastOption - if isRepeated(param) - } yield repeatedToSingle(param.tpe) - } - - val normalArgc = sym.tpe.params.size - - (if (repeatedTpe.isDefined) 1 else 0) - - // optional repeated parameter list - val jsVarArg = repeatedTpe map { tpe => - // Copy arguments that go to vararg into an array, put it in a wrapper - - val countIdent = freshLocalIdent("count") - val count = js.VarRef(countIdent, mutable = false)(jstpe.IntType) - - val counterIdent = freshLocalIdent("i") - val counter = js.VarRef(counterIdent, mutable = true)(jstpe.IntType) - - val arrayIdent = freshLocalIdent("varargs") - val array = js.VarRef(arrayIdent, mutable = false)(jstpe.AnyType) - - val arguments = js.VarRef(js.Ident("arguments"), - mutable = false)(jstpe.AnyType) - val argLen = js.Unbox( - js.JSBracketSelect(arguments, js.StringLiteral("length")), 'I') - val argOffset = js.IntLiteral(normalArgc) - - val jsArrayCtor = - js.JSBracketSelect( - js.JSBracketSelect(js.JSEnvInfo(), js.StringLiteral("global")), - js.StringLiteral("Array")) - - js.Block( - // var i = 0 - js.VarDef(counterIdent, jstpe.IntType, mutable = true, - rhs = js.IntLiteral(0)), - // val count = arguments.length - - js.VarDef(countIdent, jstpe.IntType, mutable = false, - rhs = js.BinaryOp(js.BinaryOp.Int_-, argLen, argOffset)), - // val varargs = new Array(count) - js.VarDef(arrayIdent, jstpe.AnyType, mutable = false, - rhs = js.JSNew(jsArrayCtor, List(count))), - // while (i < count) - js.While(js.BinaryOp(js.BinaryOp.Num_<, counter, count), js.Block( - // varargs[i] = arguments[ + i]; - js.Assign( - js.JSBracketSelect(array, counter), - js.JSBracketSelect(arguments, - js.BinaryOp(js.BinaryOp.Int_+, argOffset, counter))), - // i = i + 1 (++i won't work, desugar eliminates it) - js.Assign(counter, js.BinaryOp(js.BinaryOp.Int_+, - counter, js.IntLiteral(1))) - )), - // new WrappedArray(varargs) - genNew(WrappedArrayClass, WrappedArray_ctor, List(array)) - ) - } - - // normal arguments - val jsArgs = genFormalArgs(normalArgc) - val jsArgRefs = jsArgs.map(_.ref) - - // Generate JS code to prepare arguments (default getters and unboxes) - val jsArgPrep = genPrepareArgs(jsArgRefs, sym) - val jsResult = genResult(sym, jsArgPrep.map(_.ref) ++ jsVarArg) - - js.Block(jsArgPrep :+ jsResult) - } - - /** Generate the necessary JavaScript code to prepare the arguments of an - * exported method (unboxing and default parameter handling) - */ - private def genPrepareArgs(jsArgs: List[js.VarRef], sym: Symbol)( - implicit pos: Position): List[js.VarDef] = { - - val result = new mutable.ListBuffer[js.VarDef] - - val funTpe = enteringPhase(currentRun.posterasurePhase)(sym.tpe) - for { - (jsArg, (param, i)) <- jsArgs zip funTpe.params.zipWithIndex - } yield { - // Code to verify the type of the argument (if it is defined) - val verifiedArg = { - val tpePosterasure = - enteringPhase(currentRun.posterasurePhase)(param.tpe) - tpePosterasure match { - case tpe if isPrimitiveValueType(tpe) => - val unboxed = makePrimitiveUnbox(jsArg, tpe) - // Ensure we don't convert null to a primitive value type - js.If(js.BinaryOp(js.BinaryOp.===, jsArg, js.Null()), - genThrowTypeError(s"Found null, expected $tpe"), - unboxed)(unboxed.tpe) - case tpe: ErasedValueType => - val boxedClass = tpe.valueClazz - val unboxMethod = boxedClass.derivedValueClassUnbox - genApplyMethod( - genAsInstanceOf(jsArg, tpe), - boxedClass, unboxMethod, Nil) - case tpe => - genAsInstanceOf(jsArg, tpe) - } - } - - // If argument is undefined and there is a default getter, call it - val verifiedOrDefault = if (param.hasFlag(Flags.DEFAULTPARAM)) { - js.If(js.BinaryOp(js.BinaryOp.===, jsArg, js.Undefined()), { - val trgSym = { - if (sym.isClassConstructor) sym.owner.companionModule.moduleClass - else sym.owner - } - val defaultGetter = trgSym.tpe.member( - nme.defaultGetterName(sym.name, i+1)) - - assert(defaultGetter.exists, - s"need default getter for method ${sym.fullName}") - assert(!defaultGetter.isOverloaded) - - val trgTree = { - if (sym.isClassConstructor) genLoadModule(trgSym) - else js.This()(encodeClassType(trgSym)) - } - - // Pass previous arguments to defaultGetter - genApplyMethod(trgTree, trgSym, defaultGetter, - result.take(defaultGetter.tpe.params.size).toList.map(_.ref)) - }, { - // Otherwise, unbox the argument - verifiedArg - })(verifiedArg.tpe) - } else { - // Otherwise, it is always the unboxed argument - verifiedArg - } - - result += - js.VarDef(js.Ident("prep"+jsArg.ident.name, jsArg.ident.originalName), - verifiedOrDefault.tpe, mutable = false, verifiedOrDefault) - } - - result.toList - } - - /** Generate the final forwarding call to the exported method. - * Attention: This method casts the arguments to the right type. The IR - * checker will not detect if you pass in a wrongly typed argument. - */ - private def genResult(sym: Symbol, - args: List[js.Tree])(implicit pos: Position) = { - val thisType = - if (sym.owner == ObjectClass) jstpe.ClassType(ir.Definitions.ObjectClass) - else encodeClassType(sym.owner) - val call = genApplyMethod(js.This()(thisType), sym.owner, sym, args) - ensureBoxed(call, - enteringPhase(currentRun.posterasurePhase)(sym.tpe.resultType)) - } - - private sealed abstract class Exported { - def pos: Position - def params: List[Type] - def body: js.Tree - def name: String - def typeInfo: String - def hasRepeatedParam: Boolean - } - - private case class ExportedSymbol(sym: Symbol) extends Exported { - def pos: Position = sym.pos - def params: List[Type] = sym.tpe.params.map(_.tpe) - def body: js.Tree = genApplyForSym(sym) - def name: String = sym.name.toString - def typeInfo: String = sym.tpe.toString - def hasRepeatedParam: Boolean = GenJSExports.this.hasRepeatedParam(sym) - } - - private case class ExportedBody(params: List[Type], body: js.Tree, - name: String, pos: Position) extends Exported { - def typeInfo: String = params.mkString("(", ", ", ")") - val hasRepeatedParam: Boolean = false - } - } - - private def isOverridingExport(sym: Symbol): Boolean = { - lazy val osym = sym.nextOverriddenSymbol - sym.isOverridingSymbol && !osym.owner.isInterface - } - - private sealed abstract class RTTypeTest - - private final case class HijackedTypeTest( - boxedClassName: String, rank: Int) extends RTTypeTest - - private final case class InstanceOfTypeTest(tpe: Type) extends RTTypeTest { - override def equals(that: Any): Boolean = { - that match { - case InstanceOfTypeTest(thatTpe) => tpe =:= thatTpe - case _ => false - } - } - } - - private case object NoTypeTest extends RTTypeTest - - private object RTTypeTest { - implicit object Ordering extends PartialOrdering[RTTypeTest] { - override def tryCompare(lhs: RTTypeTest, rhs: RTTypeTest): Option[Int] = { - if (lteq(lhs, rhs)) if (lteq(rhs, lhs)) Some(0) else Some(-1) - else if (lteq(rhs, lhs)) Some(1) else None - } - - override def lteq(lhs: RTTypeTest, rhs: RTTypeTest): Boolean = { - (lhs, rhs) match { - // NoTypeTest is always last - case (_, NoTypeTest) => true - case (NoTypeTest, _) => false - - case (HijackedTypeTest(_, rank1), HijackedTypeTest(_, rank2)) => - rank1 <= rank2 - - case (InstanceOfTypeTest(t1), InstanceOfTypeTest(t2)) => - t1 <:< t2 - - case (_:HijackedTypeTest, _:InstanceOfTypeTest) => true - case (_:InstanceOfTypeTest, _:HijackedTypeTest) => false - } - } - - override def equiv(lhs: RTTypeTest, rhs: RTTypeTest): Boolean = { - lhs == rhs - } - } - } - - // Very simple O(n²) topological sort for elements assumed to be distinct - private def topoSortDistinctsBy[A <: AnyRef, B](coll: List[A])(f: A => B)( - implicit ord: PartialOrdering[B]): List[A] = { - - @scala.annotation.tailrec - def loop(coll: List[A], acc: List[A]): List[A] = { - if (coll.isEmpty) acc - else if (coll.tail.isEmpty) coll.head :: acc - else { - val (lhs, rhs) = coll.span(x => !coll.forall( - y => (x eq y) || !ord.lteq(f(x), f(y)))) - assert(!rhs.isEmpty, s"cycle while ordering $coll") - loop(lhs ::: rhs.tail, rhs.head :: acc) - } - } - - loop(coll, Nil) - } - - private def typeTestForTpe(tpe: Type): RTTypeTest = { - tpe match { - case tpe: ErasedValueType => - InstanceOfTypeTest(tpe.valueClazz.typeConstructor) - - case _ => - import ir.{Definitions => Defs} - (toTypeKind(tpe): @unchecked) match { - case VoidKind => HijackedTypeTest(Defs.BoxedUnitClass, 0) - case BooleanKind => HijackedTypeTest(Defs.BoxedBooleanClass, 1) - case ByteKind => HijackedTypeTest(Defs.BoxedByteClass, 2) - case ShortKind => HijackedTypeTest(Defs.BoxedShortClass, 3) - case IntKind => HijackedTypeTest(Defs.BoxedIntegerClass, 4) - case FloatKind => HijackedTypeTest(Defs.BoxedFloatClass, 5) - case DoubleKind => HijackedTypeTest(Defs.BoxedDoubleClass, 6) - - case CharKind => InstanceOfTypeTest(boxedClass(CharClass).tpe) - case LongKind => InstanceOfTypeTest(boxedClass(LongClass).tpe) - - case REFERENCE(cls) => - if (cls == StringClass) HijackedTypeTest(Defs.StringClass, 7) - else if (cls == ObjectClass) NoTypeTest - else if (isRawJSType(tpe)) { - cls match { - case JSUndefinedClass => HijackedTypeTest(Defs.BoxedUnitClass, 0) - case JSBooleanClass => HijackedTypeTest(Defs.BoxedBooleanClass, 1) - case JSNumberClass => HijackedTypeTest(Defs.BoxedDoubleClass, 6) - case JSStringClass => HijackedTypeTest(Defs.StringClass, 7) - case _ => NoTypeTest - } - } else InstanceOfTypeTest(tpe) - - case ARRAY(_) => InstanceOfTypeTest(tpe) - } - } - } - - // Group-by that does not rely on hashCode(), only equals() - O(n²) - private def groupByWithoutHashCode[A, B]( - coll: List[A])(f: A => B): List[(B, List[A])] = { - - import scala.collection.mutable.ArrayBuffer - val m = new ArrayBuffer[(B, List[A])] - m.sizeHint(coll.length) - - for (elem <- coll) { - val key = f(elem) - val index = m.indexWhere(_._1 == key) - if (index < 0) m += ((key, List(elem))) - else m(index) = (key, elem :: m(index)._2) - } - - m.toList - } - - private def genThrowTypeError(msg: String = "No matching overload")( - implicit pos: Position): js.Tree = { - js.Throw(js.StringLiteral(msg)) - } - - private def genFormalArgs(count: Int)(implicit pos: Position): List[js.ParamDef] = - (1 to count map genFormalArg).toList - - private def genFormalArg(index: Int)(implicit pos: Position): js.ParamDef = - js.ParamDef(js.Ident("arg$" + index), jstpe.AnyType, mutable = false) - - private def hasRepeatedParam(sym: Symbol) = - enteringPhase(currentRun.uncurryPhase) { - sym.paramss.flatten.lastOption.exists(isRepeated _) - } +object System { + def a[@b T] = 1 } diff --git a/scalaParser/src/test/scala/scalaParser/SyntaxTest.scala b/scalaParser/src/test/scala/scalaParser/SyntaxTest.scala index 45f86b2..0f9b734 100644 --- a/scalaParser/src/test/scala/scalaParser/SyntaxTest.scala +++ b/scalaParser/src/test/scala/scalaParser/SyntaxTest.scala @@ -8,6 +8,13 @@ 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{ @@ -27,429 +34,546 @@ object SyntaxTest extends TestSuite{ println("running") def tests = TestSuite{ 'unit { - * - 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{ - | - | 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 - ) + 'pos { + * - check( + "package torimatomeru" - * - check( - """/* __ *\ - |** ________ ___ / / ___ __ ____ Scala.js CLI ** - |** / __/ __// _ | / / / _ | __ / // __/ (c) 2013-2014, LAMP/EPFL ** - |** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** - |** /____/\___/_/ |_/____/_/ | |__/ /____/ ** - |** |/____/ ** - |\* */ + ) + * - 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{ | - |package scala.scalajs.cli + | def apply = { + | def rec = t match { + | case 0 => 0 + | } | - """.stripMargin - ) - * - check( - """ - |object O{ - | for { - | a <- b - | c <- d - | } { - | 1 + | rec(tree) | } |} - """.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 - ) + """. + 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 + ) + } + '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 + ) + } } def checkFile(path: String) = check(io.Source.fromFile(path).mkString) 'file{ -- cgit v1.2.3