(defun dojo-js-api-process-extracted-class (class) (let* ((resource-id (dojo-class-resource-id class))) (if (null resource-id) (log-js-api (format "[WARNING] Did not find a resource-id for class [%s]; will not be able to load the corresponding api.xml." (dojo-class-id class))) (log-js-api (format "Will load api.xml for project of resource-id [%s]" resource-id)) (dojo-core-load-load-api-by-resource resource-id))) (let* ((api-class (dojo-js-api-get-or-create-api-class class)) (api-this-symbol (dojo-class-this-symbol api-class)) (api-static-symbol (dojo-class-static-symbol api-class)) (this-symbol (dojo-class-this-symbol class)) (static-symbol (dojo-class-static-symbol class)) (api-this-members (dojo-symbol-get-object-members api-this-symbol)) (api-static-members (dojo-symbol-get-object-members api-static-symbol)) (this-members (dojo-symbol-get-object-members this-symbol)) (static-members (dojo-symbol-get-object-members static-symbol)) (api-this-to-delete ()) (api-static-to-delete ()) (api-symbols-afterwards (make-hash-table :test 'equal)) (class-id (dojo-class-id class)) (project (dojo-class-project class)) (path-key (dojo-core-workspace-get-path-key class)) (id-to-api-class (dojo-workspace-id-to-api-class dojo-current-workspace)) (path-key-to-id-to-api-class (dojo-workspace-path-key-to-id-to-api-class dojo-current-workspace)) (id-to-api-class-for-path-key (gethash path-key path-key-to-id-to-api-class)) (dirty-api-path-keys (dojo-workspace-dirty-api-path-keys dojo-current-workspace))) ; Delete all members from api-this-symbol and api-static-symbol, which are not ; present in the given class. Reason: We only want to recognize members of the ; public API here, and those members are supposed to be found while extracting ; the class. (maphash (lambda (name symbol) (if (not (gethash name this-members)) (push name api-this-to-delete))) api-this-members) (dolist (member-to-delete api-this-to-delete) (log-js-api (format "Deleting member [%s] from api-this-members since it is not present in class." member-to-delete)) (remhash member-to-delete api-this-members)) (maphash (lambda (name symbol) (if (not (gethash name static-members)) (push name api-static-to-delete))) api-static-members) (dolist (member-to-delete api-static-to-delete) (log-js-api (format "Deleting member [%s] from api-static-members since it is not present in class." member-to-delete)) (remhash member-to-delete api-static-members)) ; Merge / clone class symbols towards api-class. (maphash (lambda (name this-member) (if (dojo-core-util-is-function-symbol this-member) (let ((api-this-member (gethash name api-this-members))) (if api-this-member (puthash name (dojo-js-api-merge-api-symbol api-class api-this-member this-member nil nil) api-this-members) (puthash name (dojo-js-api-clone-api-symbol api-class this-member) api-this-members))))) this-members) (maphash (lambda (name static-member) (let ((api-static-member (gethash name api-static-members))) (log-assign 1 (format "Processing static member [%s]: %s" name (dojo-core-util-symbol-to-short-string api-static-member))) (if api-static-member (puthash name (dojo-js-api-merge-api-symbol api-class api-static-member static-member nil nil) api-static-members) (puthash name (dojo-js-api-clone-api-symbol api-class static-member) api-static-members)))) static-members) (let* ((api-mixin-symbol (gethash "mixin" api-static-members)) (mixin-symbol (gethash "mixin" static-members))) (log-assign 0 (format "process-extracted-class: api-mixin: %s" (dojo-core-util-symbol-to-short-string api-mixin-symbol))) (log-assign 0 (format "process-extracted-class: mixin: %s" (dojo-core-util-symbol-to-short-string mixin-symbol)))) ; Get rid of no longer referenced symbols in api-class. (dojo-core-util-extract-symbol-to-map class-id api-this-symbol api-symbols-afterwards nil) (dojo-core-util-extract-symbol-to-map class-id api-static-symbol api-symbols-afterwards nil) (let* ((api-id-to-symbol (dojo-class-id-to-symbol api-class)) (api-symbol-ids-to-delete ())) (maphash (lambda (id symbol) (if (not (gethash id api-symbols-afterwards)) (push id api-symbol-ids-to-delete))) api-id-to-symbol) (dolist (api-symbol-id-to-delete api-symbol-ids-to-delete) (remhash api-symbol-id-to-delete api-id-to-symbol))) (if (null id-to-api-class-for-path-key) (setq id-to-api-class-for-path-key (make-hash-table :test 'equal))) ; In some cases, e.g. when processing the statement '1 && lang.mixin(dojo, lang);' at the end of dojo/_base/lang.js, ; the parent-id of a class member points to an unexpected destination. ; That destination is not wrong (*), but unwanted. ; Here, we fix this by always ensuring that the this-symbol and static-symbol has the class-id as parent, and the ; members of this-symbol and static-symbol have this/static-symbol as parent. ; Those two cases are sufficient for e.g. properly detecting lang.mixin when processing code. ; ; (*) Object members may be members of multiple objects, and we have just one parent id, thus the last ; register-object-member call for a particular member decides where parent-id points to. ; TODO: Maybe, we can get rid of setting parent-id in extraction code anyway, and just set it here. (dojo-core-util-fix-parent-references api-class) (log-js-api (format "Storing api-class [%s:%s:%s] under path-key [%s] and class-id [%s]" (dojo-class-id api-class) (dojo-class-project api-class) (dojo-class-path api-class) path-key class-id)) (puthash class-id api-class id-to-api-class-for-path-key) (puthash path-key id-to-api-class-for-path-key path-key-to-id-to-api-class) (puthash path-key t dirty-api-path-keys))) (defun dojo-js-api-register-api-class (api-class) (if (not (dojo-class-is-api-class api-class)) (error (format "[ERROR] Attempt to register non-api class [%s:%s:%s:%s] in dojo-workspace-id-to-api-class" (dojo-class-id api-class) (dojo-class-project api-class) (dojo-class-path api-class) (dojo-class-is-api-class api-class)))) (puthash (dojo-class-id api-class) api-class (dojo-workspace-id-to-api-class dojo-current-workspace))) (defun dojo-js-api-get-api-class-by-resource (resource &optional class) (dojo-core-load-load-api-by-resource (dojo-resource-id resource)) (let* ((class-id (dojo-resource-parsed-id resource)) (id-to-api-class (dojo-workspace-id-to-api-class dojo-current-workspace)) (api-class (if (null class-id) nil (gethash class-id id-to-api-class)))) api-class)) (defun dojo-js-api-get-or-create-api-class (class) (log-js-api (format "Called get-or-create-api-class for class with id [%s], project [%s], path [%s]" (dojo-class-id class) (dojo-class-project class) (dojo-class-path class))) (log-assign 0 (format "Called get-or-create-api-class for class with id [%s], project [%s], path [%s]" (dojo-class-id class) (dojo-class-project class) (dojo-class-path class))) (let* ((class-id (dojo-class-id class)) (id-to-api-class (dojo-workspace-id-to-api-class dojo-current-workspace)) (api-class (gethash class-id id-to-api-class))) (if (null api-class) (progn (setq api-class (dojo-class--create)) (setf (dojo-class-is-api-class api-class) t) (setf (dojo-class-id api-class) class-id) (setf (dojo-class-project api-class) (dojo-class-project class)) (setf (dojo-class-path api-class) (dojo-class-path class)) (setf (dojo-class-resource-id api-class) (dojo-class-resource-id class)) (dojo-class-set-this-symbol api-class (construct-dojo-symbol-api dojo-current-workspace api-class "this" 'DOJO-JSTYPE-OBJECT)) (dojo-class-set-static-symbol api-class (construct-dojo-symbol-api dojo-current-workspace api-class nil 'DOJO-JSTYPE-OBJECT)) (dojo-js-api-register-api-class api-class) api-class) api-class))) (defun dojo-js-api-get-or-create-api-class-by-resource (resource-id) (let* ((id-to-resource (dojo-workspace-id-to-resource dojo-current-workspace)) (resource (gethash resource-id id-to-resource)) (class-id (if resource (dojo-resource-parsed-id resource) nil)) (id-to-api-class (dojo-workspace-id-to-api-class dojo-current-workspace)) (api-class (if (null class-id) nil (gethash class-id id-to-api-class)))) (log-js-api (format "get-or-create-api-class-by-resource for resource [%s %s] found api-class [%s]" resource-id (if resource (dojo-resource-path resource) "---") (if api-class (dojo-class-id api-class) "---"))) (if (null api-class) (if (null resource) (progn (log-js-api (format "[WARNING] Did not find a resource for resource-id [%s], cannot create an api-class based on that." resource-id)) nil) (progn (if (null class-id) (progn (setq api-class (construct-dojo-api-class dojo-current-workspace resource-id (dojo-resource-project resource) (dojo-resource-path resource))) ; TODO: resource state handling? (setf (dojo-resource-parsed-id resource) (dojo-class-id api-class))) (setq api-class (dojo-class--create)) (setf (dojo-class-is-api-class api-class) t) (setf (dojo-class-id api-class) class-id) (setf (dojo-class-project api-class) (dojo-resource-project resource)) (setf (dojo-class-path api-class) (dojo-resource-path resource)) (setf (dojo-class-resource-id api-class) resource-id)) (dojo-class-set-this-symbol api-class (construct-dojo-symbol-api dojo-current-workspace api-class "this" 'DOJO-JSTYPE-OBJECT)) (dojo-class-set-static-symbol api-class (construct-dojo-symbol-api dojo-current-workspace api-class nil 'DOJO-JSTYPE-OBJECT)) (log-js-api (format "Registering new api-class with id [%s], project [%s] and path [%s]; resource-project is [%s]" (dojo-class-id api-class) (dojo-class-project api-class) (dojo-class-path api-class) (dojo-resource-project resource))) (dojo-js-api-register-api-class api-class) (let* ((path-key-to-id-to-api-class (dojo-workspace-path-key-to-id-to-api-class dojo-current-workspace)) (project (dojo-resource-project resource)) (path-key (dojo-core-workspace-get-path-key resource)) (id-to-api-class-for-path-key (gethash path-key path-key-to-id-to-api-class)) (dirty-api-path-keys (dojo-workspace-dirty-api-path-keys dojo-current-workspace))) (if (null id-to-api-class-for-path-key) (setq id-to-api-class-for-path-key (make-hash-table :test 'equal))) (puthash (dojo-class-id api-class) api-class id-to-api-class-for-path-key) (puthash path-key id-to-api-class-for-path-key path-key-to-id-to-api-class) (puthash path-key t dirty-api-path-keys)) api-class)) api-class))) ; (setf (dojo-class-scan-id api-class) (dojo-class-scan-id class)) ; (setf (dojo-class-superclass-paths api-class) (dojo-class-superclass-paths class)) ; api-class)) (defun dojo-js-api-clone-api-symbol (api-class symbol &optional id-to-cloned-symbol) (if (or (null symbol) (not (dojo-symbol-p symbol))) symbol (if (null id-to-cloned-symbol) (setq id-to-cloned-symbol (make-hash-table :test 'equal))) (let* ((id (dojo-symbol-id symbol)) (already-cloned-symbol (gethash id id-to-cloned-symbol))) (if already-cloned-symbol already-cloned-symbol (let* ((name (dojo-symbol-name symbol)) (value (dojo-symbol-value symbol)) (scan-id (dojo-symbol-scan-id symbol)) (min-pos (dojo-symbol-min-pos symbol)) (max-pos (dojo-symbol-max-pos symbol)) (cloned-symbol (construct-dojo-symbol dojo-current-workspace api-class name))) (setf (dojo-symbol-value cloned-symbol) value) (setf (dojo-symbol-is-api-symbol cloned-symbol) (dojo-class-is-api-class api-class)) (setf (dojo-symbol-scan-id cloned-symbol) scan-id) (setf (dojo-symbol-min-pos cloned-symbol) min-pos) (setf (dojo-symbol-max-pos cloned-symbol) max-pos) (puthash id cloned-symbol id-to-cloned-symbol) (dojo-js-api-clone-additional-attributes api-class symbol cloned-symbol id-to-cloned-symbol) cloned-symbol))))) (defun dojo-js-api-clone-additional-attributes (api-class source-symbol dest-symbol id-to-cloned-symbol) (let ((type (dojo-symbol-type source-symbol))) (dojo-symbol-set-type dest-symbol type) (cond ((eq type 'DOJO-JSTYPE-ARRAY) (setf (dojo-array-value-type (dojo-symbol-details dest-symbol)) (dojo-js-api-clone-api-symbol api-class (dojo-array-value-type (dojo-symbol-details source-symbol)) id-to-cloned-symbol))) ((or (eq type 'DOJO-JSTYPE-ARRAY-OR-OBJECT) (eq type 'DOJO-JSTYPE-OBJECT)) (setf (dojo-object-key-type (dojo-symbol-details dest-symbol)) (dojo-js-api-clone-api-symbol api-class (dojo-object-key-type (dojo-symbol-details source-symbol)) id-to-cloned-symbol)) (setf (dojo-object-value-type (dojo-symbol-details dest-symbol)) (dojo-js-api-clone-api-symbol api-class (dojo-object-value-type (dojo-symbol-details source-symbol)) id-to-cloned-symbol)) (setf (dojo-object-function-symbol (dojo-symbol-details dest-symbol)) (dojo-js-api-clone-api-symbol api-class (dojo-object-function-symbol (dojo-symbol-details source-symbol)) id-to-cloned-symbol)) (setf (dojo-object-object-type (dojo-symbol-details dest-symbol)) (dojo-object-object-type (dojo-symbol-details source-symbol))) (setf (dojo-object-object-info (dojo-symbol-details dest-symbol)) (dojo-object-object-info (dojo-symbol-details source-symbol))) (let* ((name-to-symbol (dojo-symbol-get-object-members source-symbol))) (maphash (lambda (name symbol) (dojo-symbol-register-object-member name (dojo-js-api-clone-api-symbol api-class symbol id-to-cloned-symbol) dest-symbol)) name-to-symbol))) ((eq type 'DOJO-JSTYPE-FUNCTION) (let ((arguments (dojo-symbol-get-function-arguments source-symbol)) (new-arguments ())) (dolist (argument arguments) (push (dojo-js-api-clone-api-symbol api-class argument id-to-cloned-symbol) new-arguments)) (dojo-symbol-set-function-arguments dest-symbol (nreverse new-arguments))) (setf (dojo-function-return-type (dojo-symbol-details dest-symbol)) (dojo-js-api-clone-api-symbol api-class (dojo-function-return-type (dojo-symbol-details source-symbol)) id-to-cloned-symbol)) (setf (dojo-function-builtin-fct (dojo-symbol-details dest-symbol)) (dojo-js-api-clone-api-symbol api-class (dojo-function-builtin-fct (dojo-symbol-details source-symbol)) id-to-cloned-symbol))) ((or (eq type 'DOJO-JSTYPE-IMPORT) (eq type 'DOJO-JSTYPE-INSTANCE)) (setf (dojo-import-resource-id (dojo-symbol-details dest-symbol)) (dojo-import-resource-id (dojo-symbol-details source-symbol))) (setf (dojo-import-type (dojo-symbol-details dest-symbol)) (dojo-import-type (dojo-symbol-details source-symbol))) (setf (dojo-import-path (dojo-symbol-details dest-symbol)) (dojo-import-path (dojo-symbol-details source-symbol)))) ((eq type 'DOJO-JSTYPE-REF) (setf (dojo-ref-type (dojo-symbol-details dest-symbol)) (dojo-ref-type (dojo-symbol-details source-symbol))) (let ((ref-symbols (dojo-symbol-get-ref-symbols source-symbol)) (new-ref-symbols ())) (dolist (ref-symbol ref-symbols) (push (dojo-js-api-clone-api-symbol api-class ref-symbol id-to-cloned-symbol) new-ref-symbols)) (dojo-symbol-set-ref-symbols dest-symbol (nreverse new-ref-symbols)))) (t ())))) (defun dojo-js-api-merge-clone-api-symbol (api-class symbol cloned-id-to-symbol) "Calls dojo-js-api-clone-api-symbol on the given symbol if necessary. I.e., if the symbol is present in the given cloned-id-to-symbol map, return it from there, otherwise actually call dojo-js-api-clone-api-symbol and register the cloned symbol in the cloned-id-to-symbol map. The keys of the map are ids in the id space of symbol, whereas the values are cloned symbols as returned by dojo-js-api-clone-api-symbol. See also documentation of dojo-js-api-merge-api-symbol for why we need this." (log-js-api (format "Called merge-clone-api-symbol for symbol %s" (dojo-core-util-symbol-to-short-string symbol))) (if (or (null symbol) (not (dojo-symbol-p symbol))) symbol (let* ((id (dojo-symbol-id symbol)) (already-cloned-symbol (gethash id cloned-id-to-symbol))) (if already-cloned-symbol (progn (log-js-api (format "... already cloned the symbol with id [%s], returning %s" id (dojo-core-util-symbol-to-short-string already-cloned-symbol))) already-cloned-symbol) (let* ((cloned-symbol (dojo-js-api-clone-api-symbol api-class symbol cloned-id-to-symbol))) (puthash id cloned-symbol cloned-id-to-symbol) (log-js-api (format "... cloned symbol, registering it under id [%s]: %s" id (dojo-core-util-symbol-to-short-string cloned-symbol))) cloned-symbol))))) (defun dojo-js-api-merge-api-symbol (api-class api-symbol symbol &optional api-symbols-win omit-additional-object-members cloned-id-to-symbol) "Merges the given symbol into the given api-symbol (to be exactly, merging symbol into api-symbol is the typical usecase, but the caller may decide to call the function with any kind of symbols). The goal is to keep the api-symbol, and update its content with the content of the given symbol. E.g., when merging object symbols, the goal is that the api-symbol lateron contains the members of both api-symbol and symbol. In general, symbols that are present in both api-symbol and symbol are merged using this function, symbols that need to be added to api-symbol newly (like object members not present so far) will be cloned using dojo-js-api-clone-api-symbol. Cloned symbols will be created in the given api-class, and registered in the given cloned-id-to-symbol map. The latter is to avoid cloning the same symbol twice, but reusing it. The map should in generally not be passed by external callers, it will silently be created and passed to recursive calls of this function if it isn't set when the function is called. The keys of the map are ids in the id space of symbol, whereas the values of the map are the newly created symbols in api-class. Note that api-symbol and symbol in generally live in completely different id spaces, i.e. symbols are matched by names, positions in argument lists, etc., but *not* by id. By default, if the information found in api-symbol and symbol conflicts, the information in symbol wins since the idea is that a just parsed symbol is merged into a long-living api-symbol, i.e. the former has the newer information. This e.g. applies when a function argument that used to be of type string suddendly is an object - then we want to overwrite the information 'string' in the api-class by the newer information 'object' in the just parsed class. This behaviour can be inverted by setting the flag api-symbols-win --- if this flag is set, in case of conflicts the information in the api-symbol is kept. If the flag omit-additional-object-members is set, and an object symbol is merged into an object api-symbol, members only present in symbol are not added to api-symbol. This flag is not passed recursively, and its sense is to properly treat the case that a member of a dojo-class was deleted. Then we don't want to keep the deleted member by means of merging, but simply forget about it." (log-js-api (format "Merging api-symbol %s with symbol %s" (dojo-core-util-symbol-to-short-string api-symbol) (dojo-core-util-symbol-to-short-string symbol))) (if (null cloned-id-to-symbol) (setq cloned-id-to-symbol (make-hash-table :test 'equal))) (cond ((null api-symbol) (cond ((null symbol) nil) (t (dojo-js-api-clone-api-symbol api-class symbol cloned-id-to-symbol)))) (t (cond ((null symbol) api-symbol) (t (dojo-js-api-merge-non-nil-api-symbol api-class api-symbol symbol api-symbols-win omit-additional-object-members cloned-id-to-symbol)))))) ; TODO: REF instances don't form a tree, but reuse function arguments and other symbols. ; Store the cloned instances, and reuse them whenever possible. (defun dojo-js-api-merge-non-nil-api-symbol (api-class api-symbol symbol api-symbols-win omit-additional-object-members cloned-id-to-symbol) ; TODO Completely support changing the api-symbol inline. (let* ((api-type (dojo-symbol-type api-symbol)) (type (dojo-symbol-type symbol)) (api-name (dojo-symbol-name api-symbol)) (name (dojo-symbol-name symbol)) (value (dojo-symbol-value symbol)) (api-min-pos (dojo-symbol-min-pos api-symbol)) (min-pos (dojo-symbol-min-pos symbol)) (api-max-pos (dojo-symbol-max-pos api-symbol)) (max-pos (dojo-symbol-max-pos symbol)) (array-or-object-found (or (eq api-type 'DOJO-JSTYPE-ARRAY-OR-OBJECT) (eq type 'DOJO-JSTYPE-ARRAY-OR-OBJECT))) (array-found (or (eq api-type 'DOJO-JSTYPE-ARRAY) (eq type 'DOJO-JSTYPE-ARRAY))) (object-found (or (eq api-type 'DOJO-JSTYPE-OBJECT) (eq type 'DOJO-JSTYPE-OBJECT))) (result nil)) ; Avoid endless recursion; if we find a symbol for the second time, ; we already processed it (setting its contents etc.), thus then ; the api-symbol simply wins. (if (gethash (dojo-symbol-id symbol) cloned-id-to-symbol) api-symbol (puthash (dojo-symbol-id symbol) api-symbol cloned-id-to-symbol) (cond ((and array-or-object-found array-found) (log-js-api (format "... Found both ARRAY-OR-OBJECT and ARRAY, will unify types to ARRAY before proceeding.")) (setq api-type 'DOJO-JSTYPE-ARRAY) (setq type 'DOJO-JSTYPE-ARRAY)) ((and array-or-object-found object-found) (log-js-api (format "... Found both ARRAY-OR-OBJECT and OBJECT, will unify types to OBJECT before proceeding.")) (setq api-type 'DOJO-JSTYPE-OBJECT) (setq type 'DOJO-JSTYPE-OBJECT))) (cond ((or (null api-type) (null type) (not (eq api-type type))) (if (and api-symbols-win (not (null api-type))) (log-js-api (format "... Types are nil or differ, however api-symbols-win is set; thus will do nothing.")) (log-js-api (format "... Types are nil or differ; will overwrite api-type with type.")) (let* ((id (dojo-symbol-id symbol)) (type (dojo-symbol-type symbol)) (name (dojo-symbol-name symbol)) (scan-id (dojo-symbol-scan-id symbol)) (min-pos (dojo-symbol-min-pos symbol)) (max-pos (dojo-symbol-max-pos symbol)) (id-to-cloned-symbol (make-hash-table :test 'equal))) (dojo-symbol-set-type api-symbol type nil nil) (setf (dojo-symbol-scan-id api-symbol) scan-id) ; (setf (dojo-symbol-min-pos api-symbol) min-pos) ; (setf (dojo-symbol-max-pos api-symbol) max-pos) ; Should at least in most cases not be possible, but if someone manages to set up a circular ; relationship it might be helpful. (puthash id api-symbol id-to-cloned-symbol) (dojo-js-api-clone-additional-attributes api-class symbol api-symbol id-to-cloned-symbol))) (setq result api-symbol)) ; At this point, api-type and type are equal, and we can proceed with a type distinction based on that type ((eq api-type 'DOJO-JSTYPE-OBJECT) (log-js-api (format "... types equal: [%s]" api-type)) (let* ((api-key-type (dojo-symbol-get-object-key-type api-symbol)) (key-type (dojo-symbol-get-object-key-type symbol)) (api-value-type (dojo-symbol-get-object-value-type api-symbol)) (value-type (dojo-symbol-get-object-value-type symbol)) (api-name-to-symbol (dojo-symbol-get-object-members api-symbol)) (name-to-symbol (dojo-symbol-get-object-members symbol))) ; Merge key-type and value-type (dojo-symbol-set-object-key-type api-symbol (dojo-js-api-merge-api-symbol api-class api-key-type key-type api-symbols-win nil cloned-id-to-symbol)) (dojo-symbol-set-object-value-type api-symbol (dojo-js-api-merge-api-symbol api-class api-value-type value-type api-symbols-win nil cloned-id-to-symbol)) (if (not api-symbols-win) (progn (dojo-symbol-set-object-object-type api-symbol (dojo-symbol-get-object-object-type symbol)) (dojo-symbol-set-object-object-info api-symbol (dojo-symbol-get-object-object-info symbol)))) ; Merge members in api-symbol with members in symbol. ; I.e., if a member with some particular name is present in both symbols, merge the member symbols. ; If a member is only present in symbol, add a cloned copy of it to the api-symbol. (maphash (lambda (name symbol) (let* ((api-symbol (gethash name api-name-to-symbol))) (if api-symbol (puthash name (dojo-js-api-merge-api-symbol api-class api-symbol symbol api-symbols-win nil cloned-id-to-symbol) api-name-to-symbol) ; When merging api-this-symbol into this-symbol (or -static-), in order to enrich the types ; derived from parsing a class with the types already known in the API class, don't keep symbols ; present in api-this-symbol (or api-static-symbol), but not in this-symbol or static-symbol. ; Reason: We expect that we find all member functions etc. while parsing a class, though ; without types already known. Thus, when a member function is present in API, but not in class, ; this most probably means that it simply was deleted. (if (not omit-additional-object-members) (puthash name (dojo-js-api-clone-api-symbol api-class symbol cloned-id-to-symbol) api-name-to-symbol))))) name-to-symbol) (dojo-symbol-set-object-members api-symbol api-name-to-symbol)) (setq result api-symbol)) ((eq api-type 'DOJO-JSTYPE-FUNCTION) (let* ((api-named-arguments (dojo-core-util-has-named-argument api-symbol)) (named-arguments (dojo-core-util-has-named-argument symbol)) (api-arguments (dojo-symbol-get-function-arguments api-symbol)) (arguments (dojo-symbol-get-function-arguments symbol)) (api-return-type (dojo-symbol-get-function-return-type api-symbol)) (return-type (dojo-symbol-get-function-return-type symbol)) (new-api-arguments ())) (cond (named-arguments (cond (api-named-arguments (let ((old-api-name-to-argument (dojo-core-util-get-named-argument-map api-symbol))) (dolist (argument arguments) (let ((old-api-argument (gethash (dojo-symbol-name argument) old-api-name-to-argument))) (if old-api-argument (push (dojo-js-api-merge-api-symbol api-class old-api-argument argument api-symbols-win nil cloned-id-to-symbol) new-api-arguments) (push (dojo-js-api-clone-api-symbol api-class argument cloned-id-to-symbol) new-api-arguments)))))) (t (dotimes (n (length arguments)) (let* ((argument (nth n arguments)) (api-argument (nth n api-arguments))) (if api-argument (let ((new-api-argument (dojo-js-api-merge-api-symbol api-class api-argument argument api-symbols-win nil cloned-id-to-symbol))) (setf (dojo-symbol-name new-api-argument) (dojo-symbol-name argument)) (push new-api-argument new-api-arguments)) (push (dojo-js-api-clone-api-symbol api-class argument cloned-id-to-symbol) new-api-arguments))))))) (t (cond (api-named-arguments (dotimes (n (length api-arguments)) (let* ((argument (nth n arguments)) (api-argument (nth n api-arguments))) (if argument (let ((merged-api-argument (dojo-js-api-merge-api-symbol api-class api-argument argument api-symbols-win nil cloned-id-to-symbol))) (push merged-api-argument new-api-arguments)) (log-js-api (format "[WARNING] Found more positional arguments in symbol %s than named arguments in api-symbol %s; this is strange." (dojo-core-util-symbol-to-short-string symbol) (dojo-core-util-symbol-to-short-string api-symbol))))))) (t (dotimes (n (max (length arguments) (length api-arguments))) (let* ((argument (nth n arguments)) (api-argument (nth n api-arguments))) (cond ((null api-argument) (push (dojo-js-api-clone-api-symbol api-class argument cloned-id-to-symbol) new-api-arguments)) ((null argument) (push (dojo-js-api-clone-api-symbol api-class api-argument cloned-id-to-symbol) new-api-arguments)) (t (push (dojo-js-api-merge-api-symbol api-class api-argument argument api-symbols-win nil cloned-id-to-symbol) new-api-arguments))))))))) (dojo-symbol-set-function-arguments api-symbol (nreverse new-api-arguments)) (dojo-symbol-set-function-return-type api-symbol (dojo-js-api-merge-api-symbol api-class api-return-type return-type api-symbols-win nil cloned-id-to-symbol)) (setq result api-symbol))) ((or (eq type 'DOJO-JSTYPE-INSTANCE) (eq type 'DOJO-JSTYPE-IMPORT)) (if (not api-symbols-win) (progn (dojo-symbol-set-import-resource-id api-symbol (dojo-symbol-get-import-resource-id symbol)) (dojo-symbol-set-import-type api-symbol (dojo-symbol-get-import-type symbol)) (dojo-symbol-set-import-path api-symbol (dojo-symbol-get-import-path symbol)))) (setq result api-symbol)) ((eq type 'DOJO-JSTYPE-REF) (if (not api-symbols-win) (progn (dojo-symbol-set-ref-type api-symbol (dojo-symbol-get-ref-type symbol)) (let* ((new-ref-symbols ()) (api-ref-symbols (dojo-symbol-get-ref-symbols api-symbol)) (ref-symbols (dojo-symbol-get-ref-symbols symbol)) (ref-index 0)) (dolist (ref-symbol ref-symbols) (let* ((api-ref-symbol (nth ref-index api-ref-symbols))) (if (and api-ref-symbol (dojo-symbol-p api-ref-symbol) (dojo-symbol-p ref-symbol)) (push (dojo-js-api-merge-api-symbol api-class api-ref-symbol ref-symbol api-symbols-win nil cloned-id-to-symbol) new-ref-symbols) (push (dojo-js-api-clone-api-symbol api-class ref-symbol cloned-id-to-symbol) new-ref-symbols)) (incf ref-index))) (dojo-symbol-set-ref-symbols api-symbol (nreverse new-ref-symbols))))) (setq result api-symbol)) ; The above cases should handle all non-primitive types where merging actually involves merging attributes, return types, ; object members, and so on. ; Here, we expect that both symbols have the same, primitive type. Thus just take the api-symbol. (t (setq result api-symbol))) ; If name is set, use it as name of the merged symbol. (if (not (null name)) (setf (dojo-symbol-name result) name)) (if (and (not api-symbols-win) (not (null min-pos))) (setf (dojo-symbol-min-pos result) min-pos)) (if (and (not api-symbols-win) (not (null max-pos))) (setf (dojo-symbol-max-pos result) max-pos)) (if (string= (dojo-symbol-value result) "Organisation") (log-i18n (format "merge-api-symbol: Setting value of symbol %s, formerly 'Organisation', to [%s]" (dojo-core-util-symbol-to-short-string result) value))) (setf (dojo-symbol-value result) value) (log-js-api (format "Finished merging api-symbol %s with symbol %s" (dojo-core-util-symbol-to-short-string api-symbol) (dojo-core-util-symbol-to-short-string symbol))) (log-js-api (format "... result is %s" (dojo-core-util-symbol-to-short-string result))) result))) (defun dojo-js-api-get-class-by-import-symbol (import-symbol) (let* ((import-resource-id (dojo-symbol-get-import-resource-id import-symbol))) (log-dep (format "About to fetch api-class for import-resource-id [%s]" import-resource-id)) (if (null import-resource-id) nil (dojo-core-load-load-api-by-resource import-resource-id) (dojo-js-api-get-or-create-api-class-by-resource import-resource-id)))) (defun dojo-js-api-get-class-by-resource-id (resource-id) (dojo-core-load-load-api-by-resource resource-id) (let* ((id-to-resource (dojo-workspace-id-to-resource dojo-current-workspace)) (resource (gethash resource-id id-to-resource)) (class-id (if resource (dojo-resource-parsed-id resource) nil)) (id-to-api-class (dojo-workspace-id-to-api-class dojo-current-workspace)) (api-class (if (null class-id) nil (gethash class-id id-to-api-class)))) api-class)) (defun dojo-js-api-get-class-by-id (class-id) (let* ((id-to-api-class (dojo-workspace-id-to-api-class dojo-current-workspace)) (api-class (if (null class-id) nil (gethash class-id id-to-api-class)))) api-class)) (provide 'dojo-js-api)