Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically checking whether a string is a reserved word in Scala

Is there a simple way to implement the following function?

i.e. to decide whether the given piece of text needs to be quoted with backticks or not when generating code.

def isReservedWord(text: String): Boolean

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

Of course, I could just maintain a list of keywords based on the Scala Syntax Summary at the end of the language spec, and check against that, but is there a better way?

like image 622
Chris B Avatar asked Feb 26 '14 09:02

Chris B


2 Answers

The compiler maintains a list of keywords which can easily be accessed:

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

scala> val compiler = new Global(new Settings)
compiler: scala.tools.nsc.Global = scala.tools.nsc.Global@29935953

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)

Luckily, Scala already provides the reflection API, which is nothing else than the compiler that is accessed by a public API. You can access the symbol table, which contains all the definitions, when you cast the public type to the internal one:

scala> val st = scala.reflect.runtime.universe.asInstanceOf[scala.reflect.internal.SymbolTable]
st: scala.reflect.internal.SymbolTable = scala.reflect.runtime.JavaUniverse@472250c4

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, <%)

Inside of the REPL you can also use the :power mode to get access to the compiler directly:

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)
like image 56
kiritsuku Avatar answered Oct 25 '22 03:10

kiritsuku


Grepping the compiler source, I found the following:

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

That is package-private for html, so you might have to write a wrapper. Probably it's easier to just copy that array to your own source.

There is more stuff in internal API, e.g. scala.reflect.internal.StdNames. And scala.reflect.internal.Printers has a method quotedName, but you need the whole cake to access these. Maybe you can get any of these through the official reflection API?

like image 38
0__ Avatar answered Oct 25 '22 04:10

0__