Inheritance: Wren.Core.Objects.Obj
Exemple #1
0
        static bool Eval(WrenVM vm, Obj[] args, int stackStart)
        {
            if (args[stackStart + 1] is ObjString)
            {

                // Eval the code in the module where the calling function was defined.
                Obj callingFn = vm.Fiber.GetFrame().Fn;
                ObjModule module = (callingFn is ObjFn)
                    ? ((ObjFn)callingFn).Module
                    : ((ObjClosure)callingFn).Function.Module;

                // Compile it.
                ObjFn fn = Compiler.Compile(vm, module, "", args[stackStart + 1].ToString(), false);

                if (fn == null)
                {
                    vm.Fiber.Error = Obj.MakeString("Could not compile source code.");
                    return false;
                }

                // TODO: Include the compile errors in the runtime error message.

                // Create a fiber to run the code in.
                ObjFiber evalFiber = new ObjFiber(fn) { Caller = vm.Fiber };

                // Switch to the fiber.
                args[stackStart] = evalFiber;

                return false;
            }

            vm.Fiber.Error = Obj.MakeString("Source code must be a string.");
            return false;
        }
Exemple #2
0
        // Resets [fiber] back to an initial state where it is ready to invoke [fn].
        private void ResetFiber(Obj fn)
        {
            Stack = new Obj[InitialStackSize];
            Capacity = InitialStackSize;
            Frames = new List<CallFrame>();

            // Push the stack frame for the function.
            StackTop = 0;
            NumFrames = 1;
            OpenUpvalues = null;
            Caller = null;
            Error = null;
            CallerIsTrying = false;

            CallFrame frame = new CallFrame { Fn = fn, StackStart = 0, Ip = 0 };
            Frames.Add(frame);
        }
Exemple #3
0
        // Resets [fiber] back to an initial state where it is ready to invoke [fn].
        private void ResetFiber(Obj fn)
        {
            Stack    = new Obj[InitialStackSize];
            Capacity = InitialStackSize;
            Frames   = new List <CallFrame>();

            // Push the stack frame for the function.
            StackTop       = 0;
            NumFrames      = 1;
            OpenUpvalues   = null;
            Caller         = null;
            Error          = null;
            CallerIsTrying = false;

            CallFrame frame = new CallFrame {
                Fn = fn, StackStart = 0, Ip = 0
            };

            Frames.Add(frame);
        }
Exemple #4
0
        public InterpretResult Interpret(string moduleName, string sourcePath, string source)
        {
            if (sourcePath.Length == 0) return LoadIntoCore(source);

            // TODO: Better module name.
            Obj name = Obj.MakeString(moduleName);

            ObjFiber f = LoadModule(name, source);
            if (f == null)
            {
                return InterpretResult.CompileError;
            }

            Fiber = f;

            bool succeeded = RunInterpreter();

            return succeeded ? InterpretResult.Success : InterpretResult.RuntimeError;
        }
