Esempio n. 1
0
        public void ChunkReturnsConstantIndices()
        {
            var chunk = new Chunk();

            Assert.Equal(0, chunk.AddConstant(Values.Bool(true)));
            Assert.Equal(1, chunk.AddConstant(Values.Number(0m)));
        }
Esempio n. 2
0
        public void ValueEqualMemberAndExtensionAreEquivalent()
        {
            Assert.Equal(Values.Bool(true).Equals(Values.Bool(true)), Values.Bool(true).EqualsValue(Values.Bool(true)));
            Assert.Equal(Values.Number(123).Equals(Values.Number(123)), Values.Number(123).EqualsValue(Values.Number(123)));
            Assert.Equal(Values.Number(123).Equals(Values.Bool(false)), Values.Number(123).EqualsValue(Values.Bool(false)));

            Assert.Equal(Values.Number(123).Equals((object)Values.Bool(false)), Values.Number(123).EqualsValue(Values.Bool(false)));
            Assert.Equal(Values.Bool(true).Equals((object)Values.Bool(true)), Values.Bool(true).EqualsValue(Values.Bool(true)));
        }
Esempio n. 3
0
        public void ChunkWritesConstants()
        {
            var chunk = new Chunk();

            chunk.AddConstant(Values.String("test"));
            chunk.AddConstant(Values.Bool(true));

            Assert.Equal(Values.String("test"), chunk.Constants[0]);
            Assert.Equal(Values.Bool(true), chunk.Constants[1]);
        }
Esempio n. 4
0
        public void ValuesDoNotEqualUnwrappedValues()
        {
            Assert.False(Values.Bool(true).Equals(null));
            Assert.False(Values.Bool(true).Equals(true));
            Assert.False(Values.String("test").Equals("test"));

            var func = new Function("test", 0);

            Assert.False(Values.Function(func).Equals(func));
        }
Esempio n. 5
0
        public void PeekBeyondStackBorderThrows()
        {
            var vm = new VirtualMachine();

            vm.Push(Values.Bool(true));
            vm.Push(Values.Bool(false));

            vm.Peek(0);
            vm.Peek(1);
            Assert.Throws <RuntimeExecutionException>(() => vm.Peek(2));
            Assert.Throws <RuntimeExecutionException>(() => vm.Peek(3));
            Assert.Throws <RuntimeExecutionException>(() => vm.Peek(1_000_000_000));
        }
Esempio n. 6
0
        public void ValuesAreTheirOwnType()
        {
            Assert.True(Values.Bool(true).IsBool());
            Assert.True(Values.Bool(false).IsBool());

            Assert.True(Values.Number(1m).IsNumber());

            Assert.True(Values.String("").IsString());

            Assert.True(Values.Function(new Function("testfunc", 0)).IsFunction());

            Assert.True(Values.NativeFunction(args => Values.Bool(true), 0).IsNativeFunction());
        }
Esempio n. 7
0
        public void PushAndPopAndPeekWorkAsStack()
        {
            var vm = new VirtualMachine();

            var firstVal  = Values.Bool(false);
            var secondVal = Values.Number(decimal.MinusOne);

            vm.Push(firstVal);
            vm.Push(secondVal);

            Assert.Equal(vm.Peek(0), secondVal);
            Assert.Equal(vm.Peek(1), firstVal);
            Assert.Equal(vm.Pop(), secondVal);
            Assert.Equal(vm.Pop(), firstVal);
        }
