| @@ -57,6 +57,7 @@ class LarkOptions(object): | |||||
| self.profile = o.pop('profile', False) | self.profile = o.pop('profile', False) | ||||
| self.ambiguity = o.pop('ambiguity', 'auto') | self.ambiguity = o.pop('ambiguity', 'auto') | ||||
| self.propagate_positions = o.pop('propagate_positions', False) | self.propagate_positions = o.pop('propagate_positions', False) | ||||
| self.earley__predict_all = o.pop('earley__predict_all', False) | |||||
| assert self.parser in ('earley', 'lalr', None) | assert self.parser in ('earley', 'lalr', None) | ||||
| @@ -126,6 +126,7 @@ class XEarley: | |||||
| parser_conf.callback, | parser_conf.callback, | ||||
| resolve_ambiguity=get_ambiguity_resolver(options), | resolve_ambiguity=get_ambiguity_resolver(options), | ||||
| ignore=ignore, | ignore=ignore, | ||||
| predict_all=options.earley__predict_all | |||||
| ) | ) | ||||
| def _prepare_expansion(self, expansion): | def _prepare_expansion(self, expansion): | ||||
| @@ -90,7 +90,7 @@ class NewsList(list): | |||||
| class Column: | class Column: | ||||
| "An entry in the table, aka Earley Chart. Contains lists of items." | "An entry in the table, aka Earley Chart. Contains lists of items." | ||||
| def __init__(self, i, FIRST): | |||||
| def __init__(self, i, FIRST, predict_all=False): | |||||
| self.i = i | self.i = i | ||||
| self.to_reduce = NewsList() | self.to_reduce = NewsList() | ||||
| self.to_predict = NewsList() | self.to_predict = NewsList() | ||||
| @@ -100,6 +100,7 @@ class Column: | |||||
| self.predicted = set() | self.predicted = set() | ||||
| self.completed = {} | self.completed = {} | ||||
| self.predict_all = predict_all | |||||
| def add(self, items): | def add(self, items): | ||||
| """Sort items into scan/predict/reduce newslists | """Sort items into scan/predict/reduce newslists | ||||
| @@ -108,9 +109,9 @@ class Column: | |||||
| """ | """ | ||||
| for item in items: | for item in items: | ||||
| item_key = item, item.tree # Elsewhere, tree is not part of the comparison | |||||
| if item.is_complete: | if item.is_complete: | ||||
| # XXX Potential bug: What happens if there's ambiguity in an empty rule? | # XXX Potential bug: What happens if there's ambiguity in an empty rule? | ||||
| item_key = item, item.tree # Elsewhere, tree is not part of the comparison | |||||
| if item.rule.expansion and item_key in self.completed: | if item.rule.expansion and item_key in self.completed: | ||||
| old_tree = self.completed[item_key].tree | old_tree = self.completed[item_key].tree | ||||
| if old_tree == item.tree: | if old_tree == item.tree: | ||||
| @@ -137,9 +138,10 @@ class Column: | |||||
| if isinstance(item.expect, Terminal): | if isinstance(item.expect, Terminal): | ||||
| self.to_scan.append(item) | self.to_scan.append(item) | ||||
| else: | else: | ||||
| if item in self.predicted: | |||||
| k = item_key if self.predict_all else item | |||||
| if k in self.predicted: | |||||
| continue | continue | ||||
| self.predicted.add(item) | |||||
| self.predicted.add(k) | |||||
| self.to_predict.append(item) | self.to_predict.append(item) | ||||
| self.item_count += 1 # Only count if actually added | self.item_count += 1 # Only count if actually added | ||||
| @@ -28,11 +28,12 @@ from .grammar_analysis import GrammarAnalyzer | |||||
| from .earley import ApplyCallbacks, Item, Column | from .earley import ApplyCallbacks, Item, Column | ||||
| class Parser: | class Parser: | ||||
| def __init__(self, rules, start_symbol, callback, resolve_ambiguity=None, ignore=()): | |||||
| def __init__(self, rules, start_symbol, callback, resolve_ambiguity=None, ignore=(), predict_all=False): | |||||
| self.analysis = GrammarAnalyzer(rules, start_symbol) | self.analysis = GrammarAnalyzer(rules, start_symbol) | ||||
| self.start_symbol = start_symbol | self.start_symbol = start_symbol | ||||
| self.resolve_ambiguity = resolve_ambiguity | self.resolve_ambiguity = resolve_ambiguity | ||||
| self.ignore = list(ignore) | self.ignore = list(ignore) | ||||
| self.predict_all = predict_all | |||||
| self.postprocess = {} | self.postprocess = {} | ||||
| @@ -107,9 +108,10 @@ class Parser: | |||||
| for j in range(1, len(s)): | for j in range(1, len(s)): | ||||
| m = item.expect.match(s[:-j]) | m = item.expect.match(s[:-j]) | ||||
| if m: | if m: | ||||
| delayed_matches[m.end()].append(item.advance(m.group(0))) | |||||
| t = Token(item.expect.name, m.group(0), i, text_line, text_column) | |||||
| delayed_matches[i+m.end()].append(item.advance(t)) | |||||
| next_set = Column(i+1, self.FIRST) | |||||
| next_set = Column(i+1, self.FIRST, predict_all=self.predict_all) | |||||
| next_set.add(delayed_matches[i+1]) | next_set.add(delayed_matches[i+1]) | ||||
| del delayed_matches[i+1] # No longer needed, so unburden memory | del delayed_matches[i+1] # No longer needed, so unburden memory | ||||
| @@ -119,7 +121,7 @@ class Parser: | |||||
| return next_set | return next_set | ||||
| # Main loop starts | # Main loop starts | ||||
| column0 = Column(0, self.FIRST) | |||||
| column0 = Column(0, self.FIRST, predict_all=self.predict_all) | |||||
| column0.add(predict(start_symbol, column0)) | column0.add(predict(start_symbol, column0)) | ||||
| column = column0 | column = column0 | ||||