(require 'cl-lib) (require 'dojo-common-containers) ; Auflösung Typen: ; - Referenz dojo-symbol --> dojo-scope für function-symbols ; ==> scope enthält alle Variablen in der function ; - Liste dojo-symbol.in-symbols ; ==> alle dojo-symbols die in dieses dojo-symbol kopiert werden ; - Liste dojo-symbol.out-symbols ; ==> alle dojo-symbols in die dieses dojo-symbol kopiert werden ; - in-symbols und out-symbols bleiben innerhalb desselben dojo-scopes ; - dojo-symbol.arguments und dojo-symbol.return-type verweisen auf ; eigenständige Kopien der dojo-symbols aus dem scope ; (um Garbage-Collection zu erleichtern, wenn arguments und return-type ; bestimmt sind, und der oben genannte dojo-scope nicht mehr benötigt ; wird) ; - Neue Referenz dojo-symbol.parent um vom dojo-symbol 'Objektattribut' ; zum dazugehörigen dojo-symbol 'Objekt' zu kommen ; out-symbol = (symbol-id scan-class-id scan-time) (defvar DOJO-JSTYPE-ARRAY) ; value-type (defvar DOJO-JSTYPE-ARRAY-OR-OBJECT) (defvar DOJO-JSTYPE-BOOLEAN) ; (defvar DOJO-JSTYPE-DATE) ; (defvar DOJO-JSTYPE-DOMNODE) ; (defvar DOJO-JSTYPE-DOUBLE) ; Double (in Java sense, or any floating point number in Javascript) (defvar DOJO-JSTYPE-EXCEPTION) ; (defvar DOJO-JSTYPE-FLOAT) ; Float (in Java sense) (defvar DOJO-JSTYPE-FUNCTION) ; arguments, return-type (defvar DOJO-JSTYPE-IMAGE) (defvar DOJO-JSTYPE-IMPORT) ; project, path, prefix (defvar DOJO-JSTYPE-INSTANCE) ; project, path (defvar DOJO-JSTYPE-INTEGER) ; Integer (in Java sense) (defvar DOJO-JSTYPE-LONG) ; Long (in Java sense, or any integral number in Javascript) (defvar DOJO-JSTYPE-NUMBER) ; Any number in Javascript, exact type (e.g. Int vs. Double) unknown (defvar DOJO-JSTYPE-OBJECT) ; key-type, value-type, name-to-symbol (defvar DOJO-JSTYPE-REF) ; Reference, value can be derived from other symbols (defvar DOJO-JSTYPE-REGEXP) ; (defvar DOJO-JSTYPE-STRING) ; (defvar DOJO-JSTYPE-STRING-MAP (make-hash-table :test 'equal)) (puthash "DOJO-JSTYPE-ARRAY" 'DOJO-JSTYPE-ARRAY DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-ARRAY-OR-OBJECT" 'DOJO-JSTYPE-ARRAY-OR-OBJECT DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-BOOLEAN" 'DOJO-JSTYPE-BOOLEAN DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-DATE" 'DOJO-JSTYPE-DATE DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-DOMNODE" 'DOJO-JSTYPE-DOMNODE DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-EXCEPTION" 'DOJO-JSTYPE-EXCEPTION DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-FUNCTION" 'DOJO-JSTYPE-FUNCTION DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-IMAGE" 'DOJO-JSTYPE-IMAGE DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-IMPORT" 'DOJO-JSTYPE-IMPORT DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-INSTANCE" 'DOJO-JSTYPE-INSTANCE DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-NUMBER" 'DOJO-JSTYPE-NUMBER DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-OBJECT" 'DOJO-JSTYPE-OBJECT DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-REF" 'DOJO-JSTYPE-REF DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-REGEXP" 'DOJO-JSTYPE-REGEXP DOJO-JSTYPE-STRING-MAP) (puthash "DOJO-JSTYPE-STRING" 'DOJO-JSTYPE-STRING DOJO-JSTYPE-STRING-MAP) (defvar DOJO-REFTYPE-STRING-MAP (make-hash-table :test 'equal)) (puthash "DOJO-REFTYPE-OBJECT-MEMBER" 'DOJO-REFTYPE-OBJECT-MEMBER DOJO-REFTYPE-STRING-MAP) (puthash "DOJO-REFTYPE-ANY-OBJECT-MEMBER" 'DOJO-REFTYPE-ANY-OBJECT-MEMBER DOJO-REFTYPE-STRING-MAP) ; The following symbols represent builtin Javascript functions, and special Dojo functions. (defvar DOJO-FCT-ARRAY-PUSH) (defvar DOJO-REFTYPE-OBJECT-MEMBER) (defvar DOJO-REFTYPE-ANY-OBJECT-MEMBER) ; The following symbols are for the object-type variable in struct dojo-object (defvar DOJO-OBJECTTYPE-SERVICE) ; A service; the object members are the methods parsed from the service interface (defvar DOJO-OBJECTTYPE-STATIC) ; The static-symbol of a class (defvar DOJO-OBJECTTYPE-THIS) ; The this-symbol of a class (defvar DOJO-OBJECTTYPE-STRING-MAP (make-hash-table :test 'equal)) (puthash "DOJO-OBJECTTYPE-SERVICE" 'DOJO-OBJECTTYPE-SERVICE DOJO-OBJECTTYPE-STRING-MAP) (puthash "DOJO-OBJECTTYPE-STATIC" 'DOJO-OBJECTTYPE-STATIC DOJO-OBJECTTYPE-STRING-MAP) (puthash "DOJO-OBJECTTYPE-THIS" 'DOJO-OBJECTTYPE-THIS DOJO-OBJECTTYPE-STRING-MAP) (cl-defstruct (dojo-symbol) "Information about a symbol in Javascript/Dojo source code." ;; Id id ;; Name of the symbol in source code name ;; Type of the symbol if known, nil otherwise. If known, the one of the following: ;; - a Javascript type like 'string', 'number' or 'function' ;; - the name of a builtin Javascript class like 'RegExp' ;; - 'array' for an Javascript array ;; - 'object' for Javascript objects that don't meet the following conditions ;; - 'import' for the import symbol of an imported dojo class ;; - 'instance' for an instance of a dojo class (e.g. assigned to new Memory()) type ;; Value of the symbol. ;; Only filled in special cases, e.g. for i18n strings. value ;; Details about the symbol, depending on its type. ;; For type DOJO-JSTYPE-FUNCTION, this is a dojo-function instance. details ;; Builtin functions of the symbol (things like .push). ;; Filled in a lazy manner, i.e. only symbols for functions whose ;; calls were actually found while interpreting the source code are ;; created and stored here. ;; If no such functions were created yet, this variable is nil, otherwise ;; it is a hashtable from function name to function symbol. functions ;; Reference to the parent. ;; - For the this-symbol, and for the static-symbol, this is the dojo-class ;; containing the this-symbol or static-symbol ;; - For other symbols, this is the dojo-symbol (e.g. a dojo-object) where ;; the symbol is inside. parent-id ;; The dojo-scan id of the dojo-class scan that created the symbol. ;; In particular, by inspecting that scan, one can find out about the ;; dojo-class (and corresponding Js file) whose extraction caused the ;; creation of this symbol. That information can e.g. used for ;; garbage collection tasks. scan-id ;; The id of the dojo-class containing the symbol. All child symbols of ;; this-symbol and static-symbol of a class belong to the class (including ;; all symbols down the tree of object membership). Furthermore, all ;; argument symbols, return value symbols, similar things, ;; including potential members belong to the class. ;; E.g., if in class B, an object A a exists, and there (inside B) ;; is an assignment a.foo = "bar", then a symbol foo for class A, not ;; for class B is to be created. class-id ;; Flag which indicates that the symbol is part of an API class, i.e. a ;; class stored in some api.xml. The sense is that e.g. when creating ;; a member for some object symbol, we can easily detect that the member ;; needs to be added in the api class (in dojo-workspace-id-to-api-class). is-api-symbol ;; The js2-node-abs-pos of the corresponding js2-node. May be nil. min-pos ;; The js2-node-abs-end of the corresponding js2-node. May be nil. max-pos ;; The symbol is not stored in any class, but lives just temporary. ;; In order to avoid such symbols spreading all over the data structures, ;; calling code must explicitely allow the called code the construction ;; of such symbols --- and lateron deal with the results in a proper ;; manner. ;; Example: call-node calls the result of a prop-get-node. ;; process-call-node may allow process-prop-get-node the ;; construction of a transient reference symbol --- ;; but must do something senseful with that transient symbol ;; without distributing it all over the place. transient ;; Value of the symbol if known, nil otherwise. ;; For type == "object", this is a hashtable from name to symbol. ;; For type == "function", this is a dojo-scope containing the local variables of the function. ; value ;; If type == 'import' or 'instance' the project where the import / dojo class comes from. E.g. "dojo-clazzes" ;; If type == "object", the project of the constructed class (if known) ; project ;; If type == 'import' or 'instance', the path of the import / dojo class. E.g. "clazzes/dateTime/DateTimeSpinBox" ;; If type == "object", the path of the constructed class (if known) ; path ;; If type == "import", and the import path has a prefix like "dojo/i18n!", the prefix; otherwise nil. ;; If type == "function", list of its arguments as dojo-symbols. They are *not* shared with their counterparts ;; in the dojo-scope stored in variable value (to allow for easy garbage collection once ;; the dojo-scope is no longer needed) ; arguments ;; If type == "function", its return type as dojo-symbol (if known, otherwise nil). *Not* shared with its counterpart ;; in the dojo-scope stored in variable value. ; return-type ) (cl-defstruct (dojo-class (:constructor dojo-class--create)) "Information about a Dojo class" ;; Id id ;; Project of the class, e.g. "dojo-clazzes" project ;; Path of the class, e.g. "clazzes/dateTime/DateTimeSpinBox" path ;; Flag that indicates that this class instance is an API class, ;; i.e. stored in dojo-workspace-id-to-api-class. is-api-class ;; Id of the resource the class was parsed from resource-id ;; Id of the Dojo scan which created this dojo-class scan-id ;; The paths of the super classes, in the order in which they occur in the source code file superclass-paths ; deprecated ;; Name of the variable the declared class (static or not) is assigned to. nil if it is directly returned. return-var-name ;; Hash table mapping imported symbol names like "TinyLog" to their respective dojo-symbol structures (import-to-symbol (make-hash-table :test 'equal)) ; deprecated ;; Hash table mapping top level variables (in the function passed as second parameter to define) to their respective dojo-symbol structures (define-var-to-symbol (make-hash-table :test 'equal)) ; deprecated ;; Hash table mapping members (usually functions, but also all other variables defined in a declare statement) to their respective dojo-symbol structures (member-to-symbol (make-hash-table :test 'equal)) ; deprecated ;; Hash table mapping static members to their respective dojo-symbol structures (static-to-symbol (make-hash-table :test 'equal)) ;; Map containing all symbols of this class. (id-to-symbol (make-hash-table :test 'equal)) ;; The next free id for symbols *within* this dojo-class (next-free-symbol-id 0) ;; Contains entries for all dojo-scopes of this class. (id-to-scope (make-hash-table :test 'equal)) ;; The next free id for scopes *within* this dojo-class (next-free-scope-id 0) ;; dojo-symbol representing the function parameter of the define call. Contains the import-symbols ;; as arguments, and the variables defined in the function body ;; (typically, e.g. 'var log = new TinyLog(...)') in the function scope. ;; Instance and static members defined by declare call and by assignments to the returned symbol can ;; be found in this-symbol and static-symbol. define-symbol this-symbol static-symbol ;; Map from lists (class-id symbol-id) to hashtables mapping (class-id symbol-id) to t. ;; Stores assignments pointing towards the key symbols. ;; I.e., if code extracting finds an assignment "a = b", then an entry ;; (class-id b) --> (in value hashtable) (class-id a) --> t ;; is added to the in-assignment-map. ;; Elements of foreign api classes may be stored here, but not internal symbols ;; not present in the foreign api class. (in-assignment-map (make-hash-table :test 'equal)) ;; Map from lists (class-id symbol-id) to hashtables mapping (class-id symbol-id) to t. ;; Stores assignments from the key symbols to some other symbols. ;; I.e., if code extracting finds an assignment "a = b", then an entry ;; (class-id a) --> (in value hashtable) (class-id b) --> t ;; is added to the out-assignment-map. ;; Elements of foreign api classes may be stored here, but not internal symbols ;; not present in the foreign api class. I.e., we do not store assignments to internal ;; symbols of foreign classes here, just assignments to the public API, like caused ;; by calling a public function or the constructor of some foreign class. (out-assignment-map (make-hash-table :test 'equal)) ;; Utcseconds when this class was last needed (e.g. last parsed, or the last time some symbol etc. was required). ;; Based on this value, garbage collection of classes can take place. ;; This value is transient, and will not be saved to the xml files. last-needed-utcseconds ;; List of annotations in the file. ;; They are comments starting with '////' in the file. ;; If they have the form '//// foo=bar', the corresponding dojo-annotation instance has key 'foo' and value 'bar', ;; otherwise the whole content of the annotation is stored in field 'value'. ;; See also struct dojo-annotation. (annotations nil) (transient nil) ) (cl-defstruct (dojo-annotation (:constructor nil) (:constructor construct-dojo-annotation (&optional key value min-pos max-pos))) (key nil) (value nil) (min-pos nil) (max-pos nil)) (cl-defstruct (dojo-scope (:constructor nil) (:constructor dojo-scope--create)) ; Id of the scope id ; Id of the scan in which the scope was created. ; See also corresponding comment for dojo-symbol, variable scan-id. scan-id ; Id of the class this scope belongs to. class-id ; Level of the scope, starting with zero for the topmost scope in the functin parameter to the define call. level ; Human readable description of the scope, for debugging description ; Contents of the scope. Maps variable names to corresponding dojo-symbols. ; Special magic names used as keys are: ; - If a name starts with "=scope=", the value is expected to be a dojo-scope, otherwise the dojo-symbol ; with the name. The part of a name following =scope= should identify the part of source code the ; scope is for as clear as possible. ; - The symbol returned from a function is stored under the key =return= (name-to-symbol (make-hash-table :test 'equal)) ;; Maps node keys to corresponding symbols. E.g., ;; the node key of a call node might be mapped to ;; the corresponding anonymous function symbol. ;; See comment of dojo-js-key-get-node-key for more ;; information. (key-to-symbol (make-hash-table :test 'equal)) ; Only used during completion, not saved: If this flag is true, check in the defined-symbols set, ; wether the symbol was defined before point. That check in particular is senseless for function ; arguments. (defined-symbols-check-enabled nil) ) (defun construct-dojo-symbol-api (workspace class-or-ref-symbol name &optional type) (let ((new-symbol (construct-dojo-symbol workspace class-or-ref-symbol name type))) (setf (dojo-symbol-is-api-symbol new-symbol) t) new-symbol)) (defun construct-dojo-symbol (workspace class-or-ref-symbol name &optional type) "Constructs a dojo-symbol and registers it in the class specified by class-or-ref-symbol. The class is determined as follows: - if class-or-ref-symbol is nil, it is fetched based on dojo-workspace-curr-scan-id (i.e., the new symbol is placed in the class we currently scan) - if class-or-ref-symbol is a number, it is taken as class-id - if class-or-ref-symbol is a dojo-symbol, its dojo-symbol-class-id is taken (i.e., the new symbol is placed in the same class as the reference symbol) - if class-or-ref-symbol is a dojo-class, its id is taken" (let* ((symbol (make-dojo-symbol)) (curr-scan-id (dojo-workspace-curr-scan-id workspace)) (used-class-id (cond ((null class-or-ref-symbol) (dojo-core-util-get-class-id-for-current-scan workspace)) ((numberp class-or-ref-symbol) class-or-ref-symbol) ((dojo-symbol-p class-or-ref-symbol) (dojo-symbol-class-id class-or-ref-symbol)) ((dojo-class-p class-or-ref-symbol) (dojo-class-id class-or-ref-symbol)) (t (error (format "Illegal class-or-ref-symbol passed to construct-dojo-symbol: [%s]" class-or-ref-symbol))))) ; (class (gethash used-class-id (dojo-workspace-id-to-class workspace))) (is-api-symbol (cond ((dojo-symbol-p class-or-ref-symbol) (dojo-symbol-is-api-symbol class-or-ref-symbol)) ((dojo-class-p class-or-ref-symbol) (dojo-class-is-api-class class-or-ref-symbol)) (t nil))) (class (progn (log-assign 0 (format "used-class-id is [%s], is-api-symbol is [%s]" used-class-id is-api-symbol)) (if (dojo-class-p class-or-ref-symbol) class-or-ref-symbol (let* ((id-to-class (if is-api-symbol (dojo-workspace-id-to-api-class workspace) (dojo-workspace-id-to-class workspace)))) (gethash used-class-id id-to-class))))) (id-to-symbol (dojo-class-id-to-symbol class))) (setf (dojo-symbol-id symbol) (dojo-class-next-free-symbol-id class)) (if is-api-symbol (setf (dojo-symbol-is-api-symbol symbol) t)) (incf (dojo-class-next-free-symbol-id class)) (setf (dojo-symbol-name symbol) name) (setf (dojo-symbol-type symbol) type) (setf (dojo-symbol-scan-id symbol) curr-scan-id) (setf (dojo-symbol-class-id symbol) used-class-id) ; Initialize details field based on the type of the symbol (dojo-symbol-init-details symbol) (puthash (dojo-symbol-id symbol) symbol id-to-symbol) (setf (dojo-class-id-to-symbol class) id-to-symbol) (log-assign 0 (format "Constructed symbol %s in %s class %s" (dojo-core-util-symbol-to-short-string symbol) (if (dojo-class-transient class) "transient" "non-transient") used-class-id)) (if (not (eq is-api-symbol (dojo-class-is-api-class class))) (error (format "[ERROR] is-api-symbol and is-api-class differs in construct-dojo-symbol. Class [%s:%s:%s:%s], Symbol %s" (dojo-class-id class) (dojo-class-project class) (dojo-class-path class) (dojo-class-is-api-class class) (dojo-core-util-symbol-to-short-string symbol)))) symbol)) (defun construct-transient-dojo-symbol (name &optional type) (let* ((symbol (make-dojo-symbol))) (setf (dojo-symbol-id symbol) nil) (setf (dojo-symbol-name symbol) name) (setf (dojo-symbol-type symbol) type) (setf (dojo-symbol-scan-id symbol) nil) (setf (dojo-symbol-class-id symbol) nil) (setf (dojo-symbol-transient symbol) t) ; Initialize details field based on the type of the symbol (dojo-symbol-init-details symbol) (log-assign 0 (format "Constructed transient symbol %s" (dojo-core-util-symbol-to-short-string symbol))) symbol)) (cl-defstruct (dojo-array (:constructor nil) (:constructor construct-dojo-array (&optional value-type))) (value-type nil)) (cl-defstruct (dojo-function (:constructor nil) (:constructor construct-dojo-function (&optional arguments return-type))) arguments (return-type nil) ; TODO: Type attribute to mark asynchronous functions builtin-fct ;; dojo-scope containing the symbols declared inside the function. scope) (defvar DOJO-IMPORT-CLASS) ;; Import of a normal Dojo class, something like "clazzes/TinyLog" (defvar DOJO-IMPORT-I18N) ;; Import of a Dojo i18n file, something like "dojo/i18n!/cdes/nls/cdes-web-i18n.js" (defvar DOJO-IMPORT-SMD) ;; Import of a SMD file, something like "dojo/text!/cdes/svc/plotService?smd" (defvar DOJO-IMPORT-TEXT) ;; dojo/text! import, that is not specific as described above, i.e. no SMD (defvar DOJO-IMPORT-STRING-MAP (make-hash-table :test 'equal)) (puthash "DOJO-IMPORT-CLASS" 'DOJO-IMPORT-CLASS DOJO-IMPORT-STRING-MAP) (puthash "DOJO-IMPORT-I18N" 'DOJO-IMPORT-I18N DOJO-IMPORT-STRING-MAP) (puthash "DOJO-IMPORT-SMD" 'DOJO-SMD-CLASS DOJO-IMPORT-STRING-MAP) (puthash "DOJO-IMPORT-TEXT" 'DOJO-TEXT-CLASS DOJO-IMPORT-STRING-MAP) (cl-defstruct (dojo-import (:constructor nil) (:constructor construct-dojo-import (&optional project path prefix))) ;; Id of the resource this import was resolved to. Nil, if no matching resource ;; could be found, or no attempt to resolve the resource was performed so far. resource-id ;; Kind of import, one of the DOJO-IMPORT types type ;; Import path. Partly redundant to the referenced dojo-resource. In detail: ;; - For DOJO-IMPORT-CLASS: The imported path; relative paths like ./foo are normalized to absolute ones ;; - For DOJO-IMPORT-I18N: The part after the '!/', and before the '.js', i.e. something like 'cdes/nls/cdes-web-i18n' ;; - For DOJO-IMPORT-SMD: The part after the '!' and before the '?smd', i.e. something like '/cdes/svc/plotService' ;; - For DOJO-IMPORT-TEXT: The part after the '!' path) (cl-defstruct (dojo-object (:constructor nil) (:constructor construct-dojo-object (&optional key-type value-type))) (key-type nil) (value-type nil) (name-to-symbol (make-hash-table :test 'equal)) (object-type nil) (object-info nil) ; Certain classes, like dojo/on, behave like objects, but are also functions. ; In such a case, the corresponding symbol is saved as dojo-object, and the ; function symbol (e.g. 'on(...)') is stored here. (function-symbol)) (cl-defstruct (dojo-ref (:constructor nil) (:constructor construct-dojo-ref (&optional type))) ; Type of the reference, something like DOJO-REFTYPE-OBJECT-MEMBER. ; See the DOJO-REFTYPE-* constants. (type nil) ; Symbols the reference refers to. The details depend on type: ; - DOJO-REFTYPE-OBJECT-MEMBER: (list object-symbol member-symbol) ; - DOJO-REFTYPE-ANY-OBJECT-MEMBER: (list object-symbol) (symbols nil)) (defun dojo-symbol-init-details (symbol) "Given the type of the symbol (see the DOJO-JSTYPE-* symbols defined above), this function (re-)initializes the corresponding details field of the dojo-symbol. No old information is kept from that field." (let ((type (dojo-symbol-type symbol))) (cond ((null type) (setf (dojo-symbol-details symbol) nil)) ((eq type 'DOJO-JSTYPE-ARRAY) (let ((details (dojo-symbol-details symbol))) (if (not (dojo-array-p details)) (setf (dojo-symbol-details symbol) (construct-dojo-array))))) ((eq type 'DOJO-JSTYPE-ARRAY-OR-OBJECT) (let ((details (dojo-symbol-details symbol))) (if (not (dojo-object-p details)) (setf (dojo-symbol-details symbol) (construct-dojo-object))))) ((eq type 'DOJO-JSTYPE-FUNCTION) (let ((details (dojo-symbol-details symbol))) (if (not (dojo-function-p details)) (setf (dojo-symbol-details symbol) (construct-dojo-function))))) ((eq type 'DOJO-JSTYPE-IMPORT) (let ((details (dojo-symbol-details symbol))) (if (not (dojo-import-p details)) (setf (dojo-symbol-details symbol) (construct-dojo-import))))) ((eq type 'DOJO-JSTYPE-INSTANCE) ; Deliberately construct a dojo-import here, both cases need the same fields (let ((details (dojo-symbol-details symbol))) (if (not (dojo-import-p details)) (setf (dojo-symbol-details symbol) (construct-dojo-import))))) ((eq type 'DOJO-JSTYPE-OBJECT) (let ((details (dojo-symbol-details symbol))) (if (not (dojo-object-p details)) (setf (dojo-symbol-details symbol) (construct-dojo-object))))) ((eq type 'DOJO-JSTYPE-REF) (let ((details (dojo-symbol-details symbol))) (if (not (dojo-ref-p details)) (setf (dojo-symbol-details symbol) (construct-dojo-ref))))) (t (setf (dojo-symbol-details symbol) nil))))) (defun construct-dojo-scope (workspace level description) (let* ((scope (dojo-scope--create)) (curr-scan-id (dojo-workspace-curr-scan-id workspace)) (scan (if (not (null curr-scan-id)) (gethash curr-scan-id (dojo-workspace-id-to-scan workspace)) nil)) (class-id (if scan (dojo-scan-class-id scan) nil)) (class (gethash class-id (dojo-workspace-id-to-class workspace))) (id-to-scope (dojo-class-id-to-scope class))) (setf (dojo-scope-id scope) (dojo-class-next-free-scope-id class)) (incf (dojo-class-next-free-scope-id class)) (setf (dojo-scope-level scope) level) (setf (dojo-scope-description scope) description) (setf (dojo-scope-scan-id scope) (dojo-workspace-curr-scan-id workspace)) (puthash (dojo-scope-id scope) scope id-to-scope) scope)) ; A dojo-dependency represents the fact, that a dojo-resource ; depends on some other dojo-resource. ; Examples: ; - Resource foo has an import statement for resource bar ; --> foo depends on bar ; - Resource foo has an instance variable of type bar ; --> foo depends on bar ; The type attribute is for distinguishing those cases. ; In more detail, the type of an instance variable can be ; defined by a constructor call inside a resource, or by ; injecting it from outside. DOJO-DEP-API is for the latter ; case. ; Dependency to the same resource, but with different type ; and origin may exist. ; ; One can store the information "foo depends on bar" on ; the one hand, and the information "bar is needed by ; foo" on the other hand. Both cases are handled ; using this struct; the source (foo in the former case, ; bar in the latter case) is not part of this struct, ; but part of the map containing the dojo-dependency. ; Only the destination is stored in dojo-dependency ; instances. (cl-defstruct (dojo-dependency (:constructor nil) (:constructor construct-dojo-dependency (resource-id type origin))) ; Resource-id of the dependency, as described above resource-id ; Kind of dependency. type ; Resource-id which triggered setting up the dependency. ; For DOJO-DEP-IMPORT, the resource which contains the import ; statement / which contains the instance variable. ; For DOJO-DEP-API, the resource whose scan triggered setting up the dependency. ; E.g., origin) (defvar DOJO-DEP-IMPORT) ; Dependency enforced by import. This also covers instance ; variables set up by "new Foo()" statements, since they ; always have an import as counterpart. (defvar DOJO-DEP-API) ; Dependency enforced by using the API of some resource from outside. ; E.g., if the PageChooser inserts the ApplicationContext into the ; AboutPage, the AboutPage receives an API dependency to ; ApplicationContext. (defvar DOJO-DEPTYPE-STRING-MAP (make-hash-table :test 'equal)) (puthash "DOJO-DEP-IMPORT" 'DOJO-DEP-IMPORT DOJO-DEPTYPE-STRING-MAP) (puthash "DOJO-DEP-API" 'DOJO-DEP-API DOJO-DEPTYPE-STRING-MAP) ; dojo-assignments represent assignments between dojo-symbols. E.g., for an assignment ; a.b = c.d, in dojo-symbol b, a dojo-assignment towards c.d might be stored. ; They refer to the ids of the dojo-symbols and dojo-classes at hand, not to the references. ; This is to avoid trouble with garbage collection. If the symbol an assignment refers to ; has been deleted in the meantime, we can just silently delete the assignment. However, if ; we would use the reference to the dojo-symbol here, this dojo-assignment would prevent ; garbage collection of the dojo-symbol. ; ; Together with the source and destination of the assignment, we store in which dojo-class at which ; time the assignment was derived. This allows for deciding wether an particular assignment ; is still up-to-date. (cl-defstruct (dojo-assignment (:constructor nil) (:constructor construct-dojo-assignment (source-symbol-id dest-symbol-id scan-id))) ; Reference to the source of the assignment (i.e. the corresponding dojo-symbol id) source-symbol-id ; Reference to the destination of the assignment (i.e. the corresponding dojo-symbol id) dest-symbol-id ; Class the source symbol is located in source-class-id ; Class the dest symbol is located in dest-class-id ; nil, if the assignment may be removed as soon as a type for the source-symbol is known, ; t if the assignment must be kept even if the type(s) are known. ; The latter case especially applies to assignments between different dojo-classes. permanent ; Scan in which the assignment was recorded scan-id) (defvar DOJO-WORKSTATE-IDLE) ; No work. (defvar DOJO-WORKSTATE-SCAN) ; Scanning the workspace, finding out which resources exist (defvar DOJO-WORKSTATE-IMPORTS) ; Deriving imports in a heuristic manner (defvar DOJO-WORKSTATE-PLAN-EXTRACT) ; Decide, in which order the resources should be extracted (defvar DOJO-WORKSTATE-DO-EXTRACT) ; Do the resource extraction (defvar DOJO-WORKSTATE-SAVE) ; Save anything which needs to be saved (defvar DOJO-WORKSTATE-DEFAULT-ORDER (list 'DOJO-WORKSTATE-SCAN 'DOJO-WORKSTATE-IMPORTS 'DOJO-WORKSTATE-PLAN-EXTRACT 'DOJO-WORKSTATE-DO-EXTRACT 'DOJO-WORKSTATE-SAVE)) (defvar DOJO-WORKSTATE-STRING-MAP (make-hash-table :test 'equal)) (puthash "DOJO-WORKSTATE-IDLE" 'DOJO-WORKSTATE-IDLE DOJO-WORKSTATE-STRING-MAP) (puthash "DOJO-WORKSTATE-SCAN" 'DOJO-WORKSTATE-SCAN DOJO-WORKSTATE-STRING-MAP) (puthash "DOJO-WORKSTATE-IMPORTS" 'DOJO-WORKSTATE-IMPORTS DOJO-WORKSTATE-STRING-MAP) (puthash "DOJO-WORKSTATE-PLAN-EXTRACT" 'DOJO-WORKSTATE-PLAN-EXTRACT DOJO-WORKSTATE-STRING-MAP) (puthash "DOJO-WORKSTATE-DO-EXTRACT" 'DOJO-WORKSTATE-DO-EXTRACT DOJO-WORKSTATE-STRING-MAP) (puthash "DOJO-WORKSTATE-SAVE" 'DOJO-WORKSTATE-SAVE DOJO-WORKSTATE-STRING-MAP) (cl-defstruct (dojo-workstate (:constructor nil) (:constructor construct-dojo-workstate (work-fct last-exec-utcseconds next-exec-utcseconds))) (work-fct nil) (last-exec-utcseconds nil) (next-exec-utcseconds nil) (state nil)) (defvar DOJO-SAVESTATE-API) ; Workstate SAVE saves api classes (when it runs next time) (defvar DOJO-SAVESTATE-CLASSES) ; Workstate SAVE saves the indiviual classes xmls (when it runs next time) (defvar DOJO-SAVESTATE-DEPENDENCIES) ; Workstate SAVE saves the dependency.xmls (when it runs next time) (defvar DOJO-SAVESTATE-RESOURCES) ; Workstate SAVE saves resource xmls (when it runs next time) (cl-defstruct (dojo-workspace (:constructor nil) (:constructor dojo-workspace--create ())) ;; Current work state. (work-state 'DOJO-WORKSTATE-IDLE) (exec-map (make-hash-table :test 'equal)) ;; Sorted list of all project names in the dojo-workspace-path. (project-names ()) ;; Name of the last project the scan for existing resources started with. ;; Will be set to nil, if the scan terminates without being interrupted by ;; the user. ;; See last-scanned-tokens for the position inside the project. (last-scanned-project nil) ;; Last path the scan for existing resources inspected, as a list of ;; Will be set to nil, if the scan terminates without being interrupted by ;; the user. ;; directory path tokens relative to the webapp directory of the project. (last-scanned-tokens nil) ;; The sum of last-ast-time and last-parse-time of all js resource extractions. ;; I.e., initially the sum as loaded from resource xmls is calculated, then ;; subsequently on each extraction, the corresponding time is added to this ;; variable. ;; See also total-extract-size and total-extract-count. ;; The sense of this variables is to be able to get a notion of, how long ;; does an extraction per size last in average. This way, we can try an ;; estimation how aggressive (in terms of input just done by the user) we ;; should trigger future extractions. (total-js-extract-time 0) ;; The same as total-extract-time, just for resource sizes. (total-js-extract-size 0) ;; The same as total-extract-time, just the count of considered resource ;; extractions. (total-js-extract-count 0) ;; t if and only if a new scan of the workspace is to be performed. (workspace-scan-pending t) ;; t if and only if a previous scan of the workspace was interrupted ;; (by user-input, detected via (input-pending-p)), and may be continued. (workspace-scan-interrupted nil) ;; Timestamp the last workspace scan completed (successfully, i.e. without ;; being interrupted by the user) (last-scan-utcseconds nil) ;; Timestamp the last extraction of the own class completed successfully. (last-extract-own-utcseconds nil) ;; Timestamp the last extraction of referenced classes completed successfully. (last-extract-referenced-utcseconds nil) ;; Timestamp when the last extraction of classes scheduled for extraction ;; ended successfully. (last-extract-utcseconds nil) ;; Timestamp when the last extraction of imports in a heuristic manner ;; (scan whole workspace in a quick, heuristic, manner) has ended ;; successfully. (last-extract-imports-utcseconds nil) ;; Timestamp when extraction of resources was last planned. ;; See (dojo-core-workspace-derive-own-resources-to-parse). (last-plan-extract-utcseconds nil) ;; Timestamp the class-ids-to-save where saved last. ;; See also dojo-save-classes-interval. (last-save-api-utcseconds nil) (last-save-classes-utcseconds nil) (last-save-dependencies-utcseconds nil) (last-save-resources-utcseconds nil) (last-garbage-collect-utcseconds nil) (garbage-collection-pending nil) ;; Id of the current scan. (curr-scan-id 0) ;; AST derived for a resource parse. Only set if we aborted the workspace ;; processing function due to input or time exhaustion after setting up the ;; AST and before interpreting it. (curr-parse-ast nil) ;; The affected resource in the case described above for curr-parse-ast. (curr-parse-resource nil) ;; Wether we should extract our own class from the js2-mode-ast next time ;; we have the opportunity to do so. (own-class-extraction-pending t) ;; Wether we should try to extract the referenced classes next time ;; we have the opportunity to do so. Note that this first triggers the checks ;; wether some referenced classes need to be parsed / extracted. I.e., ;; if nothing changes with the referenced classes, the corresponding step ;; should perform the aforementioned checks, but not re-parse and re-extract ;; the referenced classes. (referenced-extraction-pending t) (extraction-pending t) (extract-imports-pending t) (plan-extract-pending t) ; Resource ids where extraction of imports is to be performed. ; Once the workspace scan decides that imports should be ; extracted, this map will be initialized, and filled ; with the ids of all js resources. ; Import extraction will then process all of them, and ; remove processed ones from the set. Once the set is empty, ; import extraction ends, and this reference will be set back to nil. (extract-import-resource-ids nil) ;; Wether we should save contents of the class-ids-to-save map next time ;; we have the opportunity to do so. (save-classes-pending t) ;; Maps resources that should be extracted in the near future to t, i.e. works ;; like a set of such resources. Resources are identified by strings "project/path". (pending-extractions (make-hash-table :test 'equal)) ;; Contains entries for all resources that are registered for future extraction ;; (i.e. for future parsing). The keys are resource-ids, the values hashtables ;; from priority to counts, how often the resource was requested with that ;; particular priority. ;; ;; Priority works as follows: The currently opened resource gains priority 1. ;; A resource required by that resource (e.g. some import) gains priority 2. ;; An import of such an import gains priority 3. And so on. ;; This way, we distribute lower priority, the farer away a resource is in terms ;; of "needed by" from the currently opened resource. ;; ;; As resources can be imported and used by many other resources, we can reach ;; (in the sense of 'required by') a resource on many different ways. Thus, we ;; also keep track how often a particular resource was needed, in order to be ;; able to prioritize resources that are needed often, and thus seem to be 'central' ;; in some sense. (resource-to-priority-to-count (make-hash-table :test 'equal)) ;; Contains the same data as resource-to-priority-to-count, but maps priorities ;; to hashtables from resource to count. (priority-to-resource-to-count (make-hash-table :test 'equal)) ;; Maximum priority, for which currently a resource is registered in the maps above. (max-priority 0) ;; While extracting a class: The current priority, i.e. the priority the resource had ;; in the priority maps when dojo-core-workspace-choose-extract-resource chose to ;; extract it. curr-priority ;; Map from paths (given like in Dojo import lists) to lists of their ;; corresponding dojo-resource structures. (path-to-resources (make-hash-table :test 'equal)) ;; Map from project names to lists of css resources in the project. (project-to-css-resources (make-hash-table :test 'equal)) ;; During workspace scan, all resources we processed so far in the *current* project. ;; Once the scan completes a particular project, these resources form the resources.xml ;; file being written for that project. ;; The reason why this list exists is efficiency; otherwise for each such file, we would ;; have to iterate over the whole path-to-resources map. (curr-scan-project-resources nil) ;; Map from file paths to lists (project path), as returned by ;; dojo-get-project-and-path. (file-path-to-path-info (make-hash-table :test 'equal)) ;; The next not yet used id for dojo-scans (next-free-scan-id 0) ;; Contains at least all scans of dojo-classes, whose results are still valid. (id-to-scan (make-hash-table :test 'equal)) (next-free-project-id 0) (id-to-project (make-hash-table :test 'equal)) (name-to-project (make-hash-table :test 'equal)) (next-free-resource-id 0) (id-to-resource (make-hash-table :test 'equal)) (resource-id-to-project (make-hash-table :test 'equal)) ;; Vector of all dojo-java-classes in the workspace, sorted by qualified name. (java-classes-sorted-by-qualified-name nil) ;; Vector of all dojo-java-classes in the workspace, sorted by name (java-classes-sorted-by-name nil) ;; Sorted vector with all unqualified java class names found in the workspace (java-class-names nil) (java-class-indices nil) ;; The next not yet used id for dojo-classes. (next-free-class-id 0) ;; Contains entries for all dojo-classes in this dojo-workspace. ; (id-to-class (make-hash-table :test 'equal :weakness 'value)) (id-to-class (make-hash-table :test 'equal)) ;; The next not yet used id for dojo-symbols (next-free-symbol-id 0) ;; Contains entries for all dojo-symbols in this dojo-workspace ;; The weakness is set to 'value, to avoid storing a lot of ;; outdated symbols from previous parsing operations here. Thus, ;; the goal is that symbols disappear from this map, once the ;; corresponding dojo-class etc. was garbage-collected and replaced ;; by a newer version. Removing those symbols manually wouldn't ;; be that easy. ; (id-to-symbol (make-hash-table :test 'equal)) ; (id-to-symbol (make-hash-table :test 'equal :weakness 'value)) ;; The next not yet used id for dojo-scopes. (next-free-scope-id 0) ;; Contains entries for all dojo-scopes in this dojo-workspace ; (id-to-scope (make-hash-table :test 'equal)) ;; Here, the ids of all symbols whose type was touched during the current class extraction are stored. ;; The idea is, that afterwards, starting at these symbols, other symbol types can be derived by ;; following the assignments. (dirty-symbol-ids (make-hash-table :test 'equal)) ;; Ids of the dojo-class instances that need to be saved. Mapped to ;; the utcseconds when the id was last registered in the map. ;; Background: To avoid saving files too often, we don't immediately ;; save the class xml files when a class has been parsed / has changed, ;; but do this some time later, and more seldom. ;; Obviously, this data doesn't need to be saved. (class-ids-to-save (make-hash-table :test 'equal)) ;; Map from class ids to dojo-class instances representing the public API (id-to-api-class (make-hash-table :test 'equal)) ;; Map from projects to maps storing dependencies. ;; Those maps have class-ids as keys, and lists of dojo-dependencies ;; as values. E.g., if PageChooser imports ApplicationContext, ;; an entry is ;; stored in such a map. (project-to-dep-maps (make-hash-table :test 'equal)) ;; Map from projects to inverse dependency maps. ;; Those maps have class-ids as keys, and lists of dojo-dependencies ;; as values, and store which class has a dependency to a class at hand. ;; E.g., if PageChooser imports ApplicationContext, an entry ;; is stored in ;; such a map. (project-to-inverse-dep-maps (make-hash-table :test 'equal)) ;; Projects where the dependency maps need to be saved (dirty-dep-projects (make-hash-table :test 'equal)) ;; Map from projects to maps containing the public API of that project. (path-key-to-id-to-api-class (make-hash-table :test 'equal)) ;; Path keys (i.e. project:path) for paths whose API files need to be saved (dirty-api-path-keys (make-hash-table :test 'equal)) ;; Project names for which the corresponding resources.xml needs to ;; be saved. (resource-projects-to-save (make-hash-table :test 'equal)) ;; Map from project names to (possibly unparsed) blueprint ;; services.xml file resources. (project-to-services-resource (make-hash-table :test 'equal)) ) (defun construct-dojo-workspace () (let* ((workspace (dojo-workspace--create)) (exec-map (dojo-core-workspace-construct-exec-map))) (setf (dojo-workspace-exec-map workspace) exec-map) workspace)) ;(defun dojo-workspace-register-in-assignment (workspace assignment level) ; (let* ((dest-symbol-id (dojo-assignment-dest-symbol-id assignment)) ; (dest-class-id (dojo-assignment-dest-class-id assignment)) ; (dest-class (gethash dest-class-id (dojo-workspace-id-to-class workspace))) ; (in-assignment-map (if dest-class (dojo-class-in-assignment-map dest-class) nil)) ; (in-assignments (if in-assignment-map (gethash dest-symbol-id in-assignment-map) nil)) ; (already-existing nil)) ; ; TODO: Maybe make this more efficient (linear loop over in-assignments) ; ; (if (null dest-class) ; (log-assign level (format "[WARNING] Did not find dest-class [%s]" dest-class-id)) ; (dojo-core-util-mark-class-needed dest-class) ; (dolist (in-assignment in-assignments) ; (if (and (= (dojo-assignment-source-symbol-id in-assignment) (dojo-assignment-source-symbol-id assignment)) ; (= (dojo-assignment-dest-symbol-id in-assignment) (dojo-assignment-dest-symbol-id assignment))) ; (progn ; (setf (dojo-assignment-scan-id in-assignment) (dojo-assignment-scan-id assignment)) ; (log-assign level (format "REGISTERING in-assignment for symbol [%s], starting at symbol [%s], reusing existing assignment." ; (dojo-assignment-dest-symbol-id assignment) (dojo-assignment-source-symbol-id assignment))) ; (setq already-existing t)))) ; (if (not already-existing) ; (progn ; (push assignment in-assignments) ; (log-assign level (format "REGISTERING in-assignment for symbol [%s], starting at symbol [%s], adding new assignment." ; (dojo-assignment-dest-symbol-id assignment) (dojo-assignment-source-symbol-id assignment))) ; (puthash dest-symbol-id in-assignments in-assignment-map)))))) ; ;(defun dojo-workspace-register-out-assignment (workspace assignment level) ; (let* ((source-symbol-id (dojo-assignment-source-symbol-id assignment)) ; (source-class-id (dojo-assignment-source-class-id assignment)) ; (source-class (gethash source-class-id (dojo-workspace-id-to-class workspace))) ; (out-assignment-map (if source-class (dojo-class-out-assignment-map source-class) nil)) ; (out-assignments (if out-assignment-map (gethash source-symbol-id out-assignment-map) nil)) ; (already-existing nil)) ; ; TODO: Maybe make this more efficient (linear loop over out-assignments) ; ; (if (null source-class) ; (log-assign level (format "[WARNING] Did not find source-class for class-id [%s]" source-class-id)) ; (dojo-core-util-mark-class-needed source-class) ; (dolist (out-assignment out-assignments) ; (if (and (= (dojo-assignment-source-symbol-id out-assignment) (dojo-assignment-source-symbol-id assignment)) ; (= (dojo-assignment-dest-symbol-id out-assignment) (dojo-assignment-dest-symbol-id assignment))) ; (progn ; (setf (dojo-assignment-scan-id out-assignment) (dojo-assignment-scan-id assignment)) ; (log-assign level (format "REGISTERING out-assignment for symbol [%s], to symbol [%s], reusing existing assignment." ; (dojo-assignment-source-symbol-id assignment) (dojo-assignment-dest-symbol-id assignment))) ; (setq already-existing t)))) ; (if (not already-existing) ; (progn ; (push assignment out-assignments) ; (puthash source-symbol-id out-assignments out-assignment-map) ; (log-assign level (format "REGISTERING out-assignment for symbol [%s], to symbol [%s], adding new assignment." ; (dojo-assignment-source-symbol-id assignment) (dojo-assignment-dest-symbol-id assignment))) ; (puthash source-symbol-id out-assignments out-assignment-map)))))) (defun dojo-workspace-get-resource (workspace project path) (let* ((path-to-resources (dojo-workspace-path-to-resources workspace)) (resources (gethash path path-to-resources)) (found-resource nil) ) (if (null resources) (setq found-resource nil) (dolist (resource resources) (if (or (null project) (string= (dojo-resource-project resource) project)) (progn (setq found-resource resource) (return nil) ) ) ) ) found-resource ) ) (defun dojo-workspace-register-dirty-symbol (dirty-symbol) (let ((dirty-symbol-ids (dojo-workspace-dirty-symbol-ids dojo-current-workspace)) (dirty-symbol-id (if (dojo-symbol-p dirty-symbol) (dojo-symbol-id dirty-symbol) dirty-symbol))) (puthash dirty-symbol-id t dirty-symbol-ids))) (defun dojo-workspace-get-class (workspace project path) (let* ((resource (dojo-workspace-get-resource workspace project path))) ; (log-workspace (format "Queried resource [%s]" resource)) (let* ((state (if resource (dojo-resource-state resource) nil)) (type (if resource (dojo-resource-type resource) nil))) (if (and (or (string= state "parsed") (string= state "derived")) (dojo-core-workspace-is-any-js-resource resource)) (let* ((class-id (dojo-resource-parsed-id resource)) (id-to-class (dojo-workspace-id-to-class workspace))) (if (null class-id) nil (gethash class-id id-to-class))) nil)))) ; 14.9.1 Sorting Lists ; 24.9 Contents of directory ; 31.25 Checksum/Hash (defun construct-dojo-api-class (workspace resource-id project path) (construct-dojo-class workspace resource-id project path t)) (defun construct-dojo-class (workspace resource-id project path &optional is-api) (let ((class (dojo-class--create)) (id-to-class (if is-api (dojo-workspace-id-to-api-class workspace) (dojo-workspace-id-to-class workspace)))) (setf (dojo-class-id class) (dojo-workspace-next-free-class-id workspace)) (setf (dojo-class-is-api-class class) is-api) (setf (dojo-class-resource-id class) resource-id) (setf (dojo-class-project class) project) (setf (dojo-class-path class) path) (incf (dojo-workspace-next-free-class-id workspace)) (dojo-core-util-mark-class-needed class) (puthash (dojo-class-id class) class id-to-class) (log-assign 0 (format "Constructed class [%s%s] with project [%s] and path [%s]" (dojo-class-id class) (if is-api " API" "") (dojo-class-project class) (dojo-class-path class))) class)) (defun construct-transient-dojo-class (workspace class-id resource-id project path) (let ((class (dojo-class--create))) ; Maybe distribute temporary id -1 (or similar) ; (setf (dojo-class-id class) (dojo-workspace-next-free-class-id workspace)) (setf (dojo-class-id class) class-id) (setf (dojo-class-resource-id class) resource-id) (setf (dojo-class-project class) project) (setf (dojo-class-path class) path) (setf (dojo-class-transient class) t) ; TODO dojo-core-util-mark-class-needed? ; (incf (dojo-workspace-next-free-class-id workspace)) ; (puthash (dojo-class-id class) class (dojo-workspace-id-to-class workspace)) (log-assign 0 (format "Constructed transient class [%s] with project [%s] and path [%s]" (dojo-class-id class) (dojo-class-project class) (dojo-class-path class))) class)) (defun dojo-core-api-get-class-by-id (workspace class-id) (gethash class-id (dojo-workspace-id-to-class workspace))) (defun dojo-core-api-get-or-create-member (workspace class name &optional type) "Returns a member with the given name from the given class. If such a symbol does not yet exist, it is created using construct-dojo-symbol, registered in member-to-symbol of the given class, and returned." (let* ((this-symbol (dojo-class-this-symbol class)) (member-to-symbol (dojo-symbol-get-object-members this-symbol)) (symbol (gethash name member-to-symbol))) (if symbol symbol (let* ((symbol (construct-dojo-symbol workspace class name type))) (puthash name symbol member-to-symbol) symbol)))) ;; Main i18n of the project; magic constant for the locale-to-i18n-resource map (defvar DOJO-PROJECT-I18N-MAIN "main") ;; Main css of the project; magic constant for the css-resources map (defvar DOJO-PROJECT-CSS-MAIN "main") ;; Information about a project in workspace. Projects are identified by ;; the directory level below the top workspace level. (cl-defstruct (dojo-project (:constructor nil) (:constructor dojo-project--create ())) ;; Unique, numeric, id of the project id ;; Name of the project, i.e. the directory name below the workspace level name ;; Flag indicating that this is a Dojo Js project is-js-dojo-project ;; Map from locales to the i18n resource ids matching those locales. ;; The main i18n resource of a Dojo project can additionally be found under the key ;; DOJO-PROJECT-I18N-MAIN (i.e. 'main') (locale-to-i18n-resource (make-hash-table :test 'equal)) ;; Map containing the resource ids of all CSS resources in the project. ;; One CSS file per project can be marked as main, it can be stored ;; in this map under the magic key DOJO-PROJECT-CSS-MAIN. (css-resources (make-hash-table :test 'equal)) ;; Id of the resource corresponding to the pom.xml of the project pom-resource-id ;; Id of the resource corresponding to a potential blueprint services.xml file blueprint-resource-id ;; Blueprint file as parsed by blueprint-parse; transient and not permanently stored. blueprint-file ;; Id of the resource corresponding to a potential datamodel.xml of the project datamodel-resource-id ;; Number of seconds needed when saving the api.xml last time last-save-api-time ;; Number of seconds needed when saving the dependencies.xml last time last-save-dep-time ;; Number of seconds needed when saving the resources.xml last time last-save-resources-time ;; If it exists, the full file system path src/main/resource/OSGI-INF/webapp ;; Not yet saved in workspace.xml webapp-path ) (defun construct-dojo-project (name) (let ((project (dojo-project--create))) (setf (dojo-project-id project) (dojo-workspace-next-free-project-id dojo-current-workspace)) (setf (dojo-project-name project) name) (incf (dojo-workspace-next-free-project-id dojo-current-workspace)) (puthash (dojo-project-id project) project (dojo-workspace-id-to-project dojo-current-workspace)) (puthash name project (dojo-workspace-name-to-project dojo-current-workspace)) project)) (cl-defstruct (dojo-resource (:constructor nil) (:constructor dojo-resource--create ())) id ;; State of the resource. ;; - "located" means, that the resource was located while ;; scanning the projects, but not yet parsed ;; (i.e., parsed-id is nil) ;; - "parsed" means, that it is also parsed. ;; - "derived" means, that not really the resource was ;; parsed, but while parsing some other ;; resource, it was derived that the resource ;; exists, and it was necessary to construct it. ;; E.g. something like 'dojo.behaviour = new Behaviour();' ;; while parsing dojo/behaviour. ;; - "parse-failed" means that an attempt to parse the resource ;; was made, but failed, e.g. because some Lisp ;; error was emitted (state nil) ;; Timestamp when the resource was last located while scanning the projects. (last-located-utc-seconds nil) ;; Timestamp when the resource was last parsed. ;; Used in particular for deciding wether a resource *not* in the current buffer is to ;; be reparsed (i.e. we compare against the last file modification timestamp for those) (last-parsed-utc-seconds nil) ;; Result of (buffer-size) at last parse of resource. ;; Used in particular for deciding wether (current-buffer) needs to be reparsed. In ;; that case, with frequent modifications the user doesn't save immediately, file ;; modification timestamp doesn't seem to be that reliable for deciding wether changes ;; to be changed have happened. In contrast, most edits will change the buffer size. (last-parsed-size nil) ;; Time (in seconds) the last extraction of the AST using js2-mode needed. ;; Measured in terms of current (float-time), may be subject to any kind of ;; influences from the system. (last-ast-time nil) ;; Time (in seconds) the last extraction of the class needed. Measured in terms of ;; current (float-time), may be subject to any kind of influences from the system. (last-parse-time nil) ;; md5 hash of the file contents when they where parsed last. (file-hash nil) ;; Id of the last scan that located the resource. (last-scan-id nil) ;; Kind of resource, for now only "js" for Javascript is supported. (type nil) ;; Id pointing to the parsed content of this resource. ;; For Javascript, this points to a dojo-class, i.e. it ;; is a class-id in the sense of dojo-workspace-id-to-class. (parsed-id nil) ;; Name of the project the resource is located in. (project nil) ;; Path of the resource. For Javascript, the import path as used in Dojo imports. (path nil) ;; The complete file name path, i.e. the path in the sense of the file system. (file-path nil) (annotations ()) ;; Flag indicating that a resource corresponding to a non-current buffer was already ;; checked with respect to a potential necessary extraction. Once the buffer ;; becomes current, this flag needs to be cleared. ;; transient, the flag is not stored in resources.xml (extraction-checked nil) ) (defun construct-dojo-resource (workspace) (let ((resource (dojo-resource--create))) (setf (dojo-resource-id resource) (dojo-workspace-next-free-resource-id workspace)) (incf (dojo-workspace-next-free-resource-id workspace)) (puthash (dojo-resource-id resource) resource (dojo-workspace-id-to-resource workspace)) resource)) (cl-defstruct (dojo-scan (:constructor dojo-scan--create)) ; Id of the scan id ; Id of the class processed in this scan class-id ; Time when we started processing the class start-utcseconds ; Time when we finished processing the class end-utcseconds ; Convenience attribute, saving end-utcseconds - start-utcseconds, ; in order to be able to easily inspect the length of scans in the xml file. length ; t if and only if the result of this scan was already discarded. ; This most probably happens if the class is processed again at ; a later time, which results in overwriting/replacing the former ; results. (discarded nil)) (defun construct-dojo-scan (workspace) (let ((scan (dojo-scan--create))) (setf (dojo-scan-id scan) (dojo-workspace-next-free-scan-id workspace)) (incf (dojo-workspace-next-free-scan-id workspace)) (puthash (dojo-scan-id scan) scan (dojo-workspace-id-to-scan workspace)) scan)) (defun copy-dojo-resource (source target) (setf (dojo-resource-state target) (dojo-resource-state source)) (setf (dojo-resource-last-located-utc-seconds target) (dojo-resource-last-located-utc-seconds source)) (setf (dojo-resource-last-parsed-utc-seconds target) (dojo-resource-last-parsed-utc-seconds source)) (setf (dojo-resource-last-parsed-size target) (dojo-resource-last-parsed-size source)) (setf (dojo-resource-file-hash target) (dojo-resource-file-hash source)) (setf (dojo-resource-last-scan-id target) (dojo-resource-last-scan-id source)) (setf (dojo-resource-type target) (dojo-resource-type source)) (setf (dojo-resource-parsed-id target) (dojo-resource-parsed-id source)) (setf (dojo-resource-project target) (dojo-resource-project source)) (setf (dojo-resource-path target) (dojo-resource-path source)) (setf (dojo-resource-file-path target) (dojo-resource-file-path source)) ) (defun dojo-get-symbol-by-path (base-symbol path start-index) "Given a path of symbol names, and a start index inside this path, and a base symbol, this function returns the symbol corresponding to the last element of the path. If the path is too short, the base-symbol is returned. Otherwise, the symbol name found at start-index in the path is assumed to be found inside the base symbol. If one cannot follow the path along object symbols (or similar symbols) until this point, nil is returned." ; TODO Dive down symbol path - will fix completing symbol chains A.B.foo (if (> (length path) start-index) (let* ((searched-symbol (nth start-index path)) ) nil ) base-symbol ) ) (defun dojo-get-symbol-from-scopes (scopes searched-symbol-name) "Searches for a symbol with the given name in the given list of scopes. The innermost scope is expected to come first in the list. Returns nil if no such symbol can be found in any of the scopes, otherwise the symbol from the first (innermost) scope containing such a symbol (multiple scopes can contain symbols with the same name, shadowing each other)." (let* ((found-symbol nil) ; searched-symbol-name can be a path like "ErrorHelper.p". ; We need to locate the outermost symbol (here ErrorHelper) in ; the scopes, and dive down accordingly. (path-tokens (split-string searched-symbol-name "\\.")) (first-searched-symbol-name (nth 0 path-tokens)) ) (dolist (scope scopes) (let* ((name-to-symbol (dojo-scope-name-to-symbol scope)) (symbol-names (hash-table-get-all-keys name-to-symbol)) ) (dolist (symbol-name symbol-names) (if (string= symbol-name first-searched-symbol-name) (progn (let* ((base-symbol (gethash first-searched-symbol-name name-to-symbol)) ) (setq found-symbol (dojo-get-symbol-by-path base-symbol path-tokens 1)) ) (return nil) ) ) ) ) (if found-symbol (return nil) ) ) found-symbol ) ) (cl-defstruct (dojo-indent-scan-state (:constructor nil) (:constructor construct-dojo-indent-scan-state ())) ; Custom state attribute, which allows for storing scan-dependent information, something like "we have passed a dot". ; During the initial backward scan: END_OF_LINE_SECTION while we are in the section between a newline / final comment start, ; and the last non-whitespace character of the line, nil otherwise (state nil) ; The current nesting level of round brackets. Each closing round bracket increases the level, each opening round bracket decreases it. (round-bracket-level 0) ; The current nesting level of square brackets. Each closing square bracket increases the level, each opening square bracket decreases it. (square-bracket-level 0) ; The current nesting level of curly brackets. Each closing curly bracket increases the level, each opening curly bracket decreases it. (curly-bracket-level 0) ; True if and only if the very last scanned character was a slash "/". Needed for detecting comments properly. (slash-found nil) ; The number of lines the scan moved upwards so far. (number-of-lines 0) ; The position of the first non-whitespace character in the line to indent. (start-position nil) ; The position after the end of code of the current line. Can be the start of the last comment of the line, or the newline character terminating the line. (end-of-line-code-position nil) ; The very first non-whitespace character of the line to be indented. (start-char nil) ; Column of the leftmost colon in the current line (up to the current scan position) (first-colon-column nil) ; Initial backward scan: The final non-whitespace, non-comment and non-newline character of the line before the scan starts ; Used for detection, wether we are in the first line of the current expression, or somewhere further down. (last-prev-line-char nil) ; Forward-scan: The position of the first non-whitespace character on the line (line-start-pos nil) ; Length of the leftmost member name in the current line (up to the current scan position). ; The sequence of text, starting with a colon, until a previous space or tab followed ; by a non-space/whitespace is considered a member name here. (first-member-name-length 0) ; Maximum length of what looks like an object member name (i.e. "foo" in "foo : bar"). ; Only the leftmost colon of a line will be considered. Also, the decision wether we ; consider the text we see really a object definition is delayed until we parse a ; possible opening curly brace. (max-member-name-length 0) ) (cl-defstruct (dojo-inspect-token (:constructor nil) (:constructor construct-dojo-inspect-token (node symbol))) ;; The js2-node of the corresponding position in the ancestor-path node ;; The symbol representing that node. May be nil. symbol ;; An additional hint not (yet) represented by any symbol. ;; In the case of inspecting something like 'i18n.foo', with ;; 'foo' being not yet a defined member of 'i18n', this will be ;; the string 'foo'. This enables subsequent code to add a new ;; i18n.foo symbol. hint) (defun dojo-class-get-path-for-import-symbol (name class) "Returns the path for the given import symbol name of the given class. Example: If 'foo/bar' is imported as 'Bar', this function answers the argument 'Bar' by returning 'foo/bar'." (let* ((import-to-symbol (dojo-class-import-to-symbol class)) (import-symbol (gethash name import-to-symbol)) (import-path (if import-symbol (dojo-symbol-get-import-path import-symbol) nil)) ) import-path ) ) (defun construct-dojo-symbol-array (workspace class-id name &optional value-type) (let* ((symbol (construct-dojo-symbol workspace class-id name 'DOJO-JSTYPE-ARRAY)) (details (dojo-symbol-details symbol))) (setf (dojo-array-value-type details) value-type) symbol)) (defun construct-dojo-symbol-array-or-object (workspace class-id name &optional key-type value-type) (let* ((symbol (construct-dojo-symbol workspace class-id name 'DOJO-JSTYPE-ARRAY-OR-OBJECT)) (details (dojo-symbol-details symbol))) (setf (dojo-object-key-type details) key-type) (setf (dojo-object-value-type details) value-type) symbol)) (defun construct-dojo-symbol-function (workspace class-id name &optional arguments return-type) (let* ((symbol (construct-dojo-symbol workspace class-id name 'DOJO-JSTYPE-FUNCTION)) (details (dojo-symbol-details symbol))) (setf (dojo-function-arguments details) arguments) (setf (dojo-function-return-type details) return-type) symbol)) (defun construct-dojo-symbol-import (workspace class-id name &optional resource-id type path) (let* ((symbol (construct-dojo-symbol workspace class-id name 'DOJO-JSTYPE-IMPORT)) (details (dojo-symbol-details symbol))) (if (and (not (null resource-id)) (not (numberp resource-id))) (error "Wrong type of resource-id")) (setf (dojo-import-resource-id details) resource-id) (setf (dojo-import-type details) type) (setf (dojo-import-path details) path) symbol)) (defun construct-dojo-symbol-instance (workspace class-id name &optional resource-id type path) (let* ((symbol (construct-dojo-symbol workspace class-id name 'DOJO-JSTYPE-INSTANCE)) (details (dojo-symbol-details symbol))) ; The cases IMPORT and INSTANCE share struct dojo-import (if (and (not (null resource-id)) (not (numberp resource-id))) (error "Wrong type of resource-id")) (setf (dojo-import-resource-id details) resource-id) (setf (dojo-import-type details) type) (setf (dojo-import-path details) path) symbol)) (defun construct-dojo-symbol-object (workspace class-id name &optional key-type value-type) (let* ((symbol (construct-dojo-symbol workspace class-id name 'DOJO-JSTYPE-OBJECT)) (details (dojo-symbol-details symbol))) (setf (dojo-object-key-type details) key-type) (setf (dojo-object-value-type details) value-type) symbol)) (defun construct-dojo-symbol-ref (workspace class-id name &optional ref-type symbols) (let* ((symbol (construct-dojo-symbol workspace class-id name 'DOJO-JSTYPE-REF)) (details (dojo-symbol-details symbol))) (setf (dojo-ref-type details) ref-type) (setf (dojo-ref-symbols details) symbols) symbol)) (defun dojo-symbol-set-type (symbol type &optional register-dirty-symbol omit-if-unchanged) "Setter for dojo-symbol-type, which at the same time updates the dojo-symbol-details field." (if (or (not omit-if-unchanged) (not (eq (dojo-symbol-type symbol) type))) (progn (setf (dojo-symbol-type symbol) type) (dojo-symbol-init-details symbol) (if register-dirty-symbol (dojo-workspace-register-dirty-symbol symbol))))) (defun dojo-symbol-set-array-value-type (symbol value-type) (setf (dojo-array-value-type (dojo-symbol-details symbol)) value-type)) (defun dojo-symbol-get-array-value-type (symbol) (dojo-array-value-type (dojo-symbol-details symbol))) (defun dojo-symbol-set-array-or-object-key-type (symbol key-type) (setf (dojo-object-key-type (dojo-symbol-details symbol)) key-type)) (defun dojo-symbol-get-array-or-object-key-type (symbol) (dojo-object-key-type (dojo-symbol-details symbol))) (defun dojo-symbol-set-array-or-object-value-type (symbol value-type) (setf (dojo-object-value-type (dojo-symbol-details symbol)) value-type)) (defun dojo-symbol-get-array-or-object-value-type (symbol) (dojo-object-value-type (dojo-symbol-details symbol))) (defun dojo-symbol-set-function-arguments (symbol arguments) (setf (dojo-function-arguments (dojo-symbol-details symbol)) arguments)) (defun dojo-symbol-get-function-arguments (symbol) (dojo-function-arguments (dojo-symbol-details symbol))) (defun dojo-symbol-set-function-return-type (symbol ret-symbol) (setf (dojo-function-return-type (dojo-symbol-details symbol)) ret-symbol)) (defun dojo-symbol-get-function-return-type (symbol) (dojo-function-return-type (dojo-symbol-details symbol))) (defun dojo-symbol-set-function-builtin-fct (symbol builtin-fct) (setf (dojo-function-builtin-fct (dojo-symbol-details symbol)) builtin-fct)) (defun dojo-symbol-get-function-builtin-fct (symbol) (dojo-function-builtin-fct (dojo-symbol-details symbol))) (defun dojo-symbol-set-function-scope (symbol scope) (setf (dojo-function-scope (dojo-symbol-details symbol)) scope)) (defun dojo-symbol-get-function-scope (symbol) (dojo-function-scope (dojo-symbol-details symbol))) (defun dojo-symbol-set-import-resource-id (symbol resource-id) (if (and (not (null resource-id)) (not (numberp resource-id))) (error "Wrong type of resource-id")) (setf (dojo-import-resource-id (dojo-symbol-details symbol)) resource-id)) (defun dojo-symbol-get-import-resource-id (symbol) (dojo-import-resource-id (dojo-symbol-details symbol))) (defun dojo-symbol-set-import-type (symbol type) (setf (dojo-import-type (dojo-symbol-details symbol)) type)) (defun dojo-symbol-get-import-type (symbol) (dojo-import-type (dojo-symbol-details symbol))) (defun dojo-symbol-set-import-path (symbol path) (setf (dojo-import-path (dojo-symbol-details symbol)) path)) (defun dojo-symbol-get-import-path (symbol) (dojo-import-path (dojo-symbol-details symbol))) (defun dojo-symbol-set-object-key-type (symbol key-type) (setf (dojo-object-key-type (dojo-symbol-details symbol)) key-type)) (defun dojo-symbol-get-object-key-type (symbol) (dojo-object-key-type (dojo-symbol-details symbol))) (defun dojo-symbol-set-object-value-type (symbol value-type) (setf (dojo-object-value-type (dojo-symbol-details symbol)) value-type)) (defun dojo-symbol-get-object-value-type (symbol) (dojo-object-value-type (dojo-symbol-details symbol))) (defun dojo-symbol-get-object-member (name symbol) (let ((name-to-symbol (dojo-symbol-get-object-members symbol))) (gethash name name-to-symbol))) (defun dojo-symbol-get-object-members (symbol) (dojo-object-name-to-symbol (dojo-symbol-details symbol))) (defun dojo-symbol-set-object-members (symbol name-to-symbol) (setf (dojo-object-name-to-symbol (dojo-symbol-details symbol)) name-to-symbol)) (defun dojo-symbol-register-object-member (name member object-symbol) (let ((name-to-symbol (dojo-symbol-get-object-members object-symbol))) (if (and (dojo-symbol-p member) (or (not (eq (dojo-symbol-class-id member) (dojo-symbol-class-id object-symbol))) (not (eq (dojo-symbol-is-api-symbol member) (dojo-symbol-is-api-symbol object-symbol))))) (error (format "[Error] Attempt to register member-symbol in object-symbol, although class / is-api differ. Member %s, object %s" (dojo-core-util-symbol-to-short-string member) (dojo-core-util-symbol-to-short-string object-symbol)))) (puthash name member name-to-symbol) (setf (dojo-symbol-parent-id member) (dojo-symbol-id object-symbol)) (log-data (format "Registered [object %s %s].[member %s %s]" (dojo-symbol-id object-symbol) (dojo-symbol-name object-symbol) (dojo-symbol-id member) name)))) (defun dojo-symbol-remove-object-member (name object-symbol) (let ((name-to-symbol (dojo-symbol-get-object-members object-symbol))) (remhash name name-to-symbol))) (defun dojo-symbol-has-object-members (object-symbol) (let ((result nil) (name-to-symbol (dojo-symbol-get-object-members object-symbol))) (maphash (lambda (name symbol) (setq result t)) name-to-symbol) result)) (defun dojo-symbol-get-ref-type (symbol) (dojo-ref-type (dojo-symbol-details symbol))) (defun dojo-symbol-set-ref-type (symbol ref-type) (setf (dojo-ref-type (dojo-symbol-details symbol)) ref-type)) (defun dojo-symbol-get-ref-symbols (symbol) (dojo-ref-symbols (dojo-symbol-details symbol))) (defun dojo-symbol-set-ref-symbols (symbol ref-symbols) (setf (dojo-ref-symbols (dojo-symbol-details symbol)) ref-symbols)) (defun dojo-symbol-set-object-object-type (symbol object-type) (setf (dojo-object-object-type (dojo-symbol-details symbol)) object-type)) (defun dojo-symbol-get-object-object-type (symbol) (dojo-object-object-type (dojo-symbol-details symbol))) (defun dojo-symbol-set-object-object-info (symbol object-info) (setf (dojo-object-object-info (dojo-symbol-details symbol)) object-info)) (defun dojo-symbol-get-object-object-info (symbol) (dojo-object-object-info (dojo-symbol-details symbol))) (defun dojo-symbol-set-object-function-symbol (symbol function-symbol) (setf (dojo-object-function-symbol (dojo-symbol-details symbol)) function-symbol)) (defun dojo-symbol-get-object-function-symbol (symbol) (dojo-object-function-symbol (dojo-symbol-details symbol))) (defun dojo-class-set-this-symbol (class this-symbol) (dojo-symbol-set-object-object-type this-symbol 'DOJO-OBJECTTYPE-THIS) (setf (dojo-symbol-parent-id this-symbol) (dojo-class-id class)) (setf (dojo-class-this-symbol class) this-symbol)) (defun dojo-class-set-static-symbol (class static-symbol) (cond ((dojo-core-util-is-object-symbol static-symbol) (dojo-symbol-set-object-object-type static-symbol 'DOJO-OBJECTTYPE-STATIC) (setf (dojo-symbol-parent-id static-symbol) (dojo-class-id class)) ; Statements like 'Color.prototype.sanitize = function() {' trigger creation of ; an object symbol named 'prototype' inside the static-symbol of class Color. ; But Javascript semantics is, that such symbols belong into the this-symbol. ; Thus, here we check wether the passed static-symbol contains an object member ; named 'prototype', and if yes, we copy its contents to the this-symbol, and ; remove it from the static-symbol afterwards. (let* ((prototype-member (dojo-symbol-get-object-member "prototype" static-symbol)) (this-symbol (dojo-class-this-symbol class))) (if (and prototype-member (dojo-core-util-is-object-symbol prototype-member)) (progn (if (null this-symbol) (progn (setq this-symbol (construct-dojo-symbol-object dojo-current-workspace static-symbol "this")))) (let ((member-to-symbol (dojo-symbol-get-object-members prototype-member))) (dolist (name (hash-table-get-all-keys member-to-symbol)) (let ((symbol-in-prototype (gethash name member-to-symbol))) (dojo-symbol-register-object-member name symbol-in-prototype this-symbol)))) (setf (dojo-class-this-symbol class) this-symbol) (dojo-symbol-remove-object-member "prototype" static-symbol)))) (setf (dojo-class-static-symbol class) static-symbol)) ((dojo-core-util-is-instance-symbol static-symbol) (let* ((import-class (dojo-core-util-get-class-by-import-symbol dojo-current-workspace static-symbol)) (import-this-symbol (if import-class (dojo-class-this-symbol import-class) (log-assign 0 (format "[WARNING] Found no import-class for static-symbol %s" (dojo-core-util-symbol-to-short-string static-symbol))) nil))) (if import-this-symbol (progn (log-assign 0 (format "Switched to import-this-symbol [%s]" (dojo-core-util-symbol-to-short-string import-this-symbol))) (setf (dojo-class-static-symbol class) (dojo-core-util-clone-symbol import-this-symbol)))))))) (defun dojo-symbol-get-parent (workspace symbol) (let* ((class-id (dojo-symbol-class-id symbol)) (is-api-symbol (dojo-symbol-is-api-symbol symbol)) (id-to-class (if is-api-symbol (dojo-workspace-id-to-api-class workspace) (dojo-workspace-id-to-class workspace))) (class (gethash class-id id-to-class)) (id-to-symbol (dojo-class-id-to-symbol class)) (parent-id (dojo-symbol-parent-id symbol))) (if (null parent-id) nil (gethash parent-id id-to-symbol)))) (defun dojo-core-api-is-integral-type (type) (or (eq type 'DOJO-JSTYPE-NUMBER) (eq type 'DOJO-JSTYPE-INTEGER) (eq type 'DOJO-JSTYPE-LONG))) (defun dojo-core-api-is-numeric-type (type) (or (eq type 'DOJO-JSTYPE-NUMBER) (eq type 'DOJO-JSTYPE-INTEGER) (eq type 'DOJO-JSTYPE-LONG) (eq type 'DOJO-JSTYPE-FLOAT) (eq type 'DOJO-JSTYPE-DOUBLE))) (cl-defstruct (dojo-java-class (:constructor nil) (:constructor construct-dojo-java-class (qualified-name name resource-id))) qualified-name name resource-id) (defvar dojo-js-non-object-functions #s(hash-table test equal data ( ; Array properties "length" t "prototype" t ; Array methods "concat" t "copyWithin" t "entries" t "every" t "fill" t "filter" t "find" t "findIndex" t "forEach" t "from" t "includes" t "indexOf" t "isArray" t "join" t "keys" t "lastIndexOf" t "map" t "pop" t "push" t "reduce" t "reduceRight" t "reverse" t "shift" t "slice" t "some" t "sort" t "splice" t "toString" t "unshift" t "valueOf" t ; Date properties "getDate" t "getDay" t "getFullYear" t "getHours" t "getMilliseconds" t "getMinutes" t "getMonth" t "getSeconds" t "getTime" t "getTimezoneOffset" t "getUTCDate" t "getUTCDay" t "getUTCFullYear" t "getUTCHours" t "getUTCMilliseconds" t "getUTCMinutes" t "getUTCMonth" t "getUTCSeconds" t "getYear" t "now" t "parse" t "setDate" t "setFullYear" t "setHours" t "setMilliseconds" t "setMinutes" t "setMonth" t "setSeconds" t "setTime" t "setUTCDate" t "setUTCFullYear" t "setUTCHours" t "setUTCMilliseconds" t "setUTCMinutes" t "setUTCMonth" t "setUTCSeconds" t "setYear" t "toDateString" t "toGMTString" t "toISOString" t "toJSON" t "toLocaleDateString" t "toLocaleTimeString" t "toLocaleString" t "toTimeString" t "toUTCString" t "UTC" t ; Error properties "message" t ; Function properties "apply" t "arguments" t "caller" t "name" t "displayName" t ; Number properties "MAX_VALUE" t "MIN_VALUE" t "NEGATIVE_INFINITY" t "NaN" t "POSITIVE_INFINITY" t "isFinite" t "isInteger" t "isNaN" t "isSafeInteger" t "toExponential" t "toFixed" t "toPrecision" t ; RegExp properties "compile" t "exec" t "test" t ; String properties "charAt" t "charCodeAt" t "concat" t "endsWith" t "fromCharCode" t "includes" t "indexOf" t "lastIndexOf" t "localeCompare" t "match" t "repeat" t "replace" t "search" t "slice" t "split" t "startsWith" t "substr" t "substring" t "toLocaleLowerCase" t "toLocaleUpperCase" t "toLowerCase" t "toUpperCase" t "trim" t ; DOM Element methods "accessKey" t "addEventListener" t "appendChild" t "attributes" t "blur" t "childElementCount" t "childNodes" t "children" t "classList" t "className" t "click" t "clientHeight" t "clientLeft" t "clientTop" t "clientWidth" t "cloneNode" t "compareDocumentPosition" t "contains" t "contentEditable" t "dir" t "exitFullscreen" t "firstChild" t "firstElementChild" t "focus" t "getAttribute" t "getAttributeNode" t "getBoundingClientRect" t "getElementsByClassName" t "getElementsByTagName" t "hasAttribute" t "hasAttributes" t "hasChildNodes" t "id" t "innerHTML" t "innerText" t "insertAdjacentElement" t "insertAdjacentHTML" t "insertAdjacentText" t "insertBefore" t "isContentEditable" t "isDefaultNamespace" t "isEqualNode" t "isSameNode" t "isSupported" t "lang" t "lastChild" t "lastElementChild" t "namespaceURI" t "nextSibling" t "nextElementSibling" t "nodeName" t "nodeType" t "nodeValue" t "normalize" t "offsetHeight" t "offsetWidth" t "offsetLeft" t "offsetParent" t "offsetTop" t "ownerDocument" t "parentNode" t "parentElement" t "previousSibling" t "previousElementSibling" t "querySelector" t "querySelectorAll" t "removeAttribute" t "removeAttributeNode" t "removeChild" t "removeEventListener" t "replaceChild" t "requestFullscreen" t "scrollHeight" t "scrollIntoView" t "scrollLeft" t "scrollTop" t "scrollWidth" t "setAttribute" t "setAttributeNode" t "style" t "tabIndex" t "tagName" t "textContent" t "title" t ))) (provide 'dojo-core-api)