(enum (make-instance 'protobuf-enum
:class type
:name name
+ :qualified-name (make-qualified-name *protobuf* name)
:alias-for alias-for
:options options
:documentation documentation)))
(message (make-instance 'protobuf-message
:class type
:name name
+ :qualified-name (make-qualified-name *protobuf* name)
:parent *protobuf*
:alias-for alias-for
:conc-name conc-name
(make-instance 'protobuf-message
:class type
:name name
+ :qualified-name (make-qualified-name *protobuf* name)
:parent (proto-parent message)
:alias-for alias-for
:conc-name conc-name
:name (slot-name->proto slot)
:type name
:class type
+ :qualified-name (make-qualified-name *protobuf* (slot-name->proto slot))
:required arity
:index index
:value slot
(message (make-instance 'protobuf-message
:class type
:name name
+ :qualified-name (make-qualified-name *protobuf* name)
:alias-for alias-for
:conc-name conc-name
:options (remove-options options "default" "packed")
:name (or name (slot-name->proto slot))
:type ptype
:class pclass
+ :qualified-name (make-qualified-name *protobuf* (or name (slot-name->proto slot)))
;; One of :required, :optional or :repeated
:required reqd
:index idx
(service (make-instance 'protobuf-service
:class type
:name name
+ :qualified-name (make-qualified-name *protobuf* name)
:options options
:documentation documentation))
(index 0))
(method (make-instance 'protobuf-method
:class function
:name (or name (class-name->proto function))
+ :qualified-name (make-qualified-name *protobuf* (or name (class-name->proto function)))
:client-stub client-fn
:server-stub server-fn
:input-type input-type
;; A few things (the pretty printer) want to keep track of the current schema
(defvar *protobuf* nil
- "The Protobufs object currently being defined, e.g., a schema, a message, etc.")
+ "The Protobufs object currently being defined, either a schema or a message.")
(defvar *protobuf-package* nil
"The Lisp package in which the Protobufs schema is being defined.")
:reader proto-name
:initarg :name
:initform nil)
- (full-name :type (or null string) ;the fully qualified name, e.g., "proto2.MessageSet"
+ (qual-name :type string ;the fully qualified name, e.g., "proto2.MessageSet"
:accessor proto-qualified-name
:initarg :qualified-name
- :initform nil)
+ :initform "")
(options :type (list-of protobuf-option) ;options, mostly just passed along
:accessor proto-options
:initarg :options
"The base class for all Protobufs model classes."))
(defun find-qualified-name (name protos
- &key (proto-key #'proto-name) (lisp-key #'proto-class))
+ &key (proto-key #'proto-name) (full-key #'proto-qualified-name)
+ (lisp-key #'proto-class))
"Find something by its string name.
First do a simple name match.
Failing that, exhaustively search qualified names."
(or (find name protos :key proto-key :test #'string=)
+ (find name protos :key full-key :test #'string=)
;; Get desperate in the face of incomplete namespace support
;;--- This needs to be more sophisticated than just using Lisp packages
(multiple-value-bind (name package path other)
:accessor proto-package
:initarg :package
:initform nil)
- (lisp-pkg :type (or null string) ;the Lisp package, from 'option lisp_package = ...'
+ (lisp-pkg :type (or null string) ;the Lisp package, from 'option lisp_package = ...'
:accessor proto-lisp-package
:initarg :lisp-package
:initform nil)
(format stream "~@[~S~]~@[ (package ~A)~]"
(proto-class s) (proto-package s))))
+(defgeneric make-qualified-name (proto name)
+ (:documentation
+ "Give a schema or message and a name,
+ generate a fully qualified name string for the name."))
+
+(defmethod make-qualified-name ((schema protobuf-schema) name)
+ ;; If we're at the parent, the qualified name is the schema's
+ ;; packaged "dot" the name
+ (strcat (proto-package schema) "." name))
+
(defgeneric find-enum (protobuf type)
(:documentation
"Given a Protobufs schema or message and the name of an enum type,
:accessor proto-message-type
:initarg :message-type
:initform :message))
- (:documentation
+ (:documentation
"The model class that represents a Protobufs message."))
(defmethod make-load-form ((m protobuf-message) &optional environment)
(eq (proto-message-type m) :group)
(eq (proto-message-type m) :extends))))
+(defmethod proto-package ((message protobuf-message))
+ (and (proto-parent message)
+ (proto-package (proto-parent message))))
+
+(defmethod proto-lisp-package ((message protobuf-message))
+ (and (proto-parent message)
+ (proto-lisp-package (proto-parent message))))
+
+(defmethod make-qualified-name ((message protobuf-message) name)
+ ;; If there's a parent for this message (there should be -- the schema),
+ ;; make a partially qualified name of message name "dot" name, then
+ ;; ask the parent to add its own qualifiers
+ (if (proto-parent message)
+ (make-qualified-name (proto-parent message) (strcat (proto-name message) "." name))
+ (strcat (proto-name message) "." name)))
+
(defmethod find-message ((message protobuf-message) (type symbol))
;; Extended messages "shadow" non-extended ones
(or (find type (proto-extenders message) :key #'proto-class)
(maybe-skip-comments stream)))
(enum (make-instance 'protobuf-enum
:class (proto->class-name name *protobuf-package*)
- :name name)))
+ :name name
+ :qualified-name (make-qualified-name protobuf name))))
(loop
(let ((name (parse-token stream)))
(when (null name)
(class (proto->class-name name *protobuf-package*))
(message (make-instance 'protobuf-message
:class class
- :name name
+ :name name
+ :qualified-name (make-qualified-name protobuf name)
:parent protobuf
;; Maybe force accessors for all slots
:conc-name (conc-name-for-type class *protobuf-conc-name*)))
(message (find-message protobuf name))
(extends (and message
(make-instance 'protobuf-message
- :class (proto->class-name name *protobuf-package*)
- :name name
+ :class (proto->class-name name *protobuf-package*)
+ :name name
+ :qualified-name (make-qualified-name protobuf name)
:parent (proto-parent message)
:conc-name (proto-conc-name message)
:alias-for (proto-alias-for message)
:name name
:type type
:class class
+ :qualified-name (make-qualified-name message name)
;; One of :required, :optional or :repeated
:required reqd
:index idx
:name name
:type type
:class class
+ :qualified-name (make-qualified-name message name)
:required (kintern required)
:index idx
:value slot
(maybe-skip-comments stream)))
(service (make-instance 'protobuf-service
:class (proto->class-name name *protobuf-package*)
- :name name))
+ :name name
+ :qualified-name (make-qualified-name *protobuf* name)))
(index 0))
(loop
(let ((token (parse-token stream)))
(method (make-instance 'protobuf-method
:class stub
:name name
+ :qualified-name (make-qualified-name *protobuf* name)
:input-type (proto->class-name in *protobuf-package*)
:input-name in
:output-type (proto->class-name out *protobuf-package*)