private void Generate(AbstractNode node)
        {
            var debugNodeTypes = new NodeType[]
            {
                /*NodeType.Block,
                 * NodeType.Literal,
                 * NodeType.Identifier,
                 * NodeType.Loop,
                 * NodeType.Operation,*/
            };

            if (debugNodeTypes.Contains(node.Type))
            {
                Debug(node.ToString());
            }
            switch (node.Type)
            {
            case NodeType.Block:
                ((BlockNode)node).Statements.ForEach(Generate);
                break;

            case NodeType.Operation:
                var operation = (OperationNode)node;

                // Operations that require two integer as input
                var integerOperations = new[]
                {
                    OperatorType.BitwiseAnd,
                    OperatorType.AndAlso,
                    OperatorType.BitwiseOr,
                    OperatorType.OrElse
                };

                var outputIntegerOperations = new[]
                {
                    OperatorType.Equals,
                    OperatorType.Greater,
                    OperatorType.NotGreater,
                    OperatorType.Less,
                    OperatorType.NotLess,
                    OperatorType.NotEquals
                };

                /*
                 *  We accept floating only, sometimes we need integer (logical and/or)
                 *  In this case, we cast the floating into an integer and cast back the result into a floating one.
                 */
                var requireInteger         = integerOperations.Contains(operation.Operator);
                var requireOutputTransform = outputIntegerOperations.Contains(operation.Operator);

                Generate(operation.LeftOperand);
                if (requireInteger)
                {
                    Write("ftoi");
                }

                Generate(operation.RightOperand);
                if (requireInteger)
                {
                    Write("ftoi");
                }

                switch (operation.Operator)
                {
                case OperatorType.Add:
                    Write("add.f");
                    break;

                case OperatorType.Sub:
                    Write("sub.f");
                    break;

                case OperatorType.Mul:
                    Write("mul.f");
                    break;

                case OperatorType.Div:
                    Write("div.f");
                    break;

                case OperatorType.BitwiseAnd:
                case OperatorType.AndAlso:
                    Write("and");
                    break;

                case OperatorType.BitwiseOr:
                case OperatorType.OrElse:
                    Write("or");
                    break;

                case OperatorType.Equals:
                    Write("cmpeq.f");
                    break;

                case OperatorType.NotEquals:
                    Write("cmpne.f");
                    break;

                case OperatorType.NotGreater:
                    Write("cmple.f");
                    break;

                case OperatorType.Less:
                    Write("cmplt.f");
                    break;

                case OperatorType.NotLess:
                    Write("cmpge.f");
                    break;

                case OperatorType.Greater:
                    Write("cmpgt.f");
                    break;

                case OperatorType.EuclidianDiv:
                    Write(Drop());
                    Write(Drop());
                    Generate(BuiltinFunctions.EuclidianDiv(operation.LeftOperand, operation.RightOperand));
                    break;

                case OperatorType.Mod:
                    Write(Drop());
                    Write(Drop());
                    Generate(BuiltinFunctions.Mod(operation.LeftOperand, operation.RightOperand));
                    break;

                case OperatorType.Pow:
                    Write(Drop());
                    Write(Drop());
                    Generate(BuiltinFunctions.Pow(operation.LeftOperand, operation.RightOperand));
                    break;
                }
                if (requireInteger || requireOutputTransform)
                {
                    Write("itof");
                }
                break;

            case NodeType.Declaration:
                var dcl = (AddressableDeclarationNode)node;
                switch (dcl.Identifier.Symbol.Type)
                {
                case ObjectType.Floating:
                    Generate(dcl.Expression);
                    Write
                    (
                        Set(dcl.Identifier.Symbol.Pointer)
                    );
                    break;

                case ObjectType.Pointer:
                    var indexExpressions = ((MultiExpressionNode)dcl.Expression).Expressions;
                    indexExpressions.Reverse();
                    AbstractExpressionNode finalExpression = LiteralNode.One;
                    for (var i = 0; i < indexExpressions.Count - 1; i++)
                    {
                        finalExpression = new OperationNode
                                          (
                            OperatorType.Mul,
                            new OperationNode
                            (
                                OperatorType.Add,
                                LiteralNode.One,
                                indexExpressions[i]
                            ),
                            finalExpression
                                          );
                    }
                    finalExpression = new OperationNode
                                      (
                        OperatorType.Mul,
                        indexExpressions.Last(),
                        finalExpression
                                      );
                    Generate(BuiltinFunctions.BorrowMemory(finalExpression));
                    Write(Set(dcl.Identifier.Symbol.Pointer));
                    var tempVar = new AddressableIdentifierNode(new PrimitiveVariableSymbol("", PointerIndex + 1));
                    Write(Pushf());
                    Generate(BuiltinFunctions.BorrowMemory(new LiteralNode(indexExpressions.Count)));
                    Write(Set(tempVar.Symbol.Pointer));
                    indexExpressions.Reverse();
                    for (var i = 0; i < indexExpressions.Count; i++)
                    {
                        Generate
                        (
                            new PointerAssignationNode
                            (
                                new OperationNode
                                (
                                    OperatorType.Add,
                                    tempVar,
                                    new LiteralNode(i)
                                ),
                                indexExpressions[i]
                            )
                        );
                    }

                    /*
                     *      var a = bmem(6);
                     *      var b = bmem(2);
                     *      :b = 2;
                     *      :b + 1 = 2;
                     *      init_array(a, b, 2);
                     */
                    Generate(BuiltinFunctions.InitArray(dcl.Identifier, tempVar, new LiteralNode(indexExpressions.Count)));
                    Write(Get(tempVar.Symbol.Pointer));
                    Generate(BuiltinFunctions.RecoverMemory(tempVar));
                    break;
                }
                break;

            case NodeType.Reference:
                var refnode = (ReferenceNode)node;
                Write
                (
                    Pushf(refnode.Identifier.Symbol.Pointer)
                );
                break;

            case NodeType.Dereference:
                var deref = (DereferenceNode)node;
                Generate(deref.Expression);
                Writes
                (
                    Ftoi(),
                    MemRead(),
                    Itof()
                );
                break;

            case NodeType.Assignation:
                var assign = (AssignationNode)node;
                Generate(assign.ValueExpression);
                Write
                (
                    Set(assign.Identifier.Symbol.Pointer)
                );
                break;

            case NodeType.Drop:
                Write(Drop());
                break;

            case NodeType.PointerAssignation:
                var ptrAssign = (PointerAssignationNode)node;
                Generate(ptrAssign.AddressExpression);
                Write
                (
                    Ftoi()
                );
                Generate(ptrAssign.ValueExpression);
                Writes
                (
                    Ftoi(),
                    MemWrite()
                );
                break;

            case NodeType.Literal:
                var lit = (LiteralNode)node;
                Write(Pushf(lit.Value));
                break;

            case NodeType.Identifier:
                var ident = (AddressableIdentifierNode)node;
                Write
                (
                    Get(ident.Symbol.Pointer)
                );
                break;

            case NodeType.Crash:
                Write("halt");
                break;

            case NodeType.Print:
                if (node is PrintExpressionNode)
                {
                    var printe = (PrintExpressionNode)node;
                    Generate(printe.Expression);
                    Write("out.f");
                }
                else
                {
                    var prints = (PrintStringNode)node;
                    foreach (var c in prints.Content)
                    {
                        Write($"push.i {(int)c}");
                        Write("out.c");
                    }
                }
                Write("push.i 10");
                Write("out.c");
                break;

            case NodeType.Loop:
                var loop = (LoopNode)node;
                {
                    Write(DeclareLabel(BeginLoop(loop.UniqueId)));
                    Generate(loop.Conditional);
                    Write(DeclareLabel(IterationLoop(loop.UniqueId)));
                    Generate(loop.Iteration);
                    Write(Jump(BeginLoop(loop.UniqueId)));
                    Write(DeclareLabel(EndLoop(loop.UniqueId)));
                }
                break;

            case NodeType.Break:
                var breakNode = (BreakNode)node;
                Write(Jump(EndLoop(breakNode.LoopId)));
                break;

            case NodeType.Continue:
                var cont = (ContinueNode)node;
                Write(Jump(EndIf(cont.CondId)));
                break;

            case NodeType.Conditional:
                var cond = (ConditionalNode)node;
                {
                    Generate(cond.Expression);
                    Write(JumpFalse(Else(cond.UniqueId)));
                    Generate(cond.TrueStatement);
                    Write(Jump(EndIf(cond.UniqueId)));
                    Write(DeclareLabel(Else(cond.UniqueId)));
                    Generate(cond.FalseStatement);
                    Write(DeclareLabel(EndIf(cond.UniqueId)));
                }
                break;

            case NodeType.MultiExpression:
                var multi = (MultiExpressionNode)node;
                foreach (var expression in multi.Expressions)
                {
                    Generate(expression);
                }
                break;

            case NodeType.Function:
                var fun = (FunctionNode)node;
                Write(DeclareLabel(fun.Identifier.Symbol.Name));
                PointerIndex = fun.Arguments.Count - 1;
                PreGenerate(fun.Statement);
                Generate(fun.Statement);
                if (fun.Identifier.Symbol.Name != "start")
                {
                    Write(Pushf());
                    Write(Ret());
                }
                else
                {
                    Write(Halt());
                }
                break;

            case NodeType.Return:
                var ret = (ReturnNode)node;
                Generate(ret.Expression);
                Write(Ret());
                break;

            case NodeType.Call:
                var call = (CallNode)node;
                Write(Prep(call.Target.Symbol.Name));
                foreach (var arg in call.Parameters)
                {
                    Generate(arg);
                }
                Write(Call(call.Parameters.Count));
                break;

            case NodeType.Root:
                var root = (RootNode)node;
                foreach (var f in root.Functions)
                {
                    Generate(f);
                }
                break;
            }
        }
 public override AbstractStatementNode ReleaseInstruction()
 {
     return(BuiltinFunctions.RecoverMemory(new AddressableIdentifierNode(this)));
 }