Exemple #5
0
        // The main bytecode interpreter loop. This is where the magic happens. It is
        // also, as you can imagine, highly performance critical. Returns `true` if the
        // fiber completed without error.
        private bool RunInterpreter()
        {
            /* Load Frame */
            CallFrame frame = Fiber.Frames[Fiber.NumFrames - 1];
            int ip = frame.Ip;
            int stackStart = frame.StackStart;
            Obj[] stack = Fiber.Stack;

            ObjFn fn = frame.Fn as ObjFn ?? ((ObjClosure)frame.Fn).Function;
            byte[] bytecode = fn.Bytecode;

            while (true)
            {
                Instruction instruction = (Instruction)bytecode[ip++];
                int index;
                switch (instruction)
                {
                    case Instruction.LOAD_LOCAL_0:
                    case Instruction.LOAD_LOCAL_1:
                    case Instruction.LOAD_LOCAL_2:
                    case Instruction.LOAD_LOCAL_3:
                    case Instruction.LOAD_LOCAL_4:
                    case Instruction.LOAD_LOCAL_5:
                    case Instruction.LOAD_LOCAL_6:
                    case Instruction.LOAD_LOCAL_7:
                    case Instruction.LOAD_LOCAL_8:
                        {
                            index = stackStart + instruction - Instruction.LOAD_LOCAL_0;
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = stack[index];
                            break;
                        }

                    case Instruction.LOAD_LOCAL:
                        {
                            index = stackStart + bytecode[ip++];
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = stack[index];
                            break;
                        }

                    case Instruction.LOAD_FIELD_THIS:
                        {
                            byte field = bytecode[ip++];
                            ObjInstance instance = (ObjInstance)stack[stackStart];
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = instance.Fields[field];
                            break;
                        }

                    case Instruction.POP:
                        {
                            Fiber.StackTop--;
                            break;
                        }

                    case Instruction.DUP:
                        {
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop] = stack[Fiber.StackTop - 1];
                            Fiber.StackTop++;
                            break;
                        }

                    case Instruction.NULL:
                        {
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = Obj.Null;
                            break;
                        }

                    case Instruction.FALSE:
                        {
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = Obj.False;
                            break;
                        }

                    case Instruction.TRUE:
                        {
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = Obj.True;
                            break;
                        }

                    case Instruction.CALL_0:
                    case Instruction.CALL_1:
                    case Instruction.CALL_2:
                    case Instruction.CALL_3:
                    case Instruction.CALL_4:
                    case Instruction.CALL_5:
                    case Instruction.CALL_6:
                    case Instruction.CALL_7:
                    case Instruction.CALL_8:
                    case Instruction.CALL_9:
                    case Instruction.CALL_10:
                    case Instruction.CALL_11:
                    case Instruction.CALL_12:
                    case Instruction.CALL_13:
                    case Instruction.CALL_14:
                    case Instruction.CALL_15:
                    case Instruction.CALL_16:
                    // Handle Super calls
                    case Instruction.SUPER_0:
                    case Instruction.SUPER_1:
                    case Instruction.SUPER_2:
                    case Instruction.SUPER_3:
                    case Instruction.SUPER_4:
                    case Instruction.SUPER_5:
                    case Instruction.SUPER_6:
                    case Instruction.SUPER_7:
                    case Instruction.SUPER_8:
                    case Instruction.SUPER_9:
                    case Instruction.SUPER_10:
                    case Instruction.SUPER_11:
                    case Instruction.SUPER_12:
                    case Instruction.SUPER_13:
                    case Instruction.SUPER_14:
                    case Instruction.SUPER_15:
                    case Instruction.SUPER_16:
                        {
                            int numArgs = instruction - (instruction >= Instruction.SUPER_0 ? Instruction.SUPER_0 : Instruction.CALL_0) + 1;
                            int symbol = (bytecode[ip] << 8) + bytecode[ip + 1];
                            ip += 2;

                            // The receiver is the first argument.
                            int argStart = Fiber.StackTop - numArgs;
                            Obj receiver = stack[argStart];
                            ObjClass classObj;

                            if (instruction < Instruction.SUPER_0)
                            {
                                if (receiver.Type == ObjType.Obj)
                                    classObj = receiver.ClassObj;
                                else if (receiver.Type == ObjType.Num)
                                    classObj = NumClass;
                                else if (receiver == Obj.True || receiver == Obj.False)
                                    classObj = BoolClass;
                                else
                                    classObj = NullClass;
                            }
                            else
                            {
                                // The superclass is stored in a constant.
                                classObj = fn.Constants[(bytecode[ip] << 8) + bytecode[ip + 1]] as ObjClass;
                                ip += 2;
                            }

                            // If the class's method table doesn't include the symbol, bail.
                            Method method = symbol < classObj.Methods.Length ? classObj.Methods[symbol] : null;

                            if (method == null)
                            {
                                /* Method not found */
                                frame.Ip = ip;
                                MethodNotFound(this, classObj, symbol);
                                if (!HandleRuntimeError())
                                    return false;
                                frame = Fiber.Frames[Fiber.NumFrames - 1];
                                ip = frame.Ip;
                                stackStart = frame.StackStart;
                                stack = Fiber.Stack;
                                fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                bytecode = fn.Bytecode;
                                break;
                            }

                            if (method.MType == MethodType.Primitive)
                            {
                                // After calling this, the result will be in the first arg slot.
                                if (method.Primitive(this, stack, argStart))
                                {
                                    Fiber.StackTop = argStart + 1;
                                }
                                else
                                {
                                    frame.Ip = ip;

                                    if (Fiber.Error != null && Fiber.Error != Obj.Null)
                                    {
                                        if (!HandleRuntimeError())
                                            return false;
                                    }
                                    else
                                    {
                                        // If we don't have a fiber to switch to, stop interpreting.
                                        if (stack[argStart] == Obj.Null)
                                            return true;
                                        Fiber = stack[argStart] as ObjFiber;
                                        if (Fiber == null)
                                            return false;
                                    }

                                    /* Load Frame */
                                    frame = Fiber.Frames[Fiber.NumFrames - 1];
                                    ip = frame.Ip;
                                    stackStart = frame.StackStart;
                                    stack = Fiber.Stack;
                                    fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                    bytecode = fn.Bytecode;
                                }
                                break;
                            }

                            frame.Ip = ip;

                            if (method.MType == MethodType.Block)
                            {
                                receiver = method.Obj;
                            }
                            else if (!CheckArity(stack, numArgs, argStart))
                            {
                                if (!HandleRuntimeError())
                                    return false;

                                frame = Fiber.Frames[Fiber.NumFrames - 1];
                                ip = frame.Ip;
                                stackStart = frame.StackStart;
                                stack = Fiber.Stack;
                                fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                bytecode = fn.Bytecode;
                                break;
                            }

                            Fiber.Frames.Add(frame = new CallFrame { Fn = receiver, StackStart = argStart, Ip = 0 });
                            Fiber.NumFrames++;
                            /* Load Frame */
                            ip = 0;
                            stackStart = argStart;
                            fn = (receiver as ObjFn) ?? (receiver as ObjClosure).Function;
                            bytecode = fn.Bytecode;
                            break;
                        }

                    case Instruction.STORE_LOCAL:
                        {
                            index = stackStart + bytecode[ip++];
                            stack[index] = stack[Fiber.StackTop - 1];
                            break;
                        }

                    case Instruction.CONSTANT:
                        {
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = fn.Constants[(bytecode[ip] << 8) + bytecode[ip + 1]];
                            ip += 2;
                            break;
                        }

                    case Instruction.LOAD_UPVALUE:
                        {
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = ((ObjClosure)frame.Fn).Upvalues[bytecode[ip++]].Container;
                            break;
                        }

                    case Instruction.STORE_UPVALUE:
                        {
                            ObjUpvalue[] upvalues = ((ObjClosure)frame.Fn).Upvalues;
                            upvalues[bytecode[ip++]].Container = stack[Fiber.StackTop - 1];
                            break;
                        }

                    case Instruction.LOAD_MODULE_VAR:
                        {
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = fn.Module.Variables[(bytecode[ip] << 8) + bytecode[ip + 1]].Container;
                            ip += 2;
                            break;
                        }

                    case Instruction.STORE_MODULE_VAR:
                        {
                            fn.Module.Variables[(bytecode[ip] << 8) + bytecode[ip + 1]].Container = stack[Fiber.StackTop - 1];
                            ip += 2;
                            break;
                        }

                    case Instruction.STORE_FIELD_THIS:
                        {
                            byte field = bytecode[ip++];
                            ObjInstance instance = (ObjInstance)stack[stackStart];
                            instance.Fields[field] = stack[Fiber.StackTop - 1];
                            break;
                        }

                    case Instruction.LOAD_FIELD:
                        {
                            byte field = bytecode[ip++];
                            ObjInstance instance = (ObjInstance)stack[--Fiber.StackTop];
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = instance.Fields[field];
                            break;
                        }

                    case Instruction.STORE_FIELD:
                        {
                            byte field = bytecode[ip++];
                            ObjInstance instance = (ObjInstance)stack[--Fiber.StackTop];
                            instance.Fields[field] = stack[Fiber.StackTop - 1];
                            break;
                        }

                    case Instruction.JUMP:
                        {
                            int offset = (bytecode[ip] << 8) + bytecode[ip + 1];
                            ip += offset + 2;
                            break;
                        }

                    case Instruction.LOOP:
                        {
                            // Jump back to the top of the loop.
                            int offset = (bytecode[ip] << 8) + bytecode[ip + 1];
                            ip += 2;
                            ip -= offset;
                            break;
                        }

                    case Instruction.JUMP_IF:
                        {
                            int offset = (bytecode[ip] << 8) + bytecode[ip + 1];
                            ip += 2;
                            Obj condition = stack[--Fiber.StackTop];

                            if (condition == Obj.False || condition == Obj.Null) ip += offset;
                            break;
                        }

                    case Instruction.AND:
                    case Instruction.OR:
                        {
                            int offset = (bytecode[ip] << 8) + bytecode[ip + 1];
                            ip += 2;
                            Obj condition = stack[Fiber.StackTop - 1];

                            if ((condition == Obj.Null || condition == Obj.False) ^ instruction == Instruction.OR)
                                ip += offset;
                            else
                                Fiber.StackTop--;
                            break;
                        }

                    case Instruction.CLOSE_UPVALUE:
                        {
                            Fiber.CloseUpvalue();
                            Fiber.StackTop--;
                            break;
                        }

                    case Instruction.RETURN:
                        {
                            Fiber.Frames.RemoveAt(--Fiber.NumFrames);
                            Obj result = stack[--Fiber.StackTop];
                            // Close any upvalues still in scope.
                            if (Fiber.StackTop > stackStart)
                            {
                                while (Fiber.OpenUpvalues != null && Fiber.OpenUpvalues.Index >= stackStart)
                                {
                                    Fiber.CloseUpvalue();
                                }
                            }

                            // If the fiber is complete, end it.
                            if (Fiber.NumFrames == 0)
                            {
                                // If this is the main fiber, we're done.
                                if (Fiber.Caller == null)
                                    return true;

                                // We have a calling fiber to resume.
                                Fiber = Fiber.Caller;
                                stack = Fiber.Stack;
                                // Store the result in the resuming fiber.
                                stack[Fiber.StackTop - 1] = result;
                            }
                            else
                            {
                                // Discard the stack slots for the call frame (leaving one slot for the result).
                                Fiber.StackTop = stackStart + 1;

                                // Store the result of the block in the first slot, which is where the
                                // caller expects it.
                                stack[stackStart] = result;
                            }

                            /* Load Frame */
                            frame = Fiber.Frames[Fiber.NumFrames - 1];
                            ip = frame.Ip;
                            stackStart = frame.StackStart;
                            fn = frame.Fn as ObjFn ?? (frame.Fn as ObjClosure).Function;
                            bytecode = fn.Bytecode;
                            break;
                        }

                    case Instruction.CLOSURE:
                        {
                            ObjFn prototype = fn.Constants[(bytecode[ip] << 8) + bytecode[ip + 1]] as ObjFn;
                            ip += 2;

                            // Create the closure and push it on the stack before creating upvalues
                            // so that it doesn't get collected.
                            ObjClosure closure = new ObjClosure(prototype);
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = closure;

                            // Capture upvalues.
                            for (int i = 0; i < prototype.NumUpvalues; i++)
                            {
                                byte isLocal = bytecode[ip++];
                                index = bytecode[ip++];
                                if (isLocal > 0)
                                {
                                    // Make an new upvalue to close over the parent's local variable.
                                    closure.Upvalues[i] = Fiber.CaptureUpvalue(stackStart + index);
                                }
                                else
                                {
                                    // Use the same upvalue as the current call frame.
                                    closure.Upvalues[i] = ((ObjClosure)frame.Fn).Upvalues[index];
                                }
                            }

                            break;
                        }

                    case Instruction.CLASS:
                        {
                            Obj name = stack[Fiber.StackTop - 2];
                            ObjClass superclass = stack[Fiber.StackTop - 1] as ObjClass;

                            Obj error = ValidateSuperclass(name, stack[Fiber.StackTop - 1]);
                            if (error != null)
                            {
                                Fiber.Error = error;
                                frame.Ip = ip;
                                if (!HandleRuntimeError())
                                    return false;
                                /* Load Frame */
                                frame = Fiber.Frames[Fiber.NumFrames - 1];
                                ip = frame.Ip;
                                stackStart = frame.StackStart;
                                stack = Fiber.Stack;
                                fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                bytecode = fn.Bytecode;
                                break;
                            }

                            int numFields = bytecode[ip++];

                            Obj classObj = new ObjClass(superclass, numFields, name as ObjString);

                            // Don't pop the superclass and name off the stack until the subclass is
                            // done being created, to make sure it doesn't get collected.
                            Fiber.StackTop -= 2;

                            // Now that we know the total number of fields, make sure we don't overflow.
                            if (superclass.NumFields + numFields <= Compiler.MaxFields)
                            {
                                stack[Fiber.StackTop++] = classObj;
                                break;
                            }

                            // Overflow handling
                            frame.Ip = ip;
                            Fiber.Error = Obj.MakeString(string.Format("Class '{0}' may not have more than 255 fields, including inherited ones.", name));
                            if (!HandleRuntimeError())
                                return false;
                            /* Load Frame */
                            frame = Fiber.Frames[Fiber.NumFrames - 1];
                            ip = frame.Ip;
                            stackStart = frame.StackStart;
                            stack = Fiber.Stack;
                            fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                            bytecode = fn.Bytecode;
                            break;
                        }

                    case Instruction.METHOD_INSTANCE:
                    case Instruction.METHOD_STATIC:
                        {
                            int symbol = (bytecode[ip] << 8) + bytecode[ip + 1];
                            ip += 2;
                            ObjClass classObj = stack[Fiber.StackTop - 1] as ObjClass;
                            Obj method = stack[Fiber.StackTop - 2];
                            bool isStatic = instruction == Instruction.METHOD_STATIC;
                            if (!BindMethod(isStatic, symbol, classObj, method))
                            {
                                frame.Ip = ip;
                                Fiber.Error = Obj.MakeString("Error while binding method");
                                if (!HandleRuntimeError())
                                    return false;
                                /* Load Frame */
                                frame = Fiber.Frames[Fiber.NumFrames - 1];
                                ip = frame.Ip;
                                stackStart = frame.StackStart;
                                stack = Fiber.Stack;
                                fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                bytecode = fn.Bytecode;
                                break;
                            }
                            Fiber.StackTop -= 2;
                            break;
                        }

                    case Instruction.LOAD_MODULE:
                        {
                            Obj name = fn.Constants[(bytecode[ip] << 8) + bytecode[ip + 1]];
                            ip += 2;
                            Obj result = ImportModule(name);

                            // If it returned a string, it was an error message.
                            if ((result is ObjString))
                            {
                                frame.Ip = ip;
                                Fiber.Error = result;
                                if (!HandleRuntimeError())
                                    return false;
                                /* Load Frame */
                                frame = Fiber.Frames[Fiber.NumFrames - 1];
                                ip = frame.Ip;
                                stackStart = frame.StackStart;
                                stack = Fiber.Stack;
                                fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                bytecode = fn.Bytecode;
                                break;
                            }

                            // Make a slot that the module's fiber can use to store its result in.
                            // It ends up getting discarded, but CODE_RETURN expects to be able to
                            // place a value there.
                            if (Fiber.StackTop >= Fiber.Capacity)
                                stack = Fiber.IncreaseStack();
                            stack[Fiber.StackTop++] = Obj.Null;

                            // If it returned a fiber to execute the module body, switch to it.
                            if (result is ObjFiber)
                            {
                                // Return to this module when that one is done.
                                (result as ObjFiber).Caller = Fiber;

                                frame.Ip = ip;
                                Fiber = (result as ObjFiber);
                                /* Load Frame */
                                frame = Fiber.Frames[Fiber.NumFrames - 1];
                                ip = frame.Ip;
                                stackStart = frame.StackStart;
                                stack = Fiber.Stack;
                                fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                bytecode = fn.Bytecode;
                            }

                            break;
                        }

                    case Instruction.IMPORT_VARIABLE:
                        {
                            Obj module = fn.Constants[(bytecode[ip] << 8) + bytecode[ip + 1]];
                            ip += 2;
                            Obj variable = fn.Constants[(bytecode[ip] << 8) + bytecode[ip + 1]];
                            ip += 2;
                            Obj result;
                            if (ImportVariable(module, variable, out result))
                            {
                                if (Fiber.StackTop >= Fiber.Capacity)
                                    stack = Fiber.IncreaseStack();
                                stack[Fiber.StackTop++] = result;
                            }
                            else
                            {
                                frame.Ip = ip;
                                Fiber.Error = result;
                                if (!HandleRuntimeError())
                                    return false;
                                /* Load Frame */
                                frame = Fiber.Frames[Fiber.NumFrames - 1];
                                ip = frame.Ip;
                                stackStart = frame.StackStart;
                                stack = Fiber.Stack;
                                fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                bytecode = fn.Bytecode;
                            }
                            break;
                        }

                    case Instruction.CONSTRUCT:
                        {
                            int stackPosition = Fiber.StackTop - 1 + (Instruction.CALL_0 - (Instruction)bytecode[ip]);
                            ObjClass v = stack[stackPosition] as ObjClass;
                            if (v == null)
                            {
                                Fiber.Error = Obj.MakeString("'this' should be a class.");
                                if (!HandleRuntimeError())
                                    return false;
                                /* Load Frame */
                                frame = Fiber.Frames[Fiber.NumFrames - 1];
                                ip = frame.Ip;
                                stackStart = frame.StackStart;
                                stack = Fiber.Stack;
                                fn = (frame.Fn as ObjFn) ?? (frame.Fn as ObjClosure).Function;
                                bytecode = fn.Bytecode;
                                break;
                            }
                            stack[stackPosition] = new ObjInstance(v);
                        }
                        break;

                    case Instruction.FOREIGN_CLASS:
                        // Not yet implemented
                        break;

                    case Instruction.FOREIGN_CONSTRUCT:
                        // Not yet implemented
                        break;

                    case Instruction.END:
                        // A CODE_END should always be preceded by a CODE_RETURN. If we get here,
                        // the compiler generated wrong code.
                        return false;
                }
            }

            // We should only exit this function from an explicit return from CODE_RETURN
            // or a runtime error.
        }
