forked from ground/ground-old
Closures in Ground
This commit is contained in:
@@ -208,6 +208,10 @@ GroundProgram groundParseFile(const char* code);
|
|||||||
GroundStruct groundCreateStruct();
|
GroundStruct groundCreateStruct();
|
||||||
void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field);
|
void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field);
|
||||||
|
|
||||||
|
// Run function returned by Ground code
|
||||||
|
// Use argc to set count of args, accepts that amount of GroundValue's after
|
||||||
|
GroundValue groundRunFunction(GroundFunction* function, size_t argc, ...);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -83,9 +83,19 @@ GroundValue groundCreateValue(GroundValueType type, ...) {
|
|||||||
return createNoneGroundValue();
|
return createNoneGroundValue();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ERROR:
|
|
||||||
case CUSTOM: {
|
case CUSTOM: {
|
||||||
|
// CUSTOM values are created from structs
|
||||||
|
GroundValue gv;
|
||||||
|
GroundStruct* gstruct = va_arg(args, GroundStruct*);
|
||||||
|
gv.type = CUSTOM;
|
||||||
|
gv.data.customVal = malloc(sizeof(GroundObject));
|
||||||
|
*gv.data.customVal = createObject(*gstruct);
|
||||||
|
gv.customType = gstruct;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ERROR: {
|
||||||
// FIXME
|
// FIXME
|
||||||
|
return createNoneGroundValue();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,3 +138,25 @@ void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field
|
|||||||
char* groundCompileProgram(GroundProgram* program) {
|
char* groundCompileProgram(GroundProgram* program) {
|
||||||
return compileGroundProgram(program);
|
return compileGroundProgram(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundValue groundRunFunction(GroundFunction* function, size_t argc, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, argc);
|
||||||
|
|
||||||
|
GroundScope callScope = copyGroundScope(&function->closure);
|
||||||
|
|
||||||
|
if (argc != function->argSize) {
|
||||||
|
return createErrorGroundValue(createGroundError("Too few or too many arguments for function", "callError", NULL, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < argc; i++) {
|
||||||
|
GroundValue gv = va_arg(args, GroundValue);
|
||||||
|
if (checkFnTypes(&gv, &function->args[i]) == false) {
|
||||||
|
return createErrorGroundValue(createGroundError("Mismatched argument type", "callError", NULL, NULL));
|
||||||
|
}
|
||||||
|
addVariable(callScope.variables, function->args[i].name, gv);
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return interpretGroundProgram(&function->program, &callScope);
|
||||||
|
}
|
||||||
|
|||||||
@@ -449,6 +449,7 @@ GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffs
|
|||||||
|
|
||||||
GroundFunction* function = parseFunction(&gp, errorOffset);
|
GroundFunction* function = parseFunction(&gp, errorOffset);
|
||||||
function->startLine = i;
|
function->startLine = i;
|
||||||
|
function->closure = copyGroundScope(scope);
|
||||||
GroundValue gv = createFunctionGroundValue(function);
|
GroundValue gv = createFunctionGroundValue(function);
|
||||||
addFieldToStruct(&gstruct, name, gv);
|
addFieldToStruct(&gstruct, name, gv);
|
||||||
break;
|
break;
|
||||||
@@ -484,42 +485,6 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
|||||||
if (in->instructions[i].type == CREATELABEL) {
|
if (in->instructions[i].type == CREATELABEL) {
|
||||||
addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i);
|
addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i);
|
||||||
}
|
}
|
||||||
if (in->instructions[i].type == FUN) {
|
|
||||||
if (in->instructions[i].args.length < 1) {
|
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i);
|
|
||||||
}
|
|
||||||
if (in->instructions[i].args.args[0].type != FNREF) {
|
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", &in->instructions[i], i);
|
|
||||||
}
|
|
||||||
char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1);
|
|
||||||
strcpy(name, in->instructions[i].args.args[0].value.refName);
|
|
||||||
|
|
||||||
size_t counter = 1;
|
|
||||||
GroundProgram gp = createGroundProgram();
|
|
||||||
addInstructionToProgram(&gp, in->instructions[i]);
|
|
||||||
size_t errorOffset = i;
|
|
||||||
i++;
|
|
||||||
while (counter > 0) {
|
|
||||||
if (i >= in->size) {
|
|
||||||
runtimeError(PREMATURE_EOF, "Reached end of scope before function definition ended", &in->instructions[i - 1], i - 1);
|
|
||||||
}
|
|
||||||
if (in->instructions[i].type == FUN) {
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
if (in->instructions[i].type == ENDFUN) {
|
|
||||||
counter--;
|
|
||||||
}
|
|
||||||
addInstructionToProgram(&gp, in->instructions[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
i--;
|
|
||||||
|
|
||||||
GroundFunction* function = parseFunction(&gp, errorOffset);
|
|
||||||
function->startLine = i;
|
|
||||||
GroundValue gv = createFunctionGroundValue(function);
|
|
||||||
|
|
||||||
addVariable(scope.variables, name, gv);
|
|
||||||
}
|
|
||||||
if (in->instructions[i].type == STRUCT) {
|
if (in->instructions[i].type == STRUCT) {
|
||||||
if (in->instructions[i].args.length < 1) {
|
if (in->instructions[i].args.length < 1) {
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", &in->instructions[i], i);
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", &in->instructions[i], i);
|
||||||
@@ -562,6 +527,44 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < in->size; i++) {
|
for (size_t i = 0; i < in->size; i++) {
|
||||||
|
if (in->instructions[i].type == FUN) {
|
||||||
|
if (in->instructions[i].args.length < 1) {
|
||||||
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.args[0].type != FNREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1);
|
||||||
|
strcpy(name, in->instructions[i].args.args[0].value.refName);
|
||||||
|
|
||||||
|
size_t counter = 1;
|
||||||
|
GroundProgram gp = createGroundProgram();
|
||||||
|
addInstructionToProgram(&gp, in->instructions[i]);
|
||||||
|
size_t errorOffset = i;
|
||||||
|
i++;
|
||||||
|
while (counter > 0) {
|
||||||
|
if (i >= in->size) {
|
||||||
|
runtimeError(PREMATURE_EOF, "Reached end of scope before function definition ended", &in->instructions[i - 1], i - 1);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == FUN) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == ENDFUN) {
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
addInstructionToProgram(&gp, in->instructions[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
|
||||||
|
GroundFunction* function = parseFunction(&gp, errorOffset);
|
||||||
|
function->startLine = i;
|
||||||
|
function->closure = copyGroundScope(inScope);
|
||||||
|
GroundValue gv = createFunctionGroundValue(function);
|
||||||
|
|
||||||
|
addVariable(scope.variables, name, gv);
|
||||||
|
}
|
||||||
|
/*
|
||||||
if (in->instructions[i].type == FUN) {
|
if (in->instructions[i].type == FUN) {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
@@ -577,6 +580,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (in->instructions[i].type == STRUCT) {
|
if (in->instructions[i].type == STRUCT) {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
@@ -1789,11 +1793,6 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
if (in->args.args[in->args.length - 1].type != DIRREF) {
|
if (in->args.args[in->args.length - 1].type != DIRREF) {
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef as the last arg", in, currentInstruction);
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef as the last arg", in, currentInstruction);
|
||||||
}
|
}
|
||||||
GroundVariable* variables = NULL;
|
|
||||||
GroundLabel* labels = NULL;
|
|
||||||
GroundScope newScope;
|
|
||||||
newScope.variables = &variables;
|
|
||||||
newScope.labels = &labels;
|
|
||||||
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
|
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
|
||||||
if (var == NULL) {
|
if (var == NULL) {
|
||||||
runtimeError(UNKNOWN_VARIABLE, "Function not found", in, currentInstruction);
|
runtimeError(UNKNOWN_VARIABLE, "Function not found", in, currentInstruction);
|
||||||
@@ -1841,6 +1840,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
}
|
}
|
||||||
free(argsList.values);
|
free(argsList.values);
|
||||||
} else {
|
} else {
|
||||||
|
GroundScope newScope = copyGroundScope(&function->closure);
|
||||||
for (size_t i = 0; i < function->argSize; i++) {
|
for (size_t i = 0; i < function->argSize; i++) {
|
||||||
if (in->args.args[i + 1].type != VALUE) {
|
if (in->args.args[i + 1].type != VALUE) {
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction);
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#ifndef INTERPRETER_H
|
#ifndef INTERPRETER_H
|
||||||
#define INTERPRETER_H
|
#define INTERPRETER_H
|
||||||
#define MAX_ID_LEN 64
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
@@ -14,24 +13,6 @@ typedef enum GroundDebugInstructionType {
|
|||||||
DUMP, INSPECT, EVAL, CONTINUE, EXIT, STEP, VIEW, HELP, UNKNOWN
|
DUMP, INSPECT, EVAL, CONTINUE, EXIT, STEP, VIEW, HELP, UNKNOWN
|
||||||
} GroundDebugInstructionType;
|
} GroundDebugInstructionType;
|
||||||
|
|
||||||
typedef struct GroundLabel {
|
|
||||||
char id[MAX_ID_LEN];
|
|
||||||
int lineNum;
|
|
||||||
UT_hash_handle hh;
|
|
||||||
} GroundLabel;
|
|
||||||
|
|
||||||
typedef struct GroundVariable {
|
|
||||||
char id[MAX_ID_LEN];
|
|
||||||
GroundValue value;
|
|
||||||
UT_hash_handle hh;
|
|
||||||
} GroundVariable;
|
|
||||||
|
|
||||||
typedef struct GroundScope {
|
|
||||||
GroundLabel** labels;
|
|
||||||
GroundVariable** variables;
|
|
||||||
bool isMainScope;
|
|
||||||
} GroundScope;
|
|
||||||
|
|
||||||
typedef struct GroundDebugInstruction {
|
typedef struct GroundDebugInstruction {
|
||||||
GroundDebugInstructionType type;
|
GroundDebugInstructionType type;
|
||||||
char* arg;
|
char* arg;
|
||||||
@@ -42,7 +23,6 @@ GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset);
|
|||||||
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
|
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
|
||||||
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
|
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
|
||||||
|
|
||||||
void addVariable(GroundVariable **head, const char *id, GroundValue data);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
21
src/types.c
21
src/types.c
@@ -709,3 +709,24 @@ bool checkTypes(GroundValue* left, GroundValue* right) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundScope copyGroundScope(GroundScope* scope) {
|
||||||
|
GroundScope newScope = {
|
||||||
|
.labels = malloc(sizeof(GroundLabel*)),
|
||||||
|
.variables = malloc(sizeof(GroundVariable*)),
|
||||||
|
.isMainScope = false
|
||||||
|
};
|
||||||
|
*newScope.variables = NULL;
|
||||||
|
*newScope.labels = NULL;
|
||||||
|
|
||||||
|
if (scope == NULL) {
|
||||||
|
printf("oh no scope is null\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundVariable *var, *tmp = NULL;
|
||||||
|
HASH_ITER(hh, *scope->variables, var, tmp) {
|
||||||
|
addVariable(newScope.variables, var->id, var->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newScope;
|
||||||
|
}
|
||||||
|
|||||||
26
src/types.h
26
src/types.h
@@ -8,6 +8,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "include/uthash.h"
|
#include "include/uthash.h"
|
||||||
|
|
||||||
|
#define MAX_ID_LEN 64
|
||||||
|
|
||||||
typedef enum GroundInstType {
|
typedef enum GroundInstType {
|
||||||
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, ITOC, CTOI, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, ERRORCMD
|
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, ITOC, CTOI, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, ERRORCMD
|
||||||
} GroundInstType;
|
} GroundInstType;
|
||||||
@@ -77,6 +79,24 @@ typedef struct GroundValue {
|
|||||||
} data;
|
} data;
|
||||||
} GroundValue;
|
} GroundValue;
|
||||||
|
|
||||||
|
typedef struct GroundLabel {
|
||||||
|
char id[MAX_ID_LEN];
|
||||||
|
int lineNum;
|
||||||
|
UT_hash_handle hh;
|
||||||
|
} GroundLabel;
|
||||||
|
|
||||||
|
typedef struct GroundVariable {
|
||||||
|
char id[MAX_ID_LEN];
|
||||||
|
GroundValue value;
|
||||||
|
UT_hash_handle hh;
|
||||||
|
} GroundVariable;
|
||||||
|
|
||||||
|
typedef struct GroundScope {
|
||||||
|
GroundLabel** labels;
|
||||||
|
GroundVariable** variables;
|
||||||
|
bool isMainScope;
|
||||||
|
} GroundScope;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Indicates status when accessing a list.
|
* Indicates status when accessing a list.
|
||||||
* Associated functions:
|
* Associated functions:
|
||||||
@@ -145,6 +165,7 @@ typedef struct GroundFunction {
|
|||||||
GroundProgram program;
|
GroundProgram program;
|
||||||
size_t startLine;
|
size_t startLine;
|
||||||
bool isNative;
|
bool isNative;
|
||||||
|
GroundScope closure;
|
||||||
NativeGroundFunction nativeFn;
|
NativeGroundFunction nativeFn;
|
||||||
} GroundFunction;
|
} GroundFunction;
|
||||||
|
|
||||||
@@ -284,5 +305,10 @@ bool checkFnTypes(GroundValue* left, GroundFunctionArgs* arg);
|
|||||||
// Compares types of two values.
|
// Compares types of two values.
|
||||||
bool checkTypes(GroundValue* left, GroundValue* right);
|
bool checkTypes(GroundValue* left, GroundValue* right);
|
||||||
|
|
||||||
|
// Adds variable to GroundScope
|
||||||
|
void addVariable(GroundVariable **head, const char *id, GroundValue data);
|
||||||
|
|
||||||
|
// Deep copies a GroundScope
|
||||||
|
GroundScope copyGroundScope(GroundScope* scope);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
27
tests/closure.grnd
Normal file
27
tests/closure.grnd
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
set &x 5
|
||||||
|
|
||||||
|
PAUSE
|
||||||
|
|
||||||
|
fun !dingle -function -int &a
|
||||||
|
|
||||||
|
PAUSE
|
||||||
|
|
||||||
|
fun !capture -int -int &b
|
||||||
|
|
||||||
|
PAUSE
|
||||||
|
|
||||||
|
add $a $b &tmp
|
||||||
|
add $tmp $x &tmp
|
||||||
|
return $tmp
|
||||||
|
endfun
|
||||||
|
|
||||||
|
return $capture
|
||||||
|
|
||||||
|
endfun
|
||||||
|
|
||||||
|
call !dingle 3 &result
|
||||||
|
|
||||||
|
PAUSE
|
||||||
|
|
||||||
|
call !result 5 &y
|
||||||
|
println $y
|
||||||
Reference in New Issue
Block a user