mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Function calls, with args and single returns are working
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
|
|
||||||
|
fn name(param1, param2) {
|
||||||
fn name(argument: type, arg2: type, ...rest): int {
|
print "foobar";
|
||||||
print "hello world";
|
print param1;
|
||||||
return 0;
|
return param2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var result = name("hello world", "goodnight world");
|
||||||
|
|
||||||
print name;
|
print "fizz";
|
||||||
|
print result;
|
||||||
|
print "buzz";
|
||||||
|
|||||||
@@ -29,3 +29,6 @@ void initCommand(int argc, const char* argv[]);
|
|||||||
void usageCommand(int argc, const char* argv[]);
|
void usageCommand(int argc, const char* argv[]);
|
||||||
void helpCommand(int argc, const char* argv[]);
|
void helpCommand(int argc, const char* argv[]);
|
||||||
void copyrightCommand(int argc, const char* argv[]);
|
void copyrightCommand(int argc, const char* argv[]);
|
||||||
|
|
||||||
|
//NOTE: assigning to a byte from a short loses data
|
||||||
|
#define AS_USHORT(value) (*(unsigned short*)(&(value)))
|
||||||
@@ -10,9 +10,6 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
//assigning to a byte from a short loses data
|
|
||||||
#define AS_USHORT(value) (*(unsigned short*)(&(value)))
|
|
||||||
|
|
||||||
void initCompiler(Compiler* compiler) {
|
void initCompiler(Compiler* compiler) {
|
||||||
initLiteralArray(&compiler->literalCache);
|
initLiteralArray(&compiler->literalCache);
|
||||||
compiler->bytecode = NULL;
|
compiler->bytecode = NULL;
|
||||||
@@ -21,7 +18,7 @@ void initCompiler(Compiler* compiler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//separated out, so it can be recursive
|
//separated out, so it can be recursive
|
||||||
static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal) {
|
static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal literal, bool skipDuplicationOptimisation) {
|
||||||
//if it's a compound type, recurse and store the results
|
//if it's a compound type, recurse and store the results
|
||||||
if (AS_TYPE(literal).typeOf == LITERAL_ARRAY || AS_TYPE(literal).typeOf == LITERAL_DICTIONARY) {
|
if (AS_TYPE(literal).typeOf == LITERAL_ARRAY || AS_TYPE(literal).typeOf == LITERAL_DICTIONARY) {
|
||||||
//I don't like storing types in an array, but it's the easiest and most straight forward method
|
//I don't like storing types in an array, but it's the easiest and most straight forward method
|
||||||
@@ -33,7 +30,7 @@ static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal)
|
|||||||
|
|
||||||
for (int i = 0; i < AS_TYPE(literal).count; i++) {
|
for (int i = 0; i < AS_TYPE(literal).count; i++) {
|
||||||
//write the values to the cache, and the indexes to the store
|
//write the values to the cache, and the indexes to the store
|
||||||
int subIndex = writeLiteralTypeToCache(literalCache, ((Literal*)(AS_TYPE(literal).subtypes))[i]);
|
int subIndex = writeLiteralTypeToCacheOpt(literalCache, ((Literal*)(AS_TYPE(literal).subtypes))[i], false);
|
||||||
pushLiteralArray(store, TO_INTEGER_LITERAL(subIndex));
|
pushLiteralArray(store, TO_INTEGER_LITERAL(subIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +39,7 @@ static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal)
|
|||||||
literal.type = LITERAL_TYPE_INTERMEDIATE; //NOTE: tweaking the type usually isn't a good idea
|
literal.type = LITERAL_TYPE_INTERMEDIATE; //NOTE: tweaking the type usually isn't a good idea
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skipDuplicationOptimisation) {
|
||||||
//BUGFIX: check if exactly this literal array exists
|
//BUGFIX: check if exactly this literal array exists
|
||||||
int index = findLiteralIndex(literalCache, literal);
|
int index = findLiteralIndex(literalCache, literal);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
@@ -50,6 +48,14 @@ static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal)
|
|||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
return pushLiteralArray(literalCache, literal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal) {
|
||||||
|
return writeLiteralTypeToCacheOpt(literalCache, literal, false);
|
||||||
|
}
|
||||||
|
|
||||||
static int writeNodeCompoundToCache(Compiler* compiler, Node* node) {
|
static int writeNodeCompoundToCache(Compiler* compiler, Node* node) {
|
||||||
int index = -1;
|
int index = -1;
|
||||||
@@ -155,49 +161,18 @@ static int writeNodeCompoundToCache(Compiler* compiler, Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int writeNodeCollectionToCache(Compiler* compiler, Node* node) {
|
static int writeNodeCollectionToCache(Compiler* compiler, Node* node) {
|
||||||
//stored as an array
|
|
||||||
LiteralArray* store = ALLOCATE(LiteralArray, 1);
|
LiteralArray* store = ALLOCATE(LiteralArray, 1);
|
||||||
initLiteralArray(store);
|
|
||||||
|
|
||||||
//ensure each literal value is in the cache, individually
|
//ensure each literal value is in the cache, individually
|
||||||
for (int i = 0; i < node->fnCollection.count; i++) {
|
for (int i = 0; i < node->fnCollection.count; i++) {
|
||||||
switch(node->fnCollection.nodes[i].type) {
|
switch(node->fnCollection.nodes[i].type) {
|
||||||
case NODE_VAR_DECL: {
|
case NODE_VAR_DECL: {
|
||||||
//write each piece of the declaration to the bytecode
|
//write each piece of the declaration to the cache
|
||||||
int identifierIndex = findLiteralIndex(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.identifier);
|
int identifierIndex = pushLiteralArray(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.identifier); //store without duplication optimisation
|
||||||
if (identifierIndex < 0) {
|
int typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.typeLiteral, false);
|
||||||
identifierIndex = pushLiteralArray(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
int typeIndex = writeLiteralTypeToCache(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.typeLiteral);
|
pushLiteralArray(store, TO_INTEGER_LITERAL(identifierIndex));
|
||||||
|
pushLiteralArray(store, TO_INTEGER_LITERAL(typeIndex));
|
||||||
//embed the info into the bytecode
|
|
||||||
if (identifierIndex >= 256 || typeIndex >= 256) {
|
|
||||||
//push a "long" declaration
|
|
||||||
compiler->bytecode[compiler->count++] = OP_VAR_DECL_LONG; //1 byte
|
|
||||||
|
|
||||||
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)identifierIndex; //2 bytes
|
|
||||||
compiler->count += sizeof(unsigned short);
|
|
||||||
|
|
||||||
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)typeIndex; //2 bytes
|
|
||||||
compiler->count += sizeof(unsigned short);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//push a declaration
|
|
||||||
compiler->bytecode[compiler->count++] = OP_VAR_DECL; //1 byte
|
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)identifierIndex; //1 byte
|
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)typeIndex; //1 byte
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NODE_LITERAL: {
|
|
||||||
//values
|
|
||||||
int val = findLiteralIndex(&compiler->literalCache, node->fnCollection.nodes[i].atomic.literal);
|
|
||||||
if (val < 0) {
|
|
||||||
val = pushLiteralArray(&compiler->literalCache, node->fnCollection.nodes[i].atomic.literal);
|
|
||||||
}
|
|
||||||
pushLiteralArray(store, TO_INTEGER_LITERAL(val));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -207,7 +182,7 @@ static int writeNodeCollectionToCache(Compiler* compiler, Node* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//push the store to the cache, with instructions about how pack it
|
//store the store
|
||||||
return pushLiteralArray(&compiler->literalCache, TO_ARRAY_LITERAL(store));
|
return pushLiteralArray(&compiler->literalCache, TO_ARRAY_LITERAL(store));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,9 +346,9 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
|||||||
//run a compiler over the function
|
//run a compiler over the function
|
||||||
Compiler* fnCompiler = ALLOCATE(Compiler, 1);
|
Compiler* fnCompiler = ALLOCATE(Compiler, 1);
|
||||||
initCompiler(fnCompiler);
|
initCompiler(fnCompiler);
|
||||||
writeCompiler(fnCompiler, node->fnDecl.arguments);
|
writeCompiler(fnCompiler, node->fnDecl.arguments); //can be empty, but not NULL
|
||||||
writeCompiler(fnCompiler, node->fnDecl.returns);
|
writeCompiler(fnCompiler, node->fnDecl.returns); //can be empty, but not NULL
|
||||||
writeCompiler(fnCompiler, node->fnDecl.block);
|
writeCompiler(fnCompiler, node->fnDecl.block); //can be empty, but not NULL
|
||||||
|
|
||||||
//create the function in the literal cache (by storing the compiler object)
|
//create the function in the literal cache (by storing the compiler object)
|
||||||
Literal fnLiteral = TO_FUNCTION_LITERAL(fnCompiler, 0);
|
Literal fnLiteral = TO_FUNCTION_LITERAL(fnCompiler, 0);
|
||||||
@@ -409,22 +384,42 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_FN_COLLECTION: {
|
case NODE_FN_COLLECTION: {
|
||||||
|
//embed these in the bytecode...
|
||||||
int index = writeNodeCollectionToCache(compiler, node);
|
int index = writeNodeCollectionToCache(compiler, node);
|
||||||
|
|
||||||
|
compiler->bytecode[compiler->count] = (unsigned short)index; //2 bytes
|
||||||
|
compiler->count += sizeof(unsigned short);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_FN_CALL: {
|
||||||
|
//NOTE: assume the function definition/name is above us
|
||||||
|
|
||||||
|
for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter
|
||||||
|
//write each argument to the bytecode
|
||||||
|
int argumentsIndex = findLiteralIndex(&compiler->literalCache, node->fnCall.arguments->fnCollection.nodes[i].atomic.literal);
|
||||||
|
if (argumentsIndex < 0) {
|
||||||
|
argumentsIndex = pushLiteralArray(&compiler->literalCache, node->fnCall.arguments->fnCollection.nodes[i].atomic.literal);
|
||||||
|
}
|
||||||
|
|
||||||
//push the node opcode to the bytecode
|
//push the node opcode to the bytecode
|
||||||
if (index >= 256) {
|
if (argumentsIndex >= 256) {
|
||||||
//push a "long" index
|
//push a "long" index
|
||||||
compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte
|
compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte
|
||||||
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)index; //2 bytes
|
|
||||||
|
|
||||||
|
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)argumentsIndex; //2 bytes
|
||||||
compiler->count += sizeof(unsigned short);
|
compiler->count += sizeof(unsigned short);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//push the index
|
//push the index
|
||||||
compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte
|
compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)index; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)argumentsIndex; //1 byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//call the function
|
||||||
|
//DO NOT call the collection, this is done in binary
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_PATH_IF: {
|
case NODE_PATH_IF: {
|
||||||
@@ -605,7 +600,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
|||||||
}
|
}
|
||||||
|
|
||||||
//push the return, with the number of literals
|
//push the return, with the number of literals
|
||||||
compiler->bytecode[compiler->count++] = OP_RETURN; //1 byte
|
compiler->bytecode[compiler->count++] = OP_FN_RETURN; //1 byte
|
||||||
|
|
||||||
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)(node->path.thenPath->fnCollection.count); //2 bytes
|
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)(node->path.thenPath->fnCollection.count); //2 bytes
|
||||||
compiler->count += sizeof(unsigned short);
|
compiler->count += sizeof(unsigned short);
|
||||||
|
|||||||
@@ -51,9 +51,7 @@ void freeInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
freeLiteralArray(&interpreter->literalCache);
|
freeLiteralArray(&interpreter->literalCache);
|
||||||
|
|
||||||
while (interpreter->scope) {
|
|
||||||
interpreter->scope = popScope(interpreter->scope);
|
interpreter->scope = popScope(interpreter->scope);
|
||||||
}
|
|
||||||
|
|
||||||
freeLiteralArray(&interpreter->stack);
|
freeLiteralArray(&interpreter->stack);
|
||||||
}
|
}
|
||||||
@@ -156,7 +154,7 @@ static bool execPrint(Interpreter* interpreter) {
|
|||||||
|
|
||||||
printLiteralCustom(lit, interpreter->printOutput);
|
printLiteralCustom(lit, interpreter->printOutput);
|
||||||
|
|
||||||
freeLiteral(lit);
|
// freeLiteral(lit); //it's a reference (to the dictionaries), so don't free it
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -397,6 +395,47 @@ static bool execVarDecl(Interpreter* interpreter, bool lng) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool execFnDecl(Interpreter* interpreter, bool lng) {
|
||||||
|
//read the index in the cache
|
||||||
|
int identifierIndex = 0;
|
||||||
|
int functionIndex = 0;
|
||||||
|
Scope* scope = pushScope(interpreter->scope);
|
||||||
|
|
||||||
|
if (lng) {
|
||||||
|
identifierIndex = (int)readShort(interpreter->bytecode, &interpreter->count);
|
||||||
|
functionIndex = (int)readShort(interpreter->bytecode, &interpreter->count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
identifierIndex = (int)readByte(interpreter->bytecode, &interpreter->count);
|
||||||
|
functionIndex = (int)readByte(interpreter->bytecode, &interpreter->count);
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal identifier = interpreter->literalCache.literals[identifierIndex];
|
||||||
|
Literal function = interpreter->literalCache.literals[functionIndex];
|
||||||
|
|
||||||
|
function.as.function.scope = scope; //hacked in
|
||||||
|
|
||||||
|
Literal type = TO_TYPE_LITERAL(LITERAL_FUNCTION, true);
|
||||||
|
|
||||||
|
if (!declareScopeVariable(interpreter->scope, identifier, type)) {
|
||||||
|
printf(ERROR "ERROR: Can't redefine the function \"");
|
||||||
|
printLiteral(identifier);
|
||||||
|
printf("\"\n" RESET);
|
||||||
|
popScope(scope);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setScopeVariable(interpreter->scope, identifier, function, false)) {
|
||||||
|
printf(ERROR "ERROR: Incorrect type assigned to variable \"");
|
||||||
|
printLiteral(identifier);
|
||||||
|
printf("\"\n" RESET);
|
||||||
|
popScope(scope);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool execVarAssign(Interpreter* interpreter) {
|
static bool execVarAssign(Interpreter* interpreter) {
|
||||||
Literal rhs = popLiteralArray(&interpreter->stack);
|
Literal rhs = popLiteralArray(&interpreter->stack);
|
||||||
Literal lhs = popLiteralArray(&interpreter->stack);
|
Literal lhs = popLiteralArray(&interpreter->stack);
|
||||||
@@ -703,8 +742,111 @@ static bool execFalseJump(Interpreter* interpreter) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//forward declare
|
||||||
|
static void execInterpreter(Interpreter*);
|
||||||
|
static void readInterpreterSections(Interpreter* interpreter);
|
||||||
|
|
||||||
|
static bool execFnCall(Interpreter* interpreter) {
|
||||||
|
LiteralArray arguments;
|
||||||
|
initLiteralArray(&arguments);
|
||||||
|
|
||||||
|
//unpack the arguments
|
||||||
|
while (interpreter->stack.count > 1) {
|
||||||
|
pushLiteralArray(&arguments, popLiteralArray(&interpreter->stack)); //NOTE: also reverses the order
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal identifier = popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
|
Literal func = identifier;
|
||||||
|
parseIdentifierToValue(interpreter, &func);
|
||||||
|
|
||||||
|
//set up a new interpreter
|
||||||
|
Interpreter inner;
|
||||||
|
|
||||||
|
//init the inner interpreter manually
|
||||||
|
initLiteralArray(&inner.literalCache);
|
||||||
|
inner.scope = pushScope(func.as.function.scope);
|
||||||
|
inner.bytecode = AS_FUNCTION(func);
|
||||||
|
inner.length = func.as.function.length;
|
||||||
|
inner.count = 0;
|
||||||
|
initLiteralArray(&inner.stack);
|
||||||
|
setInterpreterPrint(&inner, interpreter->printOutput);
|
||||||
|
setInterpreterAssert(&inner, interpreter->assertOutput);
|
||||||
|
|
||||||
|
//prep the sections
|
||||||
|
readInterpreterSections(&inner);
|
||||||
|
|
||||||
|
//prep the arguments
|
||||||
|
LiteralArray* paramArray = AS_ARRAY(inner.literalCache.literals[ readShort(inner.bytecode, &inner.count) ]);
|
||||||
|
LiteralArray* returnArray = AS_ARRAY(inner.literalCache.literals[ readShort(inner.bytecode, &inner.count) ]);
|
||||||
|
|
||||||
|
for (int i = 0; i < paramArray->count; i += 2) { //contents is the indexes of identifier & type
|
||||||
|
//declare and define each entry in the scope
|
||||||
|
if (!declareScopeVariable(inner.scope, paramArray->literals[i], paramArray->literals[i + 1])) {
|
||||||
|
printf(ERROR "[internal] Could not redeclare parameter\n" RESET);
|
||||||
|
freeInterpreter(&inner);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setScopeVariable(inner.scope, paramArray->literals[i], popLiteralArray(&arguments), false)) {
|
||||||
|
printf(ERROR "[internal] Could not redefine parameter\n" RESET);
|
||||||
|
freeInterpreter(&inner);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute the interpreter
|
||||||
|
execInterpreter(&inner);
|
||||||
|
|
||||||
|
//accept the stack as the results
|
||||||
|
LiteralArray returns;
|
||||||
|
initLiteralArray(&returns);
|
||||||
|
|
||||||
|
//unpack the results
|
||||||
|
while (inner.stack.count > 0) {
|
||||||
|
pushLiteralArray(&returns, popLiteralArray(&inner.stack)); //NOTE: also reverses the order
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < returns.count; i++) {
|
||||||
|
pushLiteralArray(&interpreter->stack, popLiteralArray(&returns)); //NOTE: reverses again
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
freeLiteralArray(&returns);
|
||||||
|
freeLiteralArray(&arguments);
|
||||||
|
freeInterpreter(&inner);
|
||||||
|
|
||||||
|
//actual bytecode persists until next call
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool execFnReturn(Interpreter* interpreter) {
|
||||||
|
LiteralArray returns;
|
||||||
|
initLiteralArray(&returns);
|
||||||
|
|
||||||
|
//get the values of everything on the stack
|
||||||
|
while (interpreter->stack.count > 0) {
|
||||||
|
Literal lit = popLiteralArray(&interpreter->stack);
|
||||||
|
parseIdentifierToValue(interpreter, &lit);
|
||||||
|
pushLiteralArray(&returns, lit); //reverses the order
|
||||||
|
}
|
||||||
|
|
||||||
|
//and back again
|
||||||
|
while (returns.count > 0) {
|
||||||
|
pushLiteralArray(&interpreter->stack, popLiteralArray(&returns));
|
||||||
|
}
|
||||||
|
|
||||||
|
freeLiteralArray(&returns);
|
||||||
|
|
||||||
|
//finally
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//the heart of toy
|
//the heart of toy
|
||||||
static void execInterpreter(Interpreter* interpreter) {
|
static void execInterpreter(Interpreter* interpreter) {
|
||||||
|
//set the starting point for the interpreter
|
||||||
|
interpreter->codeStart = interpreter->count;
|
||||||
|
|
||||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||||
|
|
||||||
while(opcode != OP_EOF && opcode != OP_SECTION_END) {
|
while(opcode != OP_EOF && opcode != OP_SECTION_END) {
|
||||||
@@ -790,6 +932,13 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_FN_DECL:
|
||||||
|
case OP_FN_DECL_LONG:
|
||||||
|
if (!execFnDecl(interpreter, opcode == OP_FN_DECL_LONG)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OP_VAR_ASSIGN:
|
case OP_VAR_ASSIGN:
|
||||||
if (!execVarAssign(interpreter)) {
|
if (!execVarAssign(interpreter)) {
|
||||||
return;
|
return;
|
||||||
@@ -868,6 +1017,18 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_FN_CALL:
|
||||||
|
if (!execFnCall(interpreter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_FN_RETURN:
|
||||||
|
if (!execFnReturn(interpreter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf(ERROR "Error: Unknown opcode found %d, terminating\n" RESET, opcode);
|
printf(ERROR "Error: Unknown opcode found %d, terminating\n" RESET, opcode);
|
||||||
printLiteralArray(&interpreter->stack, "\n");
|
printLiteralArray(&interpreter->stack, "\n");
|
||||||
@@ -1085,7 +1246,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
|||||||
|
|
||||||
//read the function code (literal cache and all)
|
//read the function code (literal cache and all)
|
||||||
unsigned char* bytes = ALLOCATE(unsigned char, size);
|
unsigned char* bytes = ALLOCATE(unsigned char, size);
|
||||||
memcpy(bytes, interpreter->bytecode + interpreter->count, size);
|
memcpy(bytes, interpreter->bytecode + interpreter->count, size); //TODO: -1 for the ending mark
|
||||||
interpreter->count += size;
|
interpreter->count += size;
|
||||||
|
|
||||||
//assert that the last memory slot is function end
|
//assert that the last memory slot is function end
|
||||||
@@ -1100,10 +1261,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
consumeByte(OP_SECTION_END, interpreter->bytecode, &interpreter->count); //terminate the function section
|
||||||
|
|
||||||
//set the starting point for the interpreter
|
|
||||||
interpreter->codeStart = interpreter->count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length) {
|
void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ typedef struct {
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
void* ptr;
|
void* ptr;
|
||||||
|
void* scope;
|
||||||
int length;
|
int length;
|
||||||
} function;
|
} function;
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ typedef struct {
|
|||||||
#define TO_STRING_LITERAL(value) _toStringLiteral(value)
|
#define TO_STRING_LITERAL(value) _toStringLiteral(value)
|
||||||
#define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }})
|
#define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }})
|
||||||
#define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }})
|
#define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }})
|
||||||
#define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.ptr = value, .function.length = l }})
|
#define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.ptr = value, .function.scope = NULL, .function.length = l }})
|
||||||
#define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value, strlen(value))
|
#define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value, strlen(value))
|
||||||
#define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
|
#define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ void freeNode(Node* node) {
|
|||||||
FREE_ARRAY(Node, node->fnCollection.nodes, node->fnCollection.capacity);
|
FREE_ARRAY(Node, node->fnCollection.nodes, node->fnCollection.capacity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_FN_CALL:
|
||||||
|
freeNode(node->fnCall.arguments);
|
||||||
|
break;
|
||||||
|
|
||||||
case NODE_PATH_IF:
|
case NODE_PATH_IF:
|
||||||
case NODE_PATH_WHILE:
|
case NODE_PATH_WHILE:
|
||||||
case NODE_PATH_FOR:
|
case NODE_PATH_FOR:
|
||||||
@@ -198,6 +202,15 @@ void emitNodeFnDecl(Node** nodeHandle, Literal identifier, Node* arguments, Node
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emitFnCall(Node** nodeHandle, Node* arguments) {
|
||||||
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
|
tmp->type = NODE_FN_CALL;
|
||||||
|
tmp->fnCall.arguments = arguments;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
void emitNodeFnCollection(Node** nodeHandle) {
|
void emitNodeFnCollection(Node** nodeHandle) {
|
||||||
Node* tmp = ALLOCATE(Node, 1);
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ typedef enum NodeType {
|
|||||||
NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
|
NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
|
||||||
NODE_FN_DECL, //containd identifier literal, arguments node, returns node, block node
|
NODE_FN_DECL, //containd identifier literal, arguments node, returns node, block node
|
||||||
NODE_FN_COLLECTION, //parts of a function
|
NODE_FN_COLLECTION, //parts of a function
|
||||||
|
NODE_FN_CALL,
|
||||||
NODE_PATH_IF, //for control flow
|
NODE_PATH_IF, //for control flow
|
||||||
NODE_PATH_WHILE, //for control flow
|
NODE_PATH_WHILE, //for control flow
|
||||||
NODE_PATH_FOR, //for control flow
|
NODE_PATH_FOR, //for control flow
|
||||||
@@ -101,6 +102,11 @@ typedef struct NodeFnCollection {
|
|||||||
int count;
|
int count;
|
||||||
} NodeFnCollection;
|
} NodeFnCollection;
|
||||||
|
|
||||||
|
typedef struct NodeFnCall {
|
||||||
|
NodeType type;
|
||||||
|
Node* arguments;
|
||||||
|
} NodeFnCall;
|
||||||
|
|
||||||
typedef struct NodePath {
|
typedef struct NodePath {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
Node* preClause;
|
Node* preClause;
|
||||||
@@ -129,6 +135,7 @@ union _node {
|
|||||||
NodeVarDecl varDecl;
|
NodeVarDecl varDecl;
|
||||||
NodeFnDecl fnDecl;
|
NodeFnDecl fnDecl;
|
||||||
NodeFnCollection fnCollection;
|
NodeFnCollection fnCollection;
|
||||||
|
NodeFnCall fnCall;
|
||||||
NodePath path;
|
NodePath path;
|
||||||
NodeIncrement increment;
|
NodeIncrement increment;
|
||||||
};
|
};
|
||||||
@@ -144,6 +151,7 @@ void emitNodePair(Node** nodeHandle, Node* left, Node* right);
|
|||||||
void emitNodeVarTypes(Node** nodeHandle, Literal literal);
|
void emitNodeVarTypes(Node** nodeHandle, Literal literal);
|
||||||
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression);
|
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression);
|
||||||
void emitNodeFnDecl(Node** nodeHandle, Literal identifier, Node* arguments, Node* returns, Node* block);
|
void emitNodeFnDecl(Node** nodeHandle, Literal identifier, Node* arguments, Node* returns, Node* block);
|
||||||
|
void emitFnCall(Node** nodeHandle, Node* arguments);
|
||||||
void emitNodeFnCollection(Node** nodeHandle);
|
void emitNodeFnCollection(Node** nodeHandle);
|
||||||
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
|
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
|
||||||
void emiteNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
void emiteNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ typedef enum Opcode {
|
|||||||
//jumps, and conditional jumps (absolute)
|
//jumps, and conditional jumps (absolute)
|
||||||
OP_JUMP,
|
OP_JUMP,
|
||||||
OP_IF_FALSE_JUMP,
|
OP_IF_FALSE_JUMP,
|
||||||
OP_RETURN,
|
OP_FN_CALL,
|
||||||
|
OP_FN_RETURN,
|
||||||
|
|
||||||
//meta
|
//meta
|
||||||
OP_FN_END, //different from SECTION_END
|
OP_FN_END, //different from SECTION_END
|
||||||
|
|||||||
@@ -627,6 +627,51 @@ static Opcode decrementInfix(Parser* parser, Node** nodeHandle) {
|
|||||||
return OP_EOF;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Opcode fnCall(Parser* parser, Node** nodeHandle) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
//binary() is an infix rule - so only get the RHS of the operator
|
||||||
|
switch(parser->previous.type) {
|
||||||
|
//arithmetic
|
||||||
|
case TOKEN_PAREN_LEFT: {
|
||||||
|
Node* arguments = NULL;
|
||||||
|
emitNodeFnCollection(&arguments);
|
||||||
|
|
||||||
|
//if there's arguments
|
||||||
|
if (!match(parser, TOKEN_PAREN_RIGHT)) {
|
||||||
|
//read each argument
|
||||||
|
do {
|
||||||
|
//emit the node to the argument list (grow the node if needed)
|
||||||
|
if (arguments->fnCollection.capacity < arguments->fnCollection.count + 1) {
|
||||||
|
int oldCapacity = arguments->fnCollection.capacity;
|
||||||
|
|
||||||
|
arguments->fnCollection.capacity = GROW_CAPACITY(oldCapacity);
|
||||||
|
arguments->fnCollection.nodes = GROW_ARRAY(Node, arguments->fnCollection.nodes, oldCapacity, arguments->fnCollection.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* node = NULL;
|
||||||
|
parsePrecedence(parser, &node, PREC_TERNARY);
|
||||||
|
arguments->fnCollection.nodes[arguments->fnCollection.count++] = *node;
|
||||||
|
} while(match(parser, TOKEN_COMMA));
|
||||||
|
|
||||||
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of argument list");
|
||||||
|
}
|
||||||
|
|
||||||
|
//emit the call
|
||||||
|
emitFnCall(nodeHandle, arguments);
|
||||||
|
|
||||||
|
return OP_FN_CALL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error(parser, parser->previous, "Unexpected token passed to function call precedence rule");
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
ParseRule parseRules[] = { //must match the token types
|
ParseRule parseRules[] = { //must match the token types
|
||||||
//types
|
//types
|
||||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
||||||
@@ -685,7 +730,7 @@ ParseRule parseRules[] = { //must match the token types
|
|||||||
{NULL, binary, PREC_ASSIGNMENT},// TOKEN_ASSIGN,
|
{NULL, binary, PREC_ASSIGNMENT},// TOKEN_ASSIGN,
|
||||||
|
|
||||||
//logical operators
|
//logical operators
|
||||||
{grouping, NULL, PREC_CALL},// TOKEN_PAREN_LEFT,
|
{grouping, fnCall, PREC_CALL},// TOKEN_PAREN_LEFT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT,
|
{NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT,
|
||||||
{compound, NULL, PREC_CALL},// TOKEN_BRACKET_LEFT,
|
{compound, NULL, PREC_CALL},// TOKEN_BRACKET_LEFT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACKET_RIGHT,
|
{NULL, NULL, PREC_NONE},// TOKEN_BRACKET_RIGHT,
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ void runSource(char* source) {
|
|||||||
// for (size_t i = 0; i < size; i++) {
|
// for (size_t i = 0; i < size; i++) {
|
||||||
// printf("%d, ", tb[i]);
|
// printf("%d, ", tb[i]);
|
||||||
// }
|
// }
|
||||||
|
// printf("\n");
|
||||||
|
|
||||||
runBinary(tb, size);
|
runBinary(tb, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,12 @@ static bool checkType(Literal typeLiteral, Literal value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: function type checking
|
if (IS_FUNCTION(value)) {
|
||||||
|
//check value's type
|
||||||
|
if (AS_TYPE(typeLiteral).typeOf != LITERAL_FUNCTION) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_TYPE && !IS_TYPE(value)) {
|
if (AS_TYPE(typeLiteral).typeOf == LITERAL_TYPE && !IS_TYPE(value)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -108,7 +113,7 @@ Scope* pushScope(Scope* ancestor) {
|
|||||||
|
|
||||||
//tick up all scope reference counts
|
//tick up all scope reference counts
|
||||||
scope->references = 0;
|
scope->references = 0;
|
||||||
for (Scope* ptr = scope; ptr; ptr = ptr->ancestor) {
|
for (Scope* ptr = scope; ptr != NULL; ptr = ptr->ancestor) {
|
||||||
ptr->references++;
|
ptr->references++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user