use "collections"
use ast = "../ast"
use ".."
class KeywordBuilder
let _kwd_strings: Array[String] val
let _context: Context
let _trivia: TriviaBuilder
let _keywords: Map[String, NamedRule]
let kwd: NamedRule = NamedRule("a keyword" where memoize' = true)
let not_kwd: NamedRule = NamedRule("something other than a keyword")
let cap: NamedRule = NamedRule("a reference capability")
let gencap: NamedRule = NamedRule("a generic capability")
new create(context: Context, trivia: TriviaBuilder) =>
_context = context
_trivia = trivia
_kwd_strings = [
ast.Keywords.kwd_actor()
ast.Keywords.kwd_addressof()
ast.Keywords.kwd_and()
ast.Keywords.kwd_as()
ast.Keywords.kwd_be()
ast.Keywords.kwd_box()
ast.Keywords.kwd_break()
ast.Keywords.kwd_class()
ast.Keywords.kwd_compile_error()
ast.Keywords.kwd_compile_intrinsic()
ast.Keywords.kwd_consume()
ast.Keywords.kwd_continue()
ast.Keywords.kwd_digestof()
ast.Keywords.kwd_do()
ast.Keywords.kwd_elseif()
ast.Keywords.kwd_else()
ast.Keywords.kwd_embed()
ast.Keywords.kwd_end()
ast.Keywords.kwd_error()
ast.Keywords.kwd_false()
ast.Keywords.kwd_for()
ast.Keywords.kwd_fun()
ast.Keywords.kwd_hash_alias()
ast.Keywords.kwd_hash_any()
ast.Keywords.kwd_hash_read()
ast.Keywords.kwd_hash_send()
ast.Keywords.kwd_hash_share()
ast.Keywords.kwd_iftype()
ast.Keywords.kwd_ifdef()
ast.Keywords.kwd_if()
ast.Keywords.kwd_interface()
ast.Keywords.kwd_in()
ast.Keywords.kwd_iso()
ast.Keywords.kwd_is()
ast.Keywords.kwd_let()
ast.Keywords.kwd_loc()
ast.Keywords.kwd_match()
ast.Keywords.kwd_new()
ast.Keywords.kwd_not()
ast.Keywords.kwd_object()
ast.Keywords.kwd_or()
ast.Keywords.kwd_primitive()
ast.Keywords.kwd_ref()
ast.Keywords.kwd_recover()
ast.Keywords.kwd_repeat()
ast.Keywords.kwd_return()
ast.Keywords.kwd_struct()
ast.Keywords.kwd_tag()
ast.Keywords.kwd_then()
ast.Keywords.kwd_this()
ast.Keywords.kwd_trait()
ast.Keywords.kwd_trn()
ast.Keywords.kwd_true()
ast.Keywords.kwd_try()
ast.Keywords.kwd_type()
ast.Keywords.kwd_until()
ast.Keywords.kwd_use()
ast.Keywords.kwd_val()
ast.Keywords.kwd_var()
ast.Keywords.kwd_where()
ast.Keywords.kwd_while()
ast.Keywords.kwd_with()
ast.Keywords.kwd_xor()
]
let t = _trivia.trivia
_keywords = Map[String, NamedRule]
for str in _kwd_strings.values() do
_add_rule("Keyword_" + str, str, t, _keywords)
end
_build_kwd()
_build_not_kwd()
_build_cap()
_build_gencap()
fun tag _add_rule(
name: String,
str: String,
t: NamedRule,
m: Map[String, NamedRule])
=>
let rule =
NamedRule(name,
_Build.with_post[ast.Trivia](
Conj(
[ Literal(str)
Neg(Single(_Letters.with_underscore())) ]),
t,
{(d, r, c, b, p) =>
let src_info = _Build.info(d, r)
ast.NodeWith[ast.Keyword](
src_info, _Build.span_and_post(src_info, c, p), ast.Keyword(str)
where post_trivia' = p)
}))
m.insert(str, rule)
fun apply(str: String): this->NamedRule =>
try
_keywords(str)?
else
recover
let msg =
recover val
"INVALID KEYWORD '" + StringUtil.escape(str) +
"'; add it to the list in KeywordBuilder if necessary"
end
NamedRule(msg, Error(msg))
end
end
fun ref _build_kwd() =>
let literals = Array[RuleNode](_kwd_strings.size())
for str in _kwd_strings.values() do
literals.push(Literal(str))
end
kwd.set_body(
_Build.with_post[ast.Trivia](
Conj([ Disj(literals); Neg(Single(_Id.chars())) ]),
_trivia.trivia,
{(d, r, c, b, p) =>
let src_info = _Build.info(d, r)
let next =
try
p(0)?.src_info().start
else
src_info.next
end
let str =
match (src_info.start, next)
| (let s': Loc, let n': Loc) =>
recover val String .> concat(s'.values(n')) end
else
""
end
ast.NodeWith[ast.Keyword](
src_info, _Build.span_and_post(src_info, c, p), ast.Keyword(str)
where post_trivia' = p)
}))
fun ref _build_not_kwd() =>
not_kwd.set_body(Neg(kwd))
fun ref _build_cap() =>
let kwd_iso = this(ast.Keywords.kwd_iso())
let kwd_trn = this(ast.Keywords.kwd_trn())
let kwd_ref = this(ast.Keywords.kwd_ref())
let kwd_val = this(ast.Keywords.kwd_val())
let kwd_box = this(ast.Keywords.kwd_box())
let kwd_tag = this(ast.Keywords.kwd_tag())
cap.set_body(
Disj([
kwd_iso
kwd_trn
kwd_ref
kwd_val
kwd_box
kwd_tag
]))
fun ref _build_gencap() =>
let kwd_read = this(ast.Keywords.kwd_hash_read())
let kwd_send = this(ast.Keywords.kwd_hash_send())
let kwd_share = this(ast.Keywords.kwd_hash_share())
let kwd_alias = this(ast.Keywords.kwd_hash_alias())
let kwd_any = this(ast.Keywords.kwd_hash_any())
gencap.set_body(
Disj(
[ kwd_read
kwd_send
kwd_share
kwd_alias
kwd_any
]))