@@ -53,7 +53,10 @@ class CalculateTree(Transformer): | |||||
return value | return value | ||||
def var(self, name): | def var(self, name): | ||||
return self.vars[name] | |||||
try: | |||||
return self.vars[name] | |||||
except KeyError: | |||||
raise Exception("Variable not found: %s" % name) | |||||
calc_parser = Lark(calc_grammar, parser='lalr', transformer=CalculateTree()) | calc_parser = Lark(calc_grammar, parser='lalr', transformer=CalculateTree()) | ||||
@@ -4,6 +4,7 @@ from copy import deepcopy | |||||
from .lalr_analysis import Shift, Reduce | from .lalr_analysis import Shift, Reduce | ||||
from .. import Token | from .. import Token | ||||
from ..exceptions import ParseError | |||||
class ParserPuppet(object): | class ParserPuppet(object): | ||||
@@ -32,7 +33,8 @@ class ParserPuppet(object): | |||||
state = state_stack[-1] | state = state_stack[-1] | ||||
action, arg = self.parser.parse_table.states[state][token.type] | action, arg = self.parser.parse_table.states[state][token.type] | ||||
assert arg != end_state | |||||
if arg == end_state: | |||||
raise ParseError(arg) | |||||
while action is Reduce: | while action is Reduce: | ||||
rule = arg | rule = arg | ||||
@@ -56,7 +58,10 @@ class ParserPuppet(object): | |||||
return self.result | return self.result | ||||
state = state_stack[-1] | state = state_stack[-1] | ||||
action, arg = self.parser.parse_table.states[state][token.type] | |||||
try: | |||||
action, arg = self.parser.parse_table.states[state][token.type] | |||||
except KeyError as e: | |||||
raise ParseError(e) | |||||
assert arg != end_state | assert arg != end_state | ||||
assert action is Shift | assert action is Shift | ||||
@@ -111,13 +116,14 @@ class ParserPuppet(object): | |||||
def accepts(self): | def accepts(self): | ||||
accepts = set() | accepts = set() | ||||
for t in self.choices(): | for t in self.choices(): | ||||
new_puppet = self.copy() | |||||
try: | |||||
new_puppet.feed_token(Token(t, '')) | |||||
except KeyError: | |||||
pass | |||||
else: | |||||
accepts.add(t) | |||||
if t.isupper(): # is terminal? | |||||
new_puppet = self.copy() | |||||
try: | |||||
new_puppet.feed_token(Token(t, '')) | |||||
except ParseError: | |||||
pass | |||||
else: | |||||
accepts.add(t) | |||||
return accepts | return accepts | ||||
def resume_parse(self): | def resume_parse(self): | ||||
@@ -39,6 +39,14 @@ def _deserialize(data, namespace, memo): | |||||
class Serialize(object): | class Serialize(object): | ||||
"""Safe-ish serialization interface that doesn't rely on Pickle | |||||
Attributes: | |||||
__serialize_fields__ (List[str]): Fields (aka attributes) to serialize. | |||||
__serialize_namespace__ (list): List of classes that deserialization is allowed to instanciate. | |||||
Should include all field types that aren't builtin types. | |||||
""" | |||||
def memo_serialize(self, types_to_memoize): | def memo_serialize(self, types_to_memoize): | ||||
memo = SerializeMemoizer(types_to_memoize) | memo = SerializeMemoizer(types_to_memoize) | ||||
return self.serialize(memo), memo.serialize() | return self.serialize(memo), memo.serialize() | ||||
@@ -78,6 +86,8 @@ class Serialize(object): | |||||
class SerializeMemoizer(Serialize): | class SerializeMemoizer(Serialize): | ||||
"A version of serialize that memoizes objects to reduce space" | |||||
__serialize_fields__ = 'memoized', | __serialize_fields__ = 'memoized', | ||||
def __init__(self, types_to_memoize): | def __init__(self, types_to_memoize): | ||||