import std.stdio; import std.string; import std.conv; import chunk; import parser; //import parser; //import dbg; //import value; bool DEBUG = false; bool REPL = false; void printForm(Form f, string prefix = "") { switch (f.type) { case FormType.EOF: writeln("eof"); return; case FormType.ATOM: writefln("%s atom: %s", prefix, atomAsString(cast(Atom)f)); break; case FormType.CONS: Cons c = cast(Cons)f; writef("%s cons <", prefix); if (c.evaluate) { writeln("true>"); } else { writeln("false>"); } printForm(c.head, format("%s>", prefix)); foreach (Form i ; c.tail) { printForm(i, format("%s>", prefix)); } break; case FormType.NIL: writefln("%s NIL", prefix); break; case FormType.PARSE_ERROR: ParseError pe = cast(ParseError)f; writefln("ERROR: %s", pe.message); break; case FormType.SYMBOL: Symbol s = cast(Symbol)f; writefln("%s sym: %s", prefix, s.name); break; case FormType.FUNC: Func func = cast(Func)f; writefln("%s ", prefix, func.name.name); printForm(func.args, format("%s -", prefix)); writefln("%s with %d body lines", prefix, func.funcBody.length); writefln("%s ", prefix, func.name.name); break; case FormType.DEF: Def def = cast(Def)f; writefln("%s var: %s", prefix, def.name.name); break; case FormType.BLOCK: Block block = cast(Block)f; writefln("%s block of %d", prefix, block.blockBody.length); break; default: writeln("printFormDefault"); break; } } string printableValue(Value val) { switch (val.type) { case ValueType.STRING: return val.as.str; case ValueType.NUMBER: return format("%g", val.as.number); case ValueType.BOOLEAN: if (val.as.boolean) { return "#true"; } else { return "#false"; } case ValueType.OBJ: return printableFunction(val.as.obj); case ValueType.TYPE: return val.as.type; case ValueType.NIL: return "nil"; case ValueType.SEQ: return printableSeq(val.as.seq); default: return "! unknown value type !"; } } string printableSeq(Seq seq) { return format("%s", seq); } string printableFunction(Obj func) { return format("%s", func); } string atomAsString(Atom a) { return printableValue(a.value); } int jumpInstruction(string message, int sign, Chunk chunk, int offset) { uint jump = to!uint(chunk.code[offset + 1] << 8); jump |= chunk.code[offset + 2]; writefln("%-16s %4d -> %d", message, offset, offset + 3 + sign * jump); return offset + 3; } int byteInstruction(string message, Chunk chunk, int offset) { ubyte slot = chunk.code[offset + 1]; writefln("%-16s %4d", message, slot); return offset + 2; } int constantInstruction(string message, Chunk chunk, int offset) { ubyte idx = chunk.code[offset + 1]; //writeln("dunno how to write a constant"); writefln("%-16s %4d '%s'", message, idx, printableValue(chunk.constants[idx])); //writefln("%-16s %4d '%s'", message, idx, atomAsString(chunk.constants[idx])); return offset + 2; } int listInstruction(string message, Chunk chunk, int offset) { ubyte idx = chunk.code[offset + 1]; writefln("%-16s %4d", message, idx); return offset + 2; } int simpleInstruction(string message, int offset) { writeln(message); return offset + 1; } void disassembleChunk(Chunk chunk, string name) { writefln("== %s ==", name); int cnt = 0; while(true) { if (cnt >= chunk.code.length) { break; } cnt = disassemble(chunk, cnt); } } int disassemble(Chunk chunk, int offset) { writef("%04d %4d ", offset, chunk.lines[offset]); ubyte inst = chunk.code[offset]; switch (inst) { case OpCode.OP_IS_NIL: return simpleInstruction("OP_IS_NIL", offset); case OpCode.OP_DUPLICATE: return simpleInstruction("OP_DUPLICATE", offset); case OpCode.OP_DUPLICATE_2: return simpleInstruction("OP_DUPLICATE_2", offset); case OpCode.OP_ROTATE_N: return simpleInstruction("OP_ROTATE_N", offset); case OpCode.OP_ZERO: return simpleInstruction("OP_ZERO", offset); case OpCode.OP_INCREMENT: return simpleInstruction("OP_INCREMENT", offset); case OpCode.OP_LIST_N: return simpleInstruction("OP_LIST_N", offset); case OpCode.OP_DEF_LOCAL: return byteInstruction("OP_DEF_LOCAL", chunk, offset); case OpCode.OP_GET_LOCAL: return byteInstruction("OP_GET_LOCAL", chunk, offset); case OpCode.OP_SET_LOCAL: return byteInstruction("OP_SET_LOCAL", chunk, offset); case OpCode.OP_LIST: return listInstruction("OP_LIST", chunk, offset); case OpCode.OP_ADD: return simpleInstruction("OP_ADD", offset); case OpCode.OP_MULTIPLY: return simpleInstruction("OP_MULTIPLY", offset); case OpCode.OP_LESS: return simpleInstruction("OP_LESS", offset); case OpCode.OP_GREATER: return simpleInstruction("OP_GREATER", offset); case OpCode.OP_NOT: return simpleInstruction("OP_NOT", offset); case OpCode.OP_SUBTRACT: return simpleInstruction("OP_SUBTRACT", offset); case OpCode.OP_CONSTANT: return constantInstruction("OP_CONSTANT", chunk, offset); case OpCode.OP_DEF_GLOBAL: return constantInstruction("OP_DEF_GLOBAL", chunk, offset); case OpCode.OP_GET_GLOBAL: return constantInstruction("OP_GET_GLOBAL", chunk, offset); case OpCode.OP_NEGATE: return simpleInstruction("OP_NEGATE", offset); case OpCode.OP_POP: return simpleInstruction("OP_POP", offset); case OpCode.OP_POPB: return simpleInstruction("OP_POPB", offset); case OpCode.OP_POP_SCOPE: return simpleInstruction("OP_POP_SCOPE", offset); case OpCode.OP_RETURN: return simpleInstruction("OP_RETURN", offset); case OpCode.OP_NIL: return simpleInstruction("OP_NIL", offset); case OpCode.OP_JUMP: return jumpInstruction("OP_JUMP", 1, chunk, offset); case OpCode.OP_JUMP_TO: return jumpInstruction("OP_JUMP_TO", -1, chunk, offset); case OpCode.OP_JUMP_IF_FALSE: return jumpInstruction("OP_JUMP_IF_FALSE", 1, chunk, offset); case OpCode.OP_JUMP_IF_TRUE: return jumpInstruction("OP_JUMP_IF_TRUE", 1, chunk, offset); case OpCode.OP_CALL: return byteInstruction("OP_CALL", chunk, offset); case OpCode.OP_TYPE_CHECK_NUMBER: return simpleInstruction("OP_TYPE_CHECK_NUMBER", offset); case OpCode.OP_TYPE_CHECK_BOOLEAN: return simpleInstruction("OP_TYPE_CHECK_BOOLEAN", offset); case OpCode.OP_TYPE_CHECK_SEQ: return simpleInstruction("OP_TYPE_CHECK_SEQ", offset); case OpCode.OP_FIRST: return simpleInstruction("OP_FIRST", offset); case OpCode.OP_REST: return simpleInstruction("OP_REST", offset); case OpCode.OP_CONCAT: return simpleInstruction("OP_CONCAT", offset); case OpCode.OP_APPEND: return simpleInstruction("OP_APPEND", offset); case OpCode.OP_PRINT: return simpleInstruction("OP_PRINT", offset); case OpCode.OP_MOST: return simpleInstruction("OP_MOST", offset); case OpCode.OP_LAST: return simpleInstruction("OP_LAST", offset); case OpCode.OP_REVERSE: return simpleInstruction("OP_REVERSE", offset); case OpCode.OP_EQUAL: return simpleInstruction("OP_EQUAL", offset); default: writeln("unknown opcode?"); return offset + 1; } return 0; }