Refactor to encapsulate all state in a 'ucl'
This commit is contained in:
@@ -3,12 +3,15 @@
|
||||
|
||||
struct ucl_scope;
|
||||
struct ucl_object;
|
||||
struct ucl;
|
||||
|
||||
struct ucl_object *ucl_tokenize(const char *source);
|
||||
struct ucl_object *ucl_parse(const char *sexp);
|
||||
struct ucl_object *ucl_evaluate(struct ucl_scope *state, struct ucl_object *sexp);
|
||||
struct ucl* ucl_create(void);
|
||||
void ucl_delete(struct ucl* state);
|
||||
|
||||
// TODO: State encapsulation is all wonky here)
|
||||
void ucl_gc();
|
||||
struct ucl_object *ucl_tokenize(struct ucl* state, const char *source);
|
||||
struct ucl_object *ucl_parse(struct ucl* state, const char *sexp);
|
||||
struct ucl_object *ucl_evaluate(struct ucl* state, struct ucl_object *sexp);
|
||||
|
||||
void ucl_gc(struct ucl* ucl);
|
||||
|
||||
#endif
|
||||
|
||||
258
src/builtins.c
258
src/builtins.c
@@ -2,6 +2,7 @@
|
||||
#include "lisp.h"
|
||||
#include "builtins.h"
|
||||
#include "common.h"
|
||||
#include "scope.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
@@ -9,142 +10,142 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_type, scope, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_type, state, scope, arg) {
|
||||
switch (arg->type) {
|
||||
case UCL_TYPE_CELL:
|
||||
return ucl_symbol_create("list");
|
||||
return ucl_symbol_create(state, "list");
|
||||
case UCL_TYPE_SYMBOL:
|
||||
return ucl_symbol_create("symbol");
|
||||
return ucl_symbol_create(state, "symbol");
|
||||
case UCL_TYPE_INT:
|
||||
return ucl_symbol_create("int");
|
||||
return ucl_symbol_create(state, "int");
|
||||
case UCL_TYPE_STRING:
|
||||
return ucl_symbol_create("string");
|
||||
return ucl_symbol_create(state, "string");
|
||||
case UCL_TYPE_ERROR:
|
||||
return ucl_symbol_create("error");
|
||||
return ucl_symbol_create(state, "error");
|
||||
case UCL_TYPE_BUILTIN:
|
||||
return ucl_symbol_create("builtin");
|
||||
return ucl_symbol_create(state, "builtin");
|
||||
case UCL_TYPE_SPECIAL:
|
||||
return ucl_symbol_create("special");
|
||||
return ucl_symbol_create(state, "special");
|
||||
case UCL_TYPE_COUNT:
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return ucl_error_create("Unreachable error in 'ucl_builtin_type'");
|
||||
return ucl_error_create(state, "Unreachable error in 'ucl_builtin_type'");
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_error, scope, arg) {
|
||||
LISP_FUNC_1(ucl_builtin_error, state, scope, arg) {
|
||||
if (arg->type != UCL_TYPE_STRING) {
|
||||
return ucl_error_create("Expected type string passed to 'error'");
|
||||
return ucl_error_create(state, "Expected type string passed to 'error'");
|
||||
}
|
||||
|
||||
return ucl_error_create(arg->error);
|
||||
return ucl_error_create(state, arg->error);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_symbol_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_SYMBOL);
|
||||
LISP_FUNC_1(ucl_builtin_symbol_p, state, scope, arg) {
|
||||
return ucl_predicate(state, arg->type == UCL_TYPE_SYMBOL);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_string_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_STRING);
|
||||
LISP_FUNC_1(ucl_builtin_string_p, state, scope, arg) {
|
||||
return ucl_predicate(state, arg->type == UCL_TYPE_STRING);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_int_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_INT);
|
||||
LISP_FUNC_1(ucl_builtin_int_p, state, scope, arg) {
|
||||
return ucl_predicate(state, arg->type == UCL_TYPE_INT);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_list_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_CELL);
|
||||
LISP_FUNC_1(ucl_builtin_list_p, state, scope, arg) {
|
||||
return ucl_predicate(state, arg->type == UCL_TYPE_CELL);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_error_p, scope, arg) {
|
||||
return ucl_predicate(arg->type == UCL_TYPE_ERROR);
|
||||
LISP_FUNC_1(ucl_builtin_error_p, state, scope, arg) {
|
||||
return ucl_predicate(state, arg->type == UCL_TYPE_ERROR);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_car, scope, arg) {
|
||||
return ucl_car(arg);
|
||||
LISP_FUNC_1(ucl_builtin_car, state, scope, arg) {
|
||||
return ucl_car(state, arg);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_cdr, scope, arg) {
|
||||
return ucl_cdr(arg);
|
||||
LISP_FUNC_1(ucl_builtin_cdr, state, scope, arg) {
|
||||
return ucl_cdr(state, arg);
|
||||
}
|
||||
|
||||
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");
|
||||
LISP_FUNC_2(ucl_builtin_nth, state, scope, n, list) {
|
||||
UCL_COND_OR_RET_ERROR(state, n->type == UCL_TYPE_INT, "First argument to nth must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(state, list->type == UCL_TYPE_CELL, "Second argument to nth must be a list");
|
||||
|
||||
return ucl_list_nth(list, n->integer);
|
||||
return ucl_list_nth(state, list, n->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_add, scope, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_add, state, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'add'");
|
||||
return ucl_error_create(state, "Invalid type of argument 0 to 'add'");
|
||||
}
|
||||
|
||||
if (arg1->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 1 to 'add'");
|
||||
return ucl_error_create(state, "Invalid type of argument 1 to 'add'");
|
||||
}
|
||||
|
||||
return ucl_int_create(arg0->integer + arg1->integer);
|
||||
return ucl_int_create(state, arg0->integer + arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_sub, scope, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_sub, state, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'sub'");
|
||||
return ucl_error_create(state, "Invalid type of argument 0 to 'sub'");
|
||||
}
|
||||
|
||||
if (arg1->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create(("Invalid type of argument 1 to 'sub'"));
|
||||
return ucl_error_create(state, ("Invalid type of argument 1 to 'sub'"));
|
||||
}
|
||||
|
||||
return ucl_int_create(arg0->integer - arg1->integer);
|
||||
return ucl_int_create(state, arg0->integer - arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_mul, scope, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_mul, state, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'mul'");
|
||||
return ucl_error_create(state, "Invalid type of argument 0 to 'mul'");
|
||||
}
|
||||
|
||||
if (arg1->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 1 to 'mul'");
|
||||
return ucl_error_create(state, "Invalid type of argument 1 to 'mul'");
|
||||
}
|
||||
|
||||
return ucl_int_create(arg0->integer * arg1->integer);
|
||||
return ucl_int_create(state, arg0->integer * arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_div, scope, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_div, state, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'div'");
|
||||
return ucl_error_create(state, "Invalid type of argument 0 to 'div'");
|
||||
}
|
||||
|
||||
if (arg1->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 1 to 'div'");
|
||||
return ucl_error_create(state, "Invalid type of argument 1 to 'div'");
|
||||
}
|
||||
|
||||
UCL_COND_OR_RET_ERROR(arg1->integer != 0, "Division by zero");
|
||||
return ucl_int_create(arg0->integer / arg1->integer);
|
||||
UCL_COND_OR_RET_ERROR(state, arg1->integer != 0, "Division by zero");
|
||||
return ucl_int_create(state, arg0->integer / arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_mod, scope, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_mod, state, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'mod'");
|
||||
return ucl_error_create(state, "Invalid type of argument 0 to 'mod'");
|
||||
}
|
||||
|
||||
if (arg1->type != UCL_TYPE_INT) {
|
||||
return ucl_error_create("Invalid type of argument 1 to 'mod'");
|
||||
return ucl_error_create(state, "Invalid type of argument 1 to 'mod'");
|
||||
}
|
||||
|
||||
return ucl_int_create(arg0->integer % arg1->integer);
|
||||
return ucl_int_create(state, arg0->integer % arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_concat, scope, arg0, arg1) {
|
||||
LISP_FUNC_2(ucl_builtin_concat, state, scope, arg0, arg1) {
|
||||
if (arg0->type != UCL_TYPE_STRING) {
|
||||
return ucl_error_create("Invalid type of argument 0 to 'concat'");
|
||||
return ucl_error_create(state, "Invalid type of argument 0 to 'concat'");
|
||||
}
|
||||
|
||||
if (arg1->type != UCL_TYPE_STRING) {
|
||||
return ucl_error_create("Invalid type of argument 1 to 'concat'");
|
||||
return ucl_error_create(state, "Invalid type of argument 1 to 'concat'");
|
||||
}
|
||||
|
||||
int len = strlen(arg0->string) + strlen(arg1->string);
|
||||
@@ -153,120 +154,167 @@ LISP_FUNC_2(ucl_builtin_concat, scope, arg0, arg1) {
|
||||
strcat(outstr, arg0->string);
|
||||
strcat(outstr, arg1->string);
|
||||
|
||||
struct ucl_object *result = ucl_string_create(outstr);
|
||||
struct ucl_object *result = ucl_string_create(state, outstr);
|
||||
free(outstr);
|
||||
return result;
|
||||
}
|
||||
|
||||
LISP_FUNC_0(ucl_builtin_now_millis_mono, scope) {
|
||||
LISP_FUNC_0(ucl_builtin_now_millis_mono, state, scope) {
|
||||
// TODO: Implement and move to a 'platform' file
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_print, scope, arg0) {
|
||||
LISP_FUNC_1(ucl_builtin_print, state, scope, arg0) {
|
||||
ucl_print_obj(arg0);
|
||||
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_printl, scope, arg0) {
|
||||
LISP_FUNC_1(ucl_builtin_printl, state, scope, arg0) {
|
||||
ucl_print_obj(arg0);
|
||||
printf("\n");
|
||||
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_builtin_list(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *head = ucl_nil_create();
|
||||
struct ucl_object *ucl_builtin_list(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *head = ucl_nil_create(state);
|
||||
FOREACH_LIST(args, iter, item) {
|
||||
ucl_list_append(head, item);
|
||||
ucl_list_append(state, head, item);
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_mapcar, scope, fun, elems) {
|
||||
LISP_FUNC_2(ucl_builtin_mapcar, state, scope, fun, elems) {
|
||||
// TODO: Support arbitrary number of 'elems' lists
|
||||
struct ucl_object *result = ucl_nil_create();
|
||||
struct ucl_object *result = ucl_nil_create(state);
|
||||
FOREACH_LIST(elems, iter, elem) {
|
||||
struct ucl_object *form = ucl_tuple_create(fun, elem);
|
||||
struct ucl_object *value = ucl_evaluate(scope, form);
|
||||
struct ucl_object *form = ucl_tuple_create(state, fun, elem);
|
||||
struct ucl_object *value = ucl_evaluate_in_scope(state, scope, form);
|
||||
UCL_RET_IF_ERROR(value);
|
||||
ucl_list_append(result, value);
|
||||
ucl_list_append(state, result, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_filter, scope, predicate, elems) {
|
||||
LISP_FUNC_2(ucl_builtin_filter, state, scope, predicate, elems) {
|
||||
// TODO: Support arbitrary number of 'elems' lists
|
||||
struct ucl_object *result = ucl_nil_create();
|
||||
struct ucl_object *result = ucl_nil_create(state);
|
||||
struct ucl_object *result_tail = result;
|
||||
FOREACH_LIST(elems, iter, elem) {
|
||||
struct ucl_object *form = ucl_tuple_create(predicate, elem);
|
||||
struct ucl_object *value = ucl_evaluate(scope, form);
|
||||
struct ucl_object *form = ucl_tuple_create(state, predicate, elem);
|
||||
struct ucl_object *value = ucl_evaluate_in_scope(state, scope, form);
|
||||
UCL_RET_IF_ERROR(value);
|
||||
if (ucl_truthy_bool(value)) {
|
||||
result_tail = ucl_list_append(result_tail, elem);
|
||||
result_tail = ucl_list_append(state, result_tail, elem);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LISP_FUNC_3(ucl_builtin_reduce, scope, fun, elems, initial_value) {
|
||||
LISP_FUNC_3(ucl_builtin_reduce, state, scope, fun, elems, initial_value) {
|
||||
// TODO: Support arbitrary number of 'elems' lists
|
||||
struct ucl_object *result = initial_value;
|
||||
FOREACH_LIST(elems, iter, elem) {
|
||||
struct ucl_object *form = ucl_tuple_create(fun, elem);
|
||||
ucl_list_append(form, result);
|
||||
result = ucl_evaluate(scope, form);
|
||||
struct ucl_object *form = ucl_tuple_create(state, fun, elem);
|
||||
ucl_list_append(state, form, result);
|
||||
result = ucl_evaluate_in_scope(state, scope, form);
|
||||
UCL_RET_IF_ERROR(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_equal, scope, arg0, arg1) {
|
||||
return ucl_equal(arg0, arg1);
|
||||
LISP_FUNC_2(ucl_builtin_equal, state, scope, arg0, arg1) {
|
||||
return ucl_equal(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_gt, state, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "First argument to > must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "Second argument to > must be an integer");
|
||||
return ucl_predicate(state, arg0->integer > arg1->integer);
|
||||
}
|
||||
|
||||
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_ge, state, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "First argument to >= must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "Second argument to >= must be an integer");
|
||||
return ucl_predicate(state, arg0->integer > arg1->integer);
|
||||
}
|
||||
|
||||
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_lt, state, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "First argument to < must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "Second argument to < must be an integer");
|
||||
return ucl_predicate(state, arg0->integer < arg1->integer);
|
||||
}
|
||||
|
||||
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_le, state, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "First argument to <= must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "Second argument to <= must be an integer");
|
||||
return ucl_predicate(state, arg0->integer < arg1->integer);
|
||||
}
|
||||
|
||||
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_num_eq, state, scope, arg0, arg1) {
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "First argument to = must be an integer");
|
||||
UCL_COND_OR_RET_ERROR(state, arg0->type == UCL_TYPE_INT, "Second argument to = must be an integer");
|
||||
return ucl_predicate(state, arg0->integer == arg1->integer);
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_xor, scope, arg0, arg1) {
|
||||
return ucl_predicate(ucl_truthy_bool(arg0) || ucl_truthy_bool(arg1));
|
||||
LISP_FUNC_2(ucl_builtin_xor, state, scope, arg0, arg1) {
|
||||
return ucl_predicate(state, ucl_truthy_bool(arg0) || ucl_truthy_bool(arg1));
|
||||
}
|
||||
|
||||
LISP_FUNC_1(ucl_builtin_not, scope, arg0) {
|
||||
return ucl_predicate(!ucl_truthy_bool(arg0));
|
||||
LISP_FUNC_1(ucl_builtin_not, state, scope, arg0) {
|
||||
return ucl_predicate(state, !ucl_truthy_bool(arg0));
|
||||
}
|
||||
|
||||
LISP_FUNC_2(ucl_builtin_append, scope, list, elem) {
|
||||
ucl_list_append(list, elem);
|
||||
LISP_FUNC_2(ucl_builtin_append, state, scope, list, elem) {
|
||||
ucl_list_append(state, list, elem);
|
||||
return list;
|
||||
}
|
||||
|
||||
// TODO: publicize
|
||||
static void ucl_add_builtin(struct ucl* ucl, const char *name, ucl_lisp fun) {
|
||||
ucl_scope_put(ucl, ucl->global_scope, name, ucl_builtin_create(ucl, fun));
|
||||
}
|
||||
|
||||
void ucl_add_builtins(struct ucl* state) {
|
||||
ucl_add_builtin(state, "print", ucl_builtin_print);
|
||||
ucl_add_builtin(state, "printl", ucl_builtin_printl);
|
||||
// TODO:
|
||||
// - object -> string
|
||||
// - formatted printing?
|
||||
|
||||
ucl_add_builtin(state, "+", ucl_builtin_add);
|
||||
ucl_add_builtin(state, "-", ucl_builtin_sub);
|
||||
ucl_add_builtin(state, "*", ucl_builtin_mul);
|
||||
ucl_add_builtin(state, "/", ucl_builtin_div);
|
||||
ucl_add_builtin(state, "%", ucl_builtin_mod);
|
||||
ucl_add_builtin(state, ">", ucl_builtin_gt);
|
||||
ucl_add_builtin(state, ">=", ucl_builtin_ge);
|
||||
ucl_add_builtin(state, "<", ucl_builtin_lt);
|
||||
ucl_add_builtin(state, "<=", ucl_builtin_le);
|
||||
ucl_add_builtin(state, "=", ucl_builtin_num_eq);
|
||||
ucl_add_builtin(state, "not", ucl_builtin_not);
|
||||
ucl_add_builtin(state, "xor", ucl_builtin_xor);
|
||||
// TODO:
|
||||
// - Floats or nah?
|
||||
|
||||
ucl_add_builtin(state, "concat", ucl_builtin_concat);
|
||||
|
||||
ucl_add_builtin(state, "error", ucl_builtin_error);
|
||||
ucl_add_builtin(state, "type", ucl_builtin_type);
|
||||
ucl_add_builtin(state, "symbol-p", ucl_builtin_symbol_p);
|
||||
ucl_add_builtin(state, "string-p", ucl_builtin_string_p);
|
||||
ucl_add_builtin(state, "int-p", ucl_builtin_int_p);
|
||||
ucl_add_builtin(state, "list-p", ucl_builtin_list_p);
|
||||
|
||||
ucl_add_builtin(state, "list", ucl_builtin_list);
|
||||
ucl_add_builtin(state, "car", ucl_builtin_car);
|
||||
ucl_add_builtin(state, "cdr", ucl_builtin_cdr);
|
||||
ucl_add_builtin(state, "nth", ucl_builtin_nth);
|
||||
ucl_add_builtin(state, "mapcar", ucl_builtin_mapcar);
|
||||
ucl_add_builtin(state, "filter", ucl_builtin_filter);
|
||||
ucl_add_builtin(state, "reduce", ucl_builtin_reduce);
|
||||
ucl_add_builtin(state, "equal", ucl_builtin_equal);
|
||||
ucl_add_builtin(state, "append", ucl_builtin_append);
|
||||
}
|
||||
|
||||
@@ -1,44 +1 @@
|
||||
#ifndef _UCLISP_BUILTINS_H_
|
||||
#define _UCLISP_BUILTINS_H_
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
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_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_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_scope *scope, 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_filter(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_reduce(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_builtin_append(struct ucl_scope *scope, 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);
|
||||
|
||||
struct ucl_object *ucl_builtin_equal(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define UCL_COND_OR_RET_ERROR(cond, msg) \
|
||||
#define UCL_COND_OR_RET_ERROR(ucl, cond, msg) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
return ucl_error_create(msg); \
|
||||
return ucl_error_create(ucl, msg); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
@@ -7,78 +7,78 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct ucl_object *ucl_evaluate_builtin_form(struct ucl_scope *scope, struct ucl_object *list) {
|
||||
struct ucl_object *ucl_evaluate_builtin_form(struct ucl *state, struct ucl_scope *scope, struct ucl_object *list) {
|
||||
// TODO: Reasonably split builtin and non-builtin evaluation
|
||||
struct ucl_object *evaluated_list = ucl_nil_create();
|
||||
struct ucl_object *evaluated_list = ucl_nil_create(state);
|
||||
struct ucl_object *evaluated_list_tail = evaluated_list;
|
||||
|
||||
FOREACH_LIST(list, iter, item) {
|
||||
struct ucl_object *obj = ucl_evaluate(scope, item);
|
||||
struct ucl_object *obj = ucl_evaluate_in_scope(state, scope, item);
|
||||
UCL_RET_IF_ERROR(obj);
|
||||
evaluated_list_tail = ucl_list_append(evaluated_list_tail, obj);
|
||||
evaluated_list_tail = ucl_list_append(state, evaluated_list_tail, obj);
|
||||
};
|
||||
|
||||
struct ucl_object *fun = ucl_car(evaluated_list);
|
||||
struct ucl_object *fun = ucl_car(state, evaluated_list);
|
||||
struct ucl_object *result = NULL;
|
||||
|
||||
if (fun->type == UCL_TYPE_BUILTIN) {
|
||||
struct ucl_object *args = ucl_cdr(evaluated_list);
|
||||
result = fun->builtin(scope, args);
|
||||
struct ucl_object *args = ucl_cdr(state, evaluated_list);
|
||||
result = fun->builtin(state, scope, args);
|
||||
} else if (fun->type == UCL_TYPE_CELL) {
|
||||
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);
|
||||
struct ucl_scope *fun_scope = ucl_scope_create_child(state, scope);
|
||||
struct ucl_object *fun_arg_syms = ucl_car(state, fun);
|
||||
struct ucl_object *fun_forms = ucl_cdr(state, fun);
|
||||
int i = 0;
|
||||
FOREACH_LIST(fun_arg_syms, iter, sym) {
|
||||
ucl_scope_put(fun_scope, sym->symbol, ucl_list_nth(evaluated_list, i + 1));
|
||||
ucl_scope_put(state, fun_scope, sym->symbol, ucl_list_nth(state, evaluated_list, i + 1));
|
||||
i++;
|
||||
}
|
||||
result = ucl_progn(fun_scope, fun_forms);
|
||||
ucl_scope_delete(fun_scope);
|
||||
result = ucl_progn(state, fun_scope, fun_forms);
|
||||
ucl_scope_delete(state, fun_scope);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return (result == NULL) ? ucl_nil_create() : result;
|
||||
return (result == NULL) ? ucl_nil_create(state) : result;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_evaluate_special_form(struct ucl_scope *scope, struct ucl_object *list) {
|
||||
const char *fun_sym = ucl_car(list)->symbol;
|
||||
struct ucl_object *ucl_evaluate_special_form(struct ucl* state, struct ucl_scope *scope, struct ucl_object *list) {
|
||||
const char *fun_sym = ucl_car(state, list)->symbol;
|
||||
|
||||
struct ucl_object *fun = ucl_scope_get(scope, fun_sym);
|
||||
struct ucl_object *args = ucl_cdr(list);
|
||||
struct ucl_object *fun = ucl_scope_get(state, scope, fun_sym);
|
||||
struct ucl_object *args = ucl_cdr(state, list);
|
||||
struct ucl_object *result = NULL;
|
||||
|
||||
result = fun->special(scope, args);
|
||||
result = fun->special(state, scope, args);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_evaluate_list(struct ucl_scope *scope, struct ucl_object *list) {
|
||||
struct ucl_object *ucl_evaluate_list(struct ucl* state, struct ucl_scope *scope, struct ucl_object *list) {
|
||||
if (list->cell.car == NULL) {
|
||||
return list;
|
||||
}
|
||||
|
||||
struct ucl_object *fun = ucl_evaluate(scope, ucl_car(list));
|
||||
struct ucl_object *fun = ucl_evaluate_in_scope(state, scope, ucl_car(state, list));
|
||||
UCL_RET_IF_ERROR(fun);
|
||||
|
||||
if (fun->type == UCL_TYPE_SPECIAL) {
|
||||
return ucl_evaluate_special_form(scope, list);
|
||||
return ucl_evaluate_special_form(state, scope, list);
|
||||
} else if (fun->type == UCL_TYPE_BUILTIN || fun->type == UCL_TYPE_CELL) {
|
||||
return ucl_evaluate_builtin_form(scope, list);
|
||||
return ucl_evaluate_builtin_form(state, scope, list);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_evaluate(struct ucl_scope *scope, struct ucl_object *obj) {
|
||||
struct ucl_object *ucl_evaluate_in_scope(struct ucl *state, struct ucl_scope *scope, struct ucl_object *obj) {
|
||||
assert(obj != NULL);
|
||||
|
||||
switch (obj->type) {
|
||||
case UCL_TYPE_CELL:
|
||||
return ucl_evaluate_list(scope, obj);
|
||||
return ucl_evaluate_list(state, scope, obj);
|
||||
case UCL_TYPE_SYMBOL:
|
||||
return ucl_scope_get(scope, obj->symbol);
|
||||
return ucl_scope_get(state, scope, obj->symbol);
|
||||
case UCL_TYPE_INT:
|
||||
case UCL_TYPE_STRING:
|
||||
case UCL_TYPE_ERROR:
|
||||
@@ -91,5 +91,9 @@ struct ucl_object *ucl_evaluate(struct ucl_scope *scope, struct ucl_object *obj)
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return ucl_error_create("Unreachable error in ucl_evaluate");
|
||||
return ucl_error_create(state, "Unreachable error in ucl_evaluate");
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_evaluate(struct ucl *state, struct ucl_object *obj) {
|
||||
return ucl_evaluate_in_scope(state, state->global_scope, obj);
|
||||
}
|
||||
|
||||
58
src/lisp.h
58
src/lisp.h
@@ -3,65 +3,65 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define LISP_FUNC_0(func_name, scope_name) \
|
||||
static struct ucl_object *func_name##_impl(); \
|
||||
struct ucl_object *func_name(struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
#define LISP_FUNC_0(func_name, ucl_name, scope_name) \
|
||||
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope); \
|
||||
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
if (args->cell.car != NULL) { \
|
||||
return NULL; \
|
||||
} \
|
||||
return func_name##_impl(scope_name); \
|
||||
return func_name##_impl(ucl, scope); \
|
||||
} \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope)
|
||||
static struct ucl_object *func_name##_impl(struct ucl *ucl_name, struct ucl_scope *scope)
|
||||
|
||||
#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); \
|
||||
#define LISP_FUNC_1(func_name, ucl_name, scope_name, arg0_name) \
|
||||
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name); \
|
||||
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
struct ucl_object *len_obj = ucl_list_length(ucl, args); \
|
||||
if (len_obj->type != UCL_TYPE_INT) { \
|
||||
return NULL; \
|
||||
} \
|
||||
if (len_obj->integer != 1) { \
|
||||
return NULL; \
|
||||
} \
|
||||
struct ucl_object *arg0 = ucl_car(args); \
|
||||
return func_name##_impl(scope_name, arg0); \
|
||||
struct ucl_object *arg0 = ucl_car(ucl, args); \
|
||||
return func_name##_impl(ucl, scope_name, arg0); \
|
||||
} \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name)
|
||||
static struct ucl_object *func_name##_impl(struct ucl* ucl_name, 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, 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); \
|
||||
#define LISP_FUNC_2(func_name, ucl_name, scope_name, arg0_name, arg1_name) \
|
||||
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name); \
|
||||
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
struct ucl_object *len_obj = ucl_list_length(ucl, args); \
|
||||
if (len_obj->type != UCL_TYPE_INT) { \
|
||||
return NULL; \
|
||||
} \
|
||||
if (len_obj->integer != 2) { \
|
||||
return NULL; \
|
||||
} \
|
||||
struct ucl_object *arg0 = ucl_list_nth(args, 0); \
|
||||
struct ucl_object *arg1 = ucl_list_nth(args, 1); \
|
||||
return func_name##_impl(scope_name, arg0, arg1); \
|
||||
struct ucl_object *arg0 = ucl_list_nth(ucl, args, 0); \
|
||||
struct ucl_object *arg1 = ucl_list_nth(ucl, args, 1); \
|
||||
return func_name##_impl(ucl, scope, arg0, arg1); \
|
||||
} \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name)
|
||||
static struct ucl_object *func_name##_impl(struct ucl *ucl_name, struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name)
|
||||
|
||||
// TODO: Unroll the args more efficiently, this is O(n^2)
|
||||
#define LISP_FUNC_3(func_name, scope_name, arg0_name, arg1_name, arg2_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 *arg2_name); \
|
||||
struct ucl_object *func_name(struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
struct ucl_object *len_obj = ucl_list_length(args); \
|
||||
#define LISP_FUNC_3(func_name, ucl_name, scope_name, arg0_name, arg1_name, arg2_name) \
|
||||
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name); \
|
||||
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
||||
struct ucl_object *len_obj = ucl_list_length(ucl, args); \
|
||||
if (len_obj->type != UCL_TYPE_INT) { \
|
||||
return NULL; \
|
||||
} \
|
||||
if (len_obj->integer != 3) { \
|
||||
return NULL; \
|
||||
} \
|
||||
struct ucl_object *arg0 = ucl_list_nth(args, 0); \
|
||||
struct ucl_object *arg1 = ucl_list_nth(args, 1); \
|
||||
struct ucl_object *arg2 = ucl_list_nth(args, 2); \
|
||||
return func_name##_impl(scope_name, arg0, arg1, arg2); \
|
||||
struct ucl_object *arg0 = ucl_list_nth(ucl, args, 0); \
|
||||
struct ucl_object *arg1 = ucl_list_nth(ucl, args, 1); \
|
||||
struct ucl_object *arg2 = ucl_list_nth(ucl, args, 2); \
|
||||
return func_name##_impl(ucl, scope, arg0, arg1, arg2); \
|
||||
} \
|
||||
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name)
|
||||
static struct ucl_object *func_name##_impl(struct ucl* ucl_name, struct ucl_scope *scope_name, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
65
src/main.c
65
src/main.c
@@ -17,61 +17,8 @@
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
(void) argc, (void) argv;
|
||||
struct ucl_scope *scope = ucl_scope_create();
|
||||
|
||||
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));
|
||||
|
||||
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_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_scope_put(scope, "concat", ucl_builtin_create(ucl_builtin_concat));
|
||||
|
||||
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_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, "filter", ucl_builtin_create(ucl_builtin_filter));
|
||||
ucl_scope_put(scope, "reduce", ucl_builtin_create(ucl_builtin_reduce));
|
||||
ucl_scope_put(scope, "equal", ucl_builtin_create(ucl_builtin_equal));
|
||||
ucl_scope_put(scope, "append", ucl_builtin_create(ucl_builtin_append));
|
||||
|
||||
ucl_scope_put(scope, "dotimes", ucl_special_create(ucl_special_dotimes));
|
||||
ucl_scope_put(scope, "dolist", ucl_special_create(ucl_special_dolist));
|
||||
ucl_scope_put(scope, "while", ucl_special_create(ucl_special_while));
|
||||
struct ucl *ucl = ucl_create();
|
||||
|
||||
if (argc < 2) {
|
||||
while (1) {
|
||||
@@ -87,22 +34,22 @@ int main(int argc, const char **argv) {
|
||||
#else
|
||||
// TODO
|
||||
#endif
|
||||
struct ucl_object *sexp = ucl_parse(line);
|
||||
struct ucl_object *sexp = ucl_parse(ucl, line);
|
||||
struct ucl_object *result = NULL;
|
||||
if (sexp->type == UCL_TYPE_ERROR) {
|
||||
result = sexp;
|
||||
} else {
|
||||
result = ucl_evaluate(scope, ucl_car(sexp));
|
||||
result = ucl_evaluate(ucl, ucl_car(ucl, sexp));
|
||||
}
|
||||
ucl_print_obj(result);
|
||||
printf("\n");
|
||||
|
||||
free(line);
|
||||
ucl_gc();
|
||||
ucl_gc(ucl);
|
||||
}
|
||||
} else {
|
||||
struct ucl_object *sexp = ucl_parse(argv[1]);
|
||||
struct ucl_object *result = ucl_evaluate(scope, ucl_car(sexp));
|
||||
struct ucl_object *sexp = ucl_parse(ucl, argv[1]);
|
||||
struct ucl_object *result = ucl_evaluate(ucl, ucl_car(ucl, sexp));
|
||||
|
||||
if (result->type == UCL_TYPE_ERROR) {
|
||||
printf("%s", result->error);
|
||||
|
||||
78
src/memory.c
78
src/memory.c
@@ -1,8 +1,7 @@
|
||||
#include "uclisp.h"
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "arena.h"
|
||||
|
||||
// TODO: Fix weird structuring of arena locations
|
||||
#include "utility.h"
|
||||
#include "scope.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -22,10 +21,7 @@
|
||||
|
||||
static struct ucl_object *ucl_object_alloc();
|
||||
|
||||
static struct ucl_arena *object_arena = NULL;
|
||||
extern struct ucl_arena *scope_arena;
|
||||
|
||||
struct ucl_object *ucl_cell_create(struct ucl_object *car, struct ucl_object *cdr)
|
||||
struct ucl_object *ucl_cell_create(struct ucl *ucl, struct ucl_object *car, struct ucl_object *cdr)
|
||||
{
|
||||
struct ucl_object* obj = ucl_object_alloc();
|
||||
obj->type = UCL_TYPE_CELL;
|
||||
@@ -34,7 +30,7 @@ struct ucl_object *ucl_cell_create(struct ucl_object *car, struct ucl_object *cd
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_int_create(int integer)
|
||||
struct ucl_object *ucl_int_create(struct ucl *ucl, int integer)
|
||||
{
|
||||
struct ucl_object* obj = ucl_object_alloc();
|
||||
obj->type = UCL_TYPE_INT;
|
||||
@@ -42,7 +38,7 @@ struct ucl_object *ucl_int_create(int integer)
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_symbol_create(const char *symbol)
|
||||
struct ucl_object *ucl_symbol_create(struct ucl* ucl, const char *symbol)
|
||||
{
|
||||
struct ucl_object* obj = ucl_object_alloc();
|
||||
obj->type = UCL_TYPE_SYMBOL;
|
||||
@@ -50,7 +46,7 @@ struct ucl_object *ucl_symbol_create(const char *symbol)
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_string_create(const char *string)
|
||||
struct ucl_object *ucl_string_create(struct ucl* ucl, const char *string)
|
||||
{
|
||||
struct ucl_object* obj = ucl_object_alloc();
|
||||
obj->type = UCL_TYPE_STRING;
|
||||
@@ -58,7 +54,7 @@ struct ucl_object *ucl_string_create(const char *string)
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_error_create(const char *error)
|
||||
struct ucl_object *ucl_error_create(struct ucl* ucl, const char *error)
|
||||
{
|
||||
struct ucl_object* obj = ucl_object_alloc();
|
||||
obj->type = UCL_TYPE_ERROR;
|
||||
@@ -67,7 +63,7 @@ struct ucl_object *ucl_error_create(const char *error)
|
||||
}
|
||||
|
||||
|
||||
struct ucl_object *ucl_builtin_create(ucl_lisp builtin)
|
||||
struct ucl_object *ucl_builtin_create(struct ucl* ucl, ucl_lisp builtin)
|
||||
{
|
||||
struct ucl_object* obj = ucl_object_alloc();
|
||||
obj->type = UCL_TYPE_BUILTIN;
|
||||
@@ -75,7 +71,7 @@ struct ucl_object *ucl_builtin_create(ucl_lisp builtin)
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_create(ucl_lisp special)
|
||||
struct ucl_object *ucl_special_create(struct ucl* ucl, ucl_lisp special)
|
||||
{
|
||||
struct ucl_object* obj = ucl_object_alloc();
|
||||
obj->type = UCL_TYPE_SPECIAL;
|
||||
@@ -84,25 +80,20 @@ struct ucl_object *ucl_special_create(ucl_lisp special)
|
||||
}
|
||||
|
||||
|
||||
static struct ucl_object* ucl_object_alloc() {
|
||||
if (object_arena == NULL) {
|
||||
object_arena = ucl_arena_create(sizeof(struct ucl_object), UCL_OBJECT_ARENA_SIZE);
|
||||
}
|
||||
struct ucl_object *obj = ucl_arena_get(object_arena);
|
||||
static struct ucl_object* ucl_object_alloc(struct ucl* ucl) {
|
||||
struct ucl_object *obj = ucl_arena_get(ucl->obj_arena);
|
||||
assert(obj != NULL);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void ucl_object_delete(struct ucl_object *obj) {
|
||||
static void ucl_object_delete_internal(struct ucl_arena* obj_arena, struct ucl_object *obj) {
|
||||
if (obj == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (obj->type) {
|
||||
case UCL_TYPE_CELL:
|
||||
//ucl_object_delete(obj->cell.car);
|
||||
obj->cell.car = NULL;
|
||||
//ucl_object_delete(obj->cell.cdr);
|
||||
obj->cell.cdr = NULL;
|
||||
break;
|
||||
case UCL_TYPE_SYMBOL:
|
||||
@@ -124,7 +115,11 @@ void ucl_object_delete(struct ucl_object *obj) {
|
||||
break;
|
||||
}
|
||||
|
||||
ucl_arena_put(object_arena, obj);
|
||||
ucl_arena_put(obj_arena, obj);
|
||||
}
|
||||
|
||||
void ucl_object_delete(struct ucl* state, struct ucl_object *obj) {
|
||||
ucl_object_delete_internal(state->obj_arena, obj);
|
||||
}
|
||||
|
||||
static void ucl_object_mark(struct ucl_object *obj) {
|
||||
@@ -156,28 +151,35 @@ static void ucl_gc_sweep(struct ucl_arena * arena, void *obj) {
|
||||
(void) arena;
|
||||
struct ucl_object *object = (struct ucl_object *) obj;
|
||||
if (object->reachable == 0) {
|
||||
ucl_object_delete(object);
|
||||
ucl_object_delete_internal(arena, object);
|
||||
}
|
||||
}
|
||||
|
||||
static void ucl_gc_deleteall(struct ucl_arena * arena, void *obj) {
|
||||
(void) arena;
|
||||
struct ucl_object *object = (struct ucl_object *) obj;
|
||||
ucl_object_delete(object);
|
||||
}
|
||||
// TODO: Implement full cleanup
|
||||
/* static void ucl_gc_deleteall(struct ucl_arena * arena, void *obj) { */
|
||||
/* (void) arena; */
|
||||
/* struct ucl_object *object = (struct ucl_object *) obj; */
|
||||
/* ucl_object_delete_internal(arena, object); */
|
||||
/* } */
|
||||
|
||||
|
||||
void ucl_gc() {
|
||||
if (object_arena == NULL) {
|
||||
return;
|
||||
void ucl_gc(struct ucl* ucl) {
|
||||
// TODO: Implement scope cleanup
|
||||
|
||||
ucl_arena_map(ucl->obj_arena, ucl_gc_unmark);
|
||||
ucl_arena_map(ucl->scope_arena, ucl_scope_mark);
|
||||
ucl_arena_map(ucl->obj_arena, ucl_gc_sweep);
|
||||
}
|
||||
|
||||
if (scope_arena != NULL) {
|
||||
ucl_arena_map(object_arena, ucl_gc_unmark);
|
||||
ucl_arena_map(scope_arena, ucl_scope_mark);
|
||||
ucl_arena_map(object_arena, ucl_gc_sweep);
|
||||
} else {
|
||||
ucl_arena_map(object_arena, ucl_gc_deleteall);
|
||||
}
|
||||
struct ucl *ucl_create() {
|
||||
struct ucl *ucl = malloc(sizeof(*ucl));
|
||||
|
||||
ucl->obj_arena = ucl_arena_create(sizeof(struct ucl_object), 1 << 16);
|
||||
ucl->scope_arena = ucl_arena_create(sizeof(struct ucl_scope), 64);
|
||||
ucl->global_scope = ucl_scope_create(ucl);
|
||||
|
||||
ucl_add_builtins(ucl);
|
||||
ucl_add_specials(ucl);
|
||||
|
||||
return ucl;
|
||||
}
|
||||
|
||||
16
src/memory.h
16
src/memory.h
@@ -3,14 +3,14 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct ucl_object *ucl_cell_create(struct ucl_object *car, struct ucl_object *cdr);
|
||||
struct ucl_object *ucl_int_create(int integer);
|
||||
struct ucl_object *ucl_symbol_create(const char* symbol);
|
||||
struct ucl_object *ucl_string_create(const char* string);
|
||||
struct ucl_object *ucl_error_create(const char* error);
|
||||
struct ucl_object *ucl_builtin_create(ucl_lisp builtin);
|
||||
struct ucl_object *ucl_special_create(ucl_lisp special);
|
||||
struct ucl_object *ucl_cell_create(struct ucl* ucl, struct ucl_object *car, struct ucl_object *cdr);
|
||||
struct ucl_object *ucl_int_create(struct ucl* ucl, int integer);
|
||||
struct ucl_object *ucl_symbol_create(struct ucl* ucl, const char* symbol);
|
||||
struct ucl_object *ucl_string_create(struct ucl* ucl, const char* string);
|
||||
struct ucl_object *ucl_error_create(struct ucl* ucl, const char* error);
|
||||
struct ucl_object *ucl_builtin_create(struct ucl* ucl, ucl_lisp builtin);
|
||||
struct ucl_object *ucl_special_create(struct ucl* ucl, ucl_lisp special);
|
||||
|
||||
void ucl_object_delete(struct ucl_object *obj);
|
||||
void ucl_object_delete(struct ucl* ucl, struct ucl_object *obj);
|
||||
|
||||
#endif
|
||||
|
||||
64
src/parse.c
64
src/parse.c
@@ -36,7 +36,7 @@ static bool ucl_is_delimiter(char c) {
|
||||
return ucl_is_whitespace(c) || ucl_is_token(c) || c == '\0';
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_token_next(const char **curr_src) {
|
||||
struct ucl_object *ucl_token_next(struct ucl* state, const char **curr_src) {
|
||||
assert(*curr_src != NULL);
|
||||
const char *start = *curr_src;
|
||||
|
||||
@@ -57,7 +57,7 @@ struct ucl_object *ucl_token_next(const char **curr_src) {
|
||||
str[0] = **curr_src;
|
||||
str[1] = '\0';
|
||||
(*curr_src)++;
|
||||
return ucl_symbol_create(str);
|
||||
return ucl_symbol_create(state, str);
|
||||
case QUOTE_CHAR:
|
||||
// skip beginning quote
|
||||
(*curr_src)++;
|
||||
@@ -70,7 +70,7 @@ struct ucl_object *ucl_token_next(const char **curr_src) {
|
||||
// -2 for removing start/end quotes
|
||||
str = strndup(start + 1, *curr_src - start - 2);
|
||||
// TODO: free
|
||||
return ucl_string_create(str);
|
||||
return ucl_string_create(state, str);
|
||||
case '-':
|
||||
case '+':
|
||||
case '0'...'9': {
|
||||
@@ -83,9 +83,9 @@ struct ucl_object *ucl_token_next(const char **curr_src) {
|
||||
|
||||
*curr_src = end;
|
||||
if (!ucl_is_delimiter(*end)) {
|
||||
return ucl_error_create("Integer value contained non-digits");
|
||||
return ucl_error_create(state, "Integer value contained non-digits");
|
||||
}
|
||||
return ucl_int_create(value);
|
||||
return ucl_int_create(state, value);
|
||||
}
|
||||
default:
|
||||
symbol_case:
|
||||
@@ -94,30 +94,30 @@ struct ucl_object *ucl_token_next(const char **curr_src) {
|
||||
}
|
||||
// TODO: Free
|
||||
str = strndup(start, *curr_src - start);
|
||||
return ucl_symbol_create(str);
|
||||
return ucl_symbol_create(state, str);
|
||||
}
|
||||
}
|
||||
|
||||
// Unreachable
|
||||
assert(false);
|
||||
return ucl_error_create("Unreachable error in ucl_token_next");
|
||||
return ucl_error_create(state, "Unreachable error in ucl_token_next");
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_tokenize(const char *source) {
|
||||
struct ucl_object *tokens = ucl_nil_create();
|
||||
struct ucl_object *ucl_tokenize(struct ucl* state, const char *source) {
|
||||
struct ucl_object *tokens = ucl_nil_create(state);
|
||||
struct ucl_object *tokens_tail = tokens;
|
||||
struct ucl_object *curr_token = NULL;
|
||||
const char *curr_src = source;
|
||||
|
||||
while ((curr_token = ucl_token_next(&curr_src)) != NULL) {
|
||||
while ((curr_token = ucl_token_next(state, &curr_src)) != NULL) {
|
||||
UCL_RET_IF_ERROR(curr_token);
|
||||
tokens_tail = ucl_list_append(tokens_tail, curr_token);
|
||||
tokens_tail = ucl_list_append(state, tokens_tail, curr_token);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_parse_token_atom(struct ucl_object *maybe_atom) {
|
||||
struct ucl_object *ucl_parse_token_atom(struct ucl* state, struct ucl_object *maybe_atom) {
|
||||
struct ucl_object *atom = NULL;
|
||||
switch (maybe_atom->type) {
|
||||
case UCL_TYPE_CELL:
|
||||
@@ -131,14 +131,14 @@ struct ucl_object *ucl_parse_token_atom(struct ucl_object *maybe_atom) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
atom = ucl_symbol_create(maybe_atom->symbol);
|
||||
atom = ucl_symbol_create(state, maybe_atom->symbol);
|
||||
break;
|
||||
}
|
||||
case UCL_TYPE_STRING:
|
||||
atom = ucl_string_create(maybe_atom->string);
|
||||
atom = ucl_string_create(state, maybe_atom->string);
|
||||
break;
|
||||
case UCL_TYPE_INT:
|
||||
atom = ucl_int_create(maybe_atom->integer);
|
||||
atom = ucl_int_create(state, maybe_atom->integer);
|
||||
break;
|
||||
case UCL_TYPE_ERROR:
|
||||
case UCL_TYPE_BUILTIN:
|
||||
@@ -147,7 +147,7 @@ struct ucl_object *ucl_parse_token_atom(struct ucl_object *maybe_atom) {
|
||||
assert(false);
|
||||
}
|
||||
if (atom == NULL) {
|
||||
return ucl_error_create("Unreachable error in ucl_parse_token_atom");
|
||||
return ucl_error_create(state, "Unreachable error in ucl_parse_token_atom");
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
@@ -156,7 +156,7 @@ static void advance_token_iter(struct ucl_object **token_iter) {
|
||||
*token_iter = (*token_iter)->cell.cdr;
|
||||
}
|
||||
|
||||
static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_iter) {
|
||||
static struct ucl_object *ucl_parse_tokens_recursive(struct ucl* state, struct ucl_object **token_iter) {
|
||||
// Invariants:
|
||||
// - This function returns NULL if it encounters the first unmatched END_LIST_CHAR
|
||||
// - This function returns NULL if it encounters end-of-list without first finding a START_LIST_CHAR
|
||||
@@ -172,7 +172,7 @@ static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_i
|
||||
if (token == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct ucl_object *next_sexp = ucl_parse_token_atom(token);
|
||||
struct ucl_object *next_sexp = ucl_parse_token_atom(state, token);
|
||||
if (next_sexp != NULL) {
|
||||
advance_token_iter(token_iter);
|
||||
return next_sexp;
|
||||
@@ -187,7 +187,7 @@ static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_i
|
||||
while (1) {
|
||||
if (*token_iter == NULL) {
|
||||
// Unexpected end of parsing
|
||||
return ucl_error_create("Unmatched open parenthesis");
|
||||
return ucl_error_create(state, "Unmatched open parenthesis");
|
||||
}
|
||||
|
||||
token = (*token_iter)->cell.car;
|
||||
@@ -195,40 +195,40 @@ static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_i
|
||||
if (token->type == UCL_TYPE_SYMBOL && token->symbol[0] == END_LIST_CHAR) {
|
||||
advance_token_iter(token_iter);
|
||||
if (list == NULL) {
|
||||
list = ucl_cell_create(NULL, NULL);
|
||||
list = ucl_cell_create(state, NULL, NULL);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
next_sexp = ucl_parse_tokens_recursive(token_iter);
|
||||
next_sexp = ucl_parse_tokens_recursive(state, token_iter);
|
||||
UCL_RET_IF_ERROR(next_sexp);
|
||||
|
||||
*next_node = ucl_cell_create(next_sexp, NULL);
|
||||
*next_node = ucl_cell_create(state, next_sexp, NULL);
|
||||
next_node = &(*next_node)->cell.cdr;
|
||||
}
|
||||
} else if (token->symbol[0] == END_LIST_CHAR) {
|
||||
return ucl_error_create("Unmatched closed parenthesis");
|
||||
return ucl_error_create(state, "Unmatched closed parenthesis");
|
||||
}
|
||||
// Any other symbol type should have been an atom, this shouldn't happen
|
||||
assert(false);
|
||||
return ucl_error_create("Unreachable ucl_parse_tokens_recursive error");
|
||||
return ucl_error_create(state, "Unreachable ucl_parse_tokens_recursive error");
|
||||
}
|
||||
|
||||
// parse_tokens -> doesn't care about quotes, terminates on EOF
|
||||
// parse_tokens_recursive -> error on EOF)
|
||||
|
||||
struct ucl_object *ucl_parse_tokens(struct ucl_object *tokens) {
|
||||
struct ucl_object* result = ucl_nil_create();
|
||||
struct ucl_object *ucl_parse_tokens(struct ucl* state, struct ucl_object *tokens) {
|
||||
struct ucl_object* result = ucl_nil_create(state);
|
||||
struct ucl_object* result_tail = result;
|
||||
struct ucl_object** token_iter = &tokens;
|
||||
|
||||
while (*token_iter != NULL) {
|
||||
struct ucl_object *new_sexp = ucl_parse_tokens_recursive(token_iter);
|
||||
struct ucl_object *new_sexp = ucl_parse_tokens_recursive(state, token_iter);
|
||||
if (new_sexp == NULL || new_sexp->type == UCL_TYPE_ERROR) {
|
||||
return new_sexp;
|
||||
}
|
||||
|
||||
result_tail = ucl_list_append(result_tail, new_sexp);
|
||||
result_tail = ucl_list_append(state, result_tail, new_sexp);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -236,13 +236,13 @@ struct ucl_object *ucl_parse_tokens(struct ucl_object *tokens) {
|
||||
|
||||
// TODO: Should the parse a single sexp (return the last-parsed position), or
|
||||
// all sexps in the source (return a list of sexps)?
|
||||
struct ucl_object *ucl_parse(const char *source) {
|
||||
struct ucl_object *tokens = ucl_tokenize(source);
|
||||
struct ucl_object *ucl_parse(struct ucl* state, const char *source) {
|
||||
struct ucl_object *tokens = ucl_tokenize(state, source);
|
||||
UCL_RET_IF_ERROR(tokens);
|
||||
|
||||
struct ucl_object *sexp = ucl_parse_tokens(tokens);
|
||||
struct ucl_object *sexp = ucl_parse_tokens(state, tokens);
|
||||
if (sexp == NULL) {
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
return sexp;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct ucl_object *ucl_token_next(const char **curr_src);
|
||||
struct ucl_object *ucl_parse_token_atom(struct ucl_object *maybe_atom);
|
||||
struct ucl_object *ucl_token_next(struct ucl* state, const char **curr_src);
|
||||
struct ucl_object *ucl_parse_token_atom(struct ucl* state, struct ucl_object *maybe_atom);
|
||||
|
||||
#endif
|
||||
|
||||
45
src/scope.c
45
src/scope.c
@@ -16,12 +16,10 @@
|
||||
|
||||
#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) {
|
||||
static struct ucl_object *ucl_scope_get_cell(struct ucl *state, 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;
|
||||
const char *item_name = ucl_list_nth(state, item, NAME_POSITION)->string;
|
||||
if (!strcmp(name, item_name)) {
|
||||
return item;
|
||||
}
|
||||
@@ -30,25 +28,27 @@ static struct ucl_object *ucl_scope_get_cell(struct ucl_scope *scope, const char
|
||||
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);
|
||||
struct ucl_object *ucl_scope_get(struct ucl *state, struct ucl_scope *scope, const char *name) {
|
||||
struct ucl_object *cell = ucl_scope_get_cell(state, scope, name);
|
||||
if (cell == NULL) {
|
||||
if (scope->parent == NULL) {
|
||||
// TODO: Include the symbol name
|
||||
return ucl_error_create("Unbound symbol");
|
||||
return ucl_error_create(state, "Unbound symbol");
|
||||
} else {
|
||||
return ucl_scope_get(scope->parent, name);
|
||||
return ucl_scope_get(state, scope->parent, name);
|
||||
}
|
||||
}
|
||||
return ucl_list_nth(cell, DATA_POSITION);
|
||||
return ucl_list_nth(state, 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);
|
||||
void ucl_scope_put(struct ucl *state, struct ucl_scope *scope, const char *name, struct ucl_object *obj) {
|
||||
struct ucl_object *cell = ucl_scope_get_cell(state, scope, name);
|
||||
if (cell == NULL) {
|
||||
ucl_list_append(scope->list,
|
||||
ucl_list_append(state,
|
||||
scope->list,
|
||||
ucl_tuple_create(
|
||||
ucl_string_create(name),
|
||||
state,
|
||||
ucl_string_create(state, name),
|
||||
obj));
|
||||
} else {
|
||||
// TODO: Refcounting / cleanup
|
||||
@@ -56,18 +56,15 @@ void ucl_scope_put(struct ucl_scope *scope, const char *name, struct ucl_object
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
struct ucl_scope *ucl_scope_create(struct ucl *state) {
|
||||
struct ucl_scope *scope = ucl_arena_get(state->scope_arena);
|
||||
scope->list = ucl_nil_create(state);
|
||||
scope->parent = NULL;
|
||||
return scope;
|
||||
}
|
||||
|
||||
struct ucl_scope *ucl_scope_create_child(struct ucl_scope *parent) {
|
||||
struct ucl_scope *scope = ucl_scope_create();
|
||||
struct ucl_scope *ucl_scope_create_child(struct ucl *state, struct ucl_scope *parent) {
|
||||
struct ucl_scope *scope = ucl_scope_create(state);
|
||||
scope->parent = parent;
|
||||
return scope;
|
||||
}
|
||||
@@ -79,8 +76,8 @@ struct ucl_scope *ucl_scope_get_root(struct ucl_scope *scope) {
|
||||
return scope;
|
||||
}
|
||||
|
||||
void ucl_scope_delete(struct ucl_scope *scope) {
|
||||
assert(scope_arena != NULL);
|
||||
ucl_arena_put(scope_arena, scope);
|
||||
void ucl_scope_delete(struct ucl *ucl, struct ucl_scope *scope) {
|
||||
assert(ucl->scope_arena != NULL);
|
||||
ucl_arena_put(ucl->scope_arena, scope);
|
||||
// Garbage collection will handle the objects, they are shared
|
||||
}
|
||||
|
||||
12
src/scope.h
12
src/scope.h
@@ -1,15 +1,15 @@
|
||||
#ifndef _UCLISP_SCOPE_H_
|
||||
#define _UCLISP_SCOPE_H_
|
||||
|
||||
struct ucl;
|
||||
struct ucl_scope;
|
||||
|
||||
struct ucl_scope *ucl_scope_create();
|
||||
struct ucl_scope *ucl_scope_create_child(struct ucl_scope *parent);
|
||||
struct ucl_scope *ucl_scope_create(struct ucl* state);
|
||||
struct ucl_scope *ucl_scope_create_child(struct ucl* state, struct ucl_scope *parent);
|
||||
void ucl_scope_delete(struct ucl* state, struct ucl_scope *scope);
|
||||
|
||||
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_object *ucl_scope_get(struct ucl *state, struct ucl_scope *scope, const char *name);
|
||||
void ucl_scope_put(struct ucl *state, struct ucl_scope *scope, const char *name, struct ucl_object *obj);
|
||||
struct ucl_scope *ucl_scope_get_root(struct ucl_scope *scope);
|
||||
|
||||
#endif
|
||||
|
||||
165
src/special.c
165
src/special.c
@@ -7,174 +7,174 @@
|
||||
|
||||
// TODO: Macro support?
|
||||
|
||||
struct ucl_object *ucl_special_let(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_let(struct ucl *state, 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_scope *let_scope = ucl_scope_create_child(scope);
|
||||
struct ucl_object *assignments = ucl_car(state, args);
|
||||
struct ucl_object *expressions = ucl_cdr(state, args);
|
||||
struct ucl_scope *let_scope = ucl_scope_create_child(state, 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_scope, expr);
|
||||
struct ucl_object *sym = ucl_car(state, item);
|
||||
struct ucl_object *expr = ucl_car(state, ucl_cdr(state, item));
|
||||
struct ucl_object *value = ucl_evaluate_in_scope(state, let_scope, expr);
|
||||
|
||||
assert(sym->type == UCL_TYPE_SYMBOL);
|
||||
//assert(ucl_list_length(expr)->integer == 1);
|
||||
|
||||
if (value->type == UCL_TYPE_ERROR) {
|
||||
ucl_scope_delete(let_scope);
|
||||
ucl_scope_delete(state, let_scope);
|
||||
return value;
|
||||
}
|
||||
ucl_scope_put(let_scope, sym->symbol, value);
|
||||
ucl_scope_put(state, let_scope, sym->symbol, value);
|
||||
}
|
||||
|
||||
struct ucl_object *result = ucl_progn(let_scope, expressions);
|
||||
ucl_scope_delete(let_scope);
|
||||
struct ucl_object *result = ucl_progn(state, let_scope, expressions);
|
||||
ucl_scope_delete(state, let_scope);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_if(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_if(struct ucl *state, 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 = ucl_car(state, args);
|
||||
struct ucl_object *true_form = ucl_list_nth(state, args, 1);
|
||||
struct ucl_object *false_forms = ucl_cdr(state, ucl_cdr(state, args));
|
||||
|
||||
struct ucl_object *cond_result = ucl_evaluate(scope, cond);
|
||||
struct ucl_object *cond_result = ucl_evaluate_in_scope(state, scope, cond);
|
||||
UCL_RET_IF_ERROR(cond_result);
|
||||
if (ucl_truthy(cond_result)->type == UCL_TYPE_SYMBOL) {
|
||||
return ucl_evaluate(scope, true_form);
|
||||
if (ucl_truthy(state, cond_result)->type == UCL_TYPE_SYMBOL) {
|
||||
return ucl_evaluate_in_scope(state, scope, true_form);
|
||||
}
|
||||
|
||||
return ucl_progn(scope, false_forms);
|
||||
return ucl_progn(state, scope, false_forms);
|
||||
}
|
||||
|
||||
|
||||
struct ucl_object *ucl_special_defun(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_defun(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *fun_sym = ucl_car(args);
|
||||
struct ucl_object *fun_sym = ucl_car(state, args);
|
||||
if (fun_sym->type != UCL_TYPE_SYMBOL) {
|
||||
return ucl_error_create("First argument to defun must be a symbol");
|
||||
return ucl_error_create(state, "First argument to defun must be a symbol");
|
||||
}
|
||||
|
||||
struct ucl_object *fun_args = ucl_list_nth(args, 1);
|
||||
struct ucl_object *fun_args = ucl_list_nth(state, args, 1);
|
||||
if (fun_args->type != UCL_TYPE_CELL) {
|
||||
// TODO: Check that the list contains only symbols
|
||||
return ucl_error_create("Second argument to defun must be a list of symbols");
|
||||
return ucl_error_create(state, "Second argument to defun must be a list of symbols");
|
||||
}
|
||||
|
||||
// For now, other elements are just forms to be evaluated. Maybe one day
|
||||
// there will be docstrings, maybe not!
|
||||
|
||||
// Functions are added to the root scope
|
||||
ucl_scope_put(ucl_scope_get_root(scope), fun_sym->symbol, ucl_cdr(args));
|
||||
ucl_scope_put(state, ucl_scope_get_root(scope), fun_sym->symbol, ucl_cdr(state, args));
|
||||
|
||||
return fun_sym;
|
||||
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_lambda(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_lambda(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *fun_args = ucl_list_nth(args, 0);
|
||||
struct ucl_object *fun_args = ucl_list_nth(state, args, 0);
|
||||
if (fun_args->type != UCL_TYPE_CELL) {
|
||||
// TODO: Check that the list contains only symbols
|
||||
return ucl_error_create("First argument to lambda must be a list of symbols");
|
||||
return ucl_error_create(state, "First argument to lambda must be a list of symbols");
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_dotimes(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_dotimes(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *assignment = ucl_car(args);
|
||||
struct ucl_object *body = ucl_cdr(args);
|
||||
struct ucl_object *assignment = ucl_car(state, args);
|
||||
struct ucl_object *body = ucl_cdr(state, args);
|
||||
|
||||
struct ucl_object *var = ucl_car(assignment);
|
||||
struct ucl_object *times = ucl_evaluate(scope, ucl_list_nth(assignment, 1));
|
||||
struct ucl_object *var = ucl_car(state, assignment);
|
||||
struct ucl_object *times = ucl_evaluate_in_scope(state, scope, ucl_list_nth(state, assignment, 1));
|
||||
|
||||
UCL_COND_OR_RET_ERROR(var->type == UCL_TYPE_SYMBOL, "'var' argument to dotimes must be an symbol");
|
||||
UCL_COND_OR_RET_ERROR(times->type == UCL_TYPE_INT, "'times' argument to dotimes must be an int");
|
||||
UCL_COND_OR_RET_ERROR(state, var->type == UCL_TYPE_SYMBOL, "'var' argument to dotimes must be an symbol");
|
||||
UCL_COND_OR_RET_ERROR(state, times->type == UCL_TYPE_INT, "'times' argument to dotimes must be an int");
|
||||
|
||||
struct ucl_scope *let_scope = ucl_scope_create_child(scope);
|
||||
struct ucl_scope *let_scope = ucl_scope_create_child(state, scope);
|
||||
|
||||
for (int i = 0; i < times->integer; i++) {
|
||||
ucl_scope_put(let_scope, var->symbol, ucl_int_create(i));
|
||||
struct ucl_object *iterval = ucl_progn(let_scope, body);
|
||||
ucl_scope_put(state, let_scope, var->symbol, ucl_int_create(state, i));
|
||||
struct ucl_object *iterval = ucl_progn(state, let_scope, body);
|
||||
UCL_RET_IF_ERROR(iterval);
|
||||
}
|
||||
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_dolist(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_dolist(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *assignment = ucl_car(args);
|
||||
struct ucl_object *body = ucl_cdr(args);
|
||||
struct ucl_object *assignment = ucl_car(state, args);
|
||||
struct ucl_object *body = ucl_cdr(state, args);
|
||||
|
||||
struct ucl_object *var = ucl_car(assignment);
|
||||
struct ucl_object *list = ucl_evaluate(scope, ucl_list_nth(assignment, 1));
|
||||
struct ucl_object *var = ucl_car(state, assignment);
|
||||
struct ucl_object *list = ucl_evaluate_in_scope(state, scope, ucl_list_nth(state, assignment, 1));
|
||||
|
||||
UCL_COND_OR_RET_ERROR(var->type == UCL_TYPE_SYMBOL, "'var' argument to dolist must be an symbol");
|
||||
UCL_COND_OR_RET_ERROR(list->type == UCL_TYPE_CELL, "'list' argument to dolist must be a list");
|
||||
UCL_COND_OR_RET_ERROR(state, var->type == UCL_TYPE_SYMBOL, "'var' argument to dolist must be an symbol");
|
||||
UCL_COND_OR_RET_ERROR(state, list->type == UCL_TYPE_CELL, "'list' argument to dolist must be a list");
|
||||
|
||||
struct ucl_scope *let_scope = ucl_scope_create_child(scope);
|
||||
struct ucl_scope *let_scope = ucl_scope_create_child(state, scope);
|
||||
|
||||
FOREACH_LIST(list, iter, item) {
|
||||
ucl_scope_put(let_scope, var->symbol, item);
|
||||
struct ucl_object *iterval = ucl_progn(let_scope, body);
|
||||
ucl_scope_put(state, let_scope, var->symbol, item);
|
||||
struct ucl_object *iterval = ucl_progn(state, let_scope, body);
|
||||
if (iterval->type == UCL_TYPE_ERROR) {
|
||||
ucl_scope_delete(let_scope);
|
||||
ucl_scope_delete(state, let_scope);
|
||||
}
|
||||
UCL_RET_IF_ERROR(iterval);
|
||||
}
|
||||
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_while(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_while(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *condition = ucl_car(args);
|
||||
struct ucl_object *body = ucl_cdr(args);
|
||||
struct ucl_object *condition = ucl_car(state, args);
|
||||
struct ucl_object *body = ucl_cdr(state, args);
|
||||
|
||||
while (1) {
|
||||
struct ucl_object* cond_val = ucl_evaluate(scope, condition);
|
||||
struct ucl_object* cond_val = ucl_evaluate_in_scope(state, scope, condition);
|
||||
UCL_RET_IF_ERROR(cond_val);
|
||||
if (!ucl_truthy_bool(cond_val)) {
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
struct ucl_object *val = ucl_progn(scope, body);
|
||||
struct ucl_object *val = ucl_progn(state, scope, body);
|
||||
UCL_RET_IF_ERROR(val);
|
||||
}
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_setq(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *ucl_special_setq(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
// TODO: Check arguments
|
||||
struct ucl_object *sym = ucl_car(args);
|
||||
struct ucl_object *sym = ucl_car(state, args);
|
||||
if (sym->type != UCL_TYPE_SYMBOL) {
|
||||
return ucl_error_create("First argument to setq must be a symbol");
|
||||
return ucl_error_create(state, "First argument to setq must be a symbol");
|
||||
}
|
||||
|
||||
struct ucl_object *value = ucl_evaluate(scope, ucl_list_nth(args, 1));
|
||||
struct ucl_object *value = ucl_evaluate_in_scope(state, scope, ucl_list_nth(state, args, 1));
|
||||
UCL_RET_IF_ERROR(value);
|
||||
|
||||
ucl_scope_put(scope, sym->symbol, value);
|
||||
ucl_scope_put(state, scope, sym->symbol, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_progn(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
return ucl_progn(scope, args);
|
||||
struct ucl_object *ucl_special_progn(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
return ucl_progn(state, scope, args);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_quote(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
return ucl_car(args);
|
||||
struct ucl_object *ucl_special_quote(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
return ucl_car(state, args);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_and(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *value = ucl_t_create();
|
||||
struct ucl_object *ucl_special_and(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *value = ucl_t_create(state);
|
||||
FOREACH_LIST(args, iter, form) {
|
||||
value = ucl_evaluate(scope, form);
|
||||
value = ucl_evaluate_in_scope(state, scope, form);
|
||||
if (!ucl_truthy_bool(value)) {
|
||||
return value;
|
||||
}
|
||||
@@ -182,13 +182,34 @@ struct ucl_object *ucl_special_and(struct ucl_scope *scope, struct ucl_object *a
|
||||
return value;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_special_or(struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *value = ucl_nil_create();
|
||||
struct ucl_object *ucl_special_or(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||
struct ucl_object *value = ucl_nil_create(state);
|
||||
FOREACH_LIST(args, iter, form) {
|
||||
value = ucl_evaluate(scope, form);
|
||||
value = ucl_evaluate_in_scope(state, scope, form);
|
||||
if (ucl_truthy_bool(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void ucl_add_special(struct ucl *state, const char *name, ucl_lisp fun) {
|
||||
ucl_scope_put(state, state->global_scope, name, ucl_special_create(state, fun));
|
||||
}
|
||||
|
||||
void ucl_add_specials(struct ucl *state) {
|
||||
ucl_add_special(state, "let", ucl_special_let);
|
||||
ucl_add_special(state, "if", ucl_special_if);
|
||||
ucl_add_special(state, "defun", ucl_special_defun);
|
||||
ucl_add_special(state, "lambda", ucl_special_lambda);
|
||||
ucl_add_special(state, "setq", ucl_special_setq);
|
||||
ucl_add_special(state, "progn", ucl_special_progn);
|
||||
ucl_add_special(state, "quote", ucl_special_quote);
|
||||
ucl_add_special(state, "and", ucl_special_and);
|
||||
ucl_add_special(state, "or", ucl_special_or);
|
||||
|
||||
ucl_add_special(state, "dotimes", ucl_special_dotimes);
|
||||
ucl_add_special(state, "dolist", ucl_special_dolist);
|
||||
ucl_add_special(state, "while", ucl_special_while);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef _UCLISP_SPECIAL_H_
|
||||
#define _UCLISP_SPECIAL_H_
|
||||
|
||||
#include "uclisp.h"
|
||||
|
||||
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_dotimes(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_dolist(struct ucl_scope *scope, struct ucl_object *args);
|
||||
struct ucl_object *ucl_special_while(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
|
||||
|
||||
20
src/types.h
20
src/types.h
@@ -1,6 +1,11 @@
|
||||
#ifndef _UCLISP_TYPES_H_
|
||||
#define _UCLISP_TYPES_H_
|
||||
|
||||
struct ucl;
|
||||
struct ucl_scope;
|
||||
struct ucl_cell;
|
||||
struct ucl_object;
|
||||
|
||||
enum ucl_type {
|
||||
UCL_TYPE_CELL = 0,
|
||||
UCL_TYPE_SYMBOL = 1,
|
||||
@@ -17,8 +22,12 @@ struct ucl_cell {
|
||||
struct ucl_object *cdr;
|
||||
};
|
||||
|
||||
struct ucl_scope;
|
||||
typedef struct ucl_object *(*ucl_lisp)(struct ucl_scope* state, struct ucl_object *args);
|
||||
typedef struct ucl_object *(*ucl_lisp)(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
enum ucl_object_flag {
|
||||
UCL_OBJ_FLAG_REACHABLE = 1 << 0,
|
||||
UCL_OBJ_FLAG_PINNED = 1 << 1,
|
||||
};
|
||||
|
||||
struct ucl_object {
|
||||
union {
|
||||
@@ -39,4 +48,11 @@ struct ucl_scope {
|
||||
struct ucl_scope *parent;
|
||||
};
|
||||
|
||||
struct ucl {
|
||||
struct ucl_scope *global_scope;
|
||||
|
||||
struct ucl_arena *scope_arena;
|
||||
struct ucl_arena *obj_arena;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,56 +9,58 @@
|
||||
#include "common.h"
|
||||
|
||||
|
||||
struct ucl_object *ucl_car(struct ucl_object *list) {
|
||||
struct ucl_object *ucl_car(struct ucl *state, struct ucl_object *list) {
|
||||
UCL_COND_OR_RET_ERROR(
|
||||
state,
|
||||
list != NULL && list->type == UCL_TYPE_CELL,
|
||||
"Invalid type of argument 0 to 'ucl_car'");
|
||||
|
||||
struct ucl_object *car = list->cell.car;
|
||||
if (car == NULL) {
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
return car;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_cdr(struct ucl_object *list) {
|
||||
UCL_COND_OR_RET_ERROR(
|
||||
struct ucl_object *ucl_cdr(struct ucl* state, struct ucl_object *list) {
|
||||
UCL_COND_OR_RET_ERROR(state,
|
||||
list != NULL && list->type == UCL_TYPE_CELL,
|
||||
"Invalid type of argument 0 to 'ucl_cdr'");
|
||||
|
||||
struct ucl_object *cdr = list->cell.cdr;
|
||||
if (cdr == NULL) {
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
return cdr;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_nil_create() {
|
||||
return ucl_cell_create(NULL, NULL);
|
||||
struct ucl_object *ucl_nil_create(struct ucl* state) {
|
||||
return ucl_cell_create(state, NULL, NULL);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_t_create() {
|
||||
return ucl_symbol_create("t");
|
||||
struct ucl_object *ucl_t_create(struct ucl* state) {
|
||||
return ucl_symbol_create(state, "t");
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_predicate(bool value) {
|
||||
struct ucl_object *ucl_predicate(struct ucl* state, bool value) {
|
||||
if (value) {
|
||||
return ucl_t_create();
|
||||
return ucl_t_create(state);
|
||||
} else {
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_list_length(struct ucl_object *list) {
|
||||
struct ucl_object *ucl_list_length(struct ucl *state, struct ucl_object *list) {
|
||||
UCL_COND_OR_RET_ERROR(
|
||||
state,
|
||||
list != NULL && list->type == UCL_TYPE_CELL,
|
||||
"Invalid type of argument 0 to 'ucl_list_length'");
|
||||
|
||||
struct ucl_object *node = list;
|
||||
if (list->cell.car == NULL) {
|
||||
return ucl_int_create(0);
|
||||
return ucl_int_create(state, 0);
|
||||
}
|
||||
|
||||
int length = 1;
|
||||
@@ -67,17 +69,18 @@ struct ucl_object *ucl_list_length(struct ucl_object *list) {
|
||||
length++;
|
||||
}
|
||||
|
||||
return ucl_int_create(length);
|
||||
return ucl_int_create(state, length);
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_list_nth(struct ucl_object *list, int n) {
|
||||
struct ucl_object *ucl_list_nth(struct ucl *state, struct ucl_object *list, int n) {
|
||||
UCL_COND_OR_RET_ERROR(
|
||||
state,
|
||||
list != NULL && list->type == UCL_TYPE_CELL,
|
||||
"Invalid type of argument 0 to 'ucl_list_nth'");
|
||||
|
||||
int length = ucl_list_length(list)->integer;
|
||||
UCL_COND_OR_RET_ERROR(length > n, "Position n >= list length in ucl_list_nth");
|
||||
UCL_COND_OR_RET_ERROR(n >= 0, "Index to ucl_list_nth was less that zero");
|
||||
int length = ucl_list_length(state, list)->integer;
|
||||
UCL_COND_OR_RET_ERROR(state, length > n, "Position n >= list length in ucl_list_nth");
|
||||
UCL_COND_OR_RET_ERROR(state, n >= 0, "Index to ucl_list_nth was less that zero");
|
||||
|
||||
struct ucl_object *node = list;
|
||||
for (int i = 0; i < n; i++) {
|
||||
@@ -101,17 +104,17 @@ bool ucl_truthy_bool(struct ucl_object *obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_truthy(struct ucl_object *obj) {
|
||||
return ucl_predicate(ucl_truthy_bool(obj));
|
||||
struct ucl_object *ucl_truthy(struct ucl *state, struct ucl_object *obj) {
|
||||
return ucl_predicate(state, ucl_truthy_bool(obj));
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_tuple_create(struct ucl_object *obj0, struct ucl_object *obj1) {
|
||||
struct ucl_object *tuple = ucl_cell_create(obj0, NULL);
|
||||
ucl_list_append(tuple, obj1);
|
||||
struct ucl_object *ucl_tuple_create(struct ucl* state, struct ucl_object *obj0, struct ucl_object *obj1) {
|
||||
struct ucl_object *tuple = ucl_cell_create(state, obj0, NULL);
|
||||
ucl_list_append(state, tuple, obj1);
|
||||
return tuple;
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_list_append(struct ucl_object *list, struct ucl_object *obj) {
|
||||
struct ucl_object *ucl_list_append(struct ucl* state, struct ucl_object *list, struct ucl_object *obj) {
|
||||
struct ucl_object *iter = list;
|
||||
|
||||
if (list->cell.car == NULL) {
|
||||
@@ -122,7 +125,7 @@ struct ucl_object *ucl_list_append(struct ucl_object *list, struct ucl_object *o
|
||||
while (iter->cell.cdr != NULL) {
|
||||
iter = iter->cell.cdr;
|
||||
}
|
||||
iter->cell.cdr = ucl_cell_create(obj, NULL);
|
||||
iter->cell.cdr = ucl_cell_create(state, obj, NULL);
|
||||
|
||||
return iter->cell.cdr;
|
||||
}
|
||||
@@ -165,56 +168,56 @@ void ucl_print_obj(struct ucl_object *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
struct ucl_object *ucl_progn(struct ucl_scope *state, struct ucl_object *forms) {
|
||||
struct ucl_object *ucl_progn(struct ucl *state, struct ucl_scope *scope, struct ucl_object *forms) {
|
||||
struct ucl_object *result = NULL;
|
||||
FOREACH_LIST(forms, iter, form) {
|
||||
result = ucl_evaluate(state, form);
|
||||
result = ucl_evaluate_in_scope(state, scope, form);
|
||||
if (result->type == UCL_TYPE_ERROR) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return (result == NULL) ? ucl_nil_create() : result;
|
||||
return (result == NULL) ? ucl_nil_create(state) : result;
|
||||
}
|
||||
|
||||
|
||||
struct ucl_object *ucl_equal(
|
||||
struct ucl_object *ucl_equal(struct ucl *state,
|
||||
struct ucl_object *arg0, struct ucl_object *arg1) {
|
||||
if (arg0 == arg1) {
|
||||
return ucl_t_create();
|
||||
return ucl_t_create(state);
|
||||
}
|
||||
|
||||
if ((arg0 == NULL) || (arg1 == NULL)) {
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
if (arg0->type != arg1->type) {
|
||||
return ucl_nil_create();
|
||||
return ucl_nil_create(state);
|
||||
}
|
||||
|
||||
switch (arg0->type) {
|
||||
case UCL_TYPE_INT:
|
||||
return ucl_predicate(arg0->integer == arg1->integer);
|
||||
return ucl_predicate(state, arg0->integer == arg1->integer);
|
||||
case UCL_TYPE_SYMBOL:
|
||||
return ucl_predicate(!strcmp(arg0->symbol, arg1->symbol));
|
||||
return ucl_predicate(state, !strcmp(arg0->symbol, arg1->symbol));
|
||||
case UCL_TYPE_CELL: {
|
||||
struct ucl_object *car_equal = ucl_equal(arg0->cell.car, arg1->cell.car);
|
||||
if (!ucl_truthy(car_equal)) {
|
||||
struct ucl_object *car_equal = ucl_equal(state, arg0->cell.car, arg1->cell.car);
|
||||
if (!ucl_truthy(state, car_equal)) {
|
||||
return car_equal;
|
||||
}
|
||||
return ucl_equal(arg0->cell.cdr, arg1->cell.cdr);
|
||||
return ucl_equal(state, arg0->cell.cdr, arg1->cell.cdr);
|
||||
}
|
||||
case UCL_TYPE_BUILTIN:
|
||||
return ucl_predicate(arg0->special == arg1->builtin);
|
||||
return ucl_predicate(state, arg0->special == arg1->builtin);
|
||||
case UCL_TYPE_SPECIAL:
|
||||
return ucl_predicate(arg0->special == arg1->builtin);
|
||||
return ucl_predicate(state, arg0->special == arg1->builtin);
|
||||
case UCL_TYPE_STRING:
|
||||
return ucl_predicate(!strcmp(arg0->string, arg1->string));
|
||||
return ucl_predicate(state, !strcmp(arg0->string, arg1->string));
|
||||
case UCL_TYPE_ERROR:
|
||||
case UCL_TYPE_COUNT:
|
||||
return ucl_error_create("");
|
||||
return ucl_error_create(state, "");
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return ucl_error_create("Unreachable error in ucl_equal");
|
||||
return ucl_error_create(state, "Unreachable error in ucl_equal");
|
||||
}
|
||||
|
||||
@@ -4,23 +4,28 @@
|
||||
#include <stdbool.h>
|
||||
#include "types.h"
|
||||
|
||||
struct ucl_object *ucl_nil_create();
|
||||
struct ucl_object *ucl_t_create();
|
||||
struct ucl_object *ucl_predicate(bool value);
|
||||
struct ucl_object *ucl_truthy(struct ucl_object *arg);
|
||||
struct ucl_object *ucl_nil_create(struct ucl* state);
|
||||
struct ucl_object *ucl_t_create(struct ucl* state);
|
||||
struct ucl_object *ucl_predicate(struct ucl* state, bool value);
|
||||
struct ucl_object *ucl_truthy(struct ucl* state, struct ucl_object *arg);
|
||||
bool ucl_truthy_bool(struct ucl_object *arg);
|
||||
struct ucl_object *ucl_equal(struct ucl_object *arg0, struct ucl_object *arg1);
|
||||
struct ucl_object *ucl_equal(struct ucl* state, struct ucl_object *arg0, struct ucl_object *arg1);
|
||||
|
||||
struct ucl_object* ucl_car(struct ucl_object *list);
|
||||
struct ucl_object* ucl_cdr(struct ucl_object *list);
|
||||
struct ucl_object* ucl_car(struct ucl* state, struct ucl_object *list);
|
||||
struct ucl_object* ucl_cdr(struct ucl* state, struct ucl_object *list);
|
||||
|
||||
struct ucl_object* ucl_list_length(struct ucl_object *list);
|
||||
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_list_length(struct ucl* state, struct ucl_object *list);
|
||||
struct ucl_object* ucl_list_nth(struct ucl* state, struct ucl_object *list, int n);
|
||||
struct ucl_object* ucl_list_append(struct ucl* state, struct ucl_object *list, struct ucl_object *obj);
|
||||
struct ucl_object* ucl_tuple_create(struct ucl* state, struct ucl_object *obj0, struct ucl_object *obj1);
|
||||
|
||||
struct ucl_object *ucl_progn(struct ucl_scope *scope, struct ucl_object *forms);
|
||||
struct ucl_object *ucl_progn(struct ucl* state, struct ucl_scope *scope, struct ucl_object *forms);
|
||||
|
||||
void ucl_print_obj(struct ucl_object *obj);
|
||||
|
||||
void ucl_add_builtins(struct ucl *state);
|
||||
void ucl_add_specials(struct ucl *state);
|
||||
|
||||
struct ucl_object* ucl_evaluate_in_scope(struct ucl *state, struct ucl_scope *scope, struct ucl_object* sexp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,44 +10,26 @@
|
||||
#include "builtins.h"
|
||||
#include "special.h"
|
||||
|
||||
static struct ucl *state;
|
||||
static struct ucl_object *input;
|
||||
static struct ucl_object *response;
|
||||
static struct ucl_scope *scope;
|
||||
|
||||
void setUp(void) {
|
||||
input = NULL;
|
||||
response = NULL;
|
||||
|
||||
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, "filter", ucl_builtin_create(ucl_builtin_filter));
|
||||
ucl_scope_put(scope, "reduce", ucl_builtin_create(ucl_builtin_reduce));
|
||||
ucl_scope_put(scope, "lambda", ucl_special_create(ucl_special_lambda));
|
||||
ucl_scope_put(scope, "quote", ucl_special_create(ucl_special_quote));
|
||||
ucl_scope_put(scope, "%", ucl_builtin_create(ucl_builtin_mod));
|
||||
state = ucl_create();
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
ucl_scope_delete(scope);
|
||||
ucl_gc();
|
||||
|
||||
// TODO: Actually release resources
|
||||
state = NULL;
|
||||
input = NULL;
|
||||
response = NULL;
|
||||
scope = NULL;
|
||||
}
|
||||
|
||||
static struct ucl_object *eval (const char *code) {
|
||||
struct ucl_object *sexp = ucl_parse(code);
|
||||
return ucl_evaluate(scope, ucl_car(sexp));
|
||||
struct ucl_object *sexp = ucl_parse(state, code);
|
||||
return ucl_evaluate(state, ucl_car(state, sexp));
|
||||
}
|
||||
|
||||
void test_simple_add(void) {
|
||||
@@ -96,7 +78,7 @@ void test_eval_string(void) {
|
||||
}
|
||||
|
||||
void test_eval_sym_defined(void) {
|
||||
ucl_scope_put(scope, "foo", ucl_int_create(2));
|
||||
ucl_scope_put(state, state->global_scope, "foo", ucl_int_create(state, 2));
|
||||
response = eval("foo");
|
||||
TEST_ASSERT_OBJ_INT_V(response, 2);
|
||||
}
|
||||
@@ -114,7 +96,7 @@ void test_eval_nested_error(void) {
|
||||
void test_eval_list(void) {
|
||||
response = eval("(list 1 2 3)");
|
||||
TEST_ASSERT_OBJ_LIST(response);
|
||||
TEST_ASSERT_EQUAL(ucl_list_length(response)->integer, 3);
|
||||
TEST_ASSERT_EQUAL(ucl_list_length(state, response)->integer, 3);
|
||||
|
||||
int i = 1;
|
||||
FOREACH_LIST(response, iter, item) {
|
||||
@@ -227,7 +209,7 @@ void test_eval_defun_gc(void) {
|
||||
|
||||
TEST_ASSERT_OBJ_SYMBOL_V(response, "foo");
|
||||
|
||||
ucl_gc();
|
||||
ucl_gc(state);
|
||||
response = eval("(foo 10 15)");
|
||||
|
||||
TEST_ASSERT_OBJ_INT_V(response, 25);
|
||||
|
||||
@@ -9,14 +9,17 @@
|
||||
#include "parse.h"
|
||||
|
||||
/* static struct ucl_parse_result *result; */
|
||||
static struct ucl *state;
|
||||
static struct ucl_object *response;
|
||||
|
||||
void setUp(void) {
|
||||
state = ucl_create();
|
||||
response = NULL;
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
ucl_gc();
|
||||
// TODO: Release state
|
||||
state = NULL;
|
||||
response = NULL;
|
||||
}
|
||||
|
||||
@@ -24,7 +27,7 @@ static void test_token_next_empty_str(void) {
|
||||
const char *input = "";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_NULL(response);
|
||||
TEST_ASSERT_EQUAL('\0', *curr);
|
||||
@@ -34,7 +37,7 @@ static void test_token_next_only_whitespace(void) {
|
||||
const char *input = " \n";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_NULL(response);
|
||||
TEST_ASSERT_EQUAL('\0', *curr);
|
||||
@@ -44,7 +47,7 @@ static void test_token_next_lparen(void) {
|
||||
const char *input = "(";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
TEST_ASSERT_OBJ_SYMBOL_V(response, "(");
|
||||
TEST_ASSERT_EQUAL('\0', *curr);
|
||||
}
|
||||
@@ -53,7 +56,7 @@ static void test_token_next_rparen(void) {
|
||||
const char *input = ")";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_OBJ_SYMBOL_V(response, ")");
|
||||
TEST_ASSERT_EQUAL('\0', *curr);
|
||||
@@ -63,12 +66,12 @@ static void test_token_next_lrparen(void) {
|
||||
const char *input = "()";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_OBJ_SYMBOL_V(response, "(");
|
||||
|
||||
ucl_object_delete(response);
|
||||
response = ucl_token_next(&curr);
|
||||
ucl_object_delete(state, response);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_OBJ_SYMBOL_V(response, ")");
|
||||
TEST_ASSERT_EQUAL('\0', *curr);
|
||||
@@ -78,7 +81,7 @@ static void test_token_next_string(void) {
|
||||
const char *input = "\"foo\"";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_OBJ_STRING_V(response, "foo");
|
||||
TEST_ASSERT_EQUAL('\0', *curr);
|
||||
@@ -88,7 +91,7 @@ static void test_token_next_string_w_whitespace(void) {
|
||||
const char *input = " \"foo\" ";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_OBJ_STRING_V(response, "foo");
|
||||
TEST_ASSERT_EQUAL_STRING(" ", curr);
|
||||
@@ -98,7 +101,7 @@ static void test_token_next_symbol(void) {
|
||||
const char *input = "foo";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_OBJ_SYMBOL_V(response, "foo");
|
||||
TEST_ASSERT_EQUAL_STRING("", curr);
|
||||
@@ -108,20 +111,20 @@ static void test_token_next_symbol_w_whitespace(void) {
|
||||
const char *input = " foo ";
|
||||
const char *curr = input;
|
||||
|
||||
response = ucl_token_next(&curr);
|
||||
response = ucl_token_next(state, &curr);
|
||||
|
||||
TEST_ASSERT_OBJ_SYMBOL_V(response, "foo");
|
||||
TEST_ASSERT_EQUAL_STRING(" ", curr);
|
||||
}
|
||||
|
||||
static void test_tokenize_empty_str(void) {
|
||||
response = ucl_tokenize("");
|
||||
response = ucl_tokenize(state, "");
|
||||
|
||||
TEST_ASSERT_NIL(response);
|
||||
}
|
||||
|
||||
static void test_tokenize_nil(void) {
|
||||
response = ucl_tokenize("()");
|
||||
response = ucl_tokenize(state, "()");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -141,7 +144,7 @@ static void test_tokenize_nil(void) {
|
||||
}
|
||||
|
||||
static void test_tokenize_scopement(void) {
|
||||
response = ucl_tokenize("(foo)");
|
||||
response = ucl_tokenize(state, "(foo)");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -166,27 +169,27 @@ static void test_tokenize_scopement(void) {
|
||||
}
|
||||
|
||||
static void test_parse_atom_symbol(void) {
|
||||
response = ucl_parse_token_atom(ucl_symbol_create("foo"));
|
||||
response = ucl_parse_token_atom(state, ucl_symbol_create(state, "foo"));
|
||||
|
||||
TEST_ASSERT_EQUAL(response->type, UCL_TYPE_SYMBOL);
|
||||
TEST_ASSERT_EQUAL_STRING(response->symbol, "foo");
|
||||
}
|
||||
|
||||
static void test_parse_atom_lparen(void) {
|
||||
response = ucl_parse_token_atom(ucl_symbol_create("("));
|
||||
response = ucl_parse_token_atom(state, ucl_symbol_create(state, "("));
|
||||
|
||||
TEST_ASSERT_NULL(response);
|
||||
}
|
||||
|
||||
static void test_parse_atom_rparen(void) {
|
||||
response = ucl_parse_token_atom(ucl_symbol_create(")"));
|
||||
response = ucl_parse_token_atom(state, ucl_symbol_create(state, ")"));
|
||||
|
||||
TEST_ASSERT_NULL(response);
|
||||
}
|
||||
|
||||
|
||||
static void test_parse_empty_str(void) {
|
||||
response = ucl_parse("");
|
||||
response = ucl_parse(state, "");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -195,7 +198,7 @@ static void test_parse_empty_str(void) {
|
||||
}
|
||||
|
||||
static void test_parse_symbol(void) {
|
||||
response = ucl_parse("foo");
|
||||
response = ucl_parse(state, "foo");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -206,7 +209,7 @@ static void test_parse_symbol(void) {
|
||||
}
|
||||
|
||||
static void test_parse_nil(void) {
|
||||
response = ucl_parse("()");
|
||||
response = ucl_parse(state, "()");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -219,7 +222,7 @@ static void test_parse_nil(void) {
|
||||
}
|
||||
|
||||
static void test_parse_list_1elem(void) {
|
||||
response = ucl_parse("(foo)");
|
||||
response = ucl_parse(state, "(foo)");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -235,7 +238,7 @@ static void test_parse_list_1elem(void) {
|
||||
}
|
||||
|
||||
static void test_parse_list_2elem(void) {
|
||||
response = ucl_parse("(foo bar)");
|
||||
response = ucl_parse(state, "(foo bar)");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -256,7 +259,7 @@ static void test_parse_list_2elem(void) {
|
||||
}
|
||||
|
||||
static void test_parse_2elem(void) {
|
||||
response = ucl_parse("foo bar");
|
||||
response = ucl_parse(state, "foo bar");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -273,7 +276,7 @@ static void test_parse_2elem(void) {
|
||||
}
|
||||
|
||||
static void test_parse_2elem_str(void) {
|
||||
response = ucl_parse("\"foo\" \"bar\"");
|
||||
response = ucl_parse(state, "\"foo\" \"bar\"");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -290,7 +293,7 @@ static void test_parse_2elem_str(void) {
|
||||
}
|
||||
|
||||
static void test_parse_nested(void) {
|
||||
response = ucl_parse("((foo))");
|
||||
response = ucl_parse(state, "((foo))");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type);
|
||||
@@ -309,45 +312,45 @@ static void test_parse_nested(void) {
|
||||
}
|
||||
|
||||
static void test_parse_mismatched_open(void) {
|
||||
response = ucl_parse("(");
|
||||
response = ucl_parse(state, "(");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_parse_mismatched_closed(void) {
|
||||
response = ucl_parse(")");
|
||||
response = ucl_parse(state, ")");
|
||||
|
||||
TEST_ASSERT_NOT_NULL(response);
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_parse_int(void) {
|
||||
response = ucl_parse("123");
|
||||
response = ucl_parse(state, "123");
|
||||
|
||||
TEST_ASSERT_OBJ_INT_V(response->cell.car, 123);
|
||||
}
|
||||
|
||||
static void test_parse_int_hex(void) {
|
||||
response = ucl_parse("0xa");
|
||||
response = ucl_parse(state, "0xa");
|
||||
|
||||
TEST_ASSERT_OBJ_INT_V(response->cell.car, 0xa);
|
||||
}
|
||||
|
||||
static void test_parse_int_neg(void) {
|
||||
response = ucl_parse("-7");
|
||||
response = ucl_parse(state, "-7");
|
||||
|
||||
TEST_ASSERT_OBJ_INT_V(response->cell.car, -7);
|
||||
}
|
||||
|
||||
static void test_parse_int_plus(void) {
|
||||
response = ucl_parse("+7");
|
||||
response = ucl_parse(state, "+7");
|
||||
|
||||
TEST_ASSERT_OBJ_INT_V(response->cell.car, 7);
|
||||
}
|
||||
|
||||
static void test_parse_int_garbled(void) {
|
||||
response = ucl_parse("+1234g7");
|
||||
response = ucl_parse(state, "+1234g7");
|
||||
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
@@ -9,51 +9,52 @@
|
||||
#include "scope.h"
|
||||
|
||||
/* static struct ucl_parse_result *result; */
|
||||
static struct ucl *state;
|
||||
static struct ucl_scope *scope;
|
||||
static struct ucl_object *response;
|
||||
|
||||
void setUp(void) {
|
||||
scope = ucl_scope_create();
|
||||
state = ucl_create();
|
||||
scope = ucl_scope_create(state);
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
ucl_scope_delete(scope);
|
||||
ucl_gc();
|
||||
state = NULL;
|
||||
scope = NULL;
|
||||
}
|
||||
|
||||
static void test_get_empty(void) {
|
||||
response = ucl_scope_get(scope, "foo");
|
||||
response = ucl_scope_get(state, scope, "foo");
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_put_get(void) {
|
||||
ucl_scope_put(scope, "foo", ucl_t_create());
|
||||
response = ucl_scope_get(scope, "foo");
|
||||
ucl_scope_put(state, scope, "foo", ucl_t_create(state));
|
||||
response = ucl_scope_get(state, scope, "foo");
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
static void test_put2_get(void) {
|
||||
ucl_scope_put(scope, "foo1", ucl_t_create());
|
||||
ucl_scope_put(scope, "foo2", ucl_nil_create());
|
||||
response = ucl_scope_get(scope, "foo1");
|
||||
ucl_scope_put(state, scope, "foo1", ucl_t_create(state));
|
||||
ucl_scope_put(state, scope, "foo2", ucl_nil_create(state));
|
||||
response = ucl_scope_get(state, scope, "foo1");
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
static void test_put_modify_get(void) {
|
||||
struct ucl_object *obj = ucl_tuple_create(
|
||||
ucl_string_create("bar"),
|
||||
ucl_string_create("baz"));
|
||||
struct ucl_object *obj = ucl_tuple_create(state,
|
||||
ucl_string_create(state, "bar"),
|
||||
ucl_string_create(state, "baz"));
|
||||
|
||||
ucl_scope_put(scope, "foo", obj);
|
||||
ucl_list_append(obj, ucl_string_create("quux"));
|
||||
response = ucl_scope_get(scope, "foo");
|
||||
ucl_scope_put(state, scope, "foo", obj);
|
||||
ucl_list_append(state, obj, ucl_string_create(state, "quux"));
|
||||
response = ucl_scope_get(state, scope, "foo");
|
||||
|
||||
TEST_ASSERT_OBJ_STRING(ucl_list_nth(response, 2));
|
||||
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(response, 2)->string, "quux");
|
||||
TEST_ASSERT_OBJ_STRING(ucl_list_nth(state, response, 2));
|
||||
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(state, response, 2)->string, "quux");
|
||||
|
||||
TEST_ASSERT_OBJ_STRING(ucl_list_nth(obj, 2));
|
||||
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(obj, 2)->string, "quux");
|
||||
TEST_ASSERT_OBJ_STRING(ucl_list_nth(state, obj, 2));
|
||||
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(state, obj, 2)->string, "quux");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,89 +7,91 @@
|
||||
#include "uclisp.h"
|
||||
#include "common.h"
|
||||
|
||||
static struct ucl *state;
|
||||
static struct ucl_object *input;
|
||||
static struct ucl_object *response;
|
||||
|
||||
void setUp(void) {
|
||||
state = ucl_create();
|
||||
input = NULL;
|
||||
response = NULL;
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
ucl_gc();
|
||||
|
||||
// TODO: Release memory
|
||||
state = NULL;
|
||||
input = NULL;
|
||||
response = NULL;
|
||||
}
|
||||
|
||||
static void test_nil_create(void) {
|
||||
response = ucl_nil_create();
|
||||
response = ucl_nil_create(state);
|
||||
|
||||
TEST_ASSERT_NIL(response);
|
||||
}
|
||||
|
||||
static void test_t_create(void) {
|
||||
response = ucl_t_create();
|
||||
response = ucl_t_create(state);
|
||||
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
static void test_predicate_true(void) {
|
||||
response = ucl_predicate(true);
|
||||
response = ucl_predicate(state, true);
|
||||
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
static void test_predicate_false(void) {
|
||||
response = ucl_predicate(false);
|
||||
response = ucl_predicate(state, false);
|
||||
|
||||
TEST_ASSERT_NIL(response);
|
||||
}
|
||||
|
||||
static void test_car_nil(void) {
|
||||
response = ucl_car(ucl_nil_create());
|
||||
response = ucl_car(state, ucl_nil_create(state));
|
||||
|
||||
TEST_ASSERT_NIL(response);
|
||||
}
|
||||
|
||||
static void test_cdr_nil(void) {
|
||||
response = ucl_cdr(ucl_nil_create());
|
||||
response = ucl_cdr(state, ucl_nil_create(state));
|
||||
|
||||
TEST_ASSERT_NIL(response);
|
||||
}
|
||||
|
||||
static void test_car_t(void) {
|
||||
response = ucl_car(ucl_t_create());
|
||||
response = ucl_car(state, ucl_t_create(state));
|
||||
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_cdr_t(void) {
|
||||
response = ucl_car(ucl_t_create());
|
||||
response = ucl_car(state, ucl_t_create(state));
|
||||
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_car_list(void) {
|
||||
input = ucl_tuple_create(
|
||||
ucl_string_create("foo"),
|
||||
ucl_t_create());
|
||||
response = ucl_car(input);
|
||||
input = ucl_tuple_create(state,
|
||||
ucl_string_create(state, "foo"),
|
||||
ucl_t_create(state));
|
||||
response = ucl_car(state, input);
|
||||
|
||||
TEST_ASSERT_OBJ_STRING(response);
|
||||
}
|
||||
|
||||
static void test_cdr_list(void) {
|
||||
input = ucl_tuple_create(
|
||||
ucl_t_create(),
|
||||
ucl_string_create("foo"));
|
||||
response = ucl_cdr(input);
|
||||
input = ucl_tuple_create(state,
|
||||
ucl_t_create(state),
|
||||
ucl_string_create(state, "foo"));
|
||||
response = ucl_cdr(state, input);
|
||||
|
||||
TEST_ASSERT_OBJ_STRING(ucl_car(response));
|
||||
TEST_ASSERT_OBJ_STRING(ucl_car(state, response));
|
||||
}
|
||||
|
||||
static void test_list_length_nil() {
|
||||
response = ucl_list_length(ucl_nil_create());
|
||||
response = ucl_list_length(state, ucl_nil_create(state));
|
||||
|
||||
TEST_ASSERT_OBJ_INT(response);
|
||||
TEST_ASSERT_EQUAL(response->integer, 0);
|
||||
@@ -97,8 +99,9 @@ static void test_list_length_nil() {
|
||||
|
||||
static void test_list_length_1() {
|
||||
response = ucl_list_length(
|
||||
ucl_cell_create(
|
||||
ucl_t_create(), NULL));
|
||||
state,
|
||||
ucl_cell_create(state,
|
||||
ucl_t_create(state), NULL));
|
||||
|
||||
TEST_ASSERT_OBJ_INT(response);
|
||||
TEST_ASSERT_EQUAL(response->integer, 1);
|
||||
@@ -106,9 +109,10 @@ static void test_list_length_1() {
|
||||
|
||||
static void test_list_length_2() {
|
||||
response = ucl_list_length(
|
||||
ucl_tuple_create(
|
||||
ucl_t_create(),
|
||||
ucl_t_create()));
|
||||
state,
|
||||
ucl_tuple_create(state,
|
||||
ucl_t_create(state),
|
||||
ucl_t_create(state)));
|
||||
|
||||
TEST_ASSERT_OBJ_INT(response);
|
||||
TEST_ASSERT_EQUAL(response->integer, 2);
|
||||
@@ -116,36 +120,37 @@ static void test_list_length_2() {
|
||||
|
||||
|
||||
static void test_list_append_nil() {
|
||||
input = ucl_nil_create();
|
||||
ucl_list_append(input, ucl_t_create());
|
||||
input = ucl_nil_create(state);
|
||||
ucl_list_append(state, input, ucl_t_create(state));
|
||||
|
||||
TEST_ASSERT_EQUAL(ucl_list_length(input)->integer, 1);
|
||||
TEST_ASSERT_EQUAL(ucl_list_length(state, input)->integer, 1);
|
||||
}
|
||||
|
||||
static void test_list_append_list() {
|
||||
input = ucl_tuple_create(ucl_t_create(), ucl_t_create());
|
||||
ucl_list_append(input, ucl_t_create());
|
||||
input = ucl_tuple_create(state, ucl_t_create(state), ucl_t_create(state));
|
||||
ucl_list_append(state, input, ucl_t_create(state));
|
||||
|
||||
TEST_ASSERT_EQUAL(ucl_list_length(input)->integer, 3);
|
||||
TEST_ASSERT_EQUAL(ucl_list_length(state, input)->integer, 3);
|
||||
}
|
||||
|
||||
static void test_list_nth_nil_0() {
|
||||
response = ucl_list_nth(ucl_nil_create(), 0);
|
||||
response = ucl_list_nth(state, ucl_nil_create(state), 0);
|
||||
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_list_nth_nil_1() {
|
||||
response = ucl_list_nth(ucl_nil_create(), 1);
|
||||
response = ucl_list_nth(state, ucl_nil_create(state), 1);
|
||||
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_list_nth_list_0() {
|
||||
response = ucl_list_nth(
|
||||
ucl_tuple_create(
|
||||
ucl_t_create(),
|
||||
ucl_string_create("foo")),
|
||||
state,
|
||||
ucl_tuple_create(state,
|
||||
ucl_t_create(state),
|
||||
ucl_string_create(state, "foo")),
|
||||
0);
|
||||
|
||||
TEST_ASSERT_T(response);
|
||||
@@ -153,30 +158,32 @@ static void test_list_nth_list_0() {
|
||||
|
||||
static void test_list_nth_list_1() {
|
||||
response = ucl_list_nth(
|
||||
ucl_tuple_create(
|
||||
ucl_t_create(),
|
||||
ucl_string_create("foo")),
|
||||
state,
|
||||
ucl_tuple_create(state,
|
||||
ucl_t_create(state),
|
||||
ucl_string_create(state, "foo")),
|
||||
1);
|
||||
|
||||
TEST_ASSERT_OBJ_STRING(response);
|
||||
}
|
||||
|
||||
static void test_list_nth_t_0() {
|
||||
response = ucl_list_nth(ucl_t_create(), 1);
|
||||
response = ucl_list_nth(state, ucl_t_create(state), 1);
|
||||
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_list_nth_bounds_0() {
|
||||
response = ucl_list_nth(ucl_nil_create(), 0);
|
||||
response = ucl_list_nth(state, ucl_nil_create(state), 0);
|
||||
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_list_nth_bounds_1() {
|
||||
response = ucl_list_nth(
|
||||
ucl_cell_create(
|
||||
ucl_nil_create(),
|
||||
state,
|
||||
ucl_cell_create(state,
|
||||
ucl_nil_create(state),
|
||||
NULL),
|
||||
1);
|
||||
|
||||
@@ -185,42 +192,43 @@ static void test_list_nth_bounds_1() {
|
||||
|
||||
static void test_list_nth_bounds_2() {
|
||||
response = ucl_list_nth(
|
||||
ucl_tuple_create(
|
||||
ucl_nil_create(),
|
||||
ucl_nil_create()),
|
||||
state,
|
||||
ucl_tuple_create(state,
|
||||
ucl_nil_create(state),
|
||||
ucl_nil_create(state)),
|
||||
2);
|
||||
|
||||
TEST_ASSERT_OBJ_ERROR(response);
|
||||
}
|
||||
|
||||
static void test_truthy_0() {
|
||||
response = ucl_truthy(ucl_int_create(0));
|
||||
response = ucl_truthy(state, ucl_int_create(state, 0));
|
||||
|
||||
TEST_ASSERT_NIL(response);
|
||||
}
|
||||
|
||||
static void test_truthy_1() {
|
||||
response = ucl_truthy(ucl_int_create(1));
|
||||
response = ucl_truthy(state, ucl_int_create(state, 1));
|
||||
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
static void test_truthy_nil() {
|
||||
response = ucl_truthy(ucl_nil_create());
|
||||
response = ucl_truthy(state, ucl_nil_create(state));
|
||||
|
||||
TEST_ASSERT_NIL(response);
|
||||
}
|
||||
|
||||
static void test_truthy_list_w_elem() {
|
||||
struct ucl_object *list = ucl_nil_create();
|
||||
ucl_list_append(list, ucl_int_create(0));
|
||||
response = ucl_truthy(list);
|
||||
struct ucl_object *list = ucl_nil_create(state);
|
||||
ucl_list_append(state, list, ucl_int_create(state, 0));
|
||||
response = ucl_truthy(state, list);
|
||||
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
static void test_truthy_sym() {
|
||||
response = ucl_truthy(ucl_symbol_create("t"));
|
||||
response = ucl_truthy(state, ucl_symbol_create(state, "t"));
|
||||
|
||||
TEST_ASSERT_T(response);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#define TEST_ASSERT_LIST_LEN(list, len) \
|
||||
do { \
|
||||
TEST_ASSERT_OBJ_LIST(list); \
|
||||
TEST_ASSERT_EQUAL(len, ucl_list_length(list)->integer); \
|
||||
TEST_ASSERT_EQUAL(len, ucl_list_length(state, list)->integer); \
|
||||
} while(0)
|
||||
|
||||
#define TEST_ASSERT_NIL(obj) \
|
||||
|
||||
Reference in New Issue
Block a user