private void ProcessCall(ScriptBuilder sb)
        {
            if (Arguments.Length < 1 || Arguments.Length > 2)
            {
                throw new CompilerException(LineNumber, ERR_INCORRECT_NUMBER);
            }

            if (!Arguments[0].IsLabel())
            {
                throw new CompilerException(LineNumber, ERR_INVALID_ARGUMENT);
            }

            byte regCount = 0;

            if (Arguments.Length < 2)
            {
                regCount = VirtualMachine.DefaultRegisterCount;
            }
            else
            if (Arguments[1].IsNumber())
            {
                regCount = (byte)Arguments[1].AsNumber();
            }
            else
            {
                throw new CompilerException(LineNumber, ERR_INVALID_ARGUMENT);
            }

            sb.EmitCall(Arguments[0].AsLabel(), regCount);
        }
Beispiel #2
0
        public void TestBreakPointStepOver()
        {
            using (var engine = new ExecutionEngine())
                using (var script = new ScriptBuilder())
                {
                    /* ┌     CALL
                     * │  ┌> NOT
                     * │  │  RET
                     * └>X│  PUSH0
                     *   └┘  RET */
                    script.EmitCall(4);
                    script.Emit(OpCode.NOT);
                    script.Emit(OpCode.RET);
                    script.Emit(OpCode.PUSH0);
                    script.Emit(OpCode.RET);

                    engine.LoadScript(script.ToArray());

                    var debugger = new Debugger(engine);

                    Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode);

                    debugger.AddBreakPoint(engine.CurrentContext.Script, 5);
                    Assert.AreEqual(VMState.BREAK, debugger.StepOver());

                    Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode);
                    Assert.AreEqual(5, engine.CurrentContext.InstructionPointer);
                    Assert.AreEqual(VMState.BREAK, engine.State);

                    debugger.Execute();

                    Assert.AreEqual(true, engine.ResultStack.Pop().ToBoolean());
                    Assert.AreEqual(VMState.HALT, engine.State);
                }
        }
Beispiel #3
0
        public void TestStepInto()
        {
            using (var engine = new ExecutionEngine())
                using (var script = new ScriptBuilder())
                {
                    /* ┌     CALL
                     * │  ┌> NOT
                     * │  │  RET
                     * └> │  PUSH0
                     *  └─┘  RET */
                    script.EmitCall(4);
                    script.Emit(OpCode.NOT);
                    script.Emit(OpCode.RET);
                    script.Emit(OpCode.PUSH0);
                    script.Emit(OpCode.RET);

                    engine.LoadScript(script.ToArray());

                    var debugger = new Debugger(engine);

                    var context = engine.CurrentContext;

                    Assert.AreEqual(context, engine.CurrentContext);
                    Assert.AreEqual(context, engine.EntryContext);
                    Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode);

                    Assert.AreEqual(VMState.BREAK, debugger.StepInto());

                    Assert.AreNotEqual(context, engine.CurrentContext);
                    Assert.AreEqual(context, engine.EntryContext);
                    Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode);

                    Assert.AreEqual(VMState.BREAK, debugger.StepInto());
                    Assert.AreEqual(VMState.BREAK, debugger.StepInto());

                    Assert.AreEqual(context, engine.CurrentContext);
                    Assert.AreEqual(context, engine.EntryContext);
                    Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode);

                    Assert.AreEqual(VMState.BREAK, debugger.StepInto());
                    Assert.AreEqual(VMState.HALT, debugger.StepInto());

                    Assert.AreEqual(true, engine.ResultStack.Pop().ToBoolean());
                    Assert.AreEqual(VMState.HALT, engine.State);

                    // Test step into again

                    Assert.AreEqual(VMState.HALT, debugger.StepInto());
                    Assert.AreEqual(VMState.HALT, engine.State);
                }
        }
 public void TestEmitCall()
 {
     using (var script = new ScriptBuilder())
     {
         script.EmitCall(0);
         CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL, (byte)0 }, script.ToArray());
     }
     using (var script = new ScriptBuilder())
     {
         script.EmitCall(12345);
         CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL_L }.Concat(BitConverter.GetBytes(12345)).ToArray(), script.ToArray());
     }
     using (var script = new ScriptBuilder())
     {
         script.EmitCall(-12345);
         CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL_L }.Concat(BitConverter.GetBytes(-12345)).ToArray(), script.ToArray());
     }
 }
