Example #1
0
        void Function_success_when_some_param_name_exist_in_shallow()
        {
            var name = new IdentifierToken("SendRequest", default);

            var scope = new SymbolScope();

            scope.AddSymbol(new VariableSymbol("length1", false, false, DataType.Double));

            var param1 = new FunctionParamAst(null, new IdentifierToken("length1", default),
                                              new OperatorToken(Operator.Colon, default), new IdentifierToken("int", default));
            var param2 = new FunctionParamAst(null, new IdentifierToken("length2", default),
                                              new OperatorToken(Operator.Colon, default), new IdentifierToken("int", default));
            var paramList = new FunctionParamListAst(new FunctionParamAst[] { param1, param2 });

            var bodyBlock = new Mock <BlockStatementAst>().Object;

            var ast = new FunctionAst(
                new KeywordToken(Keyword.Fn, default), name, new OperatorToken(Operator.LeftParen, default),
                paramList, new OperatorToken(Operator.RightParen, default),
                new OperatorToken(Operator.Arrow, default), returnType: new IdentifierToken("int", default),
                bodyBlock
                );

            var generator = ConfigureGenerator(scope, mock =>
            {
                mock.Setup(p => p.ProcessBlockStatement(bodyBlock, It.IsAny <bool>())).Returns(true);
            });

            generator.ProcessFunction(ast);
        }
Example #2
0
        public SymbolImplementation BuildMethod(SourceMethodDefinitionSymbol methodSymbol)
        {
            var methodBody  = methodSymbol.Syntax.Body;
            var symbolTable = (ISymbolTable)methodSymbol.Parent;

            _rootScope    = new SymbolScope(symbolTable);
            _currentScope = _rootScope;

            var symbolContext      = methodSymbol;
            var implementationNode = methodBody;

            var statements       = new List <BoundStatement>();
            var statementBuilder = new StatementBinder(this, symbolContext, _diagnostics);

            if (symbolContext.Parameters != null)
            {
                int parameterCount = symbolContext.Parameters.Length;
                for (int paramIndex = 0; paramIndex < parameterCount; paramIndex++)
                {
                    _currentScope.AddSymbol(symbolContext.Parameters[paramIndex]);
                }
            }

            foreach (var statementNode in implementationNode.Statements)
            {
                var statement = statementBuilder.BuildStatement(statementNode);
                if (statement != null)
                {
                    statements.Add(statement);
                }
            }

            return(new SymbolImplementation(statements.ToImmutableArray(), _rootScope));
        }
Example #3
0
        void ProcessCallExpression_returns_returnType_when_ok()
        {
            var scope = new SymbolScope();

            var name = new IdentifierToken("print", default);

            var funcSymbol = new FunctionSymbol(name.Value, DataType.Long,                            // return
                                                new DataType[] { DataType.Double, DataType.Double }); // need

            scope.AddSymbol(funcSymbol);

            var param1        = new Mock <ExpressionAst>().Object;
            var param2        = new Mock <ExpressionAst>().Object;
            var callParamList = new CallParamListAst(new[] { param1, param2 });

            var ast = new CallExpressionAst(
                name, new OperatorToken(Operator.LeftParen, default), callParamList,
                new OperatorToken(Operator.RightParen, default));

            var generator = ConfigureGenerator(scope, mock =>
            {
                mock.Setup(p => p.ProcessExpression(param1)).Returns(DataType.Double); // provide
                mock.Setup(p => p.ProcessExpression(param2)).Returns(DataType.Double); // provide
            });

            Assert.Equal(DataType.Long, generator.ProcessCallExpression(ast));
        }
