Ejemplo n.º 1
0
        private void Build(DIteratorLiteral node, Hints hints, CompilerContext ctx)
        {
            var dec = new DFunctionDeclaration(node.Location)
            {
                Body = node.YieldBlock
            };

            Build(dec, hints.Append(Iterator), ctx);
        }
Ejemplo n.º 2
0
        private void BuildCoalesce(DAssignment node, Hints hints, CompilerContext ctx)
        {
            CheckTarget(node.Target);

            var exitLab = cw.DefineLabel();

            Build(node.Target, hints.Remove(Last).Append(Push), ctx);
            cw.Brtrue(exitLab);
            Build(node.Value, hints.Append(Push), ctx);
            Build(node.Target, hints.Append(Pop), ctx);
            cw.MarkLabel(exitLab);
            cw.Nop();

            if (hints.Has(Push))
            {
                cw.Dup();
            }
        }
Ejemplo n.º 3
0
        private void Build(DMemberCheck node, Hints hints, CompilerContext ctx)
        {
            Build(node.Target, hints.Append(Push), ctx);
            AddLinePragma(node);
            var nameId = GetMemberNameId(node.Name);

            cw.HasMember(nameId);
            PopIf(hints);
        }
Ejemplo n.º 4
0
    private bool BuildSetterAutoAssign(DAssignment node, Hints hints, CompilerContext ctx)
    {
        var acc = (DAccess)node.Target;

        Build(acc.Target, hints.Remove(Last).Append(Push), ctx);
        cw.GetMember(Builtins.Setter(acc.Name));
        cw.FunPrep(1);
        EmitGetter(acc.Target, acc.Name, hints, ctx);
        Build(node.Value, hints.Append(Push), ctx);
        EmitBinaryOp(node.AutoAssign !.Value);
        cw.FunArgIx(0);
        cw.FunCall(1);
        PopIf(hints);
        return(true);
    }
Ejemplo n.º 5
0
        private void Build(DPrivateScope node, Hints hints, CompilerContext ctx)
        {
            if (privateScope)
            {
                AddError(CompilerError.PrivateScopeNested, node.Location);
            }

            if (currentScope != globalScope)
            {
                AddError(CompilerError.PrivateScopeOnlyGlobal, node.Location);
            }

            privateScope = true;
            Build(node.Block, hints.Append(NoScope), ctx);
            privateScope = false;
        }
Ejemplo n.º 6
0
        private void Build(DYieldBlock node, Hints hints, CompilerContext ctx)
        {
            for (var i = 0; i < node.Elements.Count; i++)
            {
                var n    = node.Elements[i];
                var last = i == node.Elements.Count - 1;
                Build(n, hints.Append(Push), ctx);
                AddLinePragma(node);
                cw.Yield();

                if (last)
                {
                    PushIf(hints);
                }
            }
        }
Ejemplo n.º 7
0
    private void Build(DTryCatch node, Hints hints, CompilerContext ctx)
    {
        var gotcha = cw.DefineLabel();

        cw.Start(gotcha);
        Build(node.Expression, hints, ctx);

        AddLinePragma(node);
        cw.End();
        var skip = cw.DefineLabel();

        cw.Br(skip);
        cw.MarkLabel(gotcha);

        StartScope(ScopeKind.Lexical, node.Catch.Location);
        //We are inside a catch, we need preserve an exception object for
        //possible rethrows
        cw.Dup();
        var a = AddVariable();

        cw.PopVar(a);
        ctx.Errors.Push(a);

        if (node.BindVariable is not null)
        {
            AddLinePragma(node.BindVariable);

            if (node.BindVariable.Value is not "_")
            {
                var sv = AddVariable(node.BindVariable.Value, node.Catch.Location, VarFlags.Const);
                cw.PopVar(sv);
            }
            else
            {
                cw.Pop();
            }
        }

        Build(node.Catch, hints.Append(Catch), ctx);

        ctx.Errors.Pop();
        EndScope();

        cw.MarkLabel(skip);
        AddLinePragma(node);
        cw.Nop();
    }
