Пример #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;
        }
Пример #2
0
 public Obj GetKey(int index)
 {
     if (index < 0 || index >= _entries.Count)
         return Undefined;
     Obj[] v = new Obj[_entries.Count];
     _entries.Keys.CopyTo(v, 0);
     return v[index];
 }
Пример #3
0
        // Removes [key] from [map], if present. Returns the value for the key if found
        // or `NULL_VAL` otherwise.
        public Obj Remove(Obj key)
        {
            Obj v;
            if (!_entries.TryGetValue(key, out v)) 
                return Null;

            _entries.Remove(key);
            return v;
        }
Пример #4
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);
        }
Пример #5
0
        // TODO: The argument list here is getting a bit gratuitous.
        // Creates a new function object with the given code and constants. The new
        // function will take over ownership of [bytecode] and [sourceLines]. It will
        // copy [constants] into its own array.
        public ObjFn(ObjModule module,
            Obj[] constants,
            int numUpvalues, int arity,
            byte[] bytecode, ObjString debugSourcePath,
            string debugName, int[] sourceLines)
        {
            Bytecode = bytecode;
            Constants = constants;
            Module = module;
            NumUpvalues = numUpvalues;
            NumConstants = constants.Length;
            Arity = arity;

            /* Debug Information */
            SourcePath = debugSourcePath;
            Name = debugName;
            SourceLines = sourceLines;

            ClassObj = WrenVM.FnClass;
        }
Пример #6
0
        static bool prim_map_subscriptSetter(WrenVM vm, Obj[] args, int stackStart)
        {
            if (ValidateKey(args[stackStart + 1]))
            {
                ObjMap map = args[stackStart] as ObjMap;

                if (map != null)
                {
                    map.Set(args[stackStart + 1], args[stackStart + 2]);
                }
                args[stackStart] = args[stackStart + 2];
                return true;
            }

            vm.Fiber.Error = Obj.MakeString("Key must be a value type or fiber.");
            return false;
        }
Пример #7
0
 static bool prim_map_clear(WrenVM vm, Obj[] args, int stackStart)
 {
     ObjMap m = args[stackStart] as ObjMap;
     if (m != null)
         m.Clear();
     args[stackStart] = Obj.Null;
     return true;
 }
Пример #8
0
        // Looks up [key] in [map]. If found, returns the value. Otherwise, returns UNDEFINED.
        public Obj Get(Obj key)
        {
            Obj v;

            return(_entries.TryGetValue(key, out v) ? v : Undefined);
        }
Пример #9
0
        static bool prim_map_subscript(WrenVM vm, Obj[] args, int stackStart)
        {
            Obj a = args[stackStart + 1];
            if (ValidateKey(a))
            {
                ObjMap map = args[stackStart] as ObjMap;
                if (map != null)
                {
                    args[stackStart] = map.Get(a);
                    if (args[stackStart] == Obj.Undefined)
                    {
                        args[stackStart] = Obj.Null;
                    }
                }
                else
                {
                    args[stackStart] = Obj.Null;
                }
                return true;
            }

            vm.Fiber.Error = Obj.MakeString("Key must be a value type or fiber.");
            return false;
        }
Пример #10
0
 static bool prim_fn_toString(WrenVM vm, Obj[] args, int stackStart)
 {
     args[stackStart] = Obj.MakeString("<fn>");
     return true;
 }
Пример #11
0
        // Defines [methodValue] as a method on [classObj].
        private static bool BindMethod(bool isStatic, int symbol, ObjClass classObj, Obj methodContainer)
        {
            // If we are binding a foreign method, just return, as this will be handled later
            if (methodContainer is ObjString)
                return true;

            ObjFn methodFn = methodContainer as ObjFn ?? ((ObjClosure)methodContainer).Function;

            Method method = new Method { MType = MethodType.Block, Obj = methodContainer };

            if (isStatic)
                classObj = classObj.ClassObj;

            // Methods are always bound against the class, and not the metaclass, even
            // for static methods, because static methods don't have instance fields
            // anyway.
            Compiler.BindMethodCode(classObj, methodFn);

            classObj.BindMethod(symbol, method);
            return true;
        }
