SetStack() public method

Modifies a value from the stack.
public SetStack ( int frame, int offset, object value ) : void
frame int Base address of stack frame
offset int Offset into stack frame
value object New value for stack variable
return void
        private void SetOperand(PrologContext context, int framePointer, ref ushort pc, object newValue)
        {
            int registerNumber = code[pc++];

            if (registerNumber < 0x80)
            {
                context.SetStack(framePointer, registerNumber, newValue);
            }
            else
            {
                object s         = Term.Deref(context.GetStack(framePointer, registerNumber & 0x7f));
                int    argNumber = code[pc++];
                object value     = ((Structure)s).Arguments[argNumber & 0x7f] = newValue;
                if (argNumber >= 0x80)
                {
                    context.SetStack(framePointer, code[pc++], value);
                }
            }
        }
        private ushort StartCallInstruction(PrologContext context, int framePointer, ref ushort pc, out ushort succeedPC,
                                            out IEnumerator <CutState> iterator)
        {
            int    iteratorRegister = code[pc++];
            ushort failPC           = GetUShort(ref pc);

            succeedPC = GetUShort(ref pc);
            iterator  = null;
            // Make the iterator.  How we do this depends on the opcode, so re-fetch it.
            switch ((Opcode)code[pc - CallTargetOffset])
            {
            case Opcode.CallWokenGoals:
            {
                if (context.GoalsHaveWoken)
                {
                    iterator = context.ProveAllWokenGoals().GetEnumerator();
                }
            }
            break;

            case Opcode.Call:
            {
                // It's a user-defined predicate call
                PredicateInfo calledPredicate = GetPredicate(ref pc);
                PushCallArgs(context, framePointer, predicate.Arity, ref pc);
                iterator = calledPredicate.StackCall(context).GetEnumerator();
            }
            break;

            case Opcode.CallPrimitive:
            {
                // It's a primitive call
                PrologPrimitives.PrimitiveImplementation implementation = GetPrimitive(ref pc);
                int arity = code[pc++];
                PushCallArgs(context, framePointer, arity, ref pc);
                iterator =
                    PrologPrimitives.StackCall(implementation, arity, context).GetEnumerator();
            }
            break;

            default:
                Debug.Assert(false, "Bad call opcode");
                break;
            }
            context.SetStack(framePointer, iteratorRegister, iterator);
            return(failPC);
        }
        private object DecodeOperand(PrologContext context, int framePointer, ref ushort pc)
        {
            int    registerNumber = code[pc++];
            object value          = Term.Deref(context.GetStack(framePointer, registerNumber & 0x7f));

            if (registerNumber < 0x80)
            {
                return(value);
            }
            int argNumber = code[pc++];

            value = ((Structure)value).Argument(argNumber & 0x7f);
            if (argNumber >= 0x80)
            {
                context.SetStack(framePointer, code[pc++], value);
            }
            return(value);
        }
        private const byte NoRegister      = 0xff;            // Target register meaning not to write to register

        // So here's append([], X, X). :
        //    MatchLiteral([], 0)
        //    MatchVarFirst(1)               % This is actually a no-op
        //    MatchVar(1, 2)
        //    Return
        //
        // And here's append([H|T], X, [H|T1]) :- append(T, X, T1).
        //    MatchStructure(dot, 2, L1, 0)
        //    MatchVarFirst(0>0>3)      % H is at 3
        //    MatchVarFirst(0>1>4)      % T is at 4
        // L1 MatchVarFirst(1)               % Actually a no-op
        //    MatchStructure(dot, 2, L2, 2)
        //    MatchVar(3, 2>0)
        //    MatchVarFirst(5, 2>1)        % T1 is at 5
        // L2 Call(6, Fail, Succeed, append/3, register(4), register(2), register(5))
        #endregion

        #region Interpreter
        internal IEnumerable <CutState> StackCall(PrologContext context)
        {
            int traceMark = context.MarkTrail();
            // On entry, the stack pointer points at the base of our arguments.
            int    framePointer        = context.MakeFrame(frameSize);
            ushort pc                  = 0;
            ushort writeModeEndAddress = 0; // We're in write mode if pc < writeModeEndAddress.
// ReSharper disable TooWideLocalVariableScope
            // Resharper is confused - can't move this inside the while loop, or its lifetime changes.
            ushort endOfBuilds;         // PC of last call instruction whose arguments have been built.

// ReSharper restore TooWideLocalVariableScope

            while (true)
            {
                switch ((Opcode)code[pc++])
                {
                    #region Head opcodes
                case Opcode.MatchLiteral:
                {
                    object literal = GetLiteral(ref pc);
                    if (pc < writeModeEndAddress)
                    {
                        // Write mode
                        SetOperand(context, framePointer, ref pc, literal);
                    }
                    else
                    {
                        // Read mode
                        if (!Term.Unify(DecodeOperand(context, framePointer, ref pc), literal, context))
                        {
                            goto fail;
                        }
                    }
                }
                break;

                case Opcode.MatchVarFirst:
                {
                    if (pc < writeModeEndAddress)
                    {
                        // Write mode
                        Symbol name     = GetSymbol(ref pc);
                        int    register = code[pc++];
                        var    l        = new LogicVariable(name);
                        SetOperand(context, framePointer, ref pc, l);
                        if (register != NoRegister)
                        {
                            context.SetStack(framePointer, register, l);
                        }
                    }
                    else
                    {
                        pc += 2;         // Skip over variable name.
                        int register = code[pc++];
                        // Read mode
                        object operand = DecodeOperand(context, framePointer, ref pc);
                        if (register != NoRegister)
                        {
                            context.SetStack(framePointer, register, operand);
                        }
                    }
                }
                break;

                case Opcode.MatchVar:
                {
                    object register = Register(context, framePointer, pc++);
                    if (pc < writeModeEndAddress)
                    {
                        // Write mode
                        SetOperand(context, framePointer, ref pc, register);
                    }
                    else
                    {
                        // Read mode
                        if (!Term.Unify(DecodeOperand(context, framePointer, ref pc), register, context))
                        {
                            goto fail;
                        }
                    }
                }
                break;

                case Opcode.MatchStructure:
                {
                    Symbol functor    = GetSymbol(ref pc);
                    int    arity      = code[pc++];
                    ushort endAddress = GetUShort(ref pc);

                    if (pc < writeModeEndAddress)
                    {
                        // Write mode
                        SetOperand(context, framePointer, ref pc, new Structure(functor, new object[arity]));
                    }
                    else
                    {
                        // Read mode
                        object arg = DecodeOperand(context, framePointer, ref pc);
                        var    s   = arg as Structure;
                        if (s == null || !s.IsFunctor(functor, arity))
                        {
                            var l = arg as LogicVariable;
                            if (l == null)
                            {
                                goto fail;
                            }
                            l.UnifyWithStructure(new Structure(functor, new object[arity]));
                            writeModeEndAddress = endAddress;
                        }
                    }
                }
                break;
                    #endregion

                    #region Body opcodes: structure building
                case Opcode.BuildStructure:
                {
                    Symbol functor = GetSymbol(ref pc);
                    int    arity   = code[pc++];
                    SetOperand(context, framePointer, ref pc,
                               new Structure(functor, new object[arity]));
                }
                break;

                case Opcode.BuildLiteral:
                    SetOperand(context, framePointer, ref pc, GetLiteral(ref pc));
                    break;

                case Opcode.BuildVar:
                {
                    Symbol name = GetSymbol(ref pc);
                    SetOperand(context, framePointer, ref pc, new LogicVariable(name));
                }
                break;

                case Opcode.BuildReg:
                    object registerValue = Register(context, framePointer, pc++);
                    SetOperand(context, framePointer, ref pc, registerValue);
                    break;
                    #endregion

                    #region Body: control flow
                case Opcode.CallWokenGoals:
                case Opcode.Call:
                case Opcode.CallPrimitive:
                    endOfBuilds = pc;
                    // ReSharper disable once InconsistentNaming
                    ushort succeedPC;
                    IEnumerator <CutState> iterator;
                    var failPC = StartCallInstruction(context, framePointer, ref pc, out succeedPC, out iterator);
                    while (true)
                    {
                        if (iterator == null || iterator.MoveNext())
                        {
                            // Call succeeds
                            if (succeedPC == SuccessContinuationPC)
                            {
                                yield return(CutState.Continue);

                                // If we get here, then our caller is requesting a redo
                                // Fall through and continue this iterator.
                                if (iterator == null)
                                {
                                    goto fail;                     // Kluge: special case to handle CallWokenGoals instruction where there are no woken goals.
                                }
                            }
                            else
                            {
                                if (succeedPC > endOfBuilds)
                                {
                                    // Haven't run the build instructions for next goal, so break out and run them.
                                    break;
                                }
                                pc = (ushort)(succeedPC + 1);   // StartCallInstruction assumes we've skipped over the opcode.
                                // succeedPC is address of call/callprimitive instruction; next byte is iterator register
                                failPC = this.StartCallInstruction(context, framePointer, ref pc, out succeedPC, out iterator);
                                // Continue while loop
                            }
                        }
                        else
                        {
                            // Call fails
                            switch (failPC)
                            {
                            case FailContinuationPC:
                                goto fail;

                            case CutContinuationPC:
                                goto cut;

                            default:
                                // failPC is address of call/callprimitive instruction; next byte is iterator register
                                pc       = (ushort)(failPC + 1);    // +1 because we're skipping over the opcode
                                iterator =
                                    (IEnumerator <CutState>)context.GetStack(framePointer, code[pc++]);
                                if (iterator == null)          // Kluge: special case to handle CallWokenGoals instruction where there are no woken goals.
                                {
                                    goto fail;
                                }

                                failPC    = GetUShort(ref pc);
                                succeedPC = GetUShort(ref pc);
                                break;
                            }
                        }
                    }
                    break;
                    #endregion

                default:
                    Debug.Assert(false, "Bad opcode in byte compiled Prolog rule, pc=" + (pc - 1) + ", opcode=" + ((Opcode)code[pc - 1]));
                    break;
                }
            }

            // The while loop above never terminates normally; it only yeilds or branches to one of the following labels
cut:
            context.PopFrame(framePointer);
            context.RestoreVariables(traceMark);
            yield return(CutState.ForceFail);

fail:
            context.PopFrame(framePointer);
            context.RestoreVariables(traceMark);
        }