Ejemplo n.º 8
0
    private void Build(DMatch node, Hints hints, CompilerContext ctx)
    {
        ValidateMatch(node);
        StartScope(ScopeKind.Lexical, node.Location);

        ctx = new(ctx)
        {
            MatchExit = cw.DefineLabel()
        };

        var sys  = AddVariable();
        var push = hints.Append(Push);

        if (node.Expression != null)
        {
            Build(node.Expression, push.Remove(Last), ctx);
        }

        cw.PopVar(sys);
        var sysVar = new ScopeVar(sys);

        foreach (var e in node.Entries)
        {
            BuildEntry(e, sysVar, push, ctx);
        }

        //It is some kind of a hack, but Expression can be null
        //only if this match is inside try/catch
        if (node.Expression != null)
        {
            ThrowError(DyError.MatchFailed);
            cw.Fail();
        }
        else
        {
            cw.PushVar(sysVar);
            cw.Fail();
        }

        cw.MarkLabel(ctx.MatchExit);
        cw.Nop();
        PopIf(hints);
        EndScope();
    }
Ejemplo n.º 9
0
        private void Build(DReturn node, Hints hints, CompilerContext ctx)
        {
            if (ctx.FunctionExit.IsEmpty())
            {
                AddError(CompilerError.ReturnNotAllowed, node.Location);
            }

            if (node.Expression != null)
            {
                Build(node.Expression, hints.Append(Push), ctx);
            }
            else
            {
                cw.PushNil();
            }

            AddLinePragma(node);
            cw.Br(ctx.FunctionExit);
        }
Ejemplo n.º 10
0
        private bool CanBeOptimized(DBindingBase node, Hints hints, CompilerContext ctx)
        {
            if (!options.NoOptimizations &&
                node.Init != null &&
                node.Init.NodeType == NodeType.Tuple &&
                node.Pattern.NodeType == NodeType.TuplePattern &&
                node.Init.GetElementCount() == node.Pattern.GetElementCount())
            {
                var init = (DTupleLiteral)node.Init;
                var pat  = (DTuplePattern)node.Pattern;

                for (var i = 0; i < pat.Elements.Count; i++)
                {
                    if (pat.Elements[i].NodeType != NodeType.NamePattern)
                    {
                        return(false);
                    }
                }

                for (var i = 0; i < init.Elements.Count; i++)
                {
                    Build(init.Elements[i], hints.Append(Push), ctx);
                }

                for (var i = 0; i < pat.Elements.Count; i++)
                {
                    var e    = pat.Elements[pat.Elements.Count - i - 1];
                    var addr = node.NodeType == NodeType.Binding
                        ? AddVariable(e.GetName(), e, VarFlags.None)
                        : GetVariableToAssign(e.GetName(), e, false);
                    if (addr == -1 && node.NodeType == NodeType.Rebinding)
                    {
                        addr = AddVariable(e.GetName(), e, VarFlags.None);
                    }
                    cw.PopVar(addr);
                }

                return(true);
            }

            return(false);
        }
Ejemplo n.º 11
0
    private void Build(DBreak node, Hints hints, CompilerContext ctx)
    {
        if (ctx.BlockExit.IsEmpty())
        {
            AddError(CompilerError.NoEnclosingLoop, node.Location);
        }

        if (node.Expression is not null)
        {
            Build(node.Expression, hints.Append(Push), ctx);
        }
        else
        {
            cw.PushNil();
        }

        CallAutosForKind(ScopeKind.Loop);
        AddLinePragma(node);
        cw.Br(ctx.BlockBreakExit);
    }
