Пример #1
0
        public object Visit(Expr.Call expr)
        {
            object callee = Evaluate(expr.Callee);

            List <object> arguments = new List <object>();

            foreach (Expr arg in expr.Arguments)
            {
                arguments.Add(Evaluate(arg));
            }

            // Make sure we the callee is actually callable
            if (!(callee is ILoxCallable))
            {
                throw new RuntimeErrorException(expr.Paren, "Can only call functions and classes.");
            }

            ILoxCallable function = (ILoxCallable)callee;

            // Make sure we are passing the correct number of arguments
            if (arguments.Count() != function.Arity)
            {
                throw new RuntimeErrorException(expr.Paren, $"Expected {function.Arity} argumuments, but got {arguments.Count()}.");
            }

            return(function.Call(this, arguments));
        }
Пример #2
0
        public void Validate_Call_expr_does_something_useful()
        {
            // Arrange
            var name       = new Token(TokenType.IDENTIFIER, "to_string", null, 1);
            var identifier = new Expr.Identifier(name);
            var get        = new Expr.Get(identifier, name);
            var paren      = new Token(TokenType.RIGHT_PAREN, ")", null, 1);
            var callExpr   = new Expr.Call(get, paren, new List <Expr>());
            var bindings   = new Dictionary <Expr, Binding>
            {
                { identifier, new NativeClassBinding(identifier, typeof(string)) }
            };

            var typeValidationErrors = new List <TypeValidationError>();
            var warnings             = new List <CompilerWarning>();

            // Act
            TypeValidator.Validate(
                new List <Stmt> {
                new Stmt.ExpressionStmt(callExpr)
            },
                error => typeValidationErrors.Add(error),
                expr => bindings[expr],
                warning => warnings.Add(warning)
                );

            // Assert
            Assert.Empty(typeValidationErrors);
            Assert.Empty(warnings);
        }
Пример #3
0
        void superCall(Expr.Call sCallExpr)
        {
            Expr.Super superExpr = (Expr.Super)sCallExpr.callee;

            captureToken(superExpr.keyword);

            if (currentClass == null)
            {
                error("Cannot use 'super' outside of a class.");
            }
            else if (!currentClass.hasSuperclass)
            {
                error("Cannot use 'super' in a class with no superclass.");
            }

            captureToken(superExpr.method);

            byte name = identifierConstant(superExpr.method);

            getNamedVariable(syntheticToken("this"));

            byte argCount = compile_argumentList(sCallExpr.arguments);

            getNamedVariable(superExpr.keyword);

            emitBytes((byte)OpCode.OP_SUPER_INVOKE, name);
            emitByte(argCount);
        }
Пример #4
0
    public object VisitCallExpr(Expr.Call expr)
    {
        object        callee    = Evaluate(expr.Callee);
        List <object> arguments = new List <object>();

        foreach (Expr argument in expr.Arguments)
        {
            arguments.Add(Evaluate(argument));
        }

        if (!(callee is LoxCallable))
        {
            throw new RuntimeException(
                      expr.Paren, "Can only call functions and classes.");
        }

        LoxCallable function = (LoxCallable)callee;
        int         arity    = function.Arity();

        if (arguments.Count != arity)
        {
            throw new RuntimeException(expr.Paren,
                                       $"Expected {arity} arguments but got {arguments.Count}.");
        }

        return(function.Call(this, arguments));
    }
Пример #5
0
        public object VisitCallExpr(Expr.Call expr)
        {
            object callee = Evaluate(expr.Callee);

            IList <object> arguments = new List <object>();

            foreach (var argument in expr.Arguments)
            {
                arguments.Add(Evaluate(argument));
            }


            if (!(callee is ICallable))
            {
                throw new RuntimeError(expr.Paren, "Can only call functions and classes");
            }

            ICallable function = (ICallable)callee;

            if (arguments.Count != function.Arity())
            {
                throw new RuntimeError(expr.Paren, "Expected " + function.Arity() + " arguments but got " + arguments.Count);
            }

            return(function.Call(this, arguments));
        }
Пример #6
0
        public object visitCallExpr(Expr.Call expr)
        {
            object callee = evaluate(expr.callee);

            List <object> arguments = new List <object>();

            foreach (Expr argument in expr.arguments)
            {
                arguments.Add(evaluate(argument));
            }

            if (!(callee is LoxCallable))
            {
                throw new RuntimeError(expr.paren, "Can only call functions and classes.");
            }

            LoxCallable function = (LoxCallable)callee;

            if (arguments.Count != function.arity())
            {
                throw new RuntimeError(expr.paren, "Expected " + function.arity() + " arguments but got " + arguments.Count + ".");
            }


            return(function.call(this, arguments));
        }
