@@ -15,7 +15,6 @@ class Rule(object): | |||||
expansion : a list of symbols | expansion : a list of symbols | ||||
""" | """ | ||||
def __init__(self, origin, expansion, alias=None): | def __init__(self, origin, expansion, alias=None): | ||||
assert expansion, "No support for empty rules" | |||||
self.origin = origin | self.origin = origin | ||||
self.expansion = expansion | self.expansion = expansion | ||||
self.alias = alias | self.alias = alias | ||||
@@ -91,9 +90,10 @@ class GrammarAnalyzer(object): | |||||
init_ptr = RulePtr(r, 0) | init_ptr = RulePtr(r, 0) | ||||
init_ptrs.add(init_ptr) | init_ptrs.add(init_ptr) | ||||
new_r = init_ptr.next | |||||
if not is_terminal(new_r): | |||||
yield new_r | |||||
if r.expansion: # if not empty rule | |||||
new_r = init_ptr.next | |||||
if not is_terminal(new_r): | |||||
yield new_r | |||||
_ = list(bfs([rule], _expand_rule)) | _ = list(bfs([rule], _expand_rule)) | ||||
@@ -32,7 +32,6 @@ class LarkOptions(object): | |||||
self.debug = bool(o.pop('debug', False)) | self.debug = bool(o.pop('debug', False)) | ||||
self.only_lex = bool(o.pop('only_lex', False)) | self.only_lex = bool(o.pop('only_lex', False)) | ||||
self.keep_all_tokens = bool(o.pop('keep_all_tokens', False)) | self.keep_all_tokens = bool(o.pop('keep_all_tokens', False)) | ||||
self.keep_empty_trees = bool(o.pop('keep_empty_trees', True)) | |||||
self.tree_class = o.pop('tree_class', Tree) | self.tree_class = o.pop('tree_class', Tree) | ||||
self.cache_grammar = o.pop('cache_grammar', False) | self.cache_grammar = o.pop('cache_grammar', False) | ||||
self.ignore_postproc = bool(o.pop('ignore_postproc', False)) | self.ignore_postproc = bool(o.pop('ignore_postproc', False)) | ||||
@@ -42,6 +41,8 @@ class LarkOptions(object): | |||||
assert self.parser in ENGINE_DICT | assert self.parser in ENGINE_DICT | ||||
if self.parser == 'earley' and self.transformer: | if self.parser == 'earley' and self.transformer: | ||||
raise ValueError('Cannot specify an auto-transformer when using the Earley algorithm. Please use your transformer on the resulting parse tree, or use a different algorithm (i.e. lalr)') | raise ValueError('Cannot specify an auto-transformer when using the Earley algorithm. Please use your transformer on the resulting parse tree, or use a different algorithm (i.e. lalr)') | ||||
if self.keep_all_tokens: | |||||
raise NotImplementedError("Not implemented yet!") | |||||
if o: | if o: | ||||
raise ValueError("Unknown options: %s" % o.keys()) | raise ValueError("Unknown options: %s" % o.keys()) | ||||
@@ -74,7 +74,7 @@ RULES = [ | |||||
('expansion', ['_expansion']), | ('expansion', ['_expansion']), | ||||
('expansion', ['_expansion', 'TO', 'RULE']), | ('expansion', ['_expansion', 'TO', 'RULE']), | ||||
('_expansion', ['expr']), | |||||
('_expansion', []), | |||||
('_expansion', ['_expansion', 'expr']), | ('_expansion', ['_expansion', 'expr']), | ||||
('expr', ['atom']), | ('expr', ['atom']), | ||||
@@ -149,6 +149,12 @@ class SaveDefinitions(object): | |||||
def tokenvalue(self, tokenvalue): | def tokenvalue(self, tokenvalue): | ||||
value = tokenvalue.value[1:-1] | value = tokenvalue.value[1:-1] | ||||
import codecs | |||||
decoder = codecs.getdecoder('unicode_escape') | |||||
if '\u' in value: | |||||
# XXX for now, you can't mix unicode escaping and unicode characters at the same token | |||||
value = decoder(value)[0] | |||||
if tokenvalue.type == 'STRING': | if tokenvalue.type == 'STRING': | ||||
value = re.escape(value) | value = re.escape(value) | ||||
return tokenvalue, value | return tokenvalue, value | ||||
@@ -26,8 +26,11 @@ class Parser(object): | |||||
raise ParseError("Unexpected input %r.\nExpected: %s\nContext: %s" % (key, expected, context)) | raise ParseError("Unexpected input %r.\nExpected: %s\nContext: %s" % (key, expected, context)) | ||||
def reduce(rule): | def reduce(rule): | ||||
s = stack[-len(rule.expansion):] | |||||
del stack[-len(rule.expansion):] | |||||
if rule.expansion: | |||||
s = stack[-len(rule.expansion):] | |||||
del stack[-len(rule.expansion):] | |||||
else: | |||||
s = [] | |||||
res = self.callbacks[rule]([x[0] for x in s]) | res = self.callbacks[rule]([x[0] for x in s]) | ||||
@@ -1,3 +1,4 @@ | |||||
from copy import deepcopy | |||||
from utils import inline_args | from utils import inline_args | ||||
class Tree(object): | class Tree(object): | ||||
@@ -29,6 +30,8 @@ class Tree(object): | |||||
kid = self.children[i] | kid = self.children[i] | ||||
self.children[i:i+1] = kid.children | self.children[i:i+1] = kid.children | ||||
def __eq__(self, other): | |||||
return self.data == other.data and self.children == other.children | |||||
# def find_path(self, pred): | # def find_path(self, pred): | ||||
# if pred(self): | # if pred(self): | ||||
@@ -49,8 +52,12 @@ class Tree(object): | |||||
# x = self.follow_path(path[:-1]) | # x = self.follow_path(path[:-1]) | ||||
# x.children[path[-1]] = value | # x.children[path[-1]] = value | ||||
def clone(self): | |||||
return Tree(self.data, [c.clone() if isinstance(c, Tree) else c for c in self.children]) | |||||
# def clone(self): | |||||
# return Tree(self.data, [c.clone() if isinstance(c, Tree) else c for c in self.children]) | |||||
def __deepcopy__(self, memo): | |||||
return type(self)(self.data, deepcopy(self.children, memo)) | |||||
class Transformer(object): | class Transformer(object): | ||||