Fixed jumps in functions issue

This commit is contained in:
2022-09-03 07:57:25 +01:00
parent d2aacea8c5
commit 4ad33a3082
7 changed files with 183 additions and 45 deletions

View File

@@ -1,8 +1,19 @@
fn capture(count: int) {
print count;
print capture;
if (count < 5) {
return count;
}
print count;
print capture;
fn foo() {
//
count++;
count++;
// return capture(count + 1);
return -1;
}
foo();
print capture(52);

View File

@@ -0,0 +1,87 @@
fn sanity() {
//test true jump
if (true) {
assert true, "if-then failed (1)";
}
else {
assert false, "if-then failed (2)";
}
//test false jump
if (false) {
assert false, "if-then failed (3)";
}
else {
assert true, "if-then failed (4)";
}
//test while loop
var whileCounter = 0;
while (whileCounter < 10) {
whileCounter = whileCounter + 1;
}
assert whileCounter == 10, "while-loop failed";
//test for loop
var forCache = 0;
for (var i = 0; i < 20; i++) {
forCache = i;
}
assert forCache == 19, "for-loop failed";
//test break - while
var breakWhileCache = 0;
while(true) {
breakWhileCache = breakWhileCache + 1;
if (breakWhileCache >= 7) {
break;
}
}
assert breakWhileCache == 7, "break-while failed";
//test continue - while
var continueWhileCache = 0;
while (continueWhileCache < 10) {
continueWhileCache = continueWhileCache + 1;
if (continueWhileCache >= 7) {
continue;
}
assert continueWhileCache < 7, "continue-while failed";
}
//test break - for
for (var i = 0; i < 10; i++) {
if (i >= 7) {
break;
}
assert i < 7, "break-for failed";
}
//test break - continue
for (var i = 0; i < 10; i++) {
if (i >= 7) {
continue;
}
assert i < 7, "continue-for failed";
}
print "All good";
}
//invoke the test
sanity();

View File

@@ -267,7 +267,7 @@ static int writeLiteralToCompiler(Compiler* compiler, Literal literal) {
return index;
}
static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAddressesPtr, void* continueAddressesPtr) {
static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAddressesPtr, void* continueAddressesPtr, int jumpOffsets) { //NOTE: jumpOfsets are included, because function arg and return indexes are embedded in the code body i.e. need to include thier sizes in the jump
//grow if the bytecode space is too small
if (compiler->count + 32 > compiler->capacity) {
int oldCapacity = compiler->capacity;
@@ -291,20 +291,20 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
case NODE_UNARY:
//pass to the child node, then embed the unary command (print, negate, etc.)
writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, node->unary.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
compiler->bytecode[compiler->count++] = (unsigned char)node->unary.opcode; //1 byte
break;
case NODE_BINARY:
//pass to the child nodes, then embed the binary command (math, etc.)
writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, node->binary.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
break;
case NODE_GROUPING:
compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_BEGIN; //1 byte
writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, node->grouping.child, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_END; //1 byte
break;
@@ -312,7 +312,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte
for (int i = 0; i < node->block.count; i++) {
writeCompilerWithJumps(compiler, &(node->block.nodes[i]), breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, &(node->block.nodes[i]), breakAddressesPtr, continueAddressesPtr, jumpOffsets);
}
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_END; //1 byte
@@ -343,7 +343,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
case NODE_VAR_DECL: {
//first, embed the expression (leaves it on the stack)
writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, node->varDecl.expression, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
//write each piece of the declaration to the bytecode
int identifierIndex = findLiteralIndex(&compiler->literalCache, node->varDecl.identifier);
@@ -379,7 +379,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
initCompiler(fnCompiler);
writeCompiler(fnCompiler, node->fnDecl.arguments); //can be empty, but not NULL
writeCompiler(fnCompiler, node->fnDecl.returns); //can be empty, but not NULL
writeCompiler(fnCompiler, node->fnDecl.block); //can be empty, but not NULL
writeCompilerWithJumps(fnCompiler, node->fnDecl.block, NULL, NULL, -4); //can be empty, but not NULL
//create the function in the literal cache (by storing the compiler object)
Literal fnLiteral = TO_FUNCTION_LITERAL(fnCompiler, 0);
@@ -429,7 +429,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter
//sub-calls
if (node->fnCall.arguments->fnCollection.nodes[i].type != NODE_LITERAL) {
writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets);
continue;
}
@@ -482,7 +482,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
case NODE_PATH_IF: {
//process the condition
writeCompilerWithJumps(compiler, node->path.condition, breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, node->path.condition, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
//cache the point to insert the jump distance at
compiler->bytecode[compiler->count++] = OP_IF_FALSE_JUMP; //1 byte
@@ -490,7 +490,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
compiler->count += sizeof(unsigned short); //2 bytes
//write the then path
writeCompilerWithJumps(compiler, node->path.thenPath, breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, node->path.thenPath, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
int jumpToEnd = 0;
@@ -502,14 +502,14 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
}
//update the jumpToElse to point here
AS_USHORT(compiler->bytecode[jumpToElse]) = compiler->count; //2 bytes
AS_USHORT(compiler->bytecode[jumpToElse]) = compiler->count + jumpOffsets; //2 bytes
if (node->path.elsePath) {
//if there's an else path, write it and
writeCompilerWithJumps(compiler, node->path.elsePath, breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, node->path.elsePath, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
//update the jumpToEnd to point here
AS_USHORT(compiler->bytecode[jumpToEnd]) = compiler->count; //2 bytes
AS_USHORT(compiler->bytecode[jumpToEnd]) = compiler->count + jumpOffsets; //2 bytes
}
}
break;
@@ -526,7 +526,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
unsigned short jumpToStart = compiler->count;
//process the condition
writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses);
writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets);
//if false, jump to end
compiler->bytecode[compiler->count++] = OP_IF_FALSE_JUMP; //1 byte
@@ -534,27 +534,30 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
compiler->count += sizeof(unsigned short); //2 bytes
//write the body
writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses);
writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets);
//jump to condition
compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte
AS_USHORT(compiler->bytecode[compiler->count]) = jumpToStart;
AS_USHORT(compiler->bytecode[compiler->count]) = jumpToStart + jumpOffsets;
compiler->count += sizeof(unsigned short); //2 bytes
//jump from condition
AS_USHORT(compiler->bytecode[jumpToEnd]) = (unsigned short)compiler->count;
AS_USHORT(compiler->bytecode[jumpToEnd]) = (unsigned short)compiler->count + jumpOffsets;
//set the breaks and continues
for (int i = 0; i < breakAddresses.count; i++) {
int point = AS_INTEGER(breakAddresses.literals[i]);
AS_USHORT(compiler->bytecode[point]) = (unsigned short)compiler->count;
AS_USHORT(compiler->bytecode[point]) = (unsigned short)compiler->count + jumpOffsets;
}
for (int i = 0; i < continueAddresses.count; i++) {
int point = AS_INTEGER(continueAddresses.literals[i]);
AS_USHORT(compiler->bytecode[point]) = jumpToStart;
AS_USHORT(compiler->bytecode[point]) = jumpToStart + jumpOffsets;
}
//clear the stack after use
compiler->bytecode[compiler->count++] = OP_POP_STACK; //1 byte
//cleanup
freeLiteralArray(&breakAddresses);
freeLiteralArray(&continueAddresses);
@@ -572,11 +575,11 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte
//initial setup
writeCompilerWithJumps(compiler, node->path.preClause, &breakAddresses, &continueAddresses);
writeCompilerWithJumps(compiler, node->path.preClause, &breakAddresses, &continueAddresses, jumpOffsets);
//conditional
unsigned short jumpToStart = compiler->count;
writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses);
writeCompilerWithJumps(compiler, node->path.condition, &breakAddresses, &continueAddresses, jumpOffsets);
//if false jump to end
compiler->bytecode[compiler->count++] = OP_IF_FALSE_JUMP; //1 byte
@@ -585,34 +588,37 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
//write the body
compiler->bytecode[compiler->count++] = OP_SCOPE_BEGIN; //1 byte
writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses);
writeCompilerWithJumps(compiler, node->path.thenPath, &breakAddresses, &continueAddresses, jumpOffsets);
compiler->bytecode[compiler->count++] = OP_SCOPE_END; //1 byte
//for-breaks actually jump to the bottom
int jumpToIncrement = compiler->count;
//evaluate third clause, restart
writeCompilerWithJumps(compiler, node->path.postClause, &breakAddresses, &continueAddresses);
writeCompilerWithJumps(compiler, node->path.postClause, &breakAddresses, &continueAddresses, jumpOffsets);
compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte
AS_USHORT(compiler->bytecode[compiler->count]) = jumpToStart;
AS_USHORT(compiler->bytecode[compiler->count]) = jumpToStart + jumpOffsets;
compiler->count += sizeof(unsigned short); //2 bytes
AS_USHORT(compiler->bytecode[jumpToEnd]) = compiler->count;
AS_USHORT(compiler->bytecode[jumpToEnd]) = compiler->count + jumpOffsets;
compiler->bytecode[compiler->count++] = OP_SCOPE_END; //1 byte
//set the breaks and continues
for (int i = 0; i < breakAddresses.count; i++) {
int point = AS_INTEGER(breakAddresses.literals[i]);
AS_USHORT(compiler->bytecode[point]) = compiler->count;
AS_USHORT(compiler->bytecode[point]) = compiler->count + jumpOffsets;
}
for (int i = 0; i < continueAddresses.count; i++) {
int point = AS_INTEGER(continueAddresses.literals[i]);
AS_USHORT(compiler->bytecode[point]) = jumpToIncrement;
AS_USHORT(compiler->bytecode[point]) = jumpToIncrement + jumpOffsets;
}
//clear the stack after use
compiler->bytecode[compiler->count++] = OP_POP_STACK; //1 byte
//cleanup
freeLiteralArray(&breakAddresses);
freeLiteralArray(&continueAddresses);
@@ -658,7 +664,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
case NODE_PATH_RETURN: {
//read each returned literal onto the stack, and return the number of values to return
for (int i = 0; i < node->path.thenPath->fnCollection.count; i++) {
writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr);
writeCompilerWithJumps(compiler, &node->path.thenPath->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets);
}
//push the return, with the number of literals
@@ -714,7 +720,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
}
void writeCompiler(Compiler* compiler, Node* node) {
writeCompilerWithJumps(compiler, node, NULL, NULL);
writeCompilerWithJumps(compiler, node, NULL, NULL, 0);
}
void freeCompiler(Compiler* compiler) {

View File

@@ -597,9 +597,13 @@ static bool execPushLiteral(Interpreter* interpreter, bool lng) {
static bool rawLiteral(Interpreter* interpreter) {
Literal lit = popLiteralArray(&interpreter->stack);
if (IS_IDENTIFIER(lit)) {
Literal idn = lit;
if (!parseIdentifierToValue(interpreter, &lit)) {
return false;
}
freeLiteral(idn);
}
pushLiteralArray(&interpreter->stack, lit);
@@ -1277,8 +1281,12 @@ static bool execFalseJump(Interpreter* interpreter) {
//actually jump
Literal lit = popLiteralArray(&interpreter->stack);
if (!parseIdentifierToValue(interpreter, &lit)) {
return false;
bool freeLit = false;
if (IS_IDENTIFIER(lit)) {
Literal idn = lit;
parseIdentifierToValue(interpreter, &lit);
freeLiteral(idn);
freeLit = true;
}
if (IS_NULL(lit)) {
@@ -1290,7 +1298,9 @@ static bool execFalseJump(Interpreter* interpreter) {
interpreter->count = target + interpreter->codeStart;
}
if (freeLit) {
freeLiteral(lit);
}
return true;
}
@@ -1322,8 +1332,6 @@ static bool execFnCall(Interpreter* interpreter) {
return false;
}
freeLiteral(identifier);
//check for side-loaded native functions
if (IS_FUNCTION_NATIVE(func)) {
//reverse the order to the correct order
@@ -1343,6 +1351,18 @@ static bool execFnCall(Interpreter* interpreter) {
return true;
}
if (!IS_FUNCTION(func)) {
printf(ERROR "ERROR: Function not found: ");
printLiteral(identifier);
printf("\n" RESET);
freeLiteral(identifier);
freeLiteralArray(&arguments);
return false;
}
freeLiteral(identifier);
//set up a new interpreter
Interpreter inner;
@@ -1463,7 +1483,7 @@ static bool execFnCall(Interpreter* interpreter) {
initLiteralArray(&returns);
//unpack the results
while (inner.stack.count > 0) {
for (int i = 0; i < (returnArray->count || 1); i++) {
Literal lit = popLiteralArray(&inner.stack);
pushLiteralArray(&returns, lit); //NOTE: also reverses the order
freeLiteral(lit);
@@ -1473,7 +1493,7 @@ static bool execFnCall(Interpreter* interpreter) {
//TODO: remove this when multiple assignment is enabled - note the BUGFIX that balances the stack
if (returns.count > 1) {
printf(ERROR "ERROR: Too many values returned (multiple returns not yet implemented)\n" RESET);
printf(ERROR "ERROR: Too many values returned (multiple returns not yet supported)\n" RESET);
returnValue = false;
}
@@ -1526,7 +1546,11 @@ static bool execFnReturn(Interpreter* interpreter) {
//get the values of everything on the stack
while (interpreter->stack.count > 0) {
Literal lit = popLiteralArray(&interpreter->stack);
if (IS_IDENTIFIER(lit)) {
Literal idn = lit;
parseIdentifierToValue(interpreter, &lit);
freeLiteral(idn);
}
pushLiteralArray(&returns, lit); //reverses the order
freeLiteral(lit);
}
@@ -1731,6 +1755,12 @@ static void execInterpreter(Interpreter* interpreter) {
}
break;
case OP_POP_STACK:
while (interpreter->stack.count > 0) {
freeLiteral(popLiteralArray(&interpreter->stack));
}
break;
default:
printf(ERROR "Error: Unknown opcode found %d, terminating\n" RESET, opcode);
printLiteralArray(&interpreter->stack, "\n");

View File

@@ -63,6 +63,9 @@ typedef enum Opcode {
OP_FN_CALL,
OP_FN_RETURN,
//pop the stack at the end of a complex statement
OP_POP_STACK,
//meta
OP_FN_END, //different from SECTION_END
OP_SECTION_END = 255,

View File

@@ -18,7 +18,7 @@ all: $(OBJ) $(TESTS:%.c=../$(OUTDIR)/%.exe)
ifeq ($(shell uname),Linux)
valgrind --leak-check=full --track-origins=yes $@
else
@echo please run these tests with valgrind on linux
$@
endif
$(OBJ): | $(ODIR)

View File

@@ -150,13 +150,14 @@ int main() {
{
//run each file in ../scripts/test/
int count = 12;
int count = 13;
char* filenames[] = {
"arithmetic.toy",
"casting.toy",
"comparisons.toy",
"functions.toy",
"jumps.toy",
"jumps-in-functions.toy",
"logicals.toy",
"long-array.toy",
"long-dictionary.toy",