| @@ -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): | ||||