lisp-take-1/evaluate.c

191 lines
5.7 KiB
C

#include <assert.h>
#include <stdio.h>
#include <debug.h>
#include <string/struct.h>
#include <gc/inc_external_refcount.h>
#include <gc/dec_external_refcount.h>
#include <value/struct.h>
#include <value/user_lambda/new.h>
#include <value/environment/new.h>
#include <value/environment/define.h>
#include <value/environment/lookup.h>
#include "evaluate.h"
struct value* evaluate(
struct value* value,
struct value* environment,
struct gc* gc)
{
struct value* retval;
ENTER;
switch (value->kind)
{
case vk_null:
case vk_boolean:
case vk_integer:
case vk_user_lambda:
case vk_builtin_lambda:
{
retval = gc_inc_external_refcount(gc, value);
break;
}
case vk_identifier:
{
struct identifier_value* specific = &value->subclass.identifier;
retval = environment_value_lookup(environment, specific->name);
if (!retval)
{
fprintf(stderr, "unknown variable: %s\n", specific->name->data);
exit(1);
}
break;
}
case vk_list:
{
struct list_value* specific = &value->subclass.list;
struct value* first = evaluate(specific->first, environment, gc);
switch (first->kind)
{
case vk_builtin_lambda:
{
retval = (first->subclass.builtin_lambda.funcptr)(
/* arguments: */ specific->rest,
/* environment: */ environment,
/* garbage collector: */ gc,
/* evalfunc: */ evaluate);
break;
}
case vk_user_lambda:
{
struct user_lambda_value* lambda =
&first->subclass.user_lambda;
struct value* parameter_environment = new_environment_value(
/* garbage collection: */ gc,
/* fallback environment: */ lambda->environment);
struct value *parameter_names, *parameter_expressions;
for (parameter_names = lambda->parameters,
parameter_expressions = specific->rest;
parameter_names->kind == vk_list &&
parameter_expressions->kind == vk_list;
parameter_names = parameter_names->subclass.list.rest,
parameter_expressions = parameter_expressions->subclass.list.rest)
{
struct value* parameter_name = parameter_names->subclass.list.first;
struct value* parameter_expression = parameter_expressions->subclass.list.first;
if (parameter_name->kind != vk_identifier)
{
TODO;
exit(1);
}
struct value* parameter_value = evaluate(
/* expression: */ parameter_expression,
/* environment: */ environment,
/* garbage collection: */ gc);
environment_value_define(
/* environment: */ parameter_environment,
/* name: */ parameter_name->subclass.identifier.name,
/* value: */ parameter_value);
gc_dec_external_refcount(gc, parameter_value);
}
if (parameter_names->kind == vk_list)
{
assert(parameter_expressions->kind == vk_null);
retval = new_user_lambda_value(
/* garbage collection: */ gc,
/* environment: */ parameter_environment,
/* parameter names: */ parameter_names,
/* body: */ lambda->body);
}
else if (parameter_expressions->kind == vk_list)
{
assert(parameter_names->kind == vk_null);
TODO;
exit(1);
}
else
{
retval = evaluate(lambda->body, parameter_environment, gc);
}
gc_dec_external_refcount(gc, parameter_environment);
break;
}
default:
{
TODO;
exit(1);
}
}
gc_dec_external_refcount(gc, first);
break;
}
case vk_quote:
{
struct quote_value* specific = &value->subclass.quote;
retval = gc_inc_external_refcount(gc, specific->subexpression);
break;
}
default:
{
dpvu(value->kind);
TODO;
break;
}
}
EXIT;
return retval;
}