Пример #12
0
        bool CheckArity(Obj[] args, int numArgs, int stackStart)
        {
            ObjFn fn = args[stackStart] as ObjFn;
            ObjClosure c = args[stackStart] as ObjClosure;

            if (c != null)
            {
                fn = c.Function;
            }

            if (fn == null)
            {
                Fiber.Error = Obj.MakeString("Receiver must be a function or closure.");
                return false;
            }

            if (numArgs - 1 < fn.Arity)
            {
                Fiber.Error = Obj.MakeString("Function expects more arguments.");
                return false;
            }

            return true;
        }
Пример #13
0
        private static bool prim_map_iterate(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjMap map = (ObjMap)args[stackStart];

            if (map.Count() == 0)
            {
                args[stackStart] = Obj.False;
                return true;
            }

            // Start one past the last entry we stopped at.
            if (args[stackStart + 1].Type == ObjType.Num)
            {
                if (args[stackStart + 1].Num < 0)
                {
                    args[stackStart] = Obj.False;
                    return true;
                }
                int index = (int)args[stackStart + 1].Num;

                if (index == args[stackStart + 1].Num)
                {
                    args[stackStart] = index > map.Count() || map.Get(index) == Obj.Undefined ? Obj.False : new Obj(index + 1);
                    return true;
                }

                vm.Fiber.Error = Obj.MakeString("Iterator must be an integer.");
                return false;
            }

            // If we're starting the iteration, start at the first used entry.
            if (args[stackStart + 1] == Obj.Null)
            {
                args[stackStart] = new Obj(1);
                return true;
            }

            vm.Fiber.Error = Obj.MakeString("Iterator must be a number.");
            return false;
        }
Пример #14
0
        static bool prim_list_count(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjList list = args[stackStart] as ObjList;
            if (list != null)
            {
                args[stackStart] = new Obj(list.Count());
                return true;
            }

            vm.Fiber.Error = Obj.MakeString("Trying to clear a non-list");
            return false;
        }
Пример #15
0
        static bool prim_list_insert(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjList list = (ObjList)args[stackStart];

            if (args[stackStart + 1].Type == ObjType.Num)
            {
                int index = (int)args[stackStart + 1].Num;
                if (args[stackStart + 1].Num == index)
                {
                    if (index < 0)
                        index += list.Count() + 1;
                    if (index >= 0 && index <= list.Count())
                    {
                        list.Insert(args[stackStart + 2], index);
                        args[stackStart] = args[stackStart + 2];
                        return true;
                    }
                    vm.Fiber.Error = Obj.MakeString("Index out of bounds.");
                    return false;
                }

                // count + 1 here so you can "insert" at the very end.
                vm.Fiber.Error = Obj.MakeString("Index must be an integer.");
                return false;
            }

            vm.Fiber.Error = Obj.MakeString("Index must be a number.");
            return false;
        }
Пример #16
0
        static bool prim_list_clear(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjList list = args[stackStart] as ObjList;
            if (list == null)
            {
                vm.Fiber.Error = Obj.MakeString("Trying to clear a non-list");
                return false;
            }
            list.Clear();

            args[stackStart] = Obj.Null;
            return true;
        }
Пример #17
0
 static bool prim_list_add(WrenVM vm, Obj[] args, int stackStart)
 {
     ObjList list = args[stackStart] as ObjList;
     if (list == null)
     {
         vm.Fiber.Error = Obj.MakeString("Trying to add to a non-list");
         return false;
     }
     list.Add(args[stackStart + 1]);
     args[stackStart] = args[stackStart + 1];
     return true;
 }
Пример #18
0
 static bool prim_list_instantiate(WrenVM vm, Obj[] args, int stackStart)
 {
     args[stackStart] = new ObjList(16);
     return true;
 }
