move all globals into an execution context

This commit is contained in:
Sami Samhuri 2011-04-23 14:34:28 -07:00
parent ccdffc87aa
commit 8d66a7cbd1
16 changed files with 168 additions and 223 deletions

View file

@ -1,7 +1,7 @@
CC = gcc CC = gcc
CFLAGS := -Wall -g $(shell pkg-config --cflags glib-2.0) CFLAGS := -Wall -g $(shell pkg-config --cflags glib-2.0)
LFLAGS := $(shell pkg-config --libs glib-2.0) LFLAGS := $(shell pkg-config --libs glib-2.0)
OBJS = lake.o env.o int.o string.o sym.o parse.o bool.o list.o eval.o \ OBJS = lake.o env.o int.o string.o sym.o parse.o list.o eval.o \
symtable.o fn.o dlist.o primitive.o comment.o symtable.o fn.o dlist.o primitive.o comment.o
all: lake all: lake

View file

@ -1,38 +0,0 @@
/**
* bool.c
* Lake Scheme
*
* Copyright 2011 Sami Samhuri
* MIT License
*
*/
#include <glib.h>
#include "bool.h"
#include "lake.h"
#include "string.h"
LakeBool *bool_from_int(int n)
{
return n ? T : F;
}
char *bool_repr(LakeBool *b)
{
return g_strdup(BOOL_VAL(b) ? "#t" : "#f");
}
LakeStr *bool_to_str(LakeBool *b)
{
return str_from_c(BOOL_VAL(b) ? "#t" : "#f");
}
LakeVal* bool_and(LakeVal *a, LakeVal *b)
{
return IS_TRUTHY(a) && IS_TRUTHY(b) ? b : a;
}
LakeVal* bool_or(LakeVal *a, LakeVal *b)
{
return IS_TRUTHY(a) ? a : b;
}

View file

@ -1,22 +0,0 @@
/**
* bool.h
* Lake Scheme
*
* Copyright 2011 Sami Samhuri
* MIT License
*
*/
#ifndef _LAKE_BOOL_H
#define _LAKE_BOOL_H 1
#include <glib.h>
#include "lake.h"
LakeBool *bool_from_int(int b);
LakeStr *bool_to_str(LakeBool *b);
char *bool_repr(LakeBool *b);
LakeVal* bool_and(LakeVal *a, LakeVal *b);
LakeVal* bool_or(LakeVal *a, LakeVal *b);
#endif

View file

