1
0
Fork 0

syntax "define"

This commit is contained in:
Alex Kotov 2023-05-07 17:28:45 +04:00
parent 27337e4624
commit e225caea00
Signed by: kotovalexarian
GPG Key ID: 553C0EBBEB5D5F08
6 changed files with 112 additions and 39 deletions

View File

@ -11,10 +11,15 @@
static struct Object *lookup(struct Object *namespace, struct Object *name); static struct Object *lookup(struct Object *namespace, struct Object *name);
static struct Object *eval_list(struct Object *object); static struct Object *eval_list(
struct Object *object,
struct Object *environment
);
struct Object *eval_str(const char *const str) struct Object *eval_str(
{ const char *const str,
struct Object *const environment
) {
assert(str); assert(str);
Tokens tokens = Tokens_new(); Tokens tokens = Tokens_new();
@ -34,16 +39,21 @@ struct Object *eval_str(const char *const str)
struct Object *const program = parse(tokens); struct Object *const program = parse(tokens);
TOKENS_DELETE(tokens); TOKENS_DELETE(tokens);
return eval(program); return eval(program, environment);
} }
struct Object *eval(struct Object *const object) struct Object *eval(
{ struct Object *const object,
struct Object *const environment
) {
assert(Object_is_pair(environment));
assert(OBJECT_IS_NULL(environment->pair.cdr));
// NULL is an empty list, can't eval // NULL is an empty list, can't eval
assert(object); assert(!OBJECT_IS_NULL(object));
// SYMBOL performs lookup // SYMBOL performs lookup
if (Object_is_symbol(object)) return lookup(NULL, object); if (Object_is_symbol(object)) return lookup(environment->pair.car, object);
// Almost everything evaluates to itself // Almost everything evaluates to itself
if (!Object_is_pair(object)) return object; if (!Object_is_pair(object)) return object;
@ -52,19 +62,30 @@ struct Object *eval(struct Object *const object)
struct Object *const args = object->pair.cdr; struct Object *const args = object->pair.cdr;
if (Object_is_symbol(func_expr)) { if (Object_is_symbol(func_expr)) {
if (strcmp(func_expr->s, "begin") == 0) return syntax_begin(args); if (strcmp(func_expr->s, "begin") == 0) {
if (strcmp(func_expr->s, "quote") == 0) return syntax_quote(args); return syntax_begin(args, environment);
if (strcmp(func_expr->s, "if") == 0) return syntax_if(args); }
if (strcmp(func_expr->s, "define") == 0) {
return syntax_define(args, environment);
}
if (strcmp(func_expr->s, "quote") == 0) {
return syntax_quote(args, environment);
}
if (strcmp(func_expr->s, "if") == 0) {
return syntax_if(args, environment);
}
} }
struct Object *const func = eval(func_expr); struct Object *const func = eval(func_expr, environment);
assert(Object_is_procedure(func)); assert(Object_is_procedure(func));
struct Object *const evaluated_args = eval_list(args); struct Object *const evaluated_args = eval_list(args, environment);
return Object_procedure_call(func, evaluated_args); return Object_procedure_call(func, evaluated_args);
} }
struct Object *eval_list(struct Object *const object) struct Object *eval_list(
{ struct Object *const object,
struct Object *const environment
) {
assert(OBJECT_IS_LIST_HEAD(object)); assert(OBJECT_IS_LIST_HEAD(object));
if (OBJECT_IS_NULL(object)) return NULL; if (OBJECT_IS_NULL(object)) return NULL;
@ -72,12 +93,12 @@ struct Object *eval_list(struct Object *const object)
if (OBJECT_IS_NULL(object->pair.car)) { if (OBJECT_IS_NULL(object->pair.car)) {
return Object_new_pair( return Object_new_pair(
NULL, NULL,
eval_list(object->pair.cdr) eval_list(object->pair.cdr, environment)
); );
} else { } else {
return Object_new_pair( return Object_new_pair(
eval(object->pair.car), eval(object->pair.car, environment),
eval_list(object->pair.cdr) eval_list(object->pair.cdr, environment)
); );
} }
} }

View File

@ -3,7 +3,7 @@
#include "object.h" #include "object.h"
struct Object *eval_str(const char * str); struct Object *eval_str(const char * str, struct Object *environment);
struct Object *eval(struct Object *object); struct Object *eval(struct Object *object, struct Object *environment);
#endif #endif

View File