Пример #19
0
        static bool prim_map_containsKey(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjMap map = (ObjMap)args[stackStart];

            if (ValidateKey(args[stackStart + 1]))
            {
                Obj v = map.Get(args[stackStart + 1]);

                args[stackStart] = Obj.Bool(v != Obj.Undefined);
                return true;
            }

            vm.Fiber.Error = Obj.MakeString("Key must be a value type or fiber.");
            return false;
        }
Пример #20
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;
        }
Пример #21
0
 static bool prim_map_count(WrenVM vm, Obj[] args, int stackStart)
 {
     ObjMap m = (ObjMap)args[stackStart];
     args[stackStart] = new Obj(m.Count());
     return true;
 }
Пример #22
0
        private bool ImportVariable(Obj moduleName, Obj variableName, out Obj result)
        {
            ObjModule module = GetModule(moduleName);
            if (module == null)
            {
                result = Obj.MakeString("Could not load module");
                return false; // Should only look up loaded modules
            }

            ObjString variable = variableName as ObjString;
            if (variable == null)
            {
                result = Obj.MakeString("Variable name must be a string");
                return false;
            }

            int variableEntry = module.Variables.FindIndex(v => v.Name == variable.ToString());

            // It's a runtime error if the imported variable does not exist.
            if (variableEntry == -1)
            {
                result = Obj.MakeString(string.Format("Could not find a variable named '{0}' in module '{1}'.", variableName, moduleName));
                return false;
            }

            result = module.Variables[variableEntry].Container;
            return true;
        }
Пример #23
0
        static bool prim_list_iterate(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjList list = (ObjList)args[stackStart];

            // If we're starting the iteration, return the first index.
            if (args[stackStart + 1] == Obj.Null)
            {
                if (list.Count() != 0)
                {
                    args[stackStart] = new Obj(0.0);
                    return true;
                }

                args[stackStart] = Obj.False;
                return true;
            }

            if (args[stackStart + 1].Type == ObjType.Num)
            {
                int index = (int)args[stackStart + 1].Num;
                if (args[stackStart + 1].Num == index)
                {
                    if (!(index < 0) && !(index >= list.Count() - 1))
                    {
                        // Move to the next index.
                        args[stackStart] = new Obj(index + 1);
                        return true;
                    }

                    // Stop if we're out of bounds.
                    args[stackStart] = Obj.False;
                    return true;
                }

                vm.Fiber.Error = Obj.MakeString("Iterator must be an integer.");
                return false;
            }

            vm.Fiber.Error = Obj.MakeString("Iterator must be a number.");
            return false;
        }
Пример #24
0
 // Associates [key] with [value] in [map].
 public void Set(Obj key, Obj c)
 {
     _entries[key] = c;
 }
Пример #25
0
 // Looks up the previously loaded module with [name].
 // Returns null if no module with that name has been loaded.
 private ObjModule GetModule(Obj name)
 {
     Obj moduleContainer = _modules.Get(name);
     return moduleContainer == Obj.Undefined ? null : moduleContainer as ObjModule;
 }
Пример #26
0
        static bool prim_list_removeAt(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjList list = (ObjList)args[stackStart];

            if (args[stackStart + 1].Type == ObjType.Num)
            {
                int index = (int)args[stackStart + 1].Num;
                if (args[stackStart + 1].Num == index)
                {
                    if (index < 0)
                        index += list.Count();
                    if (index >= 0 && index < list.Count())
                    {
                        args[stackStart] = list.RemoveAt(index);
                        return true;
                    }

                    vm.Fiber.Error = Obj.MakeString("Index out of bounds.");
                    return false;
                }

                vm.Fiber.Error = Obj.MakeString("Index must be an integer.");
                return false;
            }

            vm.Fiber.Error = Obj.MakeString("Index must be a number.");
            return false;
        }
Пример #27
0
        private Obj ImportModule(Obj name)
        {
            // If the module is already loaded, we don't need to do anything.
            if (_modules.Get(name) != Obj.Undefined) return Obj.Null;

            // Load the module's source code from the embedder.
            string source = LoadModuleFn(name.ToString());
            if (source == null)
            {
                // Couldn't load the module.
                return Obj.MakeString(string.Format("Could not find module '{0}'.", name));
            }

            ObjFiber moduleFiber = LoadModule(name, source);

            // Return the fiber that executes the module.
            return moduleFiber;
        }