Пример #7
0
 public Unit VisitCallExpr(Expr.Call expr)
 {
     foreach (Expr argument in expr.Arguments)
     {
         Resolve(argument);
     }
     return(new Unit());
 }
Пример #8
0
        public object VisitCallExpr(Expr.Call expr)
        {
            Resolve(expr.Callee);
            foreach (var argument in expr.Arguments)
            {
                Resolve(argument);
            }

            return(null);
        }
Пример #9
0
        public LoxVoid VisitCallExpr(Expr.Call expr)
        {
            Resolve(expr.Callee);

            foreach (Expr argument in expr.Arguments)
            {
                Resolve(argument);
            }

            return(null);
        }
Пример #10
0
        public object visitCallExpr(Expr.Call expr)
        {
            resolve(expr.callee);

            foreach (Expr argument in expr.arguments)
            {
                resolve(argument);
            }

            return(null);
        }
Пример #11
0
        /// <summary>
        /// Resolve a call expression
        /// </summary>
        /// <param name="expr">The expression</param>
        /// <returns></returns>
        public object Visit(Expr.Call expr)
        {
            Resolve(expr.Callee);

            foreach (Expr arg in expr.Arguments)
            {
                Resolve(arg);
            }

            return(null);
        }
Пример #12
0
        void getCall(Expr.Call gCallExpr)
        {
            Expr.Get getExpr = (Expr.Get)gCallExpr.callee;
            compile(getExpr.object_);

            captureToken(getExpr.name);

            byte name     = identifierConstant(getExpr.name);
            byte argCount = compile_argumentList(gCallExpr.arguments);

            emitBytes((byte)OpCode.OP_INVOKE, name);
            emitByte(argCount);
        }
Пример #13
0
        public Value Visit(Expr.Call expr)
        {
            var function = this.GetFunction(expr.Callee);

            var args = new Value[Math.Max(expr.Arguments.Length, 0)];

            for (var i = 0; i < args.Length; i++)
            {
                args[i] = expr.Arguments[i].Accept(this);
            }

            return(this._instructionBuilder.Call(function, args).RegisterName("calltmp"));
        }
Пример #14
0
        public override VoidObject VisitCallExpr(Expr.Call expr)
        {
            if (expr.Callee is Expr.Get get)
            {
                VisitCallExprForGetCallee(expr, get);
            }
            else
            {
                VisitCallExprForOtherCallee(expr);
            }

            return(VoidObject.Void);
        }
Пример #15
0
        private Expression EmitCallExpression(Expr.Call call)
        {
            if (call.FuncName.Ref.Symbol.FirstDeclarationOrDefault is FilterFunDeclaration filterDeclaration)
            {
                var args = new[] { EmitExpression(call.Arg0) }.Concat(call.Args.Select(expr => EmitExpression(expr))).ToArray();
                if (args.Length > 0)
                {
                    return(Expression.Call(filterDeclaration.Method, args));
                }
                return(Expression.Call(filterDeclaration.Method));
            }

            return(Expression.Empty());
        }
Пример #16
0
        public VoidObject VisitCallExpr(Expr.Call expr)
        {
            Resolve(expr.Callee);

            foreach (Expr argument in expr.Arguments)
            {
                Resolve(argument);
            }

            if (expr.Callee is Expr.Identifier identifierExpr)
            {
                ResolveLocalOrGlobal(expr, identifierExpr.Name);
            }

            return(VoidObject.Void);
        }
Пример #17
0
        public object VisitCallExpr(Expr.Call expr)
        {
            object callee = Evalutate(expr.Callee);

            List <object> arguments = expr.Arguments
                                      .Select(e => Evalutate(e))
                                      .ToList();

            if (callee is ILoxCallable function)
            {
                if (arguments.Count != function.Arity)
                {
                    throw new RuntimeError(expr.Paren, $"Expected {function.Arity} " +
                                           $"arguments but got {arguments.Count}.");
                }

                return(function.Call(this, arguments));
            }

            throw new RuntimeError(expr.Paren, "Can only call functions and classes.");
        }
Пример #18
0
        /*
         * Expr.Get and Expr.Super callees are intercepted
         * for separate treatment for invoke and property
         */
        public object visitCallExpr(Expr.Call callExpr)
        {
            captureToken(callExpr.paren);
            byte argCount;

            if (callExpr.callee is Expr.Variable) // "common"/global functions
            {
                getNamedVariable(((Expr.Variable)callExpr.callee).name);

                argCount = compile_argumentList(callExpr.arguments);
                emitBytes((byte)OpCode.OP_CALL, argCount);

                return(null);
            }

            if (callExpr.callee is Expr.Get) // methods
            {
                getCall(callExpr);
                return(null);
            }

            if (callExpr.callee is Expr.Super) // super methods
            {
                superCall(callExpr);
                return(null);
            }

            if (callExpr.callee is Expr.Call) // nested calls
            {
                argCount = compile_argumentList(callExpr.arguments);
                visitCallExpr((Expr.Call)callExpr.callee);

                emitBytes((byte)OpCode.OP_CALL, argCount);
                return(null);
            }

            error("Can only call functions and classes."); // runtime error in clox

            return(null);
        }