Exemple #6
0
        private static PrimitiveResult prim_map_iterate(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjMap map = (ObjMap)args[0].Obj;

            if (map.Count() == 0)
            {
                args[0] = new Value(false);
                return PrimitiveResult.Value;
            }

            // Start one past the last entry we stopped at.
            if (args[1].Type == ValueType.Num)
            {
                if (args[1].Num < 0)
                {
                    args[0] = new Value(false);
                    return PrimitiveResult.Value;
                }
                int index = (int)args[1].Num;

                if (index == args[1].Num)
                {
                    args[0] = index > map.Count() || map.Get(index).Type == ValueType.Undefined ? new Value(false) : new Value(index + 1);
                    return PrimitiveResult.Value;
                }

                args[0] = new Value("Iterator must be an integer.");
                return PrimitiveResult.Error;
            }

            // If we're starting the iteration, start at the first used entry.
            if (args[1].Type == ValueType.Null)
            {
                args[0] = new Value(1);
                return PrimitiveResult.Value;
            }

            args[0] = new Value("Iterator must be a number.");
            return PrimitiveResult.Error;
        }
Exemple #7
0
        static PrimitiveResult prim_map_containsKey(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjMap map = (ObjMap)args[0].Obj;

            if (ValidateKey(args[1]))
            {
                Value v = map.Get(args[1]);

                args[0] = new Value(v.Type != ValueType.Undefined);
                return PrimitiveResult.Value;
            }

            args[0] = new Value("Key must be a value type or fiber.");
            return PrimitiveResult.Error;
        }
