Example #1
0
        private static bool call(ObjClosure closure, int argCount)
        {
            if (argCount != closure.function.arity)
            {
                runtimeError("Expected {0} but got {1}.", closure.function.arity.ToString(), argCount.ToString());
                return(false);
            }

            if (vm.frameCount == FRAMES_MAX)
            {
                runtimeError("Stack overflow.");
                return(false);
            }

            if (vm.frameCount > 0)
            {
                vm.frames[vm.frameCount - 1]._ip_index = _caller_ip_index;
            }

            CallFrame frame = vm.frames[vm.frameCount++];

            frame.closure   = closure;
            frame.ip        = closure.function.chunk.code;
            frame._ip_index = 0;

            frame._ip_count = frame.closure.function.chunk.count;

            frame.slots        = vm.stack;
            frame._slot_offset = vm.stackTop - argCount - 1;

            vm.frames[vm.frameCount - 1] = frame;             // Csharp ref WORK AROUND

            return(true);
        }
Example #2
0
        static void runtimeError(string format, params string[] args)
        {
            System.Console.Write(format, args);
            System.Console.WriteLine();

            for (int i = vm.frameCount - 1; i >= 0; i--)
            {
                CallFrame   frame       = vm.frames[i];
                ObjFunction function    = frame.closure.function;
                int         instruction = frame._ip_index - 1;
                System.Console.Write("[line {0}] in ", function.chunk.lines[instruction].ToString());

                if (function.name == null)
                {
                    System.Console.WriteLine("script");
                }
                else
                {
                    System.Console.WriteLine("{0} ()", new string(function.name.chars, 0, function.name.chars.Length - 1));
                }
            }

#if DEBUG
            System.Console.ReadKey();             // convenience pause
#endif
            resetStack();
        }
