Пример #1
0
    def search_symbol_for_value(self,
                                symbol: Symbol,
                                name: list,
                                type=SYMBOL_VAR):
        """
        Traverses through symbol values to try and find a value
        """

        # One at a time, loops through each component of the name
        while len(name) > 0:
            # If the current symbol is of type INSTANCE (Storing another scope)
            if symbol.data_type == DATA_INSTANCE:
                symbol = self.search_scope_for_symbol(symbol.value, name[0],
                                                      type)

            # If current scope is of type LIST
            elif symbol.data_type == DATA_LIST:
                try:
                    symbol = symbol.value[int(name[0])]
                except:
                    raise InvalidSymbolAccess(
                        "Invalid list access `" + name[0] +
                        "` for symbol value `" + str(symbol.value) +
                        "`. Scriptax.SymbolTable@search_symbol_for_value")
                if not isinstance(symbol, Symbol):
                    symbol = Symbol(name=name[0], value=symbol)

            # If current scope is of type DICT
            elif symbol.data_type == DATA_DICT:
                try:
                    symbol = symbol.value[str(name[0])]
                except:
                    raise InvalidSymbolAccess(
                        "Invalid dict access `" + name[0] +
                        "` for symbol value `" + str(symbol.value) +
                        "`. Scriptax.SymbolTable@search_symbol_for_value")
                if not isinstance(symbol, Symbol):
                    symbol = Symbol(name=name[0], value=symbol)

            # If current scope is of type PYTHONIC
            elif symbol.data_type == DATA_PYTHONIC:
                symbol = Symbol(name=name[0], value=None)

            # If current scope is of type THREAD
            elif symbol.data_type == DATA_THREAD:
                symbol = Symbol(name=name[0], value=None)

            else:
                raise InvalidSymbolAccess(
                    "Unsupported symbol access `" + name[0] +
                    "` for symbol value `" + str(symbol.value) +
                    "`. Scriptax.SymbolTable@search_symbol_for_value")

            name.pop(0)

        return symbol.value
Пример #2
0
    def remove_symbol(self, name: str, type=SYMBOL_VAR):
        """
        Remove a symbol
        """

        if not self.has_symbol(name, type):
            raise InvalidSymbolAccess(
                "Cannot remove symbol with name `" + name +
                "` as it does not exist within this scope. Scriptax.SymbolTable@remove_symbol"
            )

        name: list = self.make_and_verify_name(name)
        scope: SymbolScope = self.traverse_up(name)

        # See if a symbol already exists, if not, it excepts
        try:
            symbol: Symbol = self.search_scope_for_symbol(scope, name[0], type)
        except:
            raise InvalidSymbolAccess(
                "Cannot remove symbol with name `" + "".join(name) +
                "` as it does not exist within this scope. Scriptax.SymbolTable@remove_symbol"
            )

        # If a symbol exists, this section will remove it
        try:
            # Pops the name we used to find the starting symbol from the first try/except above
            name.pop(0)
            # If the name still has more components, then we haven't yet found the right symbol to remove
            if len(name) > 0:
                # Index holds the last component in the name
                index = name[-1]
                # Finds the symbol corresponding to the name excluding the last name component
                symbol = Symbol(name="".join(name),
                                value=self.search_symbol_for_value(
                                    symbol, name[:-1], type))
                # If the symbol is an INSTANCE (Another scope), then find the symbol in that scope and remove it
                if symbol.data_type == DATA_INSTANCE:
                    symbol.value.remove_symbol(name=index)
                # If the symbol is a DICT, remove it the key
                elif symbol.data_type == DATA_DICT:
                    symbol.value.pop(str(index))
                # If the symbol is a LIST, remove the index
                elif symbol.data_type == DATA_LIST:
                    symbol.value.pop(int(index))
                # If the symbol is any other type, then we should not be able to apply another name component to it,
                #   thus it is an error
                else:
                    raise InvalidSymbolAccess(
                        "Unsupported symbol access `" + index +
                        "` for symbol value `" + str(symbol.value) +
                        "`. Scriptax.SymbolTable@remove_symbol")
            else:
                # If the name has no more components, we have already found the symbol we want to remove
                scope.remove_symbol(symbol=symbol)
        except:
            raise InvalidSymbolAccess(
                "Removing existing symbol failed. Scriptax.SymbolTable@remove_symbol"
            )