Exemple #8
0
        static PrimitiveResult prim_map_subscriptSetter(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjMap map = args[0].Obj as ObjMap;

            if (ValidateKey(args[1]))
            {
                if (map != null)
                {
                    map.Set(args[1], args[2]);
                }
                args[0] = args[2];
                return PrimitiveResult.Value;
            }

            args[0] = new Value("Key must be a value type or fiber.");
            return PrimitiveResult.Error;
        }
Exemple #9
0
 static PrimitiveResult prim_map_instantiate(WrenVM vm, ObjFiber fiber, Value[] args)
 {
     args[0] = new Value(new ObjMap());
     return PrimitiveResult.Value;
 }
Exemple #10
0
 static PrimitiveResult prim_fn_toString(WrenVM vm, ObjFiber fiber, Value[] args)
 {
     args[0] = new Value("<fn>");
     return PrimitiveResult.Value;
 }
Exemple #11
0
 static PrimitiveResult prim_fn_call16(WrenVM vm, ObjFiber fiber, Value[] args) { return CallFn(args, 16); }
Exemple #12
0
 static PrimitiveResult prim_fn_arity(WrenVM vm, ObjFiber fiber, Value[] args)
 {
     ObjFn fn = args[0].Obj as ObjFn;
     args[0] = fn != null ? new Value(fn.Arity) : new Value(0.0);
     return PrimitiveResult.Value;
 }
