private int DisassembleConstant(string name, GearsChunk chunk, int offset, EGearsOpCode constantType, Action <string> writeLine) { int constantIndex = (chunk.ReadCode(ref offset) << 8) + chunk.ReadCode(ref offset); switch (constantType) { case OP_LOAD_CONSTANT: { GearsValue value = chunk.ReadConstantValue(constantIndex); writeLine($"{name} const[{constantIndex}] ({value})"); } break; case OP_LOAD_STRING: { string value = chunk.Strings.ReadStringConstant(constantIndex); writeLine($"{name} string[{constantIndex}] ({value})"); } break; case OP_LOAD_FUNCTION: { string value = chunk.ReadConstantValueAsBitStr(constantIndex); writeLine($"{name} bitstr[{constantIndex}] ({value})"); } break; } return(offset); }
private int DisassembleTwoParams(string name, GearsChunk chunk, int offset, Action <string> writeLine) { int index = (chunk.ReadCode(ref offset) << 8) + chunk.ReadCode(ref offset); writeLine($"{name} ({index})"); return(offset); }
public GearsObjFunction(GearsChunk chunk, int arity, int upvalueCount, int ip = 0) { Chunk = chunk; Arity = arity; IP = ip; Upvalues = new GearsObjUpvalue[upvalueCount]; }
/// <summary> /// Reset the VM. Heap, globals, and stack are cleared. /// Then the VM is run once, unless firstRun == false /// </summary> internal Gears Reset(GearsChunk chunk, bool firstRun) { Chunk = chunk; _SP = 0; for (int i = 0; i < _Stack.Length; i++) { _Stack[i] = 0; } _FrameCount = 0; for (int i = 0; i < _Frames.Length; i++) { _Frames[i] = null; } for (int i = 0; i < _Heap.Length; i++) { _Heap[i] = null; } Globals.Reset(); _GrayList.Clear(); GearsObjFunction closure = new GearsObjFunction(Chunk, 0, 0, 0); PushFrame(new GearsCallFrame(closure)); Push(GearsValue.CreateObjPtr(HeapAddObject(closure))); AddNativeFunctionToGlobals("clock", 0, NativeFnClock); AddNativeFunctionToGlobals("print", 1, NativeFnPrint); if (firstRun) { Run(); } return(this); }
private static void DoFixups(GearsChunk chunk, int origin, Func <GearsValue, int> makeConstant, Func <string, int> makeConstant2, List <LoxCompiler> fns) { foreach (LoxCompiler fn in fns) { int codeBase = chunk.SizeCode; chunk.WriteCode(fn._Chunk._Code, fn._Chunk._Lines, fn._Chunk.SizeCode); chunk.WriteCodeAt(origin + fn._OriginAddress, (byte)(codeBase >> 8)); chunk.WriteCodeAt(origin + fn._OriginAddress + 1, (byte)(codeBase & 0xff)); foreach (LoxCompilerFixup fixup in fn._FixupConstants) { GearsValue value = fn._Chunk.ReadConstantValue(fixup.Value); int constantFixup = makeConstant(value); // as fixup chunk.WriteCodeAt(codeBase + fixup.Address, (byte)(constantFixup >> 8)); chunk.WriteCodeAt(codeBase + fixup.Address + 1, (byte)(constantFixup & 0xff)); } foreach (LoxCompilerFixup fixup in fn._FixupStrings) { string value = fn._Chunk.Strings.ReadStringConstant(fixup.Value); int constantFixup = makeConstant2(value); // as fixup chunk.WriteCodeAt(codeBase + fixup.Address, (byte)(constantFixup >> 8)); chunk.WriteCodeAt(codeBase + fixup.Address + 1, (byte)(constantFixup & 0xff)); } DoFixups(chunk, codeBase, makeConstant, makeConstant2, fn._FixupFns); chunk.Compress(); } }
private int DisassembleInvoke(string name, GearsChunk chunk, int offset, Action <string> writeLine) { int args = chunk.ReadCode(ref offset); int nameIndex = (chunk.ReadCode(ref offset) << 8) + chunk.ReadCode(ref offset); string value = chunk.ReadConstantValueAsBitStr(nameIndex); writeLine($"{name} const[{nameIndex}] ({value})"); return(offset); }
internal partial class Gears { // disassembly // === Disassembly =========================================================================================== // =========================================================================================================== public void Disassemble(GearsChunk chunk, Action <string> write, Action <string> writeLine) { writeLine($"=== chunk ==="); int offset = 0; while (offset < chunk.SizeCode) { offset = Disassemble(chunk, offset, write, writeLine); } }
private int DisassembleFunction(string name, GearsChunk chunk, int offset, Action <string> writeLine) { int argCount = chunk.ReadCode(ref offset); int fnAddress = (chunk.ReadCode(ref offset) << 8) + chunk.ReadCode(ref offset); int upvalueCount = chunk.ReadCode(ref offset); writeLine($"{name} ({argCount} arguments, {upvalueCount} upvalues) @{fnAddress:D4}"); for (int i = 0; i < upvalueCount; i++) { chunk.ReadCode(ref offset); // local? chunk.ReadCode(ref offset); // index } return(offset); }
private LoxCompiler(TokenList tokens, ELoxFunctionType type, string name, LoxCompiler enclosing, LoxCompilerClass enclosingClass) : base(tokens, name) { _FunctionType = type; Arity = 0; _Chunk = new GearsChunk(name); _Rules = new List <Rule>(); _EnclosingCompiler = enclosing; _CurrentClass = enclosingClass; // stack slot zero is used for 'this' reference in methods, and is empty for script/functions: if (type != ELoxFunctionType.TYPE_FUNCTION) { _LocalVarData[_LocalCount++] = new LoxCompilerLocal("this", 0); } else { _LocalVarData[_LocalCount++] = new LoxCompilerLocal(string.Empty, 0); } }
/// <summary> /// Attempts to compile the passed source, tokenizing first. /// If compilation is successful, compiler.Chunk will be set. /// If compilation fails, status will be the error message. /// </summary> public static bool TryCompileFromPath(string path, out GearsChunk chunk, out string status) { chunk = null; string source; if (!File.Exists(path)) { status = $"LoxCompiler: File '{path}' does not exist."; return(false); } try { source = File.ReadAllText(path); } catch (Exception e) { status = $"LoxCompiler: Could not read '{path}': {e.Message}"; return(false); } return(TryCompileFromSource(path, source, out chunk, out status)); }
/// <summary> /// Attempts to compile the passed source, tokenizing first. /// If compilation is successful, compiler.Chunk will be set. /// If compilation fails, status will be the error message. /// </summary> public static bool TryCompileFromSource(string path, string source, out GearsChunk chunk, out string status) { try { TokenList tokens = new LoxTokenizer(path, source).ScanTokens(); LoxCompiler compiler = new LoxCompiler(tokens, ELoxFunctionType.TYPE_SCRIPT, path, null, null); if (compiler.Compile()) { chunk = compiler._Chunk; status = null; return(true); } status = $"LoxCompiler: uncaught error while compiling {path}."; chunk = null; return(false); } catch (CompilerException e) { chunk = null; status = $"LoxCompiler at {e.TargetSite.DeclaringType.Name}.{e.TargetSite.Name} {path} {e}"; return(false); } }
private int Disassemble(GearsChunk chunk, int offset, Action <string> write, Action <string> writeLine) { write($"{chunk._Lines[offset]:D4} {offset:D4} "); EGearsOpCode instruction = (EGearsOpCode)chunk.ReadCode(ref offset); switch (instruction) { case OP_LOAD_CONSTANT: return(DisassembleConstant("OP_LOAD_CONSTANT", chunk, offset, OP_LOAD_CONSTANT, writeLine)); case OP_LOAD_STRING: return(DisassembleConstant("OP_LOAD_STRING", chunk, offset, OP_LOAD_STRING, writeLine)); case OP_LOAD_FUNCTION: return(DisassembleFunction("OP_LOAD_FUNCTION", chunk, offset, writeLine)); case OP_NIL: return(DisassembleSimple("OP_NIL", chunk, offset, writeLine)); case OP_TRUE: return(DisassembleSimple("OP_TRUE", chunk, offset, writeLine)); case OP_FALSE: return(DisassembleSimple("OP_FALSE", chunk, offset, writeLine)); case OP_POP: return(DisassembleSimple("OP_POP", chunk, offset, writeLine)); case OP_GET_LOCAL: return(DisassembleTwoParams("OP_GET_LOCAL", chunk, offset, writeLine)); case OP_SET_LOCAL: return(DisassembleTwoParams("OP_SET_LOCAL", chunk, offset, writeLine)); case OP_DEFINE_GLOBAL: return(DisassembleConstant("OP_DEF_GLOBAL", chunk, offset, OP_LOAD_FUNCTION, writeLine)); case OP_GET_GLOBAL: return(DisassembleConstant("OP_GET_GLOBAL", chunk, offset, OP_LOAD_FUNCTION, writeLine)); case OP_SET_GLOBAL: return(DisassembleConstant("OP_SET_GLOBAL", chunk, offset, OP_LOAD_FUNCTION, writeLine)); case OP_GET_UPVALUE: return(DisassembleTwoParams("OP_GET_UPVALUE", chunk, offset, writeLine)); case OP_SET_UPVALUE: return(DisassembleTwoParams("OP_SET_UPVALUE", chunk, offset, writeLine)); case OP_GET_PROPERTY: return(DisassembleConstant("OP_GET_PROPERTY", chunk, offset, OP_LOAD_FUNCTION, writeLine)); case OP_SET_PROPERTY: return(DisassembleConstant("OP_SET_PROPERTY", chunk, offset, OP_LOAD_FUNCTION, writeLine)); case OP_GET_SUPER: return(DisassembleConstant("OP_GET_SUPER", chunk, offset, OP_LOAD_FUNCTION, writeLine)); case OP_EQUAL: return(DisassembleSimple("OP_EQUAL", chunk, offset, writeLine)); case OP_GREATER: return(DisassembleSimple("OP_GREATER", chunk, offset, writeLine)); case OP_LESS: return(DisassembleSimple("OP_LESS", chunk, offset, writeLine)); case OP_ADD: return(DisassembleSimple("OP_ADD", chunk, offset, writeLine)); case OP_SUBTRACT: return(DisassembleSimple("OP_SUBTRACT", chunk, offset, writeLine)); case OP_MULTIPLY: return(DisassembleSimple("OP_MULTIPLY", chunk, offset, writeLine)); case OP_DIVIDE: return(DisassembleSimple("OP_DIVIDE", chunk, offset, writeLine)); case OP_NOT: return(DisassembleSimple("OP_NOT", chunk, offset, writeLine)); case OP_NEGATE: return(DisassembleSimple("OP_NEGATE", chunk, offset, writeLine)); case OP_JUMP: return(DisassembleTwoParams("OP_JUMP", chunk, offset, writeLine)); case OP_JUMP_IF_FALSE: return(DisassembleTwoParams("OP_JUMP_IF_FALSE", chunk, offset, writeLine)); case OP_LOOP: return(DisassembleTwoParams("OP_LOOP", chunk, offset, writeLine)); case OP_CALL: return(DisassembleOneParam("OP_CALL", chunk, offset, writeLine)); case OP_INVOKE: return(DisassembleInvoke("OP_INVOKE", chunk, offset, writeLine)); case OP_SUPER_INVOKE: return(DisassembleInvoke("OP_SUPER_INVOKE", chunk, offset, writeLine)); case OP_CLOSE_UPVALUE: return(DisassembleSimple("OP_CLOSE_UPVALUE", chunk, offset, writeLine)); case OP_RETURN: return(DisassembleSimple("OP_RETURN", chunk, offset, writeLine)); case OP_CLASS: return(DisassembleConstant("OP_CLASS", chunk, offset, OP_LOAD_FUNCTION, writeLine)); case OP_INHERIT: return(DisassembleSimple("OP_INHERIT", chunk, offset, writeLine)); case OP_METHOD: return(DisassembleSimple("OP_METHOD", chunk, offset, writeLine)); default: writeLine($"Unknown opcode {instruction}"); return(offset); } }
private int DisassembleSimple(string name, GearsChunk chunk, int offset, Action <string> writeLine) { writeLine(name); return(offset); }