-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjni.scm
137 lines (121 loc) · 6.35 KB
/
jni.scm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#>
#include <jni.h>
<#
(module jni
(jlambda jimport)
(import scheme chicken srfi-1)
(reexport jni-lolevel)
(import-for-syntax jni-lolevel)
(use jni-lolevel)
(begin-for-syntax
(require-library jni-lolevel srfi-1))
(cond-expand
(android)
(else
(export jvm-init)
(define-syntax jvm-init
(ir-macro-transformer
(lambda (x i c)
(let ((class-path (if (null? (cdr x)) "." (cadr x))))
(if (not (jni-env))
(jvm-init-lolevel class-path))
`(unless (jni-env)
(jvm-init-lolevel ,class-path))))))))
(define-for-syntax (make-parameter-list ParameterTypes)
(map class->type (reverse (array->list ParameterTypes))))
(define-for-syntax (method-signature Method)
(cons* (static? (Method.getModifiers Method))
(class->type (Method.getReturnType Method))
(make-parameter-list (Method.getParameterTypes Method))))
(define-for-syntax (constructor-signature Constructor)
(cons* #f 'void (make-parameter-list (Constructor.getParameterTypes Constructor))))
(define-for-syntax (define-constructors r class-name)
(let* ((%jlambda-methods (r 'jlambda-methods))
(class-object (find-class/or-error class-name))
(Constructors (array-map! (Class.getConstructors class-object) local->global))
(signatures (map constructor-signature Constructors)))
`(,%jlambda-methods (##core#quote ,class-name) (##core#quote new) (##core#quote ,signatures))))
(define-for-syntax (define-methods r class-name method-name)
(let* ((%jlambda-methods (r 'jlambda-methods))
(class-object (find-class/or-error class-name))
(Methods (array-map! (find-methods-by-name/helper class-object (symbol->string method-name)) local->global)))
(if (not (null? Methods))
(let* ((static (static? (Method.getModifiers (car Methods))))
(signatures (map method-signature Methods)))
`(,%jlambda-methods (##core#quote ,class-name) (##core#quote ,method-name) (##core#quote ,signatures)))
#f)))
(define-for-syntax (define-field r class-name field-name)
(let* ((%lambda (r 'lambda))
(%catch (r 'catch))
(%jlambda-field (r 'jlambda-field))
(%error (r 'error))
(class-object (find-class/or-error class-name))
(Field (local->global (find-field/helper class-object (symbol->string field-name)))))
(if Field
(let* ((static (static? (Field.getModifiers Field)))
(type (class->type (Field.getType Field))))
`(,%catch (,%lambda ()
(,%jlambda-field ,static ,type ,class-name ,field-name))
(,%lambda args
(,%error "field not found" ,(symbol->string class-name) ,(symbol->string field-name)))))
#f)))
(define-syntax jlambda
(er-macro-transformer
(lambda (x r c)
(let* ((%find-class/or-error (r 'find-class/or-error))
(class-name (cadr x))
(rest (cddr x)))
(if (null? rest)
`(,%find-class/or-error (##core#quote ,class-name))
(let ((method/field (car rest)))
(if (eq? method/field 'new)
(define-constructors r class-name)
(or (define-field r class-name method/field)
(define-methods r class-name method/field)
(error 'jlambda "invalid jlambda expression" x)))))))))
(define-for-syntax (find-unique-names elements get-name)
(delete-duplicates (map (lambda (e)
(jstring->string (get-name e))) (array->list elements))))
(define-for-syntax (make-jlambda-definitions r class-name names)
(let ((%define (r '%define))
(%jlambda (r '%jlambda)))
(map (lambda (field/method)
(let ((name (string->symbol field/method)))
`(,%define ,name (,%jlambda ,class-name ,(string->symbol field/method))))) names)))
(define-for-syntax (replace-placeholder value ls)
(map (lambda (e)
(cond ((list? e)
(replace-placeholder value e))
((eq? '<> e)
value)
(else
e))) ls))
(define-syntax jimport
(er-macro-transformer
(lambda (x r c)
(let* ((%module (r 'module))
(%import (r 'import))
(%use (r 'use))
(%require (r 'require))
(%begin (r 'begin))
(%define (r 'define))
(%jlambda (r 'jlambda))
(class-name (cadr x))
(specifiers (cddr x))
(class-object (find-class/or-error class-name))
(Methods (find-unique-names (find-methods/helper class-object) Method.getName))
(Fields (find-unique-names (find-fields/helper class-object) Field.getName)))
`(,%begin
(,%module ,class-name
*
(,%import (prefix scheme %)
(prefix chicken %))
(,%require (##core#quote jni))
(,%import (prefix jni %))
(,%define new (,%jlambda ,class-name new))
,@(make-jlambda-definitions r class-name Methods)
,@(make-jlambda-definitions r class-name Fields))
(,%import ,@(if (null? specifiers)
(list class-name)
(replace-placeholder class-name specifiers))))))))
) ; end of jni module