Skip to content

Commit

Permalink
Merge pull request #2 from giancarlopro/closure
Browse files Browse the repository at this point in the history
fix: closure data capture
  • Loading branch information
giancarlopro authored Sep 24, 2023
2 parents 936d507 + 37e6dc6 commit 0cd29c8
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 73 deletions.
1 change: 1 addition & 0 deletions src/error.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ void runtime_error(const char *message, ...) {
va_start(args, message);
fprintf(stderr, "Runtime error: ");
vfprintf(stderr, message, args);
fprintf(stderr, "\n");
exit(1);
}
88 changes: 39 additions & 49 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ result_t *print(term_t *root) {
printf_c(", ");
print(tuple->second);
printf_c(")");
} else if (match(res->type, "Function")) {
printf_c("<#closure>");
} else {
runtime_error("Print for kind %s not implemented", res->type);
}
Expand Down Expand Up @@ -276,16 +278,6 @@ void print_stack_variables() {
variables = variables->next;
}
}

if (stack->functions != NULL) {
term_map_t *functions = stack->functions;

while (functions != NULL) {
printf("[%d] Function -> %s\n", stack_size, functions->key);

functions = functions->next;
}
}
}

void add_stack() {
Expand All @@ -304,36 +296,16 @@ void push_variable(const char *key, result_t *value) {
result_map_add(stack->variables, make_result_map_t(key, value));
}

void push_function(const char *key, term_t *value) {
if (stack == NULL) {
stack = make_stack_t();
}

stack_t *root = stack;

while (root->parent != NULL) {
root = root->parent;
}

root->functions =
term_map_add(root->functions, make_term_map_t(key, value));
void replace_variable(const char *key, result_t *value) {
stack->variables =
result_map_replace(stack->variables, make_result_map_t(key, value));
}

void clean() {
free_stack_t(stack);
// free_stack_t(stack);
stack = NULL;
}

function_t *lookup_function(const char *name) {
stack_t *root = stack;

while (root->parent != NULL) {
root = root->parent;
}

return (function_t *)lookup_term(root->functions, name);
}

result_t *lookup_variable(const char *name) {
stack_t *root = stack;
result_t *result = NULL;
Expand All @@ -357,7 +329,10 @@ result_t *eval(term_t *root) {
}

if (match(root->kind, "Print")) {
return print((term_t *)root->value);
result_t *result = print((term_t *)root->value);
printf_c("\n");

return result;
} else if (match(root->kind, "Str") || match(root->kind, "Int") ||
match(root->kind, "Bool")) {
return make_result_t(root->value, root->kind);
Expand Down Expand Up @@ -403,13 +378,8 @@ result_t *eval(term_t *root) {
} else if (match(root->kind, "Let")) {
let_t *let = (let_t *)root;

if (match(let->value->kind, "Function")) {
push_function(let->name->text, let->value);
} else {
result_t *result = eval(let->value);

push_variable(let->name->text, result);
}
result_t *result = eval(let->value);
push_variable(let->name->text, result);

if (let->next != NULL) {
return eval(let->next);
Expand All @@ -427,19 +397,23 @@ result_t *eval(term_t *root) {

return result;
} else if (match(root->kind, "Function")) {
return make_result_t(NULL, "Void");
function_t *f = (function_t *)root;

f->closure_stack = stack_copy(stack);

return make_result_t((void *)root, "Function");
} else if (match(root->kind, "Call")) {
call_t *call = (call_t *)root;
function_t *function = NULL;

if (match(call->callee->kind, "Var")) {
function = lookup_function(((var_t *)call->callee)->text);
}
result_t *var = eval(call->callee);

if (function == NULL) {
runtime_error("Unknown function %s", ((var_t *)call->callee)->text);
if (var != NULL && !match(var->type, "Function")) {
runtime_error("Cannot call %s", var->type);
}

function = (function_t *)var->value;

if (call->arguments != NULL && function->parameters != NULL &&
len(call->arguments) != len(function->parameters)) {
runtime_error("Wrong number of arguments");
Expand Down Expand Up @@ -467,9 +441,25 @@ result_t *eval(term_t *root) {

add_stack();

if (function->closure_stack != NULL) {
stack_t *root = function->closure_stack;

do {
result_map_t *variables = root->variables;

while (variables != NULL) {
push_variable(variables->key, variables->value);

variables = variables->next;
}

root = root->parent;
} while (root != NULL);
}

if (call->arguments != NULL) {
for (int i = 0; i < call->arguments->length; i++) {
push_variable(variables[i]->key, variables[i]->value);
replace_variable(variables[i]->key, variables[i]->value);
}
}

Expand Down
20 changes: 11 additions & 9 deletions src/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,6 @@ typedef struct {
const char *text;
} var_t;

typedef struct {
const char *kind;
array_t *parameters;
term_t *value;
} function_t;

typedef struct {
const char *kind;
term_t *callee;
Expand All @@ -125,7 +119,6 @@ if_t *make_if_t(term_t *condition, term_t *then, term_t *otherwise);
parameter_t *make_parameter_t(const char *text);
let_t *make_let_t(parameter_t *name, term_t *value, term_t *next);
var_t *make_var_t(const char *text);
function_t *make_function_t(array_t *parameters, term_t *value);
call_t *make_call_t(term_t *callee, array_t *arguments);
variable_t *make_variable_t(const char *key, result_t *value);
array_t *make_array_t(size_t length, void **values);
Expand All @@ -144,7 +137,6 @@ void free_if_t(if_t *value);
void free_parameter_t(parameter_t *parameter);
void free_let_t(let_t *let);
void free_var_t(var_t *var);
void free_function_t(function_t *function);
void free_call_t(call_t *call);
void clean();
void free_variable_t(variable_t *variable);
Expand All @@ -171,7 +163,6 @@ typedef struct stack_t {
struct stack_t *next;
struct stack_t *parent;
result_map_t *variables;
term_map_t *functions;
} stack_t;

result_map_t *make_result_map_t(const char *key, result_t *value);
Expand All @@ -181,6 +172,7 @@ void free_term_map_t(term_map_t *term_map);
stack_t *make_stack_t();
void free_stack_t(stack_t *stack);
int stack_len(stack_t *stack);
stack_t *stack_copy(stack_t *stack);
term_t *lookup_term(term_map_t *map, const char *key);
result_t *lookup_result(result_map_t *map, const char *key);
stack_t *stack_add(stack_t *stack, stack_t *value);
Expand All @@ -190,3 +182,13 @@ term_map_t *term_map_add(term_map_t *map, term_map_t *value);

void printf_c(const char *fmt, ...);
void set_interpreter_stdout(FILE *stdout);

typedef struct {
const char *kind;
array_t *parameters;
term_t *value;
stack_t *closure_stack;
} function_t;

function_t *make_function_t(array_t *parameters, term_t *value);
void free_function_t(function_t *function);
8 changes: 7 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
int main(int argc, char **argv) {
char *filename = argv[1];

json_object *root = json_object_from_file(filename);
json_object *root = NULL;

if (match(filename, "-")) {
root = json_object_from_fd(0);
} else {
root = json_object_from_file(filename);
}

if (!root) return 1;

Expand Down
23 changes: 14 additions & 9 deletions src/stack.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ stack_t *make_stack_t() {

stack->parent = NULL;
stack->variables = NULL;
stack->functions = NULL;

return stack;
}
Expand All @@ -60,7 +59,6 @@ void free_stack_t(stack_t *stack) {
}

free_result_map_t(stack->variables);
free_term_map_t(stack->functions);
free(stack);
}

Expand Down Expand Up @@ -120,7 +118,6 @@ result_map_t *result_map_replace(result_map_t *map, result_map_t *value) {

while (current != NULL) {
if (match(current->key, value->key)) {
free_result_t(current->value);
current->value = value->value;

return map;
Expand Down Expand Up @@ -153,9 +150,17 @@ term_map_t *term_map_add(term_map_t *map, term_map_t *value) {
}

int stack_len(stack_t *stack) {
if (stack == NULL) {
return 0;
} else {
return 1 + stack_len(stack->next);
}
}
if (stack == NULL) return 0;
if (stack->parent == NULL) return 1;

return 1 + stack_len(stack->parent);
}

stack_t *stack_copy(stack_t *stack) {
stack_t *copy = make_stack_t();

copy->parent = stack->parent;
copy->variables = stack->variables;

return copy;
}
2 changes: 1 addition & 1 deletion tests/minunit.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
} while (0)
#define mu_run_test(test) \
do { \
clean(); \
char *message = test(); \
tests_run++; \
if (message) return message; \
clean(); \
} while (0)
extern int tests_run;
7 changes: 3 additions & 4 deletions tests/test_interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,13 +450,12 @@ static char* test_parse_print_expression() {

term_t* term = parse_expression(root);

mu_assert("error, term->kind != \"Print\"",
strcmp(term->kind, "Print") == 0);
mu_assert("error, term->kind != \"Print\"", match(term->kind, "Print"));

str_t* str = term->value;

mu_assert("error, str->kind != \"Str\"", strcmp(str->kind, "Str") == 0);
mu_assert("error, str->value != \"data\"", strcmp(str->value, "data") == 0);
mu_assert("error, str->kind != \"Str\"", match(str->kind, "Str"));
mu_assert("error, str->value != \"data\"", match(str->value, "data"));
}

static char* test_parse_int() {
Expand Down

0 comments on commit 0cd29c8

Please sign in to comment.