diff options
| author | Stefan Monnier | 2010-04-19 21:50:52 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2010-04-19 21:50:52 -0400 |
| commit | ce5b453a449e4e7729abb5128114e2687f08360d (patch) | |
| tree | 55a132b01782b9667ff6f754949d55d5e52e76a4 /src/eval.c | |
| parent | 56d365a93da3c6b439998c251e9f01c73791f4b2 (diff) | |
| download | emacs-ce5b453a449e4e7729abb5128114e2687f08360d.tar.gz emacs-ce5b453a449e4e7729abb5128114e2687f08360d.zip | |
Make variable forwarding explicit rather the using special values.
Basically, this makes the structure of buffer-local values and object
forwarding explicit in the type of Lisp_Symbols rather than use
special Lisp_Objects for that. This tends to lead to slightly more
verbose code, but is more C-like, simpler, and makes it easier to make
sure we handled all cases, among other things by letting the compiler
help us check it.
* lisp.h (enum Lisp_Misc_Type, union Lisp_Misc):
Removing forwarding objects.
(enum Lisp_Fwd_Type, enum symbol_redirect, union Lisp_Fwd): New types.
(struct Lisp_Symbol): Make the various forms of variable-forwarding
explicit rather than hiding them inside Lisp_Object "values".
(XFWDTYPE): New macro.
(XINTFWD, XBOOLFWD, XOBJFWD, XKBOARD_OBJFWD): Redefine.
(XBUFFER_LOCAL_VALUE): Remove.
(SYMBOL_VAL, SYMBOL_ALIAS, SYMBOL_BLV, SYMBOL_FWD, SET_SYMBOL_VAL)
(SET_SYMBOL_ALIAS, SET_SYMBOL_BLV, SET_SYMBOL_FWD): New macros.
(SYMBOL_VALUE, SET_SYMBOL_VALUE): Remove.
(struct Lisp_Intfwd, struct Lisp_Boolfwd, struct Lisp_Objfwd)
(struct Lisp_Buffer_Objfwd, struct Lisp_Kboard_Objfwd):
Remove the Lisp_Misc_* header.
(struct Lisp_Buffer_Local_Value): Redefine.
(BLV_FOUND, SET_BLV_FOUND, BLV_VALUE, SET_BLV_VALUE): New macros.
(struct Lisp_Misc_Any): Add filler to get the right size.
(struct Lisp_Free): Use struct Lisp_Misc_Any rather than struct
Lisp_Intfwd.
(DEFVAR_LISP, DEFVAR_LISP_NOPRO, DEFVAR_BOOL, DEFVAR_INT)
(DEFVAR_KBOARD): Allocate a forwarding object.
* data.c (do_blv_forwarding, store_blv_forwarding): New macros.
(let_shadows_global_binding_p): New function.
(union Lisp_Val_Fwd): New type.
(make_blv): New function.
(swap_in_symval_forwarding, indirect_variable, do_symval_forwarding)
(store_symval_forwarding, swap_in_global_binding, Fboundp)
(swap_in_symval_forwarding, find_symbol_value, Fset)
(let_shadows_buffer_binding_p, set_internal, default_value)
(Fset_default, Fmake_variable_buffer_local, Fmake_local_variable)
(Fkill_local_variable, Fmake_variable_frame_local)
(Flocal_variable_p, Flocal_variable_if_set_p)
(Fvariable_binding_locus):
* xdisp.c (select_frame_for_redisplay):
* lread.c (Fintern, Funintern, init_obarray, defvar_int)
(defvar_bool, defvar_lisp_nopro, defvar_lisp, defvar_kboard):
* frame.c (store_frame_param):
* eval.c (Fdefvaralias, Fuser_variable_p, specbind, unbind_to):
* bytecode.c (Fbyte_code) <varref, varset>: Adapt to the new symbol
value structure.
* buffer.c (PER_BUFFER_SYMBOL): Move from buffer.h.
(clone_per_buffer_values): Only adjust markers into the current buffer.
(reset_buffer_local_variables): PER_BUFFER_IDX is never -2.
(Fbuffer_local_value, set_buffer_internal_1)
(swap_out_buffer_local_variables):
Adapt to the new symbol value structure.
(DEFVAR_PER_BUFFER): Allocate a Lisp_Buffer_Objfwd object.
(defvar_per_buffer): Take a new arg for the fwd object.
(buffer_lisp_local_variables): Return a proper alist (different fix
for bug#4138).
* alloc.c (Fmake_symbol): Use SET_SYMBOL_VAL.
(Fgarbage_collect): Don't handle buffer_defaults specially.
(mark_object): Handle new symbol value structure rather than the old
special Lisp_Misc_* objects.
(gc_sweep) <symbols>: Free also the buffer-local-value objects.
* term.c (set_tty_color_mode):
* bidi.c (bidi_initialize): Don't access the ->value field directly.
* buffer.h (PER_BUFFER_VAR_OFFSET): Don't bother with
a buffer_local_flags.
* print.c (print_object): Get rid of impossible forwarding objects.
Diffstat (limited to 'src/eval.c')
| -rw-r--r-- | src/eval.c | 214 |
1 files changed, 129 insertions, 85 deletions
diff --git a/src/eval.c b/src/eval.c index 6609d3b5c8a..cb1d435cb8b 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -767,24 +767,46 @@ The return value is BASE-VARIABLE. */) | |||
| 767 | CHECK_SYMBOL (new_alias); | 767 | CHECK_SYMBOL (new_alias); |
| 768 | CHECK_SYMBOL (base_variable); | 768 | CHECK_SYMBOL (base_variable); |
| 769 | 769 | ||
| 770 | if (SYMBOL_CONSTANT_P (new_alias)) | ||
| 771 | error ("Cannot make a constant an alias"); | ||
| 772 | |||
| 773 | sym = XSYMBOL (new_alias); | 770 | sym = XSYMBOL (new_alias); |
| 771 | |||
| 772 | if (sym->constant) | ||
| 773 | if (sym->redirect == SYMBOL_VARALIAS) | ||
| 774 | sym->constant = 0; /* Reset. */ | ||
| 775 | else | ||
| 776 | /* Not sure why. */ | ||
| 777 | error ("Cannot make a constant an alias"); | ||
| 778 | |||
| 779 | switch (sym->redirect) | ||
| 780 | { | ||
| 781 | case SYMBOL_FORWARDED: | ||
| 782 | error ("Cannot make an internal variable an alias"); | ||
| 783 | case SYMBOL_LOCALIZED: | ||
| 784 | error ("Don't know how to make a localized variable an alias"); | ||
| 785 | } | ||
| 786 | |||
| 774 | /* http://lists.gnu.org/archive/html/emacs-devel/2008-04/msg00834.html | 787 | /* http://lists.gnu.org/archive/html/emacs-devel/2008-04/msg00834.html |
| 775 | If n_a is bound, but b_v is not, set the value of b_v to n_a. | 788 | If n_a is bound, but b_v is not, set the value of b_v to n_a, |
| 776 | This is for the sake of define-obsolete-variable-alias and user | 789 | so that old-code that affects n_a before the aliasing is setup |
| 777 | customizations. */ | 790 | still works. */ |
| 778 | if (NILP (Fboundp (base_variable)) && !NILP (Fboundp (new_alias))) | 791 | if (NILP (Fboundp (base_variable))) |
| 779 | XSYMBOL(base_variable)->value = sym->value; | 792 | set_internal (base_variable, find_symbol_value (new_alias), NULL, 1); |
| 780 | sym->indirect_variable = 1; | 793 | |
| 781 | sym->value = base_variable; | 794 | { |
| 795 | struct specbinding *p; | ||
| 796 | |||
| 797 | for (p = specpdl_ptr - 1; p >= specpdl; p--) | ||
| 798 | if (p->func == NULL | ||
| 799 | && (EQ (new_alias, | ||
| 800 | CONSP (p->symbol) ? XCAR (p->symbol) : p->symbol))) | ||
| 801 | error ("Don't know how to make a let-bound variable an alias"); | ||
| 802 | } | ||
| 803 | |||
| 804 | sym->redirect = SYMBOL_VARALIAS; | ||
| 805 | SET_SYMBOL_ALIAS (sym, XSYMBOL (base_variable)); | ||
| 782 | sym->constant = SYMBOL_CONSTANT_P (base_variable); | 806 | sym->constant = SYMBOL_CONSTANT_P (base_variable); |
| 783 | LOADHIST_ATTACH (new_alias); | 807 | LOADHIST_ATTACH (new_alias); |
| 784 | if (!NILP (docstring)) | 808 | /* Even if docstring is nil: remove old docstring. */ |
| 785 | Fput (new_alias, Qvariable_documentation, docstring); | 809 | Fput (new_alias, Qvariable_documentation, docstring); |
| 786 | else | ||
| 787 | Fput (new_alias, Qvariable_documentation, Qnil); | ||
| 788 | 810 | ||
| 789 | return base_variable; | 811 | return base_variable; |
| 790 | } | 812 | } |
| @@ -944,7 +966,7 @@ chain of symbols. */) | |||
| 944 | return Qnil; | 966 | return Qnil; |
| 945 | 967 | ||
| 946 | /* If indirect and there's an alias loop, don't check anything else. */ | 968 | /* If indirect and there's an alias loop, don't check anything else. */ |
| 947 | if (XSYMBOL (variable)->indirect_variable | 969 | if (XSYMBOL (variable)->redirect == SYMBOL_VARALIAS |
| 948 | && NILP (internal_condition_case_1 (lisp_indirect_variable, variable, | 970 | && NILP (internal_condition_case_1 (lisp_indirect_variable, variable, |
| 949 | Qt, user_variable_p_eh))) | 971 | Qt, user_variable_p_eh))) |
| 950 | return Qnil; | 972 | return Qnil; |
| @@ -968,11 +990,11 @@ chain of symbols. */) | |||
| 968 | || (!NILP (Fget (variable, intern ("custom-autoload"))))) | 990 | || (!NILP (Fget (variable, intern ("custom-autoload"))))) |
| 969 | return Qt; | 991 | return Qt; |
| 970 | 992 | ||
| 971 | if (!XSYMBOL (variable)->indirect_variable) | 993 | if (!(XSYMBOL (variable)->redirect == SYMBOL_VARALIAS)) |
| 972 | return Qnil; | 994 | return Qnil; |
| 973 | 995 | ||
| 974 | /* An indirect variable? Let's follow the chain. */ | 996 | /* An indirect variable? Let's follow the chain. */ |
| 975 | variable = XSYMBOL (variable)->value; | 997 | XSETSYMBOL (variable, SYMBOL_ALIAS (XSYMBOL (variable))); |
| 976 | } | 998 | } |
| 977 | } | 999 | } |
| 978 | 1000 | ||
| @@ -3263,78 +3285,94 @@ void | |||
| 3263 | specbind (symbol, value) | 3285 | specbind (symbol, value) |
| 3264 | Lisp_Object symbol, value; | 3286 | Lisp_Object symbol, value; |
| 3265 | { | 3287 | { |
| 3266 | Lisp_Object valcontents; | 3288 | struct Lisp_Symbol *sym; |
| 3289 | |||
| 3290 | eassert (!handling_signal); | ||
| 3267 | 3291 | ||
| 3268 | CHECK_SYMBOL (symbol); | 3292 | CHECK_SYMBOL (symbol); |
| 3293 | sym = XSYMBOL (symbol); | ||
| 3269 | if (specpdl_ptr == specpdl + specpdl_size) | 3294 | if (specpdl_ptr == specpdl + specpdl_size) |
| 3270 | grow_specpdl (); | 3295 | grow_specpdl (); |
| 3271 | 3296 | ||
| 3272 | /* The most common case is that of a non-constant symbol with a | 3297 | start: |
| 3273 | trivial value. Make that as fast as we can. */ | 3298 | switch (sym->redirect) |
| 3274 | valcontents = SYMBOL_VALUE (symbol); | 3299 | { |
| 3275 | if (!MISCP (valcontents) && !SYMBOL_CONSTANT_P (symbol)) | 3300 | case SYMBOL_VARALIAS: |
| 3276 | { | 3301 | sym = indirect_variable (sym); XSETSYMBOL (symbol, sym); goto start; |
| 3277 | specpdl_ptr->symbol = symbol; | 3302 | case SYMBOL_PLAINVAL: |
| 3278 | specpdl_ptr->old_value = valcontents; | 3303 | { /* The most common case is that of a non-constant symbol with a |
| 3279 | specpdl_ptr->func = NULL; | 3304 | trivial value. Make that as fast as we can. */ |
| 3280 | ++specpdl_ptr; | 3305 | specpdl_ptr->symbol = symbol; |
| 3281 | SET_SYMBOL_VALUE (symbol, value); | 3306 | specpdl_ptr->old_value = SYMBOL_VAL (sym); |
| 3282 | } | 3307 | specpdl_ptr->func = NULL; |
| 3283 | else | 3308 | ++specpdl_ptr; |
| 3284 | { | 3309 | if (!sym->constant) |
| 3285 | Lisp_Object ovalue = find_symbol_value (symbol); | 3310 | SET_SYMBOL_VAL (sym, value); |
| 3286 | specpdl_ptr->func = 0; | ||
| 3287 | specpdl_ptr->old_value = ovalue; | ||
| 3288 | |||
| 3289 | valcontents = XSYMBOL (symbol)->value; | ||
| 3290 | |||
| 3291 | if (BUFFER_LOCAL_VALUEP (valcontents) | ||
| 3292 | || BUFFER_OBJFWDP (valcontents)) | ||
| 3293 | { | ||
| 3294 | Lisp_Object where, current_buffer; | ||
| 3295 | |||
| 3296 | current_buffer = Fcurrent_buffer (); | ||
| 3297 | |||
| 3298 | /* For a local variable, record both the symbol and which | ||
| 3299 | buffer's or frame's value we are saving. */ | ||
| 3300 | if (!NILP (Flocal_variable_p (symbol, Qnil))) | ||
| 3301 | where = current_buffer; | ||
| 3302 | else if (BUFFER_LOCAL_VALUEP (valcontents) | ||
| 3303 | && XBUFFER_LOCAL_VALUE (valcontents)->found_for_frame) | ||
| 3304 | where = XBUFFER_LOCAL_VALUE (valcontents)->frame; | ||
| 3305 | else | 3311 | else |
| 3306 | where = Qnil; | 3312 | set_internal (symbol, value, 0, 1); |
| 3307 | 3313 | break; | |
| 3308 | /* We're not using the `unused' slot in the specbinding | ||
| 3309 | structure because this would mean we have to do more | ||
| 3310 | work for simple variables. */ | ||
| 3311 | specpdl_ptr->symbol = Fcons (symbol, Fcons (where, current_buffer)); | ||
| 3312 | |||
| 3313 | /* If SYMBOL is a per-buffer variable which doesn't have a | ||
| 3314 | buffer-local value here, make the `let' change the global | ||
| 3315 | value by changing the value of SYMBOL in all buffers not | ||
| 3316 | having their own value. This is consistent with what | ||
| 3317 | happens with other buffer-local variables. */ | ||
| 3318 | if (NILP (where) | ||
| 3319 | && BUFFER_OBJFWDP (valcontents)) | ||
| 3320 | { | ||
| 3321 | ++specpdl_ptr; | ||
| 3322 | Fset_default (symbol, value); | ||
| 3323 | return; | ||
| 3324 | } | ||
| 3325 | } | 3314 | } |
| 3326 | else | 3315 | case SYMBOL_LOCALIZED: case SYMBOL_FORWARDED: |
| 3327 | specpdl_ptr->symbol = symbol; | 3316 | { |
| 3328 | 3317 | Lisp_Object ovalue = find_symbol_value (symbol); | |
| 3329 | specpdl_ptr++; | 3318 | specpdl_ptr->func = 0; |
| 3330 | /* We used to do | 3319 | specpdl_ptr->old_value = ovalue; |
| 3331 | if (BUFFER_OBJFWDP (ovalue) || KBOARD_OBJFWDP (ovalue)) | 3320 | |
| 3332 | store_symval_forwarding (symbol, ovalue, value, NULL); | 3321 | eassert (sym->redirect != SYMBOL_LOCALIZED |
| 3333 | else | 3322 | || (EQ (SYMBOL_BLV (sym)->where, |
| 3334 | but ovalue comes from find_symbol_value which should never return | 3323 | SYMBOL_BLV (sym)->frame_local ? |
| 3335 | such an internal value. */ | 3324 | Fselected_frame () : Fcurrent_buffer ()))); |
| 3336 | eassert (!(BUFFER_OBJFWDP (ovalue) || KBOARD_OBJFWDP (ovalue))); | 3325 | |
| 3337 | set_internal (symbol, value, 0, 1); | 3326 | if (sym->redirect == SYMBOL_LOCALIZED |
| 3327 | || BUFFER_OBJFWDP (SYMBOL_FWD (sym))) | ||
| 3328 | { | ||
| 3329 | Lisp_Object where, cur_buf = Fcurrent_buffer (); | ||
| 3330 | |||
| 3331 | /* For a local variable, record both the symbol and which | ||
| 3332 | buffer's or frame's value we are saving. */ | ||
| 3333 | if (!NILP (Flocal_variable_p (symbol, Qnil))) | ||
| 3334 | { | ||
| 3335 | eassert (sym->redirect != SYMBOL_LOCALIZED | ||
| 3336 | || (BLV_FOUND (SYMBOL_BLV (sym)) | ||
| 3337 | && EQ (cur_buf, SYMBOL_BLV (sym)->where))); | ||
| 3338 | where = cur_buf; | ||
| 3339 | } | ||
| 3340 | else if (sym->redirect == SYMBOL_LOCALIZED | ||
| 3341 | && BLV_FOUND (SYMBOL_BLV (sym))) | ||
| 3342 | where = SYMBOL_BLV (sym)->where; | ||
| 3343 | else | ||
| 3344 | where = Qnil; | ||
| 3345 | |||
| 3346 | /* We're not using the `unused' slot in the specbinding | ||
| 3347 | structure because this would mean we have to do more | ||
| 3348 | work for simple variables. */ | ||
| 3349 | /* FIXME: The third value `current_buffer' is only used in | ||
| 3350 | let_shadows_buffer_binding_p which is itself only used | ||
| 3351 | in set_internal for local_if_set. */ | ||
| 3352 | specpdl_ptr->symbol = Fcons (symbol, Fcons (where, cur_buf)); | ||
| 3353 | |||
| 3354 | /* If SYMBOL is a per-buffer variable which doesn't have a | ||
| 3355 | buffer-local value here, make the `let' change the global | ||
| 3356 | value by changing the value of SYMBOL in all buffers not | ||
| 3357 | having their own value. This is consistent with what | ||
| 3358 | happens with other buffer-local variables. */ | ||
| 3359 | if (NILP (where) | ||
| 3360 | && sym->redirect == SYMBOL_FORWARDED) | ||
| 3361 | { | ||
| 3362 | eassert (BUFFER_OBJFWDP (SYMBOL_FWD (sym))); | ||
| 3363 | ++specpdl_ptr; | ||
| 3364 | Fset_default (symbol, value); | ||
| 3365 | return; | ||
| 3366 | } | ||
| 3367 | } | ||
| 3368 | else | ||
| 3369 | specpdl_ptr->symbol = symbol; | ||
| 3370 | |||
| 3371 | specpdl_ptr++; | ||
| 3372 | set_internal (symbol, value, 0, 1); | ||
| 3373 | break; | ||
| 3374 | } | ||
| 3375 | default: abort (); | ||
| 3338 | } | 3376 | } |
| 3339 | } | 3377 | } |
| 3340 | 3378 | ||
| @@ -3394,7 +3432,12 @@ unbind_to (count, value) | |||
| 3394 | if (NILP (where)) | 3432 | if (NILP (where)) |
| 3395 | Fset_default (symbol, this_binding.old_value); | 3433 | Fset_default (symbol, this_binding.old_value); |
| 3396 | else if (BUFFERP (where)) | 3434 | else if (BUFFERP (where)) |
| 3397 | set_internal (symbol, this_binding.old_value, XBUFFER (where), 1); | 3435 | if (!NILP (Flocal_variable_p (symbol, where))) |
| 3436 | set_internal (symbol, this_binding.old_value, XBUFFER (where), 1); | ||
| 3437 | /* else if (!NILP (Fbuffer_live_p (where))) | ||
| 3438 | error ("Unbinding local %s to global!", symbol); */ | ||
| 3439 | else | ||
| 3440 | ; | ||
| 3398 | else | 3441 | else |
| 3399 | set_internal (symbol, this_binding.old_value, NULL, 1); | 3442 | set_internal (symbol, this_binding.old_value, NULL, 1); |
| 3400 | } | 3443 | } |
| @@ -3403,8 +3446,9 @@ unbind_to (count, value) | |||
| 3403 | /* If variable has a trivial value (no forwarding), we can | 3446 | /* If variable has a trivial value (no forwarding), we can |
| 3404 | just set it. No need to check for constant symbols here, | 3447 | just set it. No need to check for constant symbols here, |
| 3405 | since that was already done by specbind. */ | 3448 | since that was already done by specbind. */ |
| 3406 | if (!MISCP (SYMBOL_VALUE (this_binding.symbol))) | 3449 | if (XSYMBOL (this_binding.symbol)->redirect == SYMBOL_PLAINVAL) |
| 3407 | SET_SYMBOL_VALUE (this_binding.symbol, this_binding.old_value); | 3450 | SET_SYMBOL_VAL (XSYMBOL (this_binding.symbol), |
| 3451 | this_binding.old_value); | ||
| 3408 | else | 3452 | else |
| 3409 | set_internal (this_binding.symbol, this_binding.old_value, 0, 1); | 3453 | set_internal (this_binding.symbol, this_binding.old_value, 0, 1); |
| 3410 | } | 3454 | } |