Example #4
0
        void ProcessCallExpression_throw_when_param_number_not_match()
        {
            var scope = new SymbolScope();

            var name = new IdentifierToken("print", default);

            var funcSymbol = new FunctionSymbol(name.Value, DataType.Long, new DataType[] { DataType.Long });

            scope.AddSymbol(funcSymbol);

            var param1        = new Mock <ExpressionAst>().Object;
            var param2        = new Mock <ExpressionAst>().Object;
            var callParamList = new CallParamListAst(new[] { param1, param2 });

            var ast = new CallExpressionAst(
                name, new OperatorToken(Operator.LeftParen, default), callParamList,
                new OperatorToken(Operator.RightParen, default));

            var generator = ConfigureGenerator(scope, mock =>
            {
                mock.Setup(p => p.ProcessExpression(param1)).Returns(DataType.Long);
                mock.Setup(p => p.ProcessExpression(param2)).Returns(DataType.Long);
            });

            Assert.Throws <SemanticException>(() => generator.ProcessCallExpression(ast));
        }
Example #5
0
        void Function_success_and_write_self_and_params_to_symbol_table()
        {
            var name = new IdentifierToken("SendRequest", default);

            var scope = new SymbolScope();

            scope.AddSymbol(new VariableSymbol("lll3", false, false, DataType.Long));

            var param1 = new FunctionParamAst(null, new IdentifierToken("length1", default),
                                              new OperatorToken(Operator.Colon, default), new IdentifierToken("int", default));
            var paramList = new FunctionParamListAst(new FunctionParamAst[] { param1 });

            var functionBlock = new Mock <BlockStatementAst>().Object;

            var ast = new FunctionAst(
                new KeywordToken(Keyword.Fn, default), name, new OperatorToken(Operator.LeftParen, default),
                paramList, new OperatorToken(Operator.RightParen, default),
                new OperatorToken(Operator.Arrow, default), returnType: new IdentifierToken("int", default),
                functionBlock
                );

            var generator = ConfigureGenerator(scope, mock =>
            {
                mock.Setup(p => p.ProcessBlockStatement(functionBlock, It.IsAny <bool>())).Returns(false);
            });

            generator.ProcessFunction(ast);

            // Assert


            // self
            Assert.True(scope.FindSymbolShallow(ast.Name.Value, out Symbol symx));
            var funcSym = Assert.IsType <FunctionSymbol>(symx);

            Assert.Equal(DataType.Long, funcSym.ReturnType);
            Assert.Equal(DataType.Long, funcSym.ParamTypes.Single());

            // params
            Assert.True(scope.FindSymbolShallow(name.Value, out Symbol s0));
            scope = (s0 as FunctionSymbol).BodyBlockScope;

            Assert.True(scope.FindSymbolShallow(param1.Name.Value, out Symbol sym1));
            var var1 = Assert.IsType <VariableSymbol>(sym1);

            Assert.Equal(param1.IsConstant, var1.IsConstant);
            Assert.False(var1.IsGlobal);
            Assert.Equal(DataType.Long, var1.Type);
            Assert.Equal(param1.Name.Value, var1.Name);
        }
Example #6
0
        void ProcessIdentExpression_returns_type_when_constvar_ok()
        {
            var scope      = new SymbolScope();
            var funcSymbol = new VariableSymbol("aCounter", true, false, DataType.Long);

            scope.AddSymbol(funcSymbol);

            var name = new IdentifierToken("aCounter", default);

            var ast = new IdentExpressionAst(name);

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Equal(DataType.Long, generator.ProcessIdentExpression(ast));
        }
Example #7
0
        void ProcessIdentExpression_throws_when_symbol_not_var_or_const()
        {
            var scope      = new SymbolScope();
            var funcSymbol = new FunctionSymbol("aCounter", DataType.Void, new DataType[0]);

            scope.AddSymbol(funcSymbol);

            var name = new IdentifierToken("aCounter", default);

            var ast = new IdentExpressionAst(name);

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Throws <SemanticException>(() => generator.ProcessIdentExpression(ast));
        }
Example #8
0
        void ProcessLetDeclaration_throws_when_symbol_exist_in_shallow()
        {
            var existingSymbol = new VariableSymbol("webClient", false, false, DataType.Long);
            var scope          = new SymbolScope();

            scope.AddSymbol(existingSymbol);

            var name = new IdentifierToken("webClient", default);

            var ast = new LetDeclarationStatementAst(
                new KeywordToken(Keyword.Let, default), name, new OperatorToken(Operator.Colon, default),
                new IdentifierToken("int", default), new OperatorToken(Operator.Assign, default),
                initialExpression: null, new OperatorToken(Operator.Semicolon, default));

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Throws <SemanticException>(() => generator.ProcessLetDeclarationStatement(ast));
        }