Ejemplo n.º 12
0
        private void Build(DUnaryOperation node, Hints hints, CompilerContext ctx)
        {
            Build(node.Node, hints.Append(Push), ctx);
            AddLinePragma(node);

            if (node.Operator == UnaryOperator.Neg)
            {
                cw.Neg();
            }
            else if (node.Operator == UnaryOperator.Not)
            {
                cw.Not();
            }
            else if (node.Operator == UnaryOperator.BitwiseNot)
            {
                cw.BitNot();
            }

            PopIf(hints);
        }
Ejemplo n.º 13
0
    private void Build(DThrow node, Hints hints, CompilerContext ctx)
    {
        if (node.Expression is not null)
        {
            Build(node.Expression, hints.Append(Push), ctx);
            AddLinePragma(node);
            cw.Fail();
        }
        else
        {
            if (!hints.Has(Catch) || ctx.Errors.Count is 0)
            {
                AddError(CompilerError.InvalidRethrow, node.Location);
            }
            else
            {
                cw.PushVar(new ScopeVar(ctx.Errors.Peek()));
            }

            AddLinePragma(node);
            cw.Fail();
        }
    }
Ejemplo n.º 14
0
        private void Build(DBreak node, Hints hints, CompilerContext ctx)
        {
            if (ctx.BlockExit.IsEmpty())
            {
                AddError(CompilerError.NoEnclosingLoop, node.Location);
            }

            if (node.Expression != null)
            {
                Build(node.Expression, hints.Append(Push), ctx);
                if (!hints.Has(ExpectPush))
                {
                    cw.Pop();
                }
            }
            else if (hints.Has(ExpectPush))
            {
                cw.PushNil();
            }

            AddLinePragma(node);
            cw.Br(ctx.BlockBreakExit);
        }
Ejemplo n.º 15
0
    private void Build(DWhile node, Hints hints, CompilerContext ctx)
    {
        ctx = new(ctx)
        {
            BlockSkip      = cw.DefineLabel(),
            BlockExit      = cw.DefineLabel(),
            BlockBreakExit = cw.DefineLabel()
        };
        StartScope(ScopeKind.Loop, node.Location);
        var iter = cw.DefineLabel();

        hints = hints.Remove(Last);
        var nh = hints.Remove(Push);

        if (node.DoWhile)
        {
            Build(node.Body, nh, ctx);
        }

        cw.MarkLabel(iter);
        Build(node.Condition, hints.Append(Push), ctx);
        cw.Brfalse(ctx.BlockExit);

        Build(node.Body, nh, ctx);

        cw.MarkLabel(ctx.BlockSkip);
        cw.Br(iter);

        cw.MarkLabel(ctx.BlockExit);
        cw.PushNil();
        AddLinePragma(node);

        cw.MarkLabel(ctx.BlockBreakExit);
        PopIf(hints);
        cw.Nop();
        EndScope();
    }
Ejemplo n.º 16
0
        private void Build(DFor node, Hints hints, CompilerContext ctx)
        {
            ctx = new CompilerContext(ctx)
            {
                BlockSkip      = cw.DefineLabel(),
                BlockExit      = cw.DefineLabel(),
                BlockBreakExit = cw.DefineLabel()
            };
            StartScope(false, node.Location);
            hints = hints.Remove(Last);

            var inc = -1;

            if (node.Pattern.NodeType == NodeType.NamePattern &&
                GetTypeHandle(null, node.Pattern.GetName(), out var _, out var _) != CompilerError.None)
            {
                inc = AddVariable(node.Pattern.GetName(), node.Pattern, VarFlags.None);
            }

            var sys      = AddVariable();
            var initSkip = cw.DefineLabel();

            Build(node.Target, hints.Append(Push), ctx);

            cw.Briter(initSkip);

            cw.GetMember(GetMemberNameId(Builtins.Iterator));

            cw.FunPrep(0);
            cw.FunCall(0);

            cw.MarkLabel(initSkip);
            cw.PopVar(sys);

            var iter = cw.DefineLabel();

            cw.MarkLabel(iter);
            cw.PushVar(new ScopeVar(sys));

            cw.FunPrep(0);
            cw.FunCall(0);

            cw.Brterm(ctx.BlockExit);

            if (inc > -1)
            {
                cw.PopVar(inc);
            }
            else
            {
                BuildPattern(node.Pattern, hints, ctx);
                cw.Brfalse(ctx.BlockSkip);
            }

            if (node.Guard != null)
            {
                Build(node.Guard, hints.Append(Push), ctx);
                cw.Brfalse(ctx.BlockSkip);
            }

            var nh = hints.Has(Push) ? hints.Remove(Push).Append(ExpectPush) : hints.Remove(ExpectPush);

            Build(node.Body, nh, ctx);

            cw.MarkLabel(ctx.BlockSkip);
            cw.Br(iter);

            cw.MarkLabel(ctx.BlockExit);
            cw.Pop();
            PushIf(hints);
            AddLinePragma(node);

            cw.MarkLabel(ctx.BlockBreakExit);
            cw.Nop();
            EndScope();
        }