Пример #3
0
    def set_symbol(self, name: str, value, type=SYMBOL_VAR):
        """
        Set's the value of an existing symbol, creates the symbol if it does not exist yet, handles LIST and DICT as well
        """

        name: list = self.make_and_verify_name(name)
        scope: SymbolScope = self.traverse_up(name)

        # See if a symbol already exists, if not, it excepts and will insert a new symbol
        try:
            symbol: Symbol = self.search_scope_for_symbol(scope, name[0], type)
        except:
            # If we are inserting a new symbol, then the symbol name must only have a single component
            if len(name) > 1:
                raise InvalidSymbolAccess(
                    "Variable access contains too many components for uninitialized subcomponent `"
                    + "".join(name) + "`. Scriptax.SymbolTable@set_symbol")
            scope.insert_symbol(Symbol(name=name[0], value=value))
            return

        # If a symbol already exists, this section will modify its value
        try:
            # Pops the name we used to find the starting symbol from the first try/except above
            name.pop(0)
            # If the name still has more components, then we haven't yet found the right value to modify
            if len(name) > 0:
                # Index holds the last component in the name
                index = name[-1]
                # Finds the symbol corresponding to the name excluding the last name component
                symbol = Symbol(name="".join(name),
                                value=self.search_symbol_for_value(
                                    symbol, name[:-1], type))
                # If the symbol is an INSTANCE (Another scope), then find the symbol in that scope and modify its value
                # This will not insert a brand new symbol into the scope, thus all symbols MUST be pre-defined in the
                #   scope
                if symbol.data_type == DATA_INSTANCE:
                    symbol = symbol.value.get_symbol(index)
                    symbol.value = value
                # If the symbol is a DICT, add it via dictionary indexing
                elif symbol.data_type == DATA_DICT:
                    symbol.value[str(index)] = value
                # If the symbol is a LIST, add it via numeric index
                elif symbol.data_type == DATA_DICT:
                    symbol.value[int(index)] = value
                # If the symbol is any other type, then we should not be able to apply another name component to it,
                #   thus it is an error
                else:
                    raise InvalidSymbolAccess(
                        "Unsupported symbol access `" + index +
                        "` for symbol value `" + str(symbol.value) +
                        "`. Scriptax.SymbolTable@set_symbol")
            else:
                # If the name has no more components, we have already found the symbol we want to modify
                symbol.value = value
        except:
            raise InvalidSymbolAccess(
                "Altering existing symbol failed. Scriptax.SymbolTable@set_symbol"
            )
Пример #4
0
    def import_module(self, name: str, module: Import) -> Symbol:
        """
        Imports a new module to the symbol table
        This does not handle the parse tree or the static method scoping and that should be done prior to calling this

        :param name:
        :param module:
        :return:
        """
        return self.scope().insert_symbol(
            Symbol(name=name, symbol_type=SYMBOL_MODULE, value=module))
Пример #5
0
 def register_method(self, name: str, method_context,
                     attributes: Attributes) -> Symbol:
     """
     Registers a method to the symbol table
     """
     symbol: Symbol = Symbol(name=name,
                             data_type=DATA_METHOD,
                             value=method_context,
                             attributes=attributes.dict())
     self.scope().insert_symbol(symbol)
     return symbol
Пример #6
0
 def insert_symbol(self, symbol: Symbol) -> Symbol:
     """
     Inserts a Symbol into this SymbolScope
     If a Symbol already exists with the same name, throws exception
     """
     symbol.name = SymbolScope.conform_name(symbol.name)
     if self.has_symbol(symbol.name, symbol.symbol_type):
         raise Exception(
             'SymbolScope already contains symbol `' + symbol.name +
             '` and cannot insert a new one. Scriptax.SymbolScope@insert_symbol'
         )
     self.symbols.append(symbol)
     return symbol