@ -32,6 +32,8 @@ void repl()
{ {
printf("Lisp by Causa Arcana\n\n"); printf("Lisp by Causa Arcana\n\n");
struct Object *const environment = Object_new_pair(NULL, NULL);
while (true) { while (true) {
Tokens tokens = Tokens_new(); Tokens tokens = Tokens_new();
assert(tokens); assert(tokens);
@ -60,14 +62,17 @@ void repl()
struct Object *const program = parse(tokens); struct Object *const program = parse(tokens);
TOKENS_DELETE(tokens); TOKENS_DELETE(tokens);
struct Object *const result = eval(program); struct Object *const result = eval(program, environment);
printf("=> "); printf("=> ");
eval(Object_build_list( eval(
2, Object_build_list(
Object_new_symbol("displayln"), 2,
Object_build_list(2, Object_new_symbol("quote"), result) Object_new_symbol("displayln"),
)); Object_build_list(2, Object_new_symbol("quote"), result)
),
environment
);
} }
} }
@ -92,5 +97,6 @@ void script()
struct Object *const program = parse(tokens); struct Object *const program = parse(tokens);
TOKENS_DELETE(tokens); TOKENS_DELETE(tokens);
eval(program); struct Object *const environment = Object_new_pair(NULL, NULL);
eval(program, environment);
} }

View File

@ -5,20 +5,46 @@
#include <assert.h> #include <assert.h>
struct Object *syntax_begin(struct Object *args) struct Object *syntax_begin(
{ struct Object *args,
struct Object *const environment
) {
assert(OBJECT_IS_LIST_HEAD(args)); assert(OBJECT_IS_LIST_HEAD(args));
struct Object *result = NULL; struct Object *result = NULL;
while (!OBJECT_IS_NULL(args)) { while (!OBJECT_IS_NULL(args)) {
assert(Object_is_pair(args)); assert(Object_is_pair(args));
result = eval(args->pair.car); result = eval(args->pair.car, environment);
args = args->pair.cdr; args = args->pair.cdr;
} }
return result; return result;
} }
struct Object *syntax_if(struct Object *const args) struct Object *syntax_define(
{ struct Object *const args,
struct Object *const environment
) {
assert(Object_is_pair(args));
struct Object *const name = args->pair.car;
assert(Object_is_symbol(name));
assert(Object_is_pair(args->pair.cdr));
struct Object *const value_expr = args->pair.cdr->pair.car;
assert(OBJECT_IS_NULL(args->pair.cdr->pair.cdr));
assert(Object_is_pair(environment));
assert(OBJECT_IS_NULL(environment->pair.cdr));
assert(OBJECT_IS_LIST_HEAD(environment->pair.car));
environment->pair.car = Object_new_pair(
Object_new_pair(name, eval(value_expr, environment)),
environment->pair.car
);
return NULL;
}
struct Object *syntax_if(
struct Object *const args,
struct Object *const environment
) {
assert(Object_is_pair(args)); assert(Object_is_pair(args));
struct Object *const cond = args->pair.car; struct Object *const cond = args->pair.car;
struct Object *const then_else_list = args->pair.cdr; struct Object *const then_else_list = args->pair.cdr;
@ -32,14 +58,18 @@ struct Object *syntax_if(struct Object *const args)
assert(OBJECT_IS_NULL(else_list->pair.cdr)); assert(OBJECT_IS_NULL(else_list->pair.cdr));
if (Object_is_false(cond)) { if (Object_is_false(cond)) {
return eval(else_branch); return eval(else_branch, environment);
} else { } else {
return eval(then_branch); return eval(then_branch, environment);
} }
} }
struct Object *syntax_quote(struct Object *const args) struct Object *syntax_quote(
{ struct Object *const args,
struct Object *const environment
) {
(void)environment; // unused
assert(Object_is_pair(args)); assert(Object_is_pair(args));
assert(OBJECT_IS_NULL(args->pair.cdr)); assert(OBJECT_IS_NULL(args->pair.cdr));
return args->pair.car; return args->pair.car;

View File

@ -3,8 +3,9 @@
#include "object.h" #include "object.h"
struct Object *syntax_begin(struct Object *args); struct Object *syntax_begin(struct Object *args, struct Object *environment);
struct Object *syntax_if(struct Object *args); struct Object *syntax_define(struct Object *args, struct Object *environment);
struct Object *syntax_quote(struct Object *args); struct Object *syntax_if(struct Object *args, struct Object *environment);
struct Object *syntax_quote(struct Object *args, struct Object *environment);
#endif #endif

View File

@ -5,6 +5,21 @@
(assert-equal 456 (begin 123 456)) (assert-equal 456 (begin 123 456))
(assert-equal 789 (begin 123 456 789)) (assert-equal 789 (begin 123 456 789))
;;; define ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(assert-equal
'(123 579)
(begin
(define x 123)
(define y (+ x 456))
(list x y)))
(assert-equal
'(123 456)
(begin
(define x 123)
(define old x)
(define x 456)
(list old x)))
;;; if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(assert-equal 123 (if #true 123 456)) (assert-equal 123 (if #true 123 456))
(assert-equal 123 (if "foo" 123 456)) (assert-equal 123 (if "foo" 123 456))