source: trunk/abcl/src/org/armedbear/lisp/scripting/lisp/abcl-script.lisp @ 11856

Last change on this file since 11856 was 11856, checked in by astalla, 14 years ago
  • loading:

added a new primitive sys::load-returning-last-result which behaves like
load but returns the last value produced instead of T

  • JSR-223:
    • used the new load-returning-last-result to evaluate both interpreted and compiled code for consistency (with a caveat, see the wiki page on JSR-223)
    • bindings established through ScriptContext? are now declared special
    • compilation using the runtime compiler has been removed due to inconsistencies with evaluation and file-based compilation
    • updated the example as suggested on the ML to show both modes of getting the AbclScriptEngine?


  • Property svn:eol-style set to LF
File size: 5.8 KB
Line 
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-special-declarations (bindings)
55  (let ((*package* (find-package :abcl-script-user)))
56    `(declare (special
57         ,@(mapcar (lambda (binding) (read-from-string (car binding)))
58       bindings)))))
59
60(defun generate-java-bindings (bindings-list actual-bindings java-bindings)
61  (loop :for binding  :in actual-bindings
62  :for jbinding :in bindings-list
63  :collect `(jcall +put-binding+
64       ,java-bindings ,(car jbinding) ,(car binding))))
65
66(defmacro eval-in-script-context ((global-bindings engine-bindings stdin stdout script-context)
67          body)
68  "Sets up an environment in which to evaluate a piece of code coming from Java through the JSR-223 methods."
69  (let ((actual-global-bindings (gensym))
70  (actual-engine-bindings (gensym)))
71    `(let ((*package* (find-package :abcl-script-user))
72     (*standard-input* ,stdin)
73     (*standard-output* ,stdout)
74     (*debugger-hook* (if *use-throwing-debugger*
75        #'sys::%debugger-hook-function
76        *debugger-hook*))
77     (,actual-global-bindings (generate-bindings ,global-bindings))
78     (,actual-engine-bindings (generate-bindings ,engine-bindings)))
79       (eval `(let (,@,actual-global-bindings)
80    (let (,@,actual-engine-bindings)
81      ,(generate-special-declarations ,global-bindings)
82      ,(generate-special-declarations ,engine-bindings)
83      (prog1
84          (progn ,@,body)
85        (finish-output *standard-output*)
86        ,@(generate-java-bindings
87           ,global-bindings 
88           ,actual-global-bindings
89           (jcall +get-bindings+ ,script-context +global-scope+))
90        ,@(generate-java-bindings
91           ,engine-bindings 
92           ,actual-engine-bindings
93           (jcall +get-bindings+ ,script-context +engine-scope+)))))))))
94 
95(defun eval-script (global-bindings engine-bindings stdin stdout
96        code-string script-context)
97  (eval-in-script-context (global-bindings engine-bindings stdin stdout script-context)
98    `((with-input-from-string (str ,code-string)
99  (sys::load-returning-last-result str)))))
100
101(defun eval-compiled-script (global-bindings engine-bindings stdin stdout
102           function script-context)
103  (eval-in-script-context (global-bindings engine-bindings stdin stdout script-context)
104    `((funcall ,function))))
105
106(defun compile-script (code-string)
107  (let* ((tmp-file (jstatic (jmethod "java.io.File" "createTempFile" "java.lang.String" "java.lang.String")
108          nil "abcl-src-file-" ".lisp"))
109   (tmp-file-path (jcall (jmethod "java.io.File" "getAbsolutePath") tmp-file)))
110    (jcall (jmethod "java.io.File" "deleteOnExit") tmp-file) ;to be really-really-really sure...
111    (unwind-protect
112   (progn
113     (with-open-file (stream tmp-file-path :direction :output)
114       (princ "(in-package :abcl-script-user)" stream)
115       (princ code-string stream)
116       (finish-output stream))
117     (let ((compiled-file (compile-file tmp-file-path)))
118       (jcall (jmethod "java.io.File" "deleteOnExit")
119        (jnew (jconstructor "java.io.File" "java.lang.String")
120        (namestring compiled-file)))
121       (lambda ()
122         (let ((*package* (find-package :abcl-script-user)))
123     (sys::load-returning-last-result compiled-file)))))
124      (delete-file tmp-file-path))))
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)
Note: See TracBrowser for help on using the repository browser.