diff options
| author | João Távora | 2020-12-23 19:57:27 +0000 |
|---|---|---|
| committer | João Távora | 2021-09-27 01:07:11 +0100 |
| commit | 68d73eb154c745cbba7b3fd6a0a0a087d7c157da (patch) | |
| tree | 1b276611e4dabd49a33daa165e38d2cb464340c1 /src | |
| parent | 71857d410635743d437ce1ee73dff69de50030d6 (diff) | |
| download | emacs-68d73eb154c745cbba7b3fd6a0a0a087d7c157da.tar.gz emacs-68d73eb154c745cbba7b3fd6a0a0a087d7c157da.zip | |
Rework Elisp shorthands to only allow only prefix substitution
This simplification in requirements makes for more complex C code but
that code is much less wasteful in Lisp strings than the previous
implementation.
* src/lread.c (read1): Rework.
(Fintern): Rework.
(Fintern_soft): Rework.
(Funintern): Rework.
(oblookup_considering_shorthand): Rewrite.
* test/lisp/progmodes/elisp-mode-tests.el (elisp-shorthand-read-buffer)
(elisp-shorthand-read-from-string): Use new format of
elisp-shorthands.
* test/lisp/progmodes/elisp-resources/simple-shorthand-test.el (f-test)
(f-test2, f-test3): Use new form of elisp-shorthands.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lread.c | 170 |
1 files changed, 129 insertions, 41 deletions
diff --git a/src/lread.c b/src/lread.c index 0c0c4f34ba3..4b7fcc2875b 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -2956,7 +2956,10 @@ read_integer (Lisp_Object readcharfun, int radix, | |||
| 2956 | return unbind_to (count, string_to_number (read_buffer, radix, NULL)); | 2956 | return unbind_to (count, string_to_number (read_buffer, radix, NULL)); |
| 2957 | } | 2957 | } |
| 2958 | 2958 | ||
| 2959 | Lisp_Object oblookup_considering_shorthand (Lisp_Object, Lisp_Object*); | 2959 | Lisp_Object oblookup_considering_shorthand |
| 2960 | (Lisp_Object obarray, | ||
| 2961 | const char *in, ptrdiff_t size, ptrdiff_t size_byte, | ||
| 2962 | char **out, ptrdiff_t *size_out, ptrdiff_t *size_byte_out); | ||
| 2960 | 2963 | ||
| 2961 | /* If the next token is ')' or ']' or '.', we store that character | 2964 | /* If the next token is ')' or ']' or '.', we store that character |
| 2962 | in *PCH and the return value is not interesting. Else, we store | 2965 | in *PCH and the return value is not interesting. Else, we store |
| @@ -3782,17 +3785,36 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3782 | } | 3785 | } |
| 3783 | else | 3786 | else |
| 3784 | { | 3787 | { |
| 3785 | /* Like intern_1 but supports multibyte names. */ | 3788 | /* Don't create the string object for the name unless |
| 3789 | we're going to retain it in a new symbol. | ||
| 3790 | |||
| 3791 | Like intern_1 but supports multibyte names. */ | ||
| 3786 | Lisp_Object obarray = check_obarray (Vobarray); | 3792 | Lisp_Object obarray = check_obarray (Vobarray); |
| 3787 | Lisp_Object name | 3793 | |
| 3788 | = make_specified_string (read_buffer, nchars, nbytes, | 3794 | char* longhand = NULL; |
| 3789 | multibyte); | 3795 | ptrdiff_t longhand_chars = 0; |
| 3790 | Lisp_Object tem = oblookup_considering_shorthand (obarray, &name); | 3796 | ptrdiff_t longhand_bytes = 0; |
| 3797 | |||
| 3798 | Lisp_Object tem | ||
| 3799 | = oblookup_considering_shorthand | ||
| 3800 | (obarray, read_buffer, nchars, nbytes, | ||
| 3801 | &longhand, &longhand_chars, &longhand_bytes); | ||
| 3791 | 3802 | ||
| 3792 | if (SYMBOLP (tem)) | 3803 | if (SYMBOLP (tem)) |
| 3793 | result = tem; | 3804 | result = tem; |
| 3794 | else | 3805 | else if (longhand) { |
| 3795 | result = intern_driver (name, obarray, tem); | 3806 | Lisp_Object name |
| 3807 | = make_specified_string (longhand, longhand_chars, | ||
| 3808 | longhand_bytes, | ||
| 3809 | multibyte); | ||
| 3810 | xfree (longhand); | ||
| 3811 | result = intern_driver (name, obarray, tem); | ||
| 3812 | } else { | ||
| 3813 | Lisp_Object name | ||
| 3814 | = make_specified_string (read_buffer, nchars, nbytes, | ||
| 3815 | multibyte); | ||
| 3816 | result = intern_driver (name, obarray, tem); | ||
| 3817 | } | ||
| 3796 | } | 3818 | } |
| 3797 | 3819 | ||
| 3798 | if (EQ (Vread_with_symbol_positions, Qt) | 3820 | if (EQ (Vread_with_symbol_positions, Qt) |
| @@ -4402,10 +4424,29 @@ it defaults to the value of `obarray'. */) | |||
| 4402 | obarray = check_obarray (NILP (obarray) ? Vobarray : obarray); | 4424 | obarray = check_obarray (NILP (obarray) ? Vobarray : obarray); |
| 4403 | CHECK_STRING (string); | 4425 | CHECK_STRING (string); |
| 4404 | 4426 | ||
| 4405 | tem = oblookup_considering_shorthand (obarray, &string); | 4427 | |
| 4428 | char* longhand = NULL; | ||
| 4429 | ptrdiff_t longhand_chars = 0; | ||
| 4430 | ptrdiff_t longhand_bytes = 0; | ||
| 4431 | tem = oblookup_considering_shorthand | ||
| 4432 | (obarray, SSDATA (string), SCHARS (string), SBYTES (string), | ||
| 4433 | &longhand, &longhand_chars, &longhand_bytes); | ||
| 4434 | |||
| 4406 | if (!SYMBOLP (tem)) | 4435 | if (!SYMBOLP (tem)) |
| 4407 | tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string), | 4436 | { |
| 4408 | obarray, tem); | 4437 | if (longhand) |
| 4438 | { | ||
| 4439 | tem = intern_driver (make_specified_string (longhand, longhand_chars, | ||
| 4440 | longhand_bytes, true), | ||
| 4441 | obarray, tem); | ||
| 4442 | xfree (longhand); | ||
| 4443 | } | ||
| 4444 | else | ||
| 4445 | { | ||
| 4446 | tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string), | ||
| 4447 | obarray, tem); | ||
| 4448 | } | ||
| 4449 | } | ||
| 4409 | return tem; | 4450 | return tem; |
| 4410 | } | 4451 | } |
| 4411 | 4452 | ||
| @@ -4426,15 +4467,24 @@ it defaults to the value of `obarray'. */) | |||
| 4426 | { | 4467 | { |
| 4427 | CHECK_STRING (name); | 4468 | CHECK_STRING (name); |
| 4428 | string = name; | 4469 | string = name; |
| 4470 | char* longhand = NULL; | ||
| 4471 | ptrdiff_t longhand_chars = 0; | ||
| 4472 | ptrdiff_t longhand_bytes = 0; | ||
| 4473 | tem = oblookup_considering_shorthand | ||
| 4474 | (obarray, SSDATA (string), SCHARS (string), SBYTES (string), | ||
| 4475 | &longhand, &longhand_chars, &longhand_bytes); | ||
| 4476 | if (longhand) xfree (longhand); | ||
| 4477 | if (FIXNUMP (tem)) return Qnil; else return tem; | ||
| 4429 | } | 4478 | } |
| 4430 | else | 4479 | else |
| 4431 | string = SYMBOL_NAME (name); | 4480 | { |
| 4432 | 4481 | // If already a symbol, we do no shorthand-longhand translation, | |
| 4433 | tem = oblookup_considering_shorthand (obarray, &string); | 4482 | // as promised in docstring. |
| 4434 | if (FIXNUMP (tem) || (SYMBOLP (name) && !EQ (name, tem))) | 4483 | string = SYMBOL_NAME (name); |
| 4435 | return Qnil; | 4484 | tem |
| 4436 | else | 4485 | = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string)); |
| 4437 | return tem; | 4486 | if (EQ (name, tem)) return tem; else return Qnil; |
| 4487 | } | ||
| 4438 | } | 4488 | } |
| 4439 | 4489 | ||
| 4440 | DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0, | 4490 | DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0, |
| @@ -4461,7 +4511,14 @@ usage: (unintern NAME OBARRAY) */) | |||
| 4461 | string = name; | 4511 | string = name; |
| 4462 | } | 4512 | } |
| 4463 | 4513 | ||
| 4464 | tem = oblookup_considering_shorthand (obarray, &string); | 4514 | char* longhand = NULL; |
| 4515 | ptrdiff_t longhand_chars = 0; | ||
| 4516 | ptrdiff_t longhand_bytes = 0; | ||
| 4517 | tem = oblookup_considering_shorthand | ||
| 4518 | (obarray, SSDATA (string), SCHARS (string), SBYTES (string), | ||
| 4519 | &longhand, &longhand_chars, &longhand_bytes); | ||
| 4520 | if (longhand) free(longhand); | ||
| 4521 | |||
| 4465 | if (FIXNUMP (tem)) | 4522 | if (FIXNUMP (tem)) |
| 4466 | return Qnil; | 4523 | return Qnil; |
| 4467 | /* If arg was a symbol, don't delete anything but that symbol itself. */ | 4524 | /* If arg was a symbol, don't delete anything but that symbol itself. */ |
| @@ -4549,34 +4606,65 @@ oblookup (Lisp_Object obarray, register const char *ptr, ptrdiff_t size, ptrdiff | |||
| 4549 | return tem; | 4606 | return tem; |
| 4550 | } | 4607 | } |
| 4551 | 4608 | ||
| 4609 | /* Like 'oblookup', but considers 'Velisp_shorthands', potentially | ||
| 4610 | recognizing that IN is shorthand for some other longhand name, | ||
| 4611 | which is then then placed in OUT. In that case, memory is | ||
| 4612 | malloc'ed for OUT (which the caller must free) while SIZE_OUT and | ||
| 4613 | SIZE_BYTE_OUT respectively hold the character and byte sizes of the | ||
| 4614 | transformed symbol name. If IN is not recognized shorthand for any | ||
| 4615 | other symbol, OUT is set to point to NULL and 'oblookup' is | ||
| 4616 | called. */ | ||
| 4617 | |||
| 4552 | Lisp_Object | 4618 | Lisp_Object |
| 4553 | oblookup_considering_shorthand (Lisp_Object obarray, Lisp_Object* string) | 4619 | oblookup_considering_shorthand |
| 4620 | (Lisp_Object obarray, | ||
| 4621 | const char *in, ptrdiff_t size, ptrdiff_t size_byte, | ||
| 4622 | char **out, ptrdiff_t *size_out, ptrdiff_t *size_byte_out) | ||
| 4554 | { | 4623 | { |
| 4555 | Lisp_Object original = *string; /* Save pointer to original string... */ | 4624 | // First, assume no transformation will take place. |
| 4625 | *out = NULL; | ||
| 4556 | Lisp_Object tail = Velisp_shorthands; | 4626 | Lisp_Object tail = Velisp_shorthands; |
| 4557 | FOR_EACH_TAIL_SAFE(tail) | 4627 | // Then, iterate each pair in Velisp_shorthands. |
| 4628 | FOR_EACH_TAIL_SAFE (tail) | ||
| 4558 | { | 4629 | { |
| 4559 | Lisp_Object pair = XCAR (tail); | 4630 | Lisp_Object pair = XCAR (tail); |
| 4560 | if (!CONSP (pair)) goto undo; | 4631 | // Be lenient to Velisp_shorthands: if some element isn't a cons |
| 4561 | Lisp_Object shorthand = XCAR (pair); | 4632 | // or some member of that cons isn't a string, just skip to the |
| 4562 | Lisp_Object longhand = XCDR (pair); | 4633 | // next element. |
| 4563 | if (!STRINGP (shorthand) || !STRINGP (longhand)) goto undo; | 4634 | if (!CONSP (pair)) continue; |
| 4564 | Lisp_Object match = Fstring_match (shorthand, *string, Qnil); | 4635 | Lisp_Object sh_prefix = XCAR (pair); |
| 4565 | if (!NILP(match)){ | 4636 | Lisp_Object lh_prefix = XCDR (pair); |
| 4566 | *string = Freplace_match(longhand, Qnil, Qnil, *string, Qnil); | 4637 | if (!STRINGP (sh_prefix) || !STRINGP (lh_prefix)) continue; |
| 4567 | } | 4638 | ptrdiff_t sh_prefix_size = SBYTES (sh_prefix); |
| 4639 | |||
| 4640 | // Compare the prefix of the transformation pair to the symbol | ||
| 4641 | // name. If a match occurs, do the renaming and exit the loop. | ||
| 4642 | // In other words, only one such transformation may take place. | ||
| 4643 | // Calculate the amount of memory to allocate for the longhand | ||
| 4644 | // version of the symbol name with realloc(). This isn't | ||
| 4645 | // strictly needed, but it could later be used as a way for | ||
| 4646 | // multiple transformations on a single symbol name. | ||
| 4647 | if (sh_prefix_size <= size_byte && | ||
| 4648 | memcmp(SSDATA(sh_prefix), in, sh_prefix_size) == 0) | ||
| 4649 | { | ||
| 4650 | ptrdiff_t lh_prefix_size = SBYTES (lh_prefix); | ||
| 4651 | ptrdiff_t suffix_size = size_byte - sh_prefix_size; | ||
| 4652 | *out = xrealloc (*out, lh_prefix_size + suffix_size); | ||
| 4653 | memcpy (*out, SSDATA(lh_prefix), lh_prefix_size); | ||
| 4654 | memcpy (*out + lh_prefix_size, in + sh_prefix_size, suffix_size); | ||
| 4655 | *size_out = SCHARS (lh_prefix) - SCHARS (sh_prefix) + size; | ||
| 4656 | *size_byte_out = lh_prefix_size + suffix_size; | ||
| 4657 | break; | ||
| 4658 | } | ||
| 4568 | } | 4659 | } |
| 4569 | goto fine; | 4660 | // Now, as promised, call oblookup() with the "final" symbol name to |
| 4570 | undo: | 4661 | // lookup. That function remains oblivious to whether a |
| 4571 | { | 4662 | // transformation happened here or not, but the caller of this |
| 4572 | static const char* warn = | 4663 | // function can tell by inspecting the OUT parameter. |
| 4573 | "Fishy value of `elisp-shorthands'. " | 4664 | if (*out) |
| 4574 | "Consider reviewing before evaluating code."; | 4665 | return oblookup (obarray, *out, *size_out, *size_byte_out); |
| 4575 | message_dolog (warn, sizeof(warn), 0, 0); | 4666 | else |
| 4576 | *string = original; /* ...so we can any failed trickery here. */ | 4667 | return oblookup (obarray, in, size, size_byte); |
| 4577 | } | ||
| 4578 | fine: | ||
| 4579 | return oblookup(obarray, SSDATA (*string), SCHARS (*string), SBYTES (*string)); | ||
| 4580 | } | 4668 | } |
| 4581 | 4669 | ||
| 4582 | 4670 | ||