Example #9
0
        void ProcessCallExpression_throws_when_symbol_is_not_function()
        {
            var scope = new SymbolScope();

            var name = new IdentifierToken("print", default);

            var varSymbol = new VariableSymbol(name.Value, true, false, DataType.Long);

            scope.AddSymbol(varSymbol);

            var ast = new CallExpressionAst(
                name, new OperatorToken(Operator.LeftParen, default), null,
                new OperatorToken(Operator.RightParen, default));

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Throws <SemanticException>(() => generator.ProcessCallExpression(ast));
        }
Example #10
0
        void ProcessAssignExpression_throws_when_symbol_is_function()
        {
            var scope = new SymbolScope();

            var name       = new IdentifierToken("today", default);
            var funcSymbol = new FunctionSymbol(name.Value, DataType.Long, new DataType[0]);

            scope.AddSymbol(funcSymbol);

            var ast = new AssignExpressionAst(
                name,
                new OperatorToken(Operator.Assign, default),
                new Mock <ExpressionAst>().Object);

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Throws <SemanticException>(() => generator.ProcessAssignExpression(ast));
        }
Example #11
0
        void ProcessCallExpression_throw_when_provide_no_param_to_call_function_need_param()
        {
            var scope = new SymbolScope();

            var name = new IdentifierToken("print", default);

            var funcSymbol = new FunctionSymbol(name.Value, DataType.Long, new DataType[] { DataType.Long });

            scope.AddSymbol(funcSymbol);

            var ast = new CallExpressionAst(
                name, new OperatorToken(Operator.LeftParen, default), null,
                new OperatorToken(Operator.RightParen, default));

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Throws <SemanticException>(() => generator.ProcessCallExpression(ast));
        }
Example #12
0
        void ProcessAssignExpression_throws_when_symbol_is_constant()
        {
            var scope = new SymbolScope();

            var name        = new IdentifierToken("today", default);
            var constSymbol = new VariableSymbol(name.Value, true, true, DataType.Double);

            scope.AddSymbol(constSymbol);

            var ast = new AssignExpressionAst(
                name,
                new OperatorToken(Operator.Assign, default),
                new Mock <ExpressionAst>().Object);

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Throws <SemanticException>(() => generator.ProcessAssignExpression(ast));
        }
Example #13
0
        void ProcessCallExpression_returns_returnType_when_0_0()
        {
            var scope = new SymbolScope();

            var name = new IdentifierToken("print", default);

            var funcSymbol = new FunctionSymbol(name.Value, DataType.Double, // return
                                                new DataType[] { });         // need

            scope.AddSymbol(funcSymbol);

            var ast = new CallExpressionAst(
                name, new OperatorToken(Operator.LeftParen, default), null,
                new OperatorToken(Operator.RightParen, default));

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Equal(DataType.Double, generator.ProcessCallExpression(ast));
        }
Example #14
0
        void Function_throws_when_function_name_exist_deep()
        {
            var name = new IdentifierToken("SendRequest", default);

            var scope = new SymbolScope();

            scope.AddSymbol(new VariableSymbol(name.Value, true, false, DataType.Long));


            var ast = new FunctionAst(
                new KeywordToken(Keyword.Fn, default), name, new OperatorToken(Operator.LeftParen, default),
                functionParamList: null, new OperatorToken(Operator.RightParen, default),
                new OperatorToken(Operator.Arrow, default), new IdentifierToken("int", default),
                new Mock <BlockStatementAst>().Object
                );

            var generator = ConfigureGenerator(scope, mock =>
            {
            });

            Assert.Throws <SemanticException>(() => generator.ProcessFunction(ast));
        }
