diff options
author | Ian Johnson <ian.johnson@appliedlanguage.com> | 2013-10-21 18:44:08 +0400 |
---|---|---|
committer | Ian Johnson <ian.johnson@appliedlanguage.com> | 2013-10-21 18:44:08 +0400 |
commit | b43d1c1ff5f0ad64552339feaee0d176156e0ed4 (patch) | |
tree | 4db70e3763529d9629a0f98d762921493e85a492 | |
parent | 6451c37835ef255ec01cbe182094a11db889d6e0 (diff) |
Resolution of do-notation.
-rw-r--r-- | src/pclc/parser/command.py | 39 | ||||
-rw-r--r-- | src/pclc/visitors/first_pass_resolver_visitor.py | 16 | ||||
-rw-r--r-- | src/pclc/visitors/second_pass_resolver_visitor.py | 8 | ||||
-rw-r--r-- | src/pclc/visitors/symbol_table.py | 104 |
4 files changed, 155 insertions, 12 deletions
diff --git a/src/pclc/parser/command.py b/src/pclc/parser/command.py index b9b3921..875a900 100644 --- a/src/pclc/parser/command.py +++ b/src/pclc/parser/command.py @@ -93,6 +93,27 @@ class Return(Entity): super(Return, self).__repr__()) class IfCommand(Entity): + class Block(Entity): + def __init__(self, filename, lineno, commands): + Entity.__init__(self, filename, lineno) + self.commands = commands + + def __iter__(self): + return self.commands.__iter__() + + def accept(self, visitor): + visitor.visit(self) + for cmd in self.commands: + cmd.accept(visitor) + + class ThenBlock(Block): + def __init__(self, filename, lineno, commands): + IfCommand.Block.__init__(self, filename, lineno, commands) + + class ElseBlock(Block): + def __init__(self, filename, lineno, commands): + IfCommand.Block.__init__(self, filename, lineno, commands) + def __init__(self, filename, lineno, @@ -101,26 +122,26 @@ class IfCommand(Entity): else_commands): Entity.__init__(self, filename, lineno) self.condition = condition - self.then_commands = then_commands - self.else_commands = else_commands + self.then_commands = IfCommand.ThenBlock(filename, then_commands[0].lineno, then_commands) + self.else_commands = IfCommand.ElseBlock(filename, else_commands[0].lineno, else_commands) def accept(self, visitor): self.condition.accept(visitor) - for then_cmd in self.then_commands: - then_cmd.accept(visitor) - for else_cmd in self.else_commands: - else_cmd.accept(visitor) + self.then_commands.accept(visitor) + self.else_commands.accept(visitor) visitor.visit(self) def __str__(self): f = lambda cmd: str(cmd) l = ['if', str(self.condition), - 'else', + 'then', " ".join(map(f, then_commands)), - " ".join(map(f, else_commands))] + 'else', + " ".join(map(f, else_commands)), + 'endif'] return " ".join(l) - + def __repr__(self): f = lambda cmd: cmd.__repr__() return "<IfCommand:\n\tcondition = %s,\n\tthen_commands = %s,\n\t" \ diff --git a/src/pclc/visitors/first_pass_resolver_visitor.py b/src/pclc/visitors/first_pass_resolver_visitor.py index 37a47e9..dc8370b 100644 --- a/src/pclc/visitors/first_pass_resolver_visitor.py +++ b/src/pclc/visitors/first_pass_resolver_visitor.py @@ -65,6 +65,7 @@ from parser.helpers import parse_component from pypeline.core.types.just import Just from pypeline.core.types.nothing import Nothing from resolver_visitor import ResolverVisitor +from symbol_table import SymbolTable # Decorator to prevent resolving more than once @@ -206,7 +207,7 @@ class FirstPassResolverVisitor(ResolverVisitor): 'configuration' : dict(), 'unused_configuration' : list(), 'command_table' : list(), - 'assignment_table' : dict()} + 'assignment_table' : SymbolTable()} if not self.__dict__.has_key("__resolve_import"): self.__resolve_import = self.__resolve_runtime_import if self._module.definition.is_leaf \ else self.__resolve_pcl_import @@ -875,7 +876,7 @@ class FirstPassResolverVisitor(ResolverVisitor): elif isinstance(argument, Identifier): if argument not in self._module.definition.inputs and \ argument not in self._module.resolution_symbols['assignment_table']: - self._add_errors("ERROR: %(filename)s at line %(lineno)d, unknown function argument %(arg_name)s TITZ", + self._add_errors("ERROR: %(filename)s at line %(lineno)d, unknown function argument %(arg_name)s", [function], lambda f: {'filename' : f.filename, 'lineno' : f.lineno, @@ -966,4 +967,13 @@ class FirstPassResolverVisitor(ResolverVisitor): @multimethod(IfCommand) def visit(self, if_command): - pass + self._module.resolution_symbols['assignment_table'].pop_inner_scope() + + @multimethod(IfCommand.ThenBlock) + def visit(self, then_block): + self._module.resolution_symbols['assignment_table'].push_inner_scope() + + @multimethod(IfCommand.ElseBlock) + def visit(self, else_block): + self._module.resolution_symbols['assignment_table'].pop_inner_scope() + self._module.resolution_symbols['assignment_table'].push_inner_scope() diff --git a/src/pclc/visitors/second_pass_resolver_visitor.py b/src/pclc/visitors/second_pass_resolver_visitor.py index 3923191..5a48e12 100644 --- a/src/pclc/visitors/second_pass_resolver_visitor.py +++ b/src/pclc/visitors/second_pass_resolver_visitor.py @@ -142,3 +142,11 @@ class SecondPassResolverVisitor(FirstPassResolverVisitor): @multimethod(IfCommand) def visit(self, if_command): pass + + @multimethod(IfCommand.ThenBlock) + def visit(self, then_block): + pass + + @multimethod(IfCommand.ElseBlock) + def visit(self, else_block): + pass diff --git a/src/pclc/visitors/symbol_table.py b/src/pclc/visitors/symbol_table.py new file mode 100644 index 0000000..1e68f80 --- /dev/null +++ b/src/pclc/visitors/symbol_table.py @@ -0,0 +1,104 @@ +# +# Copyright Capita Translation and Interpreting 2013 +# +# This file is part of Pipeline Creation Language (PCL). +# +# Pipeline Creation Language (PCL) is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pipeline Creation Language (PCL) is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Pipeline Creation Language (PCL). If not, see <http://www.gnu.org/licenses/>. +# +class SymbolTable(object): + class Scope(object): + def __init__(self): + self.__table = dict() + self.__nested_scopes = list() + self.__root = None + + def addNestedScope(self, scope): + scope.__root = self + return self.__nested_scopes.append(scope) + + def getRoot(self): + return self.__root + + def __getitem__(self, key): + return self.__table[key] + + def __setitem__(self, key, value): + self.__table[key] = value + + def __delitem__(self, key): + del self.__table[key] + + def __contains__(self, item): + return item in self.__table + + def __iteritems__(self): + return self.__table.__iteritems__() + + def iterkeys(self): + return self.__table.iterkeys() + + def keys(self): + return self.__table.keys() + + def has_key(self, key): + return self.__table.has_key(key) + + def _get_nested_scopes_iter(self): + return self.__nested_scopes.__iter__() + + def __init__(self): + self.__tree = SymbolTable.Scope() + self.__current_scope = self.__tree + + def __getitem__(self, key): + scope = self.__current_scope + while scope is not None: + if scope.has_key(key): + return scope[key] + scope.getRoot() + + raise KeyError + + def __setitem__(self, key, value): + self.__current_scope[key] = value + + def __contains__(self, item): + scope = self.__current_scope + while scope is not None: + if item in scope: + return True + scope = scope.getRoot() + + return False + + def push_inner_scope(self): + scope = SymbolTable.Scope() + self.__current_scope.addNestedScope(scope) + self.__current_scope = scope + + def pop_inner_scope(self): + outer_scope = self.__current_scope.getRoot() + if outer_scope is not None: + self.__current_scope = outer_scope + + def __str__(self): + disp = lambda s, d: (" " * d) + ("%d : " % d) + ", ".join([str(sym) for sym in s.keys()]) + "\n" + + def trav(s, d): + rep = disp(s, d) + for ns in s._get_nested_scopes_iter(): + rep += trav(ns, d + 1) + return rep + + return trav(self.__tree, 0) |