Hi Eric,
As I am currently on vacation, I got some free time to work on
Semantic 2.0 :-)
First, I submit you a patch to semantic-lex.el and semantic.el to
simplify and improve some code. See the attached file semantic.patch
for details.
My second point is the following proposal for an enhanced API to
manage nonterminal expansion (see the code at end).
* The new API can work like the old one.
In mode hook, instead of using:
(setq semantic-expand-nonterminal 'my-expander)
you must write:
(semantic-install-nonterminal-expanders
'((t . my-expander)))
* To avoid unnecessary call to the expander on every tokens (and
save CPU!), it is now also possible to do something like this:
(semantic-install-nonterminal-expanders
'((variable . my-expander)
(type . my-expander)))
* Even better it is possible to use specific expanders, like this:
(semantic-install-nonterminal-expanders
'((variable . my-variable-expander)
(type . my-type-expander)))
What do you think?
Sincerely,
David
--------------- The code:
(defvar semantic-expand-nonterminal-obarray [0]
"Buffer local obarray of nonterminal expanders.
Use the function `semantic-install-nonterminal-expanders' to install
expanders.")
(make-variable-buffer-local 'semantic-expand-nonterminal-obarray)
(defun semantic-install-nonterminal-expanders (expanders)
"Install nonterminal EXPANDERS in `semantic-nonterminal-expanders'.
EXPANDERS must be an alist of elements:
(TOKEN-CLASS . FUNCTION)
TOKEN-CLASS is a symbol equal to a semantic token class to expand
\(like type, function, variable, etc.), or t for all other ones.
FUNCTION is the function to expand the token with. It will receive
the semantic token to expand."
(if (eq semantic-expand-nonterminal-obarray
(default-value 'semantic-expand-nonterminal-obarray))
(setq semantic-expand-nonterminal-obarray (make-vector 13 0)))
(while expanders
(set (intern (symbol-name (caar expanders))
semantic-expand-nonterminal-obarray)
(cdar expanders))
(setq expanders (cdr expanders)))
semantic-expand-nonterminal-obarray)
(defsubst semantic-nonterminal-expander (token)
"Find and return the expander function for TOKEN.
Return nil if not found."
(symbol-value
(or (intern-soft (symbol-name (semantic-token-token token))
semantic-expand-nonterminal-obarray)
(intern-soft "t" semantic-expand-nonterminal-obarray))))
;; Following is the updated version of `semantic-raw-to-cooked-token'
;; to use the new mechanism.
(defun semantic-raw-to-cooked-token (token)
"Convert TOKEN from a raw state to a cooked state.
The parser returns raw tokens with positional data START/END. We
convert it from that to a cooked state with a property list and a
vector [START END]. The raw token is changed with side effects and
maybe expanded in several cooked tokens when the variable
`semantic-expand-nonterminal' is set. So this function always returns
a list of cooked tokens."
;; Because some parsers can return tokens already cooked (wisent is
;; an example), check if TOKEN was already cooked to just return it.
(if (semantic-cooked-token-p token)
token
(let* ((ncdr (- (length token) 2))
(propcdr (if (natnump ncdr) (nthcdr ncdr token)))
(rngecdr (cdr propcdr))
;; propcdr is the CDR containing the START from the token.
;; rngecdr is the CDR containing the END from the token.
;; PROPCDR will contain the property list after cooking.
;; RNGECDR will contain the [START END] vector after cooking.
(range (condition-case nil
(vector (car propcdr) (car rngecdr))
(error (debug token)
nil)))
result expander expandedtokens)
;; Convert START/END into PROPERTIES/[START END].
(setcar rngecdr range)
(setcar propcdr nil)
;; Expand based on local configuration
(if (setq expander (semantic-nonterminal-expander token))
;; Glom generated tokens. THESE TOKENS MUST BE VALID ONES!
(setq expandedtokens (funcall expander token)
result (if expandedtokens
(append expandedtokens result)
(cons token result)))
;; No expanders
(setq result (cons token result)))
result)))
|