From 46a9b83a118207f414f2f7e4c0391785dc440fa4 Mon Sep 17 00:00:00 2001 From: mryouse Date: Fri, 26 May 2023 02:24:35 +0000 Subject: make 'concat' work for sequences --- chunk.d | 26 ++++++++++++++++++++++++++ compiler.d | 18 +++++++++++++++++- vm.d | 14 ++++++++------ 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(); -- cgit v1.2.3