Changeset 15087
- Timestamp:
- 06/17/17 06:52:40 (6 years ago)
- Location:
- trunk/abcl/contrib/jss
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/abcl/contrib/jss/invoke.lisp
r15086 r15087 209 209 (let ((name (read stream))) 210 210 (if (or (find #\. name) (find #\{ name)) 211 (jss-transform-to-field name )211 (jss-transform-to-field name arg) 212 212 (let ((object-var (gensym)) 213 213 (args-var (gensym))) -
trunk/abcl/contrib/jss/transform-to-field.lisp
r14947 r15087 2 2 3 3 ;; JSS syntax for fields 4 ;; #" <thing>.<field>"4 ;; #"[<scope>]<thing>.<field>" 5 5 ;; 6 ;; <scope> is empty or "==". scope is only paid attention to when <field> is a literal string 7 ;; 6 8 ;; <thing> is either {<lisp expression>} or a class name or abbreviation that find-java-class can use 7 9 ;; If <thing> is a lisp expression, then it is evaluated (in the lexical environment) and used as an instance 10 ;; when <scope> is "==" you promise that instance will always be of the same class, and so field lookup 11 ;; is done once and cached. 8 12 ;; If <thing> is a class name the result of find-java-class is used and a static field access is done. 13 ;; when <scope> is "==" you promise the static field is final and so the result is wrapped in (load-time-value ...) 9 14 ;; 10 15 ;; <field> is either {<lisp expression} or string … … 14 19 ;; eg. #"foo.bar.baz" -> (get-java-field (find-java-class 'foo.bar) "baz" t) 15 20 ;; #"{foo}.baz" -> (get-java-field (find-java-class foo) "baz" t) 21 ;; #"==foo.baz" -> (load-time-value (get-java-field (find-java-class "foo") "bar" t)) 22 ;; #"=={foo}.baz" -> TL;DR (only look up baz field once based on class of foo, and cache) 16 23 17 18 (defun jss-transform-to-field (string) 19 (let* ((pattern (#"compile" 'java.util.regex.Pattern "(.*)\\.([^.]+)$")) 24 (defun jss-transform-to-field (string sharp-arg) 25 (let* ((pattern (#"compile" 'java.util.regex.Pattern "((==){0,1})(.*)\\.([^.]+)$")) 20 26 (matcher (#"matcher" pattern string))) 21 27 (#"find" matcher) 22 (let ((parts (list (#"group" matcher 1) (#"group" matcher 2)))) 28 (let ((parts (list (#"group" matcher 3) (#"group" matcher 4))) 29 (scope (#"group" matcher 1))) 23 30 (check-class-or-eval (first parts)) 24 31 (check-field-or-eval (second parts)) 25 (apply 'field-access-expression parts))))32 (apply 'field-access-expression sharp-arg scope parts )))) 26 33 27 34 ;; http://stackoverflow.com/questions/5205339/regular-expression-matching-fully-qualified-class-names … … 38 45 "inside #\"..\" expected either a field name or an expression surrounded by {}. Found: #~s" string)) 39 46 40 (defun field-access-expression (thing field) 41 `(get-java-field ,(if (char= (char thing 0) #\{) 42 (intern (string-upcase (subseq thing 1 (- (length thing) 1)))) 43 `(load-time-value (find-java-class ,thing))) 44 ,(if (char= (char field 0) #\{) 45 (intern (string-upcase (subseq field 1 (- (length field) 1)))) 46 field) 47 t)) 47 (defun field-access-expression (sharp-arg scope thing field ) 48 (if (and (not (char= (char thing 0) #\{)) (not (char= (char field 0) #\{))) 49 (static-field-ref-transform thing field sharp-arg scope) 50 (if (and (equal scope "==") (char= (char thing 0) #\{) (not (char= (char field 0) #\{))) 51 (always-same-signature-field-ref-transform sharp-arg thing field) 52 `(get-java-field ,(if (char= (char thing 0) #\{) 53 (read-from-string (subseq thing 1 (- (length thing) 1))) 54 `(load-time-value (find-java-class ,thing))) 55 ,(if (char= (char field 0) #\{) 56 (read-from-string (subseq field 1 (- (length field) 1))) 57 field) 58 t)))) 59 60 ;; If a class name and explicit field name we can look everything up at load time 61 (defun static-field-ref-transform (class field sharp-arg scope) 62 (if (equal scope "==") 63 `(load-time-value (get-java-field (find-java-class ,class) ,field t)) 64 `(,(if (eql sharp-arg 0) 'jcall-raw 'jcall) 65 (load-time-value (jmethod "java.lang.reflect.Field" "get" "java.lang.Object")) 66 (load-time-value 67 (let ((jfield (find-declared-field ,field (find-java-class ,class)))) 68 (#"setAccessible" jfield t) 69 jfield)) 70 (load-time-value (find-java-class ',class))))) 71 72 ;; 1 case: =={var}.foo 73 ;; Globally cache the field accessor for the first value of {var}. Subsequent calls ignore the class of var. 74 (defun always-same-signature-field-ref-transform (sharp-arg object field) 75 (let ((cached (make-symbol (format nil "CACHED-FIELD-field"))) 76 (object (intern (string-upcase (subseq object 1 (- (length object) 1)))))) 77 `(,(if (eql sharp-arg 0) 'jcall-raw 'jcall) 78 (load-time-value (jmethod "java.lang.reflect.Field" "get" "java.lang.Object")) 79 (locally (declare (special ,cached)) 80 (if (boundp ',cached) 81 ,cached 82 (progn (setq ,cached 83 (find-declared-field ,field (jcall (load-time-value (jmethod "java.lang.Object" "getClass")) ,object))) 84 (jcall (load-time-value (jmethod "java.lang.reflect.Field" "setAccessible" "boolean")) ,cached t) 85 ,cached))) 86 ,object))) 87 88 89 90 91 92
Note: See TracChangeset
for help on using the changeset viewer.