diff options
| -rw-r--r-- | chunk.d | 27 | ||||
| -rw-r--r-- | compiler.d | 18 | ||||
| -rw-r--r-- | vm.d | 5 |
3 files changed, 50 insertions, 0 deletions
@@ -47,6 +47,7 @@ abstract class Seq { abstract Seq rest(); abstract int length(); abstract Seq concat(Seq seq); + abstract bool isIn(Value val); } class String : Seq { @@ -87,6 +88,22 @@ class String : Seq { return new String(this.str ~ strSeq.str); } + override bool isIn(Value val) { + if (val.type != ValueType.SEQ) { + // how do i throw an error here? + writeln("a non-string can't be 'in?' a string (this should be a compile error)"); + return false; + } + Seq seq = val.as.seq; + if (seq.type != SeqType.STRING) { + // how do i throw an error here? + writeln("a non-string can't be 'in?' a string (this should be a compile error)"); + return false; + } + String strVal = cast(String)seq; + return (indexOf(this.str, strVal.str) != -1); + } + override string toString() { return format("\"%s\"", this.str); } @@ -130,6 +147,15 @@ class List : Seq { return ret; } + override bool isIn(Value val) { + foreach(Value mine ; this.inner) { + if (areValuesEqual(mine, val)) { + return true; + } + } + return false; + } + override string toString() { return format("list ('%s' + %d)", printableValue(this.inner[0]), this.inner.length - 1); } @@ -169,6 +195,7 @@ enum OpCode { OP_FIRST, // No? OP_REST, OP_LENGTH, + OP_MEMBER, OP_TYPE_CHECK_NUMBER, OP_TYPE_CHECK_BOOLEAN, @@ -596,6 +596,21 @@ class Compiler { this.func.chunk.writeOp(OpCode.OP_CONCAT, args[0].line); } + void compileIn(Form[] args) { + // TODO how do we identify/propagate errors? + if (args.length != 2) { + this.error(format("'in?': expected [2] arguments, received %d", args.length), -1); + this.advance(); + //writeln("COMPILE ERROR: 'first' expects exactly one argument"); + return; + } + ValueType vt1 = this.resolve(args[0], ValueType.ANY); + ValueType vt2 = this.resolve(args[1], ValueType.SEQ); + this.func.chunk.writeOp(OpCode.OP_TYPE_CHECK_SEQ, args[0].line); + + this.func.chunk.writeOp(OpCode.OP_MEMBER, args[0].line); + } + void compileFirst(Form[] args) { // TODO how do we identify/propagate errors? if (args.length != 1) { @@ -772,6 +787,9 @@ class Compiler { case "first": this.compileFirst(cons.tail); break; + case "in?": + this.compileIn(cons.tail); + break; case "length": this.compileLength(cons.tail); break; @@ -404,6 +404,11 @@ class VM { Seq seq = asSeq(this.popA()); this.pushA(makeNumberValue(seq.length())); break; + case OpCode.OP_MEMBER: + Seq seq = asSeq(this.popA()); + Value val = this.popA(); + this.pushA(makeBooleanValue(seq.isIn(val))); + break; case OpCode.OP_ADD: Value b = this.popA(); /* |
