コード例 #1
0
        public void Validate_Get_expr_yields_expected_error_for_undefined_variable()
        {
            // Arrange
            var name       = new Token(TokenType.IDENTIFIER, "foo", null, -1);
            var identifier = new Expr.Identifier(name);
            var getExpr    = new Expr.Get(identifier, name);

            var bindings = new Dictionary <Expr, Binding>
            {
                // A null TypeReference here is the condition that is expected to lead to an "undefined variable" error.
                { identifier, new VariableBinding(typeReference: null, 0, identifier) }
            };

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

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

            // Assert
            Assert.Single(typeValidationErrors);
            Assert.Matches(typeValidationErrors.Single().Message, "Undefined identifier 'foo'");

            Assert.Empty(warnings);
        }
コード例 #2
0
        public void Validate_Get_expr_yields_no_error_for_defined_variable()
        {
            // Arrange
            //
            // This is the method being referred to. The expression below roughly matches "Foo.to_string", where
            // Foo is a defined Perlang class.
            var name       = new Token(TokenType.IDENTIFIER, "to_string", null, -1);
            var identifier = new Expr.Identifier(name);
            var getExpr    = new Expr.Get(identifier, name);

            var bindings = new Dictionary <Expr, Binding>
            {
                { identifier, new ClassBinding(identifier, new PerlangClass("Foo", new List <Stmt.Function>())) }
            };

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

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

            // Assert
            Assert.Empty(typeValidationErrors);
            Assert.Empty(warnings);
        }
コード例 #3
0
        /// <summary>
        /// Parse an assignment
        /// </summary>
        /// <returns></returns>
        private Expr Assignment()
        {
            Expr expr = Or();

            if (Match(TokenType.EQUAL))
            {
                Token equals = Previous();
                Expr  value  = Assignment();

                // We have found a assignment target
                // Make sure its a variable
                if (expr is Expr.Variable)
                {
                    Token name = ((Expr.Variable)expr).Name;
                    return(new Expr.Assign(name, value));
                }
                else if (expr is Expr.Get)
                {
                    Expr.Get get = (Expr.Get)expr;
                    return(new Expr.Set(get.Object, get.Name, value));
                }

                Error(equals, "Invalid assignment target.");
            }

            return(expr);
        }
コード例 #4
0
    private Expr Assignment()
    {
        Expr expr = Or();

        if (Match(Equal))
        {
            Token equals = Previous();
            Expr  value  = Assignment();

            if (expr is Expr.Variable)
            {
                Token name = ((Expr.Variable)expr).Name;
                return(new Expr.Assign(name, value));
            }
            else if (expr is Expr.Get)
            {
                Expr.Get get = (Expr.Get)expr;
                return(new Expr.Set(get.Value, get.Name, value));
            }

            Error(equals, "Invalid assignment target.");
        }

        return(expr);
    }
コード例 #5
0
        private Expr Assignment()
        {
            Expr expr = Or();

            if (Match(EQUAL))  // We are assigning something
            {
                Token equals = Previous();
                Expr  value  = Assignment();
                /// Assigning to a 'normal' basic instance
                if (expr is Expr.Variable)
                {
                    Token name = ((Expr.Variable)expr).Name;
                    return(new Expr.Assign(name, value));
                }
                /// We are assigning something to a classinstance get...
                /// Which is impossoble, so it must be a set.
                else if (expr is Expr.Get)
                {
                    Expr.Get get = (Expr.Get)expr;
                    return(new Expr.Set(get.Object, get.Name, value));
                }

                Error(equals, "Invalid assignment target");
            }

            return(expr);
        }
コード例 #6
0
        /// <summary>
        /// Parse a function call
        /// </summary>
        /// <returns>The expression</returns>
        private Expr Call()
        {
            Expr expr = Primary();

            while (true)
            {
                if (Match(TokenType.LEFT_PAREN))
                {
                    // Function call
                    expr = FinishCall(expr);
                }
                else if (Match(TokenType.DOT))
                {
                    // Property
                    Token name = Consume(TokenType.IDENTIFIER, "Expect property name after '.'.");
                    expr = new Expr.Get(expr, name);
                }
                else
                {
                    break;
                }
            }

            return(expr);
        }
コード例 #7
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);
        }
コード例 #8
0
        public object VisitGetExpr(Expr.Get expr)
        {
            var obj = Evaluate(expr.obj);

            if (obj is LoxInstance li)
            {
                return(li.Get(expr.name));
            }

            throw new RuntimeException(expr.name, "Only instances have properties");
        }
コード例 #9
0
ファイル: Interpreter.cs プロジェクト: richsoft/CsLox
        public object Visit(Expr.Get expr)
        {
            object obj = Evaluate(expr.Object);

            if (obj is LoxInstance)
            {
                return(((LoxInstance)obj).Get(expr.Name));
            }

            throw new RuntimeErrorException(expr.Name, "Only instances has properties.");
        }
