public void Visit(ComparisonOperation node)
        {
            node.LeftOperand.Accept(this);
            node.RightOperand.Accept(this);

            if (node.LeftOperand.StaticType.Text != "Int" || node.RightOperand.StaticType.Text != "Int")
            {
                errors.Add(SemanticError.InvalidUseOfOperator(node, node.LeftOperand.StaticType, node.RightOperand.StaticType));
            }

            if (!scope.IsDefinedType("Bool", out node.StaticType))
            {
                errors.Add(SemanticError.NotDeclaredType(new TypeNode(node.Line, node.Column, "Bool")));
            }
        }
        public void Visit(WhileNode node)
        {
            node.Condition.Accept(this);
            node.Body.Accept(this);

            if (node.Condition.StaticType.Text != "Bool")
            {
                errors.Add(SemanticError.CannotConvert(node.Condition, node.Condition.StaticType, scope.GetType("Bool")));
            }

            if (!scope.IsDefinedType("Object", out node.StaticType))
            {
                errors.Add(SemanticError.NotDeclaredType(new TypeNode(node.Line, node.Column, "Object")));
            }
        }
        public void Visit(AssignmentNode node)
        {
            node.ExpressionRight.Accept(this);

            if (!scope.IsDefined(node.ID.Text, out TypeInfo type))
            {
                errors.Add(SemanticError.NotDeclaredVariable(node.ID));
            }

            if (!(node.ExpressionRight.StaticType <= type))
            {
                errors.Add(SemanticError.CannotConvert(node, node.ExpressionRight.StaticType, type));
            }

            node.StaticType = node.ExpressionRight.StaticType;
        }
        public void Visit(EqualNode node)
        {
            node.LeftOperand.Accept(this);
            node.RightOperand.Accept(this);

            if (node.LeftOperand.StaticType.Text != node.RightOperand.StaticType.Text || !(new string[3] {
                "Bool", "Int", "String"
            }.Contains(node.LeftOperand.StaticType.Text)))
            {
                errors.Add(SemanticError.InvalidUseOfOperator(node, node.LeftOperand.StaticType, node.RightOperand.StaticType));
            }

            if (!scope.IsDefinedType("Bool", out node.StaticType))
            {
                errors.Add(SemanticError.NotDeclaredType(new TypeNode(node.Line, node.Column, "Bool")));
            }
        }
        public void Visit(AttributeNode node)
        {
            node.AssignExp.Accept(this);
            var typeAssignExp = node.AssignExp.StaticType;

            if (!scope.IsDefinedType(node.Formal.Type.Text, out TypeInfo typeDeclared))
            {
                errors.Add(SemanticError.NotDeclaredType(node.Formal.Type));
            }

            if (!(typeAssignExp <= typeDeclared))
            {
                errors.Add(SemanticError.CannotConvert(node.Formal.Type, typeAssignExp, typeDeclared));
            }

            scope.Define(node.Formal.Id.Text, typeDeclared);
        }
        public void Visit(CaseNode node)
        {
            node.ExpressionCase.Accept(this);

            int branchSelected = -1;
            var typeExp0       = node.ExpressionCase.StaticType;
            var typeExpK       = scope.GetType(node.Branches[0].Formal.Type.Text);

            for (int i = 0; i < node.Branches.Count; ++i)
            {
                if (!scope.IsDefinedType(node.Branches[i].Formal.Type.Text, out TypeInfo type))
                {
                    errors.Add(SemanticError.NotDeclaredType(node.Branches[i].Formal.Type));
                }

                var typeK = scope.GetType(node.Branches[i].Formal.Type.Text);

                var scopeBranch = scope.CreateChild();
                scopeBranch.Define(node.Branches[i].Formal.Id.Text, typeK);

                node.Branches[i].Expression.Accept(new SecondSemanticVisit(scopeBranch, errors));

                typeExpK = node.Branches[i].Expression.StaticType;

                if (branchSelected == -1 && typeExp0 <= typeK)
                {
                    branchSelected = i;
                }

                if (i == 0)
                {
                    node.StaticType = node.Branches[0].Expression.StaticType;
                }
                node.StaticType = SemanticAlgorithm.LowerCommonAncestor(node.StaticType, typeExpK);
            }
            node.BranchSelected = branchSelected;

            if (node.BranchSelected == -1)
            {
                errors.Add(SemanticError.NotMatchedBranch(node));
            }
        }
        public void Visit(ArithmeticOperationNode node)
        {
            node.LeftOperand.Accept(this);
            node.RightOperand.Accept(this);

            if (node.LeftOperand.StaticType.Text != node.RightOperand.StaticType.Text)
            {
                errors.Add(SemanticError.InvalidUseOfOperator(node, node.LeftOperand.StaticType, node.RightOperand.StaticType));
            }

            else if (node.LeftOperand.StaticType.Text != "Int" || node.RightOperand.StaticType.Text != "Int")
            {
                errors.Add(SemanticError.InvalidUseOfOperator(node));
            }

            else if (!scope.IsDefinedType("Int", out node.StaticType))
            {
                errors.Add(SemanticError.NotDeclaredType(new TypeNode(node.Line, node.Column, "Int")));
            }
        }
        public void Visit(MethodNode node)
        {
            if (!scope.IsDefinedType(node.TypeReturn.Text, out TypeInfo typeReturn))
            {
                errors.Add(SemanticError.NotDeclaredType(node.TypeReturn));
            }

            node.TypeReturn = new TypeNode(node.TypeReturn.Line, node.TypeReturn.Column, typeReturn.Text);

            TypeInfo[] typeArgs = new TypeInfo[node.Arguments.Count];
            for (int i = 0; i < node.Arguments.Count; ++i)
            {
                if (!scope.IsDefinedType(node.Arguments[i].Type.Text, out typeArgs[i]))
                {
                    errors.Add(SemanticError.NotDeclaredType(node.Arguments[i].Type));
                }
            }

            scope.Define(node.Id.Text, typeArgs, typeReturn);
        }
        public void Visit(ProgramNode node)
        {
            if (!SemanticAlgorithm.TopologicalSort(node.Classes, errors))
            {
                return;
            }

            node.Classes.ForEach(cclass => scope.AddType(cclass.TypeClass.Text, new TypeInfo(cclass.TypeClass.Text, scope.GetType(cclass.TypeInherit.Text), cclass)));

            int idMain = -1;

            for (int i = 0; i < node.Classes.Count; ++i)
            {
                if (node.Classes[i].TypeClass.Text == "Main")
                {
                    idMain = i;
                }
            }

            if (idMain == -1)
            {
                errors.Add(SemanticError.NotFoundClassMain());
                return;
            }

            bool mainOK = false;

            foreach (var item in node.Classes[idMain].FeatureNodes)
            {
                if (item is MethodNode)
                {
                    var method = item as MethodNode;
                    if (method.Id.Text == "main" && method.Arguments.Count == 0)
                    {
                        mainOK = true;
                    }
                }
            }

            if (!mainOK)
            {
                errors.Add(SemanticError.NotFoundMethodmain(node.Classes[idMain]));
            }

            foreach (var cclass in node.Classes)
            {
                if (!scope.IsDefinedType(cclass.TypeInherit.Text, out TypeInfo type))
                {
                    errors.Add(SemanticError.NotDeclaredType(cclass.TypeInherit));
                    return;
                }
                if (new List <string> {
                    "Bool", "Int", "String"
                }.Contains(type.Text))
                {
                    errors.Add(SemanticError.NotInheritsOf(cclass, type));
                    return;
                }
                cclass.Accept(this);
            }
        }