Beispiel #1
0
 public ReorderInstruction(string name,
                           IEnumerable <Type> inputTypes,
                           IEnumerable <Type> outputTypes)
     : base(name, inputTypes, outputTypes, null)
 {
     innerInstruction
         = new InstructionFunc(stack =>
                               this.instruction.Apply(stack));
 }
Beispiel #2
0
        public override void LoadInstructions()
        {
            foreach (var op in new [] { "+", "-", "*", "/", ">", "<", ">=", "<=", "==" })
            {
                instructions[op] = new MathOpCompiler(op);
            }

            instructions["pop"] = new InstructionCompiler(1, ilStack => {
                ilStack.Pop();
            },
                                                          stack => stack.Peek().GetReprType());

            instructions["dup"] = new InstructionCompiler(1, ilStack => {
                // XXX This probably doesn't work well with stacks.
                ilStack.il.Emit(OpCodes.Dup);
                if (ilStack.types.Peek() == typeof(Stack))
                {
                    ilStack.stackTypes.Push(ilStack.stackTypes.Peek());
                }
                ilStack.types.Push(ilStack.types.Peek());
            },
                                                          stack => stack.Peek().GetReprType());

            foreach (var method in typeof(CompilerFunctions).GetMethods())
            {
                instructions[method.Name.ToLower()] = new InstructionCompiler(method);
            }

            instructions["swap"] = new InstructionCompiler(2, ilStack => {
                var t1 = ilStack.GetTemp(ilStack.types.Peek());
                ilStack.il.Emit(OpCodes.Stloc, t1.LocalIndex);
                ilStack.types.Pop();
                LocalBuilder t2;
                if (t1.LocalType == ilStack.types.Peek())
                {
                    t2 = ilStack.il.DeclareLocal(ilStack.types.Peek());
                }
                else
                {
                    t2 = ilStack.GetTemp(ilStack.types.Peek());
                }
                ilStack.il.Emit(OpCodes.Stloc, t2.LocalIndex);
                ilStack.types.Pop();
                ilStack.il.Emit(OpCodes.Ldloc, t1.LocalIndex);
                ilStack.types.Push(t1.LocalType);
                ilStack.il.Emit(OpCodes.Ldloc, t2.LocalIndex);
                ilStack.types.Push(t2.LocalType);
            },
                                                           stack => { var a = stack.Pop();
                                                                      var b = stack.Peek();
                                                                      stack.Push(a);
                                                                      return(b.GetReprType()); });
            instructions["split"] = new InstructionCompiler(1, ilStack => {
                ilStack.ReverseStack();
                ilStack.UnrollStack();
            },
                                                            stack => ((Stack)stack.Peek()).Peek().GetReprType());
            instructions["cat"] = new InstructionCompiler(2, ilStack => {
                ilStack.MakeReturnStack(2);
                ilStack.ReverseStack();
            },
                                                          typeof(Stack));
            instructions["if"] = new InstructionFunc(stack => {
                if (stack.Peek() is bool)
                {
                    var condition  = (bool)stack.Pop();
                    var consequent = (Stack)stack.Pop();
                    var otherwise  = (Stack)stack.Pop();

                    stack.Push(new CompilationUnit(ilStack => {
                        Compile(condition ? consequent : otherwise,
                                ilStack,
                                new [] { instructions });
                    },
                                                   typeof(int)));
                }
                else
                {
                    var condition  = (CompilationUnit)stack.Pop();
                    var consequent = (Stack)stack.Pop();
                    var otherwise  = (Stack)stack.Pop();

                    var data1 = (Stack)stack.Clone();
                    var data2 = (Stack)stack.Clone();
                    Action <ILStack> _emitter;
                    _emitter = ilStack => {
                        // if (ilStack.types.Peek() != typeof(bool))
                        //   throw new Exception($"Expected a bool not {ilStack.types.Peek().PrettyName()}");
                        // ilStack.types.Pop();
                        // if (ilStack.types.Peek() != typeof(Stack))
                        //   throw new Exception($"Expected a Stack for consequent not {ilStack.types.Peek().PrettyName()}");
                        // ilStack.types.Pop();
                        // if (ilStack.types.Peek() != typeof(Stack))
                        //   throw new Exception($"Expected a Stack for consequent not {ilStack.types.Peek().PrettyName()}");
                        var ifnot = ilStack.il.DefineLabel();
                        var end   = ilStack.il.DefineLabel();
                        // ilStack.Push(true);
                        condition.emitter(ilStack);
                        ilStack.il.Emit(OpCodes.Brfalse_S, ifnot);
                        ilStack.types.Pop(); // consume the bool
                        // Compile if possible. Interpret ifnot.
                        data1.Push(consequent);
                        // Console.WriteLine("Consequent " + data1.ToRepr());
                        var typesCount = ilStack.types.Count;
                        Compile(data1, ilStack, new [] { instructions });
                        // ilStack.il.Emit(OpCodes.Ldc_I4_1);
                        // ilStack.Push(1);
                        while (ilStack.types.Count > typesCount)
                        {
                            ilStack.types.Pop(); // In reality only type gets put on the stack.
                        }
                        ilStack.il.Emit(OpCodes.Br, end);
                        ilStack.il.MarkLabel(ifnot);
                        // ilStack.Push(0);
                        data2.Push(otherwise);
                        Compile(data2, ilStack, new [] { instructions });
                        ilStack.il.MarkLabel(end);
                    };
                    stack.Push(new CompilationUnit(_emitter, typeof(int)));
                }
            });
            instructions["do-while"] = new InstructionFunc(stack => {
                var code = (Stack)stack.Pop();
                // var program = (Stack) stack.Clone();
                // program.Push(code);
                var program = new Stack();
                // It's already on the stack. Just an ilStack noop.
                program.Push(new CompilationUnit(_ => {; }, typeof(int)));
                program.Push(code);
                Action <ILStack> emitter =
                    ilStack => {
                    var test = ilStack.il.DefineLabel();
                    var body = ilStack.il.DefineLabel();
                    // ilStack.il.Emit(OpCodes.Br, test);
                    ilStack.il.MarkLabel(body);
                    Compile(program, ilStack, new [] { instructions });
                    ilStack.il.MarkLabel(test);
                    if (ilStack.types.Peek() != typeof(bool))
                    {
                        throw new Exception("Must have bool on top of stack");
                    }
                    ilStack.il.Emit(OpCodes.Brtrue_S, body);
                    ilStack.types.Pop();
                };
                stack.Push(new CompilationUnit(emitter, typeof(int)));
            });
        }