public ReorderInstruction(string name, IEnumerable <Type> inputTypes, IEnumerable <Type> outputTypes) : base(name, inputTypes, outputTypes, null) { innerInstruction = new InstructionFunc(stack => this.instruction.Apply(stack)); }
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))); }); }