diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2013-12-07 16:55:38 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2013-12-30 19:07:05 +0300 |
commit | 4d92aec651def608628a2275e1b6bf2d1fcbabe7 (patch) | |
tree | d1d51ad3d92343c4345b0b454835a4053234508d /src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala | |
parent | 6c7b003003e6cb6a1f0b00f79f784e6deea37a39 (diff) | |
download | scala-4d92aec651def608628a2275e1b6bf2d1fcbabe7.tar.gz scala-4d92aec651def608628a2275e1b6bf2d1fcbabe7.tar.bz2 scala-4d92aec651def608628a2275e1b6bf2d1fcbabe7.zip |
unprivates important helpers in Namers.scala
This is the first of two commits that enable hooks necessary to implement
macro annotations in an honest, hackless compiler plugin.
This particular commit turns certain helpers into public methods. Of course,
there is a probability that with the evolution of macro paradise, I will need
more helper methods, and those will have to be called via reflection, but
at least for now it's nice to have a reflection-less plugin :)
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala index 09a6a553ee..61becab483 100644 --- a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala +++ b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala @@ -229,6 +229,41 @@ trait AnalyzerPlugins { self: Analyzer => * $nonCumulativeReturnValueDoc. */ def pluginsMacroRuntime(expandee: Tree): Option[MacroRuntime] = None + + /** + * Creates a symbol for the given tree in lexical context encapsulated by the given namer. + * + * Default implementation provided in `namer.enterSym` handles MemberDef's and Imports, + * doing nothing for other trees (DocDef's are seen through and rewrapped). Typical implementation + * of `enterSym` for a particular tree flavor creates a corresponding symbol, assigns it to the tree, + * enters the symbol into scope and then might even perform some code generation. + * + * $nonCumulativeReturnValueDoc. + */ + def pluginsEnterSym(namer: Namer, tree: Tree): Boolean = false + + /** + * Makes sure that for the given class definition, there exists a companion object definition. + * + * Default implementation provided in `namer.ensureCompanionObject` looks up a companion symbol for the class definition + * and then checks whether the resulting symbol exists or not. If it exists, then nothing else is done. + * If not, a synthetic object definition is created using the provided factory, which is then entered into namer's scope. + * + * $nonCumulativeReturnValueDoc. + */ + def pluginsEnsureCompanionObject(namer: Namer, cdef: ClassDef, creator: ClassDef => Tree = companionModuleDef(_)): Option[Symbol] = None + + /** + * Prepares a list of statements for being typechecked by performing domain-specific type-agnostic code synthesis. + * + * Trees passed into this method are going to be named, but not typed. + * In particular, you can rely on the compiler having called `enterSym` on every stat prior to passing calling this method. + * + * Default implementation does nothing. Current approaches to code syntheses (generation of underlying fields + * for getters/setters, creation of companion objects for case classes, etc) are too disparate and ad-hoc + * to be treated uniformly, so I'm leaving this for future work. + */ + def pluginsEnterStats(typer: Typer, stats: List[Tree]): List[Tree] = stats } @@ -363,4 +398,35 @@ trait AnalyzerPlugins { self: Analyzer => def default = macroRuntime(expandee) def custom(plugin: MacroPlugin) = plugin.pluginsMacroRuntime(expandee) }) + + /** @see MacroPlugin.pluginsEnterSym */ + def pluginsEnterSym(namer: Namer, tree: Tree): Context = invoke(new NonCumulativeOp[Context] { + def position = tree.pos + def description = "enter a symbol for this tree" + def default = namer.enterSym(tree) + def custom(plugin: MacroPlugin) = { + val hasExistingSym = tree.symbol != NoSymbol + val result = plugin.pluginsEnterSym(namer, tree) + if (result && hasExistingSym) Some(namer.context) + else if (result && tree.isInstanceOf[Import]) Some(namer.context.make(tree)) + else if (result) Some(namer.context) + else None + } + }) + + /** @see MacroPlugin.pluginsEnsureCompanionObject */ + def pluginsEnsureCompanionObject(namer: Namer, cdef: ClassDef, creator: ClassDef => Tree = companionModuleDef(_)): Symbol = invoke(new NonCumulativeOp[Symbol] { + def position = cdef.pos + def description = "enter a companion symbol for this tree" + def default = namer.ensureCompanionObject(cdef, creator) + def custom(plugin: MacroPlugin) = plugin.pluginsEnsureCompanionObject(namer, cdef, creator) + }) + + /** @see MacroPlugin.pluginsEnterStats */ + def pluginsEnterStats(typer: Typer, stats: List[Tree]): List[Tree] = { + // performance opt + if (macroPlugins.isEmpty) stats + else macroPlugins.foldLeft(stats)((current, plugin) => + if (!plugin.isActive()) current else plugin.pluginsEnterStats(typer, stats)) + } } |