return Qnil;
}
\f
+
+/* If the character at FROM_BYTE is the second part of a 2-character
+ comment opener based on PREV_FROM_SYNTAX, update STATE and return
+ true. */
+static bool
+in_2char_comment_start (struct lisp_parse_state *state,
+ int prev_from_syntax,
+ ptrdiff_t prev_from,
+ ptrdiff_t from_byte)
+{
+ int c1, syntax;
+ if (SYNTAX_FLAGS_COMSTART_FIRST (prev_from_syntax)
+ && (c1 = FETCH_CHAR_AS_MULTIBYTE (from_byte),
+ syntax = SYNTAX_WITH_FLAGS (c1),
+ SYNTAX_FLAGS_COMSTART_SECOND (syntax)))
+ {
+ /* Record the comment style we have entered so that only
+ the comment-end sequence of the same style actually
+ terminates the comment section. */
+ state->comstyle
+ = SYNTAX_FLAGS_COMMENT_STYLE (syntax, prev_from_syntax);
+ bool comnested = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax)
+ | SYNTAX_FLAGS_COMMENT_NESTED (syntax));
+ state->incomment = comnested ? 1 : -1;
+ state->comstr_start = prev_from;
+ return true;
+ }
+ return false;
+}
+
/* Parse forward from FROM / FROM_BYTE to END,
assuming that FROM has state STATE,
and return a description of the state of the parse at END.
int commentstop)
{
enum syntaxcode code;
- int c1;
- bool comnested;
struct level { ptrdiff_t last, prev; };
struct level levelstart[100];
struct level *curlevel = levelstart;
ptrdiff_t prev_from; /* Keep one character before FROM. */
ptrdiff_t prev_from_byte;
int prev_from_syntax, prev_prev_from_syntax;
- int syntax;
bool boundary_stop = commentstop == -1;
bool nofence;
bool found;
}
else if (start_quoted)
goto startquoted;
+ else if ((from < end)
+ && (in_2char_comment_start (state, prev_from_syntax,
+ prev_from, from_byte)))
+ {
+ INC_FROM;
+ prev_from_syntax = Smax; /* the syntax has already been "used up". */
+ goto atcomment;
+ }
while (from < end)
{
- if (SYNTAX_FLAGS_COMSTART_FIRST (prev_from_syntax)
- && (c1 = FETCH_CHAR (from_byte),
- syntax = SYNTAX_WITH_FLAGS (c1),
- SYNTAX_FLAGS_COMSTART_SECOND (syntax)))
- {
- /* Record the comment style we have entered so that only
- the comment-end sequence of the same style actually
- terminates the comment section. */
- state->comstyle
- = SYNTAX_FLAGS_COMMENT_STYLE (syntax, prev_from_syntax);
- comnested = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax)
- | SYNTAX_FLAGS_COMMENT_NESTED (syntax));
- state->incomment = comnested ? 1 : -1;
- state->comstr_start = prev_from;
- INC_FROM;
- prev_from_syntax = Smax; /* the syntax has already been
- "used up". */
- code = Scomment;
- }
- else
+ INC_FROM;
+
+ if ((from < end)
+ && (in_2char_comment_start (state, prev_from_syntax,
+ prev_from, from_byte)))
{
INC_FROM;
- code = prev_from_syntax & 0xff;
- if (code == Scomment_fence)
- {
- /* Record the comment style we have entered so that only
- the comment-end sequence of the same style actually
- terminates the comment section. */
- state->comstyle = ST_COMMENT_STYLE;
- state->incomment = -1;
- state->comstr_start = prev_from;
- code = Scomment;
- }
- else if (code == Scomment)
- {
- state->comstyle = SYNTAX_FLAGS_COMMENT_STYLE (prev_from_syntax, 0);
- state->incomment = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax) ?
- 1 : -1);
- state->comstr_start = prev_from;
- }
+ prev_from_syntax = Smax; /* the syntax has already been "used up". */
+ goto atcomment;
}
if (SYNTAX_FLAGS_PREFIX (prev_from_syntax))
continue;
+ code = prev_from_syntax & 0xff;
switch (code)
{
case Sescape:
symstarted:
while (from < end)
{
- int symchar = FETCH_CHAR_AS_MULTIBYTE (from_byte);
-
- if (SYNTAX_FLAGS_COMSTART_FIRST (prev_from_syntax)
- && (syntax = SYNTAX_WITH_FLAGS (symchar),
- SYNTAX_FLAGS_COMSTART_SECOND (syntax)))
+ if (in_2char_comment_start (state, prev_from_syntax,
+ prev_from, from_byte))
{
- state->comstyle
- = SYNTAX_FLAGS_COMMENT_STYLE (syntax, prev_from_syntax);
- comnested = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax)
- | SYNTAX_FLAGS_COMMENT_NESTED (syntax));
- state->incomment = comnested ? 1 : -1;
- state->comstr_start = prev_from;
INC_FROM;
- prev_from_syntax = Smax;
- code = Scomment;
+ prev_from_syntax = Smax; /* the syntax has already been "used up". */
goto atcomment;
}
+ int symchar = FETCH_CHAR_AS_MULTIBYTE (from_byte);
switch (SYNTAX (symchar))
{
case Scharquote:
curlevel->prev = curlevel->last;
break;
- case Scomment_fence: /* Can't happen because it's handled above. */
+ case Scomment_fence:
+ /* Record the comment style we have entered so that only
+ the comment-end sequence of the same style actually
+ terminates the comment section. */
+ state->comstyle = ST_COMMENT_STYLE;
+ state->incomment = -1;
+ state->comstr_start = prev_from;
+ goto atcomment;
case Scomment:
+ state->comstyle = SYNTAX_FLAGS_COMMENT_STYLE (prev_from_syntax, 0);
+ state->incomment = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax) ?
+ 1 : -1);
+ state->comstr_start = prev_from;
atcomment:
if (commentstop || boundary_stop) goto done;
startincomment:
--- /dev/null
+;;; syntax-tests.el --- tests for syntax.c functions -*- lexical-binding: t -*-
+
+;; Copyright (C) 2017 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest parse-partial-sexp-continue-over-comment-marker ()
+ "Continue a parse that stopped in the middle of a comment marker."
+ (with-temp-buffer
+ (let ((table (make-syntax-table)))
+ (modify-syntax-entry ?/ ". 124")
+ (modify-syntax-entry ?* ". 23b")
+ (set-syntax-table table))
+ (insert "/*C*/\nX")
+ (goto-char (point-min))
+ (let* ((pointC (progn (search-forward "C") (1- (point))))
+ (preC (1- pointC))
+ (pointX (progn (search-forward "X") (1- (point))))
+ (aftC (+ 2 pointC))
+ (ppsC (parse-partial-sexp (point-min) pointC))
+ (pps-preC (parse-partial-sexp (point-min) preC))
+ (pps-aftC (parse-partial-sexp (point-min) aftC))
+ (ppsX (parse-partial-sexp (point-min) pointX)))
+ ;; C should be inside comment.
+ (should (= (nth 0 ppsC) 0))
+ (should (eq (nth 4 ppsC) t))
+ (should (= (nth 8 ppsC) (- pointC 2)))
+ ;; X should not be in comment or list.
+ (should (= (nth 0 ppsX) 0))
+ (should-not (nth 4 ppsX))
+ ;; Try using OLDSTATE.
+ (should (equal (parse-partial-sexp preC pointC nil nil pps-preC)
+ ppsC))
+ (should (equal (parse-partial-sexp pointC aftC nil nil ppsC)
+ pps-aftC))
+ (should (equal (parse-partial-sexp preC aftC nil nil pps-preC)
+ pps-aftC))
+ (should (equal (parse-partial-sexp aftC pointX nil nil pps-aftC)
+ ppsX)))))
+
+(ert-deftest parse-partial-sexp-paren-comments ()
+ "Test syntax parsing with paren comment markers.
+Specifically, where the first character of the comment marker is
+also has open paren syntax (see Bug#24870)."
+ (with-temp-buffer
+ (let ((table (make-syntax-table)))
+ (modify-syntax-entry ?\{ "(}1nb" table)
+ (modify-syntax-entry ?\} "){4nb" table)
+ (modify-syntax-entry ?- ". 123" table)
+ (set-syntax-table table))
+ (insert "{-C-}\nX")
+ (goto-char (point-min))
+ (let* ((pointC (progn (search-forward "C") (1- (point))))
+ (pointX (progn (search-forward "X") (1- (point))))
+ (ppsC (parse-partial-sexp (point-min) pointC))
+ (ppsX (parse-partial-sexp (point-min) pointX)))
+ ;; C should be inside nestable comment, not list.
+ (should (= (nth 0 ppsC) 0))
+ (should (= (nth 4 ppsC) 1))
+ (should (= (nth 8 ppsC) (- pointC 2)))
+ ;; X should not be in comment or list.
+ (should (= (nth 0 ppsX) 0))
+ (should-not (nth 4 ppsX))
+ ;; Try using OLDSTATE.
+ (should (equal (parse-partial-sexp pointC pointX nil nil ppsC)
+ ppsX)))))
+
+;;; syntax-tests.el ends here