Пример #19
0
        public object VisitCallExpr(Expr.Call expr)
        {
            var callee = Evaluate(expr.callee);

            var args = new List <object>();

            foreach (var arg in expr.arguments)
            {
                args.Add(Evaluate(arg));
            }

            if (callee is ICallable function)
            {
                if (args.Count != function.Arity())
                {
                    throw new RuntimeException(expr.paren, $"Expected {function.Arity()} arguments but got {args.Count}.");
                }

                return(function.Call(this, args));
            }

            throw new RuntimeException(expr.paren, "Can only call functions and classes");
        }
Пример #20
0
 private string VisitCallExpr(Expr.Call expr)
 {
     throw new NotImplementedException();
 }
Пример #21
0
        private void VisitCallExprForGetCallee(Expr.Call call, Expr.Get get)
        {
            string methodName = get.Name.Lexeme;

            if (get.Methods.Length == 0)
            {
                if (!get.Object.TypeReference.IsResolved)
                {
                    // This is a bit of an oddball, but... We get here when an attempt is made to call a method on some
                    // undefined type. (`Foo.do_stuff`)
                    //
                    // Now, this is a compile-time error, but the problem is that it's handled by this class itself;
                    // encountering this error will not abort the tree traversal so we must avoid breaking it.
                }
                else
                {
                    // This is even more odd, but we must ensure that we have well-defined semantics in the weird case
                    // where this would happen.
                    TypeValidationErrorCallback(new TypeValidationError(
                                                    call.Paren,
                                                    $"Internal compiler error: no methods with name '{methodName}' could be found. This is a critical " +
                                                    $"error that should have aborted the compilation before the {nameof(TypesResolvedValidator)} " +
                                                    "validation is started. "
                                                    ));
                }
            }
            else if (get.Methods.Length == 1)
            {
                MethodInfo method     = get.Methods.Single();
                var        parameters = method.GetParameters();

                // There is exactly one potential method to call in this case. We use this fact to provide better
                // error messages to the caller than when calling an overloaded method.
                if (parameters.Length != call.Arguments.Count)
                {
                    TypeValidationErrorCallback(new TypeValidationError(
                                                    call.Paren,
                                                    $"Method '{methodName}' has {parameters.Length} parameter(s) but was called with {call.Arguments.Count} argument(s)"
                                                    ));

                    return;
                }

                for (int i = 0; i < call.Arguments.Count; i++)
                {
                    ParameterInfo parameter = parameters[i];
                    Expr          argument  = call.Arguments[i];

                    if (!argument.TypeReference.IsResolved)
                    {
                        throw new PerlangInterpreterException(
                                  $"Internal compiler error: Argument '{argument}' to function {methodName} not resolved");
                    }

                    // FIXME: call.Token is a bit off here; it would be useful when constructing compiler warnings based
                    // on this if we could provide the token for the argument expression instead. However, the Expr type
                    // as used by 'argument' is a non-token-based expression so this is currently impossible.
                    // FIXME: `null` here has disadvantages as described elsewhere.
                    if (!TypeCoercer.CanBeCoercedInto(parameter.ParameterType, argument.TypeReference.ClrType, null))
                    {
                        // Very likely refers to a native method, where parameter names are not available at this point.
                        TypeValidationErrorCallback(new TypeValidationError(
                                                        argument.TypeReference.TypeSpecifier !,
                                                        $"Cannot pass {argument.TypeReference.ClrType.ToTypeKeyword()} argument as {parameter.ParameterType.ToTypeKeyword()} parameter to {methodName}()"));
                    }
                }
            }
            else
            {
                // Method is overloaded. Try to resolve the best match we can find.
                foreach (MethodInfo method in get.Methods)
                {
                    var parameters = method.GetParameters();

                    if (parameters.Length != call.Arguments.Count)
                    {
                        // The number of parameters do not match, so this method will never be a suitable candidate
                        // for our expression.
                        continue;
                    }

                    bool coercionsFailed = false;

                    for (int i = 0; i < call.Arguments.Count; i++)
                    {
                        ParameterInfo parameter = parameters[i];
                        Expr          argument  = call.Arguments[i];

                        if (!argument.TypeReference.IsResolved)
                        {
                            throw new PerlangInterpreterException(
                                      $"Internal compiler error: Argument '{argument}' to method {methodName} not resolved");
                        }

                        // FIXME: The same caveat as above with call.Token applies here as well.
                        if (!TypeCoercer.CanBeCoercedInto(parameter.ParameterType, argument.TypeReference.ClrType, null))
                        {
                            coercionsFailed = true;
                            break;
                        }
                    }

                    if (!coercionsFailed)
                    {
                        // We have found a suitable overload to use. Update the expression
                        get.Methods = ImmutableArray.Create(method);
                        return;
                    }
                }

                TypeValidationErrorCallback(new NameResolutionTypeValidationError(
                                                call.Paren,
                                                $"Method '{call.CalleeToString}' found, but no overload matches the provided parameters."
                                                ));
            }
        }