Пример #7
0
    def execute_method(self, label,
                       parameters: List[Parameter]) -> BlockStatus:
        """
        Execute a method found inside of the current scope or any of its static parents going up the interface and inheritance tree
        """
        label = self.resolve_label(label)
        method_context: AhParser.Method_def_atomContext = self.symbol_table.execute(
            name=label, parameters=parameters)
        if not method_context:
            self.symbol_table.complete_execution()
            raise InvalidSymbolAccess(
                "Cannot execute something which is not a method " + label +
                ". Scriptax.Visitor@execute_method")

        # Add in optional parameters and verify that the two parameter lists (defined & passed) match
        parameter_names = []
        for parameter in parameters:
            parameter_names.append(parameter.name)
        defined_parameters = self.visit(
            method_context.flexible_parameter_block())
        defined_parameter_names = []

        # Check defined parameters against passed in parameters and add in optional ones
        for parameter in defined_parameters:
            if parameter.required and parameter.name not in parameter_names:
                raise InvalidParameters(
                    "Required parameter " + parameter.name +
                    " not found in parameter list. Scriptax.Visitor@execute_method"
                )
            if not parameter.required and parameter.name not in parameter_names:
                self.symbol_table.current.insert_symbol(
                    Symbol(name=parameter.name, value=parameter.value))
            defined_parameter_names.append(parameter.name)

        # Check passed in parameters to ensure there aren't extra ones which were not defined
        for parameter in parameters:
            if parameter.name not in defined_parameter_names:
                raise InvalidParameters("Unexpected parameter " +
                                        parameter.name +
                                        ". Scriptax.Visitor@execute_method")

        # TODO: If async attribute is true, then this needs to be launched in a thread
        result = self.visit(method_context.block())
        self.symbol_table.complete_execution()
        return result