Example #3
0
        public static InterpretResult run()
        {
            CallFrame frame = vm.frames[vm.frameCount - 1];

            frame._slot_offset = 0;

            for (;;)
            {
#if DEBUG_TRACE_EXECUTION
#if BYPASS_THIS_BLOCK
                if (prev_frame_count != vm.frameCount)
                {
                    prev_frame_count = vm.frameCount;
                    for (int i = 0; i < frame._ip_count; i++)
                    {
                        if (frame.ip[i] < (byte)OpCode.Count)
                        {
                            System.Console.WriteLine(i.ToString("D2") + "- opcode\t" + ((OpCode)frame.ip[i]).ToString());
                        }
                        else
                        {
                            System.Console.WriteLine(i.ToString("D2") + "- constn\t" + (frame.ip[i]).ToString());
                        }
                    }
                }
#endif
                System.Console.Write("          ");
                for (int slot = 0; slot < vm.stackTop; slot++)
                {
                    System.Console.Write("[ ");
                    Value.printValue(vm.stack[slot]);
                    System.Console.Write(" ]");
                }
                System.Console.WriteLine();

                Debug.disassembleInstruction(ref frame.closure.function.chunk, frame._ip_index);
#endif

                OpCode instruction;
                switch (instruction = (OpCode)READ_BYTE(ref frame))
                {
                case OpCode.OP_CONSTANT:
                {
                    Value_t constant = READ_CONSTANT(ref frame);
                    push(constant);
                    break;
                }

                case OpCode.OP_NIL:
                    push(Value.NIL_VAL());
                    break;

                case OpCode.OP_TRUE:
                    push(Value.BOOL_VAL(true));
                    break;

                case OpCode.OP_FALSE:
                    push(Value.BOOL_VAL(false));
                    break;

                case OpCode.OP_POP:
                    pop();
                    break;

                case OpCode.OP_GET_LOCAL:
                {
                    byte slot = READ_BYTE(ref frame);
                    push(frame.slots[frame._slot_offset + slot]);
                    break;
                }

                case OpCode.OP_SET_LOCAL:
                {
                    byte slot = READ_BYTE(ref frame);
                    frame.slots[frame._slot_offset + slot] = peek(0);
                    break;
                }

                case OpCode.OP_GET_GLOBAL:
                {
                    ObjString name  = READ_STRING(ref frame);
                    Value_t   value = new Value_t();
                    if (!Table.tableGet(ref vm.globals, name, ref value))
                    {
                        runtimeError("Undefined variable '{0}'.", new string(name.chars, 0, name.chars.Length - 1));
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                    push(value);
                    break;
                }

                case OpCode.OP_DEFINE_GLOBAL:
                {
                    ObjString name = READ_STRING(ref frame);
                    Table.tableSet(ref vm.globals, name, peek(0));
                    pop();
                    break;
                }

                case OpCode.OP_SET_GLOBAL:
                {
                    ObjString name = READ_STRING(ref frame);
                    if (Table.tableSet(ref vm.globals, name, peek(0)))
                    {
                        Table.tableDelete(ref vm.globals, name);
                        runtimeError("Undefined variable '{0}'.", new string(name.chars, 0, name.chars.Length - 1));
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                    break;
                }

                case OpCode.OP_GET_UPVALUE:
                {
                    byte slot = READ_BYTE(ref frame);
                    push(frame.closure.upvalues[slot]._value_src[frame.closure.upvalues[slot].location]);
                    break;
                }

                case OpCode.OP_SET_UPVALUE:
                {
                    byte slot = READ_BYTE(ref frame);
                    frame.closure.upvalues[slot]._value_src[frame.closure.upvalues[slot].location] = peek(0);
                    break;
                }

                case OpCode.OP_GET_PROPERTY:
                {
                    if (!Object.IS_INSTANCE(peek(0)))
                    {
                        runtimeError("Only instances have properties.");
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }

                    ObjInstance instance = Object.AS_INSTANCE(peek(0));
                    ObjString   name     = READ_STRING(ref frame);

                    Value_t value = new Value_t();
                    if (Table.tableGet(ref instance.fields, name, ref value))
                    {
                        pop();                                         // Instance.
                        push(value);
                        break;
                    }

                    if (!bindMethod(instance.klass, name))
                    {
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                    break;
                }

                case OpCode.OP_SET_PROPERTY:
                {
                    if (!Object.IS_INSTANCE(peek(1)))
                    {
                        runtimeError("Only instances have fields.");
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }

                    ObjInstance instance = Object.AS_INSTANCE(peek(1));
                    Table.tableSet(ref instance.fields, READ_STRING(ref frame), peek(0));

                    Value_t value = pop();
                    pop();
                    push(value);
                    break;
                }

                case OpCode.OP_GET_SUPER:
                {
                    ObjString name       = READ_STRING(ref frame);
                    ObjClass  superclass = Object.AS_CLASS(pop());
                    if (!bindMethod(superclass, name))
                    {
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                    break;
                }

                case OpCode.OP_EQUAL:
                {
                    Value_t b = pop();
                    Value_t a = pop();
                    push(Value.BOOL_VAL(Value.valuesEqual(a, b)));
                    break;
                }

                case OpCode.OP_ADD:
                {
                    if (Object.IS_STRING(peek(0)) && Object.IS_STRING(peek(1)))
                    {
                        concatenate();
                    }
                    else if (Value.IS_NUMBER(peek(0)) && Value.IS_NUMBER(peek(1)))
                    {
                        BINARY_OP(instruction);
                    }
                    else
                    {
                        runtimeError("Operands must be two numbers or two strings.");
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                }
                break;

                case OpCode.OP_GREATER:
                case OpCode.OP_LESS:
                case OpCode.OP_SUBTRACT:
                case OpCode.OP_MULTIPLY:
                case OpCode.OP_DIVIDE:
                    if (!BINARY_OP(instruction))
                    {
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                    break;

                case OpCode.OP_NOT:
                    push(Value.BOOL_VAL(isFalsey(pop())));
                    break;

                case OpCode.OP_NEGATE:
                    if (!Value.IS_NUMBER(peek(0)))
                    {
                        runtimeError("Operand must be a number.");
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }

                    push(Value.NUMBER_VAL(-Value.AS_NUMBER(pop())));
                    break;

                case OpCode.OP_PRINT:
                {
                    Value.printValue(pop());
                    System.Console.WriteLine();
                    break;
                }

                case OpCode.OP_JUMP:
                {
                    ushort offset = READ_SHORT(ref frame);
                    frame._ip_index += offset;
                    break;
                }

                case OpCode.OP_JUMP_IF_FALSE:
                {
                    ushort offset = READ_SHORT(ref frame);
                    if (isFalsey(peek(0)))
                    {
                        frame._ip_index += offset;
                    }
                    break;
                }

                case OpCode.OP_LOOP:
                {
                    ushort offset = READ_SHORT(ref frame);
                    frame._ip_index -= offset;
                    break;
                }

                case OpCode.OP_CALL:
                {
                    int argCount = READ_BYTE(ref frame);
                    _caller_ip_index = frame._ip_index;
                    if (!callValue(peek(argCount), argCount))
                    {
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                    frame = vm.frames[vm.frameCount - 1];
                    break;
                }

                case OpCode.OP_INVOKE:
                {
                    ObjString method   = READ_STRING(ref frame);
                    int       argCount = READ_BYTE(ref frame);

                    _caller_ip_index = frame._ip_index;
                    if (!invoke(method, argCount))
                    {
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                    frame = vm.frames[vm.frameCount - 1];
                    break;
                }

                case OpCode.OP_SUPER_INVOKE:
                {
                    ObjString method     = READ_STRING(ref frame);
                    int       argCount   = READ_BYTE(ref frame);
                    ObjClass  superclass = Object.AS_CLASS(pop());

                    _caller_ip_index = frame._ip_index;
                    if (!invokeFromClass(superclass, method, argCount))
                    {
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }
                    frame = vm.frames[vm.frameCount - 1];
                    break;
                }

                case OpCode.OP_CLOSURE:
                {
                    ObjFunction function = Object.AS_FUNCTION(READ_CONSTANT(ref frame));
                    ObjClosure  closure  = Object.newClosure(function);

                    for (int i = 0; i < closure.upvalueCount; i++)
                    {
                        byte isLocal = READ_BYTE(ref frame);
                        byte index   = READ_BYTE(ref frame);
                        if (isLocal != 0)
                        {
                            closure.upvalues[i] = captureUpvalue(frame._slot_offset + index);
                        }
                        else
                        {
                            closure.upvalues[i] = frame.closure.upvalues[index];
                        }
                    }

                    push(Value.OBJ_VAL(closure));                                     // cs push after modify?

                    break;
                }

                case OpCode.OP_CLOSE_UPVALUE:
                    closeUpvalues(vm.stackTop - 1);
                    pop();
                    break;

                case OpCode.OP_RETURN:
                {
                    Value_t result = pop();
                    closeUpvalues(frame._slot_offset);

                    vm.frameCount--;
                    if (vm.frameCount == 0)
                    {
                        pop();
                        return(InterpretResult.INTERPRET_OK);
                    }

                    vm.stackTop = frame._slot_offset;
                    push(result);

                    frame = vm.frames[vm.frameCount - 1];
                    break;
                }

                case OpCode.OP_CLASS:
                    push(Value.OBJ_VAL(Object.newClass(READ_STRING(ref frame))));
                    break;

                case OpCode.OP_INHERIT:
                {
                    Value_t superclass = peek(1);
                    if (!Object.IS_CLASS(superclass))
                    {
                        runtimeError("Superclass must be a class.");
                        return(InterpretResult.INTERPRET_RUNTIME_ERROR);
                    }

                    ObjClass subclass = Object.AS_CLASS(peek(0));
                    Table.tableAddAll(ref Object.AS_CLASS(superclass).methods, ref subclass.methods);
                    pop();                                     // Subclass.
                    break;
                }

                case OpCode.OP_METHOD:
                    defineMethod(READ_STRING(ref frame));
                    break;
                }

                vm.frames[vm.frameCount - 1]._ip_index = frame._ip_index;                 //Csharp reference updating workaround
            }
        }
Example #4
0
 private static ObjString READ_STRING(ref CallFrame frame)
 {
     return(Object.AS_STRING(READ_CONSTANT(ref frame)));
 }
Example #5
0
 private static Value_t READ_CONSTANT(ref CallFrame frame)
 {
     return(frame.closure.function.chunk.constants.values[READ_BYTE(ref frame)]);
 }
Example #6
0
 private static ushort READ_SHORT(ref CallFrame frame)
 {
     frame._ip_index += 2;
     return((ushort)((frame.ip[frame._ip_index - 2] << 8) | frame.ip[frame._ip_index - 1]));
 }
Example #7
0
 private static byte READ_BYTE(ref CallFrame frame)
 {
     return(frame.ip[frame._ip_index++]);
 }