aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Winston2023-05-20 22:54:07 -0400
committerBen Winston2023-05-20 22:54:07 -0400
commit2ad2be250a68e907b308b120b934edcbfc99ae6e (patch)
tree54cd9308286cb4a368a8f7eb11ad9011c74ac58a
parent38dc63a67879a42f208b5642a8590e1192e8e2e5 (diff)
block scope and local variables (not really working)
-rw-r--r--chunk.d4
-rw-r--r--compiler.d134
-rw-r--r--dbg.d16
-rw-r--r--main.d9
-rw-r--r--parser.d38
-rw-r--r--vm.d34
6 files changed, 227 insertions, 8 deletions
diff --git a/chunk.d b/chunk.d
index daced26..571cf25 100644
--- a/chunk.d
+++ b/chunk.d
@@ -38,8 +38,12 @@ enum OpCode {
OP_RETURN,
OP_CONSTANT,
OP_DEFINE_GLOBAL,
+ OP_GET_LOCAL,
+ OP_SET_LOCAL,
OP_GET_GLOBAL,
+ OP_SET_GLOBAL,
OP_POP,
+ OP_POP_SCOPE,
OP_SUBTRACT,
OP_NIL,
}
diff --git a/compiler.d b/compiler.d
index 739f887..7a198ee 100644
--- a/compiler.d
+++ b/compiler.d
@@ -23,9 +23,11 @@ class Compiler {
FunctionType type;
Parser* parser;
Local[] locals;
+ int localCount;
int scopeDepth;
Form current;
Form previous;
+
Form outer;
int outerIdx;
@@ -88,31 +90,142 @@ class Compiler {
func.chunk.writeOp(OpCode.OP_LESS, current.line);
}
- void compileDef(Form form) {
- Def def = cast(Def)form;
+ int parseVariable(Def def) {
+ declareVariable(def.name);
+ if (scopeDepth > 0) {
+ //return 0;
+ return localCount - 1;
+ //return localCount;
+ }
- // add the variable name to the chunk
int addr = func.chunk.addConstant(makeStringValue(def.name.name));
+ return addr;
+ }
+
+ void defineVariable(int addr) {
+ if (scopeDepth > 0) {
+ return;
+ }
+ func.chunk.writeOp(OpCode.OP_DEFINE_GLOBAL, current.line);
+ func.chunk.writeOp(to!ubyte(addr), current.line);
+ }
+
+ void declareVariable(Symbol sym) {
+
+ if (scopeDepth == 0) {
+ return;
+ }
+
+ for (int i = localCount - 1; i >= 0; i--) {
+ Local local = locals[i];
+ if (local.depth != -1 && local.depth < scopeDepth) {
+ break;
+ }
+
+ if (sym.name == local.sym.name) {
+ writefln("ERROR: already a variable named '%s' in this scope", sym.name);
+ return;
+ }
+ }
+
+ writefln("> > > creating a local at %d", scopeDepth);
+ Local loc = Local(sym, scopeDepth);
+ locals ~= loc;
+ localCount++;
+ writefln("localcount is now %d", localCount);
+ }
+
+ void compileDef(Form form) {
+ Def def = cast(Def)form;
// resolve the value
resolve(def.val);
+ // add the variable name to the chunk (if applicable)
+ int addr = parseVariable(def);
+
+ // are we setting a local?
+ if (scopeDepth > 0) {
+ func.chunk.writeOp(OpCode.OP_SET_LOCAL, current.line);
+ func.chunk.writeOp(to!ubyte(addr), current.line);
+ }
+
// define the variable
+ defineVariable(addr);
+ /*
func.chunk.writeOp(OpCode.OP_DEFINE_GLOBAL, current.line);
func.chunk.writeOp(to!ubyte(addr), current.line);
+ */
+
+ // is this right?
+ //func.chunk.writeOp(OpCode.OP_POP, def.line);
+ }
+
+ int resolveLocal(Symbol sym) {
+ //for (int i = localCount - 1; i >= 0; i--) {
+ for (int i = localCount - 1; i >= 0; i--) {
+ Local local = locals[i];
+ writefln(" > > looping, looking at '%s' (%d) (depth: %d)", local.sym.name, i, local.depth);
+ if (local.sym.name == sym.name) {
+ return i;
+ }
+ }
+
+ return -1;
}
void compileSymbol(Form form) {
Symbol sym = cast(Symbol)form;
+ OpCode getOp;
+ OpCode setOp;
+ int arg = resolveLocal(sym);
+ if (arg != -1) {
+ writeln("compiling a LOCAL symbol");
+ getOp = OpCode.OP_GET_LOCAL;
+ setOp = OpCode.OP_SET_LOCAL; // do we need this here
+ } else {
+ writeln("compiling a GLOBAL symbol");
+ arg = func.chunk.addConstant(makeStringValue(sym.name));
+ getOp = OpCode.OP_GET_GLOBAL;
+ setOp = OpCode.OP_SET_GLOBAL; // do we need this here
+ }
+
// add the symbol name to the chunk
- int addr = func.chunk.addConstant(makeStringValue(sym.name));
+ //int addr = func.chunk.addConstant(makeStringValue(sym.name));
// get the variable
- func.chunk.writeOp(OpCode.OP_GET_GLOBAL, sym.line);
- func.chunk.writeOp(to!ubyte(addr), sym.line);
+ func.chunk.writeOp(to!ubyte(getOp), sym.line);
+ func.chunk.writeOp(to!ubyte(arg), sym.line);
- advance();
+ //advance();
+ }
+
+ void compileBlock(Form form) {
+ Block block = cast(Block)form;
+ beginScope();
+ foreach (Form inner; block.blockBody) {
+ resolve(inner);
+ }
+ endScope();
+ }
+
+ void beginScope() {
+ scopeDepth++;
+ }
+
+ void endScope() {
+
+ writefln("> > ending scope at depth %d", scopeDepth);
+ scopeDepth--;
+
+ while (localCount > 0 &&
+ locals[localCount - 1].depth > scopeDepth) {
+ writeln("> > looping, gonna pop");
+ func.chunk.writeOp(to!ubyte(OpCode.OP_POP_SCOPE), -1);
+ //func.chunk.writeOp(to!ubyte(OpCode.OP_POP), -1);
+ localCount--;
+ }
}
void compileCons(Form form) {
@@ -168,6 +281,9 @@ class Compiler {
case FormType.SYMBOL:
this.compileSymbol(form);
break;
+ case FormType.BLOCK:
+ this.compileBlock(form);
+ break;
default:
write("not sure how to resolve: ");
printForm(form);
@@ -199,6 +315,8 @@ class Compiler {
this.parser = parser;
this.func = new Function();
this.type = type;
- locals ~= Local(new Symbol("", -1), 0);
+ localCount = 0;
+ //locals ~= Local(new Symbol("", -1), 0);
+ //localCount++;
}
}
diff --git a/dbg.d b/dbg.d
index 1290cf0..18526db 100644
--- a/dbg.d
+++ b/dbg.d
@@ -51,6 +51,10 @@ void printForm(Form f, string prefix = "") {
Def def = cast(Def)f;
writefln("%s var: %s", prefix, def.name.name);
break;
+ case FormType.BLOCK:
+ Block block = cast(Block)f;
+ writefln("%s block of %d", prefix, block.blockBody.length);
+ break;
default:
writeln("printFormDefault");
break;
@@ -79,6 +83,12 @@ string atomAsString(Atom a) {
return printableValue(a.value);
}
+int byteInstruction(string message, Chunk chunk, int offset) {
+ ubyte slot = chunk.code[offset + 1];
+ writefln("%-16s %4d", message, slot);
+ return offset + 2;
+}
+
int constantInstruction(string message, Chunk chunk, int offset) {
ubyte idx = chunk.code[offset + 1];
//writeln("dunno how to write a constant");
@@ -97,6 +107,10 @@ int disassemble(Chunk chunk, int offset) {
ubyte inst = chunk.code[offset];
switch (inst) {
+ case OpCode.OP_GET_LOCAL:
+ return byteInstruction("OP_GET_LOCAL", chunk, offset);
+ case OpCode.OP_SET_LOCAL:
+ return byteInstruction("OP_SET_LOCAL", chunk, offset);
case OpCode.OP_ADD:
return simpleInstruction("OP_ADD", offset);
case OpCode.OP_LESS:
@@ -111,6 +125,8 @@ int disassemble(Chunk chunk, int offset) {
return simpleInstruction("OP_NEGATE", offset);
case OpCode.OP_POP:
return simpleInstruction("OP_POP", offset);
+ case OpCode.OP_POP_SCOPE:
+ return simpleInstruction("OP_POP_SCOPE", offset);
case OpCode.OP_RETURN:
return simpleInstruction("OP_RETURN", offset);
case OpCode.OP_NIL:
diff --git a/main.d b/main.d
index 678bfb0..526b79a 100644
--- a/main.d
+++ b/main.d
@@ -31,6 +31,15 @@ void repl() {
Compiler compiler = new Compiler(FunctionType.SCRIPT, &parser);
Function func = compiler.compile();
+ int cnt = 0;
+ writeln("== disassembly ==");
+ while(true) {
+ if (cnt >= func.chunk.code.length) {
+ break;
+ }
+ cnt = disassemble(func.chunk, cnt);
+ }
+
VM vm = new VM(func);
vm.run();
diff --git a/parser.d b/parser.d
index ef1d736..978b218 100644
--- a/parser.d
+++ b/parser.d
@@ -13,6 +13,7 @@ enum FormType {
SYMBOL,
FUNC,
DEF,
+ BLOCK,
EOF,
PARSE_ERROR
@@ -79,6 +80,20 @@ class ParseError : Form {
}
}
+class Block : Form {
+
+ Form[] blockBody;
+
+ this(int line) {
+ this.line = line;
+ this.type = FormType.BLOCK;
+ }
+
+ void addToBody(Form f) {
+ this.blockBody ~= f;
+ }
+}
+
class Cons : Form {
Form head;
@@ -376,6 +391,27 @@ class Parser {
return func;
}
+ Form parseBlock() {
+ Block block = new Block(line);
+ char next;
+ while(peekable()) {
+ next = peek();
+ if (next == ')') {
+ break;
+ }
+ block.addToBody(parseForm());
+ }
+
+ if (!peekable()) {
+ return new ParseError("unterminated block", line);
+ }
+
+ advance(); // consume closing paren
+
+ return block;
+
+ }
+
Form parseCons() {
skipWhitespace();
@@ -395,6 +431,8 @@ class Parser {
return parseFunc();
case "def":
return parseDef();
+ case "block":
+ return parseBlock();
default:
break;
}
diff --git a/vm.d b/vm.d
index 7955963..3988d14 100644
--- a/vm.d
+++ b/vm.d
@@ -82,6 +82,15 @@ class VM {
}
writeln("\n--");
+ /*
+ write(" globals >");
+ //for (int i = 0; i < this.topOffset; i++) {
+ foreach (Value val; globals) {
+ writef("[ %s ]", printableValue(val));
+ }
+ writeln("\n--");
+ */
+
disassemble(this.func.chunk, this.ip);
ubyte inst;
switch (inst = this.readByte()) {
@@ -94,6 +103,23 @@ class VM {
Value val = pop();
globals[asString(name)] = val;
break;
+ case OpCode.OP_GET_LOCAL:
+ ubyte slot = readByte();
+ writefln("getting local '%d' stackTop '%d'", slot, topOffset);
+ //push(stack[topOffset + slot - 2]);
+ //push(stack[topOffset + slot]);
+ push(stack[topOffset - 2 + slot]);
+ //push(stack[slot]);
+ break;
+ case OpCode.OP_SET_LOCAL:
+ //writeln("in SET_LOCAL");
+ ubyte slot = readByte();
+ //stack[slot] = peek(0);
+ stack[topOffset + slot - 1] = peek(0);
+ //pop();
+ //stack[slot] = pop();
+ writefln("setting local '%d' stackTop '%d'", slot, topOffset);
+ break;
case OpCode.OP_GET_GLOBAL:
writeln("in OP_GET_GLOBAL");
Value name = func.chunk.constants[readByte()];
@@ -171,6 +197,14 @@ class VM {
Value ret = this.pop();
writefln("returned %s", printableValue(ret));
return InterpretResult.OK;
+ case OpCode.OP_POP:
+ pop();
+ break;
+ case OpCode.OP_POP_SCOPE: // pop the n-1 position
+ Value val = pop();
+ pop(); // throw this one away
+ push(val);
+ break;
default:
writeln("unknown opcode to run");
break;