Code Search for Developers
 
 
  

Statements.cs from p4shelf at Krugle


Show Statements.cs syntax highlighted

/* **********************************************************************************
 *
 * Copyright (c) Microsoft Corporation. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Shared Source License
 * for IronPython. A copy of the license can be found in the License.html file
 * at the root of this distribution. If you can not locate the Shared Source License
 * for IronPython, please send an email to ironpy@microsoft.com.
 * By using this source code in any fashion, you are agreeing to be bound by
 * the terms of the Shared Source License for IronPython.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/

using System;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
using System.Collections.Generic;
using System.CodeDom;

using System.Diagnostics;

using IronPython.Runtime;
using IronPython.Runtime.Operations;
using IronPython.Runtime.Calls;
using IronPython.CodeDom;

using IronPython.Compiler.Generation;

namespace IronPython.Compiler.Ast {
    public abstract class Statement : Node {
        public static readonly object NextStatement = new object();

        public virtual object Execute(NameEnvironment environment) {
            throw new NotImplementedException("execute: " + this);
        }

        internal abstract void Emit(CodeGen cg);

        public virtual string Documentation {
            get {
                return null;
            }
        }
    }

    public class SuiteStatement : Statement {
        private readonly Statement[] stmts;

        public IList<Statement> Statements {
            get { return stmts; }
        }

        public SuiteStatement(Statement[] statements) {
            this.stmts = statements;
        }

        public override object Execute(NameEnvironment environment) {
            object ret = Statement.NextStatement;
            foreach (Statement stmt in stmts) {
                ret = stmt.Execute(environment);
                if (ret != Statement.NextStatement) break;
            }
            return ret;
        }

        internal override void Emit(CodeGen cg) {
            // Should emit nop for the colon?
            foreach (Statement stmt in stmts) {
                stmt.Emit(cg);
            }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                foreach (Statement stmt in stmts) stmt.Walk(walker);
            }
            walker.PostWalk(this);
        }

        public override string Documentation {
            get {
                if (stmts.Length > 0 && stmts[0] is ExpressionStatement) {
                    ExpressionStatement es = (ExpressionStatement)stmts[0];
                    if (es.Expression is ConstantExpression) {
                        object val = ((ConstantExpression)es.Expression).Value;
                        if (val is string && !Options.StripDocStrings) return (string)val;
                    }
                }
                return null;
            }
        }
    }

    public class IfStatement : Statement {
        private readonly IfStatementTest[] tests;
        private readonly Statement elseStmt;

        public IfStatement(IfStatementTest[] tests, Statement else_) {
            this.tests = tests; this.elseStmt = else_;
        }

        public IList<IfStatementTest> Tests {
            get { return tests; }
        }

        public Statement ElseStatement {
            get { return elseStmt; }
        }

        public override object Execute(NameEnvironment environment) {
            foreach (IfStatementTest t in tests) {
                object val = t.Test.Evaluate(environment);
                if (Ops.IsTrue(val)) {
                    return t.Body.Execute(environment);
                }
            }
            if (elseStmt != null) {
                return elseStmt.Execute(environment);
            }
            return NextStatement;
        }

        internal override void Emit(CodeGen cg) {
            Label eoi = cg.DefineLabel();
            foreach (IfStatementTest t in tests) {
                Label next = cg.DefineLabel();
                cg.EmitPosition(t);
                cg.EmitTestTrue(t.Test);
                cg.Emit(OpCodes.Brfalse, next);
                t.Body.Emit(cg);
                // optimize no else case
                cg.Emit(OpCodes.Br, eoi);
                cg.MarkLabel(next);
            }
            if (elseStmt != null) {
                elseStmt.Emit(cg);
            }
            cg.MarkLabel(eoi);
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                foreach (IfStatementTest t in tests) t.Walk(walker);
                if (elseStmt != null) elseStmt.Walk(walker);
            }
            walker.PostWalk(this);
        }
    }

    public class IfStatementTest : Node {
        private Location header;
        private readonly Expression test;
        private Statement body;

        public IfStatementTest(Expression test, Statement body) {
            this.test = test; this.body = body;
        }

        public Location Header {
            get { return header; }
            set { header = value; }
        }

        public Expression Test {
            get { return test; }
        }

        public Statement Body {
            get { return body; }
            set { body = value; }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                test.Walk(walker);
                body.Walk(walker);
            }
            walker.PostWalk(this);
        }
    }

    public class WhileStatement : Statement {
        private Location header;
        private readonly Expression test;
        private readonly Statement body;
        private readonly Statement elseStmt;

        public WhileStatement(Expression test, Statement body, Statement else_) {
            this.test = test; this.body = body; this.elseStmt = else_;
        }

        public Location Header {
            get { return header; }
            set { header = value; }
        }

        public Expression Test {
            get { return test; }
        }

        public Statement Body {
            get { return body; }
        }

        public Statement ElseStatement {
            get { return elseStmt; }
        }

        public override object Execute(NameEnvironment environment) {
            object ret = NextStatement;
            while (Ops.IsTrue(test.Evaluate(environment))) {
                ret = body.Execute(environment);
                if (ret != NextStatement) break;
            }
            return ret;
            //			if (else_ != null) {
            //				else_.exec(env);
            //			}
        }

        internal override void Emit(CodeGen cg) {
            Label eol = cg.DefineLabel();
            Label breakTarget = cg.DefineLabel();
            Label continueTarget = cg.DefineLabel();

            cg.MarkLabel(continueTarget);

            cg.EmitPosition(Start, header);
            cg.EmitTestTrue(test);
            cg.Emit(OpCodes.Brfalse, eol);

            cg.PushTargets(breakTarget, continueTarget);

            body.Emit(cg);

            cg.Emit(OpCodes.Br, continueTarget);

            cg.PopTargets();

            cg.MarkLabel(eol);
            if (elseStmt != null) {
                elseStmt.Emit(cg);
            }
            cg.MarkLabel(breakTarget);
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                test.Walk(walker);
                body.Walk(walker);
                if (elseStmt != null) elseStmt.Walk(walker);
            }
            walker.PostWalk(this);
        }

        public void SetLoc(Location start, Location header, Location end) {
            SetLoc(null, start, header, end);
        }

        internal void SetLoc(ExternalLineMapping externalInfo, Location start, Location header, Location end) {            
            SetLoc(externalInfo, start, end);
            this.header = header;
        }
    }

    public class ForStatement : Statement {
        private Location header;
        private readonly Expression lhs;
        private Expression list;
        private Statement body;
        private readonly Statement elseStmt;

        public ForStatement(Expression lhs, Expression list, Statement body, Statement else_) {
            this.lhs = lhs; this.list = list;
            this.body = body; this.elseStmt = else_;
        }

        public Location Header {
            get { return header; }
            set { header = value; }
        }

        public Expression Left {
            get { return lhs; }
        }

        public Expression List {
            get { return list; }
            set { list = value; }
        }

        public Statement Body {
            get { return body; }
            set { body = value; }
        }

        public Statement ElseStatement {
            get { return elseStmt; }
        }

        public override object Execute(NameEnvironment environment) {
            object ret = Statement.NextStatement;

            IEnumerator i = Ops.GetEnumerator(list.Evaluate(environment));

            while (i.MoveNext()) {
                lhs.Assign(i.Current, environment);
                ret = body.Execute(environment);
                if (ret != NextStatement) return ret;
            }

            return ret;
            //			if (else_ != null) {
            //				else_.exec(env);
            //			}
        }

        internal override void Emit(CodeGen cg) {
            Label eol = cg.DefineLabel();
            Label breakTarget = cg.DefineLabel();
            Label continueTarget = cg.DefineLabel();

            cg.EmitPosition(Start, header);

            list.Emit(cg);
            cg.EmitCall(typeof(Ops), "GetEnumeratorForIteration");

            Slot iter;
            if (cg.IsGenerator()) {
                iter = cg.Names.GetTempSlot("iter", typeof(IEnumerator));
            } else {
                iter = cg.GetLocalTmp(typeof(IEnumerator));
            }

            iter.EmitSet(cg);

            cg.MarkLabel(continueTarget);
            iter.EmitGet(cg);
            cg.EmitCall(typeof(IEnumerator), "MoveNext");

            cg.Emit(OpCodes.Brfalse, eol);

            cg.PushTargets(breakTarget, continueTarget);

            iter.EmitGet(cg);
            cg.EmitCall(typeof(IEnumerator).GetProperty("Current").GetGetMethod());
            lhs.EmitSet(cg);

            body.Emit(cg);

            cg.Emit(OpCodes.Br, continueTarget);

            cg.PopTargets();

            cg.MarkLabel(eol);
            if (elseStmt != null) {
                elseStmt.Emit(cg);
            }
            cg.MarkLabel(breakTarget);

            if (!cg.IsGenerator()) {
                cg.FreeLocalTmp(iter);
            }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                lhs.Walk(walker);
                list.Walk(walker);
                body.Walk(walker);
                if (elseStmt != null) elseStmt.Walk(walker);
            }
            walker.PostWalk(this);
        }

        // For uses one local slot for the iter variable
        internal static int LocalSlots {
            get {
                return 1;
            }
        }
    }

    public class WithStatement : Statement {
        private Location header;
        private Expression contextManager;
        private Expression var;
        private Statement body;
        private List<YieldTarget> yieldTargets;// = new List<YieldTarget>();

        public WithStatement(Expression contextManager, Expression var, Statement body) {
            this.contextManager = contextManager;
            this.var = var;
            this.body = body;
        }


        public Expression Variable {
            get { return var; }
        }

        public Expression ContextManager {
            get { return contextManager; }
        }

        public Statement Body {
            get { return body; }
        }

        public Location Header {
            get { return header; }
            set { header = value; }
        }

        public IList<YieldTarget> YieldTargets {
            get { return yieldTargets; }
        }

        internal void AddYieldTarget(YieldTarget target) {
            if (yieldTargets == null)
                yieldTargets = new List<YieldTarget>();
            yieldTargets.Add(target);
        }

        // With uses 3 local slots 
        internal static int LocalSlots {
            get {
                return 3;
            }
        }


        // ***WITH STATEMENT CODE GENERATION ALGORITHM*** 
        //
        //GRAMMAR :=
        //with EXPR as VAR:
        //    BLOCK
        //
        //CODE GEN :=
        //
        //mgr = (EXPR)
        //exit = mgr.__exit__  # Not calling it yet
        //value = mgr.__enter__()
        //exc = True
        //isTryYielded = False
        //try:
        //
        //   VAR = value  # Only if "as VAR" is present
        //   BLOCK 
        //   // if yield happens in the Block, 
        //   // then isTryYielded is set to True by Yield's Code Gen
        //except:
        //   # The exceptional case is handled here
        //   exc = False
        //   if not exit(*sys.exc_info()):
        //        raise
        //   # The exception is consumed if exit() returns true
        //finally:
        //    # The normal and non-local-goto cases are handled here
        //    if  isTryYielded = False && exc == True :
        //        exit(None, None, None)



        internal override void Emit(CodeGen cg) {

            Slot exc = null;
            Slot isTryYielded = null;
            Slot exit = null;

            if (cg.IsGenerator()) {
                exc = cg.Names.GetTempSlot("with", typeof(object));
                isTryYielded = cg.Names.GetTempSlot("with", typeof(object));
                exit = cg.Names.GetTempSlot("with", typeof(object));
            } else {
                exc = cg.GetLocalTmp(typeof(object));
                isTryYielded = cg.GetLocalTmp(typeof(object));
                exit = cg.GetLocalTmp(typeof(object));
            }

            // mgr = (EXPR)
            Slot mgr = cg.GetLocalTmp(typeof(object));
            contextManager.Emit(cg);
            mgr.EmitSet(cg);

            // exit = mgr.__exit__ # not calling it yet
            cg.EmitCallerContext();
            mgr.EmitGet(cg);
            cg.EmitSymbolId("__exit__");
            cg.EmitCall(typeof(Ops), "GetAttr");
            exit.EmitSet(cg);

            mgr.EmitGet(cg);
            cg.FreeLocalTmp(mgr);
            cg.EmitSymbolId("__enter__");
            cg.EmitObjectArray(new Expression[0]);
            cg.EmitCall(typeof(Ops), "Invoke", new Type[] { typeof(object), typeof(SymbolId), typeof(object[]) });
            Slot value = cg.GetLocalTmp(typeof(object));
            value.EmitSet(cg);


            // exc = True
            cg.EmitConstantBoxed(true);
            exc.EmitSet(cg);

            Slot choiceVar = null;

            if (yieldTargets != null && yieldTargets.Count > 0) {
                Label startOfBlock = cg.DefineLabel();
                choiceVar = cg.GetLocalTmp(typeof(int));
                cg.EmitInt(-1);
                choiceVar.EmitSet(cg);
                cg.Emit(OpCodes.Br, startOfBlock);

                int index = 0;
                foreach (YieldTarget yt in yieldTargets) {
                    cg.MarkLabel(yt.TopBranchTarget);
                    cg.EmitInt(index++);
                    choiceVar.EmitSet(cg);
                    cg.Emit(OpCodes.Br, startOfBlock);
                }

                cg.MarkLabel(startOfBlock);
            }

            cg.EmitConstantBoxed(false);
            isTryYielded.EmitSet(cg);

            Label beforeFinally = cg.DefineLabel();

            cg.PushWithTryBlock(isTryYielded);
            cg.BeginExceptionBlock();

            if (yieldTargets != null && yieldTargets.Count > 0) {
                int index = 0;
                foreach (YieldTarget yt in yieldTargets) {
                    choiceVar.EmitGet(cg);
                    cg.EmitInt(index);
                    cg.Emit(OpCodes.Beq, yt.YieldContinuationTarget);
                    index++;
                }
                cg.FreeLocalTmp(choiceVar);
            }

            if (var != null) {
                value.EmitGet(cg);
                var.EmitSet(cg);
            }

            body.Emit(cg);

            EmitWithCatchBlock(cg, exc, exit);
            cg.PopTargets();
            EmitWithFinallyBlock(cg, exc, exit, isTryYielded);
            cg.EndExceptionBlock();
            if (yieldTargets != null)
                yieldTargets.Clear();

        }

        private void EmitWithCatchBlock(CodeGen cg, Slot exc, Slot exit) {
            cg.BeginCatchBlock(typeof(Exception));
            // Extract state from the carrier exception
            cg.EmitCallerContext();
            cg.EmitCall(typeof(Ops), "ExtractException",
                new Type[] { typeof(Exception), typeof(ICallerContext) });
            cg.Emit(OpCodes.Pop);

            // except body 
            cg.PushExceptionBlock(Targets.TargetBlockType.Catch, null, null);
            cg.EmitConstantBoxed(false);
            exc.EmitSet(cg);

            cg.EmitCallerContext();
            exit.EmitGet(cg);
            cg.EmitObjectArray(new Expression[0]);
            cg.EmitCallerContext();
            cg.EmitCall(typeof(Ops), "ExtractSysExcInfo");
            cg.EmitCall(typeof(Ops), "CallWithArgsTupleAndContext", new Type[] { typeof(ICallerContext), typeof(object), typeof(object[]), typeof(object) });

            Label afterRaise = cg.DefineLabel();

            cg.EmitTestTrue();
            cg.Emit(OpCodes.Brtrue, afterRaise);
            cg.EmitCall(typeof(Ops), "Raise", new Type[0]); //, new Type[] { typeof(object), typeof(SymbolId) });
            cg.MarkLabel(afterRaise);
            cg.EmitCallerContext();
            cg.EmitCall(typeof(Ops), "ClearException", new Type[] { typeof(ICallerContext) });
            cg.PopTargets();

        }

        private void EmitWithFinallyBlock(CodeGen cg, Slot exc, Slot exit, Slot isTryYielded) {
            // we are certain that Finally will never yield
            cg.PushFinallyBlock(null, null);
            cg.BeginFinallyBlock();

            //finally body
            Label endOfFinally = cg.DefineLabel();

            // isTryYielded == True ?
            isTryYielded.EmitGet(cg);
            cg.EmitTestTrue();
            cg.Emit(OpCodes.Brtrue, endOfFinally);

            // exc == False ?
            exc.EmitGet(cg);
            cg.EmitTestTrue();
            cg.Emit(OpCodes.Brfalse, endOfFinally);


            //exit(None, None, None)
            cg.EmitCallerContext();
            exit.EmitGet(cg);
            cg.Emit(OpCodes.Ldnull);
            cg.Emit(OpCodes.Ldnull);
            cg.Emit(OpCodes.Ldnull);
            cg.EmitCall(typeof(Ops), "CallWithContext", new Type[] { typeof(ICallerContext), typeof(object), typeof(object), typeof(object), typeof(object) });
            cg.Emit(OpCodes.Pop);

            cg.MarkLabel(endOfFinally);
            cg.PopTargets();

            // finally end

        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                contextManager.Walk(walker);
                if (var != null) var.Walk(walker);
                body.Walk(walker);
            }
            walker.PostWalk(this);
        }

    }

    public class TryStatement : Statement {
        class ControlFlowFinder : AstWalker {
            bool found;

            bool foundLoopControl;
            int loopCount = 0;

            public static bool FindControlFlow(Statement statement, out bool foundLoopControl) {
                // No return in null statement
                if (statement == null) {
                    foundLoopControl = false;
                    return false;
                }

                // find it now.
                ControlFlowFinder rf = new ControlFlowFinder();
                statement.Walk(rf);
                foundLoopControl = rf.foundLoopControl;
                return rf.found;
            }
            public override bool Walk(ReturnStatement node) {
                found = true;
                return true;
            }
            public override bool Walk(BreakStatement node) {
                if (loopCount == 0) {
                    found = true;
                    foundLoopControl = true;
                }
                return true;
            }
            public override bool Walk(ContinueStatement node) {
                if (loopCount == 0) {
                    found = true;
                    foundLoopControl = true;
                }
                return true;
            }

            public override bool Walk(ForStatement node) {
                loopCount++;
                return true;
            }

            public override void PostWalk(ForStatement node) {
                loopCount--;
            }

            public override bool Walk(WhileStatement node) {
                loopCount++;
                return true;
            }

            public override void PostWalk(WhileStatement node) {
                loopCount--;
            }
        }

        private Location header;
        private readonly Statement body;
        private readonly TryStatementHandler[] handlers;
        private readonly Statement elseStmt;
        private readonly Statement finallyStmt;
        private List<YieldTarget> tryYieldTargets = null;
        private List<YieldTarget> catchYieldTargets = null;
        private List<YieldTarget> finallyYieldTargets = null;
        private List<YieldTarget> elseYieldTargets = null;

        public TryStatement(Statement body, TryStatementHandler[] handlers, Statement elseSuite, Statement finallySuite) {
            this.body = body;
            this.handlers = handlers;
            this.elseStmt = elseSuite;
            this.finallyStmt = finallySuite;
        }

        public Location Header {
            get { return header; }
            set { header = value; }
        }

        public Statement Body {
            get { return body; }
        }

        public IList<TryStatementHandler> Handlers {
            get { return handlers; }
        }

        public Statement ElseStatement {
            get { return elseStmt; }
        }

        public Statement FinallyStatement {
            get { return finallyStmt; }
        }

        internal IList<YieldTarget> TryYieldTargets {
            get { return tryYieldTargets; }
        }

        internal void AddTryYieldTarget(YieldTarget target) {
            if (tryYieldTargets == null)
                tryYieldTargets = new List<YieldTarget>();
            tryYieldTargets.Add(target);
        }

        internal IList<YieldTarget> ElseYieldTargets {
            get { return elseYieldTargets; }
        }

        internal void AddElseYieldTarget(YieldTarget target) {
            if (elseYieldTargets == null)
                elseYieldTargets = new List<YieldTarget>();

            elseYieldTargets.Add(target);
        }

        internal IList<YieldTarget> CatchYieldTargets {
            get { return catchYieldTargets; }
        }

        internal void AddCatchYieldTarget(YieldTarget target) {
            if (catchYieldTargets == null)
                catchYieldTargets = new List<YieldTarget>();

            catchYieldTargets.Add(target);
        }

        internal IList<YieldTarget> FinallyYieldTargets {
            get { return finallyYieldTargets; }
        }

        internal void AddFinallyYieldTarget(YieldTarget target) {
            if (finallyYieldTargets == null)
                finallyYieldTargets = new List<YieldTarget>();

            finallyYieldTargets.Add(target);
        }

        private bool IsBlockYieldable(List<YieldTarget> block) {
            if (block != null && block.Count > 0)
                return true;
            return false;
        }

        // With uses 6 environmental slots 
        internal static int LocalSlots {
            get {
                // Binding looks for the LocalSlots even before the yield targets are counted,
                // Hence we need to set the, max posssible slots i.e 5 currently.
                // Though TryStatement requests 5 slots, during code gen it may use <= 5 based on what all block yield

                // There is scope to optimize here by getting the yield counts before binding. 
                // Once that is done uncomment the code code below, and use the instance of TryStatement in Walk(TryStatement node) in Binder.cs.

                //int ret = 0;
                //if (IsBlockYieldable(tryYieldTargets))
                //    ret++;
                //if (IsBlockYieldable(catchYieldTargets))
                //    ret += 2;
                //if (IsBlockYieldable(elseYieldTargets))
                //    ret++;
                //if (IsBlockYieldable(finallyYieldTargets))
                //    ret++; 
                return 6;
            }
        }

        private void EmitTopYieldTargetLabels(List<YieldTarget> yieldTargets, Slot choiceVar, CodeGen cg) {
            if (IsBlockYieldable(yieldTargets)) {
                Label label = cg.DefineLabel();
                cg.EmitInt(-1);
                choiceVar.EmitSet(cg);
                cg.Emit(OpCodes.Br, label);

                int index = 0;
                foreach (YieldTarget yt in yieldTargets) {
                    cg.MarkLabel(yt.TopBranchTarget);
                    cg.EmitInt(index++);
                    choiceVar.EmitSet(cg);
                    cg.Emit(OpCodes.Br, label);
                }
                cg.MarkLabel(label);
            }
        }

        private void EmitYieldDispatch(List<YieldTarget> yieldTargets, Slot isYielded, Slot choiceVar, CodeGen cg) {
            if (IsBlockYieldable(yieldTargets)) {
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isYielded.EmitSet(cg);

                int index = 0;
                foreach (YieldTarget yt in yieldTargets) {
                    choiceVar.EmitGet(cg);
                    cg.EmitInt(index);
                    cg.Emit(OpCodes.Beq, yt.YieldContinuationTarget);
                    index++;
                }
            }
        }

        private void EmitOnYieldBranchToLabel(List<YieldTarget> yieldTargets, Slot isYielded, Label label, CodeGen cg) {
            if (IsBlockYieldable(yieldTargets)) {
                isYielded.EmitGet(cg);
                cg.EmitUnbox(typeof(bool));
                cg.Emit(OpCodes.Brtrue, label);
            }
        }

        // codegen algorithm for unified try-catch-else-finally

        //    isTryYielded = false
        //    isCatchYielded = false
        //    isFinallyYielded = false
        //    isElseYielded = false
        //    Set up the labels for Try Yield Targets
        //    Set up the labels for Catch Yield Targets
        //    Set up the labels for Else Yield Targets
        //    Set up the labels for Finally Yield Targets
        //    returnVar = false
        //    isElseBlock = false

        //TRY:
        //    if isCatchYielded :
        //        rethow  storedException
        //    if finallyYielded :
        //        goto endOfTry
        //    if isElseYielded :
        //        goto beginElseBlock
        //    if isTryYielded:
        //        isTryYielded = false
        //        goto desired_label_in_TRY-BODY
        //    TRY-BODY
        //  beginElseBlock: # Note we are still under TRY
        //    isElseBlock = true
        //    if isElseYielded :
        //        isElseYielded  = false
        //        goto desired_label_in_ELSE-BODY
        //    ELSE-BODY
        //  endOfTry:
        //EXCEPT: # catches any exception
        //    if isElseBlock:
        //        rethrow
        //    pyExc = ExtractException()
        //    storedException = ExtractSysExcInfo()
        //    if pyExc == handler[0].Test :
        //        if isCatchYielded :
        //            isCatchYielded  = false
        //            goto desired_label_in_HANDLER-BODY
        //        HANDLER-BODY
        //        ClearException()
        //        Leave afterFinally
        //    elif pyExc == handler[1].Test :
        //        if isCatchYielded :
        //            isCatchYielded  = false
        //            goto desired_label_in_HANDLER-BODY
        //        HANDLER-BODY
        //        ClearException()
        //        Leave afterFinally
        //    .
        //    .
        //    .
        //    Rethrow
        //FINALLY:
        //    if (isTryYielded  or isCatchYielded  or isElseYielded ):
        //        goto endOfFinally
        //    if isFinallyYielded :
        //        isFinallyYielded  = false
        //        goto desired_label_in_FINALLY-BODY
        //    FINALLY-BODY
        //  endOfFinally:
        // #try-cathch-finally ends here
        // afterFinally:
        //    if not returnVar :
        //      goto noReturn
        //    if (finally may yield ):
        //          return 1
        //    else
        //          return appropriate_return_value
        //  noReturn:


        internal override void Emit(CodeGen cg) {
            // environmental slots
            Slot isTryYielded = null;
            Slot isCatchYielded = null;
            Slot isFinallyYielded = null;
            Slot isElseYielded = null;
            Slot storedException = null;

            // local slots
            Slot tryChoiceVar = null;
            Slot catchChoiceVar = null;
            Slot elseChoiceVar = null;
            Slot finallyChoiceVar = null;

            Slot flowControlVar = cg.GetLocalTmp(typeof(int));
            Slot isElseBlock = null;

            cg.EmitPosition(Start, header);

            if (IsBlockYieldable(tryYieldTargets)) {
                tryChoiceVar = cg.GetLocalTmp(typeof(int));
                isTryYielded = cg.Names.GetTempSlot("is", typeof(object));
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isTryYielded.EmitSet(cg);
            }

            if (IsBlockYieldable(catchYieldTargets)) {
                catchChoiceVar = cg.GetLocalTmp(typeof(int));
                storedException = cg.Names.GetTempSlot("exc", typeof(object));
                isCatchYielded = cg.Names.GetTempSlot("is", typeof(object));
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isCatchYielded.EmitSet(cg);
            }

            if (IsBlockYieldable(finallyYieldTargets)) {
                finallyChoiceVar = cg.GetLocalTmp(typeof(int));
                isFinallyYielded = cg.Names.GetTempSlot("is", typeof(object));
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isFinallyYielded.EmitSet(cg);
            }

            if (IsBlockYieldable(elseYieldTargets)) {
                elseChoiceVar = cg.GetLocalTmp(typeof(int));
                isElseYielded = cg.Names.GetTempSlot("is", typeof(object));
                cg.EmitFieldGet(typeof(Ops).GetField("FALSE"));
                isElseYielded.EmitSet(cg);
            }

            if (elseStmt != null) {
                isElseBlock = cg.GetLocalTmp(typeof(bool));
                cg.EmitInt(0);
                isElseBlock.EmitSet(cg);
            }

            Slot exception = null;
            bool foundLoopControl;
            bool returnInFinally = ControlFlowFinder.FindControlFlow(FinallyStatement, out foundLoopControl);

            if (IsBlockYieldable(finallyYieldTargets)) {
                exception = cg.Names.GetTempSlot("exception", typeof(Exception));
                cg.Emit(OpCodes.Ldnull);
                exception.EmitSet(cg);
            } else if (returnInFinally) {
                exception = cg.GetLocalTmp(typeof(Exception));
                cg.Emit(OpCodes.Ldnull);
                exception.EmitSet(cg);
            }

            EmitTopYieldTargetLabels(tryYieldTargets, tryChoiceVar, cg);
            EmitTopYieldTargetLabels(catchYieldTargets, catchChoiceVar, cg);
            EmitTopYieldTargetLabels(elseYieldTargets, elseChoiceVar, cg);
            EmitTopYieldTargetLabels(finallyYieldTargets, finallyChoiceVar, cg);


            cg.EmitInt(CodeGen.FinallyExitsNormally);
            flowControlVar.EmitSet(cg);

            Label afterFinally = cg.DefineLabel();

            cg.PushExceptionBlock(Targets.TargetBlockType.Try, flowControlVar, isTryYielded);
            cg.BeginExceptionBlock();

            // if catch yielded, rethow the storedException to be handled by Catch block
            if (IsBlockYieldable(catchYieldTargets)) {
                Label testFinally = cg.DefineLabel();
                isCatchYielded.EmitGet(cg);
                cg.EmitUnbox(typeof(bool));
                cg.Emit(OpCodes.Brfalse, testFinally);
                storedException.EmitGet(cg);
                cg.EmitCall(typeof(Ops), "Raise", new Type[] { typeof(object) });
                cg.MarkLabel(testFinally);
            }

            // if Finally yielded, Branch to the end of Try block
            Label endOfTry = cg.DefineLabel();
            EmitOnYieldBranchToLabel(finallyYieldTargets, isFinallyYielded, endOfTry, cg);

            Label beginElseBlock = cg.DefineLabel();
            if (IsBlockYieldable(elseYieldTargets)) {
                // isElseYielded ?
                Debug.Assert(isElseYielded != null);
                isElseYielded.EmitGet(cg);
                cg.EmitUnbox(typeof(bool));
                cg.Emit(OpCodes.Brtrue, beginElseBlock);
            }


            EmitYieldDispatch(tryYieldTargets, isTryYielded, tryChoiceVar, cg);

            body.Emit(cg);

            if (elseStmt != null) {
                if (IsBlockYieldable(elseYieldTargets)) {
                    cg.MarkLabel(beginElseBlock);
                }

                cg.PopTargets(Targets.TargetBlockType.Try);
                cg.PushExceptionBlock(Targets.TargetBlockType.Else, flowControlVar, isElseYielded);

                cg.EmitInt(1);
                isElseBlock.EmitSet(cg);

                EmitYieldDispatch(elseYieldTargets, isElseYielded, elseChoiceVar, cg);

                elseStmt.Emit(cg);
                cg.PopTargets(Targets.TargetBlockType.Else);
                cg.PushExceptionBlock(Targets.TargetBlockType.Try, flowControlVar, isTryYielded);

            }

            cg.MarkLabel(endOfTry);

            // get the exception if there is a yield / return  in finally
            if (IsBlockYieldable(finallyYieldTargets) || returnInFinally) {
                cg.BeginCatchBlock(typeof(Exception));
                exception.EmitSet(cg);
            }

            if (handlers != null) {
                cg.PushExceptionBlock(Targets.TargetBlockType.Catch, flowControlVar, isCatchYielded);
                if (IsBlockYieldable(finallyYieldTargets) || returnInFinally) {
                    exception.EmitGet(cg);
                } else {
                    cg.BeginCatchBlock(typeof(Exception));
                }


                // if in Catch block due to exception in else block -> just rethrow
                if (elseStmt != null) {
                    Label beginCatchBlock = cg.DefineLabel();
                    isElseBlock.EmitGet(cg);
                    cg.Emit(OpCodes.Brfalse, beginCatchBlock);
                    cg.Emit(OpCodes.Rethrow);
                    cg.MarkLabel(beginCatchBlock);
                }

                // Extract state from the carrier exception
                cg.EmitCallerContext();
                cg.EmitCall(typeof(Ops), "ExtractException",
                    new Type[] { typeof(Exception), typeof(ICallerContext) });
                Slot pyExc = cg.GetLocalTmp(typeof(object));
                Slot tmpExc = cg.GetLocalTmp(typeof(object));
                pyExc.EmitSet(cg);

                if (IsBlockYieldable(catchYieldTargets)) {
                    cg.EmitCallerContext();
                    cg.EmitCall(typeof(Ops), "ExtractSysExcInfo");
                    storedException.EmitSet(cg);
                }

                foreach (TryStatementHandler handler in handlers) {
                    cg.EmitPosition(handler.Start, handler.Header);
                    Label next = cg.DefineLabel();
                    if (handler.Test != null) {
                        pyExc.EmitGet(cg);
                        handler.Test.Emit(cg);
                        cg.EmitCall(typeof(Ops), "CheckException");
                        if (handler.Target != null) {
                            tmpExc.EmitSet(cg);
                            tmpExc.EmitGet(cg);
                        }
                        cg.EmitPythonNone();
                        cg.Emit(OpCodes.Ceq);
                        cg.Emit(OpCodes.Brtrue, next);
                    }

                    if (handler.Target != null) {
                        tmpExc.EmitGet(cg);
                        handler.Target.EmitSet(cg);
                    }

                    if (IsBlockYieldable(finallyYieldTargets) || returnInFinally) {
                        cg.Emit(OpCodes.Ldnull);
                        exception.EmitSet(cg);
                    }

                    EmitYieldDispatch(catchYieldTargets, isCatchYielded, catchChoiceVar, cg);
                    handler.Body.Emit(cg);

                    cg.EmitCallerContext();
                    cg.EmitCall(typeof(Ops), "ClearException", new Type[] { typeof(ICallerContext) });

                    cg.Emit(OpCodes.Leave, afterFinally);
                    cg.MarkLabel(next);

                }

                cg.FreeLocalTmp(tmpExc);
                cg.FreeLocalTmp(pyExc);

                cg.Emit(OpCodes.Rethrow);
                cg.PopTargets(Targets.TargetBlockType.Catch);
            }

            if (finallyStmt != null) {
                cg.PushExceptionBlock(Targets.TargetBlockType.Finally, flowControlVar, isFinallyYielded);
                cg.BeginFinallyBlock();

                Label endOfFinally = cg.DefineLabel();

                // if try yielded
                EmitOnYieldBranchToLabel(tryYieldTargets, isTryYielded, endOfFinally, cg);
                // if catch yielded
                EmitOnYieldBranchToLabel(catchYieldTargets, isCatchYielded, endOfFinally, cg);
                //if else yielded
                EmitOnYieldBranchToLabel(elseYieldTargets, isElseYielded, endOfFinally, cg);

                EmitYieldDispatch(finallyYieldTargets, isFinallyYielded, finallyChoiceVar, cg);
                finallyStmt.Emit(cg);

                if (IsBlockYieldable(finallyYieldTargets) || returnInFinally) {
                    Label nothrow = cg.DefineLabel();
                    exception.EmitGet(cg);
                    cg.Emit(OpCodes.Dup);
                    cg.Emit(OpCodes.Brfalse_S, nothrow);
                    cg.Emit(OpCodes.Throw);
                    cg.MarkLabel(nothrow);
                    cg.Emit(OpCodes.Pop);
                }


                cg.MarkLabel(endOfFinally);
                cg.EndExceptionBlock();
                cg.PopTargets(Targets.TargetBlockType.Finally);
            } else {
                cg.EndExceptionBlock();
            }
            cg.PopTargets(Targets.TargetBlockType.Try);

            cg.MarkLabel(afterFinally);
            Label noReturn = cg.DefineLabel();
            flowControlVar.EmitGet(cg);
            cg.EmitInt(CodeGen.BranchForReturn);
            cg.Emit(OpCodes.Bne_Un, noReturn);

            if (cg.IsGenerator()) {
                // return true from the generator method
                cg.Emit(OpCodes.Ldc_I4_1);
                cg.EmitReturn();
            } else if (returnInFinally) {
                // return the actual value
                cg.EmitReturnValue();
                cg.EmitReturn();
            }

            cg.MarkLabel(noReturn);

            if (foundLoopControl) {
                noReturn = cg.DefineLabel();
                flowControlVar.EmitGet(cg);
                cg.EmitInt(CodeGen.BranchForBreak);
                cg.Emit(OpCodes.Bne_Un, noReturn);
                cg.EmitBreak();
                cg.MarkLabel(noReturn);

                noReturn = cg.DefineLabel();
                flowControlVar.EmitGet(cg);
                cg.EmitInt(CodeGen.BranchForContinue);
                cg.Emit(OpCodes.Bne_Un, noReturn);
                cg.EmitContinue();
                cg.MarkLabel(noReturn);
            }

            // clean up 
            if (IsBlockYieldable(tryYieldTargets)) {
                cg.FreeLocalTmp(tryChoiceVar);
                tryYieldTargets.Clear();
            }
            if (IsBlockYieldable(catchYieldTargets)) {
                cg.FreeLocalTmp(catchChoiceVar);
                catchYieldTargets.Clear();
            }
            if (IsBlockYieldable(finallyYieldTargets)) {
                cg.FreeLocalTmp(finallyChoiceVar);
                finallyYieldTargets.Clear();
            }
            if (IsBlockYieldable(elseYieldTargets)) {
                cg.FreeLocalTmp(elseChoiceVar);
                elseYieldTargets.Clear();
            }
            if (elseStmt != null) {
                cg.FreeLocalTmp(isElseBlock);
            }

#if DEBUG
            cg.EmitInt(-1);
            flowControlVar.EmitSet(cg);
#endif

            cg.FreeLocalTmp(flowControlVar);
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                body.Walk(walker);
                if (handlers != null)
                    foreach (TryStatementHandler handler in handlers)
                        handler.Walk(walker);

                if (elseStmt != null)
                    elseStmt.Walk(walker);

                if (finallyStmt != null)
                    finallyStmt.Walk(walker);

            }
            walker.PostWalk(this);
        }
    }

    public class TryFinallyStatement : Statement {
        internal override void Emit(CodeGen cg) {
            throw new InvalidOperationException("TryFinallyStatement is deprecated");
        }

        public override void Walk(IAstWalker walker) {            
        }
    }

    public class TryStatementHandler : Node {
        private Location header;
        private readonly Expression test, target;
        private readonly Statement body;

        public TryStatementHandler(Expression test, Expression target, Statement body) {
            this.test = test; this.target = target; this.body = body;
        }

        public Location Header {
            get { return header; }
            set { header = value; }
        }

        public Expression Target {
            get { return target; }
        }

        public Expression Test {
            get { return test; }
        }

        public Statement Body {
            get { return body; }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                if (test != null) test.Walk(walker);
                if (target != null) target.Walk(walker);
                body.Walk(walker);
            }
            walker.PostWalk(this);
        }
    }



    public class ExpressionStatement : Statement {
        private readonly Expression expr;

        public ExpressionStatement(Expression expression) { this.expr = expression; }

        public Expression Expression {
            get { return expr; }
        }

        public override object Execute(NameEnvironment environment) {
            expr.Evaluate(environment);
            return NextStatement;
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
            if (cg.printExprStmts) {
                // emit & print expression.
                cg.EmitSystemState();
                expr.Emit(cg);

                Label noSet = cg.DefineLabel();
                // only set _ if the last expression is not None.
                cg.Emit(OpCodes.Dup);
                cg.Emit(OpCodes.Ldnull);
                cg.Emit(OpCodes.Beq, noSet);
                cg.Emit(OpCodes.Dup);
                cg.EmitSet(SymbolTable.Underscore);
                cg.MarkLabel(noSet);

                // finally emit the call to print the value.
                cg.EmitCall(typeof(Ops), "PrintNotNoneRepr", new Type[] { typeof(SystemState), typeof(object) });
            } else {
                // expression needs to be emitted incase it has side-effects.
                expr.Emit(cg);
                cg.Emit(OpCodes.Pop);
            }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                expr.Walk(walker);
            }
            walker.PostWalk(this);
        }

        public override string Documentation {
            get {
                ConstantExpression ce = expr as ConstantExpression;
                if (ce != null) {
                    return ce.Value as string;
                }
                return null;
            }
        }
    }

    public class AssignStatement : Statement {
        // lhs.Length is 1 for simple assignments like "x = 1"
        // lhs.Lenght will be 3 for "x = y = z = 1"
        private readonly Expression[] lhs;
        private readonly Expression rhs;

        public AssignStatement(Expression[] leftSide, Expression rightSide) {
            this.lhs = leftSide;
            this.rhs = rightSide;
        }

        public IList<Expression> Left {
            get { return lhs; }
        }

        public Expression Right {
            get { return rhs; }
        }

        public override object Execute(NameEnvironment environment) {
            object v = rhs.Evaluate(environment);
            foreach (Expression e in lhs) {
                e.Assign(v, environment);
            }
            return NextStatement;
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
            rhs.Emit(cg);
            for (int i = 0; i < lhs.Length; i++) {
                if (i < lhs.Length - 1) cg.Emit(OpCodes.Dup);
                lhs[i].EmitSet(cg);
            }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                foreach (Expression e in lhs) e.Walk(walker);
                rhs.Walk(walker);
            }
            walker.PostWalk(this);
        }

    }

    public class AugAssignStatement : Statement {
        private readonly BinaryOperator op;
        private readonly Expression lhs;
        private readonly Expression rhs;

        public AugAssignStatement(BinaryOperator binaryOperator, Expression leftSide, Expression rightSide) {
            this.op = binaryOperator; this.lhs = leftSide; this.rhs = rightSide;
        }

        public BinaryOperator Operator {
            get { return op; }
        }

        public Expression Left {
            get { return lhs; }
        }

        public Expression Right {
            get { return rhs; }
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);

            // if lhs is a complex expression (eg foo[x] or foo.bar)
            // then it's EmitSet needs to do the right thing.
            lhs.Emit(cg);
            rhs.Emit(cg);

            op.EmitInPlace(cg);
            lhs.EmitSet(cg);
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                lhs.Walk(walker);
                rhs.Walk(walker);
            }
            walker.PostWalk(this);
        }

    }

    public class PrintStatement : Statement {
        private readonly Expression dest;
        private readonly Expression[] exprs;
        private readonly bool trailingComma;

        public PrintStatement(Expression destination, Expression[] expressions, bool trailingComma) {
            this.dest = destination; this.exprs = expressions;
            this.trailingComma = trailingComma;
        }

        public Expression Destination {
            get { return dest; }
        }

        public IList<Expression> Expressions {
            get { return exprs; }
        }

        public bool TrailingComma {
            get { return trailingComma; }
        }

        public override object Execute(NameEnvironment environment) {
            Console.Out.Write("print> ");
            foreach (Expression e in exprs) {
                object val = e.Evaluate(environment);
                Ops.PrintComma(environment.Globals.SystemState, val);
            }
            if (!trailingComma) Ops.PrintNewline(environment.Globals.SystemState);

            return NextStatement;
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
            string suffix = "";
            if (dest != null) suffix = "WithDest";
            if (exprs.Length == 0) {
                cg.EmitSystemState();
                if (dest != null) dest.Emit(cg);
                cg.EmitCall(typeof(Ops), "PrintNewline" + suffix);
            } else {
                Slot destSlot = null;
                if (dest != null) {
                    destSlot = cg.GetLocalTmp(typeof(object));
                    dest.Emit(cg);
                    destSlot.EmitSet(cg);
                }
                for (int i = 0; i < exprs.Length; i++) {
                    cg.EmitSystemState();
                    if (dest != null) {
                        Debug.Assert(destSlot != null);
                        destSlot.EmitGet(cg);
                    }
                    exprs[i].Emit(cg);
                    if (i < exprs.Length - 1 || trailingComma) cg.EmitCall(typeof(Ops), "PrintComma" + suffix);
                    else cg.EmitCall(typeof(Ops), "Print" + suffix);
                }
                if (destSlot != null) {
                    cg.FreeLocalTmp(destSlot);
                }
            }
        }
        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                if (dest != null) dest.Walk(walker);
                foreach (Expression e in exprs) e.Walk(walker);
            }
            walker.PostWalk(this);
        }
    }

    public class DottedName : Node {
        private readonly SymbolId[] names;

        public DottedName(SymbolId[] names) { this.names = names; }

        public IList<SymbolId> Names {
            get { return names; }
        }

        public string MakeString() {
            StringBuilder ret = new StringBuilder(names[0].GetString());
            for (int i = 1; i < names.Length; i++) {
                ret.Append('.');
                ret.Append(names[i].GetString());
            }
            return ret.ToString();
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                ;
            }
            walker.PostWalk(this);
        }
    }

    public class ImportStatement : Statement {
        private readonly DottedName[] names;
        private readonly SymbolId[] asNames;

        public ImportStatement(DottedName[] names, SymbolId[] asNames) {
            this.names = names;
            this.asNames = asNames;
        }

        public IList<DottedName> Names {
            get { return names; }
        }

        public IList<SymbolId> AsNames {
            get { return asNames; }
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);

            for (int i = 0; i < names.Length; i++) {
                DottedName name = names[i];
                cg.EmitModuleInstance();
                cg.EmitString(name.MakeString());
                if (asNames[i] == SymbolTable.Empty) {
                    cg.EmitCall(typeof(Ops), "Import");
                    cg.EmitSet(name.Names[0]);
                } else {
                    cg.EmitString(asNames[i].GetString());
                    cg.EmitCall(typeof(Ops), "ImportAs");
                    cg.EmitSet(asNames[i]);
                }
            }
        }

        public override void Walk(IAstWalker walker) {
            walker.Walk(this);
            walker.PostWalk(this);
        }
    }

    public class FromImportStatement : Statement {
        private static readonly SymbolId[] star = new SymbolId[1];
        private readonly DottedName root;
        private readonly IList<SymbolId> names;
        private readonly IList<SymbolId> asNames;
        private readonly bool fromFuture;

        public FromImportStatement(DottedName root, IList<SymbolId> names, SymbolId[] asNames)
            : this(root, names, asNames, false) {
        }

        public static IList<SymbolId> Star {
            get { return FromImportStatement.star; }
        }

        public DottedName Root {
            get { return root; }
        }

        public IList<SymbolId> Names {
            get { return names; }
        }

        public IList<SymbolId> AsNames {
            get { return asNames; }
        }

        public FromImportStatement(DottedName root, IList<SymbolId> names, IList<SymbolId> asNames, bool fromFuture) {
            this.root = root;
            this.names = names;
            this.asNames = asNames;
            this.fromFuture = fromFuture;
        }

        public override object Execute(NameEnvironment environment) {
            Ops.ImportFrom(environment.Globals, root.MakeString(), SymbolTable.IdsToStrings(names));

            return NextStatement;
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);

            if (names == star) {
                cg.EmitCallerContext();
                cg.EmitString(root.MakeString());

                cg.EmitCall(typeof(Ops), "ImportStar");
            } else {
                cg.EmitModuleInstance();
                cg.EmitString(root.MakeString());
                
                Slot fromObj = cg.GetLocalTmp(typeof(object));
                cg.EmitStringArray(SymbolTable.IdsToStrings(names));

                if (asNames != null) {
                    cg.EmitStringArray(SymbolTable.IdsToStrings(asNames));
                    cg.EmitCall(typeof(Ops), "ImportFromAs");
                } else {
                    cg.EmitCall(typeof(Ops), "ImportFrom");
                }

                fromObj.EmitSet(cg);

                for (int i = 0; i < names.Count; i++) {
                    cg.EmitCallerContext();
                    fromObj.EmitGet(cg);
                    cg.EmitString(names[i].GetString());
                    cg.EmitCall(typeof(Ops), "ImportOneFrom");

                    SymbolId asName;
                    if (i < asNames.Count && asNames[i] != SymbolTable.Empty)
                        asName = asNames[i];
                    else
                        asName = names[i];

                    cg.EmitSet(asName);
                }
            }
        }

        public override void Walk(IAstWalker walker) {
            walker.Walk(this);
            walker.PostWalk(this);
        }

        internal bool IsFromFuture {
            get {
                return fromFuture;
            }
        }
    }

    public class GlobalStatement : Statement {
        private readonly SymbolId[] names;

        public GlobalStatement(SymbolId[] names) {
            this.names = names;
        }

        public IList<SymbolId> Names {
            get { return names; }
        }

        public override object Execute(NameEnvironment environment) {
            return NextStatement;
        }

        internal override void Emit(CodeGen cg) {
        }

        public override void Walk(IAstWalker walker) {
            walker.Walk(this);
            walker.PostWalk(this);
        }
    }

    public class DelStatement : Statement {
        private readonly Expression[] exprs;

        public DelStatement(Expression[] expressions) {
            this.exprs = expressions;
        }

        public IList<Expression> Expressions {
            get { return exprs; }
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
            foreach (Expression expr in exprs) {
                expr.EmitDel(cg);
            }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                foreach (Expression e in exprs) e.Walk(walker);
            }
            walker.PostWalk(this);
        }
    }

    public class RaiseStatement : Statement {
        private readonly Expression type, value, traceback;

        public RaiseStatement(Expression exceptionType, Expression exceptionValue, Expression traceBack) {
            this.type = exceptionType; this.value = exceptionValue; this.traceback = traceBack;
        }

        public Expression TraceBack {
            get { return traceback; }
        }

        public Expression Value {
            get { return this.value; }
        }


        public Expression ExceptionType {
            get { return type; }
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
            if (type == null && value == null && traceback == null) {
                cg.EmitCall(typeof(Ops), "Raise", Type.EmptyTypes);
                return;
            } else {
                cg.EmitExprOrNone(type);
                cg.EmitExprOrNone(value);
                cg.EmitExprOrNone(traceback);
                cg.EmitCall(typeof(Ops), "Raise", new Type[] { typeof(object), typeof(object), typeof(object) });
            }
        }
        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                if (type != null) type.Walk(walker);
                if (value != null) value.Walk(walker);
                if (traceback != null) traceback.Walk(walker);
            }
            walker.PostWalk(this);
        }

    }

    public class AssertStatement : Statement {
        private readonly Expression test, message;

        public AssertStatement(Expression test, Expression message) {
            this.test = test;
            this.message = message;
        }

        public Expression Message {
            get { return message; }
        }

        public Expression Test {
            get { return test; }
        }

        internal override void Emit(CodeGen cg) {
            if (Options.DebugMode) {
                cg.EmitPosition(this);
                cg.EmitTestTrue(test);
                Label endLabel = cg.DefineLabel();
                cg.Emit(OpCodes.Brtrue, endLabel);
                cg.EmitExprOrNone(message);
                cg.EmitConvertFromObject(typeof(string));
                cg.EmitCall(typeof(Ops), "AssertionError", new Type[] { typeof(string) });
                cg.Emit(OpCodes.Throw);
                cg.MarkLabel(endLabel);
            }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                test.Walk(walker);
                if (message != null) message.Walk(walker);
            }
            walker.PostWalk(this);
        }
    }



    public class ExecStatement : Statement {
        private readonly Expression code, locals, globals;

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "2#globals")]
        public ExecStatement(Expression code, Expression locals, Expression globals) {
            this.code = code;
            this.locals = locals;
            this.globals = globals;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Globals")]
        public Expression Globals {
            get { return globals; }
        }

        public Expression Locals {
            get { return locals; }
        }

        public Expression Code {
            get { return code; }
        }

        public bool NeedsLocalsDictionary() {
            return globals == null && locals == null;
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
            cg.EmitCallerContext();
            code.Emit(cg);
            if (locals == null && globals == null) {
                // pass in the current module's globals.
                cg.EmitCall(typeof(Ops), "Exec", new Type[] {
                        typeof(ICallerContext),
                        typeof(object),                        
                    });
            } else {
                // We must have globals now (locals is last and may be absent)
                Debug.Assert(globals != null);
                globals.Emit(cg);
                cg.EmitConvertFromObject(typeof(IAttributesDictionary));
                if (locals != null) {
                    locals.Emit(cg);        // emit locals
                } else {
                    cg.Emit(OpCodes.Dup);   // use globals
                }
                cg.EmitCall(typeof(Ops), "Exec", new Type[] {
                        typeof(ICallerContext),
                        typeof(object),
                        typeof(IAttributesDictionary),
                        typeof(object)
                    });
            }
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                code.Walk(walker);
                if (locals != null) locals.Walk(walker);
                if (globals != null) globals.Walk(walker);
            }
            walker.PostWalk(this);
        }

    }

    public class ReturnStatement : Statement {
        private readonly Expression expr;

        public ReturnStatement(Expression expression) {
            this.expr = expression;
        }

        public Expression Expression {
            get { return expr; }
        }

        public override object Execute(NameEnvironment environment) {
            return expr.Evaluate(environment);
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
            cg.EmitReturn(expr);
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                if (expr != null) expr.Walk(walker);
            }
            walker.PostWalk(this);
        }
    }

    public class YieldStatement : Statement {
        private readonly Expression expr;
        private readonly int index;
        private Label label;

        public YieldStatement(Expression expression, int index) {
            this.expr = expression;
            this.index = index;
        }

        public Expression Expression {
            get { return expr; }
        }

        public int Index {
            get { return index; }
        }

        public Label Label {
            get { return label; }
            set { label = value; }
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
            cg.EmitYield(expr, index, label);
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                expr.Walk(walker);
            }
            walker.PostWalk(this);
        }
    }

    public class PassStatement : Statement {
        public PassStatement() { }

        public override object Execute(NameEnvironment environment) {
            return NextStatement;
        }

        internal override void Emit(CodeGen cg) {
            cg.EmitPosition(this);
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                ;
            }
            walker.PostWalk(this);
        }

    }

    public class BreakStatement : Statement {
        public BreakStatement() { }

        internal override void Emit(CodeGen cg) {
            if (!cg.InLoop()) {
                cg.Context.AddError("'break' not properly in loop", this);
                return;
            }
            cg.EmitPosition(this);
            cg.EmitBreak();
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                ;
            }
            walker.PostWalk(this);
        }

    }

    public class ContinueStatement : Statement {
        public ContinueStatement() { }

        internal override void Emit(CodeGen cg) {
            if (!cg.InLoop()) {
                cg.Context.AddError("'continue' not properly in loop", this);
                return;
            }
            cg.EmitPosition(this);
            cg.EmitContinue();
        }

        public override void Walk(IAstWalker walker) {
            if (walker.Walk(this)) {
                ;
            }
            walker.PostWalk(this);
        }
    }
}




See more files for this project here

p4shelf

A feature in Visual Studio Team Studio that was immediately appealing to me was shelving. The goal of this tool is replicate that general functionality in Perforce.

Project homepage: http://code.google.com/p/p4shelf/
Programming language(s): C#,C++,Python
License: gpl2

  Binder.cs
  ClassDef.cs
  Expressions.cs
  FlowChecker.cs
  FuncDef.Generated.cs
  FuncDef.cs
  Node.cs
  Operator.Generated.cs
  Operator.cs
  ScopeStatement.Generated.cs
  ScopeStatement.cs
  Statements.cs
  Walker.Generated.cs