Ejemplo n.º 17
0
    private void Build(DFor node, Hints hints, CompilerContext ctx)
    {
        ctx = new(ctx)
        {
            BlockSkip      = cw.DefineLabel(),
            BlockExit      = cw.DefineLabel(),
            BlockBreakExit = cw.DefineLabel()
        };

        if (TryOptimizeFor(node, hints, ctx))
        {
            return;
        }

        StartScope(ScopeKind.Loop, node.Location);
        hints = hints.Remove(Last);

        var inc = false;

        if (node.Pattern.NodeType == NodeType.NamePattern && !char.IsUpper(((DNamePattern)node.Pattern).Name[0] !))
        {
            inc = true;
        }

        var sys      = AddVariable();
        var initSkip = cw.DefineLabel();

        Build(node.Target, hints.Append(Push), ctx);
        cw.Briter(initSkip);
        cw.GetMember(Builtins.Iterate);
        cw.CallNullaryFunction();

        cw.MarkLabel(initSkip);
        cw.GetIter();
        cw.PopVar(sys);

        var iter = cw.DefineLabel();

        cw.MarkLabel(iter);
        cw.PushVar(new ScopeVar(sys));
        cw.CallNullaryFunction();
        cw.Brterm(ctx.BlockExit);

        if (inc)
        {
            var ai = AddVariable(((DNamePattern)node.Pattern).Name !, node.Pattern.Location, VarFlags.None);
            cw.PopVar(ai);
        }
        else
        {
            BuildPattern(node.Pattern, hints, ctx);
            cw.Brfalse(ctx.BlockSkip);
        }

        if (node.Guard != null)
        {
            Build(node.Guard, hints.Append(Push), ctx);
            cw.Brfalse(ctx.BlockSkip);
        }

        var nh = hints.Remove(Push);

        Build(node.Body, nh, ctx);

        cw.MarkLabel(ctx.BlockSkip);
        cw.Br(iter);

        cw.MarkLabel(ctx.BlockExit);
        cw.Pop();
        cw.PushNil();
        AddLinePragma(node);

        cw.MarkLabel(ctx.BlockBreakExit);
        PopIf(hints);
        cw.Nop();
        EndScope();
    }
