aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/syntax.c117
-rw-r--r--test/src/syntax-tests.el85
2 files changed, 147 insertions, 55 deletions
diff --git a/src/syntax.c b/src/syntax.c
index 84147a2dc15..0ee1c746ec3 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3092,6 +3092,36 @@ the prefix syntax flag (p). */)
3092 return Qnil; 3092 return Qnil;
3093} 3093}
3094 3094
3095
3096/* If the character at FROM_BYTE is the second part of a 2-character
3097 comment opener based on PREV_FROM_SYNTAX, update STATE and return
3098 true. */
3099static bool
3100in_2char_comment_start (struct lisp_parse_state *state,
3101 int prev_from_syntax,
3102 ptrdiff_t prev_from,
3103 ptrdiff_t from_byte)
3104{
3105 int c1, syntax;
3106 if (SYNTAX_FLAGS_COMSTART_FIRST (prev_from_syntax)
3107 && (c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte),
3108 syntax = SYNTAX_WITH_FLAGS (c1),
3109 SYNTAX_FLAGS_COMSTART_SECOND (syntax)))
3110 {
3111 /* Record the comment style we have entered so that only
3112 the comment-end sequence of the same style actually
3113 terminates the comment section. */
3114 state->comstyle
3115 = SYNTAX_FLAGS_COMMENT_STYLE (syntax, prev_from_syntax);
3116 bool comnested = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax)
3117 | SYNTAX_FLAGS_COMMENT_NESTED (syntax));
3118 state->incomment = comnested ? 1 : -1;
3119 state->comstr_start = prev_from;
3120 return true;
3121 }
3122 return false;
3123}
3124
3095/* Parse forward from FROM / FROM_BYTE to END, 3125/* Parse forward from FROM / FROM_BYTE to END,
3096 assuming that FROM has state STATE, 3126 assuming that FROM has state STATE,
3097 and return a description of the state of the parse at END. 3127 and return a description of the state of the parse at END.
@@ -3107,8 +3137,6 @@ scan_sexps_forward (struct lisp_parse_state *state,
3107 int commentstop) 3137 int commentstop)
3108{ 3138{
3109 enum syntaxcode code; 3139 enum syntaxcode code;
3110 int c1;
3111 bool comnested;
3112 struct level { ptrdiff_t last, prev; }; 3140 struct level { ptrdiff_t last, prev; };
3113 struct level levelstart[100]; 3141 struct level levelstart[100];
3114 struct level *curlevel = levelstart; 3142 struct level *curlevel = levelstart;
@@ -3122,7 +3150,6 @@ scan_sexps_forward (struct lisp_parse_state *state,
3122 ptrdiff_t prev_from; /* Keep one character before FROM. */ 3150 ptrdiff_t prev_from; /* Keep one character before FROM. */
3123 ptrdiff_t prev_from_byte; 3151 ptrdiff_t prev_from_byte;
3124 int prev_from_syntax, prev_prev_from_syntax; 3152 int prev_from_syntax, prev_prev_from_syntax;
3125 int syntax;
3126 bool boundary_stop = commentstop == -1; 3153 bool boundary_stop = commentstop == -1;
3127 bool nofence; 3154 bool nofence;
3128 bool found; 3155 bool found;
@@ -3187,53 +3214,31 @@ do { prev_from = from; \
3187 } 3214 }
3188 else if (start_quoted) 3215 else if (start_quoted)
3189 goto startquoted; 3216 goto startquoted;
3217 else if ((from < end)
3218 && (in_2char_comment_start (state, prev_from_syntax,
3219 prev_from, from_byte)))
3220 {
3221 INC_FROM;
3222 prev_from_syntax = Smax; /* the syntax has already been "used up". */
3223 goto atcomment;
3224 }
3190 3225
3191 while (from < end) 3226 while (from < end)
3192 { 3227 {
3193 if (SYNTAX_FLAGS_COMSTART_FIRST (prev_from_syntax) 3228 INC_FROM;
3194 && (c1 = FETCH_CHAR (from_byte), 3229
3195 syntax = SYNTAX_WITH_FLAGS (c1), 3230 if ((from < end)
3196 SYNTAX_FLAGS_COMSTART_SECOND (syntax))) 3231 && (in_2char_comment_start (state, prev_from_syntax,
3197 { 3232 prev_from, from_byte)))
3198 /* Record the comment style we have entered so that only
3199 the comment-end sequence of the same style actually
3200 terminates the comment section. */
3201 state->comstyle
3202 = SYNTAX_FLAGS_COMMENT_STYLE (syntax, prev_from_syntax);
3203 comnested = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax)
3204 | SYNTAX_FLAGS_COMMENT_NESTED (syntax));
3205 state->incomment = comnested ? 1 : -1;
3206 state->comstr_start = prev_from;
3207 INC_FROM;
3208 prev_from_syntax = Smax; /* the syntax has already been
3209 "used up". */
3210 code = Scomment;
3211 }
3212 else
3213 { 3233 {
3214 INC_FROM; 3234 INC_FROM;
3215 code = prev_from_syntax & 0xff; 3235 prev_from_syntax = Smax; /* the syntax has already been "used up". */
3216 if (code == Scomment_fence) 3236 goto atcomment;
3217 {
3218 /* Record the comment style we have entered so that only
3219 the comment-end sequence of the same style actually
3220 terminates the comment section. */
3221 state->comstyle = ST_COMMENT_STYLE;
3222 state->incomment = -1;
3223 state->comstr_start = prev_from;
3224 code = Scomment;
3225 }
3226 else if (code == Scomment)
3227 {
3228 state->comstyle = SYNTAX_FLAGS_COMMENT_STYLE (prev_from_syntax, 0);
3229 state->incomment = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax) ?
3230 1 : -1);
3231 state->comstr_start = prev_from;
3232 }
3233 } 3237 }
3234 3238
3235 if (SYNTAX_FLAGS_PREFIX (prev_from_syntax)) 3239 if (SYNTAX_FLAGS_PREFIX (prev_from_syntax))
3236 continue; 3240 continue;
3241 code = prev_from_syntax & 0xff;
3237 switch (code) 3242 switch (code)
3238 { 3243 {
3239 case Sescape: 3244 case Sescape:
@@ -3252,24 +3257,15 @@ do { prev_from = from; \
3252 symstarted: 3257 symstarted:
3253 while (from < end) 3258 while (from < end)
3254 { 3259 {
3255 int symchar = FETCH_CHAR_AS_MULTIBYTE (from_byte); 3260 if (in_2char_comment_start (state, prev_from_syntax,
3256 3261 prev_from, from_byte))
3257 if (SYNTAX_FLAGS_COMSTART_FIRST (prev_from_syntax)
3258 && (syntax = SYNTAX_WITH_FLAGS (symchar),
3259 SYNTAX_FLAGS_COMSTART_SECOND (syntax)))
3260 { 3262 {
3261 state->comstyle
3262 = SYNTAX_FLAGS_COMMENT_STYLE (syntax, prev_from_syntax);
3263 comnested = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax)
3264 | SYNTAX_FLAGS_COMMENT_NESTED (syntax));
3265 state->incomment = comnested ? 1 : -1;
3266 state->comstr_start = prev_from;
3267 INC_FROM; 3263 INC_FROM;
3268 prev_from_syntax = Smax; 3264 prev_from_syntax = Smax; /* the syntax has already been "used up". */
3269 code = Scomment;
3270 goto atcomment; 3265 goto atcomment;
3271 } 3266 }
3272 3267
3268 int symchar = FETCH_CHAR_AS_MULTIBYTE (from_byte);
3273 switch (SYNTAX (symchar)) 3269 switch (SYNTAX (symchar))
3274 { 3270 {
3275 case Scharquote: 3271 case Scharquote:
@@ -3290,8 +3286,19 @@ do { prev_from = from; \
3290 curlevel->prev = curlevel->last; 3286 curlevel->prev = curlevel->last;
3291 break; 3287 break;
3292 3288
3293 case Scomment_fence: /* Can't happen because it's handled above. */ 3289 case Scomment_fence:
3290 /* Record the comment style we have entered so that only
3291 the comment-end sequence of the same style actually
3292 terminates the comment section. */
3293 state->comstyle = ST_COMMENT_STYLE;
3294 state->incomment = -1;
3295 state->comstr_start = prev_from;
3296 goto atcomment;
3294 case Scomment: 3297 case Scomment:
3298 state->comstyle = SYNTAX_FLAGS_COMMENT_STYLE (prev_from_syntax, 0);
3299 state->incomment = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax) ?
3300 1 : -1);
3301 state->comstr_start = prev_from;
3295 atcomment: 3302 atcomment:
3296 if (commentstop || boundary_stop) goto done; 3303 if (commentstop || boundary_stop) goto done;
3297 startincomment: 3304 startincomment:
diff --git a/test/src/syntax-tests.el b/test/src/syntax-tests.el
new file mode 100644
index 00000000000..6edde0b137b
--- /dev/null
+++ b/test/src/syntax-tests.el
@@ -0,0 +1,85 @@
1;;; syntax-tests.el --- tests for syntax.c functions -*- lexical-binding: t -*-
2
3;; Copyright (C) 2017 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software: you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation, either version 3 of the License, or
10;; (at your option) any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
19
20;;; Code:
21
22(require 'ert)
23
24(ert-deftest parse-partial-sexp-continue-over-comment-marker ()
25 "Continue a parse that stopped in the middle of a comment marker."
26 (with-temp-buffer
27 (let ((table (make-syntax-table)))
28 (modify-syntax-entry ?/ ". 124")
29 (modify-syntax-entry ?* ". 23b")
30 (set-syntax-table table))
31 (insert "/*C*/\nX")
32 (goto-char (point-min))
33 (let* ((pointC (progn (search-forward "C") (1- (point))))
34 (preC (1- pointC))
35 (pointX (progn (search-forward "X") (1- (point))))
36 (aftC (+ 2 pointC))
37 (ppsC (parse-partial-sexp (point-min) pointC))
38 (pps-preC (parse-partial-sexp (point-min) preC))
39 (pps-aftC (parse-partial-sexp (point-min) aftC))
40 (ppsX (parse-partial-sexp (point-min) pointX)))
41 ;; C should be inside comment.
42 (should (= (nth 0 ppsC) 0))
43 (should (eq (nth 4 ppsC) t))
44 (should (= (nth 8 ppsC) (- pointC 2)))
45 ;; X should not be in comment or list.
46 (should (= (nth 0 ppsX) 0))
47 (should-not (nth 4 ppsX))
48 ;; Try using OLDSTATE.
49 (should (equal (parse-partial-sexp preC pointC nil nil pps-preC)
50 ppsC))
51 (should (equal (parse-partial-sexp pointC aftC nil nil ppsC)
52 pps-aftC))
53 (should (equal (parse-partial-sexp preC aftC nil nil pps-preC)
54 pps-aftC))
55 (should (equal (parse-partial-sexp aftC pointX nil nil pps-aftC)
56 ppsX)))))
57
58(ert-deftest parse-partial-sexp-paren-comments ()
59 "Test syntax parsing with paren comment markers.
60Specifically, where the first character of the comment marker is
61also has open paren syntax (see Bug#24870)."
62 (with-temp-buffer
63 (let ((table (make-syntax-table)))
64 (modify-syntax-entry ?\{ "(}1nb" table)
65 (modify-syntax-entry ?\} "){4nb" table)
66 (modify-syntax-entry ?- ". 123" table)
67 (set-syntax-table table))
68 (insert "{-C-}\nX")
69 (goto-char (point-min))
70 (let* ((pointC (progn (search-forward "C") (1- (point))))
71 (pointX (progn (search-forward "X") (1- (point))))
72 (ppsC (parse-partial-sexp (point-min) pointC))
73 (ppsX (parse-partial-sexp (point-min) pointX)))
74 ;; C should be inside nestable comment, not list.
75 (should (= (nth 0 ppsC) 0))
76 (should (= (nth 4 ppsC) 1))
77 (should (= (nth 8 ppsC) (- pointC 2)))
78 ;; X should not be in comment or list.
79 (should (= (nth 0 ppsX) 0))
80 (should-not (nth 4 ppsX))
81 ;; Try using OLDSTATE.
82 (should (equal (parse-partial-sexp pointC pointX nil nil ppsC)
83 ppsX)))))
84
85;;; syntax-tests.el ends here