aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chunk.d26
-rw-r--r--compiler.d18
-rw-r--r--vm.d14
3 files changed, 51 insertions, 7 deletions
diff --git a/chunk.d b/chunk.d
index 08ba003..7a532f5 100644
--- a/chunk.d
+++ b/chunk.d
@@ -46,6 +46,7 @@ abstract class Seq {
abstract Value first();
abstract Seq rest();
abstract int length();
+ abstract Seq concat(Seq seq);
}
class String : Seq {
@@ -53,10 +54,12 @@ class String : Seq {
this(Value value) {
this.str = value.as.str;
+ this.type = SeqType.STRING;
}
this(string str) {
this.str = str;
+ this.type = SeqType.STRING;
}
override Value first() {
@@ -71,6 +74,19 @@ class String : Seq {
return to!int(str.length);
}
+ override Seq concat(Seq seq) {
+ if (seq.type != SeqType.STRING) {
+ // how do i throw an error here?
+ writeln("must concat strings to strings!");
+ return this;
+ }
+ String strSeq = cast(String)seq;
+
+ writefln("in concat with '%s' and '%s'", this.str, strSeq.str);
+
+ return new String(this.str ~ strSeq.str);
+ }
+
override string toString() {
return format("\"%s\"", this.str);
}
@@ -104,6 +120,16 @@ class List : Seq {
return to!int(this.inner.length);
}
+ override Seq concat(Seq seq) {
+ int length = to!int(this.inner.length);
+ List ret = new List(length + 1);
+ for (int i = 0; i < length; i++) {
+ ret.addItemAtIndex(this.inner[i], i);
+ }
+ ret.addItemAtIndex(makeSeqValue(seq), length);
+ return ret;
+ }
+
override string toString() {
return format("list ('%s' + %d)", printableValue(this.inner[0]), this.inner.length - 1);
}
diff --git a/compiler.d b/compiler.d
index ecd7785..992e36b 100644
--- a/compiler.d
+++ b/compiler.d
@@ -483,7 +483,7 @@ class Compiler {
ValueType vt = this.resolve(args[0], ValueType.STRING);
for (int i = 1; i < args.length; i++) {
vt = this.resolve(args[i], ValueType.STRING);
- this.func.chunk.writeOp(OpCode.OP_TYPE_CHECK_STRING, args[i].line);
+ this.func.chunk.writeOp(OpCode.OP_TYPE_CHECK_SEQ, args[i].line); // TODO wrong
this.func.chunk.writeOp(OpCode.OP_CONCAT, args[i].line);
}
return ValueType.STRING;
@@ -544,6 +544,22 @@ class Compiler {
this.func.chunk.writeOp(OpCode.OP_LENGTH, args[0].line);
}
+ void compileAppend(Form[] args) {
+ if (args.length != 2) {
+ this.error(format("'append': expected [2] arguments, received %d", args.length), -1);
+ this.advance();
+ return;
+ }
+
+ ValueType vt1 = this.resolve(args[0], ValueType.SEQ);
+ this.func.chunk.writeOp(OpCode.OP_TYPE_CHECK_SEQ, args[0].line);
+
+ // TODO if this is used for both string/list, should be able to typecheck second arg here
+ ValueType vt2 = this.resolve(args[1], ValueType.ANY);
+
+ this.func.chunk.writeOp(OpCode.OP_CONCAT, args[0].line);
+ }
+
void compileFirst(Form[] args) {
// TODO how do we identify/propagate errors?
if (args.length != 1) {
diff --git a/vm.d b/vm.d
index 40877b8..c14c746 100644
--- a/vm.d
+++ b/vm.d
@@ -153,7 +153,8 @@ class VM {
bool isString(Value value) {
return value.type == ValueType.STRING ||
- value.type == ValueType.TYPE;
+ value.type == ValueType.TYPE ||
+ value.type == ValueType.SEQ; // WRONG
}
bool isType(Value value) {
@@ -195,6 +196,9 @@ class VM {
string asString(Value value) {
if (value.type == ValueType.TYPE) {
return value.as.type;
+ } else if (value.type == ValueType.SEQ) {
+ String str = cast(String)value.as.seq;
+ return str.str;
} else {
return value.as.str;
}
@@ -443,11 +447,9 @@ class VM {
this.pushA(makeBooleanValue(!bval));
break;
case OpCode.OP_CONCAT:
- Value b = this.popA();
- Value a = this.popA();
- string bstr = asString(b);
- string astr = asString(a);
- this.pushA(makeStringValue(astr ~ bstr));
+ Seq b = asSeq(this.popA());
+ Seq a = asSeq(this.popA());
+ this.pushA(makeSeqValue(a.concat(b)));
break;
case OpCode.OP_GREATER:
Value b = this.popA();