package dotty.tools package dotc package parsing import util.SourceFile import core._ import Contexts._ import Parsers._ /**

Performs the following context-free rewritings:

*
    *
  1. * Places all pattern variables in Bind nodes. In a pattern, for * identifiers x:
     *                 x  => x @ _
     *               x:T  => x @ (_ : T)
    *
  2. *
  3. Removes pattern definitions (PatDef's) as follows: * If pattern is a simple (typed) identifier:
     *        val x = e     ==>  val x = e
     *        val x: T = e  ==>  val x: T = e
    * * if there are no variables in pattern
     *        val p = e  ==>  e match (case p => ())
    * * if there is exactly one variable in pattern
     *        val x_1 = e match (case p => (x_1))
    * * if there is more than one variable in pattern
     *        val p = e  ==>  private synthetic val t$ = e match (case p => (x_1, ..., x_N))
     *                        val x_1 = t$._1
     *                        ...
     *                        val x_N = t$._N
    *
  4. *
  5. * Removes function types as follows:
     *        (argtpes) => restpe   ==>   scala.Function_n[argtpes, restpe]
    *
  6. *
  7. * Wraps naked case definitions in a match as follows:
     *        { cases }   ==>   (x => x.match {cases}), except when already argument to match
    *
  8. *
*/ object ScriptParsers { import ast.untpd._ class ScriptParser(source: SourceFile)(implicit ctx: Context) extends Parser(source) { /** This is the parse entry point for code which is not self-contained, e.g. * a script which is a series of template statements. They will be * swaddled in Trees until the AST is equivalent to the one returned * by compilationUnit(). */ override def parse(): Tree = unsupported("parse") /* TODO: reinstantiate val stmts = templateStatSeq(false)._2 accept(EOF) def mainModuleName = ctx.settings.script.value /** If there is only a single object template in the file and it has a * suitable main method, we will use it rather than building another object * around it. Since objects are loaded lazily the whole script would have * been a no-op, so we're not taking much liberty. */ def searchForMain(): Option[Tree] = { /** Have to be fairly liberal about what constitutes a main method since * nothing has been typed yet - for instance we can't assume the parameter * type will look exactly like "Array[String]" as it could have been renamed * via import, etc. */ def isMainMethod(t: Tree) = t match { case DefDef(_, nme.main, Nil, List(_), _, _) => true case _ => false } /** For now we require there only be one top level object. */ var seenModule = false val newStmts = stmts collect { case t @ Import(_, _) => t case md @ ModuleDef(mods, name, template) if !seenModule && (template.body exists isMainMethod) => seenModule = true /** This slightly hacky situation arises because we have no way to communicate * back to the scriptrunner what the name of the program is. Even if we were * willing to take the sketchy route of settings.script.value = progName, that * does not work when using fsc. And to find out in advance would impose a * whole additional parse. So instead, if the actual object's name differs from * what the script is expecting, we transform it to match. */ md.derivedModuleDef(mods, mainModuleName.toTermName, template) case _ => /** If we see anything but the above, fail. */ return None } Some(makePackaging(0, emptyPkg, newStmts)) } if (mainModuleName == ScriptRunner.defaultScriptMain) searchForMain() foreach { return _ } /** Here we are building an AST representing the following source fiction, * where is from -Xscript (defaults to "Main") and are * the result of parsing the script file. * * object { * def main(argv: Array[String]): Unit = { * val args = argv * new AnyRef { * * } * } * } */ import definitions._ def emptyPkg = atPos(0, 0, 0) { Ident(nme.EMPTY_PACKAGE_NAME) } def emptyInit = DefDef( Modifiers(), nme.CONSTRUCTOR, Nil, List(Nil), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), Nil)), Literal(Constant(()))) ) // def main def mainParamType = AppliedTypeTree(Ident(tpnme.Array), List(Ident(tpnme.String))) def mainParameter = List(ValDef(Modifiers(Param), "argv", mainParamType, EmptyTree)) def mainSetArgv = List(ValDef(Modifiers(), "args", TypeTree(), Ident("argv"))) def mainNew = makeNew(Nil, emptyValDef, stmts, List(Nil), NoPosition, NoPosition) def mainDef = DefDef(Modifiers(), nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), Block(mainSetArgv, mainNew)) // object Main def moduleName = ScriptRunner scriptMain settings def moduleBody = Template(List(scalaScalaObjectConstr), emptyValDef, List(emptyInit, mainDef)) def moduleDef = ModuleDef(Modifiers(), moduleName, moduleBody) // package { ... } makePackaging(0, emptyPkg, List(moduleDef)) }*/ } }