2001-10-31 Miles Bader * lisp.h (struct Lisp_Symbol): Add `declared_special' field. (apply_lambda): Add new 3rd arg to decl. * alloc.c (Fmake_symbol): Initialize it. * eval.c (Vinterpreter_lexenv): New variable. (syms_of_eval): Initialize it. (Fsetq): Modify SYM's lexical binding if appropriate. (Ffunction): Return a closure if within a lexical environment. (Flet, FletX): Lexically bind non-defvar'd variables if inside a lexical environment. (Feval): Return lexical binding of variables, if they have one. Pass current lexical environment to embedded lambdas. Handle closures. (Ffuncall): Pass nil lexical environment to lambdas. Handle closures. (funcall_lambda): Add new LEXENV argument, and lexically bind arguments if it's non-nil. Bind `interpreter-lexenv' if it changed. (apply_lambda): Add new LEXENV argument and pass it to funcall_lambda. (Fdefvaralias, Fdefvar, Fdefconst): Mark the variable as special. (Qinterpreter_lexenv, Qiclosure): New constants. (syms_of_eval): Initialize them. (Fdefun, Fdefmacro): Return a closure if lexical binding is active. * lread.c (defvar_bool, defvar_lisp_nopro, defvar_per_buffer) (defvar_kboard, defvar_int): Mark the variable as special. diff -u src/lisp.h.\~1\~ src/lisp.h *** src/lisp.h.~1~ Sat Oct 27 18:50:31 2001 --- src/lisp.h Wed Oct 31 23:47:55 2001 *************** *** 868,873 **** --- 868,877 ---- enum symbol_interned. */ unsigned interned : 2; + /* Non-zero means that this variable has been explicitly declared + special (with `defvar' etc), and shouldn't be lexically bound. */ + unsigned declared_special : 1; + /* The symbol's name. This should become a Lisp_Object some day; there's no need for the Lisp_String pointer nowadays. */ struct Lisp_String *name; *************** *** 2484,2490 **** extern Lisp_Object call5 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); extern Lisp_Object call6 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); EXFUN (Fdo_auto_save, 2); ! extern Lisp_Object apply_lambda P_ ((Lisp_Object, Lisp_Object, int)); extern Lisp_Object internal_catch P_ ((Lisp_Object, Lisp_Object (*) (Lisp_Object), Lisp_Object)); extern Lisp_Object internal_condition_case P_ ((Lisp_Object (*) (void), Lisp_Object, Lisp_Object (*) (Lisp_Object))); extern Lisp_Object internal_condition_case_1 P_ ((Lisp_Object (*) (Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object))); --- 2488,2494 ---- extern Lisp_Object call5 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); extern Lisp_Object call6 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); EXFUN (Fdo_auto_save, 2); ! extern Lisp_Object apply_lambda P_ ((Lisp_Object, Lisp_Object, int, Lisp_Object)); extern Lisp_Object internal_catch P_ ((Lisp_Object, Lisp_Object (*) (Lisp_Object), Lisp_Object)); extern Lisp_Object internal_condition_case P_ ((Lisp_Object (*) (void), Lisp_Object, Lisp_Object (*) (Lisp_Object))); extern Lisp_Object internal_condition_case_1 P_ ((Lisp_Object (*) (Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object))); diff -u src/alloc.c.\~1\~ src/alloc.c *** src/alloc.c.~1~ Sun Oct 21 18:53:00 2001 --- src/alloc.c Wed Oct 31 19:13:25 2001 *************** *** 2553,2558 **** --- 2553,2559 ---- p->interned = SYMBOL_UNINTERNED; p->constant = 0; p->indirect_variable = 0; + p->declared_special = 0; consing_since_gc += sizeof (struct Lisp_Symbol); symbols_consed++; return val; diff -u src/eval.c.\~1\~ src/eval.c *** src/eval.c.~1~ Tue Oct 23 22:43:50 2001 --- src/eval.c Thu Nov 1 00:22:27 2001 *************** *** 91,97 **** Lisp_Object Qinhibit_quit, Vinhibit_quit, Vquit_flag; Lisp_Object Qmocklisp_arguments, Vmocklisp_arguments, Qmocklisp; Lisp_Object Qand_rest, Qand_optional; ! Lisp_Object Qdebug_on_error; /* This holds either the symbol `run-hooks' or nil. It is nil at an early stage of startup, and when Emacs --- 91,97 ---- Lisp_Object Qinhibit_quit, Vinhibit_quit, Vquit_flag; Lisp_Object Qmocklisp_arguments, Vmocklisp_arguments, Qmocklisp; Lisp_Object Qand_rest, Qand_optional; ! Lisp_Object Qdebug_on_error, Qinterpreter_lexenv, Qclosure; /* This holds either the symbol `run-hooks' or nil. It is nil at an early stage of startup, and when Emacs *************** *** 106,111 **** --- 106,117 ---- Lisp_Object Vautoload_queue; + /* When lexical binding is being used, this is non-nil, and contains an + alist of lexically-bound variable, or t, indicating an empty + environment. */ + + Lisp_Object Vinterpreter_lexenv; + /* Current number of specbindings allocated in specpdl. */ int specpdl_size; *************** *** 525,531 **** Lisp_Object args; { register Lisp_Object args_left; ! register Lisp_Object val, sym; struct gcpro gcpro1; if (NILP(args)) --- 531,537 ---- Lisp_Object args; { register Lisp_Object args_left; ! register Lisp_Object val, sym, lex_binding; struct gcpro gcpro1; if (NILP(args)) *************** *** 538,544 **** { val = Feval (Fcar (Fcdr (args_left))); sym = Fcar (args_left); ! Fset (sym, val); args_left = Fcdr (Fcdr (args_left)); } while (!NILP(args_left)); --- 544,560 ---- { val = Feval (Fcar (Fcdr (args_left))); sym = Fcar (args_left); ! ! if (!NILP (Vinterpreter_lexenv) ! && SYMBOLP (sym) ! && !XSYMBOL (sym)->declared_special ! && !NILP (lex_binding = Fassq (sym, Vinterpreter_lexenv))) ! /* SYM is lexically bound. */ ! XSETCDR (lex_binding, val); ! else ! /* SYM is dynamically bound. */ ! Fset (sym, val); ! args_left = Fcdr (Fcdr (args_left)); } while (!NILP(args_left)); *************** *** 564,570 **** (args) Lisp_Object args; { ! return Fcar (args); } --- 580,596 ---- (args) Lisp_Object args; { ! Lisp_Object quoted = XCAR (args); ! ! if (!NILP (Vinterpreter_lexenv) ! && CONSP (quoted) ! && EQ (XCAR (quoted), Qlambda)) ! /* This is a lambda expression within a lexical environment; ! return an interpreted closure instead of a simple lambda. */ ! return Fcons (Qclosure, Fcons (Vinterpreter_lexenv, quoted)); ! else ! /* Simply quote the argument. */ ! return quoted; } *************** *** 649,654 **** --- 675,682 ---- fn_name = Fcar (args); defn = Fcons (Qlambda, Fcdr (args)); + if (! NILP (Vinterpreter_lexenv)) + defn = Fcons (Qclosure, Fcons (Vinterpreter_lexenv, defn)); if (!NILP (Vpurify_flag)) defn = Fpurecopy (defn); Ffset (fn_name, defn); *************** *** 671,677 **** register Lisp_Object defn; fn_name = Fcar (args); ! defn = Fcons (Qmacro, Fcons (Qlambda, Fcdr (args))); if (!NILP (Vpurify_flag)) defn = Fpurecopy (defn); Ffset (fn_name, defn); --- 699,708 ---- register Lisp_Object defn; fn_name = Fcar (args); ! defn = Fcons (Qlambda, Fcdr (args)); ! if (! NILP (Vinterpreter_lexenv)) ! defn = Fcons (Qclosure, Fcons (Vinterpreter_lexenv, defn)); ! defn = Fcons (Qmacro, defn); if (!NILP (Vpurify_flag)) defn = Fpurecopy (defn); Ffset (fn_name, defn); *************** *** 698,703 **** --- 729,735 ---- sym = XSYMBOL (symbol); sym->indirect_variable = 1; + sym->declared_special = 1; sym->value = aliased; sym->constant = SYMBOL_CONSTANT_P (aliased); LOADHIST_ATTACH (symbol); *************** *** 752,757 **** --- 784,792 ---- if (NILP (tem)) LOADHIST_ATTACH (sym); + if (SYMBOLP (sym)) + XSYMBOL (sym)->declared_special = 1; + return sym; } *************** *** 776,781 **** --- 811,817 ---- if (!NILP (Vpurify_flag)) tem = Fpurecopy (tem); Fset_default (sym, tem); + XSYMBOL (sym)->declared_special = 1; tem = Fcar (Fcdr (Fcdr (args))); if (!NILP (tem)) { *************** *** 832,863 **** (args) Lisp_Object args; { ! Lisp_Object varlist, val, elt; int count = specpdl_ptr - specpdl; struct gcpro gcpro1, gcpro2, gcpro3; GCPRO3 (args, elt, varlist); varlist = Fcar (args); while (!NILP (varlist)) { QUIT; elt = Fcar (varlist); if (SYMBOLP (elt)) ! specbind (elt, Qnil); else if (! NILP (Fcdr (Fcdr (elt)))) Fsignal (Qerror, Fcons (build_string ("`let' bindings can have only one value-form"), elt)); else { val = Feval (Fcar (Fcdr (elt))); - specbind (Fcar (elt), val); } varlist = Fcdr (varlist); } UNGCPRO; val = Fprogn (Fcdr (args)); return unbind_to (count, val); } --- 868,919 ---- (args) Lisp_Object args; { ! Lisp_Object varlist, var, val, elt, lexenv; int count = specpdl_ptr - specpdl; struct gcpro gcpro1, gcpro2, gcpro3; GCPRO3 (args, elt, varlist); + lexenv = Vinterpreter_lexenv; + varlist = Fcar (args); while (!NILP (varlist)) { QUIT; + elt = Fcar (varlist); if (SYMBOLP (elt)) ! { ! var = elt; ! val = Qnil; ! } else if (! NILP (Fcdr (Fcdr (elt)))) Fsignal (Qerror, Fcons (build_string ("`let' bindings can have only one value-form"), elt)); else { + var = Fcar (elt); val = Feval (Fcar (Fcdr (elt))); } + + if (!NILP (lexenv) && SYMBOLP (var) && !XSYMBOL (var)->declared_special) + /* Lexically bind VAR by adding it to the lexenv alist. */ + lexenv = Fcons (Fcons (var, val), lexenv); + else + specbind (var, val); + varlist = Fcdr (varlist); } + + if (!EQ (lexenv, Vinterpreter_lexenv)) + /* Instantiate a new lexical environment. */ + specbind (Qinterpreter_lexenv, lexenv); + UNGCPRO; + val = Fprogn (Fcdr (args)); + return unbind_to (count, val); } *************** *** 871,877 **** (args) Lisp_Object args; { ! Lisp_Object *temps, tem; register Lisp_Object elt, varlist; int count = specpdl_ptr - specpdl; register int argnum; --- 927,933 ---- (args) Lisp_Object args; { ! Lisp_Object *temps, tem, lexenv; register Lisp_Object elt, varlist; int count = specpdl_ptr - specpdl; register int argnum; *************** *** 904,921 **** } UNGCPRO; varlist = Fcar (args); for (argnum = 0; !NILP (varlist); varlist = Fcdr (varlist)) { elt = Fcar (varlist); tem = temps[argnum++]; ! if (SYMBOLP (elt)) ! specbind (elt, tem); else ! specbind (Fcar (elt), tem); } elt = Fprogn (Fcdr (args)); return unbind_to (count, elt); } --- 960,990 ---- } UNGCPRO; + lexenv = Vinterpreter_lexenv; + varlist = Fcar (args); for (argnum = 0; !NILP (varlist); varlist = Fcdr (varlist)) { + Lisp_Object var; + elt = Fcar (varlist); + var = SYMBOLP (elt) ? elt : Fcar (elt); tem = temps[argnum++]; ! ! if (!NILP (lexenv) && SYMBOLP (var) && !XSYMBOL (var)->declared_special) ! /* Lexically bind VAR by adding it to the lexenv alist. */ ! lexenv = Fcons (Fcons (var, tem), lexenv); else ! /* Dynamically bind VAR. */ ! specbind (var, tem); } + if (!EQ (lexenv, Vinterpreter_lexenv)) + /* Instantiate a new lexical environment. */ + specbind (Qinterpreter_lexenv, lexenv); + elt = Fprogn (Fcdr (args)); + return unbind_to (count, elt); } *************** *** 1941,1947 **** if (SYMBOLP (form)) { if (EQ (Vmocklisp_arguments, Qt)) ! return Fsymbol_value (form); val = Fsymbol_value (form); if (NILP (val)) XSETFASTINT (val, 0); --- 2010,2027 ---- if (SYMBOLP (form)) { if (EQ (Vmocklisp_arguments, Qt)) ! { ! if (!NILP (Vinterpreter_lexenv) && !XSYMBOL (form)->declared_special) ! { ! Lisp_Object lex_binding = Fassq (form, Vinterpreter_lexenv); ! if (CONSP (lex_binding)) ! return XCDR (lex_binding); ! } ! ! return Fsymbol_value (form); ! } ! ! /* Mocklisp case. */ val = Fsymbol_value (form); if (NILP (val)) XSETFASTINT (val, 0); *************** *** 1949,1954 **** --- 2029,2035 ---- XSETFASTINT (val, 1); return val; } + if (!CONSP (form)) return form; *************** *** 2099,2105 **** } } if (COMPILEDP (fun)) ! val = apply_lambda (fun, original_args, 1); else { if (!CONSP (fun)) --- 2180,2186 ---- } } if (COMPILEDP (fun)) ! val = apply_lambda (fun, original_args, 1, Vinterpreter_lexenv); else { if (!CONSP (fun)) *************** *** 2115,2121 **** if (EQ (funcar, Qmacro)) val = Feval (apply1 (Fcdr (fun), original_args)); else if (EQ (funcar, Qlambda)) ! val = apply_lambda (fun, original_args, 1); else if (EQ (funcar, Qmocklisp)) val = ml_apply (fun, original_args); else --- 2196,2208 ---- if (EQ (funcar, Qmacro)) val = Feval (apply1 (Fcdr (fun), original_args)); else if (EQ (funcar, Qlambda)) ! val = apply_lambda (fun, original_args, 1, Vinterpreter_lexenv); ! else if (EQ (funcar, Qclosure) ! && CONSP (XCDR (fun)) ! && CONSP (XCDR (XCDR (fun))) ! && EQ (XCAR (XCDR (XCDR (fun))), Qlambda)) ! val = apply_lambda (XCDR (XCDR (fun)), original_args, 1, ! XCAR (XCDR (fun))); else if (EQ (funcar, Qmocklisp)) val = ml_apply (fun, original_args); else *************** *** 2777,2783 **** } } if (COMPILEDP (fun)) ! val = funcall_lambda (fun, numargs, args + 1); else if (VECTORP (fun) && XVECTOR (fun)->size >= 1) { int num_curried_args = XVECTOR (fun)->size - 1; --- 2864,2870 ---- } } if (COMPILEDP (fun)) ! val = funcall_lambda (fun, numargs, args + 1, Qnil); else if (VECTORP (fun) && XVECTOR (fun)->size >= 1) { int num_curried_args = XVECTOR (fun)->size - 1; *************** *** 2802,2808 **** if (!SYMBOLP (funcar)) return Fsignal (Qinvalid_function, Fcons (fun, Qnil)); if (EQ (funcar, Qlambda)) ! val = funcall_lambda (fun, numargs, args + 1); else if (EQ (funcar, Qmocklisp)) val = ml_apply (fun, Flist (numargs, args + 1)); else if (EQ (funcar, Qautoload)) --- 2889,2901 ---- if (!SYMBOLP (funcar)) return Fsignal (Qinvalid_function, Fcons (fun, Qnil)); if (EQ (funcar, Qlambda)) ! val = funcall_lambda (fun, numargs, args + 1, Qnil); ! else if (EQ (funcar, Qclosure) ! && CONSP (XCDR (fun)) ! && CONSP (XCDR (XCDR (fun))) ! && EQ (XCAR (XCDR (XCDR (fun))), Qlambda)) ! val = funcall_lambda (XCDR (XCDR (fun)), numargs, args + 1, ! XCAR (XCDR (fun))); else if (EQ (funcar, Qmocklisp)) val = ml_apply (fun, Flist (numargs, args + 1)); else if (EQ (funcar, Qautoload)) *************** *** 2822,2830 **** } Lisp_Object ! apply_lambda (fun, args, eval_flag) Lisp_Object fun, args; int eval_flag; { Lisp_Object args_left; Lisp_Object numargs; --- 2915,2924 ---- } Lisp_Object ! apply_lambda (fun, args, eval_flag, lexenv) Lisp_Object fun, args; int eval_flag; + Lisp_Object lexenv; { Lisp_Object args_left; Lisp_Object numargs; *************** *** 2856,2862 **** backtrace_list->nargs = i; } backtrace_list->evalargs = 0; ! tem = funcall_lambda (fun, XINT (numargs), arg_vector); /* Do the debug-on-exit now, while arg_vector still exists. */ if (backtrace_list->debug_on_exit) --- 2950,2956 ---- backtrace_list->nargs = i; } backtrace_list->evalargs = 0; ! tem = funcall_lambda (fun, XINT (numargs), arg_vector, lexenv); /* Do the debug-on-exit now, while arg_vector still exists. */ if (backtrace_list->debug_on_exit) *************** *** 2871,2880 **** FUN must be either a lambda-expression or a compiled-code object. */ Lisp_Object ! funcall_lambda (fun, nargs, arg_vector) Lisp_Object fun; int nargs; register Lisp_Object *arg_vector; { Lisp_Object val, syms_left, next; int count = specpdl_ptr - specpdl; --- 2965,2975 ---- FUN must be either a lambda-expression or a compiled-code object. */ Lisp_Object ! funcall_lambda (fun, nargs, arg_vector, lexenv) Lisp_Object fun; int nargs; register Lisp_Object *arg_vector; + Lisp_Object lexenv; { Lisp_Object val, syms_left, next; int count = specpdl_ptr - specpdl; *************** *** 2932,2944 **** specbind (next, Flist (nargs - i, &arg_vector[i])); i = nargs; } - else if (i < nargs) - specbind (next, arg_vector[i++]); - else if (!optional) - return Fsignal (Qwrong_number_of_arguments, - Fcons (fun, Fcons (make_number (nargs), Qnil))); else ! specbind (next, Qnil); } if (!NILP (syms_left)) --- 3027,3054 ---- specbind (next, Flist (nargs - i, &arg_vector[i])); i = nargs; } else ! { ! Lisp_Object val; ! ! /* Get the argument's actual value. */ ! if (i < nargs) ! val = arg_vector[i++]; ! else if (!optional) ! return Fsignal (Qwrong_number_of_arguments, ! Fcons (fun, Fcons (make_number (nargs), Qnil))); ! else ! val = Qnil; ! ! /* Bind the argument. */ ! if (!NILP (lexenv) ! && SYMBOLP (next) && !XSYMBOL (next)->declared_special) ! /* Lexically bind NEXT by adding it to the lexenv alist. */ ! lexenv = Fcons (Fcons (next, val), lexenv); ! else ! /* Dynamically bind NEXT. */ ! specbind (next, val); ! } } if (!NILP (syms_left)) *************** *** 2947,2952 **** --- 3057,3066 ---- return Fsignal (Qwrong_number_of_arguments, Fcons (fun, Fcons (make_number (nargs), Qnil))); + if (!EQ (lexenv, Vinterpreter_lexenv)) + /* Instantiate a new lexical environment. */ + specbind (Qinterpreter_lexenv, lexenv); + if (CONSP (fun)) val = Fprogn (XCDR (XCDR (fun))); else *************** *** 3397,3402 **** --- 3511,3519 ---- Qand_optional = intern ("&optional"); staticpro (&Qand_optional); + Qclosure = intern ("closure"); + staticpro (&Qclosure); + DEFVAR_LISP ("stack-trace-on-error", &Vstack_trace_on_error, "*Non-nil means automatically display a backtrace buffer\n\ after any error that is handled by the editor command loop.\n\ *************** *** 3466,3471 **** --- 3583,3597 ---- Note that `debug-on-error', `debug-on-quit' and friends\n\ still determine whether to handle the particular condition."); Vdebug_on_signal = Qnil; + + Qinterpreter_lexenv = intern ("interpreter-lexenv"); + staticpro (&Qinterpreter_lexenv); + DEFVAR_LISP ("interpreter-lexenv", &Vinterpreter_lexenv, + doc: /* If non-nil, the current lexical environment of the lisp interpreter. + When lexical binding is not being used, this variable is nil. + A value of `(t)' indicates an empty environment, otherwise it is an + alist of active lexical bindings. */); + Vinterpreter_lexenv = Qnil; Vrun_hooks = intern ("run-hooks"); staticpro (&Vrun_hooks); diff -u src/lread.c.\~1\~ src/lread.c *** src/lread.c.~1~ Wed Oct 24 15:00:29 2001 --- src/lread.c Wed Oct 31 21:00:23 2001 *************** *** 3221,3226 **** --- 3221,3227 ---- XMISCTYPE (val) = Lisp_Misc_Intfwd; XINTFWD (val)->intvar = address; SET_SYMBOL_VALUE (sym, val); + XSYMBOL (sym)->declared_special = 1; } /* Similar but define a variable whose value is T if address contains 1, *************** *** 3236,3241 **** --- 3237,3243 ---- XMISCTYPE (val) = Lisp_Misc_Boolfwd; XBOOLFWD (val)->boolvar = address; SET_SYMBOL_VALUE (sym, val); + XSYMBOL (sym)->declared_special = 1; Vbyte_boolean_vars = Fcons (sym, Vbyte_boolean_vars); } *************** *** 3255,3260 **** --- 3257,3263 ---- XMISCTYPE (val) = Lisp_Misc_Objfwd; XOBJFWD (val)->objvar = address; SET_SYMBOL_VALUE (sym, val); + XSYMBOL (sym)->declared_special = 1; } void *************** *** 3288,3293 **** --- 3291,3297 ---- XMISCTYPE (val) = Lisp_Misc_Buffer_Objfwd; XBUFFER_OBJFWD (val)->offset = offset; SET_SYMBOL_VALUE (sym, val); + XSYMBOL (sym)->declared_special = 1; PER_BUFFER_SYMBOL (offset) = sym; PER_BUFFER_TYPE (offset) = type; *************** *** 3312,3317 **** --- 3316,3322 ---- XMISCTYPE (val) = Lisp_Misc_Kboard_Objfwd; XKBOARD_OBJFWD (val)->offset = offset; SET_SYMBOL_VALUE (sym, val); + XSYMBOL (sym)->declared_special = 1; } /* Record the value of load-path used at the start of dumping