;;; cc-engine.el --- core syntax guessing engine for CC mode
-;; Copyright (C) 1985, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-;; 2010 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1987, 1992-2011 Free Software Foundation, Inc.
;; Authors: 2001- Alan Mackenzie
;; 1998- Martin Stjernholm
;; 1985 Richard M. Stallman
;; Maintainer: bug-cc-mode@gnu.org
;; Created: 22-Apr-1997 (split from cc-mode.el)
-;; Version: See cc-mode.el
-;; Keywords: c languages oop
+;; Keywords: c languages
+;; Package: cc-mode
;; This file is part of GNU Emacs.
;; cc-mode requires cc-fonts.
(declare-function c-fontify-recorded-types-and-refs "cc-fonts" ())
+(defvar c-forward-<>-arglist-recur-depth)
+
(defun c-forward-<>-arglist (all-types)
;; The point is assumed to be at a "<". Try to treat it as the open
;; paren of an angle bracket arglist and move forward to the
;; If `c-record-type-identifiers' is set then activate
;; recording of any found types that constitute an argument in
;; the arglist.
- (c-record-found-types (if c-record-type-identifiers t)))
+ (c-record-found-types (if c-record-type-identifiers t))
+ (c-forward-<>-arglist-recur--depth 0))
(if (catch 'angle-bracket-arglist-escape
(setq c-record-found-types
(c-forward-<>-arglist-recur all-types)))
nil)))
(defun c-forward-<>-arglist-recur (all-types)
+
+ ;; Temporary workaround for Bug#7722.
+ (when (boundp 'c-forward-<>-arglist-recur--depth)
+ (if (> c-forward-<>-arglist-recur--depth 200)
+ (error "Max recursion depth reached in <> arglist")
+ (setq c-forward-<>-arglist-recur--depth
+ (1+ c-forward-<>-arglist-recur--depth))))
+
;; Recursive part of `c-forward-<>-arglist'.
;;
;; This function might do hidden buffer changes.
(forward-char)
(unless (looking-at c-<-op-cont-regexp)
- (while (and
+ (while (and
(progn
- (c-forward-syntactic-ws)
- (let ((orig-record-found-types c-record-found-types))
- (when (or (and c-record-type-identifiers all-types)
- (c-major-mode-is 'java-mode))
- ;; All encountered identifiers are types, so set the
- ;; promote flag and parse the type.
- (progn
- (c-forward-syntactic-ws)
- (if (looking-at "\\?")
- (forward-char)
- (when (looking-at c-identifier-start)
- (let ((c-promote-possible-types t)
- (c-record-found-types t))
- (c-forward-type))))
+ (c-forward-syntactic-ws)
+ (let ((orig-record-found-types c-record-found-types))
+ (when (or (and c-record-type-identifiers all-types)
+ (c-major-mode-is 'java-mode))
+ ;; All encountered identifiers are types, so set the
+ ;; promote flag and parse the type.
+ (progn
+ (c-forward-syntactic-ws)
+ (if (looking-at "\\?")
+ (forward-char)
+ (when (looking-at c-identifier-start)
+ (let ((c-promote-possible-types t)
+ (c-record-found-types t))
+ (c-forward-type))))
- (c-forward-syntactic-ws)
+ (c-forward-syntactic-ws)
- (when (or (looking-at "extends")
- (looking-at "super"))
- (forward-word)
- (c-forward-syntactic-ws)
- (let ((c-promote-possible-types t)
- (c-record-found-types t))
- (c-forward-type)
- (c-forward-syntactic-ws))))))
-
- (setq pos (point))
-
- (or
- ;; Note: These regexps exploit the match order in \| so
- ;; that "<>" is matched by "<" rather than "[^>:-]>".
- (c-syntactic-re-search-forward
- ;; Stop on ',', '|', '&', '+' and '-' to catch
- ;; common binary operators that could be between
- ;; two comparison expressions "a<b" and "c>d".
- "[<;{},|+&-]\\|[>)]"
- nil t t)
- t))
+ (when (or (looking-at "extends")
+ (looking-at "super"))
+ (forward-word)
+ (c-forward-syntactic-ws)
+ (let ((c-promote-possible-types t)
+ (c-record-found-types t))
+ (c-forward-type)
+ (c-forward-syntactic-ws))))))
- (cond
- ((eq (char-before) ?>)
+ (setq pos (point))
+
+ ;; Note: These regexps exploit the match order in \| so
+ ;; that "<>" is matched by "<" rather than "[^>:-]>".
+ (c-syntactic-re-search-forward
+ ;; Stop on ',', '|', '&', '+' and '-' to catch
+ ;; common binary operators that could be between
+ ;; two comparison expressions "a<b" and "c>d".
+ "[<;{},|+&-]\\|[>)]"
+ nil t t))
+
+ (cond
+ ((eq (char-before) ?>)
;; Either an operator starting with '>' or the end of
;; the angle bracket arglist.
(when (or (setq keyword-match
(looking-at c-opt-<>-sexp-key))
(not (looking-at c-keywords-regexp)))
- (setq id-start (point))))
-
- (setq subres
- (let ((c-promote-possible-types t)
- (c-record-found-types t))
- (c-forward-<>-arglist-recur
- (and keyword-match
- (c-keyword-member
+ (setq id-start (point))))
+
+ (setq subres
+ (let ((c-promote-possible-types t)
+ (c-record-found-types t))
+ (c-forward-<>-arglist-recur
+ (and keyword-match
+ (c-keyword-member
(c-keyword-sym (match-string 1))
'c-<>-type-kwds)))))
)))
(c-forward-syntactic-ws)
(looking-at c-opt-identifier-concat-key)))
(c-record-ref-id (cons id-start id-end))
- (c-record-type-id (cons id-start id-end))))))
- t)
-
- ((and (not c-restricted-<>-arglists)
- (or (and (eq (char-before) ?&)
- (not (eq (char-after) ?&)))
- (eq (char-before) ?,)))
- ;; Just another argument. Record the position. The
- ;; type check stuff that made us stop at it is at
- ;; the top of the loop.
+ (c-record-type-id (cons id-start id-end))))))
+ t)
+
+ ((and (not c-restricted-<>-arglists)
+ (or (and (eq (char-before) ?&)
+ (not (eq (char-after) ?&)))
+ (eq (char-before) ?,)))
+ ;; Just another argument. Record the position. The
+ ;; type check stuff that made us stop at it is at
+ ;; the top of the loop.
(setq arg-start-pos (cons (point) arg-start-pos)))
(t
(defun c-forward-name ()
;; Move forward over a complete name if at the beginning of one,
- ;; stopping at the next following token. If the point is not at
- ;; something that are recognized as name then it stays put. A name
- ;; could be something as simple as "foo" in C or something as
+ ;; stopping at the next following token. A keyword, as such,
+ ;; doesn't count as a name. If the point is not at something that
+ ;; is recognized as a name then it stays put.
+ ;;
+ ;; A name could be something as simple as "foo" in C or something as
;; complex as "X<Y<class A<int>::B, BIT_MAX >> b>, ::operator<> ::
;; Z<(a>b)> :: operator const X<&foo>::T Q::G<unsigned short
;; int>::*volatile const" in C++ (this function is actually little
;; more than a `looking-at' call in all modes except those that,
- ;; like C++, have `c-recognize-<>-arglists' set). Return nil if no
- ;; name is found, 'template if it's an identifier ending with an
- ;; angle bracket arglist, 'operator of it's an operator identifier,
- ;; or t if it's some other kind of name.
+ ;; like C++, have `c-recognize-<>-arglists' set).
+ ;;
+ ;; Return
+ ;; o - nil if no name is found;
+ ;; o - 'template if it's an identifier ending with an angle bracket
+ ;; arglist;
+ ;; o - 'operator of it's an operator identifier;
+ ;; o - t if it's some other kind of name.
;;
;; This function records identifier ranges on
;; `c-record-type-identifiers' and `c-record-ref-identifiers' if
(goto-char pos)
res))
-(defun c-forward-type ()
+(defun c-forward-type (&optional brace-block-too)
;; Move forward over a type spec if at the beginning of one,
- ;; stopping at the next following token. Return t if it's a known
- ;; type that can't be a name or other expression, 'known if it's an
- ;; otherwise known type (according to `*-font-lock-extra-types'),
- ;; 'prefix if it's a known prefix of a type, 'found if it's a type
- ;; that matches one in `c-found-types', 'maybe if it's an identfier
- ;; that might be a type, or nil if it can't be a type (the point
- ;; isn't moved then). The point is assumed to be at the beginning
- ;; of a token.
+ ;; stopping at the next following token. The keyword "typedef"
+ ;; isn't part of a type spec here.
+ ;;
+ ;; BRACE-BLOCK-TOO, when non-nil, means move over the brace block in
+ ;; constructs like "struct foo {...} bar ;" or "struct {...} bar;".
+ ;; The current (2009-03-10) intention is to convert all uses of
+ ;; `c-forward-type' to call with this parameter set, then to
+ ;; eliminate it.
+ ;;
+ ;; Return
+ ;; o - t if it's a known type that can't be a name or other
+ ;; expression;
+ ;; o - 'known if it's an otherwise known type (according to
+ ;; `*-font-lock-extra-types');
+ ;; o - 'prefix if it's a known prefix of a type;
+ ;; o - 'found if it's a type that matches one in `c-found-types';
+ ;; o - 'maybe if it's an identfier that might be a type; or
+ ;; o - nil if it can't be a type (the point isn't moved then).
+ ;;
+ ;; The point is assumed to be at the beginning of a token.
;;
;; Note that this function doesn't skip past the brace definition
;; that might be considered part of the type, e.g.
;; `c-record-type-identifiers' is non-nil.
;;
;; This function might do hidden buffer changes.
- (when (looking-at "<")
+ (when (and c-recognize-<>-arglists
+ (looking-at "<"))
(c-forward-<>-arglist t)
(c-forward-syntactic-ws))
;; Skip leading type modifiers. If any are found we know it's a
;; prefix of a type.
- (when c-opt-type-modifier-key
+ (when c-opt-type-modifier-key ; e.g. "const" "volatile", but NOT "typedef"
(while (looking-at c-opt-type-modifier-key)
(goto-char (match-end 1))
(c-forward-syntactic-ws)
(setq res 'prefix)))
(cond
- ((looking-at c-type-prefix-key)
- ;; Looking at a keyword that prefixes a type identifier,
- ;; e.g. "class".
+ ((looking-at c-type-prefix-key) ; e.g. "struct", "class", but NOT
+ ; "typedef".
(goto-char (match-end 1))
(c-forward-syntactic-ws)
(setq pos (point))
- (if (memq (setq name-res (c-forward-name)) '(t template))
- (progn
- (when (eq name-res t)
- ;; In many languages the name can be used without the
- ;; prefix, so we add it to `c-found-types'.
- (c-add-type pos (point))
- (when (and c-record-type-identifiers
- c-last-identifier-range)
- (c-record-type-id c-last-identifier-range)))
- (setq res t))
- ;; Invalid syntax.
- (goto-char start)
- (setq res nil)))
+
+ (setq name-res (c-forward-name))
+ (setq res (not (null name-res)))
+ (when (eq name-res t)
+ ;; In many languages the name can be used without the
+ ;; prefix, so we add it to `c-found-types'.
+ (c-add-type pos (point))
+ (when (and c-record-type-identifiers
+ c-last-identifier-range)
+ (c-record-type-id c-last-identifier-range)))
+ (when (and brace-block-too
+ (memq res '(t nil))
+ (eq (char-after) ?\{)
+ (save-excursion
+ (c-safe
+ (progn (c-forward-sexp)
+ (c-forward-syntactic-ws)
+ (setq pos (point))))))
+ (goto-char pos)
+ (setq res t))
+ (unless res (goto-char start))) ; invalid syntax
((progn
(setq pos nil)
(setq res nil)))))
(when res
- ;; Skip trailing type modifiers. If any are found we know it's
+ ;; Skip trailing type modifiers. If any are found we know it's
;; a type.
(when c-opt-type-modifier-key
- (while (looking-at c-opt-type-modifier-key)
+ (while (looking-at c-opt-type-modifier-key) ; e.g. "const", "volatile"
(goto-char (match-end 1))
(c-forward-syntactic-ws)
(setq res t)))
-
;; Step over any type suffix operator. Do not let the existence
;; of these alter the classification of the found type, since
;; these operators typically are allowed in normal expressions
(goto-char (match-end 1))
(c-forward-syntactic-ws)))
- (when c-opt-type-concat-key
+ (when c-opt-type-concat-key ; Only/mainly for pike.
;; Look for a trailing operator that concatenates the type
;; with a following one, and if so step past that one through
;; a recursive call. Note that we don't record concatenated
;; car ^ ^ point
;; Foo::Foo (int b) : Base (b) {}
;; car ^ ^ point
- ;;
- ;; The cdr of the return value is non-nil iff a `c-typedef-decl-kwds'
- ;; specifier (e.g. class, struct, enum, typedef) is found in the
- ;; declaration, i.e. the declared identifier(s) are types.
- ;;
+ ;;
+ ;; The cdr of the return value is non-nil when a
+ ;; `c-typedef-decl-kwds' specifier is found in the declaration.
+ ;; Specifically it is a dotted pair (A . B) where B is t when a
+ ;; `c-typedef-kwds' ("typedef") is present, and A is t when some
+ ;; other `c-typedef-decl-kwds' (e.g. class, struct, enum)
+ ;; specifier is present. I.e., (some of) the declared
+ ;; identifier(s) are types.
+ ;;
;; If a cast is parsed:
;;
;; The point is left at the first token after the closing paren of
;; If `backup-at-type' is nil then the other variables have
;; undefined values.
backup-at-type backup-type-start backup-id-start
- ;; Set if we've found a specifier that makes the defined
- ;; identifier(s) types.
+ ;; Set if we've found a specifier (apart from "typedef") that makes
+ ;; the defined identifier(s) types.
at-type-decl
+ ;; Set if we've a "typedef" keyword.
+ at-typedef
;; Set if we've found a specifier that can start a declaration
;; where there's no type.
maybe-typeless
;; Look for a specifier keyword clause.
(when (looking-at c-prefix-spec-kwds-re)
+ (if (looking-at c-typedef-key)
+ (setq at-typedef t))
(setq kwd-sym (c-keyword-sym (match-string 1)))
(save-excursion
(c-forward-keyword-clause 1)
(setq kwd-clause-end (point))))
- (when (setq found-type (c-forward-type))
+ (when (setq found-type (c-forward-type t)) ; brace-block-too
;; Found a known or possible type or a prefix of a known type.
(when at-type
(setq backup-maybe-typeless t)))
(when (c-keyword-member kwd-sym 'c-typedef-decl-kwds)
+ ;; This test only happens after we've scanned a type.
+ ;; So, with valid syntax, kwd-sym can't be 'typedef.
(setq at-type-decl t))
(when (c-keyword-member kwd-sym 'c-typeless-decl-kwds)
(setq maybe-typeless t))
(goto-char type-start)
(c-forward-type))))
- (cons id-start at-type-decl))
+ (cons id-start
+ (and (or at-type-decl at-typedef)
+ (cons at-type-decl at-typedef))))
(t
;; False alarm. Restore the recorded ranges.
\f
(cc-provide 'cc-engine)
-;; arch-tag: 149add18-4673-4da5-ac47-6805e4eae089
;;; cc-engine.el ends here