2014-02-26 16 views
10

Gibt es eine einfache Möglichkeit, die folgende Funktion zu implementieren?Programmatisch prüfen, ob ein String ein reserviertes Wort in Scala ist

, d. H. Um zu entscheiden, ob das gegebene Stück Text beim Erzeugen von Code mit Backticks quotiert werden soll oder nicht.

def isReservedWord(text: String): Boolean 

isReservedWord("type") // true 
isReservedWord("foo") // false 

Natürlich könnte ich halten nur eine Liste von Schlüsselwörtern auf der Scala Syntax Zusammenfassung am Ende der Sprache spec basiert, und prüfen Sie dagegen, aber gibt es einen besseren Weg?

Antwort

10

Der Compiler führt eine Liste von Schlüsselwörtern, die leicht zugegriffen werden kann:

scala> import scala.tools.nsc._ 
import scala.tools.nsc._ 

scala> val compiler = new Global(new Settings) 
compiler: scala.tools.nsc.Global = [email protected] 

scala> compiler.nme.keywords 
res0: Set[compiler.TermName] = Set(abstract, >:, true, val, do, throw, <-, package, _, macro, @, object, false, this, if, then, var, trait, ., catch, with, def, else, class, type, #, lazy, null, =, <:, override, protected, =>, private, sealed, finally, new, implicit, extends, final, for, return, case, import, forSome, :, super, while, yield, try, match, <%) 

scala> compiler.javanme.keywords 
res1: Set[compiler.TermName] = Set(abstract, strictfp, short, int, do, goto, interface, throw, float, package, implements, enum, this, long, if, switch, native, throws, boolean, catch, else, const, class, assert, public, void, instanceof, protected, static, default, private, finally, synchronized, new, char, extends, final, volatile, for, return, continue, case, import, double, super, byte, while, break, try, transient) 

Zum Glück Scala bietet bereits die Reflection-API, die nichts anderes ist als der Compiler ist, die durch eine öffentliche API zugegriffen wird. Sie können die Symboltabelle zugreifen, die alle Definitionen enthält, wenn Sie den öffentlichen Typ an das interne Stimmen:

scala> val st = scala.reflect.runtime.universe.asInstanceOf[scala.reflect.internal.SymbolTable] 
st: scala.reflect.internal.SymbolTable = [email protected] 

scala> st.nme.keywords 
res10: Set[st.TermName] = Set(abstract, >:, true, val, do, throw, <-, package, _, macro, @, object, false, this, if, then, var, trait, ., catch, with, def, else, class, type, #, lazy, null, =, <:, override, protected, =>, private, sealed, finally, new, implicit, extends, final, for, return, case, import, forSome, :, super, while, yield, try, match, <%) 

Innerhalb des REPL Sie auch die :power Modus verwenden können direkt Zugriff auf den Compiler zu erhalten:

scala> :power 
** Power User mode enabled - BEEP WHIR GYVE ** 
** :phase has been set to 'typer'.   ** 
** scala.tools.nsc._ has been imported  ** 
** global._, definitions._ also imported ** 
** Try :help, :vals, power.<tab>   ** 

scala> nme.keywords 
res3: Set[$r.intp.global.TermName] = Set(abstract, >:, true, val, do, throw, <-, package, _, macro, @, object, false, this, if, then, var, trait, ., catch, with, def, else, class, type, #, lazy, null, =, <:, override, protected, =>, private, sealed, finally, new, implicit, extends, final, for, return, case, import, forSome, :, super, while, yield, try, match, <%) 

scala> javanme.keywords 
res4: Set[$r.intp.global.TermName] = Set(abstract, strictfp, short, int, do, goto, interface, throw, float, package, implements, enum, this, long, if, switch, native, throws, boolean, catch, else, const, class, assert, public, void, instanceof, protected, static, default, private, finally, synchronized, new, char, extends, final, volatile, for, return, continue, case, import, double, super, byte, while, break, try, transient) 
+0

Danke! Das ist perfekt. –

1

den Compiler Quelle greppen, fand ich folgendes:

scala.tools.nsc.doc.html.SyntaxHigh.reserved 

Das für html Paket-privat ist, so dass Sie einen Wrapper schreiben könnte müssen. Wahrscheinlich ist es einfacher, das Array einfach in Ihre eigene Quelle zu kopieren.

Es gibt mehr Zeug in der internen API, z.B. scala.reflect.internal.StdNames. Und scala.reflect.internal.Printers hat eine Methode quotedName, aber Sie brauchen den ganzen Kuchen, um auf diese zuzugreifen. Vielleicht können Sie diese über die offizielle Reflektions-API erhalten?