Rename 'state' to 'scope'
This commit is contained in:
@@ -17,7 +17,7 @@ lib_srcs = [
|
||||
"src/evaluate.c",
|
||||
"src/memory.c",
|
||||
"src/special.c",
|
||||
"src/state.c",
|
||||
"src/scope.c",
|
||||
"src/utility.c",
|
||||
"src/parse.c",
|
||||
]
|
||||
@@ -28,7 +28,7 @@ test_srcs = [
|
||||
"test/test_arena.c",
|
||||
"test/test_e2e.c",
|
||||
"test/test_parse.c",
|
||||
"test/test_state.c",
|
||||
"test/test_scope.c",
|
||||
"test/test_utility.c",
|
||||
]
|
||||
test_lib_srcs = ["third-party/unity/src/unity.c"]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "internal.h"
|
||||
#include "utility.h"
|
||||
#include "builtins.h"
|
||||
#include "state.h"
|
||||
#include "scope.h"
|
||||
#include "lisp.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_type, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_type, scope, arg) {
|
||||
switch (arg->type) {
|
||||
case UCL_TYPE_CELL:
|
||||
return ucl_symbol_create("list");
|
||||
@@ -33,7 +33,7 @@ LISP_FUNC_1(ucl_builtin_type, state, arg) {
|
||||
}
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_error, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_error, scope, arg) {
|
||||
if (arg->type != UCL_TYPE_STRING) {
|
||||
return ucl_error_create("Expected type string passed to 'error'");
|
||||
}
|
||||
@@ -41,42 +41,42 @@ LISP_FUNC_1(ucl_builtin_error, state, arg) {
|
||||
return ucl_error_create(arg->error);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_symbol_p, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_symbol_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_SYMBOL);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_string_p, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_string_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_STRING);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_int_p, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_int_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_INT);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_list_p, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_list_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_CELL);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_error_p, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_error_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_ERROR);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_car, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_car, scope, arg) {
|
||||
return ucl_car(arg);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_cdr, state, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_cdr, scope, arg) {
|
||||
return ucl_cdr(arg);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_nth, state, n, list) {
|
||||
LISP_FUNC_2(ucl_builtin_nth, scope, n, list) {
|
||||
UCL_COND_OR_RET_ERROR(n->type == UCL_TYPE_INT, "First argument to nth must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(list->type == UCL_TYPE_CELL, "Second argument to nth must be a list");
|
||||
|
||||
return ucl_list_nth(list, n->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_add, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_add, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'add'");
|
||||
}
|
||||
@@ -88,7 +88,7 @@ LISP_FUNC_2(ucl_builtin_add, state, arg0, arg1) {
|
||||
return ucl_int_create(arg0->integer + arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_sub, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_sub, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'sub'");
|
||||
}
|
||||
@@ -100,7 +100,7 @@ LISP_FUNC_2(ucl_builtin_sub, state, arg0, arg1) {
|
||||
return ucl_int_create(arg0->integer - arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_mul, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_mul, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'mul'");
|
||||
}
|
||||
@@ -112,7 +112,7 @@ LISP_FUNC_2(ucl_builtin_mul, state, arg0, arg1) {
|
||||
return ucl_int_create(arg0->integer * arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_div, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_div, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'div'");
|
||||
}
|
||||
@@ -125,7 +125,7 @@ LISP_FUNC_2(ucl_builtin_div, state, arg0, arg1) {
|
||||
return ucl_int_create(arg0->integer / arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_mod, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_mod, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'mod'");
|
||||
}
|
||||
@@ -137,7 +137,7 @@ LISP_FUNC_2(ucl_builtin_mod, state, arg0, arg1) {
|
||||
return ucl_int_create(arg0->integer % arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_concat, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_concat, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_STRING) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'concat'");
|
||||
}
|
||||
@@ -157,25 +157,25 @@ LISP_FUNC_2(ucl_builtin_concat, state, arg0, arg1) {
|
||||
return result;
|
||||
}
|
||||
|
||||
LISP_FUNC_0(ucl_builtin_now_millis_mono, state) {
|
||||
LISP_FUNC_0(ucl_builtin_now_millis_mono, scope) {
|
||||
// TODO: Implement and move to a 'platform' file
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_print, state, arg0) {
|
||||
LISP_FUNC_1(ucl_builtin_print, scope, arg0) {
|
||||
ucl_print_obj(arg0);
|
||||
|
||||
return ucl_nil_create();
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_printl, state, arg0) {
|
||||
LISP_FUNC_1(ucl_builtin_printl, scope, arg0) {
|
||||
ucl_print_obj(arg0);
|
||||
printf("\n");
|
||||
|
||||
return ucl_nil_create();
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_builtin_list(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_builtin_list(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *head = ucl_nil_create();
|
||||
FOREACH_LIST(args, iter, item) {
|
||||
ucl_list_append(head, item);
|
||||
@@ -184,57 +184,57 @@ struct ucl_object *ucl_builtin_list(struct ucl_state *state, struct ucl_object *
|
||||
return head;
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_mapcar, state, fun, elems) {
|
||||
LISP_FUNC_2(ucl_builtin_mapcar, scope, fun, elems) {
|
||||
// TODO: Support arbitrary number of 'elems' lists
|
||||
struct ucl_object *result = ucl_nil_create();
|
||||
FOREACH_LIST(elems, iter, elem) {
|
||||
struct ucl_object *form = ucl_tuple_create(fun, elem);
|
||||
struct ucl_object *value = ucl_evaluate(state, form);
|
||||
struct ucl_object *value = ucl_evaluate(scope, form);
|
||||
UCL_RET_IF_ERROR(value);
|
||||
ucl_list_append(result, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_equal, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_equal, scope, arg0, arg1) {
|
||||
return ucl_equal(arg0, arg1);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_gt, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_gt, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "First argument to > must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "Second argument to > must be an integer");
|
||||
return ucl_predicate(arg0->integer > arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_ge, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_ge, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "First argument to >= must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "Second argument to >= must be an integer");
|
||||
return ucl_predicate(arg0->integer > arg1->integer);
|
||||
}
|
||||
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_lt, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_lt, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "First argument to < must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "Second argument to < must be an integer");
|
||||
return ucl_predicate(arg0->integer < arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_le, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_le, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "First argument to <= must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "Second argument to <= must be an integer");
|
||||
return ucl_predicate(arg0->integer < arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_num_eq, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_num_eq, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "First argument to = must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "Second argument to = must be an integer");
|
||||
return ucl_predicate(arg0->integer == arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_xor, state, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_xor, scope, arg0, arg1) {
|
||||
return ucl_predicate(ucl_truthy_bool(arg0) || ucl_truthy_bool(arg1));
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_not, state, arg0) {
|
||||
LISP_FUNC_1(ucl_builtin_not, scope, arg0) {
|
||||
return ucl_predicate(!ucl_truthy_bool(arg0));
|
||||
}
|
||||
|
||||
@@ -3,37 +3,37 @@
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
struct ucl_object *ucl_builtin_error(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_type(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_symbol_p(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_string_p(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_int_p(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_list_p(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_error(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_type(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_symbol_p(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_string_p(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_int_p(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_list_p(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
struct ucl_object *ucl_builtin_add(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_sub(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_mul(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_div(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_mod(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_gt(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_ge(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_lt(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_le(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_num_eq(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_concat(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_add(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_sub(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_mul(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_div(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_mod(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_gt(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_ge(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_lt(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_le(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_num_eq(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_concat(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
struct ucl_object *ucl_builtin_not(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_xor(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_not(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_xor(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
struct ucl_object *ucl_builtin_now_millis_mono(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_now_millis_mono(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
struct ucl_object *ucl_builtin_car(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_cdr(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_nth(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_list(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_mapcar(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_car(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_cdr(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_nth(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_list(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_mapcar(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
struct ucl_object *ucl_builtin_print(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_printl(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_print(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_printl(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,17 +4,17 @@
|
||||
#include "uclisp.h"
|
||||
#include "internal.h"
|
||||
#include "utility.h"
|
||||
#include "state.h"
|
||||
#include "scope.h"
|
||||
|
||||
// TODO: remove string.h
|
||||
#include <string.h>
|
||||
|
||||
struct ucl_object *ucl_evaluate_builtin_form(struct ucl_state *state, struct ucl_object *list) {
|
||||
struct ucl_object *ucl_evaluate_builtin_form(struct ucl_scope *scope, struct ucl_object *list) {
|
||||
// TODO: Reasonably split builtin and non-builtin evaluation
|
||||
struct ucl_object *evaluated_list = ucl_nil_create();
|
||||
|
||||
FOREACH_LIST(list, iter, item) {
|
||||
struct ucl_object *obj = ucl_evaluate(state, item);
|
||||
struct ucl_object *obj = ucl_evaluate(scope, item);
|
||||
UCL_RET_IF_ERROR(obj);
|
||||
ucl_list_append(evaluated_list, obj);
|
||||
};
|
||||
@@ -24,18 +24,18 @@ struct ucl_object *ucl_evaluate_builtin_form(struct ucl_state *state, struct ucl
|
||||
|
||||
if (fun->type == UCL_TYPE_BUILTIN) {
|
||||
struct ucl_object *args = ucl_cdr(evaluated_list);
|
||||
result = fun->builtin(state, args);
|
||||
result = fun->builtin(scope, args);
|
||||
} else if (fun->type == UCL_TYPE_CELL) {
|
||||
struct ucl_state *fun_state = ucl_state_create_child(state);
|
||||
struct ucl_scope *fun_scope = ucl_scope_create_child(scope);
|
||||
struct ucl_object *fun_arg_syms = ucl_car(fun);
|
||||
struct ucl_object *fun_forms = ucl_cdr(fun);
|
||||
int i = 0;
|
||||
FOREACH_LIST(fun_arg_syms, iter, sym) {
|
||||
ucl_state_put(fun_state, sym->symbol, ucl_list_nth(evaluated_list, i + 1));
|
||||
ucl_scope_put(fun_scope, sym->symbol, ucl_list_nth(evaluated_list, i + 1));
|
||||
i++;
|
||||
}
|
||||
result = ucl_progn(fun_state, fun_forms);
|
||||
ucl_state_delete(fun_state);
|
||||
result = ucl_progn(fun_scope, fun_forms);
|
||||
ucl_scope_delete(fun_scope);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
@@ -45,45 +45,45 @@ struct ucl_object *ucl_evaluate_builtin_form(struct ucl_state *state, struct ucl
|
||||
return (result == NULL) ? ucl_nil_create() : result;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_evaluate_special_form(struct ucl_state *state, struct ucl_object *list) {
|
||||
struct ucl_object *ucl_evaluate_special_form(struct ucl_scope *scope, struct ucl_object *list) {
|
||||
// TODO: Recursively eval args
|
||||
const char *fun_sym = ucl_car(list)->symbol;
|
||||
|
||||
struct ucl_object *fun = ucl_state_get(state, fun_sym);
|
||||
struct ucl_object *fun = ucl_scope_get(scope, fun_sym);
|
||||
struct ucl_object *args = ucl_cdr(list);
|
||||
struct ucl_object *result = NULL;
|
||||
|
||||
result = fun->special(state, args);
|
||||
result = fun->special(scope, args);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_evaluate_list(struct ucl_state *state, struct ucl_object *list) {
|
||||
struct ucl_object *ucl_evaluate_list(struct ucl_scope *scope, struct ucl_object *list) {
|
||||
if (list->cell.car == NULL) {
|
||||
return list;
|
||||
}
|
||||
|
||||
struct ucl_object *fun = ucl_evaluate(state, ucl_car(list));
|
||||
struct ucl_object *fun = ucl_evaluate(scope, ucl_car(list));
|
||||
UCL_RET_IF_ERROR(fun);
|
||||
|
||||
if (fun->type == UCL_TYPE_SPECIAL) {
|
||||
return ucl_evaluate_special_form(state, list);
|
||||
return ucl_evaluate_special_form(scope, list);
|
||||
} else if (fun->type == UCL_TYPE_BUILTIN || fun->type == UCL_TYPE_CELL) {
|
||||
return ucl_evaluate_builtin_form(state, list);
|
||||
return ucl_evaluate_builtin_form(scope, list);
|
||||
} else {
|
||||
assert(0);
|
||||
// TODO: Lisp functions and other errors
|
||||
}
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_evaluate(struct ucl_state *state, struct ucl_object *obj) {
|
||||
struct ucl_object *ucl_evaluate(struct ucl_scope *scope, struct ucl_object *obj) {
|
||||
assert(obj != NULL);
|
||||
|
||||
switch (obj->type) {
|
||||
case UCL_TYPE_CELL:
|
||||
return ucl_evaluate_list(state, obj);
|
||||
return ucl_evaluate_list(scope, obj);
|
||||
case UCL_TYPE_SYMBOL:
|
||||
return ucl_state_get(state, obj->symbol);
|
||||
return ucl_scope_get(scope, obj->symbol);
|
||||
case UCL_TYPE_INT:
|
||||
case UCL_TYPE_STRING:
|
||||
case UCL_TYPE_ERROR:
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
iter_name = iter_name->cell.cdr, item_name = (iter_name == NULL) ? NULL : iter_name->cell.car)
|
||||
|
||||
// TODO: Refactor this struct's location
|
||||
struct ucl_state {
|
||||
struct ucl_scope {
|
||||
// TODO: For garbage collection, we need references from the parent->child state
|
||||
struct ucl_object *list;
|
||||
struct ucl_state *parent;
|
||||
struct ucl_scope *parent;
|
||||
};
|
||||
|
||||
extern struct ucl_arena *state_arena;
|
||||
extern struct ucl_arena *scope_arena;
|
||||
|
||||
struct ucl_object *ucl_cell_create(struct ucl_object *car, struct ucl_object *cdr);
|
||||
struct ucl_object *ucl_int_create(int integer);
|
||||
|
||||
28
src/lisp.h
28
src/lisp.h
@@ -4,19 +4,19 @@
|
||||
#include "uclisp.h"
|
||||
#include "utility.h"
|
||||
|
||||
#define LISP_FUNC_0(func_name, state_name) \
|
||||
#define LISP_FUNC_0(func_name, scope_name) \
|
||||
static struct ucl_object *func_name##_impl(); \
|
||||
struct ucl_object *func_name(struct ucl_state *state, struct ucl_object *args) { \
|
||||
struct ucl_object *func_name(struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
if (args->cell.car != NULL) { \
|
||||
return NULL; \
|
||||
} \
|
||||
return func_name##_impl(state_name); \
|
||||
return func_name##_impl(scope_name); \
|
||||
} \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_state *state)
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope)
|
||||
|
||||
#define LISP_FUNC_1(func_name, state_name, arg0_name) \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_state *state, struct ucl_object *arg0_name); \
|
||||
struct ucl_object *func_name(struct ucl_state *state, struct ucl_object *args) { \
|
||||
#define LISP_FUNC_1(func_name, scope_name, arg0_name) \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name); \
|
||||
struct ucl_object *func_name(struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
struct ucl_object *len_obj = ucl_list_length(args); \
|
||||
if (len_obj->type != UCL_TYPE_INT) { \
|
||||
return NULL; \
|
||||
@@ -25,14 +25,14 @@
|
||||
return NULL; \
|
||||
} \
|
||||
struct ucl_object *arg0 = ucl_car(args); \
|
||||
return func_name##_impl(state_name, arg0); \
|
||||
return func_name##_impl(scope_name, arg0); \
|
||||
} \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_state *state, struct ucl_object *arg0_name)
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name)
|
||||
|
||||
// TODO: Unroll the args more efficiently, this is O(n^2)
|
||||
#define LISP_FUNC_2(func_name, state_name, arg0_name, arg1_name) \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_state *state, struct ucl_object *arg0_name, struct ucl_object *arg1_name); \
|
||||
struct ucl_object *func_name(struct ucl_state *state, struct ucl_object *args) { \
|
||||
#define LISP_FUNC_2(func_name, scope_name, arg0_name, arg1_name) \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name); \
|
||||
struct ucl_object *func_name(struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
struct ucl_object *len_obj = ucl_list_length(args); \
|
||||
if (len_obj->type != UCL_TYPE_INT) { \
|
||||
return NULL; \
|
||||
@@ -42,8 +42,8 @@
|
||||
} \
|
||||
struct ucl_object *arg0 = ucl_list_nth(args, 0); \
|
||||
struct ucl_object *arg1 = ucl_list_nth(args, 1); \
|
||||
return func_name##_impl(state_name, arg0, arg1); \
|
||||
return func_name##_impl(scope_name, arg0, arg1); \
|
||||
} \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_state *state, struct ucl_object *arg0_name, struct ucl_object *arg1_name)
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name)
|
||||
|
||||
#endif
|
||||
|
||||
80
src/main.c
80
src/main.c
@@ -8,62 +8,62 @@
|
||||
#include "builtins.h"
|
||||
#include "internal.h"
|
||||
#include "special.h"
|
||||
#include "state.h"
|
||||
#include "scope.h"
|
||||
#include "utility.h"
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
(void) argc, (void) argv;
|
||||
struct ucl_state *state = ucl_state_create();
|
||||
struct ucl_scope *scope = ucl_scope_create();
|
||||
|
||||
ucl_state_put(state, "let", ucl_special_create(ucl_special_let));
|
||||
ucl_state_put(state, "if", ucl_special_create(ucl_special_if));
|
||||
ucl_state_put(state, "defun", ucl_special_create(ucl_special_defun));
|
||||
ucl_state_put(state, "lambda", ucl_special_create(ucl_special_lambda));
|
||||
ucl_state_put(state, "setq", ucl_special_create(ucl_special_setq));
|
||||
ucl_state_put(state, "progn", ucl_special_create(ucl_special_progn));
|
||||
ucl_state_put(state, "quote", ucl_special_create(ucl_special_quote));
|
||||
ucl_state_put(state, "and", ucl_special_create(ucl_special_and));
|
||||
ucl_state_put(state, "or", ucl_special_create(ucl_special_or));
|
||||
ucl_scope_put(scope, "let", ucl_special_create(ucl_special_let));
|
||||
ucl_scope_put(scope, "if", ucl_special_create(ucl_special_if));
|
||||
ucl_scope_put(scope, "defun", ucl_special_create(ucl_special_defun));
|
||||
ucl_scope_put(scope, "lambda", ucl_special_create(ucl_special_lambda));
|
||||
ucl_scope_put(scope, "setq", ucl_special_create(ucl_special_setq));
|
||||
ucl_scope_put(scope, "progn", ucl_special_create(ucl_special_progn));
|
||||
ucl_scope_put(scope, "quote", ucl_special_create(ucl_special_quote));
|
||||
ucl_scope_put(scope, "and", ucl_special_create(ucl_special_and));
|
||||
ucl_scope_put(scope, "or", ucl_special_create(ucl_special_or));
|
||||
|
||||
// TODO:
|
||||
// - iteration
|
||||
|
||||
ucl_state_put(state, "print", ucl_builtin_create(ucl_builtin_print));
|
||||
ucl_state_put(state, "printl", ucl_builtin_create(ucl_builtin_printl));
|
||||
ucl_scope_put(scope, "print", ucl_builtin_create(ucl_builtin_print));
|
||||
ucl_scope_put(scope, "printl", ucl_builtin_create(ucl_builtin_printl));
|
||||
// TODO:
|
||||
// - object -> string
|
||||
// - formatted printing?
|
||||
|
||||
ucl_state_put(state, "+", ucl_builtin_create(ucl_builtin_add));
|
||||
ucl_state_put(state, "-", ucl_builtin_create(ucl_builtin_sub));
|
||||
ucl_state_put(state, "*", ucl_builtin_create(ucl_builtin_mul));
|
||||
ucl_state_put(state, "/", ucl_builtin_create(ucl_builtin_div));
|
||||
ucl_state_put(state, "%", ucl_builtin_create(ucl_builtin_mod));
|
||||
ucl_state_put(state, ">", ucl_builtin_create(ucl_builtin_gt));
|
||||
ucl_state_put(state, ">=", ucl_builtin_create(ucl_builtin_ge));
|
||||
ucl_state_put(state, "<", ucl_builtin_create(ucl_builtin_lt));
|
||||
ucl_state_put(state, "<=", ucl_builtin_create(ucl_builtin_le));
|
||||
ucl_state_put(state, "=", ucl_builtin_create(ucl_builtin_num_eq));
|
||||
ucl_state_put(state, "not", ucl_builtin_create(ucl_builtin_not));
|
||||
ucl_state_put(state, "xor", ucl_builtin_create(ucl_builtin_xor));
|
||||
ucl_scope_put(scope, "+", ucl_builtin_create(ucl_builtin_add));
|
||||
ucl_scope_put(scope, "-", ucl_builtin_create(ucl_builtin_sub));
|
||||
ucl_scope_put(scope, "*", ucl_builtin_create(ucl_builtin_mul));
|
||||
ucl_scope_put(scope, "/", ucl_builtin_create(ucl_builtin_div));
|
||||
ucl_scope_put(scope, "%", ucl_builtin_create(ucl_builtin_mod));
|
||||
ucl_scope_put(scope, ">", ucl_builtin_create(ucl_builtin_gt));
|
||||
ucl_scope_put(scope, ">=", ucl_builtin_create(ucl_builtin_ge));
|
||||
ucl_scope_put(scope, "<", ucl_builtin_create(ucl_builtin_lt));
|
||||
ucl_scope_put(scope, "<=", ucl_builtin_create(ucl_builtin_le));
|
||||
ucl_scope_put(scope, "=", ucl_builtin_create(ucl_builtin_num_eq));
|
||||
ucl_scope_put(scope, "not", ucl_builtin_create(ucl_builtin_not));
|
||||
ucl_scope_put(scope, "xor", ucl_builtin_create(ucl_builtin_xor));
|
||||
// TODO:
|
||||
// - Floats or nah?
|
||||
|
||||
ucl_state_put(state, "concat", ucl_builtin_create(ucl_builtin_concat));
|
||||
ucl_scope_put(scope, "concat", ucl_builtin_create(ucl_builtin_concat));
|
||||
|
||||
ucl_state_put(state, "error", ucl_builtin_create(ucl_builtin_error));
|
||||
ucl_state_put(state, "type", ucl_builtin_create(ucl_builtin_type));
|
||||
ucl_state_put(state, "symbol-p", ucl_builtin_create(ucl_builtin_symbol_p));
|
||||
ucl_state_put(state, "string-p", ucl_builtin_create(ucl_builtin_string_p));
|
||||
ucl_state_put(state, "int-p", ucl_builtin_create(ucl_builtin_int_p));
|
||||
ucl_state_put(state, "list-p", ucl_builtin_create(ucl_builtin_list_p));
|
||||
ucl_scope_put(scope, "error", ucl_builtin_create(ucl_builtin_error));
|
||||
ucl_scope_put(scope, "type", ucl_builtin_create(ucl_builtin_type));
|
||||
ucl_scope_put(scope, "symbol-p", ucl_builtin_create(ucl_builtin_symbol_p));
|
||||
ucl_scope_put(scope, "string-p", ucl_builtin_create(ucl_builtin_string_p));
|
||||
ucl_scope_put(scope, "int-p", ucl_builtin_create(ucl_builtin_int_p));
|
||||
ucl_scope_put(scope, "list-p", ucl_builtin_create(ucl_builtin_list_p));
|
||||
|
||||
ucl_state_put(state, "list", ucl_builtin_create(ucl_builtin_list));
|
||||
ucl_state_put(state, "car", ucl_builtin_create(ucl_builtin_car));
|
||||
ucl_state_put(state, "cdr", ucl_builtin_create(ucl_builtin_cdr));
|
||||
ucl_state_put(state, "nth", ucl_builtin_create(ucl_builtin_nth));
|
||||
ucl_state_put(state, "mapcar", ucl_builtin_create(ucl_builtin_mapcar));
|
||||
ucl_state_put(state, "equal", ucl_builtin_create(ucl_builtin_mapcar));
|
||||
ucl_scope_put(scope, "list", ucl_builtin_create(ucl_builtin_list));
|
||||
ucl_scope_put(scope, "car", ucl_builtin_create(ucl_builtin_car));
|
||||
ucl_scope_put(scope, "cdr", ucl_builtin_create(ucl_builtin_cdr));
|
||||
ucl_scope_put(scope, "nth", ucl_builtin_create(ucl_builtin_nth));
|
||||
ucl_scope_put(scope, "mapcar", ucl_builtin_create(ucl_builtin_mapcar));
|
||||
ucl_scope_put(scope, "equal", ucl_builtin_create(ucl_builtin_mapcar));
|
||||
|
||||
// TODO:
|
||||
// - reduce
|
||||
@@ -80,7 +80,7 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
|
||||
struct ucl_object *sexp = ucl_parse(line);
|
||||
struct ucl_object *result = ucl_evaluate(state, ucl_car(sexp));
|
||||
struct ucl_object *result = ucl_evaluate(scope, ucl_car(sexp));
|
||||
ucl_print_obj(result);
|
||||
printf("\n");
|
||||
|
||||
@@ -89,7 +89,7 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
} else {
|
||||
struct ucl_object *sexp = ucl_parse(argv[1]);
|
||||
struct ucl_object *result = ucl_evaluate(state, ucl_car(sexp));
|
||||
struct ucl_object *result = ucl_evaluate(scope, ucl_car(sexp));
|
||||
|
||||
if (result->type == UCL_TYPE_ERROR) {
|
||||
printf("%s", result->error);
|
||||
|
||||
12
src/memory.c
12
src/memory.c
@@ -9,8 +9,8 @@
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef UCL_STATE_ARENA_SIZE
|
||||
#define UCL_STATE_ARENA_SIZE 16
|
||||
#ifndef UCL_SCOPE_ARENA_SIZE
|
||||
#define UCL_SCOPE_ARENA_SIZE 16
|
||||
#endif
|
||||
|
||||
#ifndef UCL_OBJECT_ARENA_SIZE
|
||||
@@ -134,11 +134,11 @@ void ucl_object_mark(struct ucl_object *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
void ucl_state_mark(struct ucl_arena * arena, void *obj) {
|
||||
void ucl_scope_mark(struct ucl_arena * arena, void *obj) {
|
||||
(void) arena;
|
||||
struct ucl_state *state = (struct ucl_state *) obj;
|
||||
struct ucl_scope *scope = (struct ucl_scope *) obj;
|
||||
|
||||
ucl_object_mark(state->list);
|
||||
ucl_object_mark(scope->list);
|
||||
}
|
||||
|
||||
void ucl_gc_unmark(struct ucl_arena * arena, void *obj) {
|
||||
@@ -161,7 +161,7 @@ void ucl_gc_sweep(struct ucl_arena * arena, void *obj) {
|
||||
void ucl_gc() {
|
||||
ucl_arena_map(object_arena, ucl_gc_unmark);
|
||||
|
||||
ucl_arena_map(state_arena, ucl_state_mark);
|
||||
ucl_arena_map(scope_arena, ucl_scope_mark);
|
||||
|
||||
ucl_arena_map(object_arena, ucl_gc_sweep);
|
||||
}
|
||||
|
||||
87
src/scope.c
Normal file
87
src/scope.c
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "uclisp.h"
|
||||
#include "internal.h"
|
||||
#include "scope.h"
|
||||
#include "utility.h"
|
||||
#include "arena.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Implements state as a giant alist
|
||||
|
||||
// TODO: Consider generalizing the alist concept
|
||||
|
||||
#define NAME_POSITION 0
|
||||
#define DATA_POSITION 1
|
||||
|
||||
#define SCOPE_ARENA_CAPACITY 32
|
||||
|
||||
struct ucl_arena *scope_arena;
|
||||
|
||||
static struct ucl_object *ucl_scope_get_cell(struct ucl_scope *scope, const char *name) {
|
||||
FOREACH_LIST(scope->list, iter, item) {
|
||||
assert(item->type == UCL_TYPE_CELL);
|
||||
const char *item_name = ucl_list_nth(item, NAME_POSITION)->string;
|
||||
if (!strcmp(name, item_name)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_scope_get(struct ucl_scope *scope, const char *name) {
|
||||
struct ucl_object *cell = ucl_scope_get_cell(scope, name);
|
||||
if (cell == NULL) {
|
||||
if (scope->parent == NULL) {
|
||||
// TODO: Include the symbol name
|
||||
return ucl_error_create("Unbound symbol");
|
||||
} else {
|
||||
return ucl_scope_get(scope->parent, name);
|
||||
}
|
||||
}
|
||||
return ucl_list_nth(cell, DATA_POSITION);
|
||||
}
|
||||
|
||||
void ucl_scope_put(struct ucl_scope *scope, const char *name, struct ucl_object *obj) {
|
||||
struct ucl_object *cell = ucl_scope_get_cell(scope, name);
|
||||
if (cell == NULL) {
|
||||
ucl_list_append(scope->list,
|
||||
ucl_tuple_create(
|
||||
ucl_string_create(name),
|
||||
obj));
|
||||
} else {
|
||||
// TODO: Refcounting / cleanup
|
||||
cell->cell.cdr->cell.car = obj;
|
||||
}
|
||||
}
|
||||
|
||||
struct ucl_scope *ucl_scope_create() {
|
||||
if (scope_arena == NULL) {
|
||||
scope_arena = ucl_arena_create(sizeof(struct ucl_scope), SCOPE_ARENA_CAPACITY);
|
||||
}
|
||||
struct ucl_scope *scope = ucl_arena_get(scope_arena);
|
||||
scope->list = ucl_nil_create();
|
||||
scope->parent = NULL;
|
||||
return scope;
|
||||
}
|
||||
|
||||
struct ucl_scope *ucl_scope_create_child(struct ucl_scope *parent) {
|
||||
struct ucl_scope *scope = ucl_scope_create();
|
||||
scope->parent = parent;
|
||||
return scope;
|
||||
}
|
||||
|
||||
struct ucl_scope *ucl_scope_get_root(struct ucl_scope *scope) {
|
||||
while (scope->parent != NULL) {
|
||||
scope = scope->parent;
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
void ucl_scope_delete(struct ucl_scope *scope) {
|
||||
assert(scope_arena != NULL);
|
||||
ucl_arena_put(scope_arena, scope);
|
||||
// Garbage collection will handle the objects, they are shared
|
||||
}
|
||||
15
src/scope.h
Normal file
15
src/scope.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _UCLISP_SCOPE_H_
|
||||
#define _UCLISP_SCOPE_H_
|
||||
|
||||
struct ucl_scope;
|
||||
|
||||
struct ucl_scope *ucl_scope_create();
|
||||
struct ucl_scope *ucl_scope_create_child(struct ucl_scope *parent);
|
||||
|
||||
void ucl_scope_delete(struct ucl_scope *scope);
|
||||
|
||||
struct ucl_object *ucl_scope_get(struct ucl_scope *scope, const char *name);
|
||||
void ucl_scope_put(struct ucl_scope *scope, const char *name, struct ucl_object *obj);
|
||||
struct ucl_scope *ucl_scope_get_root(struct ucl_scope *scope);
|
||||
|
||||
#endif
|
||||
@@ -1,55 +1,55 @@
|
||||
#include "state.h"
|
||||
#include "scope.h"
|
||||
#include "lisp.h"
|
||||
#include "utility.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
struct ucl_object *ucl_special_let(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_let(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *assignments = ucl_car(args);
|
||||
struct ucl_object *expressions = ucl_cdr(args);
|
||||
struct ucl_state *let_state = ucl_state_create_child(state);
|
||||
struct ucl_scope *let_scope = ucl_scope_create_child(scope);
|
||||
|
||||
FOREACH_LIST(assignments, iter, item) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *sym = ucl_car(item);
|
||||
struct ucl_object *expr = ucl_car(ucl_cdr(item));
|
||||
struct ucl_object *value = ucl_evaluate(let_state, expr);
|
||||
struct ucl_object *value = ucl_evaluate(let_scope, expr);
|
||||
|
||||
assert(sym->type == UCL_TYPE_SYMBOL);
|
||||
//assert(ucl_list_length(expr)->integer == 1);
|
||||
|
||||
if (value->type == UCL_TYPE_ERROR) {
|
||||
// TODO cleanup
|
||||
ucl_state_delete(let_state);
|
||||
ucl_scope_delete(let_scope);
|
||||
return value;
|
||||
}
|
||||
ucl_state_put(let_state, sym->symbol, value);
|
||||
ucl_scope_put(let_scope, sym->symbol, value);
|
||||
}
|
||||
|
||||
struct ucl_object *result = ucl_progn(let_state, expressions);
|
||||
ucl_state_delete(let_state);
|
||||
struct ucl_object *result = ucl_progn(let_scope, expressions);
|
||||
ucl_scope_delete(let_scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_if(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_if(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *cond = ucl_car(args);
|
||||
struct ucl_object *true_form = ucl_list_nth(args, 1);
|
||||
struct ucl_object *false_forms = ucl_cdr(ucl_cdr(args));
|
||||
|
||||
struct ucl_object *cond_result = ucl_evaluate(state, cond);
|
||||
struct ucl_object *cond_result = ucl_evaluate(scope, cond);
|
||||
UCL_RET_IF_ERROR(cond_result);
|
||||
if (ucl_truthy(cond_result)->type == UCL_TYPE_SYMBOL) {
|
||||
return ucl_evaluate(state, true_form);
|
||||
return ucl_evaluate(scope, true_form);
|
||||
}
|
||||
|
||||
return ucl_progn(state, false_forms);
|
||||
return ucl_progn(scope, false_forms);
|
||||
}
|
||||
|
||||
|
||||
struct ucl_object *ucl_special_defun(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_defun(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *fun_sym = ucl_car(args);
|
||||
if (fun_sym->type != UCL_TYPE_SYMBOL) {
|
||||
@@ -66,13 +66,13 @@ struct ucl_object *ucl_special_defun(struct ucl_state *state, struct ucl_object
|
||||
// there will be docstrings, maybe not!
|
||||
|
||||
// Functions are added to the root scope
|
||||
ucl_state_put(ucl_state_get_root(state), fun_sym->symbol, ucl_cdr(args));
|
||||
ucl_scope_put(ucl_scope_get_root(scope), fun_sym->symbol, ucl_cdr(args));
|
||||
|
||||
return fun_sym;
|
||||
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_lambda(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_lambda(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *fun_args = ucl_list_nth(args, 0);
|
||||
if (fun_args->type != UCL_TYPE_CELL) {
|
||||
@@ -84,33 +84,33 @@ struct ucl_object *ucl_special_lambda(struct ucl_state *state, struct ucl_object
|
||||
}
|
||||
|
||||
|
||||
struct ucl_object *ucl_special_setq(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_setq(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *sym = ucl_car(args);
|
||||
struct ucl_state *root_state = ucl_state_get_root(state);
|
||||
struct ucl_scope *root_scope = ucl_scope_get_root(scope);
|
||||
if (sym->type != UCL_TYPE_SYMBOL) {
|
||||
return ucl_error_create("First argument to setq must be a symbol");
|
||||
}
|
||||
|
||||
struct ucl_object *value = ucl_evaluate(state, ucl_list_nth(args, 1));
|
||||
struct ucl_object *value = ucl_evaluate(scope, ucl_list_nth(args, 1));
|
||||
|
||||
ucl_state_put(root_state, sym->symbol, value);
|
||||
ucl_scope_put(root_scope, sym->symbol, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_progn(struct ucl_state *state, struct ucl_object *args) {
|
||||
return ucl_progn(state, args);
|
||||
struct ucl_object *ucl_special_progn(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
return ucl_progn(scope, args);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_quote(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_quote(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
return ucl_car(args);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_and(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_and(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *value = ucl_t_create();
|
||||
FOREACH_LIST(args, iter, form) {
|
||||
value = ucl_evaluate(state, form);
|
||||
value = ucl_evaluate(scope, form);
|
||||
if (!ucl_truthy_bool(value)) {
|
||||
return value;
|
||||
}
|
||||
@@ -118,10 +118,10 @@ struct ucl_object *ucl_special_and(struct ucl_state *state, struct ucl_object *a
|
||||
return value;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_or(struct ucl_state *state, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_or(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *value = ucl_nil_create();
|
||||
FOREACH_LIST(args, iter, form) {
|
||||
value = ucl_evaluate(state, form);
|
||||
value = ucl_evaluate(scope, form);
|
||||
if (ucl_truthy_bool(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
#include "uclisp.h"
|
||||
|
||||
struct ucl_object *ucl_special_let(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_if(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_defun(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_lambda(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_setq(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_progn(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_quote(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_and(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_or(struct ucl_state *state, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_let(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_if(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_defun(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_lambda(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_setq(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_progn(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_quote(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_and(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_or(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
#endif
|
||||
|
||||
88
src/state.c
88
src/state.c
@@ -1,88 +0,0 @@
|
||||
#include "uclisp.h"
|
||||
#include "internal.h"
|
||||
#include "state.h"
|
||||
#include "utility.h"
|
||||
#include "arena.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Implements state as a giant alist
|
||||
|
||||
// TODO: Consider generalizing the alist concept
|
||||
// TODO: Rename 'state' to 'scope'
|
||||
|
||||
#define NAME_POSITION 0
|
||||
#define DATA_POSITION 1
|
||||
|
||||
#define STATE_ARENA_CAPACITY 32
|
||||
|
||||
struct ucl_arena *state_arena;
|
||||
|
||||
static struct ucl_object *ucl_state_get_cell(struct ucl_state *state, const char *name) {
|
||||
FOREACH_LIST(state->list, iter, item) {
|
||||
assert(item->type == UCL_TYPE_CELL);
|
||||
const char *item_name = ucl_list_nth(item, NAME_POSITION)->string;
|
||||
if (!strcmp(name, item_name)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_state_get(struct ucl_state *state, const char *name) {
|
||||
struct ucl_object *cell = ucl_state_get_cell(state, name);
|
||||
if (cell == NULL) {
|
||||
if (state->parent == NULL) {
|
||||
// TODO: Include the symbol name
|
||||
return ucl_error_create("Unbound symbol");
|
||||
} else {
|
||||
return ucl_state_get(state->parent, name);
|
||||
}
|
||||
}
|
||||
return ucl_list_nth(cell, DATA_POSITION);
|
||||
}
|
||||
|
||||
void ucl_state_put(struct ucl_state *state, const char *name, struct ucl_object *obj) {
|
||||
struct ucl_object *cell = ucl_state_get_cell(state, name);
|
||||
if (cell == NULL) {
|
||||
ucl_list_append(state->list,
|
||||
ucl_tuple_create(
|
||||
ucl_string_create(name),
|
||||
obj));
|
||||
} else {
|
||||
// TODO: Refcounting / cleanup
|
||||
cell->cell.cdr->cell.car = obj;
|
||||
}
|
||||
}
|
||||
|
||||
struct ucl_state *ucl_state_create() {
|
||||
if (state_arena == NULL) {
|
||||
state_arena = ucl_arena_create(sizeof(struct ucl_state), STATE_ARENA_CAPACITY);
|
||||
}
|
||||
struct ucl_state *state = ucl_arena_get(state_arena);
|
||||
state->list = ucl_nil_create();
|
||||
state->parent = NULL;
|
||||
return state;
|
||||
}
|
||||
|
||||
struct ucl_state *ucl_state_create_child(struct ucl_state *parent) {
|
||||
struct ucl_state *state = ucl_state_create();
|
||||
state->parent = parent;
|
||||
return state;
|
||||
}
|
||||
|
||||
struct ucl_state *ucl_state_get_root(struct ucl_state *state) {
|
||||
while (state->parent != NULL) {
|
||||
state = state->parent;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void ucl_state_delete(struct ucl_state *state) {
|
||||
assert(state_arena != NULL);
|
||||
ucl_arena_put(state_arena, state);
|
||||
// Garbage collection will handle the objects, they are shared
|
||||
}
|
||||
15
src/state.h
15
src/state.h
@@ -1,15 +0,0 @@
|
||||
#ifndef _UCLISP_STATE_H_
|
||||
#define _UCLISP_STATE_H_
|
||||
|
||||
struct ucl_state;
|
||||
|
||||
struct ucl_state *ucl_state_create();
|
||||
struct ucl_state *ucl_state_create_child(struct ucl_state *parent);
|
||||
|
||||
void ucl_state_delete(struct ucl_state *state);
|
||||
|
||||
struct ucl_object *ucl_state_get(struct ucl_state *state, const char *name);
|
||||
void ucl_state_put(struct ucl_state *state, const char *name, struct ucl_object *obj);
|
||||
struct ucl_state *ucl_state_get_root(struct ucl_state *state);
|
||||
|
||||
#endif
|
||||
@@ -17,8 +17,8 @@ struct ucl_cell {
|
||||
struct ucl_object *cdr;
|
||||
};
|
||||
|
||||
struct ucl_state;
|
||||
typedef struct ucl_object *(*ucl_lisp)(struct ucl_state* state, struct ucl_object *args);
|
||||
struct ucl_scope;
|
||||
typedef struct ucl_object *(*ucl_lisp)(struct ucl_scope* state, struct ucl_object *args);
|
||||
|
||||
struct ucl_object {
|
||||
union {
|
||||
@@ -41,11 +41,11 @@ struct ucl_parse_result {
|
||||
struct ucl_cell *statement;
|
||||
};
|
||||
|
||||
struct ucl_state; // TODO
|
||||
struct ucl_scope; // TODO
|
||||
|
||||
struct ucl_object *ucl_tokenize(const char *source);
|
||||
struct ucl_object *ucl_parse(const char *sexp);
|
||||
struct ucl_object *ucl_evaluate(struct ucl_state *state, struct ucl_object *sexp);
|
||||
struct ucl_object *ucl_evaluate(struct ucl_scope *state, struct ucl_object *sexp);
|
||||
|
||||
// TODO: State encapsulation is all wonky here)
|
||||
void ucl_gc();
|
||||
|
||||
@@ -162,7 +162,7 @@ void ucl_print_obj(struct ucl_object *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_progn(struct ucl_state *state, struct ucl_object *forms) {
|
||||
struct ucl_object *ucl_progn(struct ucl_scope *state, struct ucl_object *forms) {
|
||||
struct ucl_object *result = NULL;
|
||||
FOREACH_LIST(forms, iter, form) {
|
||||
result = ucl_evaluate(state, form);
|
||||
|
||||
@@ -20,7 +20,7 @@ struct ucl_object* ucl_list_nth(struct ucl_object *list, int n);
|
||||
struct ucl_object* ucl_list_append(struct ucl_object *list, struct ucl_object *obj);
|
||||
struct ucl_object* ucl_tuple_create(struct ucl_object *obj0, struct ucl_object *obj1);
|
||||
|
||||
struct ucl_object *ucl_progn(struct ucl_state *state, struct ucl_object *forms);
|
||||
struct ucl_object *ucl_progn(struct ucl_scope *scope, struct ucl_object *forms);
|
||||
|
||||
void ucl_print_obj(struct ucl_object *obj);
|
||||
|
||||
|
||||
@@ -6,51 +6,51 @@
|
||||
#include "internal.h"
|
||||
#include "utility.h"
|
||||
#include "testing_helpers.h"
|
||||
#include "state.h"
|
||||
#include "scope.h"
|
||||
#include "builtins.h"
|
||||
#include "special.h"
|
||||
|
||||
static struct ucl_object *input;
|
||||
static struct ucl_object *response;
|
||||
static struct ucl_state *state;
|
||||
static struct ucl_scope *scope;
|
||||
|
||||
void setUp(void) {
|
||||
input = NULL;
|
||||
response = NULL;
|
||||
|
||||
state = ucl_state_create();
|
||||
ucl_state_put(state, "let", ucl_special_create(ucl_special_let));
|
||||
ucl_state_put(state, "defun", ucl_special_create(ucl_special_defun));
|
||||
ucl_state_put(state, "+", ucl_builtin_create(ucl_builtin_add));
|
||||
ucl_state_put(state, "error", ucl_builtin_create(ucl_builtin_error));
|
||||
ucl_state_put(state, "list", ucl_builtin_create(ucl_builtin_list));
|
||||
ucl_state_put(state, "setq", ucl_special_create(ucl_special_setq));
|
||||
ucl_state_put(state, "car", ucl_builtin_create(ucl_builtin_car));
|
||||
ucl_state_put(state, "cdr", ucl_builtin_create(ucl_builtin_cdr));
|
||||
ucl_state_put(state, "nth", ucl_builtin_create(ucl_builtin_nth));
|
||||
ucl_state_put(state, "mapcar", ucl_builtin_create(ucl_builtin_mapcar));
|
||||
ucl_state_put(state, "lambda", ucl_special_create(ucl_special_lambda));
|
||||
ucl_state_put(state, "quote", ucl_special_create(ucl_special_quote));
|
||||
scope = ucl_scope_create();
|
||||
ucl_scope_put(scope, "let", ucl_special_create(ucl_special_let));
|
||||
ucl_scope_put(scope, "defun", ucl_special_create(ucl_special_defun));
|
||||
ucl_scope_put(scope, "+", ucl_builtin_create(ucl_builtin_add));
|
||||
ucl_scope_put(scope, "error", ucl_builtin_create(ucl_builtin_error));
|
||||
ucl_scope_put(scope, "list", ucl_builtin_create(ucl_builtin_list));
|
||||
ucl_scope_put(scope, "setq", ucl_special_create(ucl_special_setq));
|
||||
ucl_scope_put(scope, "car", ucl_builtin_create(ucl_builtin_car));
|
||||
ucl_scope_put(scope, "cdr", ucl_builtin_create(ucl_builtin_cdr));
|
||||
ucl_scope_put(scope, "nth", ucl_builtin_create(ucl_builtin_nth));
|
||||
ucl_scope_put(scope, "mapcar", ucl_builtin_create(ucl_builtin_mapcar));
|
||||
ucl_scope_put(scope, "lambda", ucl_special_create(ucl_special_lambda));
|
||||
ucl_scope_put(scope, "quote", ucl_special_create(ucl_special_quote));
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
// TODO: Implement GC so we can clean these both up
|
||||
//ucl_object_delete(input);
|
||||
input = NULL;
|
||||
ucl_state_delete(state);
|
||||
ucl_scope_delete(scope);
|
||||
ucl_gc();
|
||||
response = NULL;
|
||||
state = NULL;
|
||||
scope = NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct ucl_object *eval (const char *code) {
|
||||
struct ucl_object *sexp = ucl_parse(code);
|
||||
return ucl_evaluate(state, ucl_car(sexp));
|
||||
return ucl_evaluate(scope, ucl_car(sexp));
|
||||
}
|
||||
|
||||
void test_simple_add(void) {
|
||||
ucl_state_put(state, "+", ucl_builtin_create(ucl_builtin_add));
|
||||
ucl_scope_put(scope, "+", ucl_builtin_create(ucl_builtin_add));
|
||||
response = eval("(+ 2 3)");
|
||||
TEST_ASSERT_OBJ_INT(response);
|
||||
TEST_ASSERT_EQUAL(response->integer, 5);
|
||||
@@ -103,7 +103,7 @@ void test_eval_string(void) {
|
||||
}
|
||||
|
||||
void test_eval_sym_defined(void) {
|
||||
ucl_state_put(state, "foo", ucl_int_create(2));
|
||||
ucl_scope_put(scope, "foo", ucl_int_create(2));
|
||||
response = eval("foo");
|
||||
TEST_ASSERT_OBJ_INT(response);
|
||||
TEST_ASSERT_EQUAL(response->integer, 2);
|
||||
|
||||
@@ -162,7 +162,7 @@ static void test_tokenize_nil(void) {
|
||||
TEST_ASSERT_NULL(token2->cell.cdr);
|
||||
}
|
||||
|
||||
static void test_tokenize_statement(void) {
|
||||
static void test_tokenize_scopement(void) {
|
||||
response = ucl_tokenize("(foo)");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
@@ -344,7 +344,7 @@ int main(void) {
|
||||
RUN_TEST(test_token_next_symbol_w_whitespace);
|
||||
RUN_TEST(test_tokenize_empty_str);
|
||||
RUN_TEST(test_tokenize_nil);
|
||||
RUN_TEST(test_tokenize_statement);
|
||||
RUN_TEST(test_tokenize_scopement);
|
||||
RUN_TEST(test_parse_atom_symbol);
|
||||
RUN_TEST(test_parse_atom_lparen);
|
||||
RUN_TEST(test_parse_atom_rparen);
|
||||
|
||||
@@ -4,38 +4,38 @@
|
||||
|
||||
#include "uclisp.h"
|
||||
#include "internal.h"
|
||||
#include "state.h"
|
||||
#include "scope.h"
|
||||
#include "utility.h"
|
||||
#include "testing_helpers.h"
|
||||
|
||||
/* static struct ucl_parse_result *result; */
|
||||
static struct ucl_state *state;
|
||||
static struct ucl_scope *scope;
|
||||
static struct ucl_object *response;
|
||||
|
||||
void setUp(void) {
|
||||
state = ucl_state_create();
|
||||
scope = ucl_scope_create();
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
ucl_state_delete(state);
|
||||
state = NULL;
|
||||
ucl_scope_delete(scope);
|
||||
scope = NULL;
|
||||
}
|
||||
|
||||
static void test_get_empty(void) {
|
||||
response = ucl_state_get(state, "foo");
|
||||
response = ucl_scope_get(scope, "foo");
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_put_get(void) {
|
||||
ucl_state_put(state, "foo", ucl_t_create());
|
||||
response = ucl_state_get(state, "foo");
|
||||
ucl_scope_put(scope, "foo", ucl_t_create());
|
||||
response = ucl_scope_get(scope, "foo");
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
static void test_put2_get(void) {
|
||||
ucl_state_put(state, "foo1", ucl_t_create());
|
||||
ucl_state_put(state, "foo2", ucl_nil_create());
|
||||
response = ucl_state_get(state, "foo1");
|
||||
ucl_scope_put(scope, "foo1", ucl_t_create());
|
||||
ucl_scope_put(scope, "foo2", ucl_nil_create());
|
||||
response = ucl_scope_get(scope, "foo1");
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ static void test_put_modify_get(void) {
|
||||
ucl_string_create("bar"),
|
||||
ucl_string_create("baz"));
|
||||
|
||||
ucl_state_put(state, "foo", obj);
|
||||
ucl_scope_put(scope, "foo", obj);
|
||||
ucl_list_append(obj, ucl_string_create("quux"));
|
||||
response = ucl_state_get(state, "foo");
|
||||
response = ucl_scope_get(scope, "foo");
|
||||
|
||||
TEST_ASSERT_OBJ_STRING(ucl_list_nth(response, 2));
|
||||
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(response, 2)->string, "quux");
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "uclisp.h"
|
||||
#include "internal.h"
|
||||
#include "utility.h"
|
||||
#include "state.h"
|
||||
#include "scope.h"
|
||||
#include "testing_helpers.h"
|
||||
|
||||
static struct ucl_object *input;
|
||||
|
||||
Reference in New Issue
Block a user