Exemple #13
0
        static PrimitiveResult prim_fn_new(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            if (args[1].Obj == null || args[1].Obj.Type != ObjType.Fn && args[1].Obj.Type != ObjType.Closure)
            {
                args[0] = new Value("Argument must be a function.");
                return PrimitiveResult.Error;
            }

            // The block argument is already a function, so just return it.
            args[0] = args[1];
            return PrimitiveResult.Value;
        }
Exemple #14
0
 static PrimitiveResult prim_fn_instantiate(WrenVM vm, ObjFiber fiber, Value[] args)
 {
     // Return the Fn class itself. When we then call "new" on it, it will return
     // the block.
     return PrimitiveResult.Value;
 }
Exemple #15
0
        static PrimitiveResult prim_fiber_yield1(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            // Unhook this fiber from the one that called it.
            ObjFiber caller = fiber.Caller;
            fiber.Caller = null;
            fiber.CallerIsTrying = false;

            // If we don't have any other pending fibers, jump all the way out of the
            // interpreter.
            if (caller == null)
            {
                args[0] = new Value (ValueType.Null);
            }
            else
            {
                // Make the caller's run method return the argument passed to yield.
                caller.StoreValue(-1, args[1]);

                // When the yielding fiber resumes, we'll store the result of the yield call
                // in its stack. Since Fiber.yield(value) has two arguments (the Fiber class
                // and the value) and we only need one slot for the result, discard the other
                // slot now.
                fiber.StackTop--;

                // Return the fiber to resume.
                args[0] = new Value(caller);
            }

            return PrimitiveResult.RunFiber;
        }
