/// <summary> /// This method type checks the ElseStatementNode node in the AST. /// </summary> /// <param name="elseStatement">The node to check.</param> /// <returns>Returns null</returns> public override object Visit(ElseStatementNode elseStatement) { CurrentScope = GlobalScope.FindChild($"ELSESTMNT_{elseStatement.Line}"); elseStatement.Statements.ForEach(stmnt => stmnt.Accept(this)); CurrentScope = CurrentScope?.Parent ?? GlobalScope; return(null); }
/// <summary> /// This method type checks the FuncNode node in the AST. /// </summary> /// <param name="funcNode">The node to check.</param> /// <returns>Returns null</returns> public override object Visit(FuncNode funcNode) { CurrentScope = GlobalScope.FindChild($"func_{funcNode.Name.Id}_{funcNode.Line}"); funcNode.Statements.ForEach(stmnt => { if (stmnt is CallNode) { if (((CallNode)stmnt).Id.Id == funcNode.Name.Id) { new InvalidOperationException($"Illegal recursion at {stmnt.Line}:{stmnt.Offset}"); } } stmnt.Accept(this); }); if (funcNode.Statements.Any() && funcNode.Statements.Last().Type == TokenType.RETURN) { { funcNode.SymbolType = (TypeContext)funcNode.Statements.Last().Accept(this); CurrentScope = CurrentScope.Parent ?? GlobalScope; return(funcNode.SymbolType); } } CurrentScope = CurrentScope.Parent ?? GlobalScope; return(null); }
/// <summary> /// This method type checks the ForNode node in the AST. /// </summary> /// <param name="forNode">The node to check.</param> /// <returns>Returns null</returns> public override object Visit(ForNode forNode) { CurrentScope = GlobalScope.FindChild($"LOOPF_{forNode.Line}"); TypeContext fromType = (TypeContext)forNode.From.Accept(this); TypeContext toType = (TypeContext)forNode.To.Accept(this); if (null == CurrentScope.FindSymbol(forNode.CountingVariable)) { CurrentScope.Symbols.Add(new Symbol(forNode.CountingVariable.Id, NUMERIC, false, forNode.CountingVariable)); } else { CurrentScope.UpdateTypedef(forNode.CountingVariable, new TypeContext(TokenType.NUMERIC) { IsFloat = false }, CurrentScope.Name, true); } if (fromType.Type != toType.Type) { new InvalidTypeException($"Mismatch in range types at {forNode.Line}:{forNode.Offset}"); } forNode.Statements.ForEach(stmnt => stmnt.Accept(this)); CurrentScope = CurrentScope.Parent ?? GlobalScope; return(null); }
/// <summary> /// This method type checks the ElseIfStatementNode node in the AST. /// </summary> /// <param name="elseifStatementNode">The node to check.</param> /// <returns>Returns null</returns> public override object Visit(ElseifStatementNode elseifStatementNode) { CurrentScope = GlobalScope.FindChild($"{elseifStatementNode.Type}_{elseifStatementNode.Line}"); if (((TypeContext)elseifStatementNode.Expression.Accept(this)).Type == BOOL) { elseifStatementNode.Statements.ForEach(stmnt => stmnt.Accept(this)); } else { new InvalidTypeException($"Else if statement expected a boolean expression at {elseifStatementNode.Line}:{elseifStatementNode.Offset}"); } CurrentScope = CurrentScope.Parent ?? GlobalScope; return(null); }
/// <summary> /// This method type checks the CallNode node in the AST. /// </summary> /// <param name="callNode">The node to check.</param> /// <returns>Type context of the function called</returns> public override object Visit(CallNode callNode) { try { if (SymbolTableObject.FunctionDefinitions.Any(func => func.Name.Id == callNode.Id.Id && func.FunctionParameters.Count == callNode.Parameters.Count)) { FuncNode n = SymbolTableObject.FunctionDefinitions.First(node => node.Name.Id == callNode.Id.Id && node.FunctionParameters.Count == callNode.Parameters.Count); TypeContext ctx; if (n.Statements.Any()) { if (n.Statements.Last().IsType(typeof(ReturnNode))) { _temp = CurrentScope; CurrentScope = GlobalScope.FindChild($"func_{n.Name.Id}_{n.Line}"); ctx = (TypeContext)n.Statements.Last().Accept(this); CurrentScope = _temp; } else { ctx = new TypeContext(TokenType.FUNC); } } else { ctx = new TypeContext(TokenType.FUNC); } return(ctx); } else if (SymbolTableObject.PredefinedFunctions.Any(func => func.Name.Id == callNode.Id.Id && func.FunctionParameters.Count == callNode.Parameters.Count)) { TypeContext ctx = SymbolTableObject.PredefinedFunctions.First(node => node.Name.Id == callNode.Id.Id && node.FunctionParameters.Count == callNode.Parameters.Count).SymbolType; return(ctx); } else { new NotDefinedException($"A function '{callNode.Id.Id}' with {callNode.Parameters.Count} parameters has not been defined. Error at {callNode.Line}:{callNode.Offset} "); return(null); } } catch { new NotDefinedException($"Undefined function call at {callNode.Line}:{callNode.Offset}"); return(null); } }
/// <summary> /// This method type checks the ProgramNode node in the AST. /// This is the entry point for the type checker /// </summary> /// <param name="programNode">The node to check.</param> /// <returns>Returns null</returns> public override object Visit(ProgramNode programNode) { programNode.Statements.ForEach(stmnt => stmnt.Accept(this)); programNode.FunctionDefinitons.ForEach(func => { if (!(SymbolTableObject.FunctionDefinitions.Where(fn => fn.Name.Id == func.Name.Id && func.FunctionParameters.Count == fn.FunctionParameters.Count).Count() > 1)) { if (SymbolTableObject.FunctionCalls.Any(cn => cn.Id.Id == func.Name.Id && cn.Parameters.Count == func.FunctionParameters.Count)) { CallNode cn = SymbolTableObject.FunctionCalls.First(cn => cn.Id.Id == func.Name.Id && cn.Parameters.Count == func.FunctionParameters.Count); FuncNode declaredFunc = SymbolTableObject.FunctionDefinitions.First(fn => fn.Name.Id == func.Name.Id); SymbolTableObject scope = GlobalScope.FindChild($"func_{declaredFunc.Name.Id}_{declaredFunc.Line}"); for (int i = 0; i < cn.Parameters.Count; i++) { if (cn.Parameters[i].SymbolType.Type == VAR) { continue; } scope.UpdateTypedef(declaredFunc.FunctionParameters[i], cn.Parameters[i].SymbolType, scope.Name, true); } } func.Accept(this); } else { new MultipleDefinedException($"A function '{func.Name.Id}' with {func.FunctionParameters.Count} parameters has already been defined. Error at {func.Line}:{func.Offset}"); } }); if (programNode.LoopFunction == null) { new NotDefinedException("Loop function was not defined."); return(null); } programNode.LoopFunction.Accept(this); return(null); }