Beispiel #5
0
        public void TranslateInstruction(Instruction i)
        {
            switch (i.op)
            {
            case Instruction.Opcode.Label:
            {
                _output.EmitLabel(i.target);
                break;
            }

            case Instruction.Opcode.Push:
            {
                var reg = FetchRegister(i.target);
                _output.EmitPush(reg);
                break;
            }

            case Instruction.Opcode.Pop:
            {
                var reg = FetchRegister(i.target);
                _output.Emit(VM.Opcode.POP, new byte[] { reg });
                break;
            }

            case Instruction.Opcode.Assign:
            {
                if (i.literal != null)
                {
                    switch (i.literal.kind)
                    {
                    case LiteralKind.String:
                    {
                        var reg = FetchRegister(i.target);
                        _output.EmitLoad(reg, (string)i.literal.value);
                        break;
                    }

                    case LiteralKind.Boolean:
                    {
                        var reg = FetchRegister(i.target);
                        _output.EmitLoad(reg, (bool)i.literal.value);
                        break;
                    }

                    case LiteralKind.Integer:
                    {
                        var        reg = FetchRegister(i.target);
                        BigInteger val;

                        if (i.literal.value is BigInteger)
                        {
                            val = (BigInteger)i.literal.value;
                        }
                        else
                        if (i.literal.value is int)
                        {
                            val = new BigInteger((int)i.literal.value);
                        }
                        else
                        {
                            throw new Exception($"Could not convert {i.literal.value.GetType().Name} to BigInteger");
                        }

                        _output.EmitLoad(reg, val);
                        break;
                    }

                    default: throw new Exception("Unsuported " + i.literal.kind);
                    }
                }
                else
                {
                    var src = i.varName != null?FetchRegister(i.varName) : FetchRegister(i.a.target);

                    var dst = FetchRegister(i.target);
                    _output.EmitMove(src, dst);
                }
                break;
            }

            case Instruction.Opcode.Add: { InsertOp(i, VM.Opcode.ADD); break; }

            case Instruction.Opcode.Sub: { InsertOp(i, VM.Opcode.SUB); break; }

            case Instruction.Opcode.Mul: { InsertOp(i, VM.Opcode.MUL); break; }

            case Instruction.Opcode.Div: { InsertOp(i, VM.Opcode.DIV); break; }

            case Instruction.Opcode.Mod: { InsertOp(i, VM.Opcode.MOD); break; }

            case Instruction.Opcode.Shr: { InsertOp(i, VM.Opcode.SHR); break; }

            case Instruction.Opcode.Shl: { InsertOp(i, VM.Opcode.SHL); break; }

            case Instruction.Opcode.Equals: { InsertOp(i, VM.Opcode.EQUAL); break; }

            case Instruction.Opcode.LessThan: { InsertOp(i, VM.Opcode.LT); break; }

            case Instruction.Opcode.GreaterThan: { InsertOp(i, VM.Opcode.GT); break; }

            case Instruction.Opcode.LessOrEqualThan: { InsertOp(i, VM.Opcode.LTE); break; }

            case Instruction.Opcode.GreaterOrEqualThan: { InsertOp(i, VM.Opcode.GTE); break; }


            case Instruction.Opcode.Jump: InsertJump(i, VM.Opcode.JMP); break;

            case Instruction.Opcode.JumpIfFalse: InsertJump(i, VM.Opcode.JMPNOT); break;

            case Instruction.Opcode.JumpIfTrue: InsertJump(i, VM.Opcode.JMPIF); break;

            case Instruction.Opcode.Call:
                _output.EmitCall(i.target, 8);     // TODO remove hardcoded register count
                break;

            case Instruction.Opcode.Return:
                _output.Emit(VM.Opcode.RET);
                break;

            case Instruction.Opcode.Negate:
            {
                var src = FetchRegister(i.a.target);
                var dst = FetchRegister(i.target);
                _output.Emit(VM.Opcode.NEGATE, new byte[] { src, dst }); break;
            }

            case Instruction.Opcode.Not:
            {
                var src = FetchRegister(i.a.target);
                var dst = FetchRegister(i.target);
                _output.Emit(VM.Opcode.NOT, new byte[] { src, dst }); break;
            }

            default: throw new Exception("Unsupported Opcode: " + i.op);
            }
        }