86 lines
2.0 KiB
C
86 lines
2.0 KiB
C
#include "eval.h"
|
|
|
|
#include "builtins.h"
|
|
#include "lexer.h"
|
|
#include "parser.h"
|
|
#include "syntax.h"
|
|
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
static struct Object *eval_list(struct Object *object);
|
|
|
|
struct Object *eval_str(const char *const str)
|
|
{
|
|
assert(str);
|
|
|
|
Tokens tokens = Tokens_new();
|
|
assert(tokens);
|
|
|
|
Lexer lexer = Lexer_new(tokens);
|
|
assert(lexer);
|
|
|
|
for (const char *chr = str; *chr; ++chr) {
|
|
Lexer_lex(lexer, *chr);
|
|
}
|
|
Lexer_lex(lexer, '\n');
|
|
|
|
LEXER_DELETE(lexer);
|
|
assert(Tokens_top(tokens));
|
|
|
|
struct Object *const program = parse(tokens);
|
|
TOKENS_DELETE(tokens);
|
|
|
|
return eval(program);
|
|
}
|
|
|
|
struct Object *eval(struct Object *const object)
|
|
{
|
|
// NULL is an empty list, can't eval
|
|
assert(object);
|
|
|
|
// SYMBOL performs lookup
|
|
if (Object_is_symbol(object)) {
|
|
struct Object *const procedure = builtins_get(object->s);
|
|
assert(procedure);
|
|
return procedure;
|
|
}
|
|
|
|
// Almost everything evaluates to itself
|
|
if (!Object_is_pair(object)) return object;
|
|
|
|
struct Object *const func_expr = object->pair.car;
|
|
struct Object *const args = object->pair.cdr;
|
|
|
|
if (Object_is_symbol(func_expr)) {
|
|
if (strcmp(func_expr->s, "begin") == 0) return syntax_begin(args);
|
|
if (strcmp(func_expr->s, "quote") == 0) return syntax_quote(args);
|
|
if (strcmp(func_expr->s, "if") == 0) return syntax_if(args);
|
|
}
|
|
|
|
struct Object *const func = eval(func_expr);
|
|
assert(Object_is_procedure(func));
|
|
struct Object *const evaluated_args = eval_list(args);
|
|
return Object_procedure_call(func, evaluated_args);
|
|
}
|
|
|
|
struct Object *eval_list(struct Object *const object)
|
|
{
|
|
assert(OBJECT_IS_LIST_HEAD(object));
|
|
|
|
if (OBJECT_IS_NULL(object)) return NULL;
|
|
|
|
if (OBJECT_IS_NULL(object->pair.car)) {
|
|
return Object_new_pair(
|
|
NULL,
|
|
eval_list(object->pair.cdr)
|
|
);
|
|
} else {
|
|
return Object_new_pair(
|
|
eval(object->pair.car),
|
|
eval_list(object->pair.cdr)
|
|
);
|
|
}
|
|
}
|