Exemple #16
0
        static PrimitiveResult prim_list_subscriptSetter(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjList list = (ObjList)args[0].Obj;
            if (args[1].Type == ValueType.Num)
            {
                int index = (int)args[1].Num;

                if (index == args[1].Num)
                {
                    if (index < 0)
                    {
                        index += list.Count();
                    }

                    if (list != null && index >= 0 && index < list.Count())
                    {
                        list.Set(args[2], index);
                        args[0] = args[2];
                        return PrimitiveResult.Value;
                    }

                    args[0] = new Value("Subscript out of bounds.");
                    return PrimitiveResult.Error;
                }

                args[0] = new Value("Subscript must be an integer.");
                return PrimitiveResult.Error;
            }
            args[0] = new Value("Subscript must be a number.");
            return PrimitiveResult.Error;
        }
Exemple #17
0
 static PrimitiveResult prim_list_add(WrenVM vm, ObjFiber fiber, Value[] args)
 {
     ObjList list = args[0].Obj as ObjList;
     if (list == null)
     {
         args[0] = new Value("Trying to add to a non-list");
         return PrimitiveResult.Error;
     }
     list.Add(args[1]);
     args[0] = args[1];
     return PrimitiveResult.Value;
 }
Exemple #18
0
        static PrimitiveResult prim_map_subscript(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjMap map = args[0].Obj as ObjMap;

            if (ValidateKey(args[1]))
            {
                if (map != null)
                {
                    args[0] = map.Get(args[1]);
                    if (args[0].Type == ValueType.Undefined)
                    {
                        args[0] = new Value (ValueType.Null);
                    }
                }
                else
                {
                    args[0] = new Value (ValueType.Null);
                }
                return PrimitiveResult.Value;
            }

            args[0] = new Value("Key must be a value type or fiber.");
            return PrimitiveResult.Error;
        }
Exemple #19
0
        static PrimitiveResult prim_list_clear(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjList list = args[0].Obj as ObjList;
            if (list == null)
            {
                args[0] = new Value("Trying to clear a non-list");
                return PrimitiveResult.Error;
            }
            list.Clear();

            args[0] = new Value (ValueType.Null);
            return PrimitiveResult.Value;
        }
