Function calls, with args and single returns are working

This commit is contained in:
2022-08-26 01:48:26 +01:00
parent 041fe99e01
commit a4f1e048e9
11 changed files with 316 additions and 83 deletions

View File

@@ -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";

View File

@@ -28,4 +28,7 @@ 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)))

View File

@@ -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,13 +39,22 @@ 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
} }
//BUGFIX: check if exactly this literal array exists if (!skipDuplicationOptimisation) {
int index = findLiteralIndex(literalCache, literal); //BUGFIX: check if exactly this literal array exists
if (index < 0) { int index = findLiteralIndex(literalCache, literal);
index = pushLiteralArray(literalCache, literal); if (index < 0) {
} index = pushLiteralArray(literalCache, 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) {
@@ -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,21 +384,41 @@ 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);
//push the node opcode to the bytecode compiler->bytecode[compiler->count] = (unsigned short)index; //2 bytes
if (index >= 256) { compiler->count += sizeof(unsigned short);
//push a "long" index }
compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte break;
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)index; //2 bytes
compiler->count += sizeof(unsigned short); case NODE_FN_CALL: {
} //NOTE: assume the function definition/name is above us
else {
//push the index for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter
compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte //write each argument to the bytecode
compiler->bytecode[compiler->count++] = (unsigned char)index; //1 byte 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
if (argumentsIndex >= 256) {
//push a "long" index
compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)argumentsIndex; //2 bytes
compiler->count += sizeof(unsigned short);
}
else {
//push the index
compiler->bytecode[compiler->count++] = OP_LITERAL; //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;
@@ -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);

View File

@@ -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) {

View File

@@ -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 }})

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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,

View File

@@ -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);
} }

View File

@@ -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++;
} }