@ -14,16 +14,6 @@
#include "env.h" #include "env.h"
#include "symtable.h" #include "symtable.h"
static Env *_top = NULL;
Env *env_toplevel(void)
{
if (!_top) {
_top = env_make(NULL);
}
return _top;
}
Env *env_make(Env *parent) Env *env_make(Env *parent)
{ {
Env *env = g_malloc(sizeof(Env)); Env *env = g_malloc(sizeof(Env));

View file

@ -20,8 +20,6 @@ typedef struct env Env;
#include "lake.h" #include "lake.h"
Env *env_toplevel(void);
Env *env_make(Env *parent); Env *env_make(Env *parent);
LakeVal *env_define(Env *env, LakeSym *key, LakeVal *val); LakeVal *env_define(Env *env, LakeSym *key, LakeVal *val);
LakeVal *env_set(Env *env, LakeSym *key, LakeVal *val); LakeVal *env_set(Env *env, LakeSym *key, LakeVal *val);

View file

@ -14,11 +14,8 @@
#include "eval.h" #include "eval.h"
#include "fn.h" #include "fn.h"
#include "lake.h" #include "lake.h"
#include "symtable.h"
typedef LakeVal *(*special_form_handler)(Env *env, LakeList *expr); typedef LakeVal *(*special_form_handler)(LakeCtx *ctx, Env *env, LakeList *expr);
static GHashTable *special_form_handlers = NULL;
static void init_special_form_handlers(void);
static void invalid_special_form(LakeList *expr, char *detail) static void invalid_special_form(LakeList *expr, char *detail)
{ {
@ -26,7 +23,7 @@ static void invalid_special_form(LakeList *expr, char *detail)
} }
/* expr begins with the symbol "quote" so the quoted value is the 2nd value */ /* expr begins with the symbol "quote" so the quoted value is the 2nd value */
static LakeVal *_quote(Env *env, LakeList *expr) static LakeVal *_quote(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
if (LIST_N(expr) == 2) { if (LIST_N(expr) == 2) {
return list_pop(expr); return list_pop(expr);
@ -35,33 +32,33 @@ static LakeVal *_quote(Env *env, LakeList *expr)
return NULL; return NULL;
} }
static LakeVal *_and(Env *env, LakeList *expr) static LakeVal *_and(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
/* drop the "and" symbol */ /* drop the "and" symbol */
list_shift(expr); list_shift(expr);
/* (and ...) */ /* (and ...) */
LakeVal *result = LIST_N(expr) ? eval(env, list_shift(expr)) : VAL(T); LakeVal *result = LIST_N(expr) ? eval(ctx, env, list_shift(expr)) : VAL(ctx->T);
while (IS_TRUTHY(result) && LIST_N(expr) > 0) { while (IS_TRUTHY(ctx, result) && LIST_N(expr) > 0) {
result = bool_and(result, eval(env, list_shift(expr))); result = BOOL_AND(ctx, result, eval(ctx, env, list_shift(expr)));
} }
return result; return result;
} }
static LakeVal *_or(Env *env, LakeList *expr) static LakeVal *_or(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
/* drop the "or" symbol */ /* drop the "or" symbol */
list_shift(expr); list_shift(expr);
/* (or ...) */ /* (or ...) */
LakeVal *result = LIST_N(expr) ? eval(env, list_shift(expr)) : VAL(F); LakeVal *result = LIST_N(expr) ? eval(ctx, env, list_shift(expr)) : VAL(ctx->F);
while (IS_FALSY(result) && LIST_N(expr) > 0) { while (IS_FALSY(ctx, result) && LIST_N(expr) > 0) {
result = bool_or(result, eval(env, list_shift(expr))); result = BOOL_OR(ctx, result, eval(ctx, env, list_shift(expr)));
} }
return result; return result;
} }
static LakeVal *_setB(Env *env, LakeList *expr) static LakeVal *_setB(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
/* (set! x 42) */ /* (set! x 42) */
if (LIST_N(expr) == 3 && IS(TYPE_SYM, LIST_VAL(expr, 1))) { if (LIST_N(expr) == 3 && IS(TYPE_SYM, LIST_VAL(expr, 1))) {
@ -78,7 +75,7 @@ static LakeVal *_setB(Env *env, LakeList *expr)
return NULL; return NULL;
} }
static LakeVal *_define(Env *env, LakeList *expr) static LakeVal *_define(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
/* TODO: make these more robust, check all expected params */ /* TODO: make these more robust, check all expected params */
@ -87,7 +84,7 @@ static LakeVal *_define(Env *env, LakeList *expr)
list_shift(expr); /* drop the "define" symbol */ list_shift(expr); /* drop the "define" symbol */
LakeSym *var = SYM(list_shift(expr)); LakeSym *var = SYM(list_shift(expr));
LakeVal *form = list_shift(expr); LakeVal *form = list_shift(expr);
env_define(env, var, eval(env, form)); env_define(env, var, eval(ctx, env, form));
} }
/* (define (inc x) (+ 1 x)) */ /* (define (inc x) (+ 1 x)) */
@ -117,7 +114,7 @@ static LakeVal *_define(Env *env, LakeList *expr)
return NULL; return NULL;
} }
static LakeVal *_lambda(Env *env, LakeList *expr) static LakeVal *_lambda(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
/* (lambda (a b c) ...) */ /* (lambda (a b c) ...) */
if (LIST_N(expr) >= 3 && IS(TYPE_LIST, LIST_VAL(expr, 1))) { if (LIST_N(expr) >= 3 && IS(TYPE_LIST, LIST_VAL(expr, 1))) {
@ -146,26 +143,26 @@ static LakeVal *_lambda(Env *env, LakeList *expr)
} }
} }
static LakeVal *_if(Env *env, LakeList *expr) static LakeVal *_if(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
if (LIST_N(expr) != 3) { if (LIST_N(expr) != 3) {
invalid_special_form(expr, "if requires 3 parameters"); invalid_special_form(expr, "if requires 3 parameters");
return NULL; return NULL;
} }
list_shift(expr); /* "if" token */ list_shift(expr); /* "if" token */
LakeVal *cond = eval(env, list_shift(expr)); LakeVal *cond = eval(ctx, env, list_shift(expr));
if (IS_TRUTHY(cond)) { if (IS_TRUTHY(ctx, cond)) {
return eval(env, list_shift(expr)); return eval(ctx, env, list_shift(expr));
} }
else { else {
return eval(env, LIST_VAL(expr, 1)); return eval(ctx, env, LIST_VAL(expr, 1));
} }
} }
static LakeVal *_cond(Env *env, LakeList *expr) static LakeVal *_cond(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
static LakeVal *ELSE = NULL; static LakeVal *ELSE = NULL;
if (!ELSE) ELSE = VAL(sym_intern("else")); if (!ELSE) ELSE = VAL(sym_intern(ctx, "else"));
list_shift(expr); /* "cond" token */ list_shift(expr); /* "cond" token */
LakeVal *pred; LakeVal *pred;
@ -177,31 +174,30 @@ static LakeVal *_cond(Env *env, LakeList *expr)
} }
conseq = LIST(list_shift(expr)); conseq = LIST(list_shift(expr));
pred = list_shift(conseq); pred = list_shift(conseq);
if (pred == ELSE || IS_TRUTHY(eval(env, pred))) { if (pred == ELSE || IS_TRUTHY(ctx, eval(ctx, env, pred))) {
return eval_exprs1(env, conseq); return eval_exprs1(ctx, env, conseq);
} }
} }
return NULL; return NULL;
} }
static LakeVal *_when(Env *env, LakeList *expr) static LakeVal *_when(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
if (LIST_N(expr) < 2) { if (LIST_N(expr) < 2) {
invalid_special_form(expr, "when requires at least 2 parameters"); invalid_special_form(expr, "when requires at least 2 parameters");
return NULL; return NULL;
} }
list_shift(expr); /* "when" token */ list_shift(expr); /* "when" token */
LakeVal *cond = eval(env, list_shift(expr)); LakeVal *cond = eval(ctx, env, list_shift(expr));
return IS_TRUTHY(cond) ? eval_exprs1(env, expr) : NULL; return IS_TRUTHY(ctx, cond) ? eval_exprs1(ctx, env, expr) : NULL;
} }
static void init_special_form_handlers(void) void init_special_form_handlers(LakeCtx *ctx)
{ {
#define HANDLER(name, fn) g_hash_table_insert(special_form_handlers, \ #define HANDLER(name, fn) g_hash_table_insert(ctx->special_form_handlers, \
sym_intern(name), \ sym_intern(ctx, name), \
(gpointer)fn) (gpointer)fn)
special_form_handlers = symtable_make();
/* HANDLER("load", &load_special_form); */ /* HANDLER("load", &load_special_form); */
HANDLER("quote", &_quote); HANDLER("quote", &_quote);
HANDLER("and", &_and); HANDLER("and", &_and);
@ -217,38 +213,31 @@ static void init_special_form_handlers(void)
/* HANDLER("letrec", &_letrec); */ /* HANDLER("letrec", &_letrec); */
} }
gboolean is_special_form(LakeList *expr) gboolean is_special_form(LakeCtx *ctx, LakeList *expr)
{ {
if (special_form_handlers == NULL) {
init_special_form_handlers();
}
LakeVal *head = LIST_VAL(expr, 0); LakeVal *head = LIST_VAL(expr, 0);
if (!IS(TYPE_SYM, head)) return FALSE; if (!IS(TYPE_SYM, head)) return FALSE;
GList *special_form_names = g_hash_table_get_keys(special_form_handlers); GList *special_form_names = g_hash_table_get_keys(ctx->special_form_handlers);
return !!g_list_find(special_form_names, SYM(head)); return !!g_list_find(special_form_names, SYM(head));
} }
static special_form_handler get_special_form_handler(LakeSym *name) static special_form_handler get_special_form_handler(LakeCtx *ctx, LakeSym *name)
{ {
if (special_form_handlers == NULL) { return (special_form_handler)g_hash_table_lookup(ctx->special_form_handlers, name);
init_special_form_handlers();
}
return (special_form_handler)g_hash_table_lookup(special_form_handlers, name);
} }
static LakeVal *eval_special_form(Env *env, LakeList *expr) static LakeVal *eval_special_form(LakeCtx *ctx, Env *env, LakeList *expr)
{ {
LakeSym *name = SYM(LIST_VAL(expr, 0)); LakeSym *name = SYM(LIST_VAL(expr, 0));
special_form_handler handler = get_special_form_handler(name); special_form_handler handler = get_special_form_handler(ctx, name);
if (handler) { if (handler) {
return handler(env, list_copy(expr)); return handler(ctx, env, list_copy(expr));
} }
ERR("unrecognized special form: %s", SYM_S(name)); ERR("unrecognized special form: %s", SYM_S(name));
return NULL; return NULL;
} }
LakeVal *eval(Env *env, LakeVal *expr) LakeVal *eval(LakeCtx *ctx, Env *env, LakeVal *expr)
{ {
LakeVal *result; LakeVal *result;
LakeList *list; LakeList *list;
@ -282,11 +271,11 @@ LakeVal *eval(Env *env, LakeVal *expr)
result = expr; result = expr;
} }
else { else {
if (is_special_form(list)) { if (is_special_form(ctx, list)) {
result = eval_special_form(env, list); result = eval_special_form(ctx, env, list);
} }
else { else {
LakeVal *fn = eval(env, LIST_VAL(list, 0)); LakeVal *fn = eval(ctx, env, LIST_VAL(list, 0));
if (!fn) { if (!fn) {
return NULL; return NULL;
} }
@ -294,7 +283,7 @@ LakeVal *eval(Env *env, LakeVal *expr)
int i; int i;
LakeVal *v; LakeVal *v;
for (i = 1; i < LIST_N(list); ++i) { for (i = 1; i < LIST_N(list); ++i) {
v = eval(env, LIST_VAL(list, i)); v = eval(ctx, env, LIST_VAL(list, i));
if (v != NULL) { if (v != NULL) {
list_append(args, v); list_append(args, v);
} }
@ -304,7 +293,7 @@ LakeVal *eval(Env *env, LakeVal *expr)
goto done; goto done;
} }
} }
result = apply(fn, args); result = apply(ctx, fn, args);
} }
} }
break; break;
@ -317,32 +306,32 @@ LakeVal *eval(Env *env, LakeVal *expr)
done: return result; done: return result;
} }
LakeList *eval_exprs(Env *env, LakeList *exprs) LakeList *eval_exprs(LakeCtx *ctx, Env *env, LakeList *exprs)
{ {
LakeList *results = list_make_with_capacity(LIST_N(exprs)); LakeList *results = list_make_with_capacity(LIST_N(exprs));
int i; int i;
for (i = 0; i < LIST_N(exprs); ++i) { for (i = 0; i < LIST_N(exprs); ++i) {
list_append(results, eval(env, LIST_VAL(exprs, i))); list_append(results, eval(ctx, env, LIST_VAL(exprs, i)));
} }
return results; return results;
} }
LakeVal *eval_exprs1(Env *env, LakeList *exprs) LakeVal *eval_exprs1(LakeCtx *ctx, Env *env, LakeList *exprs)
{ {
LakeList *results = eval_exprs(env, exprs); LakeList *results = eval_exprs(ctx, env, exprs);
LakeVal *result = list_pop(results); LakeVal *result = list_pop(results);
list_free(results); list_free(results);
return result; return result;
} }
LakeVal *apply(LakeVal *fnVal, LakeList *args) LakeVal *apply(LakeCtx *ctx, LakeVal *fnVal, LakeList *args)
{ {
LakeVal *result = NULL; LakeVal *result = NULL;
if (IS(TYPE_PRIM, fnVal)) { if (IS(TYPE_PRIM, fnVal)) {
LakePrimitive *prim = PRIM(fnVal); LakePrimitive *prim = PRIM(fnVal);
int arity = prim->arity; int arity = prim->arity;
if (arity == ARITY_VARARGS || LIST_N(args) == arity) { if (arity == ARITY_VARARGS || LIST_N(args) == arity) {
result = prim->fn(args); result = prim->fn(ctx, args);
} }
else { else {
ERR("%s expects %d params but got %zu", prim->name, arity, LIST_N(args)); ERR("%s expects %d params but got %zu", prim->name, arity, LIST_N(args));
@ -381,7 +370,7 @@ LakeVal *apply(LakeVal *fnVal, LakeList *args)
} }
/* evaluate body */ /* evaluate body */
result = eval_exprs1(env, fn->body); result = eval_exprs1(ctx, env, fn->body);
} }
else { else {
ERR("not a function: %s", repr(fnVal)); ERR("not a function: %s", repr(fnVal));

View file

@ -13,10 +13,11 @@
#include "env.h" #include "env.h"
#include "lake.h" #include "lake.h"
LakeVal *eval(Env *env, LakeVal *expr); LakeVal *eval(LakeCtx *ctx, Env *env, LakeVal *expr);
LakeList *eval_exprs(Env *env, LakeList *exprs); LakeList *eval_exprs(LakeCtx *ctx, Env *env, LakeList *exprs);
LakeVal *eval_exprs1(Env *env, LakeList *exprs); LakeVal *eval_exprs1(LakeCtx *ctx, Env *env, LakeList *exprs);
LakeVal *apply(LakeVal *fnVal, LakeList *args); LakeVal *apply(LakeCtx *ctx, LakeVal *fnVal, LakeList *args);
gboolean is_special_form(LakeList *expr); gboolean is_special_form(LakeCtx *ctx, LakeList *expr);
void init_special_form_handlers(LakeCtx *ctx);
#endif #endif

View file

@ -8,8 +8,8 @@
*/ */
#include <glib.h> #include <glib.h>
#include "bool.h"
#include "int.h" #include "int.h"
#include "lake.h"
static LakeInt *int_alloc(void) static LakeInt *int_alloc(void)
{ {

View file

@ -23,11 +23,7 @@
#include "parse.h" #include "parse.h"
#include "primitive.h" #include "primitive.h"
#include "string.h" #include "string.h"
#include "symtable.h"
static LakeBool _T = { { TYPE_BOOL, sizeof(LakeBool) }, TRUE };
static LakeBool _F = { { TYPE_BOOL, sizeof(LakeBool) }, FALSE };
LakeBool *T = &_T;
LakeBool *F = &_F;
char *type_name(LakeVal *expr) char *type_name(LakeVal *expr)
{ {
@ -50,7 +46,7 @@ static char first_char(char *s)
return c; return c;
} }
static LakeVal *prompt_read(Env *env, char *prompt) static LakeVal *prompt_read(LakeCtx *ctx, Env *env, char *prompt)
{ {
static int n = 1024; static int n = 1024;
printf("%s", prompt); printf("%s", prompt);
@ -69,20 +65,20 @@ static LakeVal *prompt_read(Env *env, char *prompt)
/* parse list expressions */ /* parse list expressions */
if (first_char(buf) == '(') { if (first_char(buf) == '(') {
return parse_expr(buf, strlen(buf)); return parse_expr(ctx, buf, strlen(buf));
} }
/* try to parse a naked call without parens /* try to parse a naked call without parens
(makes the repl more palatable) */ (makes the repl more palatable) */
LakeList *list = parse_naked_list(buf, strlen(buf)); LakeList *list = parse_naked_list(ctx, buf, strlen(buf));
if (!list) return NULL; if (!list || LIST_N(list) == 0) return NULL;
LakeVal *result; LakeVal *result;
/* naked call */ /* naked call */
LakeVal *head; LakeVal *head;
if (is_special_form(list) || if (is_special_form(ctx, list) ||
(LIST_N(list) > 1 && (head = eval(env, LIST_VAL(list, 0))) && CALLABLE(head))) { (LIST_N(list) > 1 && (head = eval(ctx, env, LIST_VAL(list, 0))) && CALLABLE(head))) {
result = VAL(list); result = VAL(list);
} }
@ -109,7 +105,7 @@ char *repr(LakeVal *expr)
break; break;
case TYPE_BOOL: case TYPE_BOOL:
s = bool_repr(BOOL(expr)); s = BOOL_REPR(BOOL(expr));
break; break;
case TYPE_INT: case TYPE_INT:
@ -192,20 +188,20 @@ gboolean lake_equal(LakeVal *a, LakeVal *b)
} }
} }
static void run_repl(Env *env) static void run_repl(LakeCtx *ctx, Env *env)
{ {
puts("Lake Scheme v" LAKE_VERSION); puts("Lake Scheme v" LAKE_VERSION);
LakeVal *expr; LakeVal *expr;
LakeVal *result; LakeVal *result;
for (;;) { for (;;) {
expr = prompt_read(env, "> "); expr = prompt_read(ctx, env, "> ");
if (expr == VAL(EOF)) break; if (expr == VAL(EOF)) break;
if (expr == VAL(PARSE_ERR)) { if (expr == VAL(PARSE_ERR)) {
ERR("parse error"); ERR("parse error");
continue; continue;
} }
if (expr) { if (expr) {
result = eval(env, expr); result = eval(ctx, env, expr);
if (result) print(result); if (result) print(result);
} }
} }
@ -246,10 +242,32 @@ char *read_file(char const *filename)
} }
} }
LakeBool *bool_make(gboolean val)
{
LakeBool *b = g_malloc(sizeof(LakeBool));
VAL(b)->type = TYPE_BOOL;
VAL(b)->size = sizeof(LakeBool);
b->val = val;
return b;
}
LakeCtx *lake_init(void)
{
LakeCtx *ctx = g_malloc(sizeof(LakeCtx));
ctx->toplevel = env_make(NULL);
ctx->symbols = g_hash_table_new(g_str_hash, g_str_equal);
ctx->special_form_handlers = symtable_make();
ctx->T = bool_make(TRUE);
ctx->F = bool_make(FALSE);
return ctx;
}
int main (int argc, char const *argv[]) int main (int argc, char const *argv[])
{ {
/* create a top level environment */ /* create an execution context */
Env *env = primitive_bindings(); LakeCtx *ctx = lake_init();
bind_primitives(ctx);
init_special_form_handlers(ctx);
/* create and bind args */ /* create and bind args */
LakeVal **argVals = g_malloc(argc * sizeof(LakeVal *)); LakeVal **argVals = g_malloc(argc * sizeof(LakeVal *));
@ -259,21 +277,21 @@ int main (int argc, char const *argv[])
} }
LakeList *args = list_from_array(argc, argVals); LakeList *args = list_from_array(argc, argVals);
free(argVals); free(argVals);
env_define(env, sym_intern("args"), VAL(args)); env_define(ctx->toplevel, sym_intern(ctx, "args"), VAL(args));
/* if a filename is given load the file */ /* if a filename is given load the file */
if (argc > 1) { if (argc > 1) {
char *text = read_file(argv[1]); char *text = read_file(argv[1]);
if (text) { if (text) {
LakeList *exprs = parse_exprs(text, strlen(text)); LakeList *exprs = parse_exprs(ctx, text, strlen(text));
if (exprs) { if (exprs) {
eval_exprs(env, exprs); eval_exprs(ctx, ctx->toplevel, exprs);
} }
} }
} }
/* run the repl */ /* run the repl */
run_repl(env); run_repl(ctx, ctx->toplevel);
return 0; return 0;
} }

