aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJoão Távora2020-12-23 19:57:27 +0000
committerJoão Távora2021-09-27 01:07:11 +0100
commit68d73eb154c745cbba7b3fd6a0a0a087d7c157da (patch)
tree1b276611e4dabd49a33daa165e38d2cb464340c1 /src
parent71857d410635743d437ce1ee73dff69de50030d6 (diff)
downloademacs-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.c170
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
2959Lisp_Object oblookup_considering_shorthand (Lisp_Object, Lisp_Object*); 2959Lisp_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
4440DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0, 4490DEFUN ("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
4552Lisp_Object 4618Lisp_Object
4553oblookup_considering_shorthand (Lisp_Object obarray, Lisp_Object* string) 4619oblookup_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