def __init__(self): self.packages: List[Package] = [] self._generate_builtin_package('typing', TypeUtils.get_types_from_typing_lib()) self._generate_builtin_package('math', Math.get_methods_from_math_lib()) self._generate_builtin_package('boa3.builtin', Builtin.boa_builtins) self._generate_builtin_package('boa3.builtin.contract', Builtin.package_symbols('contract')) self._generate_builtin_package('boa3.builtin.interop', Interop.package_symbols) self._generate_builtin_package('boa3.builtin.nativecontract', NativeContract.package_symbols) self._generate_builtin_package('boa3.builtin.type', Builtin.package_symbols('type'))
def get_symbol(self, symbol_id: str, is_internal: bool = False) -> Optional[ISymbol]: """ Tries to get the symbol by its id name :param symbol_id: the id name of the symbol :return: the symbol if found. None otherwise. :rtype: ISymbol or None """ if symbol_id in self.symbols: # the symbol exists in the global scope return self.symbols[symbol_id] if is_internal: from boa3.model.importsymbol import Import imports = [ symbol for symbol in self.symbols.values() if isinstance(symbol, Import) ] for package in imports: if symbol_id in package.all_symbols: return package.all_symbols[symbol_id] # the symbol may be a built in. If not, returns None from boa3.model.builtin.builtin import Builtin found_symbol = Builtin.get_symbol(symbol_id) if found_symbol is None and isinstance( symbol_id, str) and self.is_exception(symbol_id): found_symbol = Builtin.Exception.return_type return found_symbol
def visit_Call(self, call: ast.Call) -> Optional[IType]: """ Visitor of a function call node :param call: the python ast function call node :return: the result type of the called function. None if the function is not found """ func_id = self.visit(call.func) func_symbol = self.get_symbol(func_id) # if func_symbol is None, the called function may be a function written after in the code # that's why it shouldn't log a compiler error here if func_symbol is None: return None if not isinstance(func_symbol, Callable): # verifiy if it is a builtin method with its name shadowed func = Builtin.get_symbol(func_id) func_symbol = func if func is not None else func_symbol func_symbol = Builtin.Exception if func_symbol is Type.exception else func_symbol if not isinstance(func_symbol, Callable): # the symbol doesn't exists self._log_error( CompilerError.UnresolvedReference(call.func.lineno, call.func.col_offset, func_id)) elif isinstance(func_symbol, IBuiltinMethod): if func_symbol.body is not None: self._builtin_functions_to_visit[func_id] = func_symbol elif func_symbol is Builtin.NewEvent: new_event = self.create_new_event(call) self.__include_callable(new_event.identifier, new_event) self._current_event = new_event return self.get_type(call.func)
def validate_builtin_callable(self, callable_id: str, callable_target: ISymbol) -> ISymbol: if not isinstance(callable_target, Callable): # verify if it is a builtin method with its name shadowed call_target = Builtin.get_symbol(callable_id) if not isinstance(call_target, Callable) and self.is_exception(callable_id): call_target = Builtin.Exception callable_target = call_target if call_target is not None else callable_target return callable_target
def _get_boa3_builtin_package(self, packages: List[str]) -> Dict[str, ISymbol]: if len(packages) > 0: if len(packages) == 1: return Builtin.package_symbols(packages[0]) if packages[0] == 'interop': return self._get_interop_symbols(packages[1]) return self._get_boa3_builtin_symbols()
def visit_Attribute(self, attribute: ast.Attribute) -> Union[ISymbol, str]: """ Gets the attribute inside the ast node :param attribute: the python ast attribute node :return: returns the type of the value, the attribute symbol and its id if the attribute exists. Otherwise, returns None """ value_id = attribute.value.id if isinstance(attribute.value, ast.Name) else None value: ISymbol = self.get_symbol(value_id) if value_id is not None else self.visit(attribute.value) if isinstance(value, Variable): value = value.type if hasattr(value, 'symbols') and attribute.attr in value.symbols: return value.symbols[attribute.attr] elif Builtin.get_symbol(attribute.attr) is not None: return Builtin.get_symbol(attribute.attr) else: return '{0}.{1}'.format(value_id, attribute.attr)
def get_symbol(self, symbol_id: str, is_internal: bool = False, check_raw_id: bool = False, origin_node: ast.AST = None) -> Optional[ISymbol]: """ Tries to get the symbol by its id name :param symbol_id: the id name of the symbol :return: the symbol if found. None otherwise. :rtype: ISymbol or None """ if symbol_id in self.symbols: # the symbol exists in the global scope return self.symbols[symbol_id] if check_raw_id: found_symbol = self._search_by_raw_id(symbol_id, list(self.symbols.values())) if found_symbol is not None: # the symbol exists in the global scope, but with an alias different from the original name return found_symbol if is_internal: from boa3.model import imports found_symbol = imports.builtin.get_internal_symbol(symbol_id) if isinstance(found_symbol, ISymbol): return found_symbol # the symbol may be a built in. If not, returns None from boa3.model.builtin.builtin import Builtin found_symbol = Builtin.get_symbol(symbol_id) if found_symbol is None and isinstance( symbol_id, str) and self.is_exception(symbol_id): found_symbol = Builtin.Exception.return_type if origin_node is not None and found_symbol is None: self._log_error( UnresolvedReference(line=origin_node.lineno, col=origin_node.col_offset, symbol_id=symbol_id)) return found_symbol
def get_symbol(self, symbol_id: str) -> Optional[ISymbol]: """ Tries to get the symbol by its id name :param symbol_id: the id name of the symbol :return: the symbol if found. None otherwise. :rtype: ISymbol or None """ if symbol_id in self.symbols: # the symbol exists in the global scope return self.symbols[symbol_id] else: # the symbol may be a built in. If not, returns None from boa3.model.builtin.builtin import Builtin found_symbol = Builtin.get_symbol(symbol_id) if found_symbol is None and isinstance( symbol_id, str) and self.is_exception(symbol_id): found_symbol = Builtin.Exception.return_type return found_symbol
def get_symbol(self, identifier: str) -> ISymbol: """ Gets a symbol in the symbol table by its id :param identifier: id of the symbol :return: the symbol if exists. Symbol None otherwise """ if self._current_method is not None and identifier in self._current_method.symbols: return self._current_method.symbols[identifier] elif identifier in self.symbol_table: return self.symbol_table[identifier] # the symbol may be a built in. If not, returns None symbol = Builtin.get_symbol(identifier) if symbol is not None: return symbol split = identifier.split('.') if len(split) > 1: attribute, symbol_id = '.'.join(split[:-1]), split[-1] attr = self.get_symbol(attribute) if hasattr(attr, 'symbols') and symbol_id in attr.symbols: return attr.symbols[symbol_id] return Type.none
def _get_boa3_builtin_symbols(self) -> Dict[str, ISymbol]: return Builtin.boa_symbols()
def _get_interop_symbols(self, package: str) -> Dict[str, ISymbol]: return Builtin.interop_symbols(package)