aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chunk.d27
-rw-r--r--compiler.d18
-rw-r--r--vm.d5
3 files changed, 50 insertions, 0 deletions
diff --git a/chunk.d b/chunk.d
index 68df45b..b6a5348 100644
--- a/chunk.d
+++ b/chunk.d
@@ -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,
diff --git a/compiler.d b/compiler.d
index 4fb37f2..4a3df27 100644
--- a/compiler.d
+++ b/compiler.d
@@ -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;
diff --git a/vm.d b/vm.d
index c7e5e8e..6ab2e96 100644
--- a/vm.d
+++ b/vm.d
@@ -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();
/*