Пример #1
0
 def __init__(self, printfunc=print):
     self.printfunc = printfunc
     # The following structures must
     # already be defined here so that they are retained for shell
     # input (which is split on several ast.Programs).
     # Everything that can be accessed with a name/identifier, is stored
     # either in globals or locals.
     # Globals is a dictionary that maps global names to instances. It
     # contains modules, typedefs, functions.
     # Locals is an array which acts as a stack for local variables.
     # Top-level statements behave like being encapsulated in an implicit
     # main()-function, i.e. their variables are not global!
     # I think that we could always use a self.locals.append() whenever
     # new names are pushed on the stack (function arguments and in let
     # statements) but it looks more high-level to access the variables
     # always in the same way, which is: self.locals[symbol_tree.get_index()].
     # To enable this when declaring variables, we use a list that
     # automatically grows.
     #self.globals : typing.Dict[str, ]
     self.locals = StackList()
     # Modules/Imports, custom types and function definitions are accessed through
     # the ast.TranslationUnit directly. The evaluator can access/read the symbol table
     # to identify stuff.
     # Here, initialized empty, filled with content when evaluating.
     self.current_unit = TranslationUnitRef(
         ast.TranslationUnit([], collections.OrderedDict(),
                             collections.OrderedDict(), [], {}))
     # All imported modules
     self.modules: typing.Dict[str, ast.TranslationUnit] = {}
     #
     self.symbol_tree = SymbolTree()
Пример #2
0
 def __init__(
     self,
     symbol_table_snapshot=None,
     modules: typing.Optional[typing.Dict[str,
                                          ast.TranslationUnit]] = None):
     self.symbol_tree = SymbolTree(symbol_table_snapshot)
     self.modules: typing.Dict[str,
                               ast.TranslationUnit] = modules if isinstance(
                                   modules, dict) else {}
Пример #3
0
 def resolve_function_interface(self, function: ast.FunctionDefinition,
                                unit: ast.TranslationUnit):
     parameters = bongtypes.TypeList([])
     returns = bongtypes.TypeList([])
     for param_name, param_type in zip(function.parameter_names,
                                       function.parameter_types):
         typ = self.resolve_type(param_type, unit, function)
         parameters.append(typ)
         SymbolTree(function.symbol_tree_snapshot)[param_name] = typ
     for ret in function.return_types:
         returns.append(self.resolve_type(ret, unit, function))
     unit.symbols_global[function.name] = bongtypes.Function(
         parameters, returns)
Пример #4
0
 def parse_function_definition(self) -> ast.FunctionDefinition:
     toks = TokenList()
     # FUNC foo (bar : int) : str { ... }
     if not toks.add(self.match(token.FUNC)):
         raise Exception("Expected function definition.")
     # func FOO (bar : int) : str { ... }
     if not toks.add(self.match(token.IDENTIFIER)):
         raise ParseException("Expected function name.")
     name = self.peek(-1).lexeme
     if name in self.symbols_global:
         raise ParseException(f"Name '{name}' already exists in symbol table. Function definition impossible.")
     # Register function name before parsing parameter names (no parameter name should have the function name!)
     self.symbols_global[name] = bongtypes.UnknownType()
     # (
     if not toks.add(self.match(token.LPAREN)):
         raise ParseException("Expected ( to start the parameter list.")
     # Parameters
     parameter_names, parameter_types = self.parse_parameters()
     # )
     if not toks.add(self.match(token.RPAREN)):
         raise ParseException("Expected ) to end the parameter list.")
     # Return types
     return_types : typing.List[ast.BongtypeIdentifier] = []
     if toks.add(self.match(token.COLON)):
         self.check_eof("Return type list expected.")
         return_types.append(self.parse_type())
         while toks.add(self.match(token.COMMA)):
             return_types.append(self.parse_type())
     # {
     if not self.peek().type == token.LBRACE:
         raise ParseException("Expected function body.")
     # New local symbol table (tree) for statement block
     # We could just store the global symbol table in the object because
     # it will always be the same. But remembering the previous symbol
     # table here theoretically allows to parse function definitions inside
     # other functions (the local symbol table would be properly restored
     # then).
     global_symbol_tree = self.symbol_tree
     self.symbol_tree = SymbolTree()
     # Parameters
     for param,typ in zip(parameter_names,parameter_types):
         if param in self.symbol_tree:
             raise ParseException(f"Argument name '{param}' appears twice in function definition")
         self.symbol_tree.register(param, bongtypes.UnknownType())
     # Snapshot before block is parsed (this changes the state of the tree)
     func_symbol_tree_snapshot = self.symbol_tree.take_snapshot()
     # Function body
     body = self.block_stmt()
     # Restore symbol table/tree
     self.symbol_tree = global_symbol_tree
     return ast.FunctionDefinition(toks, name, parameter_names, parameter_types, return_types, body, func_symbol_tree_snapshot)
Пример #5
0
    def __init__(self, lexer, snapshot=None, basepath=None):
        self.lexer = lexer

        self.basepath = basepath if basepath != None else os.getcwd()

        self.symbols_global : typing.Dict[str, bongtypes.BaseNode] = {}
        self.symbol_tree = SymbolTree()
        if snapshot != None:
            # When restoring the global dictionary, we need to copy the dict.
            # Otherwise, we change the snapshot that the caller (the repl)
            # will (most probably) reuse.
            self.symbols_global = snapshot[0].copy() # overwrite
            self.symbol_tree.restore_snapshot(snapshot[1]) # restore
        else:
            # Only when initializing symbol tables for the first time, register
            # builtin stuff
            for bfuncname, bfunc in bong_builtins.functions.items():
                self.symbols_global[bfuncname] = bongtypes.BuiltinFunction(bfunc[1])
            for btypename, btype in bongtypes.basic_types.items():
                self.symbols_global[btypename] = bongtypes.Typedef(btype())