View file

@ -65,14 +65,15 @@ struct lake_bool {
}; };
typedef struct lake_bool LakeBool; typedef struct lake_bool LakeBool;
LakeBool *T;
LakeBool *F;
#define BOOL_VAL(x) (x->val) #define BOOL_VAL(x) (x->val)
#define IS_TRUE(x) (VAL(x) == VAL(T)) #define IS_TRUE(ctx, x) (VAL(x) == VAL(ctx->T))
#define IS_FALSE(x) (VAL(x) == VAL(F)) #define IS_FALSE(ctx, x) (VAL(x) == VAL(ctx->F))
#define IS_TRUTHY(x) (!IS_FALSE(x)) #define IS_TRUTHY(ctx, x) (!IS_FALSE(ctx, x))
#define IS_FALSY(x) (IS_FALSE(x)) #define IS_FALSY(ctx, x) (IS_FALSE(ctx, x))
#define BOOL_FROM_INT(ctx, n) (n ? ctx->T : ctx->F)
#define BOOL_REPR(b) (g_strdup(BOOL_VAL(b) ? "#t" : "#f"))
#define BOOL_AND(ctx, a, b) (IS_TRUTHY(ctx, a) && IS_TRUTHY(ctx, b) ? b : a)
#define BOOL_OR(ctx, a, b) (IS_TRUTHY(ctx, a) ? a : b)
struct lake_int { struct lake_int {
LakeVal base; LakeVal base;
@ -114,7 +115,19 @@ typedef struct lake_dlist LakeDottedList;
#define DLIST_HEAD(x) (x->head) #define DLIST_HEAD(x) (x->head)
#define DLIST_TAIL(x) (x->tail) #define DLIST_TAIL(x) (x->tail)
typedef LakeVal *(*lake_prim)(LakeList *args); #include "env.h"
/* Execution context */
struct lake_ctx {
Env *toplevel;
GHashTable *symbols;
GHashTable *special_form_handlers;
LakeBool *T;
LakeBool *F;
};
typedef struct lake_ctx LakeCtx;
typedef LakeVal *(*lake_prim)(LakeCtx *ctx, LakeList *args);
struct lake_primitive { struct lake_primitive {
LakeVal base; LakeVal base;
@ -127,7 +140,6 @@ typedef struct lake_primitive LakePrimitive;
#define PRIM_ARITY(x) (x->arity) #define PRIM_ARITY(x) (x->arity)
#define ARITY_VARARGS -1 #define ARITY_VARARGS -1
#include "env.h"
struct lake_fn { struct lake_fn {
LakeVal base; LakeVal base;
@ -164,7 +176,6 @@ char *repr(LakeVal *val);
#define OOM() DIE("%s:%d out of memory", __FILE__, __LINE__) #define OOM() DIE("%s:%d out of memory", __FILE__, __LINE__)
#include "sym.h" #include "sym.h"
#include "bool.h"
#include "int.h" #include "int.h"
#include "string.h" #include "string.h"
#include "list.h" #include "list.h"

View file

@ -24,6 +24,7 @@ struct context {
size_t n; size_t n;
size_t i; size_t i;
size_t mark; size_t mark;
LakeCtx *lake_ctx;
}; };
typedef struct context Ctx; typedef struct context Ctx;
@ -46,17 +47,17 @@ static void warn_trailing(Ctx *ctx)
} }
} }
LakeVal *parse_expr(char *s, size_t n) LakeVal *parse_expr(LakeCtx *lake_ctx, char *s, size_t n)
{ {
Ctx ctx = { s, n, 0, 0 }; Ctx ctx = { s, n, 0, 0, lake_ctx };
LakeVal *result = _parse_expr(&ctx); LakeVal *result = _parse_expr(&ctx);
warn_trailing(&ctx); warn_trailing(&ctx);
return result; return result;
} }
LakeList *parse_exprs(char *s, size_t n) LakeList *parse_exprs(LakeCtx *lake_ctx, char *s, size_t n)
{ {
Ctx ctx = { s, n, 0, 0 }; Ctx ctx = { s, n, 0, 0, lake_ctx };
LakeList *results = list_make(); LakeList *results = list_make();
LakeVal *result; LakeVal *result;
while (ctx.i < ctx.n) { while (ctx.i < ctx.n) {
@ -73,9 +74,9 @@ LakeList *parse_exprs(char *s, size_t n)
return results; return results;
} }
LakeList *parse_naked_list(char *s, size_t n) LakeList *parse_naked_list(LakeCtx *lake_ctx, char *s, size_t n)
{ {
Ctx ctx = { s, n, 0, 0 }; Ctx ctx = { s, n, 0, 0, lake_ctx };
LakeList *list = list_make(); LakeList *list = list_make();
char c; char c;
maybe_spaces(&ctx); maybe_spaces(&ctx);
@ -224,13 +225,13 @@ static LakeVal *parse_sym(Ctx *ctx)
} }
s[i] = '\0'; s[i] = '\0';
if (g_strcmp0(s, "#t") == 0) { if (g_strcmp0(s, "#t") == 0) {
val = VAL(T); val = VAL(ctx->lake_ctx->T);
} }
else if (g_strcmp0(s, "#f") == 0) { else if (g_strcmp0(s, "#f") == 0) {
val = VAL(F); val = VAL(ctx->lake_ctx->F);
} }
else { else {
val = VAL(sym_intern(s)); val = VAL(sym_intern(ctx->lake_ctx, s));
} }
return val; return val;
} }
@ -331,7 +332,7 @@ static LakeVal *parse_quoted(Ctx *ctx)
{ {
ch(ctx, '\''); ch(ctx, '\'');
LakeList *list = list_make(); LakeList *list = list_make();
list_append(list, VAL(sym_intern("quote"))); list_append(list, VAL(sym_intern(ctx->lake_ctx, "quote")));
list_append(list, _parse_expr(ctx)); list_append(list, _parse_expr(ctx));
return VAL(list); return VAL(list);
} }
@ -384,6 +385,7 @@ static LakeVal *_parse_expr(Ctx *ctx)
ERR("unexpected char '%c'", c); ERR("unexpected char '%c'", c);
result = VAL(PARSE_ERR); result = VAL(PARSE_ERR);
ctx->i = ctx->n; /* consume the rest */ ctx->i = ctx->n; /* consume the rest */
result = NULL;
} }
maybe_spaces(ctx); maybe_spaces(ctx);