Ejemplo n.º 18
0
        private void Build(DStringLiteral node, Hints hints, CompilerContext ctx)
        {
            if (node.Chunks == null && NoPush(node, hints))
            {
                return;
            }

            if (node.Chunks != null)
            {
                cw.Type(new TypeHandle(DyType.String, true));
                cw.GetMember(GetMemberNameId("concat"));
                cw.FunPrep(node.Chunks.Count);

                for (var i = 0; i < node.Chunks.Count; i++)
                {
                    var c = node.Chunks[i];

                    if (c.IsCode)
                    {
                        var p = new InternalParser(new Scanner(SourceBuffer.FromString(c.GetContent())));
                        p.Parse();

                        if (p.Errors.Count > 0)
                        {
                            foreach (var e in p.Errors)
                            {
                                AddError(CompilerError.CodeIslandInvalid, new Location(node.Location.Line, node.Location.Column + e.Column), e.Message);
                            }
                        }
                        else
                        {
                            if (p.Root.Nodes == null || p.Root.Nodes.Count == 0)
                            {
                                AddError(CompilerError.CodeIslandEmpty, node.Location);
                            }
                            else
                            {
                                corrections.Push(node.Location);
                                Build(p.Root.Nodes[0], hints.Append(Push), ctx);
                                corrections.Pop();
                            }
                        }
                    }
                    else
                    {
                        cw.Push(c.GetContent());
                    }

                    cw.FunArgIx(i);
                }

                AddLinePragma(node);
                cw.FunCall(node.Chunks.Count);
            }
            else
            {
                AddLinePragma(node);
                cw.Push(node.Value);
            }

            PopIf(hints);
        }
Ejemplo n.º 19
0
        private void Build(DIndexer node, Hints hints, CompilerContext ctx)
        {
            var push = hints.Remove(Pop).Append(Push);

            if (node.Index.NodeType == NodeType.String && node.Index is DStringLiteral str && str.Chunks == null)
            {
                if (node.Target.NodeType == NodeType.Name)
                {
                    var nm = node.Target.GetName();
                    var sv = GetVariable(nm, node.Target, err: false);

                    if ((sv.Data & VarFlags.Module) == VarFlags.Module && referencedUnits.TryGetValue(nm, out var ru))
                    {
                        if (ru.Unit.ExportList.TryGetValue(str.Value, out var var))
                        {
                            if ((var.Data & VarFlags.Private) == VarFlags.Private)
                            {
                                AddError(CompilerError.PrivateNameAccess, node.Location, str.Value);
                            }

                            AddLinePragma(node);
                            cw.PushVar(new ScopeVar(ru.Handle | (var.Address >> 8) << 8, VarFlags.External));
                            return;
                        }
                        else if (GetTypeHandle(nm, str.Value, out var handle, out var std) == CompilerError.None)
                        {
                            GetMemberNameId(str.Value);
                            AddLinePragma(node);
                            cw.Type(new TypeHandle(handle, std));
                            return;
                        }
                    }
                }

                Build(node.Target, push, ctx);
                cw.Push(str.Value);

                if (!hints.Has(Pop))
                {
                    cw.Get();
                    PopIf(hints);
                }
                else
                {
                    cw.Set();
                }

                return;
            }

            Build(node.Target, push, ctx);

            if (node.Index.NodeType == NodeType.Range)
            {
                if (hints.Has(Pop))
                {
                    AddError(CompilerError.RangeIndexNotSupported, node.Index.Location);
                }

                var r = (DRange)node.Index;
                cw.GetMember(GetMemberNameId("slice"));
                cw.FunPrep(2);
                Build(r.From, hints.Append(Push), ctx);
                cw.FunArgIx(0);
                Build(r.To, hints.Append(Push), ctx);
                Build(r.From, hints.Append(Push), ctx);
                cw.Sub();
                cw.FunArgIx(1);

                AddLinePragma(node);
                cw.FunCall(2);
                PopIf(hints);
            }
            else
            {
                Build(node.Index, push, ctx);
                AddLinePragma(node);

                if (!hints.Has(Pop))
                {
                    cw.Get();
                    PopIf(hints);
                }
                else
                {
                    cw.Set();
                }
            }
        }
