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; }
public static void LoadLibrary(WrenVM vm, string libraryName, string typeName) { Type wrenLibrary = Type.GetType("Wren.Core.Library.LoadLibrary"); var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var di = new DirectoryInfo(path); foreach (var file in di.GetFiles(libraryName)) { try { var nextAssembly = Assembly.LoadFrom(file.FullName); foreach (var type in nextAssembly.GetTypes()) { if (type.GetCustomAttributes(wrenLibrary, false).Length > 0) { // This class implements the interface var m = type.GetMethod("LoadLibrary"); m.Invoke(null, new object[] {vm}); } } } catch (BadImageFormatException) { // Not a .net assembly - ignore } } }
public static void LoadLibrary(WrenVM vm) { vm.Interpret("", "", MetaLibSource); ObjClass meta = (ObjClass)vm.FindVariable("Meta"); vm.Primitive(meta.ClassObj, "eval(_)", Eval); }
public static void LoadLibrary(WrenVM vm) { vm.Interpret("scheduler", "scheduler", _schedulerSource); ObjClass scheduler = (ObjClass)vm.FindVariable("scheduler", "Scheduler"); vm.Primitive(scheduler.ClassObj, "captureMethods_()", CaptureMethods); vm.Interpret("scheduler", "scheduler", "Scheduler.captureMethods_()"); }
static int RunFile(string path) { if (!File.Exists(path)) return 66; // File Not Found _loadedFile = path; string source = File.ReadAllText(path); WrenVM vm = new WrenVM { LoadModuleFn = LoadModule }; LibraryLoader.LoadLibraries(vm); return (int)vm.Interpret("main", path, source); }
static int RunFile(string path) { if (File.Exists(path)) { loadedFile = path; string source = File.ReadAllText(path); WrenVM vm = new WrenVM { LoadModuleFn = LoadModule }; return (int)vm.Interpret(path, source); } return 66; // File Not Found }
public static void LoadLibrary(WrenVM vm) { vm.Interpret("io", "io", IoSource); ObjClass file = (ObjClass)vm.FindVariable("io", "File"); vm.Primitive(file.ClassObj, "open_(_,_)", Open); vm.Primitive(file.ClassObj, "sizePath_(_,_)", SizePath); vm.Primitive(file, "close_(_)", Close); vm.Primitive(file, "descriptor", Descriptor); vm.Primitive(file, "readBytes_(_,_)", ReadBytes); vm.Primitive(file, "size_(_)", Size); }
static void RunRepl() { WrenVM vm = new WrenVM(); Console.WriteLine("-- wren v0.0.0"); string line = ""; for (; line != "/exit"; ) { Console.Write("> "); line = Console.ReadLine(); // TODO: Handle failure. vm.Interpret("Prompt", line); } }
static void RunRepl() { WrenVM vm = new WrenVM(); LibraryLoader.LoadLibraries(vm); Console.WriteLine("-- wren v0.0.0"); string line = ""; for (; ; ) { Console.Write("> "); line += Console.ReadLine() + "\n"; if(OpenBrackets(line) > 0) continue; // TODO: Handle failure. vm.Interpret("Prompt","Prompt", line); line = ""; } }
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; }
static bool prim_map_instantiate(WrenVM vm, Obj[] args, int stackStart) { args[stackStart] = new ObjMap(); return true; }
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; }
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; }
static bool prim_fn_new(WrenVM vm, Obj[] args, int stackStart) { Obj v = args[stackStart + 1]; if (v != null && (v is ObjFn || v is ObjClosure)) { args[stackStart] = args[stackStart + 1]; return true; } // The block argument is already a function, so just return it. vm.Fiber.Error = Obj.MakeString("Argument must be a function."); return false; }
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; }
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; }
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; }
// Creates a string containing an appropriate method not found error for a // method with [symbol] on [classObj]. static void MethodNotFound(WrenVM vm, ObjClass classObj, int symbol) { vm.Fiber.Error = Obj.MakeString(string.Format("{0} does not implement '{1}'.", classObj.Name, vm.MethodNames[symbol])); }
static bool prim_list_instantiate(WrenVM vm, Obj[] args, int stackStart) { args[stackStart] = new ObjList(16); return true; }
static bool prim_fn_toString(WrenVM vm, Obj[] args, int stackStart) { args[stackStart] = Obj.MakeString("<fn>"); return true; }
static bool prim_fn_arity(WrenVM vm, Obj[] args, int stackStart) { ObjFn fn = args[stackStart] as ObjFn; args[stackStart] = fn != null ? new Obj(fn.Arity) : new Obj(0.0); return true; }
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; }
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; }
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; }
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; }
static bool prim_map_count(WrenVM vm, Obj[] args, int stackStart) { ObjMap m = (ObjMap)args[stackStart]; args[stackStart] = new Obj(m.Count()); return true; }
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; }
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; }
static bool prim_fiber_yield1(WrenVM vm, Obj[] args, int stackStart) { // Unhook this fiber from the one that called it. ObjFiber caller = vm.Fiber.Caller; vm.Fiber.Caller = null; vm.Fiber.CallerIsTrying = false; // If we don't have any other pending fibers, jump all the way out of the // interpreter. if (caller == null) { args[stackStart] = Obj.Null; } else { // Make the caller's run method return the argument passed to yield. caller.StoreValue(-1, args[stackStart + 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. vm.Fiber.StackTop--; // Return the fiber to resume. args[stackStart] = caller; } return false; }
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; }