Exemple #20
0
 static PrimitiveResult prim_map_clear(WrenVM vm, ObjFiber fiber, Value[] args)
 {
     ObjMap m = args[0].Obj as ObjMap;
     if (m != null)
         m.Clear();
     args[0] = new Value (ValueType.Null);
     return PrimitiveResult.Value;
 }
Exemple #21
0
        static PrimitiveResult prim_list_count(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjList list = args[0].Obj as ObjList;
            if (list != null)
            {
                args[0] = new Value(list.Count());
                return PrimitiveResult.Value;
            }

            args[0] = new Value("Trying to clear a non-list");
            return PrimitiveResult.Error;
        }
Exemple #22
0
 static PrimitiveResult prim_map_count(WrenVM vm, ObjFiber fiber, Value[] args)
 {
     ObjMap m = (ObjMap)args[0].Obj;
     args[0] = new Value(m.Count());
     return PrimitiveResult.Value;
 }
Exemple #23
0
        static PrimitiveResult prim_list_insert(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjList list = args[0].Obj as ObjList;
            if (list != null)
            {
                if (args[1].Type == ValueType.Num)
                {
                    if (args[1].Num == (int)args[1].Num)
                    {
                        int index = (int)args[1].Num;

                        if (index < 0)
                            index += list.Count() + 1;
                        if (index >= 0 && index <= list.Count())
                        {
                            list.Insert(args[2], index);
                            args[0] = args[2];
                            return PrimitiveResult.Value;
                        }
                        args[0] = new Value("Index out of bounds.");
                        return PrimitiveResult.Error;
                    }

                    // count + 1 here so you can "insert" at the very end.
                    args[0] = new Value("Index must be an integer.");
                    return PrimitiveResult.Error;
                }

                args[0] = new Value("Index must be a number.");
                return PrimitiveResult.Error;
            }

            args[0] = new Value("List cannot be null");
            return PrimitiveResult.Error;
        }
Exemple #24
0
        static bool prim_fiber_new(WrenVM vm, Obj[] args, int stackStart)
        {
            Obj o = args[stackStart + 1];
            if (o is ObjFn || o is ObjClosure)
            {
                ObjFiber newFiber = new ObjFiber(o);

                // The compiler expects the first slot of a function to hold the receiver.
                // Since a fiber's stack is invoked directly, it doesn't have one, so put it
                // in here.
                newFiber.Push(Obj.Null);

                args[stackStart] = newFiber;
                return true;
            }

            vm.Fiber.Error = Obj.MakeString("Argument must be a function.");
            return false;
        }
Exemple #25
0
        static PrimitiveResult prim_list_iterate(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjList list = (ObjList)args[0].Obj;

            // If we're starting the iteration, return the first index.
            if (args[1].Type == ValueType.Null)
            {
                if (list.Count() != 0)
                {
                    args[0] = new Value(0.0);
                    return PrimitiveResult.Value;
                }

                args[0] = new Value(false);
                return PrimitiveResult.Value;
            }

            if (args[1].Type == ValueType.Num)
            {
                if (args[1].Num == ((int)args[1].Num))
                {
                    double index = args[1].Num;
                    if (!(index < 0) && !(index >= list.Count() - 1))
                    {
                        args[0] = new Value(index + 1);
                        return PrimitiveResult.Value;
                    }

                    // Otherwise, move to the next index.
                    args[0] = new Value(false);
                    return PrimitiveResult.Value;
                }

                // Stop if we're out of bounds.
                args[0] = new Value("Iterator must be an integer.");
                return PrimitiveResult.Error;
            }

            args[0] = new Value("Iterator must be a number.");
            return PrimitiveResult.Error;
        }
Exemple #26
0
        private ObjFiber LoadModule(Obj name, string source)
        {
            ObjModule module = GetModule(name);

            // See if the module has already been loaded.
            if (module == null)
            {
                module = new ObjModule(name as ObjString);

                // Store it in the VM's module registry so we don't load the same module
                // multiple times.
                _modules.Set(name, module);

                // Implicitly import the core module.
                ObjModule coreModule = GetCoreModule();
                foreach (ModuleVariable t in coreModule.Variables)
                {
                    DefineVariable(module, t.Name, t.Container);
                }
            }

            ObjFn fn = Compiler.Compile(this, module, name.ToString(), source, true);
            if (fn == null)
            {
                // TODO: Should we still store the module even if it didn't compile?
                return null;
            }

            ObjFiber moduleFiber = new ObjFiber(fn);

            // Return the fiber that executes the module.
            return moduleFiber;
        }