Ejemplo n.º 20
0
        private void BuildFunctionBody(int addr, DFunctionDeclaration node, Hints hints, CompilerContext ctx)
        {
            var iter     = hints.Has(Iterator);
            var args     = CompileFunctionParameters(node.Parameters);
            var argCount = args.Length;

            StartFun(node.Name, args, argCount);

            if (node.IsStatic && !node.IsMemberFunction)
            {
                AddError(CompilerError.StaticOnlyMethods, node.Location, node.Name);
            }

            var startLabel  = cw.DefineLabel();
            var funEndLabel = cw.DefineLabel();

            //Functions are always compiled "in place": if we find a function while looping
            //through AST node we compile right away. That is the reason why we need to emit an
            //additional goto so that we can jump over this function.
            var funSkipLabel = cw.DefineLabel();

            cw.Br(funSkipLabel);

            ctx = new CompilerContext
            {
                FunctionAddress   = counters.Count | (addr >> 8) << 8,
                    FunctionStart = startLabel,
                    FunctionExit  = funEndLabel,
                    Function      = node
            };

            hints = Function | Push;

            //Start of a physical (and not compiler time) lexical scope for a function
            StartScope(fun: true, loc: node.Location);
            StartSection();

            AddLinePragma(node);
            var address       = cw.Offset;
            var variadicIndex = -1;

            //Initialize function arguments
            for (var i = 0; i < args.Length; i++)
            {
                var arg = args[i];

                if (arg.IsVarArg)
                {
                    variadicIndex = i;
                }

                AddVariable(arg.Name, node, data: VarFlags.Argument);
            }

            //If this is a member function we add an additional system variable that
            //would return an instance of an object to which this function is coupled
            //(same as this in C#)
            if (node.IsMemberFunction && !node.IsStatic)
            {
                var va = AddVariable("this", node, data: VarFlags.Const | VarFlags.This);
                cw.This();
                cw.PopVar(va);
            }

            //Start of a function that is used for tail call optimization
            cw.MarkLabel(startLabel);

            //This is an autogenerated constructor
            if (node.IsConstructor)
            {
                GenerateConstructor(node, hints, ctx);
            }
            else
            {
                //Compile function body
                if (node.IsIterator)
                {
                    var dec = new DFunctionDeclaration(node.Location)
                    {
                        Name = node.Name, Body = node.Body
                    };
                    Build(dec, hints.Append(Iterator), ctx);
                }
                else
                {
                    Build(node.Body, hints.Append(Last), ctx);
                }
            }

            //Return from a function. Any function execution should get here, it is not possible
            //to break early. An early return would actually goto here, where a real return (OpCode.Ret)
            //is executed. This is a function epilogue.
            cw.MarkLabel(funEndLabel);

            //If this is an iterator function push a terminator at the end (and pop a normal value)
            if (iter)
            {
                cw.Pop();
                cw.PushNilT();
            }

            cw.Ret();
            cw.MarkLabel(funSkipLabel);

            AddLinePragma(node);

            //Close all lexical scopes and debugging information
            var funHandle = unit.Layouts.Count;
            var ss        = EndFun(funHandle);

            unit.Layouts.Add(new MemoryLayout(currentCounter, ss, address));
            EndScope();
            EndSection();

            //Iterators are a separate type (based on function through)
            if (iter)
            {
                cw.NewIter(funHandle);
            }
            else
            {
                if (variadicIndex > -1)
                {
                    cw.Aux(variadicIndex);
                    cw.NewFunV(funHandle);
                }
                else
                {
                    cw.NewFun(funHandle);
                }
            }
        }
