(export 'class-item)
+(define-pluggable-parser class-item initfrags (scanner class pset)
+ ;; raw-class-item ::= frag-keyword `{' c-fragment `}'
+ ;; frag-keyword ::= `init' | `teardown'
+ (with-parser-context (token-scanner-context :scanner scanner)
+ (parse (seq ((make (or (seq ("init") #'make-sod-class-initfrag)
+ (seq ("teardown") #'make-sod-class-tearfrag)))
+ (frag (parse-delimited-fragment scanner #\{ #\})))
+ (funcall make class frag pset scanner)))))
+
+(define-pluggable-parser class-item initargs (scanner class pset)
+ ;; initarg-item ::= `initarg' declspec+ init-declarator-list
+ ;; init-declarator ::= declarator [`=' initializer]
+ (with-parser-context (token-scanner-context :scanner scanner)
+ (parse (seq ("initarg"
+ (base-type (parse-c-type scanner))
+ (nil (skip-many (:min 1)
+ (seq ((declarator (parse-declarator scanner
+ base-type))
+ (init (? (parse-delimited-fragment
+ scanner #\= (list #\; #\,)
+ :keep-end t))))
+ (make-sod-user-initarg class
+ (cdr declarator)
+ (car declarator)
+ pset init scanner))
+ #\,))
+ #\;)))))
+
(defun parse-class-body (scanner pset name supers)
;; class-body ::= `{' class-item* `}'
;;
body sub-pset scanner))))
(parse-initializer ()
- ;; initializer ::= `=' c-fragment | `=' `{' c-fragment `}'
+ ;; initializer ::= `=' c-fragment
;;
- ;; Return (VALUE-KIND . VALUE-FORM), ready for passing to a
- ;; `sod-initializer' constructor.
-
- ;; This is kind of tricky because we have to juggle both
- ;; layers of the parsing machinery. The character scanner
- ;; will already have consumed the lookahead token (which, if
- ;; we're going to do anything, is `=').
- (let ((char-scanner (token-scanner-char-scanner scanner)))
-
- ;; First, skip the character-scanner past any whitespace.
- ;; We don't record this consumption, which is a bit
- ;; naughty, but nobody will actually mind.
- (loop
- (when (or (scanner-at-eof-p char-scanner)
- (not (whitespace-char-p
- (scanner-current-char char-scanner))))
- (return))
- (scanner-step char-scanner))
-
- ;; Now maybe read an initializer.
- (cond ((not (eql (token-type scanner) #\=))
- ;; It's not an `=' after all. There's no
- ;; initializer.
- (values '(#\=) nil nil))
-
- ((and (not (scanner-at-eof-p char-scanner))
- (char= (scanner-current-char char-scanner)
- #\{))
- ;; There's a brace after the `=', so we should
- ;; consume the `=' here, and read a compound
- ;; initializer enclosed in braces.
- (parse (seq (#\= (frag (parse-delimited-fragment
- scanner #\{ #\})))
- (cons :compound frag))))
-
- (t
- ;; No brace, so read from the `=' up to, but not
- ;; including, the trailing `,' or `;' delimiter.
- (parse (seq ((frag (parse-delimited-fragment
- scanner #\= '(#\; #\,)
- :keep-end t)))
- (cons :simple frag)))))))
+ ;; Return a VALUE, ready for passing to a `sod-initializer'
+ ;; constructor.
+ (parse-delimited-fragment scanner #\= (list #\, #\;)
+ :keep-end t))
(parse-slot-item (sub-pset base-type type name)
;; slot-item ::=
sub-pset scanner)
(when init
(make-sod-instance-initializer
- class nick name (car init) (cdr init)
- sub-pset scanner)))
+ class nick name init sub-pset scanner)))
(skip-many ()
(seq (#\,
(ds (parse-declarator scanner
sub-pset scanner)
(when init
(make-sod-instance-initializer
- class nick (cdr ds)
- (car init) (cdr init)
+ class nick (cdr ds) init
sub-pset scanner))))
#\;)))
- (parse-initializer-item (sub-pset constructor)
+ (parse-initializer-item (sub-pset must-init-p constructor)
;; initializer-item ::=
;; [`class'] -!- slot-initializer-list `;'
;;
- ;; slot-initializer ::= id `.' id initializer
- (parse (and (skip-many ()
- (seq ((name-a :id) #\. (name-b :id)
- (init (parse-initializer)))
- (funcall constructor class
- name-a name-b
- (car init) (cdr init)
- sub-pset scanner))
- #\,)
- #\;)))
+ ;; slot-initializer ::= id `.' id [initializer]
+ (let ((parse-init (if must-init-p
+ #'parse-initializer
+ (parser () (? (parse-initializer))))))
+ (parse (and (skip-many ()
+ (seq ((name-a :id) #\. (name-b :id)
+ (init (funcall parse-init)))
+ (funcall constructor class
+ name-a name-b init
+ sub-pset scanner))
+ #\,)
+ #\;))))
(class-item-dispatch (sub-pset base-type type name)
;; Logically part of `parse-raw-class-item', but the
;; | method-item
;; | slot-item
;; | initializer-item
+ ;; | initfrag-item
;;
;; Most of the above begin with declspecs and a declarator
;; (which might be dotted). So we parse that here and
(cdr dc))))))
(and "class"
(parse-initializer-item
- sub-pset
+ sub-pset t
#'make-sod-class-initializer))
(parse-initializer-item
- sub-pset
+ sub-pset nil
#'make-sod-instance-initializer)))))
(parse (seq (#\{