diff options
| -rw-r--r-- | chunk.d | 3 | ||||
| -rw-r--r-- | compiler.d | 42 | ||||
| -rw-r--r-- | dbg.d | 5 | ||||
| -rw-r--r-- | parser.d | 8 | ||||
| -rw-r--r-- | vm.d | 44 | 
5 files changed, 89 insertions, 13 deletions
| @@ -58,6 +58,9 @@ enum OpCode {      OP_JUMP_IF_TRUE,      OP_CALL, + +    OP_TYPE_CHECK_NUMBER, +    OP_TYPE_CHECK_BOOLEAN,  }  class Chunk { @@ -22,6 +22,8 @@ class Compiler {      Form current;      Form previous; +    int currentLine; +      Form outer;      int outerIdx; @@ -48,7 +50,12 @@ class Compiler {      }      void compileAdd(Form[] args) { +        writeln("compiling add"); +        int line = args[0].line;          resolve(args[0]); +        writeln("resolved the first argument"); +        func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, line); +        writeln("wrote the typecheck op");          // (+ n) always returns n          if (args.length == 1) { @@ -57,20 +64,24 @@ class Compiler {          for (int i = 1; i < args.length; i++) {              resolve(args[i]); -            func.chunk.writeOp(OpCode.OP_ADD, current.line); +            func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, line); +            func.chunk.writeOp(OpCode.OP_ADD, line);          }      }      void compileNegate(Form arg) {          resolve(arg); -        func.chunk.writeOp(OpCode.OP_NEGATE, current.line); +        func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine); +        func.chunk.writeOp(OpCode.OP_NEGATE, currentLine);      }      void compileSubtract(Form[] args) {          resolve(args[0]); +        func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine);          for (int i = 1; i < args.length; i++) {              resolve(args[i]); -            func.chunk.writeOp(OpCode.OP_SUBTRACT, current.line); +            func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine); +            func.chunk.writeOp(OpCode.OP_SUBTRACT, currentLine);          }      } @@ -80,8 +91,10 @@ class Compiler {              return;          }          resolve(args[0]); +        func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine);          resolve(args[1]); -        func.chunk.writeOp(OpCode.OP_LESS, current.line); +        func.chunk.writeOp(OpCode.OP_TYPE_CHECK_NUMBER, currentLine); +        func.chunk.writeOp(OpCode.OP_LESS, currentLine);      }      //int parseVariable(Def def) { @@ -142,7 +155,7 @@ class Compiler {          // are we setting a local?          if (this.scopeDepth > 0) { -            func.chunk.writeOp(OpCode.OP_DEF_LOCAL, current.line); +            func.chunk.writeOp(OpCode.OP_DEF_LOCAL, def.line);          }          // define the variable @@ -195,9 +208,11 @@ class Compiler {      }      void compileIf(Form form) { +        writeln("compiling if...");          If if_ = cast(If)form;          resolve(if_.cond); +        func.chunk.writeOp(OpCode.OP_TYPE_CHECK_BOOLEAN, if_.line);          int thenJump = jump(OpCode.OP_JUMP_IF_FALSE);          this.func.chunk.writeOp(OpCode.OP_POP, if_.line); @@ -221,12 +236,15 @@ class Compiler {          And and_ = cast(And)form;          resolve(and_.clauses[0]); +        func.chunk.writeOp(OpCode.OP_TYPE_CHECK_BOOLEAN, currentLine); +          int[] jumps;          jumps ~= jump(OpCode.OP_JUMP_IF_FALSE);          int count = 1;          while (count < and_.clauses.length) { -            this.func.chunk.writeOp(OpCode.OP_POP, and_.line); +            this.func.chunk.writeOp(OpCode.OP_POP, currentLine);              resolve(and_.clauses[count]); +            func.chunk.writeOp(OpCode.OP_TYPE_CHECK_BOOLEAN, currentLine);              jumps ~= jump(OpCode.OP_JUMP_IF_FALSE);              count++;          } @@ -241,12 +259,14 @@ class Compiler {          Or or_ = cast(Or)form;          resolve(or_.clauses[0]); +        func.chunk.writeOp(OpCode.OP_TYPE_CHECK_BOOLEAN, currentLine);          int[] jumps;          jumps ~= jump(OpCode.OP_JUMP_IF_TRUE);          int count = 1;          while (count < or_.clauses.length) {              this.func.chunk.writeOp(OpCode.OP_POP, or_.line);              resolve(or_.clauses[count]); +            func.chunk.writeOp(OpCode.OP_TYPE_CHECK_BOOLEAN, currentLine);              jumps ~= jump(OpCode.OP_JUMP_IF_TRUE);              count++;          } @@ -261,7 +281,9 @@ class Compiler {          Block block = cast(Block)form;          beginScope();          foreach (Form inner; block.blockBody) { +            writeln("about to compile an inner form");              resolve(inner); +            writeln("finished compiling inner form");          }          endScope();      } @@ -292,6 +314,7 @@ class Compiler {      }      void compileFunc(Form form) { +        writeln("compiling func");          Func f = cast(Func)form;          // name the function @@ -312,6 +335,8 @@ class Compiler {              }          } +        writeln("got the arguments"); +          /*          // compile each inner Form          foreach (Form inner; f.funcBody) { @@ -325,6 +350,8 @@ class Compiler {          b.blockBody = f.funcBody;          compiler.compileBlock(b); +        writeln("compiled the body"); +          // write the function as a Value          Function outFunc = compiler.finish();          func.chunk.writeOp(OpCode.OP_CONSTANT, f.line); @@ -373,6 +400,7 @@ class Compiler {      void resolve(Form form) {          //printForm(form); +        currentLine = form.line;          switch(form.type) {              case FormType.ATOM:                  this.compileAtom(form); @@ -423,7 +451,7 @@ class Compiler {      Function finish() {          this.func.chunk.writeOp(OpCode.OP_RETURN, current.line); -        //disassembleChunk(func.chunk, to!string(func)); +        disassembleChunk(func.chunk, to!string(func));          return this.func;      } @@ -77,6 +77,8 @@ string printableValue(Value val) {              }          case ValueType.OBJ:              return printableFunction(val.as.obj); +        case ValueType.TYPE: +            return val.as.type;          default:              return "! unknown value type !";      } @@ -171,7 +173,8 @@ int disassemble(Chunk chunk, int offset) {              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);          default:              writeln("unknown opcode?");              return offset + 1; @@ -262,6 +262,7 @@ enum ValueType {      STRING,      NUMBER,      BOOLEAN, +    TYPE,      OBJ,  } @@ -269,6 +270,7 @@ union As {      bool boolean;      double number;      string str; +    string type;      Obj obj;  } @@ -302,6 +304,12 @@ Value makeObjValue(Obj obj) {      return val;  } +Value makeTypeValue(string name) { +    As as = { type: name }; +    Value val = { ValueType.TYPE, as }; +    return val; +} +  class Parser {      string source; @@ -139,7 +139,12 @@ class VM {      }      bool isString(Value value) { -        return value.type == ValueType.STRING; +        return value.type == ValueType.STRING || +                value.type == ValueType.TYPE; +    } + +    bool isType(Value value) { +        return value.type == ValueType.TYPE;      }      bool isBoolean(Value value) { @@ -159,7 +164,11 @@ class VM {      }      string asString(Value value) { -        return value.as.str; +        if (value.type == ValueType.TYPE) { +            return value.as.type; +        } else { +            return value.as.str; +        }      }      bool asBoolean(Value value) { @@ -292,47 +301,71 @@ class VM {                      double val = asNumber(popA());                      pushA(makeNumberValue(val * -1));                      break; +                case OpCode.OP_TYPE_CHECK_NUMBER: +                    if (!isNumber(peekA(0))) { +                        writeln("VM type check: not a number!"); +                        return InterpretResult.RUNTIME_ERROR; // TODO error +                    } +                    break; +                case OpCode.OP_TYPE_CHECK_BOOLEAN: +                    if (!isBoolean(peekA(0))) { +                        writeln("VM type check: not a boolean!"); +                        return InterpretResult.RUNTIME_ERROR; // TODO error +                    } +                    break;                  case OpCode.OP_ADD:                      Value b = popA(); +                    /*                      if (!isNumber(b)) {                          writeln("b is not a number!");                          return InterpretResult.RUNTIME_ERROR;  // TODO error                      } +                    */                      Value a = popA(); +                    /*                      if (!isNumber(a)) {                          writeln("a is not a number!");                          return InterpretResult.RUNTIME_ERROR; // TODO error                      } +                    */                      double bnum = asNumber(b);                      double anum = asNumber(a);                      pushA(makeNumberValue(anum + bnum));                      break;                  case OpCode.OP_SUBTRACT:                      Value b = popA(); +                    /*                      if (!isNumber(b)) {                          writeln("b is not a number!");                          return InterpretResult.RUNTIME_ERROR;  // TODO error                      } +                    */                      Value a = popA(); +                    /*                      if (!isNumber(a)) {                          writeln("a is not a number!");                          return InterpretResult.RUNTIME_ERROR; // TODO error                      } +                    */                      double bnum = asNumber(b);                      double anum = asNumber(a);                      pushA(makeNumberValue(anum - bnum));                      break;                  case OpCode.OP_LESS:                      Value b = popA(); +                    /*                      if (!isNumber(b)) {                          writeln("b is not a number!");                          return InterpretResult.RUNTIME_ERROR;  // TODO error                      } +                    */                      Value a = popA(); +                    /*                      if (!isNumber(a)) {                          writeln("a is not a number!");                          return InterpretResult.RUNTIME_ERROR; // TODO error                      } +                    */                      double bnum = asNumber(b);                      double anum = asNumber(a);                      pushA(makeBooleanValue(anum < bnum)); @@ -342,10 +375,7 @@ class VM {                      Value ret = popA();                      popA();  // function                      this.frameCount--; -                    //writefln("frameCount: %d", frameCount); -                    //if (this.frameCount == 0) {                      if (this.frameCount == 1) { -                        popA();                          writefln("returned %s", printableValue(ret));                          return InterpretResult.OK;                      } @@ -387,10 +417,12 @@ class VM {                      break;                  case OpCode.OP_JUMP_IF_TRUE:                      uint offset = readShort(); +                    /*                      if (!isBoolean(peekA(0))) {                          writeln("expecting a boolean condition");                          return InterpretResult.RUNTIME_ERROR; // TODO error                      } +                    */                      if (asBoolean(peekA(0))) {                          current.ip += offset;                      } @@ -432,6 +464,8 @@ InterpretResult interpret(string source) {      VM vm = new VM(); +//    vm.globals[":int"] = makeTypeValue(":int"); +      vm.pushA(makeObjValue(func));      CallFrame frame = { func, 0, vm.bStack, 0 };      vm.pushFrame(frame); | 
