/// <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 AssignmentNode node in the AST. /// </summary> /// <param name="assignmentNode">The node to check.</param> /// <returns>Returns null</returns> public override object Visit(AssignmentNode assignmentNode) { TypeContext lhs = (TypeContext)assignmentNode.LeftHand.Accept(this); TypeContext rhs; if (assignmentNode.RightHand.IsType(typeof(ArrayNode))) { ArrayNode arr = (ArrayNode)assignmentNode.RightHand; if (arr.HasBeenAccessed) { if (lhs.Type == VAR) { arr.SymbolType = lhs = rhs = (TypeContext)arr.FirstAccess.RightHand.Accept(this); assignmentNode.LeftHand.SymbolType = rhs; assignmentNode.LeftHand.Type = rhs.Type; } else { rhs = (TypeContext)arr.FirstAccess.RightHand.Accept(this); } } else { new InvalidTypeException($"Array type never set. Error at {arr.Line}:{arr.Offset}"); return(null); } } else { rhs = (TypeContext)assignmentNode.RightHand.Accept(this); } if (assignmentNode.RightHand.IsType(typeof(ArrayAccessNode))) { if (CurrentScope.FindArray((assignmentNode.LeftHand as ArrayAccessNode).Actual.ActualId.Id).Type == ARR) { ArrayAccessNode node = (assignmentNode.LeftHand as ArrayAccessNode); ArrayNode arr = CurrentScope.FindArray(node.Actual.ActualId.Id); if (!(arr.Dimensions.Count >= node.Accesses.Count)) { new OutOfRangeException($"Illegal access to {arr.Dimensions.Count} dimensional array. Error at {node.Line}:{node.Offset}"); return(null); } if (arr.Dimensions.Count > node.Accesses.Count && node.Accesses.Count > 1) { AssignmentNode declaringStatement = new AssignmentNode(node.Line, node.Offset); declaringStatement.LeftHand = new VarNode($"protected_declaration_{arr.ActualId.Id}_{node.Accesses.Count - 1}", new ScannerToken(node.Type, $"protected_declaration_{arr.ActualId.Id}_{node.Accesses.Count - 1}", node.Line, node.Offset)) { IsArray = true, SymbolType = new TypeContext(node.Type) }; ArrayNode declaringArray = new ArrayNode(node.Line, node.Offset); for (int i = 0; i < node.Accesses.Count; i++) { declaringArray.Dimensions.Add(arr.Dimensions[i]); } ((IScope)assignmentNode.Parent).Statements.Insert(((IScope)assignmentNode.Parent).Statements.IndexOf(assignmentNode), declaringStatement); } node.Actual.FirstAccess.LeftHand.SymbolType = rhs; node.Actual.FirstAccess.LeftHand.Type = rhs.Type; arr.SymbolType = rhs; arr.Type = rhs.Type; lhs = rhs; } } if (lhs.Type == VAR) { if (!CurrentScope.HasDeclaredVar(assignmentNode.LeftHand as AstNode)) { (assignmentNode.LeftHand as VarNode).Declaration = true; CurrentScope.DeclaredVars.Add((assignmentNode.LeftHand as VarNode).Id); } if (assignmentNode.LeftHand.IsType(typeof(VarNode))) { if (CurrentScope.FindSymbol(assignmentNode.LeftHand as VarNode).Type == VAR) { CurrentScope.UpdateTypedef(assignmentNode.LeftHand as VarNode, rhs, CurrentScope.Name, true); } lhs = CurrentScope.FindSymbol(assignmentNode.LeftHand as VarNode); } else if (assignmentNode.LeftHand.IsType(typeof(ArrayAccessNode))) { } } if (lhs.Type != rhs.Type) { if ((lhs.Type != DPIN && lhs.Type != APIN) || (rhs.Type != NUMERIC && rhs.Type != BOOL)) { new InvalidTypeException($"Type {rhs.Type} is not assignable toType {lhs.Type} at {assignmentNode.Line}:{assignmentNode.Offset}"); } } return(null); }