View file

@ -16,8 +16,8 @@
#define PARSE_EOF -1 #define PARSE_EOF -1
#define PARSE_ERR -2 #define PARSE_ERR -2
LakeVal *parse_expr(char *s, size_t n); LakeVal *parse_expr(LakeCtx *ctx, char *s, size_t n);
LakeList *parse_exprs(char *s, size_t n); LakeList *parse_exprs(LakeCtx *ctx, char *s, size_t n);
LakeList *parse_naked_list(char *s, size_t n); LakeList *parse_naked_list(LakeCtx *ctx, char *s, size_t n);
#endif #endif

View file

@ -41,7 +41,7 @@ char *prim_repr(LakePrimitive *prim)
return g_strdup_printf("<#primitive:%s(%d)>", prim->name, prim->arity); return g_strdup_printf("<#primitive:%s(%d)>", prim->name, prim->arity);
} }
static LakeVal *_car(LakeList *args) static LakeVal *_car(LakeCtx *ctx, LakeList *args)
{ {
LakeList *list = LIST(LIST_VAL(args, 0)); LakeList *list = LIST(LIST_VAL(args, 0));
if (IS(TYPE_LIST, list) && LIST_N(list) > 0) { if (IS(TYPE_LIST, list) && LIST_N(list) > 0) {
@ -51,7 +51,7 @@ static LakeVal *_car(LakeList *args)
return NULL; return NULL;
} }
static LakeVal *_cdr(LakeList *args) static LakeVal *_cdr(LakeCtx *ctx, LakeList *args)
{ {
LakeList *list = LIST(LIST_VAL(args, 0)); LakeList *list = LIST(LIST_VAL(args, 0));
if (IS(TYPE_LIST, list) && LIST_N(list) > 0) { if (IS(TYPE_LIST, list) && LIST_N(list) > 0) {
@ -63,45 +63,45 @@ static LakeVal *_cdr(LakeList *args)
return NULL; return NULL;
} }
static LakeVal *_cons(LakeList *args) static LakeVal *_cons(LakeCtx *ctx, LakeList *args)
{ {
LakeVal *car = LIST_VAL(args, 0); LakeVal *car = LIST_VAL(args, 0);
LakeVal *cdr = LIST_VAL(args, 1); LakeVal *cdr = LIST_VAL(args, 1);
return VAL(list_cons(car, cdr)); return VAL(list_cons(car, cdr));
} }
static LakeVal *_nullP(LakeList *args) static LakeVal *_nullP(LakeCtx *ctx, LakeList *args)
{ {
LakeVal *val = list_shift(args); LakeVal *val = list_shift(args);
LakeBool *is_null = IS(TYPE_LIST, val) && LIST_N(LIST(val)) == 0 ? T : F; LakeBool *is_null = BOOL_FROM_INT(ctx, IS(TYPE_LIST, val) && LIST_N(LIST(val)) == 0);
return VAL(is_null); return VAL(is_null);
} }
static LakeVal *_pairP(LakeList *args) static LakeVal *_pairP(LakeCtx *ctx, LakeList *args)
{ {
LakeVal *val = list_shift(args); LakeVal *val = list_shift(args);
LakeBool *is_pair = IS(TYPE_LIST, val) && LIST_N(LIST(val)) > 0 ? T : F; LakeBool *is_pair = BOOL_FROM_INT(ctx, IS(TYPE_LIST, val) && LIST_N(LIST(val)) > 0);
return VAL(is_pair); return VAL(is_pair);
} }
static LakeVal *_isP(LakeList *args) static LakeVal *_isP(LakeCtx *ctx, LakeList *args)
{ {
LakeVal *a = LIST_VAL(args, 0); LakeVal *a = LIST_VAL(args, 0);
LakeVal *b = LIST_VAL(args, 1); LakeVal *b = LIST_VAL(args, 1);
return VAL(bool_from_int(lake_is(a, b))); return VAL(BOOL_FROM_INT(ctx, lake_is(a, b)));
} }
static LakeVal *_equalP(LakeList *args) static LakeVal *_equalP(LakeCtx *ctx, LakeList *args)
{ {
LakeVal *a = LIST_VAL(args, 0); LakeVal *a = LIST_VAL(args, 0);
LakeVal *b = LIST_VAL(args, 1); LakeVal *b = LIST_VAL(args, 1);
return VAL(bool_from_int(lake_equal(a, b))); return VAL(BOOL_FROM_INT(ctx, lake_equal(a, b)));
} }
static LakeVal *_not(LakeList *args) static LakeVal *_not(LakeCtx *ctx, LakeList *args)
{ {
LakeVal *val = list_shift(args); LakeVal *val = list_shift(args);
LakeBool *not = IS_FALSE(val) ? T : F; LakeBool *not = BOOL_FROM_INT(ctx, IS_FALSE(ctx, val));
return VAL(not); return VAL(not);
} }
@ -112,7 +112,7 @@ static LakeVal *_not(LakeList *args)
} \ } \
} while (0) } while (0)
static LakeVal *_add(LakeList *args) static LakeVal *_add(LakeCtx *ctx, LakeList *args)
{ {
int result = 0; int result = 0;
size_t n = LIST_N(args); size_t n = LIST_N(args);
@ -125,7 +125,7 @@ static LakeVal *_add(LakeList *args)
return VAL(int_from_c(result)); return VAL(int_from_c(result));
} }
static LakeVal *_sub(LakeList *args) static LakeVal *_sub(LakeCtx *ctx, LakeList *args)
{ {
size_t n = LIST_N(args); size_t n = LIST_N(args);
@ -144,7 +144,7 @@ static LakeVal *_sub(LakeList *args)
return VAL(int_from_c(result)); return VAL(int_from_c(result));
} }
static LakeVal *_mul(LakeList *args) static LakeVal *_mul(LakeCtx *ctx, LakeList *args)
{ {
int result = 1; int result = 1;
size_t n = LIST_N(args); size_t n = LIST_N(args);
@ -159,7 +159,7 @@ static LakeVal *_mul(LakeList *args)
#define DIVIDE_BY_ZERO() ERR("divide by zero") #define DIVIDE_BY_ZERO() ERR("divide by zero")
static LakeVal *_div(LakeList *args) static LakeVal *_div(LakeCtx *ctx, LakeList *args)
{ {
size_t n = LIST_N(args); size_t n = LIST_N(args);
@ -195,7 +195,7 @@ static LakeVal *_div(LakeList *args)
return VAL(int_from_c(result)); return VAL(int_from_c(result));
} }
static LakeVal *_int_eq(LakeList *args) static LakeVal *_int_eq(LakeCtx *ctx, LakeList *args)
{ {
gboolean result = TRUE; gboolean result = TRUE;
size_t n = LIST_N(args); size_t n = LIST_N(args);
@ -210,10 +210,10 @@ static LakeVal *_int_eq(LakeList *args)
} }
prev = INT_VAL(INT(v)); prev = INT_VAL(INT(v));
} }
return VAL(bool_from_int(result)); return VAL(BOOL_FROM_INT(ctx, result));
} }
static LakeVal *_int_lt(LakeList *args) static LakeVal *_int_lt(LakeCtx *ctx, LakeList *args)
{ {
gboolean result = TRUE; gboolean result = TRUE;
size_t n = LIST_N(args); size_t n = LIST_N(args);
@ -231,10 +231,10 @@ static LakeVal *_int_lt(LakeList *args)
prev = INT_VAL(INT(v)); prev = INT_VAL(INT(v));
} }
} }
return VAL(bool_from_int(result)); return VAL(BOOL_FROM_INT(ctx, result));
} }
static LakeVal *_int_gt(LakeList *args) static LakeVal *_int_gt(LakeCtx *ctx, LakeList *args)
{ {
gboolean result = TRUE; gboolean result = TRUE;
size_t n = LIST_N(args); size_t n = LIST_N(args);
@ -252,14 +252,15 @@ static LakeVal *_int_gt(LakeList *args)
prev = INT_VAL(INT(v)); prev = INT_VAL(INT(v));
} }
} }
return VAL(bool_from_int(result)); return VAL(BOOL_FROM_INT(ctx, result));
} }
Env *primitive_bindings(void) void bind_primitives(LakeCtx *ctx)
{ {
#define DEFINE(name, fn, arity) env_define(env, sym_intern(name), VAL(prim_make(name, arity, fn))) #define DEFINE(name, fn, arity) env_define(ctx->toplevel, \
sym_intern(ctx, name), \
Env *env = env_toplevel(); VAL(prim_make(name, arity, fn)))
DEFINE("car", _car, 1); DEFINE("car", _car, 1);
DEFINE("cdr", _cdr, 1); DEFINE("cdr", _cdr, 1);
DEFINE("cons", _cons, 2); DEFINE("cons", _cons, 2);
@ -291,6 +292,4 @@ Env *primitive_bindings(void)
/* string> */ /* string> */
/* string-concatenate */ /* string-concatenate */
/* string-slice */ /* string-slice */
return env;
} }

