1 | ;;; abcl-script.lisp |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 2008 Alessio Stalla |
---|
4 | ;;; |
---|
5 | ;;; This program is free software; you can redistribute it and/or |
---|
6 | ;;; modify it under the terms of the GNU General Public License |
---|
7 | ;;; as published by the Free Software Foundation; either version 2 |
---|
8 | ;;; of the License, or (at your option) any later version. |
---|
9 | ;;; |
---|
10 | ;;; This program is distributed in the hope that it will be useful, |
---|
11 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | ;;; GNU General Public License for more details. |
---|
14 | ;;; |
---|
15 | ;;; You should have received a copy of the GNU General Public License |
---|
16 | ;;; along with this program; if not, write to the Free Software |
---|
17 | ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
18 | ;;; |
---|
19 | ;;; As a special exception, the copyright holders of this library give you |
---|
20 | ;;; permission to link this library with independent modules to produce an |
---|
21 | ;;; executable, regardless of the license terms of these independent |
---|
22 | ;;; modules, and to copy and distribute the resulting executable under |
---|
23 | ;;; terms of your choice, provided that you also meet, for each linked |
---|
24 | ;;; independent module, the terms and conditions of the license of that |
---|
25 | ;;; module. An independent module is a module which is not derived from |
---|
26 | ;;; or based on this library. If you modify this library, you may extend |
---|
27 | ;;; this exception to your version of the library, but you are not |
---|
28 | ;;; obligated to do so. If you do not wish to do so, delete this |
---|
29 | ;;; exception statement from your version. |
---|
30 | |
---|
31 | (in-package :abcl-script) |
---|
32 | |
---|
33 | (defconstant +global-scope+ |
---|
34 | (jfield "javax.script.ScriptContext" "GLOBAL_SCOPE")) |
---|
35 | |
---|
36 | (defconstant +engine-scope+ |
---|
37 | (jfield "javax.script.ScriptContext" "ENGINE_SCOPE")) |
---|
38 | |
---|
39 | (defconstant +put-binding+ (jmethod "javax.script.Bindings" |
---|
40 | "put" |
---|
41 | "java.lang.String" |
---|
42 | "java.lang.Object")) |
---|
43 | |
---|
44 | (defconstant +get-bindings+ (jmethod "javax.script.ScriptContext" |
---|
45 | "getBindings" |
---|
46 | "int")) |
---|
47 | |
---|
48 | (defun generate-bindings (bindings) |
---|
49 | (let ((*package* (find-package :abcl-script-user))) |
---|
50 | (mapcar (lambda (binding) (list (read-from-string (car binding)) |
---|
51 | (cdr binding))) |
---|
52 | bindings))) |
---|
53 | |
---|
54 | (defun generate-java-bindings (bindings-list actual-bindings java-bindings) |
---|
55 | (loop :for binding :in actual-bindings |
---|
56 | :for jbinding :in bindings-list |
---|
57 | :collect `(jcall +put-binding+ |
---|
58 | ,java-bindings ,(car jbinding) ,(car binding)))) |
---|
59 | |
---|
60 | (defmacro eval-in-script-context ((global-bindings engine-bindings stdin stdout script-context) |
---|
61 | body) |
---|
62 | "Sets up an environment in which to evaluate a piece of code coming from Java through the JSR-223 methods." |
---|
63 | (let ((actual-global-bindings (gensym)) |
---|
64 | (actual-engine-bindings (gensym))) |
---|
65 | `(let ((*package* (find-package :abcl-script-user)) |
---|
66 | (*standard-input* ,stdin) |
---|
67 | (*standard-output* ,stdout) |
---|
68 | (*debugger-hook* (if *use-throwing-debugger* |
---|
69 | #'sys::%debugger-hook-function |
---|
70 | *debugger-hook*)) |
---|
71 | (,actual-global-bindings (generate-bindings ,global-bindings)) |
---|
72 | (,actual-engine-bindings (generate-bindings ,engine-bindings))) |
---|
73 | (eval `(let (,@,actual-global-bindings) |
---|
74 | (let (,@,actual-engine-bindings) |
---|
75 | (prog1 |
---|
76 | (progn ,@,body) |
---|
77 | (finish-output *standard-output*) |
---|
78 | ,@(generate-java-bindings |
---|
79 | ,global-bindings |
---|
80 | ,actual-global-bindings |
---|
81 | (jcall +get-bindings+ ,script-context +global-scope+)) |
---|
82 | ,@(generate-java-bindings |
---|
83 | ,engine-bindings |
---|
84 | ,actual-engine-bindings |
---|
85 | (jcall +get-bindings+ ,script-context +engine-scope+))))))))) |
---|
86 | |
---|
87 | (defun eval-script (global-bindings engine-bindings stdin stdout |
---|
88 | code-string script-context) |
---|
89 | (eval-in-script-context (global-bindings engine-bindings stdin stdout script-context) |
---|
90 | (read-from-string |
---|
91 | (concatenate 'string "(" code-string ")")))) |
---|
92 | |
---|
93 | (defun eval-compiled-script (global-bindings engine-bindings stdin stdout |
---|
94 | function script-context) |
---|
95 | (eval-in-script-context (global-bindings engine-bindings stdin stdout script-context) |
---|
96 | `((funcall ,function)))) |
---|
97 | |
---|
98 | (defun compile-script (code-string) |
---|
99 | (if *compile-using-temp-files* |
---|
100 | (let* ((tmp-file (jstatic (jmethod "java.io.File" "createTempFile" "java.lang.String" "java.lang.String") |
---|
101 | nil "abcl-src-file-" ".lisp")) |
---|
102 | (tmp-file-path (jcall (jmethod "java.io.File" "getAbsolutePath") tmp-file))) |
---|
103 | (jcall (jmethod "java.io.File" "deleteOnExit") tmp-file) ;to be really-really-really sure... |
---|
104 | (unwind-protect |
---|
105 | (progn |
---|
106 | (with-open-file (stream tmp-file-path :direction :output) |
---|
107 | (princ "(in-package :abcl-script-user)" stream) |
---|
108 | (princ code-string stream) |
---|
109 | (finish-output stream)) |
---|
110 | (let ((compiled-file (compile-file tmp-file-path))) |
---|
111 | (jcall (jmethod "java.io.File" "deleteOnExit") |
---|
112 | (jnew (jconstructor "java.io.File" "java.lang.String") |
---|
113 | (namestring compiled-file))) |
---|
114 | (lambda () |
---|
115 | (let ((*package* (find-package :abcl-script-user))) |
---|
116 | (load compiled-file :verbose t :print t))))) |
---|
117 | (delete-file tmp-file-path))) |
---|
118 | (eval |
---|
119 | `(compile |
---|
120 | nil |
---|
121 | (lambda () |
---|
122 | ,@(let ((*package* (find-package :abcl-script-user))) |
---|
123 | (read-from-string |
---|
124 | (concatenate 'string "(" code-string " cl:t)")))))))) ;return T in conformity of what LOAD does. |
---|
125 | |
---|
126 | ;;Java interface implementation - TODO |
---|
127 | |
---|
128 | (defvar *interface-implementation-map* (make-hash-table :test #'equal)) |
---|
129 | |
---|
130 | (defun find-java-interface-implementation (interface) |
---|
131 | (gethash interface *interface-implementation-map*)) |
---|
132 | |
---|
133 | (defun register-java-interface-implementation (interface implementation &optional lisp-this) |
---|
134 | (setf (gethash interface *interface-implementation-map*) |
---|
135 | (jmake-proxy interface implementation lisp-this))) |
---|
136 | |
---|
137 | (defun remove-java-interface-implementation (interface) |
---|
138 | (remhash interface *interface-implementation-map*)) |
---|
139 | |
---|
140 | ;Let's load it so asdf package is already defined when loading config.lisp |
---|
141 | (require 'asdf) |
---|