Ejemplo n.º 21
0
        private void Build(DBinding node, Hints hints, CompilerContext ctx)
        {
            if (CanBeOptimized(node, hints, ctx))
            {
                PushIf(hints);
                return;
            }

            if (node.Init != null)
            {
                Build(node.Init, hints.Append(Push), ctx);
            }
            else
            {
                cw.PushNil();
            }

            if (node.Pattern.NodeType == NodeType.NamePattern)
            {
                AddLinePragma(node);
                var flags = node.Constant ? VarFlags.Const : VarFlags.None;
                var a     = AddVariable(node.Pattern.GetName(), node, flags);
                cw.PopVar(a);
            }
            else
            {
                if (node.Init == null)
                {
                    AddError(CompilerError.BindingPatternNoInit, node.Location);
                }
                else
                {
                    int n;
                    if ((n = node.Pattern.GetElementCount()) == node.Init.GetElementCount() && n != -1 &&
                        IsPureBinding(node.Pattern))
                    {
                        var xs    = node.Pattern.ListElements();
                        var ys    = node.Init.ListElements();
                        var flags = node.Constant ? VarFlags.Const : VarFlags.None;

                        for (var i = 0; i < xs.Count; i++)
                        {
                            var x = xs[i];
                            var y = ys[i];
                            Build(y, hints.Append(Push), ctx);
                            AddLinePragma(node);

                            if (x.NodeType != NodeType.WildcardPattern)
                            {
                                var a = AddVariable(x.GetName(), node, flags);
                                cw.PopVar(a);
                            }
                            else
                            {
                                cw.Pop();
                            }
                        }

                        PushIf(hints);
                        return;
                    }
                }

                var nh = hints.Append(OpenMatch);

                if (node.Constant)
                {
                    nh = nh.Append(Const);
                }

                if (node.Init != null)
                {
                    CheckPattern(node.Pattern, node.Init.GetElementCount(), node.Pattern.GetElementCount());
                }

                BuildPattern(node.Pattern, nh, ctx);
                var skip = cw.DefineLabel();
                cw.Brtrue(skip);
                cw.Fail(DyErrorCode.MatchFailed);
                cw.MarkLabel(skip);
                cw.Nop();
            }

            PushIf(hints);
        }
Ejemplo n.º 22
0
 private void Build(DThrow node, Hints hints, CompilerContext ctx)
 {
     Build(node.Expression, hints.Append(Push), ctx);
     AddLinePragma(node);
     cw.Fail();
 }
Ejemplo n.º 23
0
        private void Build(DBinaryOperation node, Hints hints, CompilerContext ctx)
        {
            var termLab = default(Label);
            var exitLab = default(Label);

            switch (node.Operator)
            {
            case BinaryOperator.Coalesce:
                exitLab = cw.DefineLabel();
                Build(node.Left, hints.Remove(Last).Append(Push), ctx);
                cw.Dup();
                cw.Brtrue(exitLab);
                cw.Pop();
                Build(node.Right, hints.Append(Push), ctx);
                cw.MarkLabel(exitLab);
                cw.Nop();
                break;

            case BinaryOperator.And:
                Build(node.Left, hints.Remove(Last).Append(Push), ctx);
                termLab = cw.DefineLabel();
                exitLab = cw.DefineLabel();
                cw.Brfalse(termLab);
                Build(node.Right, hints.Remove(Last).Append(Push), ctx);
                AddLinePragma(node);
                cw.Br(exitLab);
                cw.MarkLabel(termLab);
                AddLinePragma(node);
                cw.Push(false);
                cw.MarkLabel(exitLab);
                cw.Nop();
                break;

            case BinaryOperator.Or:
                Build(node.Left, hints.Remove(Last).Append(Push), ctx);
                termLab = cw.DefineLabel();
                exitLab = cw.DefineLabel();
                cw.Brtrue(termLab);
                Build(node.Right, hints.Remove(Last).Append(Push), ctx);
                AddLinePragma(node);
                cw.Br(exitLab);
                cw.MarkLabel(termLab);
                AddLinePragma(node);
                cw.Push(true);
                cw.MarkLabel(exitLab);
                cw.Nop();
                break;

            case BinaryOperator.Is:
            {
                var pat = (DPattern)node.Right;
                AddLinePragma(node);
                PreinitPattern(pat, hints.Remove(Last));
                Build(node.Left, hints.Remove(Last).Append(Push), ctx);
                BuildPattern(pat, hints, ctx);
            }
            break;

            default:
                Build(node.Left, hints.Remove(Last).Append(Push), ctx);
                Build(node.Right, hints.Remove(Last).Append(Push), ctx);
                AddLinePragma(node);
                EmitBinaryOp(node.Operator);
                break;
            }

            PopIf(hints);
        }