import std.stdio; import std.string; import std.conv; import parser; import dbg; enum ObjType { FUNCTION, SCRIPT, } abstract class Obj { ObjType type; } class Function : Obj { Chunk chunk; int arity; string name; ObjType type; this(ObjType type, string name = "") { this.type = type; this.chunk = new Chunk(); this.arity = 0; this.name = name; } override string toString() { if (type == ObjType.SCRIPT) { return ""; } else { return format("", name); } } } enum SeqType { LIST, STRING, } abstract class Seq { SeqType type; abstract Value first(); abstract Seq rest(); abstract int length(); } class String : Seq { string str; this(Value value) { this.str = value.as.str; } this(string str) { this.str = str; } override Value first() { return makeStringValue(to!string(this.str[0])); } override Seq rest() { return new String(this.str[1..$]); } override int length() { return to!int(str.length); } override string toString() { return format("\"%s\"", this.str); } } class List : Seq { Value[] inner; this(int length) { this.inner = new Value[length]; this.type = SeqType.LIST; } void addItemAtIndex(Value item, int idx) { this.inner[idx] = item; } override Value first() { return this.inner[0]; // this fails on NIL } override Seq rest() { List ret = new List(to!int(this.inner.length) - 1); for (int i = 1; i < this.inner.length; i++) { ret.addItemAtIndex(this.inner[i], i - 1); } return ret; } override int length() { return to!int(this.inner.length); } override string toString() { return format("list ('%s' + %d)", printableValue(this.inner[0]), this.inner.length - 1); } } enum OpCode { OP_ADD, OP_LESS, OP_NOT, OP_GREATER, OP_NEGATE, OP_RETURN, OP_CONSTANT, OP_DEF_GLOBAL, OP_GET_GLOBAL, OP_SET_GLOBAL, OP_DEF_LOCAL, OP_GET_LOCAL, OP_SET_LOCAL, OP_POP, OP_POPB, OP_POP_SCOPE, OP_SUBTRACT, OP_NIL, OP_JUMP, OP_JUMP_IF_FALSE, OP_JUMP_IF_TRUE, OP_CALL, OP_LIST, OP_CONCAT, // No? OP_FIRST, // No? OP_REST, OP_LENGTH, OP_TYPE_CHECK_NUMBER, OP_TYPE_CHECK_BOOLEAN, OP_TYPE_CHECK_STRING, OP_TYPE_CHECK_LIST, OP_TYPE_CHECK_SEQ, } class Chunk { int count = 0; ubyte[] code; int[] lines; Value[] constants; //int writeOp(OpCode opCode, int line) { int writeOp(ubyte opCode, int line) { this.code ~= opCode; this.lines ~= line; this.count++; assert(this.code.length == count); assert(this.lines.length == count); return count; } int addConstant(Value value) { this.constants ~= value; return to!int(this.constants.length - 1); } }