/src/c/eval.d
D | 258 lines | 205 code | 13 blank | 40 comment | 39 complexity | 6c41b4ed08306259fb59891f8bfa4182 MD5 | raw file
Possible License(s): LGPL-2.0, JSON
- /* -*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*- */
- /* vim: set filetype=c tabstop=8 shiftwidth=4 expandtab: */
- /*
- eval.c -- Eval.
- */
- /*
- Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
- Copyright (c) 1990, Giuseppe Attardi.
- Copyright (c) 2001, Juan Jose Garcia Ripoll.
- ECL is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- See file '../Copyright' for full details.
- */
- #include <ecl/ecl.h>
- #include <ecl/ecl-inl.h>
- #include <ecl/internal.h>
- cl_object *
- _ecl_va_sp(cl_narg narg)
- {
- return ecl_process_env()->stack_top - narg;
- }
- /* Calling conventions:
- Compiled C code calls lisp function supplying #args, and args.
- Linking function performs check_args, gets jmp_buf with _setjmp, then
- if cfun then stores C code address into function link location
- and transfers to jmp_buf at cf_self
- if cclosure then replaces #args with cc_env and calls cc_self
- otherwise, it emulates funcall.
- */
- cl_object
- ecl_apply_from_stack_frame(cl_object frame, cl_object x)
- {
- cl_object *sp = frame->frame.base;
- cl_index narg = frame->frame.size;
- cl_object fun = x;
- AGAIN:
- frame->frame.env->function = fun;
- if (ecl_unlikely(fun == OBJNULL || fun == ECL_NIL))
- FEundefined_function(x);
- switch (ecl_t_of(fun)) {
- case t_cfunfixed:
- if (ecl_unlikely(narg != (cl_index)fun->cfun.narg))
- FEwrong_num_arguments(fun);
- return APPLY_fixed(narg, fun->cfunfixed.entry_fixed, sp);
- case t_cfun:
- return APPLY(narg, fun->cfun.entry, sp);
- case t_cclosure:
- return APPLY(narg, fun->cclosure.entry, sp);
- case t_instance:
- switch (fun->instance.isgf) {
- case ECL_STANDARD_DISPATCH:
- case ECL_RESTRICTED_DISPATCH:
- return _ecl_standard_dispatch(frame, fun);
- case ECL_USER_DISPATCH:
- fun = fun->instance.slots[fun->instance.length - 1];
- goto AGAIN;
- case ECL_READER_DISPATCH:
- case ECL_WRITER_DISPATCH:
- return APPLY(narg, fun->instance.entry, sp);
- default:
- FEinvalid_function(fun);
- }
- case t_symbol:
- if (ecl_unlikely(fun->symbol.stype & ecl_stp_macro))
- FEundefined_function(x);
- fun = ECL_SYM_FUN(fun);
- goto AGAIN;
- case t_bytecodes:
- return ecl_interpret(frame, ECL_NIL, fun);
- case t_bclosure:
- return ecl_interpret(frame, fun->bclosure.lex, fun->bclosure.code);
- default:
- FEinvalid_function(x);
- }
- }
- cl_objectfn
- ecl_function_dispatch(cl_env_ptr env, cl_object x)
- {
- cl_object fun = x;
- AGAIN:
- if (ecl_unlikely(fun == OBJNULL || fun == ECL_NIL))
- FEundefined_function(x);
- switch (ecl_t_of(fun)) {
- case t_cfunfixed:
- env->function = fun;
- return fun->cfunfixed.entry;
- case t_cfun:
- env->function = fun;
- return fun->cfun.entry;
- case t_cclosure:
- env->function = fun;
- return fun->cclosure.entry;
- case t_instance:
- env->function = fun;
- return fun->instance.entry;
- case t_symbol:
- if (ecl_unlikely(fun->symbol.stype & ecl_stp_macro))
- FEundefined_function(x);
- fun = ECL_SYM_FUN(fun);
- goto AGAIN;
- case t_bytecodes:
- env->function = fun;
- return fun->bytecodes.entry;
- case t_bclosure:
- env->function = fun;
- return fun->bclosure.entry;
- default:
- FEinvalid_function(x);
- }
- }
- cl_object
- cl_funcall(cl_narg narg, cl_object function, ...)
- {
- cl_object output;
- --narg;
- {
- ECL_STACK_FRAME_VARARGS_BEGIN(narg, function, frame);
- output = ecl_apply_from_stack_frame(frame, function);
- ECL_STACK_FRAME_VARARGS_END(frame);
- }
- return output;
- }
- @(defun apply (fun lastarg &rest args)
- @
- if (narg == 2 && ecl_t_of(lastarg) == t_frame) {
- return ecl_apply_from_stack_frame(lastarg, fun);
- } else {
- cl_object out;
- cl_index i;
- struct ecl_stack_frame frame_aux;
- const cl_object frame = ecl_stack_frame_open(the_env,
- (cl_object)&frame_aux,
- narg -= 2);
- for (i = 0; i < narg; i++) {
- ECL_STACK_FRAME_SET(frame, i, lastarg);
- lastarg = ecl_va_arg(args);
- }
- if (ecl_t_of(lastarg) == t_frame) {
- /* This could be replaced with a memcpy() */
- for (i = 0; i < lastarg->frame.size; i++) {
- ecl_stack_frame_push(frame, lastarg->frame.base[i]);
- }
- } else loop_for_in (lastarg) {
- if (ecl_unlikely(i >= ECL_CALL_ARGUMENTS_LIMIT)) {
- ecl_stack_frame_close(frame);
- FEprogram_error_noreturn("CALL-ARGUMENTS-LIMIT exceeded",0);
- }
- ecl_stack_frame_push(frame, CAR(lastarg));
- i++;
- } end_loop_for_in;
- out = ecl_apply_from_stack_frame(frame, fun);
- ecl_stack_frame_close(frame);
- return out;
- }
- @)
- cl_object
- cl_eval(cl_object form)
- {
- return si_eval_with_env(1, form);
- }
- @(defun constantp (arg &optional env)
- @
- return _ecl_funcall3(@'ext::constantp-inner', arg, env);
- @)
- @(defun ext::constantp-inner (form &optional env)
- cl_object value;
- @
- AGAIN:
- switch (ecl_t_of(form)) {
- case t_list:
- if (Null(form)) {
- value = ECL_T;
- break;
- }
- if (ECL_CONS_CAR(form) == @'quote') {
- value = ECL_T;
- break;
- }
- /*
- value = cl_macroexpand(2, form, env);
- if (value != form) {
- form = value;
- goto AGAIN;
- }
- */
- value = ECL_NIL;
- break;
- case t_symbol:
- value = cl_macroexpand(2, form, env);
- if (value != form) {
- form = value;
- goto AGAIN;
- }
- if (!(form->symbol.stype & ecl_stp_constant)) {
- value = ECL_NIL;
- break;
- }
- default:
- value = ECL_T;
- }
- ecl_return1(the_env, value);
- @)
- @(defun ext::constant-form-value (form &optional env)
- cl_object value;
- @
- {
- AGAIN:
- switch (ecl_t_of(form)) {
- case t_list:
- if (Null(form)) {
- value = ECL_NIL;
- break;
- }
- if (ECL_CONS_CAR(form) == @'quote') {
- return cl_second(form);
- }
- /*
- value = cl_macroexpand(2, form, env);
- if (value != form) {
- form = value;
- goto AGAIN;
- }
- */
- ERROR:
- FEerror("EXT:CONSTANT-FORM-VALUE invoked with a non-constant form ~A",
- 0, form);
- break;
- case t_symbol:
- value = cl_macroexpand(2, form, env);
- if (value != form) {
- form = value;
- goto AGAIN;
- }
- value = ECL_SYM_VAL(the_env, value);
- break;
- default:
- value = form;
- }
- @(return value);
- }
- @)