mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Functions are successfully called, read more
Return keyword is not yet implemented. Functions are untested. See #163
This commit is contained in:
@@ -213,6 +213,16 @@ void Toy_private_emitAstFunctionDeclaration(Toy_Bucket** bucketHandle, Toy_Ast**
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstFunctionInvokation(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* args) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_FN_INVOKE;
|
||||
tmp->fnInvoke.function = (*astHandle);
|
||||
tmp->fnInvoke.args = args;
|
||||
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ typedef enum Toy_AstType {
|
||||
TOY_AST_VAR_ACCESS,
|
||||
|
||||
TOY_AST_FN_DECLARE,
|
||||
TOY_AST_FN_INVOKE,
|
||||
|
||||
TOY_AST_PASS,
|
||||
TOY_AST_ERROR,
|
||||
@@ -200,6 +201,12 @@ typedef struct Toy_AstFnDeclare {
|
||||
Toy_Ast* body;
|
||||
} Toy_AstFnDeclare;
|
||||
|
||||
typedef struct Toy_AstFnInvoke {
|
||||
Toy_AstType type;
|
||||
Toy_Ast* function;
|
||||
Toy_Ast* args;
|
||||
} Toy_AstFnInvoke;
|
||||
|
||||
typedef struct Toy_AstPass {
|
||||
Toy_AstType type;
|
||||
} Toy_AstPass;
|
||||
@@ -233,6 +240,7 @@ union Toy_Ast { //see 'test_ast.c' for bitness tests
|
||||
Toy_AstVarAssign varAssign;
|
||||
Toy_AstVarAccess varAccess;
|
||||
Toy_AstFnDeclare fnDeclare;
|
||||
Toy_AstFnInvoke fnInvoke;
|
||||
Toy_AstPass pass;
|
||||
Toy_AstError error;
|
||||
Toy_AstEnd end;
|
||||
@@ -262,8 +270,8 @@ void Toy_private_emitAstVariableAssignment(Toy_Bucket** bucketHandle, Toy_Ast**
|
||||
void Toy_private_emitAstVariableAccess(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
|
||||
void Toy_private_emitAstFunctionDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_Ast* params, Toy_Ast* body);
|
||||
void Toy_private_emitAstFunctionInvokation(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* params);
|
||||
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ typedef enum Toy_FunctionType {
|
||||
TOY_FUNCTION_NATIVE,
|
||||
} Toy_FunctionType;
|
||||
|
||||
typedef union Toy_FunctionModule {
|
||||
typedef struct Toy_FunctionModule {
|
||||
Toy_FunctionType type;
|
||||
Toy_Module module;
|
||||
} Toy_FunctionModule;
|
||||
|
||||
typedef union Toy_FunctionNative {
|
||||
typedef struct Toy_FunctionNative {
|
||||
Toy_FunctionType type;
|
||||
void* native; //TODO: replace with the native function pointer
|
||||
} Toy_FunctionNative;
|
||||
|
||||
@@ -215,6 +215,7 @@ static unsigned int emitParameters(Toy_ModuleCompiler* mb, Toy_Ast* ast) {
|
||||
|
||||
//emit to the param index
|
||||
EMIT_INT(&mb, param, dataAddr);
|
||||
EMIT_INT(&mb, param, (unsigned int)(TOY_VALUE_AS_STRING(ast->value.value)->name.varType)); //don't forget this bit
|
||||
|
||||
//this returns the number of written parameters
|
||||
return 1;
|
||||
@@ -1041,6 +1042,32 @@ static unsigned int writeInstructionFnDeclare(Toy_ModuleCompiler** mb, Toy_AstFn
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int writeInstructionFnInvoke(Toy_ModuleCompiler** mb, Toy_AstFnInvoke ast) {
|
||||
unsigned int argCount = writeModuleCompilerCode(mb, ast.args);
|
||||
|
||||
if (argCount > 255) {
|
||||
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid function invokation with %d functions arguments (maximum 255)\n" TOY_CC_RESET, (int)argCount);
|
||||
(*mb)->panic = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int fnCount = writeModuleCompilerCode(mb, ast.function);
|
||||
|
||||
if (fnCount != 1) {
|
||||
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid function invokation with %d function AST nodes (expected 1)\n" TOY_CC_RESET, (int)fnCount);
|
||||
(*mb)->panic = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//call the function
|
||||
EMIT_BYTE(mb, code, TOY_OPCODE_INVOKE);
|
||||
EMIT_BYTE(mb, code, TOY_VALUE_FUNCTION);
|
||||
EMIT_BYTE(mb, code, (unsigned char)argCount);
|
||||
EMIT_BYTE(mb, code, 0); //IDK how many returns
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int writeModuleCompilerCode(Toy_ModuleCompiler** mb, Toy_Ast* ast) {
|
||||
if (ast == NULL) {
|
||||
return 0;
|
||||
@@ -1151,6 +1178,10 @@ static unsigned int writeModuleCompilerCode(Toy_ModuleCompiler** mb, Toy_Ast* as
|
||||
result += writeInstructionFnDeclare(mb, ast->fnDeclare);
|
||||
break;
|
||||
|
||||
case TOY_AST_FN_INVOKE:
|
||||
result += writeInstructionFnInvoke(mb, ast->fnInvoke);
|
||||
break;
|
||||
|
||||
case TOY_AST_PASS:
|
||||
//NO-OP
|
||||
break;
|
||||
|
||||
@@ -10,6 +10,7 @@ typedef enum Toy_OpcodeType {
|
||||
TOY_OPCODE_ASSIGN,
|
||||
TOY_OPCODE_ASSIGN_COMPOUND, //assign to a compound's internals
|
||||
TOY_OPCODE_ACCESS,
|
||||
TOY_OPCODE_INVOKE, //for calling functions
|
||||
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
||||
TOY_OPCODE_ELIMINATE, //remove the top of the stack
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast*
|
||||
static Toy_AstFlag compound(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||
static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||
static Toy_AstFlag unaryPostfix(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||
static Toy_AstFlag invoke(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||
|
||||
//precedence definitions
|
||||
static ParsingTuple parsingRulesetTable[] = {
|
||||
@@ -181,8 +182,8 @@ static ParsingTuple parsingRulesetTable[] = {
|
||||
{PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_MULTIPLY_ASSIGN,
|
||||
{PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_DIVIDE_ASSIGN,
|
||||
{PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_MODULO_ASSIGN,
|
||||
{PREC_CALL,unary,unaryPostfix},// TOY_TOKEN_OPERATOR_INCREMENT,
|
||||
{PREC_CALL,unary,unaryPostfix},// TOY_TOKEN_OPERATOR_DECREMENT,
|
||||
{PREC_UNARY,unary,unaryPostfix},// TOY_TOKEN_OPERATOR_INCREMENT,
|
||||
{PREC_UNARY,unary,unaryPostfix},// TOY_TOKEN_OPERATOR_DECREMENT,
|
||||
{PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_ASSIGN,
|
||||
|
||||
//comparator operators
|
||||
@@ -194,7 +195,7 @@ static ParsingTuple parsingRulesetTable[] = {
|
||||
{PREC_COMPARISON,NULL,binary},// TOY_TOKEN_OPERATOR_COMPARE_GREATER_EQUAL,
|
||||
|
||||
//structural operators
|
||||
{PREC_GROUP,group,NULL},// TOY_TOKEN_OPERATOR_PAREN_LEFT,
|
||||
{PREC_CALL,group,invoke},// TOY_TOKEN_OPERATOR_PAREN_LEFT,
|
||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_PAREN_RIGHT,
|
||||
{PREC_GROUP,compound,aggregate},// TOY_TOKEN_OPERATOR_BRACKET_LEFT,
|
||||
{PREC_NONE,compound,aggregate},// TOY_TOKEN_OPERATOR_BRACKET_RIGHT,
|
||||
@@ -212,7 +213,7 @@ static ParsingTuple parsingRulesetTable[] = {
|
||||
{PREC_GROUP,NULL,aggregate},// TOY_TOKEN_OPERATOR_COMMA, // ,
|
||||
|
||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_DOT, // .
|
||||
{PREC_CALL,NULL,binary},// TOY_TOKEN_OPERATOR_CONCAT, // ..
|
||||
{PREC_UNARY,NULL,binary},// TOY_TOKEN_OPERATOR_CONCAT, // ..
|
||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_REST, // ...
|
||||
|
||||
//unused operators
|
||||
@@ -557,7 +558,7 @@ static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
|
||||
}
|
||||
|
||||
case TOY_TOKEN_OPERATOR_CONCAT: {
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_CALL + 1);
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_UNARY + 1);
|
||||
return TOY_AST_FLAG_CONCAT;
|
||||
}
|
||||
|
||||
@@ -708,6 +709,31 @@ static Toy_AstFlag unaryPostfix(Toy_Bucket** bucketHandle, Toy_Parser* parser, T
|
||||
}
|
||||
}
|
||||
|
||||
static Toy_AstFlag invoke(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||
//infix must advance
|
||||
advance(parser);
|
||||
|
||||
//read in args
|
||||
Toy_Ast* args = NULL;
|
||||
unsigned int paramIterations = 0;
|
||||
|
||||
while (parser->current.type != TOY_TOKEN_OPERATOR_PAREN_RIGHT && (paramIterations++ == 0 || match(parser, TOY_TOKEN_OPERATOR_COMMA))) {
|
||||
//get the next arg
|
||||
Toy_Ast* ast = NULL;
|
||||
parsePrecedence(bucketHandle, parser, &ast, PREC_GROUP);
|
||||
|
||||
//add to the args aggregate (is added backwards, because weird)
|
||||
Toy_private_emitAstAggregate(bucketHandle, &args, TOY_AST_FLAG_COLLECTION, ast);
|
||||
}
|
||||
|
||||
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' at the end of argument list");
|
||||
|
||||
//finally, emit the call as an Ast
|
||||
Toy_private_emitAstFunctionInvokation(bucketHandle, rootHandle, args);
|
||||
|
||||
return TOY_AST_FLAG_NONE;
|
||||
}
|
||||
|
||||
//grammar rules
|
||||
static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule) {
|
||||
//'step over' the token to parse
|
||||
@@ -741,7 +767,7 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
|
||||
return;
|
||||
}
|
||||
|
||||
Toy_Ast* ptr = NULL;
|
||||
Toy_Ast* ptr = (*rootHandle); //NOTE: infix functions will need to be careful not to damage the pre-existing tree, if they can avoid it
|
||||
Toy_AstFlag flag = infix(bucketHandle, parser, &ptr);
|
||||
|
||||
//finished
|
||||
|
||||
@@ -139,14 +139,6 @@ void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
||||
return;
|
||||
}
|
||||
|
||||
//constness check
|
||||
if (Toy_getNameStringVarConstant(key) && value.type == TOY_VALUE_NULL) {
|
||||
char buffer[key->info.length + 256];
|
||||
sprintf(buffer, "Can't declare %s as const with value 'null'", key->name.data);
|
||||
Toy_error(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
Toy_insertTable(&scope->table, TOY_VALUE_FROM_STRING(Toy_copyString(key)), value);
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) {
|
||||
}
|
||||
|
||||
case TOY_VALUE_FUNCTION:
|
||||
return false; //URGENT: check this
|
||||
return false; //URGENT: test this
|
||||
|
||||
case TOY_VALUE_OPAQUE:
|
||||
case TOY_VALUE_ANY:
|
||||
@@ -432,10 +432,10 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
||||
|
||||
switch(value.type) {
|
||||
case TOY_VALUE_NULL:
|
||||
return Toy_createString(bucketHandle, "null");
|
||||
return Toy_createString(bucketHandle, "<null>");
|
||||
|
||||
case TOY_VALUE_BOOLEAN:
|
||||
return Toy_createString(bucketHandle, value.as.boolean ? "true" : "false");
|
||||
return Toy_createString(bucketHandle, value.as.boolean ? "<true>" : "<false>");
|
||||
|
||||
case TOY_VALUE_INTEGER: {
|
||||
char buffer[16];
|
||||
@@ -622,7 +622,9 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
||||
return string;
|
||||
}
|
||||
|
||||
case TOY_VALUE_FUNCTION: //URGENT: check this
|
||||
case TOY_VALUE_FUNCTION:
|
||||
//dummy
|
||||
return Toy_createString(bucketHandle, "<fn>");
|
||||
|
||||
case TOY_VALUE_OPAQUE:
|
||||
case TOY_VALUE_ANY:
|
||||
|
||||
@@ -373,6 +373,79 @@ static void processAccess(Toy_VM* vm) {
|
||||
Toy_freeValue(name);
|
||||
}
|
||||
|
||||
static void processInvoke(Toy_VM* vm) {
|
||||
Toy_ValueType valueType = READ_BYTE(vm); //unused for now
|
||||
unsigned int argCount = (unsigned int)READ_BYTE(vm);
|
||||
fixAlignment(vm);
|
||||
|
||||
//check for invoking bad values
|
||||
if (valueType != TOY_VALUE_FUNCTION) {
|
||||
Toy_error("Unrecognized invoke on a non-function value");
|
||||
return;
|
||||
}
|
||||
|
||||
//function to call
|
||||
Toy_Value value = Toy_popStack(&vm->stack);
|
||||
if (TOY_VALUE_IS_FUNCTION(value) != true) {
|
||||
Toy_error("Can't call a non-function value");
|
||||
return;
|
||||
}
|
||||
|
||||
//process based on the function type
|
||||
Toy_Function* fn = TOY_VALUE_AS_FUNCTION(value);
|
||||
|
||||
switch(fn->type) {
|
||||
case TOY_FUNCTION_MODULE: {
|
||||
Toy_Module module = fn->module.module;
|
||||
|
||||
//NOTE: counts within the modules actually specify size in memory, so the argCount is multiplied by 8 for the 8 bytes used in the params table
|
||||
|
||||
//check args count
|
||||
if (argCount * 8 != module.paramCount) {
|
||||
Toy_error("Incorrect number of parameters specified for function call");
|
||||
break;
|
||||
}
|
||||
|
||||
if (argCount > vm->stack->count) {
|
||||
Toy_error("Incorrect number of parameters on the stack for function call");
|
||||
break;
|
||||
}
|
||||
|
||||
//spin up a new sub-vm
|
||||
Toy_VM subVM;
|
||||
Toy_initVM(&subVM);
|
||||
Toy_bindVM(&subVM, &module, false);
|
||||
|
||||
//inject params, backwards from the stack
|
||||
for (unsigned int i = argCount; i > 0; i--) {
|
||||
Toy_Value argValue = Toy_popStack(&vm->stack);
|
||||
|
||||
//paramAddr is relative to the data section, and is followed by the param type
|
||||
unsigned int paramAddr = ((unsigned int*)(module.code + module.paramAddr))[(i-1)*2];
|
||||
Toy_ValueType paramType = (Toy_ValueType)(((unsigned int*)(module.code + module.paramAddr))[(i-1)*2 + 1]);
|
||||
|
||||
//c-string of the param's name
|
||||
const char* cstr = ((char*)(module.code + module.dataAddr)) + paramAddr;
|
||||
|
||||
//as a name string
|
||||
Toy_String* name = Toy_createNameStringLength(&subVM.literalBucket, cstr, strlen(cstr), paramType, true);
|
||||
|
||||
Toy_declareScope(subVM.scope, name, argValue);
|
||||
}
|
||||
|
||||
//run and cleanup
|
||||
Toy_runVM(&subVM);
|
||||
Toy_freeVM(&subVM);
|
||||
}
|
||||
break;
|
||||
|
||||
case TOY_FUNCTION_NATIVE:
|
||||
default:
|
||||
Toy_error("Can't call an unknown function type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void processDuplicate(Toy_VM* vm) {
|
||||
Toy_Value value = Toy_copyValue(Toy_peekStack(&vm->stack));
|
||||
Toy_pushStack(&vm->stack, value);
|
||||
@@ -882,6 +955,10 @@ static void process(Toy_VM* vm) {
|
||||
processAccess(vm);
|
||||
break;
|
||||
|
||||
case TOY_OPCODE_INVOKE:
|
||||
processInvoke(vm);
|
||||
break;
|
||||
|
||||
case TOY_OPCODE_DUPLICATE:
|
||||
processDuplicate(vm);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user