public void GenerateCode(StringNode node, ICIL_CodeGenerator codeGenerator)
        {
            #region .DATA

            var data = CIL_Factory.DefineData(node.Text);
            CIL_Factory.AddData(data);

            #endregion

            #region .CODE

            var str = codeGenerator.DefineVariable();

            codeGenerator.AddLocalVariable(
                new CIL_LocalVariable(str));

            codeGenerator.AddInstruction(new Load(str, data));

            //strObj
            node.Holder = codeGenerator.DefineVariable();

            codeGenerator.AddInstruction(
                new Allocate((Variable)node.Holder, $"{BuiltIn.String}"));

            codeGenerator.AddLocalVariable(
                new CIL_LocalVariable((Variable)node.Holder));


            codeGenerator.AddInstruction(
                new SetAttr((Variable)node.Holder,
                            $"{Attribute.String_value}",
                            str));
            #endregion
        }
        public void GenerateCode(ProgramNode node, ICIL_CodeGenerator codeGenerator = null)
        {
            foreach (var cls in new[] { BuiltIn.Object, BuiltIn.IO, BuiltIn.String, BuiltIn.Bool, BuiltIn.Int })
            {
                TypeTable.IsDefinedType($"{cls}", out var type);

                #region .TYPES

                CIL_Type cilType;
                IEnumerable <CIL_FunctionDeclaration> funtions;
                IEnumerable <CIL_Attribute>           attributes;

                //var instance = type.Self.Holder ??
                //               (type.Self.Holder = codeGenerator.DefineVariable());

                //codeGenerator.AddLocalVariable(
                //    new CIL_LocalVariable((Variable)type.Self.Holder));

                switch (cls)
                {
                case BuiltIn.Object:
                    funtions = ((CoolType)type).GetMethods
                               .Select(function => new CIL_FunctionDeclaration($"{function.ParentScope}_{function.Name}"));
                    cilType = CIL_Factory.DefineType($"{cls}", funtion: funtions);
                    break;

                case BuiltIn.IO:
                    funtions = ((CoolType)type).GetMethods
                               .Select(function => new CIL_FunctionDeclaration($"{function.ParentScope}_{function.Name}"));
                    cilType = CIL_Factory.DefineType($"{cls}", $"{BuiltIn.Object}", funtion: funtions);
                    break;

                case BuiltIn.String:
                    attributes = new[] { new CIL_Attribute($"{Attribute.String_value}") };

                    funtions = ((CoolType)type).GetMethods
                               .Select(function => new CIL_FunctionDeclaration($"{function.ParentScope}_{function.Name}"));
                    cilType = CIL_Factory.DefineType($"{cls}", $"{BuiltIn.Object}", attributes, funtions);
                    break;

                case BuiltIn.Int:
                case BuiltIn.Bool:
                    attributes = new[] { new CIL_Attribute($"{cls}_value") };
                    cilType    = CIL_Factory.DefineType($"{cls}", $"{BuiltIn.Object}", attributes);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                CIL_Factory.AddType(cilType);

                #endregion
            }

            #region BFS GenerateCode

            var queue = new Queue <string>();
            queue.Enqueue("Object");
            queue.Enqueue("IO");
            var classesList = new List <ClassNode>();

            while (queue.Count != 0)
            {
                classesList.AddRange(node.ClassesList
                                     .Where(classNode =>
                {
                    var boolean = classNode.TypeParent == queue.Peek();
                    if (boolean)
                    {
                        queue.Enqueue(classNode.TypeClass);
                    }
                    return(boolean);
                }));
                queue.Dequeue();
            }

            #endregion

            foreach (var cls in classesList)
            {
                TypeTable.IsDefinedType(cls.TypeClass, out var type);

                #region .Types

                var attributes = ((CoolType)type).GetAttributes
                                 .Select(attr => new CIL_Attribute($"{cls.TypeClass}_{attr.Name}"));

                var funtions = ((CoolType)type).GetMethods
                               .Select(funtion => new CIL_FunctionDeclaration($"{funtion.ParentScope}_{funtion.Name}"));

                var cilType = CIL_Factory.DefineType(cls.TypeClass, cls.TypeParent, attributes, funtions);

                CIL_Factory.AddType(cilType);

                #endregion
            }

            foreach (var cls in classesList)
            {
                GenerateCode(cls);
            }

            #region .CODE

            #region Object

            CIL_Factory.AddFunction(CIL_FunctionBuilder.Object_copy);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.Object_type_name);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.Object_abort);

            #endregion

            #region IO

            CIL_Factory.AddFunction(CIL_FunctionBuilder.IO_out_string);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.IO_out_int);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.IO_in_string);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.IO_in_int);

            #endregion

            #region String

            CIL_Factory.AddFunction(CIL_FunctionBuilder.String_concat);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.String_length);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.String_substring);

            #endregion

            #region Exceptions

            CIL_Factory.AddFunction(CIL_FunctionBuilder.ExecutionOfACaseStatementWithoutAMatchingBranchException);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.CaseOnVoidException);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.ArgumentOutOfRangeException);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.DispatchOnVoidException);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.DivideByZeroException);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.NegativeLengthException);
            CIL_Factory.AddFunction(CIL_FunctionBuilder.SubstringOutOfRangeException);

            #endregion

            #endregion
        }
        public void GenerateCode(ClassNode node, ICIL_CodeGenerator codeGenerator = null)
        {
            TypeTable.IsDefinedType(node.TypeClass, out var type);

            //Define init_function
            var initFunction = CIL_Factory.DefineFunction($"{node.TypeClass}_Init");

            // Define Variable ('instance')
            var instance = type.Self.Holder ??
                           (type.Self.Holder = initFunction.CodeGenerator.DefineVariable());

            if (node.TypeClass == "Main")
            {
                // Add Local Variable
                initFunction.CodeGenerator.AddLocalVariable(
                    new CIL_LocalVariable((Variable)instance));

                // Allocate Main
                initFunction.CodeGenerator.AddInstruction(
                    new Allocate((Variable)instance, node.TypeClass));
            }
            else
            {
                // Define argument
                //var argument = initFunction.CodeGenerator.DefineVariable();

                //add Local Variable
                initFunction.CodeGenerator.AddLocalVariable(
                    new CIL_LocalVariable((Variable)instance));

                initFunction.CodeGenerator.AddArgument(
                    new CIL_Argument((Variable)instance));
            }

            if (node.TypeParent != $"{BuiltIn.Object}" &&
                node.TypeParent != $"{BuiltIn.IO}")

            {
                // Set Param to invoke the Parent Init_function
                initFunction.CodeGenerator.AddInstruction(
                    new Param((Variable)instance));

                //Define the variable to hold the result call of the Parent's init_fuction of TypeClass
                var rVcall = initFunction.CodeGenerator.DefineVariable();

                // add Local Variable
                initFunction.CodeGenerator.AddLocalVariable(
                    new CIL_LocalVariable(rVcall));

                //Call the Parent's init_function
                initFunction.CodeGenerator.AddInstruction(
                    new Call(rVcall, $"{node.TypeParent}_Init"));
            }

            foreach (var feature in node.FeatureList.Features)
            {
                switch (feature)
                {
                case LocalOrFieldInit localOrFieldInit:

                    GenerateCode(localOrFieldInit, initFunction.CodeGenerator);

                    initFunction.CodeGenerator.AddInstruction(
                        new SetAttr((Variable)instance, $"{node.TypeClass}_{localOrFieldInit.Name}",
                                    localOrFieldInit.Symbol.Holder));

                    break;

                case MethodNode methodNode:

                    var function = CIL_Factory.DefineFunction($"{node.TypeClass}_{methodNode.FuncName}");

                    function.CodeGenerator
                    .AddLocalVariable(new CIL_LocalVariable((Variable)instance));

                    function.CodeGenerator.AddArgument(
                        new CIL_Argument((Variable)instance));

                    GenerateCode(methodNode, function.CodeGenerator);
                    CIL_Factory.AddFunction(function);

                    break;
                }
            }

            if (node.TypeClass == "Main")
            {
                var result = initFunction.CodeGenerator.DefineVariable();

                // add Local Variable
                initFunction.CodeGenerator.AddLocalVariable(
                    new CIL_LocalVariable(result));

                // set Param to invoke the main function
                initFunction.CodeGenerator.AddInstruction(
                    new Param((Variable)instance));

                //Control is transferred to Main_main
                initFunction.CodeGenerator.AddInstruction(
                    new Call(result, $"{node.TypeClass}_main"));
            }

            //Add the return instruction's
            initFunction.CodeGenerator.AddInstruction(
                new CIL_Return());

            //Add InitFunction with the initialized code
            CIL_Factory.AddFunction(initFunction);
        }