private static GmState StepPrim(GmInstruction.Prim instruction, GmState state)
        {
            if (!PrimHandlers.TryGetValue(instruction.Type, out var handler))
            {
                throw new KeyNotFoundException(instruction.Type.ToString());
            }

            return(handler(state));
        }
 private static PrettyPrinter.Node ShowStack(GmState state) =>
 Append(
     Str("Stk ["),
     Indent(Interleave(new PrettyPrinter.Node.Newline(), state.Stack.Select(addr => Append(
                                                                                ShowAddr(addr),
                                                                                Str(": "),
                                                                                ShowNode(state, addr)
                                                                                )))),
     Str(" ]")
     );
        public IEnumerable <GmState> Evaluate(GmState state)
        {
            yield return(state);

            while (!IsComplete(state))
            {
                state = Step(state);

                yield return(state);
            }
        }
        private static GmState StepUnwind(GmInstruction.Unwind _, GmState state)
        {
            var head     = state.Stack.Peek();
            var headNode = state.Heap[head];

            return(headNode switch
            {
                GmNode.Number num => UnwindNum(num, state),
                GmNode.Application ap => UnwindAp(ap, state),
                GmNode.Global global => UnwindGlobal(global, state),
                GmNode.Indirection ind => UnwindInd(ind, state),

                _ => throw new ArgumentOutOfRangeException(nameof(headNode))
            });
        private static GmState Step(GmState state)
        {
            var(instruction, newState) = state.DequeueInstruction();

            return(instruction switch
            {
                GmInstruction.PushGlobal pushGlobal => StepPushGlobal(pushGlobal, newState),
                GmInstruction.PushInt pushInt => StepPushInt(pushInt, newState),
                GmInstruction.MkAp mkAp => StepMkAp(mkAp, newState),
                GmInstruction.Push push => StepPush(push, newState),
                GmInstruction.Update update => StepUpdate(update, newState),
                GmInstruction.Pop pop => StepPop(pop, newState),
                GmInstruction.Slide slide => StepSlide(slide, newState),
                GmInstruction.Alloc alloc => StepAlloc(alloc, newState),
                GmInstruction.Unwind unwind => StepUnwind(unwind, newState),
                GmInstruction.Eval eval => StepEval(eval, newState),
                GmInstruction.Prim prim => StepPrim(prim, newState),
                GmInstruction.Cond cond => StepCond(cond, newState),

                _ => throw new ArgumentOutOfRangeException(nameof(instruction))
            });
 private static GmState BoxBool(bool value, GmState state)
 {
     return(state.AllocateAndPush(new GmNode.Number(value ? 1 : 0)));
 }
 private static int UnboxNum(int addr, GmState state)
 {
     return(((GmNode.Number)state.Heap[addr]).Value);
 }
 private static GmState BoxNum(int value, GmState state)
 {
     return(state.AllocateAndPush(new GmNode.Number(value)));
 }
 public static string Print(GmState state) => PrettyPrinter.Display(ShowState(state));
 private static PrettyPrinter.Node ShowNode(GmState state, int addr) =>
 state.Heap[addr] switch
 {
 private static PrettyPrinter.Node ShowState(GmState state) => Append(ShowStack(state), Newline());
 private static bool IsComplete(GmState state)
 {
     return(state.Code.IsEmpty);
 }