static int RunFile(string path) { if (File.Exists(path)) { _loadedFile = path; string source = File.ReadAllText(path); SophieVM vm = new SophieVM { LoadModuleFn = LoadModule }; return (int)vm.Interpret(path, source); } return 66; // File Not Found }
static void RunRepl() { SophieVM vm = new SophieVM(); Console.WriteLine("-- sophie v0.0.0"); string line = ""; for (; line != "/exit"; ) { Console.Write("> "); line = Console.ReadLine(); // TODO: Handle failure. vm.Interpret("Prompt", line); } }
static bool WriteString(SophieVM vm, Obj[] stack, int argStart) { if (stack[argStart + 1] != null && stack[argStart + 1].Type == ObjType.Obj) { string s = stack[argStart + 1].ToString(); Console.Write(s); } stack[argStart] = Obj.Null; return true; }
static bool Time(SophieVM vm, Obj[] stack, int argStart) { stack[argStart] = new Obj((double)DateTime.Now.Ticks / 10000000); return true; }
static bool Read(SophieVM vm, Obj[] stack, int argStart) { stack[argStart] = Obj.MakeString(Console.ReadLine()); if (((ObjString)stack[argStart]).Str == "") { stack[argStart] = Obj.Null; } return true; }
public static void LoadSystemLibrary(SophieVM vm) { vm.Interpret("", SystemLibSource); ObjClass system = (ObjClass)vm.FindVariable("System"); vm.Primitive(system.ClassObj, "writeString_(_)", WriteString); vm.Primitive(system.ClassObj, "read", Read); vm.Primitive(system.ClassObj, "clock", Clock); vm.Primitive(system.ClassObj, "time", Time); }
public static string DumpByteCode(SophieVM vm, ObjFn fn) { string s = ""; int ip = 0; byte[] bytecode = fn.Bytecode; while (ip < bytecode.Length) { s += ip + ": "; Instruction instruction = (Instruction)bytecode[ip++]; s += (instruction + " "); switch (instruction) { case Instruction.Null: case Instruction.False: case Instruction.True: case Instruction.Zero: case Instruction.One: case Instruction.Pop: case Instruction.Dup: case Instruction.CloseUpvalue: case Instruction.Return: case Instruction.End: case Instruction.LoadLocal0: case Instruction.LoadLocal1: case Instruction.LoadLocal2: case Instruction.LoadLocal3: case Instruction.LoadLocal4: case Instruction.LoadLocal5: case Instruction.LoadLocal6: case Instruction.LoadLocal7: case Instruction.LoadLocal8: s += ("\n"); break; case Instruction.LoadLocal: case Instruction.StoreLocal: case Instruction.LoadUpvalue: case Instruction.StoreUpvalue: case Instruction.LoadFieldThis: case Instruction.StoreFieldThis: case Instruction.LoadField: case Instruction.StoreField: case Instruction.Class: case Instruction.SmallConstant: s += (bytecode[ip++] + "\n"); break; case Instruction.Call0: case Instruction.Call1: case Instruction.Call2: case Instruction.Call3: case Instruction.Call4: case Instruction.Call5: case Instruction.Call6: case Instruction.Call7: case Instruction.Call8: case Instruction.Call9: case Instruction.Call10: case Instruction.Call11: case Instruction.Call12: case Instruction.Call13: case Instruction.Call14: case Instruction.Call15: case Instruction.Call16: int method = (bytecode[ip] << 8) + bytecode[ip + 1]; s += vm.MethodNames[method] + "\n"; ip += 2; break; case Instruction.Constant: case Instruction.LoadModuleVar: case Instruction.StoreModuleVar: case Instruction.Jump: case Instruction.Loop: case Instruction.JumpIf: case Instruction.And: case Instruction.Or: case Instruction.MethodInstance: case Instruction.MethodStatic: case Instruction.LoadModule: int method1 = (bytecode[ip] << 8) + bytecode[ip + 1]; s += method1 + "\n"; ip += 2; break; case Instruction.Super0: case Instruction.Super1: case Instruction.Super2: case Instruction.Super3: case Instruction.Super4: case Instruction.Super5: case Instruction.Super6: case Instruction.Super7: case Instruction.Super8: case Instruction.Super9: case Instruction.Super10: case Instruction.Super11: case Instruction.Super12: case Instruction.Super13: case Instruction.Super14: case Instruction.Super15: case Instruction.Super16: case Instruction.ImportVariable: s += (bytecode[ip++]); s += (" "); s += (bytecode[ip++]); s += (" "); s += (bytecode[ip++]); s += (" "); s += (bytecode[ip++] + "\n"); break; case Instruction.Closure: { int constant = (bytecode[ip + 1] << 8) | bytecode[ip + 2]; ObjFn loadedFn = (ObjFn)fn.Constants[constant]; // There are two bytes for the constant, then two for each upvalue. int j = 2 + (loadedFn.NumUpvalues * 2); while (j > 0) { s += (bytecode[ip++]); s += (" "); j--; } s += "\n"; } break; } } return s; }
public static ObjFn Compile(SophieVM vm, ObjModule module, string sourcePath, string source, bool printErrors) { Parser parser = new Parser { Vm = vm, Module = module, SourcePath = sourcePath, Source = source, TokenStart = 0, CurrentChar = 0, CurrentLine = 1, Current = { Type = TokenType.Error, Start = 0, Length = 0, Line = 0 }, PrintErrors = printErrors, HasError = false, Raw = "" }; Compiler compiler = new Compiler(parser, null, true); // Read the first token. compiler.NextToken(); compiler.IgnoreNewlines(); while (!compiler.Match(TokenType.Eof)) { compiler.Definition(); // If there is no newline, it must be the end of the block on the same line. if (!compiler.MatchLine()) { compiler.Consume(TokenType.Eof, "Expect end of file."); break; } } compiler.Emit(Instruction.Null); compiler.Emit(Instruction.Return); // See if there are any implicitly declared module-level variables that never // got an explicit definition. // TODO: It would be nice if the error was on the line where it was used. for (int i = 0; i < parser.Module.Variables.Count; i++) { ModuleVariable t = parser.Module.Variables[i]; if (t.Container == Obj.Undefined) { compiler.Error(string.Format("Variable '{0}' is used but not defined.", t.Name)); } } return compiler.EndCompiler(); }
// Creates a string containing an appropriate method not found error for a // method with [symbol] on [classObj]. static void MethodNotFound(SophieVM vm, ObjClass classObj, int symbol) { vm.Fiber.Error = Obj.MakeString(string.Format("{0} does not implement '{1}'.", classObj.Name, vm.MethodNames[symbol])); }