(require 'dojo-common-containers) (defun dojo-js-extract-loop-extract-as () (interactive) (dotimes (n 1000) (log-extract (format "Extracting #%s" n)) (dojo-extract-get-ast-from-js2))) (defun dojo-do-extract-js (workspace resource catch-errors &optional notify) (let* ((resource-id (dojo-resource-id resource)) (project (dojo-resource-project resource)) (path (dojo-resource-path resource)) (file-path (dojo-resource-file-path resource)) (current-buffer-resource (dojo-core-workspace-get-or-create-resource (current-buffer)))) (if (and file-path (file-readable-p file-path)) (if (and current-buffer-resource (eq (dojo-resource-id current-buffer-resource) (dojo-resource-id resource))) (dojo-js-extract-extract-from-current-buffer workspace resource catch-errors) (with-temp-buffer (buffer-disable-undo (current-buffer)) (insert-file-contents file-path) ; Don't do anything, if the file wasn't modified since the last parse. (if (dojo-core-util-resource-modified-since-last-parse-p resource) (progn (if notify (message (format "Need to extract resource [%s:%s:%s] first, this will take a moment..." resource-id project path))) (log-workspace (format "[EXTRACT] Will extract resource [%s:%s:%s]" resource-id project path)) (dojo-js-extract-extract-from-current-buffer workspace resource catch-errors) (if notify (message (format "Successfully extracted resource [%s:%s:%s]." resource-id project path))) (log-workspace (format "... Done."))) (log-extract-prio (format "... Will not do that since the file is unchaned since last extraction.")) (log-workspace-details (format "[EXTRACT] Will not extract resource [%s:%s:%s] since the file is unchanged since last extraction." resource-id project path))))) (log-workspace (format "[WARNING] dojo-do-extract-js does not find a file-path for resource-id [%s], project [%s] and path [%s]" (dojo-resource-id resource) project path))))) (defun dojo-js-extract-extract-from-current-buffer (workspace resource catch-errors &optional given-ast) (let ((ast nil) (class nil)) (if given-ast (setq ast given-ast) (let* ((before-time (float-time))) (setq ast (dojo-extract-get-ast-from-js2)) (setf (dojo-resource-last-ast-time resource) (- (float-time) before-time)))) (cond ((null ast) (log-user (format "[FAILURE] Failure to extract AST for %s:%s" (dojo-resource-project resource) (dojo-resource-path resource)))) (; Abort here, if we just extracted the AST, and ran out of time / were interrupted by user input. ; In that case, we store AST and resource, and proceed as soon as we can do so in the workspace main loop. (and (not given-ast) (dojo-core-workspace-check-for-input)) (setf (dojo-workspace-curr-parse-ast workspace) ast) (setf (dojo-workspace-curr-parse-resource workspace) resource) (log-workloop (format "...... [BREAK] Making a break after AST extraction of resource [%s:%s:%s]" (dojo-resource-id resource) (dojo-resource-project resource) (dojo-resource-path resource))) (log-workspace (format "[ BREAK ] Making a break after AST extraction of %s:%s" (dojo-resource-project resource) (dojo-resource-path resource))) (log-extract-prio (format "[BREAK] Making a break after AST extraction of %s:%s" (dojo-resource-project resource) (dojo-resource-path resource)))) (t (let* ((before-time (float-time)) (size (buffer-size (current-buffer))) (parse-time nil) (ast-time (dojo-resource-last-ast-time resource)) (total-extract-time (dojo-workspace-total-js-extract-time dojo-current-workspace)) (total-extract-size (dojo-workspace-total-js-extract-size dojo-current-workspace)) (total-extract-count (dojo-workspace-total-js-extract-count dojo-current-workspace))) (setq class (dojo-extract-class-from-ast workspace ast resource catch-errors)) (setq parse-time (- (float-time) before-time)) (if class (progn (setf (dojo-resource-last-parse-time resource) parse-time) (if (not (null ast-time)) (progn (log-workloop (format "total-extract-time before: [%s], ast-time %s, parse-time %s" total-extract-time ast-time parse-time)) (setf total-extract-time (+ total-extract-time ast-time parse-time)) (setf total-extract-size (+ total-extract-size size)) (incf total-extract-count) (setf (dojo-workspace-total-js-extract-time workspace) total-extract-time) (setf (dojo-workspace-total-js-extract-size workspace) total-extract-size) (setf (dojo-workspace-total-js-extract-count workspace) total-extract-count) (log-workloop (format "Parsed resource [%s:%s:%s], total-extract-time now [%s], -size now [%s], -count now [%s]" (dojo-resource-id resource) (dojo-resource-project resource) (dojo-resource-path resource) total-extract-time total-extract-size total-extract-count)))))) (setf (dojo-resource-last-parsed-utc-seconds resource) (float-time)) (setf (dojo-resource-last-parsed-size resource) size)) (setf (dojo-resource-parsed-id resource) (if (dojo-class-p class) (dojo-class-id class) nil)) (setf (dojo-resource-state resource) (if (null class) "parse-failed" "parsed")) ; (setf (dojo-resource-file-hash resource) (secure-hash 'md5 (current-buffer))) (log-extract-prio (format "[SUCCESS] Extracted class [%s:%s:%s]" (if class (dojo-class-id class) "---") (if class (dojo-class-project class) "---") (if class (dojo-class-path class) "---"))) ; Register that class needs to be saved at some time in the future (if class (progn (dojo-core-util-mark-class-needed class) (let ((resource-projects-to-save (dojo-workspace-resource-projects-to-save workspace)) (project (dojo-resource-project resource))) (dojo-core-save-register-class-for-save workspace class) ; Mark the project, such that the resources.xml will be saved lateron. (puthash project t resource-projects-to-save)))))))) ; TODO: Remove xml for class if class is nil here (i.e. class could not be extracted for some reason)? (defun dojo-extract-class-from-ast (workspace ast resource catch-errors) "Extracts and returns a dojo-class for the given AST. Returns nil, if the given AST is nil. Otherwise, the class handling described for dojo-js-extract-do-extract-class-from-ast applies." (log-user (format "[EXTRACT] Extracting class [%s:%s:%s]..." (if resource (dojo-resource-id resource) "---") (if resource (dojo-resource-project resource) "---") (if resource (dojo-resource-path resource) "---"))) (log-workspace (format "[EXTRACT] Extracting class [%s:%s:%s]..." (if resource (dojo-resource-id resource) "---") (if resource (dojo-resource-project resource) "---") (if resource (dojo-resource-path resource) "---"))) (log-extract (format "Called dojo-extract-class-from-ast for prio [%s]" (dojo-workspace-curr-priority workspace))) (let* (; Setting the signal-hook-function here to log the stacktrace to a separate ; buffer seems to occasionally cause emacs to segfault. ; Maybe the cause is the (already fixed) bug ; https://lists.nongnu.org/archive/html/bug-gnu-emacs/2018-02/msg00574.html ;(signal-hook-function 'dojo-extract-signal-hook-function) (scan (construct-dojo-scan workspace)) (old-state (dojo-resource-state resource)) (class (dojo-core-util-get-or-load-class workspace resource)) (class-previously-known class) (project (dojo-resource-project resource)) (path (dojo-resource-path resource))) (log-extract (format "Calling dojo-extract-class-from-ast for path [%s]" path)) ; (log-extract (format "Calling dojo-extract-class-from-ast for path [%s], curr-prio [%s]" path (dojo-workspace-curr-priority dojo-current-workspace))) ; Try to reuse an existing dojo-class, if possible. If not, create a new one here. ; (if (not (dojo-class-p class)) ; (progn ; (setq class (dojo-core-workspace-get-or-create-class resource workspace project path)))) ; (log-extract (format "id-to-class now: %s" (dojo-workspace-id-to-class dojo-current-workspace))))) ; CATCH-ERRORS set to nil for debug purposes. ; (setq catch-errors nil) (if catch-errors (condition-case err (progn (setq class (dojo-js-extract-do-extract-class-from-ast resource scan class ast))) (error (log-workspace (format "... [FAILURE] Failure to extract resource %s:%s" project path)) (log-user (format "... [FAILURE] Failure to extract resource %s:%s" project path)) (log-extract-summary 0 (format "[FAILURE] Failure to extract %s:%s" project path)) (log-extract-summary 1 (format "... Error is: [%s]" err)) ; Minor syntax errors seem to be able to make class extraction fail. In such cases, ; dropping the dojo-class instance doesn't make sense - one better continues ; working with what was previously known. ; Only, if the class was not parsed successfully before at all (which especially can ; mean that we just parse it for the very first time), we drop it and mark the ; resource as parse-failed here. (if (not class-previously-known) (progn (if scan (remhash (dojo-scan-id scan) (dojo-workspace-id-to-scan workspace))) (if class (remhash (dojo-class-id class) (dojo-workspace-id-to-class workspace))) (setf (dojo-workspace-curr-scan-id dojo-current-workspace) nil) (setq class nil) (setf (dojo-resource-state resource) "parse-failed"))) nil)) (setq class (dojo-js-extract-do-extract-class-from-ast resource scan class ast))) class)) (defun dojo-js-extract-do-extract-class-from-ast (resource scan class ast) "Extracts the given class from the given AST. Expects that AST to be non-nil. If the given class is nil, a new dojo-class is constructed, filled, and returned. If, however, the given class is non-nil, a new transient dojo-class (not stored in the workspace maps) is created and filled. Then, at the end of this function, in case of successful extraction, its content will be merged into the given class. The most simple case of 'merging' is overwriting the contents of the old class completely, but more sophisticated schemes of overwriting are possible and allowed. Note that inter-class relationships (e.g. a symbol copied to some other symbol) do *not* work by reference, i.e. simply replacing the class is possible without damaging references. However, we do need to take care about symbol-ids referenced in dojo-assignments, the is subject for a more sophisticated merge code as mentioned above." (log-extract (format "Called dojo-js-extract-do-extract-class-from-ast for prio [%s]" (dojo-workspace-curr-priority dojo-current-workspace))) ; ast available, extract symbol information (setf (dojo-scan-start-utcseconds scan) (float-time)) (setf (dojo-workspace-curr-scan-id dojo-current-workspace) (dojo-scan-id scan)) (if (not (string= (js2-node-short-name ast) "js2-ast-root")) ; ast here is supposed to be the js2-ast-root node. If this is not true, just print a warn message. (progn (log-extract (format "WARNING: dojo-extract-class-from-ast cannot analyze ast, as it doesn't start at the js2-ast-root node, found: %s" (js2-node-short-name ast))) nil) (setf (dojo-workspace-dirty-symbol-ids dojo-current-workspace) (make-hash-table :test 'equal)) (let* ((resource-id (dojo-resource-id resource)) (resource-type (dojo-resource-type resource)) (project (dojo-resource-project resource)) (path (dojo-resource-path resource)) ; (class-id (if class (dojo-class-id class) nil)) (class-id (dojo-resource-parsed-id resource)) ; If the class was already parsed in the past, ; reuse its id, otherwise construct a completely new class. (new-class (if (null class-id) (construct-dojo-class dojo-current-workspace resource-id project path) (construct-transient-dojo-class dojo-current-workspace class-id resource-id project path))) (id-to-class (dojo-workspace-id-to-class dojo-current-workspace))) ; If the class wasn't parsed before, we just constructed it newly, and thus ; need to update the class-id variable. (if (null class-id) (setq class-id (dojo-class-id new-class))) (puthash class-id new-class id-to-class) ; (let* ((api-class (dojo-js-api-get-api-class-by-resource resource))) ; (if api-class ; ; If an API class already exists, it might contain information about member function parameters ; ; and similar things. In some cases, such information is useful while performing the extraction. ; ; E.g., when interpreting a 'lang.mixin(this, params)' call, one can add the right members to the ; ; this-symbol, when one already knows what the params object contains. ; ; NOTE however, that this only works when one especially cares about that case, as most of the ; ; dojo-js-assign-process-foo methods are designed to set up completely new symbols, instead of ; ; adding information to already existing symbols. ; (let* ((api-this-symbol (dojo-class-this-symbol api-class)) ; (api-static-symbol (dojo-class-static-symbol api-class))) ; (dojo-class-set-this-symbol new-class (dojo-js-api-clone-api-symbol new-class api-this-symbol)) ; (dojo-class-set-static-symbol new-class (dojo-js-api-clone-api-symbol new-class api-static-symbol))) ; (dojo-class-set-this-symbol new-class (construct-dojo-symbol dojo-current-workspace new-class "this" 'DOJO-JSTYPE-OBJECT)) ; (dojo-class-set-static-symbol new-class (construct-dojo-symbol dojo-current-workspace new-class nil 'DOJO-JSTYPE-OBJECT)))) (dojo-class-set-this-symbol new-class (construct-dojo-symbol dojo-current-workspace new-class "this" 'DOJO-JSTYPE-OBJECT)) (dojo-class-set-static-symbol new-class (construct-dojo-symbol dojo-current-workspace new-class nil 'DOJO-JSTYPE-OBJECT)) (setf (dojo-class-scan-id new-class) (dojo-scan-id scan)) (setf (dojo-scan-class-id scan) (dojo-class-id new-class)) (dolist (kid (js2-ast-root-kids ast)) (if (not (string= (js2-node-short-name kid) "js2-expr-stmt-node")) ; Seems that we get one js2-expr-stmt-node below root, that contains everything we ; are interested in. Ignore all other nodes, but report about them. (log-extract (format "[WARNING] Ignoring %s node below root, will only consider js2-expr-stmt-node" (js2-node-short-name kid))) (cond ((dojo-core-workspace-is-js-module-resource resource) (dojo-extract-class-process-top-level-stmt kid new-class)) ((dojo-core-workspace-is-js-main-i18n-resource resource) (dojo-js-i18n-extract-process-main-top-level-stmt-node kid new-class)) ((dojo-core-workspace-is-js-other-i18n-resource resource) (dojo-js-i18n-extract-process-other-top-level-stmt-node kid new-class)) (t (log-extract (format "[WARNING] Will not extract class [%s:%s:%s] as we are not interested in its type." (dojo-class-id new-class) (dojo-class-project new-class) (dojo-class-path new-class))))))) ; Don't consider old api state in case of i18n symbols; they can be ; easily extracted from the corresponding module file, no need to ; deal with incomplete information derived when parsing other classes. (if (string= resource-type "js") (let* ((api-class (dojo-js-api-get-or-create-api-class new-class))) (if api-class (let* ((api-this-symbol (dojo-class-this-symbol api-class)) (api-static-symbol (dojo-class-static-symbol api-class)) (this-symbol (dojo-class-this-symbol new-class)) (static-symbol (dojo-class-static-symbol new-class))) (log-assign 0 (format "Merging api-this-symbol and api-static-symbol into this-symbol and static-symbol.")) (log-assign 0 (format "... Reason: Have the types only known in API, before propagating types below.")) (dojo-js-api-merge-api-symbol new-class this-symbol api-this-symbol t t) (dojo-js-api-merge-api-symbol new-class static-symbol api-static-symbol t t))))) (dojo-js-assign-propagate-types-along-assignments new-class) (dojo-js-api-process-extracted-class new-class) (dojo-core-util-mark-class-needed new-class) ; Extract annotations, e.g. something like '////css-prefix = organisationPersonEdit' ; defining which prefix for css rules to use in js code generation. (dojo-js-extract-extract-annotations new-class ast) (let* ((project (dojo-resource-project resource)) (path (dojo-resource-path resource)) (this-symbol (dojo-class-this-symbol new-class)) (static-symbol (dojo-class-static-symbol new-class)) (this-symbol-symbol-count (if this-symbol (length (hash-table-get-all-keys (dojo-symbol-get-object-members this-symbol))) -1)) (static-symbol-symbol-count (if static-symbol (length (hash-table-get-all-keys (dojo-symbol-get-object-members static-symbol))) -1))) (log-user (format "... [SUCCESS] Extracted %s:%s (found [%s] this-symbols and [%s] static-symbols)" project path this-symbol-symbol-count static-symbol-symbol-count)) (log-extract (format "[SUCCESS] Extracted %s:%s (found [%s] this-symbols and [%s] static-symbols)" project path this-symbol-symbol-count static-symbol-symbol-count)) (log-extract (format "... this-symbol: %s" (dojo-core-util-symbol-to-short-string this-symbol))) (log-extract (format "... static-symbol: %s" (dojo-core-util-symbol-to-short-string static-symbol))) (log-extract-summary 0 (format "[SUCCESS] Extracted %s:%s (found [%s] this-symbols and [%s] static-symbols)" project path this-symbol-symbol-count static-symbol-symbol-count))) (setf (dojo-scan-end-utcseconds scan) (float-time)) (setf (dojo-scan-length scan) (- (dojo-scan-end-utcseconds scan) (dojo-scan-start-utcseconds scan))) new-class))) (defun dojo-js-extract-extract-own-class-manually (resource) "Test function to debug separate calls to that function." (interactive) (setf (dojo-workspace-curr-priority dojo-current-workspace) 1) (dojo-extract-own-class-from-ast dojo-current-workspace resource nil) (dojo-core-save-save-touched-classes dojo-current-workspace t) (let* ((resource-projects-to-save (dojo-workspace-resource-projects-to-save dojo-current-workspace)) (project-and-path (dojo-get-project-and-path buffer-file-name)) (project (nth 0 project-and-path))) (puthash project t resource-projects-to-save) (dojo-core-save-save-resource-files dojo-current-workspace)) (setf (dojo-workspace-curr-priority dojo-current-workspace) nil)) (defun dojo-js-extract-extract-own-class (resource) "Test function to debug separate calls to that function." (interactive) (log-assign 0 ( format "Before dojo-js-extract-own-class-from-ast ......... MEMORY: %s" (dojo-common-log-get-memory-info))) (log-workspace ( format "Before dojo-js-extract-own-class-from-ast ......... MEMORY: %s" (dojo-common-log-get-memory-info))) (unwind-protect (progn (setf (dojo-workspace-curr-priority dojo-current-workspace) 1) (dojo-extract-own-class-from-ast dojo-current-workspace resource nil) (dojo-core-save-save-touched-classes dojo-current-workspace t) (let* ((resource-projects-to-save (dojo-workspace-resource-projects-to-save dojo-current-workspace)) (project-and-path (dojo-get-project-and-path buffer-file-name)) (project (nth 0 project-and-path))) (puthash project t resource-projects-to-save) (dojo-core-save-save-resource-files dojo-current-workspace))) (progn (log-assign 0 (format "[WARNING] Parse failed.")) (setf (dojo-workspace-curr-priority dojo-current-workspace) nil))) (log-assign 0 ( format " After dojo-js-extract-own-class-from-ast ......... MEMORY: %s" (dojo-common-log-get-memory-info))) (log-workspace ( format " After dojo-js-extract-own-class-from-ast ......... MEMORY: %s" (dojo-common-log-get-memory-info)))) (defun dojo-js-extract-extract-own-class-with-dependencies () "Extract the own class, and all classes referenced (superclasses, imports)." (interactive) (save-excursion (progn (dojo-common-log-split-and-show-user-log-buffer) (setf (dojo-workspace-curr-priority dojo-current-workspace) 1) (dojo-extract-own-class-from-ast dojo-current-workspace (dojo-core-util-get-current-resource) nil) (log-user "Extracted own class") (let* ((id-to-resource (dojo-workspace-id-to-resource dojo-current-workspace)) (resource-projects-to-save (dojo-workspace-resource-projects-to-save dojo-current-workspace)) (own-resource (dojo-core-util-get-current-resource)) (own-project (dojo-resource-project own-resource)) (own-class (dojo-core-util-get-or-load-class dojo-current-workspace own-resource)) (superclass-paths (dojo-class-superclass-paths own-class)) (import-to-symbol (dojo-class-import-to-symbol own-class)) (extract-resources ())) (dolist (superclass-path superclass-paths) (let* ((superclass-resource (dojo-core-util-get-resource-by-path dojo-current-workspace superclass-path)) (superclass-project (dojo-resource-project superclass-resource))) (push superclass-resource extract-resources))) (maphash (lambda (import symbol) (let* ((import-type (dojo-symbol-get-import-type symbol))) (if (or (eq import-type 'DOJO-IMPORT-CLASS) (eq import-type 'DOJO-IMPORT-I18N)) (let* ((import-resource-id (dojo-symbol-get-import-resource-id symbol)) (import-resource (if (null import-resource-id) nil (gethash import-resource-id id-to-resource))) (import-project (if (null import-resource) nil (dojo-resource-project import-resource)))) (log-workspace-details (format "import [%s], symbol [%s], import-resource-id [%s], import-resource [%s]" import (dojo-core-util-symbol-to-short-string symbol) import-resource-id (dojo-core-util-resource-to-string import-resource))) (if (null import-resource) (log-workspace-details (format "[WARNING] Did not find import-resource [%s] with id [%s]" (dojo-core-util-resource-to-string import-resource) import-resource-id)) (push import-resource extract-resources)))))) import-to-symbol) (dolist (extract-resource (nreverse extract-resources)) (with-temp-buffer (let* ((file-path (dojo-resource-file-path extract-resource))) (log-user (format "Processing [%s]..." file-path)) (buffer-disable-undo (current-buffer)) (insert-file-contents file-path) ; Don't do anything, if the file wasn't modified since the last parse. (if (dojo-core-util-resource-modified-since-last-parse-p extract-resource) (progn ; (dojo-extract-own-class-from-ast dojo-current-workspace nil) (dojo-js-extract-extract-from-current-buffer dojo-current-workspace extract-resource nil (dojo-extract-get-ast-from-js2)) (puthash (dojo-resource-project extract-resource) t resource-projects-to-save) (log-user "...... done.")) (log-user (format "... ignored as it is unchanged." file-path)))))) (log-user "Extracted all referenced classes, finished.") (dojo-core-save-save-touched-classes dojo-current-workspace t) (log-user "Saved touched classes.") (dojo-core-save-save-resource-files dojo-current-workspace) (log-user "Saved touched resource files. Finished with all.")))) (setf (dojo-workspace-curr-priority dojo-current-workspace) nil)) (defun dojo-extract-own-class-from-ast (workspace resource catch-errors) (log-extract "Starting dojo-extract-own-class-from-ast") ; Record start time if not yet done. (if (null dojo-process-workspace-start-time) (setq dojo-process-workspace-start-time (float-time)) ) ; TODO: Try to avoid extracting the class to often, maybe even create ; the AST more seldom. See dojo-resource-file-hash. (let* ((project-and-path (dojo-get-project-and-path buffer-file-name)) (project (nth 0 project-and-path)) (path (nth 1 project-and-path)) (type (nth 2 project-and-path)) ; If we seem to deal with js code, create resource if necessary (usually ; this should not be the case thanks to our previous workspace scan), ; and fetch it. (resource (if (and buffer-file-name (string/ends-with buffer-file-name ".js")) (dojo-workspace-get-or-create-resource dojo-current-workspace project path type buffer-file-name) nil)) ; Extract a dojo-class from the js2-mode-ast. We assume that it matches ; the current file (which, hopefully, is how js2-mode behaves). ; However, it might not be created at this point, i.e. class may be nil ; afterwards. (class (if (or (null resource) (null project) (null path) (null js2-mode-ast)) nil ; ; There still seem to be some points in code, where we erronesously refer ; ; to the current buffer (something like buffer-substring). ; ; This works when using dojo-js-extract-extract-own-class, but fails ; ; once this code is executed as background job from the workspace loop. ; ; Thus, proceed with an empty buffer. (let ((ast js2-mode-ast)) (buffer-disable-undo (current-buffer)) (dojo-extract-class-from-ast workspace ast resource catch-errors))))) (log-extract (format "dojo-extract-own-class-from-ast finds: buffer-file-name = [%s], class = [%s], resource = [%s]" buffer-file-name (not (null class)) (not (null resource)))) ; If both class and resource exist, link them, and update the resource state accordingly. (if (and class resource) (progn (setf (dojo-resource-parsed-id resource) (dojo-class-id class)) (setf (dojo-resource-state resource) "parsed") (setf (dojo-resource-last-parsed-utc-seconds resource) (float-time)) (setf (dojo-resource-last-parsed-size resource) (buffer-size (current-buffer))) ; Register that class needs to be saved at some time in the future (log-extract (format "Registering class [%s] with path [%s] for save." (dojo-class-id class) (dojo-class-path class))) (dojo-core-save-register-class-for-save dojo-current-workspace class) ; Extraction was successful, we don't want to perform it again too soon. (setf (dojo-workspace-last-extract-own-utcseconds dojo-current-workspace) (float-time)) ; Now, we want to have a look on the referenced classes. Parse and extract their content ; if needed. (setf (dojo-workspace-referenced-extraction-pending dojo-current-workspace) t) (log-extract (format "Successfully parsed own file project [%s], path [%s]" project path)) ) ; Otherwise, reset last-extract-own-utcseconds (since the current buffer / file apparently ; isn't subject to extraction (setf (dojo-workspace-last-extract-own-utcseconds dojo-current-workspace) nil) ) ; Regardless of the question wether we succeded to extract our own class, we don't want to try/perform it again too soon. ; Especially, if we are not inside a js file, then here we can't do anything. But we need to avoid trying to perform it ; again in the very next millisecond, since this would cost a serious amount of CPU time. ; Thus, the usual way to re-perform extraction of the own class is the time check at the beginning of dojo-process-workspace. (setf (dojo-workspace-own-class-extraction-pending dojo-current-workspace) nil) ) (not (dojo-workspace-stop-processing-p)) ) (defun dojo-schedule-extract-referenced-classes (workspace) (let* ((path-to-resources (dojo-workspace-path-to-resources workspace)) (file-path-to-path-info (dojo-workspace-file-path-to-path-info workspace)) (project-and-path (if buffer-file-name (gethash buffer-file-name file-path-to-path-info) nil)) (project (nth 0 project-and-path)) (path (nth 1 project-and-path)) (resources (if path (gethash path path-to-resources) nil)) (resource (if (and resources project) (dojo-workspace-get-resource-from-resources resources project) nil)) (do-continue t) ) (cond ((null resource) (log-extract (format "Found no resource for buffer-file-name [%s]; project-and-path is %s" buffer-file-name project-and-path))) ((not (dojo-core-workspace-is-js-module-resource resource)) (log-extract (format "Ignoring resource [%s] in project [%s] since it does not have type [js]" path project))) ((string= (dojo-resource-state resource) "located") (log-extract (format "Scheduling own resource [%s] in project [%s] for parsing." path project)) (setf (dojo-workspace-own-class-extraction-pending workspace) t)) (t (setq do-continue (dojo-do-schedule-extract-referenced-classes workspace resource)))) (setf (dojo-workspace-last-extract-referenced-utcseconds workspace) (float-time)) (setf (dojo-workspace-referenced-extraction-pending workspace) nil) do-continue)) (defun dojo-do-schedule-extract-referenced-classes (workspace resource) (let* ((project (dojo-resource-project resource)) (path (dojo-resource-path resource)) (class (dojo-core-util-get-or-load-class workspace resource)) (import-to-symbol (dojo-class-import-to-symbol class)) (import-symbol-names (hash-table-get-all-keys import-to-symbol)) (pending-extractions (dojo-workspace-pending-extractions workspace)) ) (if (null dojo-process-workspace-start-time) (setq dojo-process-workspace-start-time (float-time))) (dolist (import-symbol-name import-symbol-names) (let* ((import-symbol (gethash import-symbol-name import-to-symbol)) (import-path (dojo-symbol-get-import-path import-symbol)) (import-resource-id (dojo-symbol-get-import-resource-id import-symbol)) ) (log-extract (format "Registering path [%s] for extraction." import-path)) (puthash import-path t pending-extractions))) (not (dojo-workspace-stop-processing-p)))) (defun dojo-extract-get-ast-from-js2 () (log-workspace-details ( format " Will extract AST ................................. MEMORY: %s" (dojo-common-log-get-memory-info))) ; (if (null dojo-test-ast) (if t (let* ((ast nil)) (unwind-protect (progn ; Prevent interruption of js2-parse in case of user input. Interruption would make ; our code more complicate, and hopefully, our machines are fast enough to tolerate ; finishing the parse work in case of user input. ; If this becomes a problem nevertheless, we would need to catch the signal, and ; continue. (setq js2-parse-interruptable-p nil) (setq ast (js2-parse))) ; But get back to the default behaviour, since js2-mode generates the js2-mode-ast by default ; quite often, and not interrupting might disturb the user. (setq js2-parse-interruptable-p t)) (log-workspace-details ( format " Finished extracting AST .......................... MEMORY: %s" (dojo-common-log-get-memory-info))) ; (setq dojo-test-ast ast) ast) dojo-test-ast)) (defun dojo-js-extract-extract-annotations (class ast) (let* ((annotations ())) (dolist (comment (js2-ast-root-comments ast)) (cond ((not (null (string-match "^[[:space:]]*////[[:space:]]*[[:graph:]]+[[:space:]]*=[[:space:]]*[[:graph:]]+[[:space:]]*$" (js2-node-string comment)))) (let* ((comment-string (dojo-common-strings-trim (js2-node-string comment))) (string-without-marker (dojo-common-strings-trim (substring comment-string 4))) (separator-pos (string-match "=" string-without-marker)) (key (dojo-common-strings-trim (substring string-without-marker 0 separator-pos))) (value (dojo-common-strings-trim (substring string-without-marker (1+ separator-pos)))) (annotation (construct-dojo-annotation (if (and key (> (length key) 0)) key nil) (if (and value (> (length value) 0)) value nil) (js2-node-abs-pos comment) (js2-node-abs-end comment)))) (push annotation annotations))) ((not (null (string-match "^[[:space:]]*////[[:space:]]*[[:graph:]]+[[:space:]]*" (js2-node-string comment)))) (let* ((comment-string (dojo-common-strings-trim (js2-node-string comment))) (value (dojo-common-strings-trim (substring comment-string 4))) (annotation (construct-dojo-annotation nil value (js2-node-abs-pos comment) (js2-node-abs-end comment)))) (push annotation annotations))))) (setf annotations (sort annotations (lambda (annotation-one annotation-two) (- (dojo-annotation-min-pos annotation-two) (dojo-annotation-min-pos annotation-one))))) (setf (dojo-class-annotations class) annotations))) (defun dojo-extract-signal-hook-function (signal-name signal-data) (let* ((curr-backtrace (with-temp-buffer (buffer-disable-undo (current-buffer)) (let ((standard-output (current-buffer))) (backtrace) (buffer-string)))) (curr-backtrace-limited (if (<= (length curr-backtrace) 10000) curr-backtrace (substring curr-backtrace 0 10000)))) (log-trace "===========================================================================") (log-trace "===========================================================================") (log-trace (format "%s" curr-backtrace-limited))) ()) (defun dojo-extract-class-process-top-level-stmt (stmt-node class) (let* ((kid (js2-expr-stmt-node-expr stmt-node))) (if (string= (js2-node-short-name kid) "js2-call-node") (let ((fct-name-node (js2-call-node-target kid))) (if (and (dojo-has-node-type fct-name-node "js2-name-node") (string= (dojo-get-name-from-name-node fct-name-node) "define")) ; Have a look at the js2-call-node (dojo-extract-class-process-define-node kid class)))))) (defun dojo-extract-class-process-define-node (call-node class) (let* ((name-node (js2-call-node-target call-node)) (fct-name (dojo-get-name-from-name-node name-node)) (arg-nodes (js2-call-node-args call-node)) (first-arg-node (nth 0 arg-nodes)) (second-arg-node (nth 1 arg-nodes)) (third-arg-node (nth 2 arg-nodes)) (param-array-node nil) (param-fct-node nil) ) (if (string= fct-name "define") (progn (log-assign 0 (format "Processing define call.")) ; See https://github.com/amdjs/amdjs-api/blob/master/AMD.md for documentation of the define parameters. (cond ; Three arguments means that both id, dependency array, and factory are given. ((>= (length arg-nodes) 3) (log-assign 0 (format "... detected case 'three parameters'")) (setq param-array-node second-arg-node) (setq param-fct-node third-arg-node)) ; Two arguments means that the first argument is either the id, or the dependency ; array (after all, both are optional), and the third argument is the factory. ((= (length arg-nodes) 2) (log-assign 0 (format "... detected case 'two parameters'")) (if (string= (js2-node-short-name first-arg-node) "js2-array-node") (progn (setq param-array-node first-arg-node) (setq param-fct-node second-arg-node)) (progn (setq param-array-node nil) (setq param-fct-node second-arg-node)))) ; One argument means that only the factory is given. ((= (length arg-nodes) 1) (log-assign 0 (format "... detected case 'one parameter'")) (setq param-array-node nil) (setq param-fct-node first-arg-node)) ; No parameter means that the module we currently inspect looks quite strange; ; probably there is something wrong with it. (t (log-assign 0 (format "[WARNING] No define call parameters found.")) (setq param-array-node nil) (setq param-fct-node nil))) (cond ((null param-fct-node) (log-assign 0 (format (concat "[WARNING] Cannot find the factory parameter of the define call, please check your module, " "and read https://github.com/amdjs/amdjs-api/blob/master/AMD.md")))) ((dojo-has-node-type param-fct-node "js2-function-node") (log-assign 0 (format "... will process case 'function', i.e. will process a class")) (dojo-extract-process-define-class-params param-array-node param-fct-node class)) ; If the define call parameter is an object, then we assume that we are just parsing a i18n file. ; TODO: If other files also end up with an object here, we need to detect this case in a more ; sophisticated way (e.g. using the directory / file names). ((dojo-has-node-type param-fct-node "js2-object-node") ; main i18n file (log-assign 0 (format "... will process case 'object', i.e. will process an i18n file")) (dojo-extract-process-define-i18n-params param-fct-node class)) ((dojo-has-node-type param-fct-node "js2-paren-node") ; other language i18n files (log-assign 0 (format "... will process case 'object', i.e. will process an i18n file")) (dojo-extract-process-define-other-i18n-params param-fct-node class)) (t (log-assign 0 (format "[WARNING] Unsupported case of param-fct-node: [%s]" (js2-node-short-name param-fct-node))))))))) (defun dojo-extract-process-define-class-params (array-node fct-node class) (let* ((array-members (if array-node (js2-array-node-elems array-node) nil)) ; (ftype (js2-function-node-ftype fct-node)) ; (form (js2-function-node-form fct-node)) ; (name (js2-function-node-name fct-node)) (params (js2-function-node-params fct-node)) (body-node (js2-function-node-body fct-node)) (import-index 0) (import-symbols nil)) (dolist (array-member-node array-members) (let* ((raw-path (dojo-get-string-from-string-node array-member-node)) (param-node (nth import-index params))) (log-dep (format "Processing raw-path [%s]" raw-path)) (if (null param-node) ; Array members in first define parameters, and function parameters in second define parameter don't match (log-extract (format "[WARNING] No corresponding function parameter to array member %s" raw-path)) ; Otherwise, proceed. (let* ((param (dojo-get-name-from-name-node param-node)) (symbol-arguments nil) (type 'DOJO-IMPORT-CLASS) (path nil)) (if (or (null raw-path) (null param)) ; Assure that we actually have the strings (log-extract (format "[WARNING] Raw path [%s] or parameter %s in define statement is nil" raw-path param)) ; First treat i18n imports properly. (let* ((i18n-prefix "dojo/i18n!/") (text-prefix "dojo/text!")) (cond ((starts-with raw-path i18n-prefix) (setq path (substring raw-path (length i18n-prefix) (- (length raw-path) (length ".js")))) (setq type 'DOJO-IMPORT-I18N)) ((starts-with raw-path text-prefix) (cond ((string/ends-with raw-path "?smd") (setq path (substring raw-path (length text-prefix) (- (length raw-path) (length "?smd")))) (setq type 'DOJO-IMPORT-SMD)) (t (setq path (substring raw-path (length text-prefix) (length raw-path))) (setq type 'DOJO-IMPORT-TEXT)))) (t (setq path (dojo-js-extract-normalize-import-path (dojo-class-path class) raw-path)) (setq type 'DOJO-IMPORT-CLASS))) (let* ((path-to-resources (dojo-workspace-path-to-resources dojo-current-workspace)) (resources (gethash path path-to-resources)) (chosen-resource (nth 0 resources)) ; TODO: Try to choose a specific resource, if there are multiple (chosen-resource-id (if chosen-resource (dojo-resource-id chosen-resource) nil)) (symbol (construct-dojo-symbol-import dojo-current-workspace class param chosen-resource-id type path)) (import-to-symbol (dojo-class-import-to-symbol class))) (log-workspace-details (format "Extracting import: Mapping path [%s] to param [%s], found chosen-resource-id [%s]" path param chosen-resource-id)) (puthash param symbol import-to-symbol) (if (and (string= param "exports") (null (dojo-class-static-symbol class))) (progn (log-extract (format "Setting static-symbol, since 'exports' import was found.")) (dojo-class-set-static-symbol class (construct-dojo-symbol-object dojo-current-workspace class nil)))) (log-dep (format "Registering symbol [%s] as import-symbol." (dojo-core-util-symbol-to-short-string symbol))) (push symbol import-symbols) ; Register dependencies to imported classes (let* ((api-class (dojo-js-api-get-class-by-import-symbol symbol))) (log-dep (format "Calling register-dependency-by-classes for class [%s:%s] and api-class [%s:%s]" (if class (dojo-class-id class) "---") (if class (dojo-class-path class) "---") (if api-class (dojo-class-id api-class) "---") (if api-class (dojo-class-path api-class) "---"))) (cond ((null class) (log-dep (format "[WARNING] Trying to call register-dependency-by-classes for null class"))) ((null api-class) (log-dep (format "[WARNING] Trying to call register-dependency-by-classes for null api-class"))) (t (let* ((anything-new-registered (dojo-core-dep-register-dependency-by-classes class api-class 'DOJO-DEP-IMPORT class))) (if anything-new-registered (progn (if (not (dojo-workspace-plan-extract-pending dojo-current-workspace)) (log-workspace (format (concat "[TRIGGER-PLAN-EXTRACT] Triggered planning the extraction of dependent resources, " "since processing import [%s] changed dependency information.") path))) (dojo-core-workspace-trigger-plan-extractions)))))))))))) (setq import-index (1+ import-index)))) (if (not (string= (js2-node-short-name body-node) "js2-block-node")) ; Expect a js2-block-node representing the body of the function passed as second argument to the define function (log-extract (format "[WARNING] Body of define parameter function is not a js2-block-node, found %s, will ignore it." (js2-node-short-name body-node))) ; Else proceed (dojo-extract-class-process-define-body body-node (nreverse import-symbols) class)))) (defun dojo-js-extract-normalize-import-path (base-path import-path) "Given a base path, and an import path, this function returns a normalized variant of the import-path, where special path tokens like './' or '..' where resolved, with the base-path as base." (let* ((normalized-path import-path) (base-path-without-class (dojo-common-strings-get-without-last-token base-path "/"))) (if (starts-with import-path "./") (setq normalized-path (concat base-path-without-class "/" (substring import-path 2)))) ; TODO: Support ".." (log-extract (format "Normalized import-path [%s] with base-path [%s] as base, the result is [%s]" import-path base-path normalized-path)) normalized-path)) (defun dojo-extract-class-process-define-body (body-node import-symbols class) "Processes the body (the js2-block-node) of a define statement. Registers the declared variables, and especially scans the declare block for its definitions." ; At this point, dojo-class-import-to-symbol already contains the import-symbols (log-extract (format "Called dojo-extract-class-process-define-body, with %s class [%s]" (if (dojo-class-transient class) "transient" "non-transient") (if (dojo-class-p class) (dojo-class-id class) "---"))) (let* ((block-children (js2-block-node-kids body-node)) (builtin-scope (dojo-js-scopes-construct-builtin-scope 0)) (import-scope (dojo-construct-import-scope 1 class)) (define-scope (construct-dojo-scope dojo-current-workspace 2 "dojo-extract-class-process-define-body")) (scopes (list builtin-scope import-scope define-scope))) (dolist (block-child block-children) (cond ((dojo-has-node-type block-child "js2-expr-stmt-node") (log-extract (format "------ Inspecting block-child of type [%s]" (js2-node-short-name block-child))) (let* ((statement-child-node (js2-expr-stmt-node-expr block-child))) (cond ((dojo-has-node-type statement-child-node "js2-var-decl-node") (dojo-js-extract-process-define-var-decl statement-child-node define-scope scopes class)) (t (log-extract (format "--------- Processing statement-child-node of type [%s], see assign log" (js2-node-short-name statement-child-node))) (dojo-js-assign-process-statement-node scopes class 1 statement-child-node))))) ((dojo-has-node-type block-child "js2-function-node") (let* ((function-symbol (dojo-js-assign-process-dojo-function-node scopes class 1 block-child nil)) (function-name (dojo-symbol-name function-symbol))) (log-extract (format "------ Extracted function [%s]" (dojo-core-util-symbol-to-short-string function-symbol))) (if function-name (dojo-core-util-register-in-scope define-scope function-name function-symbol)))) ((dojo-has-node-type block-child "js2-return-node") (let* ((retval-node (if block-child (js2-return-node-retval block-child) nil)) (ret-symbol (cond ((null retval-node) nil) ((dojo-js2-node-is-function-call retval-node "declare") (log-extract (format "---------------- About to process declare call")) (let ((new-scopes (append (list (dojo-construct-block-scope block-children block-child 0 class)) scopes)) (static-declare-symbol (construct-dojo-symbol dojo-current-workspace class nil 'DOJO-JSTYPE-OBJECT))) (dojo-process-declare-call new-scopes retval-node class) ; (dojo-core-util-register-in-scope define-scope nil static-declare-symbol) static-declare-symbol)) (t (dojo-js-assign-process-statement-node scopes class 1 retval-node))))) (log-extract (format "--- Processing return-node for ret-symbol %s" (dojo-core-util-symbol-to-short-string ret-symbol))) (if (null ret-symbol) (log-extract (format "[WARNING] Could not determine a ret-symbol for return call inside define body. Most probably, the class will remain empty.")) ; If we return a function with name constructor (see comment in function dojo-js-assign-process-assign-node), ; we regard that function as the constructor-function of the class that was created by assigning that function ; above. Sample code snippet: var AdapterRegistry = dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){ (cond ((null (dojo-symbol-type ret-symbol)) (dojo-symbol-set-type ret-symbol 'DOJO-JSTYPE-OBJECT) (log-extract (format "------ Ret-symbol didn't have any type, set it to OBJECT. static-symbol of constructed class is empty.")) (dojo-class-set-static-symbol class ret-symbol)) ; ((and (dojo-core-util-is-function-symbol ret-symbol) (string= (dojo-symbol-name ret-symbol) "constructor")) ((and (dojo-core-util-is-function-symbol ret-symbol)) (let* ((this-symbol nil) (retvar-name (if (and retval-node (dojo-has-node-type retval-node "js2-name-node")) (dojo-get-name-from-name-node retval-node) nil)) (static-symbol (construct-dojo-symbol-object dojo-current-workspace class retvar-name)) ; TODO: Is retvar-name correct? (constructor-scope (dojo-symbol-get-function-scope ret-symbol)) (constructor-scope-name-to-symbol (dojo-scope-name-to-symbol constructor-scope)) (constructor-scope-this-symbol (gethash "this" constructor-scope-name-to-symbol))) (log-extract (format "------ Registering constructor ret-symbol %s in this-symbol %s" (dojo-core-util-symbol-to-short-string ret-symbol) (dojo-core-util-symbol-to-short-string this-symbol))) ; The definition of the constructor function in the style mentioned above can contain ; assignments to the this-pointer; as at that point no this-symbol is known yet, they ; get stored in a symbol with name "this" in local function scope. ; In that case, here we make that this-symbol the this-symbol of the dojo-class (this ; in particular keeps all members already set up there), remove it from local function ; scope. ; Otherwise, we simply set up a new this-symbol here. (if constructor-scope-this-symbol (progn (setq this-symbol constructor-scope-this-symbol) (remhash "this" constructor-scope-name-to-symbol)) (setq this-symbol (construct-dojo-symbol-object dojo-current-workspace class "this"))) (dojo-symbol-register-object-member "constructor" ret-symbol this-symbol) (log-assign 0 (format "Setting this-symbol %s" (dojo-core-util-symbol-to-short-string this-symbol))) (dojo-class-set-this-symbol class this-symbol) (dojo-class-set-static-symbol class static-symbol))) ((dojo-core-util-is-import-symbol ret-symbol) (let* ((import-class (dojo-core-util-get-class-by-import-symbol dojo-current-workspace ret-symbol)) (import-class-static-symbol (if (dojo-class-p import-class) (dojo-class-static-symbol import-class) nil)) (our-static-symbol (construct-dojo-symbol-object dojo-current-workspace class nil))) (log-assign 0 (format "Class is [%s]" class)) (if import-class-static-symbol (dojo-core-util-copy-additional-attributes import-class-static-symbol our-static-symbol)) (dojo-class-set-static-symbol class our-static-symbol))) (t (dojo-class-set-static-symbol class ret-symbol)))))) (t (log-extract (format "[WARNING] Ignoring block-child of unsupported type [%s]" (js2-node-short-name block-child)))))) (log-extract (format "Will construct dojo-symbol-function with class [%s]" (if (dojo-class-p class) (dojo-class-id class) "---"))) (let ((define-symbol (construct-dojo-symbol-function dojo-current-workspace class nil import-symbols (dojo-class-static-symbol class)))) (log-extract (format "Setting scope [%s] of define-symbol [%s]" (dojo-scope-id define-scope) (dojo-symbol-id define-symbol))) (dojo-symbol-set-function-scope define-symbol define-scope) (setf (dojo-class-define-symbol class) define-symbol)))) (defun dojo-js-extract-process-define-var-decl (statement-child-node define-scope scopes class) (log-extract (format "--------- Processing statement-child-node of type [js2-var-decl-node]")) (dolist (var-init-node (js2-var-decl-node-kids statement-child-node)) (let* ((target-node (js2-var-init-node-target var-init-node)) (target-node-name (if (and target-node (dojo-has-node-type target-node "js2-name-node")) (dojo-get-name-from-name-node target-node) nil)) (initializer-node (js2-var-init-node-initializer var-init-node))) (log-extract (format "------------ Inspecting var-init-node for variable name [%s]" target-node-name)) (cond ((null target-node-name) (log-extract (format "[WARNING] target-node of var-init-node does not have type js2-name-node, found %s, will ignore it." (if target-node (js2-node-short-name target-node) "nil")))) ((null initializer-node) (log-extract (format "--------------- no initializer-node, ignored." (if target-node (js2-node-short-name target-node) "nil")))) ((dojo-js2-node-is-function-call initializer-node "declare") (log-extract (format "---------------- About to process declare call")) (let ((new-scopes (append (list (dojo-construct-block-scope block-children block-child 0 class)) scopes)) (static-declare-symbol (construct-dojo-symbol dojo-current-workspace class target-node-name 'DOJO-JSTYPE-OBJECT))) (dojo-process-declare-call new-scopes initializer-node class) (dojo-core-util-register-in-scope define-scope target-node-name static-declare-symbol))) (t (log-extract (format "---------------- Will process initializer-node of type [%s] using dojo-js-assign-process-statement-node" (js2-node-short-name initializer-node))) (let* ((initializer-symbol-or-type (dojo-js-assign-process-statement-node scopes class 0 initializer-node))) (cond ((null initializer-symbol-or-type) (log-extract (format "[WARNING] dojo-js-assign-process-statement-node returned **no** symbol-or-type for the initializer-node."))) ((dojo-symbol-p initializer-symbol-or-type) (dojo-core-util-register-in-scope define-scope target-node-name initializer-symbol-or-type)) (t ; Case, we received a plain type symbol, like 'DOJO-JSTYPE-NUMBER (let ((initializer-symbol (construct-dojo-symbol dojo-current-workspace class target-node-name initializer-symbol-or-type))) (dojo-core-util-register-in-scope define-scope target-node-name initializer-symbol)))))))))) (defun dojo-js-extract-process-define-assignment (statement-child-node define-scope scopes) (log-extract (format "--------- Processing statement-child-node of type [js2-assign-node]")) ) ;(defun dojo-extract-class-process-define-body (body-node class) ; "Processes the body (the js2-block-node) of a define statement. Registers the declared variables, ; and especially scans the declare block for its definitions." ; ; ; If the result of the declare call is assigned to a variable being returned lateron, ; ; it becomes the name of the symbol lateron. Otherwise, the symbol stays without name. ; ;(setf (dojo-class-static-symbol class) (construct-dojo-symbol nil)) ; ; (log-extract (format "==========================================================")); ; (log-extract (format "Processing dojo-extract-class-process-define-body for class [%s]" (dojo-class-path class))) ; ; ; We first need to find out about the return node. ; ; (1) If the result of a declare call is returned directly in that node, we will need to process it accordingly lateron. ; ; (2) If an object is returned, then it contains all the static symbols for the class at hand (no member variables exist in that case). ; ; (3) If some variable is returned, then it is the variable static symbols for the class at hand will be assigned to. ; ; Furthermore, we need the import scope. ; ; It might contain an 'exports' import (see https://dojotoolkit.org/documentation/tutorials/1.10/modules_advanced/), which ; ; (if it exists) acts as a container for static symbols. I.e. the symbols assigned to the 'exports' import in assignment ; ; statements will exist as static symbols, although the 'exports' import (usually) doesn't get returned. ; (let* ((return-node (dojo-extract-get-first-child-of-type body-node "js2-return-node")) ; (retval-node (if return-node (js2-return-node-retval return-node) nil)) ; (retvar-name (if (and retval-node (dojo-has-node-type retval-node "js2-name-node")) (dojo-get-name-from-name-node retval-node) nil)) ; (declare-retval-node (if (and retval-node (dojo-js2-node-is-function-call retval-node "declare")) retval-node nil)) ; (object-retval-node (if (and retval-node (dojo-has-node-type retval-node "js2-object-node")) retval-node nil)) ; (builtin-scope (dojo-js-scopes-construct-builtin-scope 0)) ; (import-scope (dojo-construct-import-scope 1 class)) ; (exports-symbol (dojo-scopes-get-exports-symbol import-scope)) ; (exports-symbol-name (if exports-symbol (dojo-symbol-name exports-symbol) nil)) ; (scopes (list builtin-scope import-scope)) ; (block-children (js2-block-node-kids body-node)) ; (static-symbol (construct-dojo-symbol-object dojo-current-workspace nil)) ; (static-name-to-symbol (dojo-symbol-get-object-members static-symbol))) ; ; (cond ; ; define function returns by "return { ... }" ==> Fetch all symbols from that object, and use them as static symbols ; ((not (null object-retval-node)) ; (log-extract (format "--- Returning a js2-object-node, retrieving symbols of static symbol directly from there")) ; (dolist (static-symbol-local (dojo-get-dojo-symbols-in-object object-retval-node class)) ; (puthash (dojo-symbol-name static-symbol-local) static-symbol-local static-name-to-symbol) ; (log-extract (format "------ Added static-symbol-local with name [%s]" (dojo-symbol-name static-symbol-local))))) ; (t ; ; Function returns a plain variable: Collect all assignments to that variable as static symbols. ; (if (not (null retvar-name)) ; (dojo-js-extract-collect-static-define-assignments block-children retvar-name static-name-to-symbol)) ; ; Module imports the magic 'exports' symbol: Collect all assignments made to the corresponding variable as static symbols. ; (if (not (null exports-symbol-name)) ; (dojo-js-extract-collect-static-define-assignments block-children exports-symbol-name static-name-to-symbol)))) ; ; (if (and retval-node (dojo-js2-node-is-function-call retval-node "declare")) ; (progn ; (log-extract (format "------------ About to process declare call")) ; (let ((new-scopes (append (list (dojo-construct-block-scope block-children return-node 0 class)) scopes))) ; (dojo-process-declare-call new-scopes retval-node class)))) ; ; (log-extract (format "--- Inspecting variable declarations:")) ; (dolist (block-child block-children) ; (log-extract (format "------ Inspecting block-child of type [%s]" (js2-node-short-name block-child))) ; (if (dojo-has-node-type block-child "js2-expr-stmt-node") ; (let* ((statement-child-node (js2-expr-stmt-node-expr block-child))) ; (log-extract (format "--------- Inspecting statement-child-node of type [%s]" (js2-node-short-name statement-child-node))) ; (cond ((dojo-has-node-type statement-child-node "js2-var-decl-node") ; (dolist (var-init-node (js2-var-decl-node-kids statement-child-node)) ; (let* ((target-node (js2-var-init-node-target var-init-node)) ; (target-node-name (if (and target-node (dojo-has-node-type target-node "js2-name-node")) (dojo-get-name-from-name-node target-node) nil)) ; (initializer-node (js2-var-init-node-initializer var-init-node))) ; (log-extract (format "------------ Inspecting var-init-node for target-node-name (variable name) [%s]" target-node-name)) ; (cond ((null target-node-name) ; (log-extract (format "[WARNING] target-node of var-init-node does not have type js2-name-node, found %s, ; will ignore it, maybe this leads to ignore the complete declare block" ; (if target-node (js2-node-short-name target-node) "nil")))) ; ((not (string= target-node-name retvar-name)) ; (log-extract (format "---------------- target-node [%s] of var-init-node does not refer to the returned variable [%s], will IGNORE it." ; target-node-name retvar-name))) ; ((and initializer-node (dojo-js2-node-is-function-call initializer-node "declare")) ; (log-extract (format "---------------- About to process declare call")) ; (let ((new-scopes (append (list (dojo-construct-block-scope block-children block-child 0 class)) scopes))) ; (dojo-process-declare-call new-scopes initializer-node class))) ; ((and initializer-node (dojo-has-node-type initializer-node "js2-object-node")) ; (log-extract (format "---------------- About to process js2-object-node")) ; (dolist (static-symbol-local (dojo-get-dojo-symbols-in-object initializer-node class)) ; (log-extract (format "------------------- About to add symbol [%s]" (dojo-symbol-name static-symbol-local))) ; (puthash (dojo-symbol-name static-symbol-local) static-symbol-local static-name-to-symbol))))))))))) ; (setf (dojo-class-static-symbol class) static-symbol))) (defun dojo-js-extract-collect-static-define-assignments (nodes static-var-name static-name-to-symbol) "Collects all assignments of members of an object with the given static-var-name in the given nodes list. Registers them as static variables in the given static-name-to-symbol map." (log-extract (format "--- Called dojo-js-extract-collect-static-define-assignments for static-var-name [%s]" static-var-name)) (dolist (node nodes) (cond ((dojo-has-node-type node "js2-expr-stmt-node") (log-extract (format "------ Processing js2-expr-stmt-node")) (let* ((statement-child-node (js2-expr-stmt-node-expr node))) (cond ((dojo-has-node-type statement-child-node "js2-assign-node") (log-extract (format "--------- Processing js2-assign-node")) (let* ((left-node (js2-infix-node-left statement-child-node)) (right-node (js2-infix-node-right statement-child-node)) (operator (js2-infix-node-type statement-child-node)) ) (if (and (eq operator js2-ASSIGN) (dojo-has-node-type left-node "js2-prop-get-node")) (let* ((instance-node (js2-prop-get-node-left left-node)) (instance-name (if (dojo-has-node-type instance-node "js2-name-node") (dojo-get-name-from-name-node instance-node) nil)) (var-node (js2-prop-get-node-right left-node)) (var-name (if (dojo-has-node-type var-node "js2-name-node") (dojo-get-name-from-name-node var-node) nil))) (if (or (null instance-name) (null var-name)) (log-extract (format "[WARNING] Ignoring assignment inside define, as either instance or variable node is not a js2-name-node"))) (if (string= instance-name static-var-name) (let* ((static-symbol-local (dojo-process-object-prop-right-node right-node var-name class))) (if static-symbol-local (progn (log-extract (format "--------- Created static-symbol-local with name [%s]" (dojo-symbol-name static-symbol-local))) (puthash var-name static-symbol-local static-name-to-symbol)))))))))))) ; Do nothing about these nodes, as they are known to ignore in this situation ((or (dojo-has-node-type node "js2-return-node")) ()) ; But warn about unexpected ones, as they might indicate expressions we should indeed treat here. (t (log-extract (format "------ dojo-js-extract-collect-static-define-assignments will IGNORE unsupported node of type [%s]" (js2-node-short-name node))))))) (defun dojo-process-declare-call (scopes call-node class) "Processes a call to declare. Registers all defined members in the given dojo-class instance." (let* ((call-argument-nodes (js2-call-node-args call-node)) (first-arg-node (nth 0 call-argument-nodes)) (second-arg-node (nth 1 call-argument-nodes)) (third-arg-node (nth 2 call-argument-nodes)) (super-class-node (if (= (length call-argument-nodes) 3) second-arg-node first-arg-node)) (object-node (if (= (length call-argument-nodes) 3) third-arg-node second-arg-node)) (superclass-names (dojo-get-superclass-names super-class-node)) (superclass-paths ()) (object-members ()) ; All symbols found in the call to declare (import-to-symbol (dojo-class-import-to-symbol class)) ) ; (dolist (super-class-name super-class-names) ; (message "Found superclass %s" super-class-name) ; ) (if (or (null object-node) (not (string= (js2-node-short-name object-node) "js2-object-node"))) ; Assure that we have a js2-object-node (progn (log-extract (format (concat "[WARNING] Third parameter to declare is not a js2-object-node, found %s, " "will ignore it (and thus all contents of the declare call)") (if object-node (js2-node-short-name object-node) "---")))) ; Proceed if this is the case (progn ; Extract the superclass information (dolist (superclass-name superclass-names) (let* ((import-symbol (gethash superclass-name import-to-symbol)) (import-path (if import-symbol (dojo-symbol-get-import-path import-symbol) nil)) ) (if import-path (setq superclass-paths (append superclass-paths (list import-path))) ) ) ) (setf (dojo-class-superclass-paths class) superclass-paths) ; Create the this-symbol, and store the object-members in it. ; Then store the this-symbol in the topmost scope. (let* ((class-id (dojo-class-id class)) (resource-id (dojo-class-resource-id class)) (id-to-resource (dojo-workspace-id-to-resource dojo-current-workspace)) (resource (gethash resource-id id-to-resource)) (api-class (dojo-js-api-get-api-class-by-resource resource class)) (api-this-symbol (if api-class (dojo-class-this-symbol api-class) nil)) (this-symbol (dojo-class-this-symbol class)) (declare-scope (construct-dojo-scope dojo-current-workspace 3 "dojo-process-declare-call")) (declare-scope-name-to-symbol (dojo-scope-name-to-symbol declare-scope))) (setf (dojo-symbol-min-pos this-symbol) (js2-node-abs-pos object-node)) (setf (dojo-symbol-max-pos this-symbol) (js2-node-abs-end object-node)) (puthash "this" this-symbol declare-scope-name-to-symbol) (log-assign 0 (format "Will call process-object-node for this-symbol %s" this-symbol)) (dojo-js-assign-process-object-node (append (list declare-scope) scopes) class 0 object-node this-symbol api-this-symbol) (log-assign 0 (format "Setting this-pointer %s" (dojo-core-util-symbol-to-short-string this-symbol))) (dojo-class-set-this-symbol class this-symbol)))))) (defun dojo-get-superclass-names (super-class-node) (let* ((result-list () ) ) (cond ((dojo-has-node-type super-class-node "js2-name-node") (push (dojo-get-name-from-name-node super-class-node) result-list)) ((dojo-has-node-type super-class-node "js2-array-node") (dolist (array-member-node (js2-array-node-elems super-class-node)) (if (not (string= (js2-node-short-name array-member-node) "js2-name-node")) (log-extract (format "[WARNING] Member of superclass array inside declare is not a js2-name-node, found %s, will ignore it." (js2-node-short-name array-member-node))) (push (dojo-get-name-from-name-node array-member-node) result-list)))) ((and (dojo-has-node-type super-class-node "js2-keyword-node") (= (js2-node-type super-class-node) js2-NULL)) ()) ; Super class null means no super class, thus leave the list empty, and return it lateron (t (log-extract (format "[WARNING] Superclass node has unsupported / probably illegal type [%s]" (js2-node-short-name super-class-node)))) ) result-list ) ) (defun dojo-get-base-symbol-for-prop-get-node (scopes class prop-get-node this-symbol &optional max-abs-pos) "Given some js2-prop-get-node (like 'foo.bar' or 'foo().bar'), this function returns the base symbol, i.e. the symbol providing 'bar' in the previous examples. For 'foo()', the base symbol would be the return type of function foo. Symbols in all the given scopes, plus member or static variables in the given class are considered. max-abs-pos is an optional filter on the position. Consider source code like 'this. this.foo' where point is after the dot of the 'this.' in the first line. Then you will get a hierarchy of two js2-prop-get-nodes, where in fact, the second one is after point and irrelevant for completion. The parser cannot recognize that we are not interested in the whole statement in this situation, but based on the position of point, we can reason that the second 'this' and whatever follows it is not relevant for our completion." (let ((left-child (js2-infix-node-left prop-get-node)) ) (log-extract (format "dojo-get-base-symbol-for-prop-get-node called for node type [%s]: [%s]" (js2-node-short-name left-child) (dojo-node-to-string prop-get-node))) (cond ((and (dojo-has-node-type left-child "js2-keyword-node") (= (js2-node-type left-child) js2-THIS)) (dojo-get-symbol-from-scopes scopes "this")) ;this-symbol) ((dojo-has-node-type left-child "js2-name-node") (dojo-get-symbol-from-scopes scopes (dojo-get-name-from-name-node left-child))) ((dojo-has-node-type left-child "js2-prop-get-node") (dojo-get-symbol-for-prop-get-node scopes class left-child this-symbol max-abs-pos)) (t (log-extract (format "[WARNING] Case node-type [%s] not yet implemented in dojo-get-base-symbol-for-prop-get-node." (js2-node-short-name left-child)))) ) ) ) (defun dojo-get-symbol-for-prop-get-node (scopes class prop-get-node this-symbol &optional max-abs-pos) (let* ((left-symbol (dojo-get-base-symbol-for-prop-get-node scopes class prop-get-node this-symbol)) (right-child (js2-infix-node-right prop-get-node)) ) (log-extract (format "max-abs-pos is [%s], js2-node-abs-pos of right-child is [%s]" max-abs-pos (js2-node-abs-pos right-child))) (cond ((null left-symbol) (log-assign 0 (format "Found no base-symbol for prop-get-node")) nil) ((and (not (null max-abs-pos)) (> (js2-node-abs-pos right-child) max-abs-pos)) left-symbol) (t (cond ((dojo-has-node-type right-child "js2-name-node") (cond ((dojo-core-util-is-object-symbol left-symbol) (dojo-symbol-get-object-member (dojo-get-name-from-name-node right-child) left-symbol)) (t (log-extract (format "[WARNING] dojo-get-symbol-for-prop-get-node doesn't support type [%s] for left symbol." (dojo-core-util-symbol-type-to-string left-symbol)))) )) (t (log-extract (format "[WARNING] dojo-get-symbol-for-prop-get-node doesn't support type [%s] of right child." (js2-node-short-name right-child)))) )) ) ) ) (defun dojo-extract-process-define-i18n-params (top-object-node class) (let* ((elem-nodes (js2-object-node-elems top-object-node)) ) (dolist (object-prop-node elem-nodes) (let* ((left-node (js2-infix-node-left object-prop-node)) (prop-name (dojo-get-name-from-object-prop-left-node left-node)) (right-node (js2-infix-node-right object-prop-node)) ) (if (string= prop-name "root") (if (not (string= (js2-node-short-name right-node) "js2-paren-node")) (log-extract (format "[WARNING] Ignoring i18n root node, as it does not have node type js2-paren-node, but [%s]" (js2-node-short-name right-node))) (let* ((object-node (js2-paren-node-expr right-node)) (static-symbol (dojo-js-assign-process-object-node () class 0 object-node))) (log-assign 0 (format "Will set extracted i18n static symbol [%s]" (dojo-core-util-symbol-to-short-string static-symbol))) (setf (dojo-class-static-symbol class) static-symbol)))))))) (defun dojo-extract-process-define-other-i18n-params (top-paren-node class) (let* ((expr-node (js2-paren-node-expr top-paren-node))) (cond ((dojo-has-node-type expr-node "js2-object-node") (let ((static-symbol (dojo-js-assign-process-object-node () class 0 expr-node))) (log-assign 0 (format "Will set extracted i18n static symbol [%s]" (dojo-core-util-symbol-to-short-string static-symbol))) (setf (dojo-class-static-symbol class) static-symbol))) (t (log-assign 0 (format "[WARNING] Unsupported node [%s] in extract-process-define-other-i18n-params" (js2-node-short-name expr-node))))))) ; ========================================= Extracting non-top symbols from object ============================================ ; ; The following code is for extracting assignments to the this-pointer and similar things from a js2-object-node. ; ; ============================================================================================================================= (defun dojo-extract-assignments-process-object-node (scopes class level object-node) "" (log-assign level (format "Called dojo-extract-process-object-node for scopes %s" (dojo-scopes-to-string scopes))) (let* ((object-prop-nodes (js2-object-node-elems object-node)) (object-members ()) (level (1+ level)) ) (dolist (object-prop-node object-prop-nodes) (let* ((left-node (js2-infix-node-left object-prop-node)) (prop-name (dojo-get-name-from-object-prop-left-node left-node)) (right-node (js2-infix-node-right object-prop-node)) ) (log-assign level (format "Processing prop-name [%s] with right-node of type [%s]" prop-name (js2-node-short-name right-node))) (cond ((dojo-has-node-type right-node "js2-function-node") (dojo-extract-assignments-process-function-node scopes class (1+ level) right-node)) (t (log-assign (1+ level) (format "Ignoring not yet supported node of type [%s]" (js2-node-short-name right-node)))) ) ) ) ) ) (defun dojo-extract-assignments-process-function-node (scopes class level function-node) (log-assign level (format "Processing [js2-function-node]")) (let* ((new-scopes (append (list (dojo-construct-function-param-scope function-node level)) scopes)) (body-node (js2-function-node-body function-node)) ) (cond ((dojo-has-node-type body-node "js2-block-node") (dojo-extract-assignments-process-block-node new-scopes class (1+ level) body-node)) (t (log-assign (1+ level) (format "Ignoring not yet supported node of type [%s]" (js2-node-short-name body-node)))) ) ) ) (defun dojo-extract-assignments-process-block-node (scopes class level block-node) (log-assign level (format "Processing [js2-block-node]")) (let* ((child-nodes (js2-block-node-kids block-node)) ) (dolist (child-node child-nodes) (cond ((dojo-has-node-type child-node "js2-expr-stmt-node") (dojo-extract-assignments-process-expr-stmt-node scopes class (1+ level) child-node)) (t (log-assign (1+ level) (format "Ignoring not yet supported node of type [%s]" (js2-node-short-name body-node)))) ) ) ) ) (defun dojo-extract-assignments-process-expr-stmt-node (scopes class level expr-stmt-node) (log-assign level (format "Processing [js2-expr-stmt-node]")) (let* ((expr-node (js2-expr-stmt-node-expr expr-stmt-node)) ) (cond ((dojo-has-node-type expr-node "js2-assign-node") (dojo-extract-assignments-process-assign-node scopes class (1+ level) expr-node)) (t (log-assign (1+ level) (format "Ignoring not yet supported node of type [%s]" (js2-node-short-name expr-node)))) ) ) ) (defun dojo-extract-assignments-process-assign-node (scopes class level assign-node) (log-assign level (format "Processing [js2-assign-node]")) (let* ((left-node (js2-infix-node-left assign-node)) (right-node (js2-infix-node-right assign-node)) (operator (js2-infix-node-type assign-node)) (left-symbol (dojo-scopes-get-node-symbol scopes (1+ level) left-node t)) ) (if (null left-symbol) (log-assign level (format "Found no left-symbol")) (progn (log-assign level (format "Found left-symbol (%s %s); operator: [%s]" (dojo-core-util-symbol-type-to-string left-symbol) (dojo-symbol-name left-symbol) (dojo-js2-node-type-to-string operator))) (cond ((eq operator js2-ASSIGN) (dojo-extract-assignments-derive-type scopes class (1+ level) left-symbol right-node)) (t (log-assign level (format "Operator [%s] is unsupported." (dojo-core-util-symbol-type-to-string left-symbol) (dojo-symbol-name left-symbol) (dojo-js2-node-type-to-string operator)))) ) (log-assign level (format "FINISHED: Derived left-symbol (%s %s) with resource/path (%s %s)" (dojo-core-util-symbol-type-to-string left-symbol) (dojo-symbol-name left-symbol) (dojo-symbol-get-import-resource-id left-symbol) (dojo-symbol-get-import-path left-symbol))) ) ) ) ) (defun dojo-extract-assignments-derive-type (scopes class level left-symbol right-node) (log-assign level (format "dojo-extract-assignments-derive-type derives type of left-symbol [%s]" (dojo-symbol-name left-symbol))) (cond ((dojo-has-node-type right-node "js2-new-node") (dojo-extract-assignments-derive-type-new-node scopes class (1+ level) left-symbol right-node)) (t (log-assign (1+ level) (format "Ignoring not yet supported node of type [%s]" (js2-node-short-name right-node)))) ) ) (defun dojo-extract-assignments-derive-type-new-node (scopes class level left-symbol right-node) (log-assign level (format "dojo-extract-assignments-derive-type-new-node")) (let* ((target-node (js2-new-node-target right-node)) ) (cond ((dojo-has-node-type target-node "js2-name-node") (dojo-extract-assignments-set-symbol-type-by-name scopes class (1+ level) left-symbol (dojo-get-name-from-name-node target-node))) (t (log-assign (1+ level) (format "Ignoring not yet supported node of type [%s]" (js2-node-short-name target-node)))) ) ) ) (defun dojo-extract-assignments-set-symbol-type-by-name (scopes class level symbol name) (let* ((import-to-symbol (dojo-class-import-to-symbol class)) (import-symbol (gethash name import-to-symbol)) ) (cond ((not (null import-symbol)) (dojo-symbol-set-type symbol 'DOJO-JSTYPE-INSTANCE) (dojo-symbol-set-import-resource-id symbol (dojo-symbol-get-import-resource-id import-symbol)) (dojo-symbol-set-import-type symbol (dojo-symbol-get-import-type import-symbol)) (dojo-symbol-set-import-path symbol (dojo-symbol-get-import-path import-symbol))) ((string= name "RegExp") (dojo-symbol-set-type symbol 'DOJO-JSTYPE-REGEXP)) ) ) ) (defun dojo-extract-get-first-child-of-type (block-node searched-type) (let* ((block-children (js2-block-node-kids block-node)) (first-child nil)) (dolist (block-child block-children) (if (dojo-has-node-type block-child searched-type) (progn (setq first-child block-child) (return nil)))) first-child)) ; ======================================== Extracting imports in an heuristic manner ========================================== ; 10523 (defun dojo-js-extract-print-import-resources (resource-id) (interactive "NResource-id: ") (let* ((id-to-resource (dojo-workspace-id-to-resource dojo-current-workspace)) (resource (gethash resource-id id-to-resource))) (cond ((null resource) (log-extract (format "No resource with id [%s] found." resource-id))) (t (log-extract (format "=========================================================================================")) (log-extract (format "Resource [%s:%s:%s] imports the following resources, according to heuristic code analysis" resource-id (dojo-resource-project resource) (dojo-resource-path resource))) (log-extract (format "=========================================================================================")) (let* ((import-resources (dojo-js-extract-get-heuristic-import-resources-by-resource resource))) (dolist (import-resource import-resources) (log-extract (format "- %s:%s:%s" (dojo-resource-id import-resource) (dojo-resource-project import-resource) (dojo-resource-path import-resource))))))))) (defun dojo-js-extract-get-heuristic-import-resources-by-resource (resource) (let* ((file-path (dojo-resource-file-path resource))) (if (file-readable-p file-path) (with-temp-buffer (buffer-disable-undo (current-buffer)) (insert-file-contents file-path) (dojo-js-extract-get-heuristic-import-resources-by-current-buffer))))) (defun dojo-js-extract-get-heuristic-import-resources-by-current-buffer () "Returns a list of all import resources, extracted from the current buffer. They will be extracted in an heuristic manner, based on magic keywords like the define statement. The objective is to return them quickly, instead of being 100 percent correct even for misformed files." (goto-char (point-min)) (let* ((define-pos (search-forward "define" nil t)) (open-square-bracket-pos (if (null define-pos) nil (search-forward "[" nil t))) (close-square-bracket-pos (if (null open-square-bracket-pos) nil (search-forward "]" nil t))) (resources ())) (if (null close-square-bracket-pos) (log-extract (format "[WARNING] Did not find delimiting square brackets of import array inside define statement; something is wrong with this file.")) (goto-char open-square-bracket-pos) (while (< (point) close-square-bracket-pos) (let* ((start-quote-pos (search-forward "\"" nil t)) (close-quote-pos (if (null start-quote-pos) nil (search-forward "\"" nil t))) (import-path (if (and (not (null close-quote-pos)) (< close-quote-pos close-square-bracket-pos)) (dojo-common-strings-trim (buffer-substring start-quote-pos (1- close-quote-pos))) nil)) (import-resource (if import-path (dojo-core-util-get-resource-by-path dojo-current-workspace import-path) nil))) (if import-resource (push import-resource resources)) ; If no quote is found, point stays at the same position, and we are done since there are no more imports. ; Avoid an endless loop in this corner case, by jumping to end of buffer, which is certainly after close-square-bracket-pos. (if (null start-quote-pos) (goto-char (point-max)))))) (nreverse resources))) ; ======================================================= Debugging =========================================================== ; name type project path arguments (defun dojo-extract-and-print-class () (interactive) (let* ((class (if (null js2-mode-ast) nil (dojo-extract-class-from-ast dojo-current-workspace js2-mode-ast nil nil))) (this-symbol (dojo-class-this-symbol class)) (static-symbol (dojo-class-static-symbol class)) ) ; (log-extract (format "Class with path %s in project %s:" (dojo-class-path class) (dojo-class-project class))) ; (log-extract "Imports:") ; (maphash (lambda (name symbol) ; (print-symbol-info symbol) ; ) (dojo-class-import-to-symbol class) ; ) ; ; (log-extract "Top level variables:") ; (maphash (lambda (name symbol) ; (print-symbol-info symbol) ; ) (dojo-class-define-var-to-symbol class) ; ) ; ; (log-extract "Static symbol:") ; (maphash (lambda (name symbol) ; (print-symbol-info symbol) ; ) (dojo-symbol-value this-symbol) ; ) ; ; (log-extract "Static members:") ; (maphash (lambda (name symbol) ; (print-symbol-info symbol) ; ) (dojo-class-static-to-symbol class) ; ) ; ; (log-extract "Static symbol:") ; (maphash (lambda (name symbol) ; (print-symbol-info symbol) ; ) (dojo-symbol-value static-symbol) ; ) ) ) (defun print-symbol-info (symbol) (log-extract (format "Registered symbol: name=%s, type=%s" (dojo-symbol-name symbol) (dojo-core-util-symbol-type-to-string symbol) )) ) (provide 'dojo-js-extract)