View file

@ -15,6 +15,6 @@
LakePrimitive *prim_make(char *name, int arity, lake_prim fn); LakePrimitive *prim_make(char *name, int arity, lake_prim fn);
char *prim_repr(LakePrimitive *prim); char *prim_repr(LakePrimitive *prim);
Env *primitive_bindings(void); void bind_primitives(LakeCtx *ctx);
#endif #endif

View file

@ -16,8 +16,6 @@
#include "string.h" #include "string.h"
#include "sym.h" #include "sym.h"
static GHashTable *_symbols;
static LakeSym *sym_alloc(void) static LakeSym *sym_alloc(void)
{ {
LakeSym *sym = g_malloc(sizeof(LakeSym)); LakeSym *sym = g_malloc(sizeof(LakeSym));
@ -26,16 +24,15 @@ static LakeSym *sym_alloc(void)
return sym; return sym;
} }
LakeSym *sym_intern(char *s) LakeSym *sym_intern(LakeCtx *ctx, char *s)
{ {
if (!_symbols) _symbols = g_hash_table_new(g_str_hash, g_str_equal); LakeSym *sym = g_hash_table_lookup(ctx->symbols, s);
LakeSym *sym = g_hash_table_lookup(_symbols, s);
if (!sym) { if (!sym) {
sym = sym_alloc(); sym = sym_alloc();
sym->n = strlen(s); sym->n = strlen(s);
sym->s = g_strdup(s); sym->s = g_strdup(s);
sym->hash = g_str_hash(s); sym->hash = g_str_hash(s);
g_hash_table_insert(_symbols, sym->s, sym); g_hash_table_insert(ctx->symbols, sym->s, sym);
} }
return sym; return sym;
} }
@ -45,9 +42,9 @@ LakeStr *sym_to_str(LakeSym *sym)
return str_from_c(sym->s); return str_from_c(sym->s);
} }
LakeSym *sym_from_str(LakeStr *str) LakeSym *sym_from_str(LakeCtx *ctx, LakeStr *str)
{ {
return sym_intern(str->s); return sym_intern(ctx, str->s);
} }
char *sym_repr(LakeSym *sym) char *sym_repr(LakeSym *sym)

View file

@ -12,9 +12,9 @@
#include "lake.h" #include "lake.h"
LakeSym *sym_intern(char *s); LakeSym *sym_intern(LakeCtx *ctx, char *s);
LakeStr *sym_to_str(LakeSym *sym); LakeStr *sym_to_str(LakeSym *sym);
LakeSym *sym_from_str(LakeStr *str); LakeSym *sym_from_str(LakeCtx *ctx, LakeStr *str);
char *sym_repr(LakeSym *sym); char *sym_repr(LakeSym *sym);
unsigned long sym_val(LakeSym *sym); unsigned long sym_val(LakeSym *sym);