Пример #8
0
    def execute(self,
                name: str,
                parameters: List[Parameter] = None,
                isolated_scope: bool = False):
        """
        Executes a method by getting the method body, and its appropriate static parent and birthing a scope for the method to operate within
        Returns the method body
        """

        if self.has_symbol(name, SYMBOL_MODULE):
            module_import: Import = self.get_symbol(name,
                                                    type=SYMBOL_MODULE,
                                                    as_value=False).value
            scope = module_import.scope
            method_name = self.make_and_verify_name(name)[1]
            tbl = create_table(scope)
            method: Symbol = tbl.get_symbol(name=method_name, as_value=False)
            instance_table: GenericTable = create_generic_table(scope)
            method_scope: SymbolScope = instance_table.birth_scope(
                name=method_name + "_method")
            # Adds each parameter into the method scope
            if parameters:
                for parameter in parameters:
                    method_scope.insert_symbol(
                        Symbol(name=parameter.name, value=parameter.value))

            # Sets up the dynamic links from the currently executing code to the called method
            self.call(method_scope)

            # Returns the body method such that some parser or compiler can execute its body
            return method.value

        # Ensures that the method symbol exists
        if not self.has_symbol(name) and self.has_symbol(name, SYMBOL_MODULE):
            raise SymbolNotFound(
                "Cannot execute `" + name +
                "` as it does not exist within scope. Scriptax.SymbolTable@execute"
            )

        # Breaks apart the name into the scope name and the method name
        # The scope name is everything before the method name
        name = self.make_and_verify_name(name)

        # Get the scope accessing name which is everything but the last component of the name
        scope_name = name[:-1]

        # If scope_name only contains an up_word, then clear out the scope_name entirely
        if len(scope_name) == 1 and self.name_has_up(scope_name):
            scope_name = []

        # Get the Method name which is just the last component of the name
        method_name = name[-1]

        # print("mn:" + str(method_name))
        # print("sn:" + str(scope_name))

        # These two lines are not needed, but are left in for readabilities sake
        instance_scope: SymbolScope = None  # This is the scope where the method is defined
        method_scope: SymbolScope = None  # This is the scope which will be used to execute the method

        # If there is a scope_name, we must be operating on an instance
        # If there is no scope_name, then we must be trying to call a function on our own instance
        #    or calling a method stored in a var
        if len(scope_name) > 0:
            # Attempts to find the symbol on instances
            try:
                instance_scope = self.get_symbol(name=".".join(scope_name))
            except:
                # If we cant find an instance with the name, then try and see if we have imported this name
                if not self.name_has_up(scope_name):
                    scope_name.insert(0, self.up_words[0])
                instance_scope = self.get_symbol(name=".".join(scope_name),
                                                 type=SYMBOL_MODULE)

        else:
            # Perhaps we are trying to call a function stored in a variable
            instance_scope = self.current

            # Let's see whether the instance_scope contains the method
            tbl = create_table(instance_scope)
            try:
                method: Symbol = tbl.get_symbol(name=method_name,
                                                as_value=False)
            except:
                # If one doesnt exist, then we must be trying to call a function on our own instance
                instance_scope = self._get_parent_module()

        # Gets the method symbol from the scope
        tbl = create_table(instance_scope)
        try:
            method: Symbol = tbl.get_symbol(name=method_name, as_value=False)
        except:
            # print(instance_scope.scope_parent.scope_children[1].symbols[0].name)
            # try:
            #     while tbl.current.scope_parent and tbl.current.scope_parent.scope_children[1] != tbl.current:
            #         print("WHAT")
            #         print(tbl.current.scope_parent.scope_children[1].name)
            #         tbl = create_table(tbl.current.scope_parent.scope_children[1])
            #     print(tbl.current.symbols[0].name)
            #     print(method_name)
            #     print(tbl.current.print_scope_debug())
            #     method: Symbol = tbl.get_symbol(name=method_name, as_value=False)
            # except Exception:
            raise SymbolNotFound(
                "Method `" + ".".join(name) +
                "` does not exist. Scriptax.SymbolTable@execute")

        # Used in a weird edge case where we pass a default parameter which is a method atom
        # TODO: Hopefully in Scriptax 5 this will no longer be required
        while isinstance(method.value,
                         Symbol) and method.value.data_type == DATA_METHOD:
            method = method.value

        if method.data_type != DATA_METHOD:
            raise InvalidSymbolAccess(
                "Cannot execute non executable data type `" +
                method.data_type + "`. Scriptax.SymbolTable@execute")

        # Spawns an anonymous scope if this should be executed in isolation, otherwise use the existing
        #   static scope
        if isolated_scope:
            method_scope = SymbolTable(name=method_name + "_isolated_method",
                                       type=SCOPE_BLOCK).scope()
        else:
            # Births a new scope for the method body inside of its static parent scope
            instance_table: GenericTable = create_generic_table(instance_scope)
            method_scope: SymbolScope = instance_table.birth_scope(
                name=method_name + "_method")

        # Adds each parameter into the method scope
        if parameters:
            for parameter in parameters:
                method_scope.insert_symbol(
                    Symbol(name=parameter.name, value=parameter.value))

        # Sets up the dynamic links from the currently executing code to the called method
        self.call(method_scope)

        # Returns the body method such that some parser or compiler can execute its body
        return method.value
Пример #9
0
# symbol_table.printTable()

from scriptax.parser.symbols.ARISymbolTable import ARISymbolTable, create_table
from scriptax.parser.symbols.SymbolScope import SymbolScope, SCOPE_GLOBAL, SCOPE_MODULE
from scriptax.parser.symbols.Symbol import Symbol, DATA_METHOD

# Simulation:

# Starting program
table = ARISymbolTable(name="program", type=SCOPE_GLOBAL)

# Loading the .ah file as a module
table.enter_scope(name='main', type=SCOPE_MODULE)

# During the parsing of the .ah file add all of the methods as symbols including the constructor as so:
table.scope().insert_symbol(Symbol(name="construct", data_type=DATA_METHOD))

# While parsing .ah file, an instance variable declaration was found
instance_table = ARISymbolTable(name="myInstance")
instance_table.scope().insert_symbol(
    Symbol(name="getValue", data_type=DATA_METHOD))
table.scope().insert_symbol(
    Symbol(name="myInstance", value=instance_table.scope()))

# After parsing the .ah file, execute the constructor by entering an anonymous scope
table.enter_scope(name="constructor_block")

# Below is doing the constructor method body

# In the constructor, we execute a call to the getValue method on our myInstance variable
instance_scope: SymbolScope = table.scope().scope_parent.get_symbol(