Example #15
0
        void ProcessAssignExpression_throws_when_expr_type_not_match_variable_type()
        {
            var scope = new SymbolScope();

            var name        = new IdentifierToken("today", default);
            var constSymbol = new VariableSymbol(name.Value, true, isConstant: false, DataType.Double);

            scope.AddSymbol(constSymbol);

            var expr = new Mock <ExpressionAst>().Object;

            var ast = new AssignExpressionAst(
                name,
                new OperatorToken(Operator.Assign, default),
                expr);

            var generator = ConfigureGenerator(scope, mock =>
            {
                mock.Setup(p => p.ProcessExpression(expr)).Returns(DataType.Long);
            });

            Assert.Throws <SemanticException>(() => generator.ProcessAssignExpression(ast));
        }
Example #16
0
        void ProcessAssignExpression_returns_DataTypeVoid_when_ok()
        {
            var scope = new SymbolScope();

            var name        = new IdentifierToken("today", default);
            var constSymbol = new VariableSymbol(name.Value, true, isConstant: false, DataType.Double);

            scope.AddSymbol(constSymbol);

            var expr = new Mock <ExpressionAst>().Object;

            var ast = new AssignExpressionAst(
                name,
                new OperatorToken(Operator.Assign, default),
                expr);

            var generator = ConfigureGenerator(scope, mock =>
            {
                mock.Setup(p => p.ProcessExpression(expr)).Returns(DataType.Double);
            });

            Assert.Equal(DataType.Void, generator.ProcessAssignExpression(ast));
        }
Example #17
0
        private SymbolImplementation BuildImplementation(ISymbolTable symbolTable, CodeMemberSymbol symbolContext,
                                                         BlockStatementNode implementationNode, bool addAllParameters)
        {
            rootScope    = new SymbolScope(symbolTable);
            currentScope = rootScope;

            List <Statement> statements       = new List <Statement>();
            StatementBuilder statementBuilder = new StatementBuilder(this, symbolContext, errorHandler, options);

            if (symbolContext.Parameters != null)
            {
                int parameterCount = symbolContext.Parameters.Count;

                if (addAllParameters == false)
                {
                    // For property getters (including indexers), we don't add the last parameter,
                    // which happens to be the "value" parameter, which only makes sense
                    // for the setter.

                    parameterCount--;
                }

                for (int paramIndex = 0; paramIndex < parameterCount; paramIndex++)
                {
                    currentScope.AddSymbol(symbolContext.Parameters[paramIndex]);
                }
            }

            if (symbolContext.Type == SymbolType.Constructor &&
                (((ConstructorSymbol)symbolContext).Visibility & MemberVisibility.Static) == 0)
            {
                Debug.Assert(symbolContext.Parent is ClassSymbol);

                if (((ClassSymbol)symbolContext.Parent).BaseClass != null)
                {
                    BaseInitializerExpression baseExpr = new BaseInitializerExpression();

                    ConstructorDeclarationNode ctorNode = (ConstructorDeclarationNode)symbolContext.ParseContext;

                    if (ctorNode.BaseArguments != null)
                    {
                        ExpressionBuilder expressionBuilder =
                            new ExpressionBuilder(this, symbolContext, errorHandler, options);

                        Debug.Assert(ctorNode.BaseArguments is ExpressionListNode);
                        ICollection <Expression> args =
                            expressionBuilder.BuildExpressionList((ExpressionListNode)ctorNode.BaseArguments);

                        foreach (Expression paramExpr in args)
                        {
                            baseExpr.AddParameterValue(paramExpr);
                        }
                    }

                    statements.Add(new ExpressionStatement(baseExpr));
                }
            }

            foreach (StatementNode statementNode in implementationNode.Statements)
            {
                Statement statement = statementBuilder.BuildStatement(statementNode);

                if (statement != null)
                {
                    statements.Add(statement);
                }
            }

            string thisIdentifier = "this";

            if (symbolContext.Type == SymbolType.AnonymousMethod)
            {
                thisIdentifier = "$this";
            }

            return(new SymbolImplementation(statements, rootScope, thisIdentifier));
        }
Example #18
0
 void ILocalSymbolTable.AddSymbol(LocalSymbol symbol)
 {
     Debug.Assert(currentScope != null);
     currentScope.AddSymbol(symbol);
 }