diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | Makefile | 24 | ||||
| -rw-r--r-- | lisp.c | 18 | ||||
| -rw-r--r-- | main.c | 26 | ||||
| -rw-r--r-- | test.c | 109 |
5 files changed, 156 insertions, 24 deletions
@@ -1,3 +1,4 @@ +*.o lex.yy.* lisp.tab.* -lisp +main @@ -3,15 +3,19 @@ YACC = bison CC = gcc -g CFLAGS = -DYYDEBUG=1 LIBS = -lreadline -lfl -lm +OBJS = lisp.o lisp.tab.o lex.yy.o .SUFFIXES: -lisp: lisp.c lisp.tab.o lex.yy.o - $(CC) $(CFLAGS) -o $@ lisp.c lisp.tab.o lex.yy.o $(LIBS) +main: main.c $(OBJS) + $(CC) $(CFLAGS) -o $@ main.c $(OBJS) $(LIBS) + +lisp.o: lisp.c lisp.h lex.yy.o + $(CC) $(CFLAGS) -c lisp.c lisp.tab.c lisp.tab.h: lisp.y $(YACC) -d lisp.y -lex.yy.c: lisp.l lisp.tab.h +lex.yy.c lex.yy.h: lisp.l lisp.tab.h $(LEX) --header-file=lex.yy.h lisp.l lisp.tab.o: lisp.tab.c @@ -21,6 +25,16 @@ lex.yy.o: lex.yy.c $(CC) $(CFLAGS) -c lex.yy.c clean: - rm -f *.o lisp lisp.tab.c lisp.tab.h lex.yy.c lex.yy.h + rm -f *.o main test lisp.tab.c lisp.tab.h lex.yy.c lex.yy.h + +test: test.o $(OBJS) + $(CC) $(CFLAGS) -o $@ test.o $(OBJS) $(LIBS) + ./test + +test.o: test.c lisp.h lex.yy.o + $(CC) $(CFLAGS) -c test.c + +run: main + ./main -.PHONY: clean +.PHONY: clean test run @@ -175,21 +175,3 @@ value *eval_pair(env *e, value *v) { } return v; } - -env *global_env = NULL; - -int main(void) { - // init global env - global_env = env_create(NULL); - // START REPL - char* line; - while ((line = readline("λ > ")) != NULL) { - if (*line) { - add_history(line); - } - yy_scan_string(line); - yyparse(); - free(line); - } - return 0; -} @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <readline/readline.h> +#include <readline/history.h> +#include "lisp.h" +#include "lex.yy.h" +#include "lisp.tab.h" + + +env *global_env = NULL; + +int main(void) { + // init global env + global_env = env_create(NULL); + // START REPL + char* line; + while ((line = readline("λ > ")) != NULL) { + if (*line) { + add_history(line); + } + yy_scan_string(line); + yyparse(); + free(line); + } + return 0; +} @@ -0,0 +1,109 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "lisp.h" +#include "lex.yy.h" +#include "lisp.tab.h" + +static int tests_run = 0; +static int tests_failed = 0; + +env *global_env = NULL; + +#define ASSERT(cond, msg) do { \ + tests_run++; \ + if (!(cond)) { \ + tests_failed++; \ + printf("FAIL: %s\n", msg); \ + } else { \ + printf("PASS: %s\n", msg); \ + } \ +} while (0) + +void test_make_int() { + value *v = make_int(42); + ASSERT(v->type == VALTYPE_INT, "make_int sets type"); + ASSERT(v->as.i == 42, "make_int sets value"); +} + +void test_cons_car_cdr() { + value *a = make_int(1); + value *b = make_int(2); + value *p = cons(a, b); + + ASSERT(p->type == VALTYPE_PAIR, "cons creates pair"); + ASSERT(car(p)->as.i == 1, "car works"); + ASSERT(cdr(p)->as.i == 2, "cdr works"); +} + + +void test_env_define_lookup() { + env *e = env_create(NULL); + value *v = make_int(10); + + env_define(e, "x", v); + value *found = env_lookup(e, "x"); + + ASSERT(found != NULL, "env_lookup finds symbol"); + ASSERT(found->as.i == 10, "env_lookup returns correct value"); +} + +void test_env_parent_lookup() { + env *parent = env_create(NULL); + env_define(parent, "x", make_int(5)); + + env *child = env_create(parent); + value *found = env_lookup(child, "x"); + + ASSERT(found != NULL, "lookup finds parent symbol"); + ASSERT(found->as.i == 5, "parent symbol value correct"); +} + +void test_eval_literal() { + env *e = env_create(NULL); + + value *v = make_int(7); + value *r = eval(e, v); + + ASSERT(r->as.i == 7, "eval of int returns itself"); +} + +void test_eval_symbol() { + env *e = env_create(NULL); + env_define(e, "x", make_int(99)); + + value *sym = make_symbol("x"); + value *r = eval(e, sym); + + ASSERT(r->as.i == 99, "eval resolves symbol"); +} + + +void test_define() { + env *e = env_create(NULL); + + value *expr =cons(make_symbol("define"), + cons(make_symbol("x"), + cons(make_int(3), make_nil()))); + + eval(e, expr); + value *r = env_lookup(e, "x"); + + ASSERT(r != NULL, "define creates binding"); + ASSERT(r->as.i == 3, "define sets correct value"); +} + +int main(void) { + test_make_int(); + test_cons_car_cdr(); + test_env_define_lookup(); + test_env_parent_lookup(); + test_eval_literal(); + test_eval_symbol(); + test_define(); + + printf("\nTests run: %d\n", tests_run); + printf("Tests failed: %d\n", tests_failed); + + return tests_failed ? 1 : 0; +} |