Пример #22
0
 string Expr.ILoxVisitor <string> .VisitCallExpr(Expr.Call expr)
 {
     throw new NotImplementedException();
 }
Пример #23
0
 public object VisitCallExpr(Expr.Call expr, object options)
 {
     return(Parenthesize2("call", expr.callee, Parenthesize("args: ", expr.arguments.ToArray())));
 }
Пример #24
0
 public string visitCallExpr(Expr.Call expr)
 {
     throw new NotImplementedException();
 }
Пример #25
0
 public string VisitCallExpr(Expr.Call expr)
 {
     throw new System.NotImplementedException();
 }
Пример #26
0
 public string VisitCallExpr(Expr.Call expr)
 {
     return(Parenthesize("func", expr));
 }
Пример #27
0
        public string VisitCallExpr(Expr.Call expr)
        {
            string arguments = string.Join(", ", expr.Arguments.Select(e => PrintExpr(e)));

            return($"{PrintExpr(expr.Callee)}({arguments})");
        }
Пример #28
0
 public Token visitCallExpr(Expr.Call call)
 {
     return(evaluate(call.callee));
 }
Пример #29
0
        private void VisitCallExprForOtherCallee(Expr.Call expr)
        {
            Binding binding = GetVariableOrFunctionCallback(expr);

            if (binding == null)
            {
                TypeValidationErrorCallback(
                    new NameResolutionTypeValidationError(expr.Paren, $"Attempting to call undefined function '{expr.CalleeToString}'")
                    );

                return;
            }

            IList <Parameter> parameters;
            string            functionName;

            switch (binding)
            {
            case FunctionBinding functionBinding:
                Stmt.Function function = functionBinding.Function;

                if (function == null)
                {
                    throw new NameResolutionTypeValidationError(expr.Paren, $"Internal compiler error: function for {expr} not expected to be null");
                }

                parameters   = function.Parameters;
                functionName = function.Name.Lexeme;
                break;

            default:
                throw new NameResolutionTypeValidationError(expr.Paren, $"Attempting to call invalid function {binding} using {expr}");
            }

            if (parameters.Count != expr.Arguments.Count)
            {
                TypeValidationErrorCallback(new TypeValidationError(
                                                expr.Paren,
                                                $"Function '{functionName}' has {parameters.Count} parameter(s) but was called with {expr.Arguments.Count} argument(s)")
                                            );

                return;
            }

            for (int i = 0; i < expr.Arguments.Count; i++)
            {
                Parameter parameter = parameters[i];
                Expr      argument  = expr.Arguments[i];

                if (!argument.TypeReference.IsResolved)
                {
                    throw new PerlangInterpreterException($"Internal compiler error: Argument '{argument}' to function {functionName} not resolved");
                }

                if (argument.TypeReference.IsNullObject)
                {
                    compilerWarningCallback(new CompilerWarning($"Null parameter detected for '{parameter.Name.Lexeme}'", expr.TokenAwareCallee.Token, WarningType.NULL_USAGE));
                }

                // FIXME: expr.Token is an approximation here as well (see other similar comments in this file)
                // FIXME: `null` here means that small-constants of e.g. `long` will not be able to be passed as `int` parameters.
                if (!TypeCoercer.CanBeCoercedInto(parameter.TypeReference, argument.TypeReference, null))
                {
                    if (parameter.Name != null)
                    {
                        TypeValidationErrorCallback(new TypeValidationError(
                                                        argument.TypeReference.TypeSpecifier !,
                                                        $"Cannot pass {argument.TypeReference.ClrType.ToTypeKeyword()} argument as parameter '{parameter.Name.Lexeme}: {parameter.TypeReference.ClrType.ToTypeKeyword()}' to {functionName}()"));
                    }
                    else
                    {
                        // Very likely refers to a native method, where parameter names are not available at this point.
                        TypeValidationErrorCallback(new TypeValidationError(
                                                        argument.TypeReference.TypeSpecifier !,
                                                        $"Cannot pass {argument.TypeReference.ClrType.ToTypeKeyword()} argument as {parameter.TypeReference.ClrType.ToTypeKeyword()} parameter to {functionName}()"));
                    }
                }
            }
        }
Пример #30
0
 public object VisitCallExpr(Expr.Call expr, object options = null)
 {
     return(null);
 }