|
@@ -75,8 +75,15 @@ static void codeRewriteI32(Context* c, size_t pos, i32 i) {
|
|
|
c->code->code.writeIndex = oldPos;
|
|
c->code->code.writeIndex = oldPos;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static i32 addVariable(Context* c, const char* name) {
|
|
|
|
|
|
|
+static bool hasLocalVar(const Context* c) {
|
|
|
|
|
+ return c->variables != nullptr && c->variables->index < 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static i32 addVariable(Context* c, const char* name, bool forceGlobal) {
|
|
|
for(Variable* v = c->variables; v != nullptr; v = v->next) {
|
|
for(Variable* v = c->variables; v != nullptr; v = v->next) {
|
|
|
|
|
+ if(!forceGlobal && c->inFunction && v->index >= 0) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
if(strcmp(v->name, name) == 0) {
|
|
if(strcmp(v->name, name) == 0) {
|
|
|
return v->index;
|
|
return v->index;
|
|
|
}
|
|
}
|
|
@@ -87,7 +94,11 @@ static i32 addVariable(Context* c, const char* name) {
|
|
|
THROW_ERROR("Too less memory for variables");
|
|
THROW_ERROR("Too less memory for variables");
|
|
|
}
|
|
}
|
|
|
v->next = c->variables;
|
|
v->next = c->variables;
|
|
|
- v->index = c->variables != nullptr ? c->variables->index + 1 : 0;
|
|
|
|
|
|
|
+ if(c->inFunction) {
|
|
|
|
|
+ v->index = hasLocalVar(c) ? c->variables->index - 1 : -1;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ v->index = c->variables != nullptr ? c->variables->index + 1 : 0;
|
|
|
|
|
+ }
|
|
|
memcpy(v->name, name, l);
|
|
memcpy(v->name, name, l);
|
|
|
c->variables = v;
|
|
c->variables = v;
|
|
|
return v->index;
|
|
return v->index;
|
|
@@ -176,18 +187,25 @@ static Token consumeNewline(Context* c) {
|
|
|
return t;
|
|
return t;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void compileReadVariable(Context* c, Token token, bool forceGlobal) {
|
|
|
|
|
+ i32 index = addVariable(c, token.stringValue, forceGlobal);
|
|
|
|
|
+ codePushInstruction(c, READ_VARIABLE);
|
|
|
|
|
+ codePushI32(c, index);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static void compileConstant(Context* c) {
|
|
static void compileConstant(Context* c) {
|
|
|
Token token = tokenizerNext(c->tokenizer);
|
|
Token token = tokenizerNext(c->tokenizer);
|
|
|
if(token.type == STRING) {
|
|
if(token.type == STRING) {
|
|
|
codePushInstruction(c, PUSH_CONSTANT_STRING);
|
|
codePushInstruction(c, PUSH_CONSTANT_STRING);
|
|
|
codePushConstantString(c, token.stringValue);
|
|
codePushConstantString(c, token.stringValue);
|
|
|
} else if(token.type == INT32) {
|
|
} else if(token.type == INT32) {
|
|
|
- codePushInstruction(c, PUSH_INT64);
|
|
|
|
|
|
|
+ codePushInstruction(c, PUSH_INT32);
|
|
|
codePushI32(c, token.intValue);
|
|
codePushI32(c, token.intValue);
|
|
|
} else if(token.type == LITERAL) {
|
|
} else if(token.type == LITERAL) {
|
|
|
- i32 index = addVariable(c, token.stringValue);
|
|
|
|
|
- codePushInstruction(c, READ_VARIABLE);
|
|
|
|
|
- codePushI32(c, index);
|
|
|
|
|
|
|
+ compileReadVariable(c, token, false);
|
|
|
|
|
+ } else if(token.type == DOLLAR) {
|
|
|
|
|
+ token = consumeToken(c, LITERAL);
|
|
|
|
|
+ compileReadVariable(c, token, true);
|
|
|
} else {
|
|
} else {
|
|
|
unexpectedToken(c, token);
|
|
unexpectedToken(c, token);
|
|
|
}
|
|
}
|
|
@@ -226,10 +244,10 @@ static void compileIf(Context* c) {
|
|
|
codeRewriteI32(c, posIndex, (i32)codeGetWritePosition(c));
|
|
codeRewriteI32(c, posIndex, (i32)codeGetWritePosition(c));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void compileSetVariable(Context* c, const char* name) {
|
|
|
|
|
|
|
+static void compileSetVariable(Context* c, const char* name, bool forceGlobal) {
|
|
|
consumeToken(c, EQUAL);
|
|
consumeToken(c, EQUAL);
|
|
|
compileExpression(c);
|
|
compileExpression(c);
|
|
|
- i32 index = addVariable(c, name);
|
|
|
|
|
|
|
+ i32 index = addVariable(c, name, forceGlobal);
|
|
|
codePushInstruction(c, SET_VARIABLE);
|
|
codePushInstruction(c, SET_VARIABLE);
|
|
|
codePushI32(c, index);
|
|
codePushI32(c, index);
|
|
|
}
|
|
}
|
|
@@ -239,13 +257,32 @@ static void compileFunction(Context* c) {
|
|
|
THROW_ERROR("Functions in functions are not allowed");
|
|
THROW_ERROR("Functions in functions are not allowed");
|
|
|
}
|
|
}
|
|
|
c->inFunction = true;
|
|
c->inFunction = true;
|
|
|
|
|
+
|
|
|
codePushInstruction(c, JUMP);
|
|
codePushInstruction(c, JUMP);
|
|
|
size_t pos = codeGetWritePosition(c);
|
|
size_t pos = codeGetWritePosition(c);
|
|
|
codePushI32(c, 0);
|
|
codePushI32(c, 0);
|
|
|
|
|
|
|
|
Token t = consumeToken(c, LITERAL);
|
|
Token t = consumeToken(c, LITERAL);
|
|
|
addFunction(c, t.stringValue, (i32)codeGetWritePosition(c));
|
|
addFunction(c, t.stringValue, (i32)codeGetWritePosition(c));
|
|
|
|
|
+
|
|
|
|
|
+ codePushInstruction(c, PUSH_STACK_VARIABLES);
|
|
|
|
|
+ size_t stackVarsLoc = codeGetWritePosition(c);
|
|
|
|
|
+ codePushI32(c, 0);
|
|
|
|
|
+
|
|
|
consumeToken(c, OPEN_ROUND_BRACKET);
|
|
consumeToken(c, OPEN_ROUND_BRACKET);
|
|
|
|
|
+ i32 vars = 0;
|
|
|
|
|
+ Variable* resetVar = c->variables;
|
|
|
|
|
+ while(true) {
|
|
|
|
|
+ if(tokenizerPeek(c->tokenizer).type != LITERAL) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ Token varToken = consumeToken(c, LITERAL);
|
|
|
|
|
+ addVariable(c, varToken.stringValue, false);
|
|
|
|
|
+ vars++;
|
|
|
|
|
+ if(tokenizerPeek(c->tokenizer).type == COMMA) {
|
|
|
|
|
+ consumeToken(c, COMMA);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
consumeToken(c, CLOSE_ROUND_BRACKET);
|
|
consumeToken(c, CLOSE_ROUND_BRACKET);
|
|
|
while(true) {
|
|
while(true) {
|
|
|
if(tokenizerPeek(c->tokenizer).type == END) {
|
|
if(tokenizerPeek(c->tokenizer).type == END) {
|
|
@@ -254,18 +291,46 @@ static void compileFunction(Context* c) {
|
|
|
compileLine(c, tokenizerNext(c->tokenizer));
|
|
compileLine(c, tokenizerNext(c->tokenizer));
|
|
|
}
|
|
}
|
|
|
consumeToken(c, END);
|
|
consumeToken(c, END);
|
|
|
|
|
+ i32 popVars = hasLocalVar(c) ? -c->variables->index : 0;
|
|
|
codePushInstruction(c, RETURN);
|
|
codePushInstruction(c, RETURN);
|
|
|
|
|
+ codePushI32(c, popVars);
|
|
|
|
|
+ codeRewriteI32(c, stackVarsLoc, popVars - vars);
|
|
|
|
|
+
|
|
|
|
|
+ while(c->variables != resetVar) {
|
|
|
|
|
+ Variable* next = c->variables->next;
|
|
|
|
|
+ memoryFree(c->variables);
|
|
|
|
|
+ c->variables = next;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
codeRewriteI32(c, pos, (i32)codeGetWritePosition(c));
|
|
codeRewriteI32(c, pos, (i32)codeGetWritePosition(c));
|
|
|
c->inFunction = false;
|
|
c->inFunction = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void compileCallFunction(Context* c, Token t) {
|
|
static void compileCallFunction(Context* c, Token t) {
|
|
|
|
|
+ // used to store return address and variable index
|
|
|
|
|
+ codePushInstruction(c, PUSH_INT32);
|
|
|
|
|
+ codePushI32(c, 0);
|
|
|
|
|
+ codePushInstruction(c, PUSH_INT32);
|
|
|
|
|
+ codePushI32(c, 0);
|
|
|
|
|
+
|
|
|
|
|
+ consumeToken(c, OPEN_ROUND_BRACKET);
|
|
|
|
|
+ i32 offset = 0;
|
|
|
|
|
+ while(true) {
|
|
|
|
|
+ if(tokenizerPeek(c->tokenizer).type == CLOSE_ROUND_BRACKET) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ offset++;
|
|
|
|
|
+ compileExpression(c);
|
|
|
|
|
+ if(tokenizerPeek(c->tokenizer).type == COMMA) {
|
|
|
|
|
+ consumeToken(c, COMMA);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ consumeToken(c, CLOSE_ROUND_BRACKET);
|
|
|
|
|
+
|
|
|
codePushInstruction(c, JUMP_SUB);
|
|
codePushInstruction(c, JUMP_SUB);
|
|
|
size_t pos = codeGetWritePosition(c);
|
|
size_t pos = codeGetWritePosition(c);
|
|
|
codePushI32(c, addCallFunction(c, t.stringValue, (i32)pos));
|
|
codePushI32(c, addCallFunction(c, t.stringValue, (i32)pos));
|
|
|
- consumeToken(c, OPEN_ROUND_BRACKET);
|
|
|
|
|
- consumeToken(c, CLOSE_ROUND_BRACKET);
|
|
|
|
|
|
|
+ codePushI32(c, offset);
|
|
|
consumeNewline(c);
|
|
consumeNewline(c);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -279,6 +344,10 @@ static void compileLine(Context* c, Token token) {
|
|
|
} else if(token.type == FUNCTION) {
|
|
} else if(token.type == FUNCTION) {
|
|
|
compileFunction(c);
|
|
compileFunction(c);
|
|
|
return;
|
|
return;
|
|
|
|
|
+ } else if(token.type == DOLLAR) {
|
|
|
|
|
+ token = consumeToken(c, LITERAL);
|
|
|
|
|
+ compileSetVariable(c, token.stringValue, true);
|
|
|
|
|
+ return;
|
|
|
} else if(token.type != LITERAL) {
|
|
} else if(token.type != LITERAL) {
|
|
|
unexpectedToken(c, token);
|
|
unexpectedToken(c, token);
|
|
|
}
|
|
}
|
|
@@ -291,7 +360,7 @@ static void compileLine(Context* c, Token token) {
|
|
|
consumeNewline(c);
|
|
consumeNewline(c);
|
|
|
codePushInstruction(c, PRINT_NEWLINE);
|
|
codePushInstruction(c, PRINT_NEWLINE);
|
|
|
} else if(tokenizerPeek(c->tokenizer).type == EQUAL) {
|
|
} else if(tokenizerPeek(c->tokenizer).type == EQUAL) {
|
|
|
- compileSetVariable(c, s);
|
|
|
|
|
|
|
+ compileSetVariable(c, s, false);
|
|
|
} else if(tokenizerPeek(c->tokenizer).type == OPEN_ROUND_BRACKET) {
|
|
} else if(tokenizerPeek(c->tokenizer).type == OPEN_ROUND_BRACKET) {
|
|
|
compileCallFunction(c, token);
|
|
compileCallFunction(c, token);
|
|
|
} else {
|
|
} else {
|