Пример #28
0
        static bool prim_list_subscript(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjList list = (ObjList)args[stackStart];

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

                    vm.Fiber.Error = Obj.MakeString("Subscript out of bounds.");
                    return false;
                }
                vm.Fiber.Error = Obj.MakeString("Subscript must be an integer.");
                return false;
            }

            ObjRange r = args[stackStart + 1] as ObjRange;

            if (r == null)
            {
                vm.Fiber.Error = Obj.MakeString("Subscript must be a number or a range.");
                return false;
            }

            // TODO: This is seriously broken and needs a rewrite
            int from = (int)r.From;
            if (from != r.From)
            {
                vm.Fiber.Error = Obj.MakeString("Range start must be an integer.");
                return false;
            }
            int to = (int)r.To;
            if (to != r.To)
            {
                vm.Fiber.Error = Obj.MakeString("Range end must be an integer.");
                return false;
            }

            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())
            {
                vm.Fiber.Error = Obj.MakeString("Range end out of bounds.");
                return false;
            }
            if (from < 0 || (from >= list.Count() && from > 0))
            {
                vm.Fiber.Error = Obj.MakeString("Range start out of bounds.");
                return false;
            }

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

            args[stackStart] = result;
            return true;
        }
Пример #29
0
        // Verifies that [superclass] is a valid object to inherit from. That means it
        // must be a class and cannot be the class of any built-in type.
        //
        // If successful, returns null. Otherwise, returns a string for the runtime
        // error message.
        private static Obj ValidateSuperclass(Obj name, Obj superclassContainer)
        {
            // Make sure the superclass is a class.
            ObjClass superClass = superclassContainer as ObjClass;
            if (superClass != null)
            {
                // Make sure it doesn't inherit from a sealed built-in type. Primitive methods
                // on these classes assume the instance is one of the other Obj___ types and
                // will fail horribly if it's actually an ObjInstance.
                return superClass.IsSealed ? Obj.MakeString(string.Format("Class '{0}' cannot inherit from built-in class '{1}'.", name as ObjString, (superClass.Name))) : null;
            }

            return Obj.MakeString(string.Format("Class '{0}' cannot inherit from a non-class object.", name));
        }
Пример #30
0
        static bool prim_list_subscriptSetter(WrenVM vm, Obj[] args, int stackStart)
        {
            ObjList list = (ObjList)args[stackStart];
            if (args[stackStart + 1].Type == ObjType.Num)
            {
                int index = (int)args[stackStart + 1].Num;

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

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

                    vm.Fiber.Error = Obj.MakeString("Subscript out of bounds.");
                    return false;
                }

                vm.Fiber.Error = Obj.MakeString("Subscript must be an integer.");
                return false;
            }
            vm.Fiber.Error = Obj.MakeString("Subscript must be a number.");
            return false;
        }
Пример #31
0
        internal int DefineVariable(ObjModule module, string name, Obj c)
        {
            if (module == null) module = GetCoreModule();
            if (module.Variables.Count == ObjModule.MaxModuleVars) return -2;

            // See if the variable is already explicitly or implicitly declared.
            int symbol = module.Variables.FindIndex(m => m.Name == name);

            if (symbol == -1)
            {
                // Brand new variable.
                module.Variables.Add(new ModuleVariable { Name = name, Container = c });
                symbol = module.Variables.Count - 1;
            }
            else if (module.Variables[symbol].Container == Obj.Undefined)
            {
                // Explicitly declaring an implicitly declared one. Mark it as defined.
                module.Variables[symbol].Container = c;
            }
            else
            {
                // Already explicitly declared.
                symbol = -1;
            }

            return symbol;
        }
Пример #32
0
 static bool prim_map_instantiate(WrenVM vm, Obj[] args, int stackStart)
 {
     args[stackStart] = new ObjMap();
     return true;
 }