Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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