public static void EmitIf(IfStatement ifst, List<ILInstuction> il)
        {
            ILDummy end = new ILDummy();
            end.Line = GetLabel();
            foreach (var ic in ifst.Clauses)
            {
                ILBranch branch = new ILBranch();
                ILDummy blockBegin = new ILDummy();
                ILDummy blockEnd = new ILDummy();
                branch.Line = GetLabel();
                blockBegin.Line = GetLabel();
                blockEnd.Line = GetLabel();

                ILGoto gotoEnd = new ILGoto(end.Line);
                gotoEnd.Line = GetLabel();
                branch.SuccessJump = blockBegin.Line;
                branch.FailJump = blockEnd.Line;
                branch.Condition = ConstructILExpression(ic.Condition);
                il.Add(branch);
                il.Add(blockBegin);
                EmitStatementList(ic.Statements, il);
                il.Add(gotoEnd);
                il.Add(blockEnd);
            }
            if (ifst.AlternativeStatements != null)
            {
                EmitStatementList(ifst.AlternativeStatements, il);
            }
            il.Add(end);
        }
        public static void _EmitWhileDo(WhileDoStatement wd, List<ILInstuction> il)
        {
            var begin = new ILDummy();
            begin.Line = GetLabel();
            il.Add(begin);
            var condtitionVariable = _EmitExpression(wd.Condition, il);

            CurrentFunction.AddLocal(condtitionVariable, wd.Condition.ResultType);

            var conditionIl = new ILBranch();
            conditionIl.Condition = _constructVariableAccess(condtitionVariable);
            il.Add(conditionIl);

            var bodyBegin = new ILDummy();
            bodyBegin.Line = GetLabel();
            var bodyEnd = new ILDummy();
            bodyEnd.Line = GetLabel();

            il.Add(bodyBegin);
            _EmitStatementList(wd.Statements, il);
            var gotoBeginIl = new ILGoto(begin.Line);
            il.Add(gotoBeginIl);
            il.Add(bodyEnd);

            conditionIl.FailJump = bodyEnd.Line;
            conditionIl.SuccessJump = bodyBegin.Line;;
        }
        public static void _EmitIf(IfStatement ifst,  List<ILInstuction> il)
        {
            ILDummy end = new ILDummy();
            end.Line = GetLabel();
            foreach (var ic in ifst.Clauses)
            {
                ILBranch branch = new ILBranch();
                ILDummy blockBegin = new ILDummy();
                ILDummy blockEnd = new ILDummy();
                branch.Line = GetLabel();
                blockBegin.Line = GetLabel();
                blockEnd.Line = GetLabel();

                ILGoto gotoEnd = new ILGoto(end.Line);
                gotoEnd.Line = GetLabel();
                branch.SuccessJump = blockBegin.Line;
                branch.FailJump = blockEnd.Line;

                var ifConditionVariable = _EmitExpression(ic.Condition, il);

                CurrentFunction.AddLocal(ifConditionVariable, ic.Condition.ResultType);

                branch.Condition = _constructVariableAccess(ifConditionVariable);

                il.Add(branch);
                il.Add(blockBegin);
                _EmitStatementList(ic.Statements, il);
                il.Add(gotoEnd);
                il.Add(blockEnd);
            }
            if (ifst.AlternativeStatements != null)
            {
                _EmitStatementList(ifst.AlternativeStatements, il);
            }
            il.Add(end);
        }
        public static string _EmitExpression(Expression expr, List<ILInstuction> il)
        {
            if (expr.IsLeaf) {
                //Variable access
                if (expr.LeafType == ExpressionLeafType.VariableAccess) {

                    CurrentFunction.AddLocal(expr.Value.ToString(), expr.ResultType);

                    return expr.Value.ToString();
                } else if (expr.LeafType == ExpressionLeafType.Constant) {
                    var resultVariable = GetVariableName();
                    object c;
                    if (expr.ResultType == VariableType.IntType)
                        c = expr.IntValue;
                    else if (expr.ResultType == VariableType.BoolType)
                        c = expr.BoolValue;
                    else
                        c = expr.Value;
                    var ilExpr = _constructAssignExpressionToConst(resultVariable, c);
                    il.Add(ilExpr);

                    //ilExpr.OriginalType = expr.ResultType;
                    CurrentFunction.AddLocal(resultVariable, expr.ResultType);

                    return resultVariable;

                } else if (expr.LeafType == ExpressionLeafType.FunctionCall) {
                    var ilExpr = new ILExpression();
                    ilExpr.Type = ILExpressionType.FunctionCall;
                    ilExpr.Const = expr.Value;
                    ilExpr.VAList = new List<ILExpression>();
                    foreach (var expression in expr.VAList) {
                        var parameterVariable = _EmitExpression(expression, il);
                        ilExpr.VAList.Add(_constructVariableAccess(parameterVariable));
                    }
                    ilExpr.Function = FindFunction((string)ilExpr.Const, expr.VAList);
                    //TODO: Add support for void functions;

                    //ilExpr.OriginalType = expr.ResultType;

                    if (ilExpr.Function.IsVoidReturn) {
                        il.Add(ilExpr);
                        return "void";
                    } else {
                        var resultVariable = GetVariableName();
                        var resultExpr = _constructAssignExpression(resultVariable, ilExpr);
                        il.Add(resultExpr);

                        CurrentFunction.AddLocal(resultVariable, expr.ResultType);

                        return resultVariable;
                    }

                } else if (expr.LeafType == ExpressionLeafType.ArrayLength) {
                    var leftOp = _EmitExpression(expr.LeftNode, il);
                    var ilExpr = new ILExpression();
                    ilExpr.Type = ILExpressionType.ArrayLength;
                    ilExpr.LeftNode = _constructVariableAccess(leftOp);
                    var resultVariable = GetVariableName();
                    var resultExpr = _constructAssignExpression(resultVariable, ilExpr);
                    il.Add(resultExpr);

                    //resultExpr.OriginalType = expr.ResultType;
                    CurrentFunction.AddLocal(resultVariable, expr.ResultType);

                    return resultVariable;

                } else if (expr.LeafType == ExpressionLeafType.ArrayAlloc) {
                    var leftOp = _EmitExpression(expr.LeftNode, il);
                    var ilExpr = new ILExpression();
                    ilExpr.Type = ILExpressionType.Alloc;
                    ilExpr.OriginalType = expr.ResultType;

                    ilExpr.LeftNode = _constructVariableAccess(leftOp);
                    var resultVariable = GetVariableName();
                    var resultExpr = _constructAssignExpression(resultVariable, ilExpr);
                    il.Add(resultExpr);

                    CurrentFunction.AddLocal(resultVariable, expr.ResultType);

                    return resultVariable;
                }
            } else {
                if (expr.OpType == OperationType.Assign) {
                    var rightOp = _EmitExpression(expr.RightNode, il);
                    if (expr.LeftNode.LeafType == ExpressionLeafType.VariableAccess) {
                        var leftOp = _EmitExpression(expr.LeftNode, il);
                        il.Add(_constructAssignExpression(leftOp, rightOp));

                        CurrentFunction.AddLocal(leftOp, expr.ResultType);

                        return leftOp;
                    } else if (expr.LeftNode.OpType == OperationType.ArrayAccess) {

                        // Emit ( E1[E2] = E3) =
                        // Emit (E3) --> R
                        // Emit (E1) --> A
                        // Emit (E2) --> I
                        // A[I] = R
                        // return R;

                        var arrLeftOp = _EmitExpression(expr.LeftNode.LeftNode, il);
                        var arrIndexOp = _EmitExpression(expr.LeftNode.RightNode, il);
                        var arrAccess = _constructBinaryExpressionFromVars(arrLeftOp, arrIndexOp, OperationType.ArrayAccess);

                        var assignExpr = _constructAssignExpression(arrAccess, rightOp);
                        il.Add(assignExpr);

            //						assignExprstring resultVar = GetVariableName();
            //						var secondAssignExpr = _constructAssignExpression(resultVar, arrAccess);
            //						il.Add(secondAssignExpr);
                        return rightOp;
                    } else {
                        throw new InvalidOperationException("Bad assign construction!");
                    }
                } else if (expr.OpType == OperationType.And) {
                    var leftOp = _EmitExpression(expr.LeftNode, il);

                    CurrentFunction.AddLocal(leftOp, expr.ResultType);

                    var branch = new ILBranch();
                    branch.Line = GetLabel();
                    branch.Condition = _constructVariableAccess(leftOp);
                    var succ = new ILDummy();
                    succ.Line = GetLabel();
                    var fail = new ILDummy();
                    fail.Line = GetLabel();
                    var end = new ILDummy();
                    end.Line = GetLabel();
                    var gotoEnd = new ILGoto(end.Line);
                    branch.SuccessJump = succ.Line;
                    branch.FailJump = fail.Line;

                    var resultVariable = GetVariableName();
                    il.Add(branch);
                    il.Add(succ);
                    var rightOp = _EmitExpression(expr.RightNode, il);

                    CurrentFunction.AddLocal(rightOp, expr.ResultType);

                    il.Add(_constructAssignExpression(resultVariable, rightOp));
                    il.Add(gotoEnd);
                    il.Add(fail);
                    il.Add(_constructAssignExpressionToConst(resultVariable, false));
                    il.Add(end);

                    CurrentFunction.AddLocal(resultVariable, expr.ResultType);

                    return resultVariable;
                } else if (expr.OpType == OperationType.Or) {
                    var leftOp = _EmitExpression(expr.LeftNode, il);

                    CurrentFunction.AddLocal(leftOp, expr.ResultType);

                    var branch = new ILBranch();
                    branch.Line = GetLabel();
                    branch.Condition = _constructVariableAccess(leftOp);
                    var succ = new ILDummy();
                    succ.Line = GetLabel();
                    var fail = new ILDummy();
                    fail.Line = GetLabel();
                    var end = new ILDummy();
                    end.Line = GetLabel();
                    var gotoEnd = new ILGoto(end.Line);
                    branch.SuccessJump = succ.Line;
                    branch.FailJump = fail.Line;

                    var resultVariable = GetVariableName();
                    il.Add(branch);
                    il.Add(fail);
                    var rightOp = _EmitExpression(expr.RightNode, il);

                    CurrentFunction.AddLocal(rightOp, expr.ResultType);

                    il.Add(_constructAssignExpression(resultVariable, rightOp));
                    il.Add(gotoEnd);
                    il.Add(succ);
                    il.Add(_constructAssignExpressionToConst(resultVariable, true));
                    il.Add(end);

                    CurrentFunction.AddLocal(resultVariable, expr.ResultType);

                    return resultVariable;
                }
                else if (expr.OpType == OperationType.UNot || expr.OpType == OperationType.UMinus) {
                    var op1 = _EmitExpression(expr.LeftNode, il);
                    string varName=  GetVariableName();
                    var ilExpr = _constructBinaryExpressionFromVars(op1, "", expr.OpType);
                    il.Add(_constructAssignExpression(varName, ilExpr));

                    CurrentFunction.AddLocal(varName, expr.ResultType);

                    return varName;
                }
                else {
                    var op1 = _EmitExpression(expr.LeftNode, il);
                    var op2 = _EmitExpression(expr.RightNode, il);
                    string varName = GetVariableName();
                    var ilExpr = _constructBinaryExpressionFromVars(op1, op2, expr.OpType);
                    il.Add(_constructAssignExpression(varName, ilExpr));

                    CurrentFunction.AddLocal(varName, expr.ResultType);

                    return varName;
                }
            }

            throw new InvalidOperationException("Bad expression! " + expr.ToString());
        }
        public static void EmitWhileDo(WhileDoStatement wd, List<ILInstuction> il)
        {
            ILBranch branch = new ILBranch();
            branch.Line = GetLabel();
            branch.Condition = ConstructILExpression(wd.Condition);
            ILDummy succ = new ILDummy();
            succ.Line = GetLabel();
            ILDummy fail = new ILDummy();
            fail.Line = GetLabel();
            ILGoto gotoBegin = new ILGoto(branch.Line);

            branch.SuccessJump = succ.Line;
            branch.FailJump = fail.Line;
            il.Add(branch);
            il.Add(succ);
            EmitStatementList(wd.Statements, il);
            il.Add(gotoBegin);
            il.Add(fail);
        }