Exemple #27
0
        static PrimitiveResult prim_list_iteratorValue(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjList list = (ObjList)args[0].Obj;

            if (args[1].Type == ValueType.Num)
            {
                if (args[1].Num == ((int)args[1].Num))
                {
                    int index = (int)args[1].Num;

                    if (index >= 0 && index < list.Count())
                    {
                        args[0] = list.Get(index);
                        return PrimitiveResult.Value;
                    }

                    args[0] = new Value("Iterator out of bounds.");
                    return PrimitiveResult.Error;
                }

                args[0] = new Value("Iterator must be an integer.");
                return PrimitiveResult.Error;
            }

            args[0] = new Value("Iterator must be a number.");
            return PrimitiveResult.Error;
        }
Exemple #28
0
        // Execute [source] in the context of the core module.
        private InterpretResult LoadIntoCore(string source)
        {
            ObjModule coreModule = GetCoreModule();

            ObjFn fn = Compiler.Compile(this, coreModule, "", source, true);
            if (fn == null) return InterpretResult.CompileError;

            Fiber = new ObjFiber(fn);

            return RunInterpreter() ? InterpretResult.Success : InterpretResult.RuntimeError;
        }
Exemple #29
0
        static PrimitiveResult prim_list_removeAt(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjList list = args[0].Obj as ObjList;

            if (list != null)
            {
                if (args[1].Type == ValueType.Num)
                {
                    if (args[1].Num == ((int)args[1].Num))
                    {
                        int index = (int)args[1].Num;
                        if (index < 0)
                            index += list.Count();
                        if (index >= 0 && index < list.Count())
                        {
                            args[0] = list.RemoveAt(index);
                            return PrimitiveResult.Value;
                        }

                        args[0] = new Value("Index out of bounds.");
                        return PrimitiveResult.Error;
                    }

                    args[0] = new Value("Index must be an integer.");
                    return PrimitiveResult.Error;
                }

                args[0] = new Value("Index must be a number.");
                return PrimitiveResult.Error;
            }

            args[0] = new Value("List cannot be null");
            return PrimitiveResult.Error;
        }
Exemple #30
0
        /* Dirty Hack */
        private bool HandleRuntimeError()
        {
            ObjFiber f = Fiber;
            if (f.CallerIsTrying)
            {
                f.Caller.SetReturnValue(f.Error);
                Fiber = f.Caller;
                return true;
            }
            Fiber = null;

            // TODO: Fix this so that there is no dependancy on the console
            if (!(f.Error is ObjString))
            {
                f.Error = Obj.MakeString("Error message must be a string.");
            }
            Console.Error.WriteLine(f.Error as ObjString);
            return false;
        }
Exemple #31
0
        static PrimitiveResult prim_list_subscript(WrenVM vm, ObjFiber fiber, Value[] args)
        {
            ObjList list = args[0].Obj as ObjList;

            if (list == null)
                return PrimitiveResult.Error;

            if (args[1].Type == ValueType.Num)
            {
                int index = (int)args[1].Num;
                if (index == args[1].Num)
                {
                    if (index < 0)
                    {
                        index += list.Count();
                    }
                    if (index >= 0 && index < list.Count())
                    {
                        args[0] = list.Get(index);
                        return PrimitiveResult.Value;
                    }

                    args[0] = new Value("Subscript out of bounds.");
                    return PrimitiveResult.Error;
                }
                args[0] = new Value("Subscript must be an integer.");
                return PrimitiveResult.Error;
            }

            ObjRange r = args[1].Obj as ObjRange;

            if (r == null)
            {
                args[0] = new Value("Subscript must be a number or a range.");
                return PrimitiveResult.Error;
            }

            // TODO: This is seriously broken and needs a rewrite
            int from = (int)r.From;
            if (from != r.From)
            {
                args[0] = new Value("Range start must be an integer.");
                return PrimitiveResult.Error;
            }
            int to = (int)r.To;
            if (to != r.To)
            {
                args[0] = new Value("Range end must be an integer.");
                return PrimitiveResult.Error;
            }

            if (from < 0)
                from += list.Count();
            if (to < 0)
                to += list.Count();

            int step = to < from ? -1 : 1;

            if (step > 0 && r.IsInclusive)
                to += 1;
            if (step < 0 && !r.IsInclusive)
                to += 1;

            // Handle copying an empty list
            if (list.Count() == 0 && to == (r.IsInclusive ? -1 : 0))
            {
                to = 0;
                step = 1;
            }

            int count = (to - from) * step + (step < 0 ? 1 : 0);

            if (to < 0 || from + (count * step) > list.Count())
            {
                args[0] = new Value("Range end out of bounds.");
                return PrimitiveResult.Error;
            }
            if (from < 0 || (from >= list.Count() && from > 0))
            {
                args[0] = new Value("Range start out of bounds.");
                return PrimitiveResult.Error;
            }

            ObjList result = new ObjList(count);
            for (int i = 0; i < count; i++)
            {
                result.Add(list.Get(from + (i * step)));
            }

            args[0] = new Value(result);
            return PrimitiveResult.Value;
        }