Evaluation#
Because Lisp code is represented with data structures, each data structure can be used as interpreter instruction. Evaluation of data, when used as interpreter expression, is defined according to data type:
number, string, builtin function, builtin syntax, function, syntax
Data of this type evaluate to itself (expression consisting of single instance of data evaluates to provided data instance).
symbol
Symbols evaluate to data associated to provided symbol in current evaluation context. If context entry associated with the symbol is not available, evaluation error is signaled.
pair/list
Lists evaluate to function/syntax application. As first step, first element of list is evaluated. If first element evaluates to function or builtin function, all remaining elements are also evaluated and used as provided arguments. If first element evaluates to syntax or builtin syntax, remaining list elements are not evaluated and are used as provided arguments. After evaluation of first element and possible argument evaluation (in case of functions), evaluation is delegated to function/syntax application (described in following chapters). If first list element doesn’t evaluate to function/syntax, evaluation error is signaled. Exception to this rule is empty list which evaluates to itself.
Source code#
eval.h#
#ifndef LISP16_EVAL_H
#define LISP16_EVAL_H
#include "env.h"
lsp_status_t lsp_eval(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t value);
#endif
eval.c#
#include "eval.h"
#include "ctx.h"
#include "apply.h"
static lsp_status_t eval_args(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args,
lsp_addr_t *result) {
lsp_addr_t last = e->m->nil;
*result = e->m->nil;
lsp_status_t status;
while (args != e->m->nil) {
lsp_addr_t arg = lsp_mem_get_pair_first(e->m, args);
status = lsp_env_resolve(e, ctx, arg, &arg);
if (status != LSP_SUCCESS)
goto error;
lsp_addr_t new_last;
status = lsp_mem_create_pair(e->m, arg, e->m->nil, &new_last);
lsp_mem_dec_ref(e->m, arg);
if (status != LSP_SUCCESS)
goto error;
if (*result == e->m->nil) {
*result = new_last;
} else {
lsp_mem_set_pair_second(e->m, last, new_last);
lsp_mem_dec_ref(e->m, new_last);
}
last = new_last;
args = lsp_mem_get_pair_second(e->m, args);
}
return LSP_SUCCESS;
error:
lsp_mem_dec_ref(e->m, *result);
return status;
}
lsp_status_t lsp_eval(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t value) {
lsp_status_t status = LSP_SUCCESS;
if (lsp_mem_is_number(e->m, value) || lsp_mem_is_string(e->m, value) ||
lsp_mem_is_builtin(e->m, value) ||
lsp_mem_is_function_or_syntax(e->m, value))
return lsp_env_set_result_value(e, value);
if (lsp_mem_is_symbol(e->m, value)) {
lsp_addr_t result;
status = lsp_ctx_get(e->m, ctx, value, &result);
if (status != LSP_SUCCESS)
return status;
status = lsp_env_set_result_value(e, result);
lsp_mem_dec_ref(e->m, result);
return status;
}
if (lsp_mem_is_pair(e->m, value)) {
if (value == e->m->nil)
return lsp_env_set_result_value(e, e->m->nil);
lsp_addr_t callable = lsp_mem_get_pair_first(e->m, value);
lsp_addr_t args = lsp_mem_get_pair_second(e->m, value);
status = lsp_env_resolve(e, ctx, callable, &callable);
if (status != LSP_SUCCESS)
return status;
if (lsp_mem_is_builtin_function(e->m, callable) ||
lsp_mem_is_function(e->m, callable)) {
status = eval_args(e, ctx, args, &args);
} else {
status = lsp_mem_inc_ref(e->m, args);
}
if (status != LSP_SUCCESS) {
lsp_mem_dec_ref(e->m, callable);
return status;
}
status = lsp_apply(e, ctx, callable, args);
lsp_mem_dec_ref(e->m, callable);
lsp_mem_dec_ref(e->m, args);
return status;
}
return LSP_ERR_EVAL;
}