def validate_callable_arguments(self, call: ast.Call, callable_target: Callable) -> bool: if (callable_target.allow_starred_argument and not hasattr(call, 'checked_starred_args') and len(call.args) > len(callable_target.args_without_default)): args = self.parse_to_node(str(Type.sequence.default_value), call) args.elts = call.args call.args = [args] call.checked_starred_args = True len_call_args = len(call.args) callable_required_args = len(callable_target.args_without_default) if len_call_args > len(callable_target.args): unexpected_arg = call.args[len(callable_target.args)] self._log_error( CompilerError.UnexpectedArgument(unexpected_arg.lineno, unexpected_arg.col_offset) ) return False elif len_call_args < callable_required_args: missed_arg = list(callable_target.args)[len(call.args)] self._log_error( CompilerError.UnfilledArgument(call.lineno, call.col_offset, missed_arg) ) return False if isinstance(callable_target, IBuiltinMethod) and callable_target.requires_reordering: if not hasattr(call, 'was_reordered') or not call.was_reordered: callable_target.reorder(call.args) call.was_reordered = True if callable_required_args <= len_call_args < len(callable_target.args): included_args = len_call_args - callable_required_args call.args.extend(callable_target.defaults[included_args:]) return True
def _read_metadata_object(self, function: ast.FunctionDef): """ Gets the metadata object defined in this function :param function: """ if self._metadata is not None: # metadata function has been defined already self._log_warning( CompilerWarning.RedeclaredSymbol( line=function.lineno, col=function.col_offset, symbol_id=Builtin.Metadata.identifier)) # this function must have a return and no arguments elif len(function.args.args) != 0: self._log_error( CompilerError.UnexpectedArgument(line=function.lineno, col=function.col_offset)) elif not any(isinstance(stmt, ast.Return) for stmt in function.body): self._log_error( CompilerError.MissingReturnStatement(line=function.lineno, col=function.col_offset, symbol_id=function.name)) else: function.returns = None function.decorator_list = [] module: ast.Module = ast.parse('') module.body = [ node for node in self._tree.body if isinstance(node, (ast.ImportFrom, ast.Import)) ] module.body.append(function) ast.copy_location(module, function) # executes the function code = compile(module, filename='<boa3>', mode='exec') namespace = {} exec(code, namespace) obj: Any = namespace[function.name]() node: ast.AST = function.body[-1] if len( function.body) > 0 else function # return must be a NeoMetadata object if not isinstance(obj, NeoMetadata): obj_type = self.get_type(obj).identifier if self.get_type( obj) is not Type.any else type(obj).__name__ self._log_error( CompilerError.MismatchedTypes( line=node.lineno, col=node.col_offset, expected_type_id=NeoMetadata.__name__, actual_type_id=obj_type)) return # validates the metadata attributes types attributes: Dict[str, Any] = { attr: value for attr, value in dict(obj.__dict__).items() if attr in Builtin.metadata_fields } if any(not isinstance(value, Builtin.metadata_fields[attr]) for attr, value in attributes.items()): for expected, actual in [ (Builtin.metadata_fields[attr], type(v_type)) for attr, v_type in attributes.items() if not isinstance(v_type, Builtin.metadata_fields[attr]) ]: if isinstance(expected, Iterable): expected_id = 'Union[{0}]'.format(', '.join( [tpe.__name__ for tpe in expected])) elif hasattr(expected, '__name__'): expected_id = expected.__name__ else: expected_id = str(expected) self._log_error( CompilerError.MismatchedTypes( line=node.lineno, col=node.col_offset, expected_type_id=expected_id, actual_type_id=actual.__name__)) else: # if the function was defined correctly, sets the metadata object of the smart contract self._metadata = obj self._metadata_node = function # for error messages only
def validate_values(self, *params: Any) -> List[Any]: values = [] if len(params) != 2: return values origin, visitor = params values.append(self.external_name) from boa3.analyser.astanalyser import IAstAnalyser if not isinstance(visitor, IAstAnalyser): return values from boa3.exception import CompilerError if not isinstance(origin, ast.Call): visitor._log_error( CompilerError.UnfilledArgument(origin.lineno, origin.col_offset, list(self.args.keys())[0])) return values args_names = list(self.args.keys()) if len(origin.args) > len(args_names): visitor._log_error( CompilerError.UnexpectedArgument(origin.lineno, origin.col_offset)) return values # read the called arguments args_len = min(len(origin.args), len(args_names)) values.clear() for x in range(args_len): values.append(visitor.visit(origin.args[x])) if len(values) < 1: values.append(self.external_name) # read the called keyword arguments for kwarg in origin.keywords: if kwarg.arg in args_names: x = args_names.index(kwarg.arg) value = visitor.visit(kwarg.value) values[x] = value else: visitor._log_error( CompilerError.UnexpectedArgument(kwarg.lineno, kwarg.col_offset)) if not isinstance(values[0], str): visitor._log_error( CompilerError.UnfilledArgument(origin.lineno, origin.col_offset, list(self.args.keys())[0])) return values if visitor.get_symbol(values[0]) is not None: visitor._log_error( CompilerError.InvalidUsage( origin.lineno, origin.col_offset, "Only literal values are accepted for 'name' argument")) values[0] = self.external_name return values