public void Visit(LetNode node)
        {
            var scopeLet = scope.CreateChild();

            foreach (var expInit in node.Initialization)
            {
                expInit.AssignExp.Accept(new SecondSemanticVisit(scopeLet, errors));
                var typeAssignExp = expInit.AssignExp.StaticType;

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

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

                if (scopeLet.IsDefined(expInit.Formal.Id.Text, out TypeInfo typeOld))
                {
                    scopeLet.UpdateType(expInit.Formal.Id.Text, typeDeclared);
                }
                else
                {
                    scopeLet.Define(expInit.Formal.Id.Text, typeDeclared);
                }
            }

            node.ExpressionBody.Accept(new SecondSemanticVisit(scopeLet, errors));
            node.StaticType = node.ExpressionBody.StaticType;
        }
        public void Visit(DispatchExplicitNode node)
        {
            node.Expression.Accept(this);
            if (node.IdType.Text == "Object")
            {
                node.IdType = new TypeNode(node.Expression.Line, node.Expression.Column, node.Expression.StaticType.Text);
            }

            if (!scope.IsDefinedType(node.IdType.Text, out TypeInfo typeSuperClass))
            {
                errors.Add(SemanticError.NotDeclaredType(node.IdType));
            }

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

            node.Arguments.ForEach(x => x.Accept(this));

            var scopeSuperClass = typeSuperClass.ClassReference.Scope;

            if (!(scopeSuperClass.IsDefined(node.IdMethod.Text, node.Arguments.Select(x => x.StaticType).ToArray(), out node.StaticType)))
            {
                errors.Add(SemanticError.NotDeclareFunction(node, node.IdMethod.Text));
            }
        }
        public void Visit(MethodNode node)
        {
            var scopeMethod = scope.CreateChild();

            foreach (var arg in node.Arguments)
            {
                if (!scope.IsDefinedType(arg.Type.Text, out TypeInfo typeArg))
                {
                    errors.Add(SemanticError.NotDeclaredType(arg.Type));
                }
                scopeMethod.Define(arg.Id.Text, typeArg);
            }

            if (!scope.IsDefinedType(node.TypeReturn.Text, out TypeInfo typeReturn))
            {
                errors.Add(SemanticError.NotDeclaredType(node.TypeReturn));
            }

            scope.Define(node.Id.Text, node.Arguments.Select(x => scope.GetType(x.Type.Text)).ToArray(), typeReturn);

            node.Body.Accept(new SecondSemanticVisit(scopeMethod, errors));

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

            node.TypeReturn = new TypeNode(node.Body.Line, node.Body.Column, typeReturn.Text);
        }
        public void Visit(IfNode node)
        {
            node.Condition.Accept(this);
            node.Body.Accept(this);
            node.ElseBody.Accept(this);

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

            node.StaticType = SemanticAlgorithm.LowerCommonAncestor(node.Body.StaticType, node.ElseBody.StaticType);
        }
        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(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);
        }