|
@@ -1168,18 +1168,19 @@ class GrammarBuilder: |
|
|
self.import_paths = import_paths or [] |
|
|
self.import_paths = import_paths or [] |
|
|
|
|
|
|
|
|
self._definitions = {} |
|
|
self._definitions = {} |
|
|
self._extend = {} |
|
|
|
|
|
self._override = {} |
|
|
|
|
|
self._ignore_names = [] |
|
|
self._ignore_names = [] |
|
|
self._import_set = {} |
|
|
|
|
|
|
|
|
|
|
|
def _is_term(self, name): |
|
|
def _is_term(self, name): |
|
|
return name.isupper() |
|
|
return name.isupper() |
|
|
|
|
|
|
|
|
def _grammer_error(self, msg, name): |
|
|
|
|
|
low_type = ("rule", "terminal")[self._is_term(name)] |
|
|
|
|
|
up_type = low_type.title() |
|
|
|
|
|
raise GrammarError(msg.format(name=name, type=low_type, Type=up_type)) |
|
|
|
|
|
|
|
|
def _grammar_error(self, msg, *names): |
|
|
|
|
|
args = {} |
|
|
|
|
|
for i, name in enumerate(names, start=1): |
|
|
|
|
|
postfix = '' if i == 1 else str(i) |
|
|
|
|
|
args['name'+ postfix] = name |
|
|
|
|
|
args['type' + postfix] = lowercase_type = ("rule", "terminal")[self._is_term(name)] |
|
|
|
|
|
args['Type' + postfix] = lowercase_type.title() |
|
|
|
|
|
raise GrammarError(msg.format(**args)) |
|
|
|
|
|
|
|
|
def _check_options(self, name, options): |
|
|
def _check_options(self, name, options): |
|
|
if self._is_term(name): |
|
|
if self._is_term(name): |
|
@@ -1197,27 +1198,26 @@ class GrammarBuilder: |
|
|
return options |
|
|
return options |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def define(self, name, exp, params=(), options=None, override=False): |
|
|
|
|
|
|
|
|
def _define(self, name, exp, params=(), options=None, override=False): |
|
|
if (name in self._definitions) ^ override: |
|
|
if (name in self._definitions) ^ override: |
|
|
if override: |
|
|
if override: |
|
|
self._grammer_error("Cannot override a nonexisting {type} {name}", name) |
|
|
|
|
|
|
|
|
self._grammar_error("Cannot override a nonexisting {type} {name}", name) |
|
|
else: |
|
|
else: |
|
|
self._grammer_error("{Type} '{name}' defined more than once", name) |
|
|
|
|
|
|
|
|
self._grammar_error("{Type} '{name}' defined more than once", name) |
|
|
if name.startswith('__'): |
|
|
if name.startswith('__'): |
|
|
self._grammer_error('Names starting with double-underscore are reserved (Error at {name})', name) |
|
|
|
|
|
|
|
|
self._grammar_error('Names starting with double-underscore are reserved (Error at {name})', name) |
|
|
self._definitions[name] = (params, exp, self._check_options(name, options)) |
|
|
self._definitions[name] = (params, exp, self._check_options(name, options)) |
|
|
|
|
|
|
|
|
def extend(self, name, exp, params=(), options=None): |
|
|
|
|
|
|
|
|
def _extend(self, name, exp, params=(), options=None): |
|
|
if name not in self._definitions: |
|
|
if name not in self._definitions: |
|
|
self._grammer_error("Can't extend {type} {name} as it wasn't defined before", name) |
|
|
|
|
|
|
|
|
self._grammar_error("Can't extend {type} {name} as it wasn't defined before", name) |
|
|
if tuple(params) != tuple(self._definitions[name][0]): |
|
|
if tuple(params) != tuple(self._definitions[name][0]): |
|
|
print(params, self._definitions[name][0]) |
|
|
|
|
|
self._grammer_error("Cannot extend {type} with different parameters: {name}", name) |
|
|
|
|
|
|
|
|
self._grammar_error("Cannot extend {type} with different parameters: {name}", name) |
|
|
# TODO: think about what to do with 'options' |
|
|
# TODO: think about what to do with 'options' |
|
|
old_expansions = self._definitions[name][1] |
|
|
old_expansions = self._definitions[name][1] |
|
|
extend_expansions(old_expansions, exp) |
|
|
extend_expansions(old_expansions, exp) |
|
|
|
|
|
|
|
|
def ignore(self, exp_or_name): |
|
|
|
|
|
|
|
|
def _ignore(self, exp_or_name): |
|
|
if isinstance(exp_or_name, str): |
|
|
if isinstance(exp_or_name, str): |
|
|
self._ignore_names.append(exp_or_name) |
|
|
self._ignore_names.append(exp_or_name) |
|
|
else: |
|
|
else: |
|
@@ -1237,10 +1237,9 @@ class GrammarBuilder: |
|
|
self._ignore_names.append(name) |
|
|
self._ignore_names.append(name) |
|
|
self._definitions[name] = ((), t, 1) |
|
|
self._definitions[name] = ((), t, 1) |
|
|
|
|
|
|
|
|
def declare(self, *names): |
|
|
|
|
|
|
|
|
def _declare(self, *names): |
|
|
for name in names: |
|
|
for name in names: |
|
|
self.define(name, None) |
|
|
|
|
|
# TODO: options/priority gets filled by this. We have to make sure that this doesn't break anything |
|
|
|
|
|
|
|
|
self._define(name, None) |
|
|
|
|
|
|
|
|
def _mangle_exp(self, exp, mangle): |
|
|
def _mangle_exp(self, exp, mangle): |
|
|
if mangle is None: |
|
|
if mangle is None: |
|
@@ -1309,7 +1308,7 @@ class GrammarBuilder: |
|
|
actions = [] # Some statements need to be delayed (override and extend) till after imports are handled |
|
|
actions = [] # Some statements need to be delayed (override and extend) till after imports are handled |
|
|
for stmt in tree.children: |
|
|
for stmt in tree.children: |
|
|
if stmt.data in ('term', 'rule'): |
|
|
if stmt.data in ('term', 'rule'): |
|
|
self.define(*self._unpack_definition(stmt, mangle)) |
|
|
|
|
|
|
|
|
self._define(*self._unpack_definition(stmt, mangle)) |
|
|
continue |
|
|
continue |
|
|
assert stmt.data == 'statement', stmt.data |
|
|
assert stmt.data == 'statement', stmt.data |
|
|
stmt ,= stmt.children |
|
|
stmt ,= stmt.children |
|
@@ -1324,18 +1323,18 @@ class GrammarBuilder: |
|
|
elif stmt.data == 'ignore': |
|
|
elif stmt.data == 'ignore': |
|
|
# if mangle is not None, we shouldn't apply ignore, since we aren't in a toplevel grammar |
|
|
# if mangle is not None, we shouldn't apply ignore, since we aren't in a toplevel grammar |
|
|
if mangle is None: |
|
|
if mangle is None: |
|
|
self.ignore(*stmt.children) |
|
|
|
|
|
|
|
|
self._ignore(*stmt.children) |
|
|
elif stmt.data == 'declare': |
|
|
elif stmt.data == 'declare': |
|
|
if mangle is None: |
|
|
if mangle is None: |
|
|
self.declare(*(t.value for t in stmt.children)) |
|
|
|
|
|
|
|
|
self._declare(*(t.value for t in stmt.children)) |
|
|
else: |
|
|
else: |
|
|
self.declare(*(mangle(t.value) for t in stmt.children)) |
|
|
|
|
|
|
|
|
self._declare(*(mangle(t.value) for t in stmt.children)) |
|
|
elif stmt.data == 'override': |
|
|
elif stmt.data == 'override': |
|
|
r ,= stmt.children |
|
|
r ,= stmt.children |
|
|
actions.append((self.define, self._unpack_definition(r, mangle)+ (True,))) |
|
|
|
|
|
|
|
|
actions.append((self._define, self._unpack_definition(r, mangle) + (True,))) |
|
|
elif stmt.data == 'extend': |
|
|
elif stmt.data == 'extend': |
|
|
r ,= stmt.children |
|
|
r ,= stmt.children |
|
|
actions.append((self.extend, self._unpack_definition(r, mangle))) |
|
|
|
|
|
|
|
|
actions.append((self._extend, self._unpack_definition(r, mangle))) |
|
|
else: |
|
|
else: |
|
|
assert False, stmt |
|
|
assert False, stmt |
|
|
|
|
|
|
|
@@ -1387,10 +1386,31 @@ class GrammarBuilder: |
|
|
for name, (params, exp, options) in self._definitions.items(): |
|
|
for name, (params, exp, options) in self._definitions.items(): |
|
|
if self._is_term(name): |
|
|
if self._is_term(name): |
|
|
assert isinstance(options, int) |
|
|
assert isinstance(options, int) |
|
|
if exp is not None: |
|
|
|
|
|
for sym in _find_used_symbols(exp): |
|
|
|
|
|
if sym not in self._definitions and sym not in params: |
|
|
|
|
|
self._grammer_error("{Type} '{name}' used but not defined (in rule %s)" % name, sym.value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i, p in enumerate(params): |
|
|
|
|
|
if p in self._definitions: |
|
|
|
|
|
raise GrammarError("Template Parameter conflicts with rule %s (in template %s)" % (p, name)) |
|
|
|
|
|
if p in params[:i]: |
|
|
|
|
|
raise GrammarError("Duplicate Template Parameter %s (in template %s)" % (p, name)) |
|
|
|
|
|
|
|
|
|
|
|
if exp is None: # Remaining checks don't work for abstract rules/terminals |
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
for temp in exp.find_data('template_usage'): |
|
|
|
|
|
sym = temp.children[0] |
|
|
|
|
|
args = temp.children[1:] |
|
|
|
|
|
if sym not in params: |
|
|
|
|
|
if sym not in self._definitions: |
|
|
|
|
|
self._grammar_error("Template '%s' used but not defined (in {type} {name})" % sym, name) |
|
|
|
|
|
if len(args) != len(self._definitions[sym][0]): |
|
|
|
|
|
expected, actual = len(self._definitions[sym][0]), len(args) |
|
|
|
|
|
self._grammar_error("Wrong number of template arguments used for {name} " |
|
|
|
|
|
"(expected %s, got %s) (in {type2} {name2})" % (expected, actual), sym, name) |
|
|
|
|
|
|
|
|
|
|
|
for sym in _find_used_symbols(exp): |
|
|
|
|
|
if sym not in self._definitions and sym not in params: |
|
|
|
|
|
self._grammar_error("{Type} '{name}' used but not defined (in {type2} {name2})", sym, name) |
|
|
|
|
|
|
|
|
if not set(self._definitions).issuperset(self._ignore_names): |
|
|
if not set(self._definitions).issuperset(self._ignore_names): |
|
|
raise GrammarError("Terminals %s were marked to ignore but were not defined!" % (set(self._ignore_names) - set(self._definitions))) |
|
|
raise GrammarError("Terminals %s were marked to ignore but were not defined!" % (set(self._ignore_names) - set(self._definitions))) |
|
|
|
|
|
|
|
@@ -1400,6 +1420,7 @@ class GrammarBuilder: |
|
|
term_defs = [] |
|
|
term_defs = [] |
|
|
for name, (params, exp, options) in self._definitions.items(): |
|
|
for name, (params, exp, options) in self._definitions.items(): |
|
|
if self._is_term(name): |
|
|
if self._is_term(name): |
|
|
|
|
|
assert len(params) == 0 |
|
|
term_defs.append((name, (exp, options))) |
|
|
term_defs.append((name, (exp, options))) |
|
|
else: |
|
|
else: |
|
|
rule_defs.append((name, params, exp, options)) |
|
|
rule_defs.append((name, params, exp, options)) |
|
|