Esempio n. 8
0
        public void ValuesRetainTheValueTheyAreGiven()
        {
            Assert.True(Values.Bool(true).AsBool());
            Assert.False(Values.Bool(false).AsBool());

            Assert.Equal(0m, Values.Number(0m).AsNumber());
            Assert.Equal(1m, Values.Number(1m).AsNumber());
            Assert.Equal(1000.500m, Values.Number(1000.500m).AsNumber());

            Assert.Equal("", Values.String("").AsString());
            Assert.Equal("test", Values.String("test").AsString());

            var func = new Function("test", 0);

            Assert.Equal(func, Values.Function(func).AsFunction());
Esempio n. 9
0
        public void ValuesAreNotSomeOtherType()
        {
            var boolVal = Values.Bool(true);

            Assert.False(boolVal.IsNumber());
            Assert.False(boolVal.IsString());
            Assert.False(boolVal.IsFunction());
            Assert.False(boolVal.IsNativeFunction());

            var numberVal = Values.Number(0m);

            Assert.False(numberVal.IsBool());
            Assert.False(numberVal.IsString());
            Assert.False(numberVal.IsFunction());
            Assert.False(numberVal.IsNativeFunction());

            var stringVal = Values.String("");

            Assert.False(stringVal.IsBool());
            Assert.False(stringVal.IsNumber());
            Assert.False(stringVal.IsFunction());
            Assert.False(stringVal.IsNativeFunction());

            var funcVal = Values.Function(new Function("myFunction", 2));

            Assert.False(funcVal.IsBool());
            Assert.False(funcVal.IsString());
            Assert.False(funcVal.IsNumber());
            Assert.False(funcVal.IsNativeFunction());

            var nativeFuncVal = Values.NativeFunction(args => Values.Bool(true), 0);

            Assert.False(nativeFuncVal.IsBool());
            Assert.False(nativeFuncVal.IsString());
            Assert.False(nativeFuncVal.IsNumber());
            Assert.False(nativeFuncVal.IsFunction());
        }
Esempio n. 10
0
        InterpretResult Run()
        {
            Frame = frames[FrameCount - 1];

            while (true)
            {
#if TRACE
                System.Diagnostics.Debug.WriteLine(CurrentChunk.DisassembleInstruction(Frame.IP));
#endif

                InstructionCounter++;
                var instruction = (OpCode)ReadByte();
                switch (instruction)
                {
                case OpCode.Nop:
                    break;

                case OpCode.Constant:
                {
                    var constant = ReadConstant();
                    Push(constant);
                }
                break;

                case OpCode.True:
                    Push(Values.Bool(true));
                    break;

                case OpCode.False:
                    Push(Values.Bool(false));
                    break;

                case OpCode.Pop:
                    Pop();
                    break;

                case OpCode.PopN:
                    Pop(ReadByte());
                    break;

                case OpCode.LoadGlobal:
                {
                    var name = ReadConstant().AsString();
                    if (!globals.TryGetValue(name, out var value))
                    {
                        throw new RuntimeExecutionException($"Undefined variable '{name}'", CreateStackTrace());
                    }
                    Push(value);
                }
                break;

                case OpCode.LoadLocal:
                {
                    var slot = ReadByte();
                    Push(stack[Frame.StackBase + slot]);
                }
                break;

                case OpCode.AssignGlobal:
                {
                    var name = ReadConstant().AsString();
                    if (!globals.ContainsKey(name))
                    {
                        throw new RuntimeExecutionException($"Undefined variable '{name}'", CreateStackTrace());
                    }
                    globals[name] = Peek();
                }
                break;

                case OpCode.AssignLocal:
                {
                    var slot = ReadByte();
                    stack[Frame.StackBase + slot] = Peek();
                }
                break;

                case OpCode.DefineGlobal:
                {
                    var globalName = ReadConstant().AsString();
                    globals[globalName] = Peek();
                    Pop();
                }
                break;

                case OpCode.Equal:
                {
                    var a      = Pop();
                    var b      = Pop();
                    var equals = a.EqualsValue(b);
                    Push(Values.Bool(equals));
                }
                break;

                case OpCode.Greater:
                    BinaryOp((a, b) => Values.Bool(a > b));
                    break;

                case OpCode.Less:
                    BinaryOp((a, b) => Values.Bool(a < b));
                    break;

                case OpCode.Add:
                    BinaryOp((a, b) => Values.Number(a + b));
                    break;

                case OpCode.Subtract:
                    BinaryOp((a, b) => Values.Number(a - b));
                    break;

                case OpCode.Multiply:
                    BinaryOp((a, b) => Values.Number(a * b));
                    break;

                case OpCode.Divide:
                    BinaryOp((a, b) => Values.Number(a / b));
                    break;

                case OpCode.Exp:
                    BinaryOp((a, b) => Values.Number((decimal)Math.Pow((double)a, (double)b)));
                    break;

                case OpCode.Modulo:
                    BinaryOp((a, b) => Values.Number(decimal.Remainder(a, b)));
                    break;

                case OpCode.Not:
                {
                    var falsey = Pop().IsFalsey();
                    Push(Values.Bool(falsey));
                }
                break;

                case OpCode.Negate:
                {
                    if (!Peek(0).IsNumber())
                    {
                        throw new RuntimeExecutionException("Operand must be a number", CreateStackTrace());
                    }
                    Push(Values.Number(-Pop().AsNumber()));
                }
                break;

                case OpCode.Print:
                    StdOut.WriteLine(Pop().ToString());
                    break;

                case OpCode.Jump:
                {
                    var offset = ReadShort();
                    Frame.IP += offset;
                }
                break;

                case OpCode.JumpIfFalse:
                {
                    var offset = ReadShort();
                    if (Peek().IsFalsey())
                    {
                        Frame.IP += offset;
                    }
                }
                break;

                case OpCode.Loop:
                {
                    var offset = ReadShort();
                    Frame.IP -= offset;
                }
                break;

                case OpCode.Call:
                {
                    var argCount = ReadByte();
                    CallValue(Peek(argCount), argCount);
                    Frame = frames[FrameCount - 1];
                }
                break;

                case OpCode.Return:
                {
                    var result = Pop();
                    FrameCount--;
                    if (FrameCount == 0)
                    {
                        Pop();
                        return(InterpretResult.Success);
                    }

                    StackPointer = Frame.StackBase;
                    Push(result);

                    Frame = frames[FrameCount - 1];
                }
                break;

                default:
                    throw new RuntimeExecutionException($"Unknown instruction value '{instruction}' at ip offset {Frame.IP,4:D4}", CreateStackTrace());
                }
            }
        }
Esempio n. 11
0
 static Value nativeFunc(Value[] args) => Values.Bool(true);