コード例 #10
0
        public object visitGetExpr(Expr.Get expr)
        {
            object object_ = evaluate(expr.object_);

            if (object_ is LoxInstance)
            {
                return(((LoxInstance)object_).get(expr.name));
            }

            throw new RuntimeError(expr.name, "Only instances have properties.");
        }
コード例 #11
0
        public object visitGetExpr(Expr.Get getExpr)
        {
            compile(getExpr.object_);

            captureToken(getExpr.name);

            byte name = identifierConstant(getExpr.name);

            emitBytes((byte)OpCode.OP_GET_PROPERTY, name);
            return(null);
        }
コード例 #12
0
ファイル: Interpreter.cs プロジェクト: jonnyboyC/cs-Lox
        public object VisitGetExpr(Expr.Get expr)
        {
            object instanceObj = Evalutate(expr.Instance);

            if (instanceObj is LoxInstance instance)
            {
                return(instance.Get(expr.Name));
            }

            throw new RuntimeError(expr.Name, "Only instances have properties.");
        }
コード例 #13
0
        public object VisitGetExpr(Expr.Get expr)
        {
            object obj = Evaluate(expr.Obj);

            if (obj is LoxInstance)
            {
                return(((LoxInstance)obj).Get(expr.Name));
            }

            throw new InterpretingException(expr.Name,
                                            "Only instances have properties.");
        }
コード例 #14
0
ファイル: Interpreter.cs プロジェクト: HereIsKevin/SharpLox
    public object VisitGetExpr(Expr.Get expr)
    {
        object value = Evaluate(expr.Value);

        if (value is LoxInstance)
        {
            return(((LoxInstance)value).Get(expr.Name));
        }

        throw new RuntimeException(expr.Name,
                                   "Only instances have properties.");
    }
コード例 #15
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);
        }
コード例 #16
0
        private Expr Call()
        {
            Expr expr = Primary();

            while (true)
            {
                if (Match(LEFT_PAREN))
                {
                    expr = FinishCall(expr);
                }
                else if (Match(DOT))
                {
                    Token name = Consume(IDENTIFIER, "Expect property name after '.'.");
                    expr = new Expr.Get(expr, name);
                }
                else
                {
                    break;
                }
            }
            return(expr);
        }
コード例 #17
0
    private Expr Call()
    {
        Expr expr = Primary();

        while (true)
        {
            if (Match(LeftParen))
            {
                expr = FinishCall(expr);
            }
            else if (Match(Dot))
            {
                Token name = Consume(Identifier, "Expect property after '.'.");
                expr = new Expr.Get(expr, name);
            }
            else
            {
                break;
            }
        }

        return(expr);
    }
コード例 #18
0
ファイル: AstPrinter.cs プロジェクト: jonnyboyC/cs-Lox
 public string VisitGetExpr(Expr.Get expr)
 {
     return($"{PrintExpr(expr.Instance)}.{expr.Name.Lexeme}");
 }
コード例 #19
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."
                                                ));
            }
        }
コード例 #20
0
ファイル: AstPrinter.cs プロジェクト: IBricchi/iglu_learning
 public string visitGetExpr(Expr.Get expr)
 {
     throw new NotImplementedException();
 }
コード例 #21
0
 public object VisitGetExpr(Expr.Get expr, object options = null)
 {
     return(null);
 }
コード例 #22
0
 public string VisitGetExpr(Expr.Get expr)
 {
     return(Parenthesize("get", expr.@object));
 }
コード例 #23
0
 public object visitGetExpr(Expr.Get expr)
 {
     resolve(expr.object_);
     return(null);
 }
コード例 #24
0
        public object VisitGetExpr(Expr.Get expr)
        {
            Resolve(expr.obj);

            return(null);
        }
コード例 #25
0
ファイル: NameResolver.cs プロジェクト: perlang-org/perlang
        public VoidObject VisitGetExpr(Expr.Get expr)
        {
            Resolve(expr.Object);

            return(VoidObject.Void);
        }
コード例 #26
0
 public Token visitGetExpr(Expr.Get get)
 {
     return(get.name);
 }
コード例 #27
0
ファイル: AstPrinter.cs プロジェクト: perlang-org/perlang
 public string VisitGetExpr(Expr.Get expr)
 {
     return(Parenthesize2(".", expr.Object, expr.Name.Lexeme));
 }
コード例 #28
0
 public object VisitGetExpr(Expr.Get expr, object options)
 {
     return(Parenthesize2(".", expr.obj, expr.token.lexeme));
 }
コード例 #29
0
 public Unit VisitGetExpr(Expr.Get expr)
 {
     Resolve(expr.Object);
     return(new Unit());
 }
コード例 #30
0
ファイル: Resolver.cs プロジェクト: richsoft/CsLox
 /// <summary>
 /// Resolve a property get
 /// </summary>
 /// <param name="expr">The expression</param>
 /// <returns></returns>
 public object Visit(Expr.Get expr)
 {
     Resolve(expr.Object);
     return(null);
 }