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); }
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)); }
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)); }
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)); }
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); }
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)); }
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)); }
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)); }
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)); }
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)); }
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)); }
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)); }
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)); }
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)); }
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)); }
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)); }
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)); }
void ILocalSymbolTable.AddSymbol(LocalSymbol symbol) { Debug.Assert(currentScope != null); currentScope.AddSymbol(symbol); }