2 |
2 |
3 theory Scala |
3 theory Scala |
4 imports Base |
4 imports Base |
5 begin |
5 begin |
6 |
6 |
7 chapter \<open>Isabelle/Scala development tools\<close> |
7 chapter \<open>Isabelle/Scala systems programming\<close> |
8 |
8 |
9 text \<open> |
9 text \<open> |
10 Isabelle/ML and Isabelle/Scala are the two main language environments for |
10 Isabelle/ML and Isabelle/Scala are the two main implementation languages of |
11 Isabelle tool implementations. There are some basic command-line tools to |
11 the Isabelle environment: |
12 work with the underlying Java Virtual Machine, the Scala toplevel and |
12 |
13 compiler. Note that Isabelle/jEdit @{cite "isabelle-jedit"} provides a Scala |
13 \<^item> Isabelle/ML is for \<^emph>\<open>mathematics\<close>, to develop tools within the context |
14 Console for interactive experimentation within the running application. |
14 of symbolic logic, e.g.\ for constructing proofs or defining |
15 \<close> |
15 domain-specific formal languages. See the \<^emph>\<open>Isabelle/Isar implementation |
16 |
16 manual\<close> @{cite "isabelle-implementation"} for more details. |
17 |
17 |
18 section \<open>Java Runtime Environment within Isabelle \label{sec:tool-java}\<close> |
18 \<^item> Isabelle/Scala is for \<^emph>\<open>physics\<close>, to connect with the world of systems |
|
19 and services, including editors and IDE frameworks. |
|
20 |
|
21 There are various ways to access Isabelle/Scala modules and operations: |
|
22 |
|
23 \<^item> Isabelle command-line tools (\secref{sec:scala-tools}) run in a separate |
|
24 Java process. |
|
25 |
|
26 \<^item> Isabelle/ML antiquotations access Isabelle/Scala functions |
|
27 (\secref{sec:scala-functions}) via the PIDE protocol: execution happens |
|
28 within the running Java process underlying Isabelle/Scala. |
|
29 |
|
30 \<^item> The \<^verbatim>\<open>Console/Scala\<close> plugin of Isabelle/jEdit @{cite "isabelle-jedit"} |
|
31 operates on the running Java application, using the Scala |
|
32 read-eval-print-loop (REPL). |
|
33 |
|
34 The main Isabelle/Scala functionality is provided by \<^verbatim>\<open>Pure.jar\<close>, but |
|
35 further add-ons are bundled with Isabelle, e.g.\ to access SQLite or |
|
36 PostgreSQL using JDBC (Java Database Connectivity). |
|
37 |
|
38 Other components may augment the system environment by providing a suitable |
|
39 \<^path>\<open>etc/settings\<close> shell script in the component directory. Some shell |
|
40 functions are available to help with that: |
|
41 |
|
42 \<^item> Function \<^bash_function>\<open>classpath\<close> adds \<^verbatim>\<open>jar\<close> files in Isabelle path |
|
43 notation (POSIX). On Windows, this is converted to native path names |
|
44 before invoking @{tool java} or @{tool scala} (\secref{sec:scala-tools}). |
|
45 |
|
46 \<^item> Function \<^bash_function>\<open>isabelle_scala_service\<close> registers global |
|
47 service providers as subclasses of |
|
48 \<^scala_type>\<open>isabelle.Isabelle_System.Service\<close>, using the raw Java name |
|
49 according to @{scala_method (in java.lang.Object) getClass} (it should be |
|
50 enclosed in single quotes to avoid special characters like \<^verbatim>\<open>$\<close> to be |
|
51 interpreted by the shell). |
|
52 |
|
53 Particular Isabelle/Scala services require particular subclasses: |
|
54 instances are filtered according to their dynamic type. For example, class |
|
55 \<^scala_type>\<open>isabelle.Isabelle_Scala_Tools\<close> collects Scala command-line |
|
56 tools, and class \<^scala_type>\<open>isabelle.Isabelle_Scala_Functions\<close> |
|
57 collects Scala functions (\secref{sec:scala-functions}). |
|
58 \<close> |
|
59 |
|
60 |
|
61 section \<open>Command-line tools \label{sec:scala-tools}\<close> |
|
62 |
|
63 subsection \<open>Java Runtime Environment \label{sec:tool-java}\<close> |
19 |
64 |
20 text \<open> |
65 text \<open> |
21 The @{tool_def java} tool is a direct wrapper for the Java Runtime |
66 The @{tool_def java} tool is a direct wrapper for the Java Runtime |
22 Environment, within the regular Isabelle settings environment |
67 Environment, within the regular Isabelle settings environment |
23 (\secref{sec:settings}). The command line arguments are that of the |
68 (\secref{sec:settings}) and Isabelle classpath. The command line arguments |
24 underlying Java version. It is run in \<^verbatim>\<open>-server\<close> mode if possible, to |
69 are that of the bundled Java distribution: see option \<^verbatim>\<open>-help\<close> in |
25 improve performance (at the cost of extra startup time). |
70 particular. |
26 |
71 |
27 The \<^verbatim>\<open>java\<close> executable is the one within @{setting ISABELLE_JDK_HOME}, |
72 The \<^verbatim>\<open>java\<close> executable is taken from @{setting ISABELLE_JDK_HOME}, according |
28 according to the standard directory layout for official JDK distributions. |
73 to the standard directory layout for regular distributions of OpenJDK. |
29 The class loader is augmented such that the name space of |
74 |
30 \<^verbatim>\<open>Isabelle/Pure.jar\<close> is available, which is the main Isabelle/Scala module. |
75 The shell function \<^bash_function>\<open>isabelle_jdk\<close> allows shell scripts to |
31 \<close> |
76 invoke other Java tools robustly (e.g.\ \<^verbatim>\<open>isabelle_jdk jar\<close>), without |
32 |
77 depending on accidental operating system installations. |
33 |
78 \<close> |
34 section \<open>Scala toplevel \label{sec:tool-scala}\<close> |
79 |
35 |
80 |
36 text \<open> |
81 subsection \<open>Scala toplevel \label{sec:tool-scala}\<close> |
37 The @{tool_def scala} tool is a direct wrapper for the Scala toplevel; see |
82 |
38 also @{tool java} above. The command line arguments are that of the |
83 text \<open> |
39 underlying Scala version. This allows to interact with Isabelle/Scala in TTY |
84 The @{tool_def scala} tool is a direct wrapper for the Scala toplevel, |
40 mode. An alternative is to use the \<^verbatim>\<open>Console/Scala\<close> plugin of Isabelle/jEdit |
85 similar to @{tool java} above. The command line arguments are that of the |
41 @{cite "isabelle-jedit"}. |
86 bundled Scala distribution: see option \<^verbatim>\<open>-help\<close> in particular. This allows |
|
87 to interact with Isabelle/Scala interactively. |
42 \<close> |
88 \<close> |
43 |
89 |
44 subsubsection \<open>Example\<close> |
90 subsubsection \<open>Example\<close> |
45 |
91 |
46 text \<open> |
92 text \<open> |
47 Explore the Isabelle system environment in Scala: |
93 Explore the Isabelle system environment in Scala: |
48 @{scala [display] |
94 @{verbatim [display, indent = 2] \<open>$ isabelle scala\<close>} |
|
95 @{scala [display, indent = 2] |
49 \<open>import isabelle._ |
96 \<open>import isabelle._ |
50 |
97 |
51 val isabelle_home = Isabelle_System.getenv("ISABELLE_HOME") |
98 val isabelle_home = Isabelle_System.getenv("ISABELLE_HOME") |
52 |
99 |
53 val options = Options.init() |
100 val options = Options.init() |
54 options.bool("browser_info") |
101 options.bool("browser_info") |
55 options.string("document")\<close>} |
102 options.string("document")\<close>} |
56 \<close> |
103 \<close> |
57 |
104 |
58 |
105 |
59 section \<open>Scala compiler \label{sec:tool-scalac}\<close> |
106 subsection \<open>Scala compiler \label{sec:tool-scalac}\<close> |
60 |
107 |
61 text \<open> |
108 text \<open> |
62 The @{tool_def scalac} tool is a direct wrapper for the Scala compiler; see |
109 The @{tool_def scalac} tool is a direct wrapper for the Scala compiler; see |
63 also @{tool scala} above. The command line arguments are that of the |
110 also @{tool scala} above. The command line arguments are that of the |
64 underlying Scala version. |
111 bundled Scala distribution. |
65 |
112 |
66 This allows to compile further Scala modules, depending on existing |
113 This allows to compile further Scala modules, depending on existing |
67 Isabelle/Scala functionality. The resulting class or jar files can be added |
114 Isabelle/Scala functionality. The resulting \<^verbatim>\<open>class\<close> or \<^verbatim>\<open>jar\<close> files can be |
68 to the Java classpath using the \<^verbatim>\<open>classpath\<close> Bash function that is provided |
115 added to the Java classpath using the shell function |
69 by the Isabelle process environment. Thus add-on components can register |
116 \<^bash_function>\<open>classpath\<close>. Thus add-on components can register themselves |
70 themselves in a modular manner, see also \secref{sec:components}. |
117 in a modular manner, see also \secref{sec:components}. |
71 |
118 |
72 Note that jEdit @{cite "isabelle-jedit"} has its own mechanisms for adding |
119 Note that Isabelle/jEdit @{cite "isabelle-jedit"} has its own mechanisms for |
73 plugin components, which needs special attention since it overrides the |
120 adding plugin components. This needs special attention, since it overrides |
74 standard Java class loader. |
121 the standard Java class loader. |
75 \<close> |
122 \<close> |
76 |
123 |
77 |
124 |
78 section \<open>Scala script wrapper\<close> |
125 subsection \<open>Scala script wrapper\<close> |
79 |
126 |
80 text \<open> |
127 text \<open> |
81 The executable @{executable "$ISABELLE_HOME/bin/isabelle_scala_script"} |
128 The executable @{executable "$ISABELLE_HOME/bin/isabelle_scala_script"} |
82 allows to run Isabelle/Scala source files stand-alone programs, by using a |
129 allows to run Isabelle/Scala source files stand-alone programs, by using a |
83 suitable ``hash-bang'' line and executable file permissions. For example: |
130 suitable ``hash-bang'' line and executable file permissions. For example: |
84 @{verbatim [display] |
131 @{verbatim [display, indent = 2] \<open>#!/usr/bin/env isabelle_scala_script\<close>} |
85 \<open>#!/usr/bin/env isabelle_scala_script |
132 @{scala [display, indent = 2] |
86 |
133 \<open>val options = isabelle.Options.init() |
87 val options = isabelle.Options.init() |
|
88 Console.println("browser_info = " + options.bool("browser_info")) |
134 Console.println("browser_info = " + options.bool("browser_info")) |
89 Console.println("document = " + options.string("document"))\<close>} |
135 Console.println("document = " + options.string("document"))\<close>} |
90 |
136 |
91 This assumes that the executable may be found via the @{setting PATH} from |
137 This assumes that the executable may be found via the @{setting PATH} from |
92 the process environment: this is the case when Isabelle settings are active, |
138 the process environment: this is the case when Isabelle settings are active, |
114 The generated configuration is for Gradle\<^footnote>\<open>\<^url>\<open>https://gradle.org\<close>\<close>, but the |
160 The generated configuration is for Gradle\<^footnote>\<open>\<^url>\<open>https://gradle.org\<close>\<close>, but the |
115 main purpose is to import it into common Scala IDEs, such as IntelliJ |
161 main purpose is to import it into common Scala IDEs, such as IntelliJ |
116 IDEA\<^footnote>\<open>\<^url>\<open>https://www.jetbrains.com/idea\<close>\<close>. This allows to explore the |
162 IDEA\<^footnote>\<open>\<^url>\<open>https://www.jetbrains.com/idea\<close>\<close>. This allows to explore the |
117 sources with static analysis and other hints in real-time. |
163 sources with static analysis and other hints in real-time. |
118 |
164 |
119 The specified project directory must not exist yet. The generated files |
165 The specified project directory needs to be fresh. The generated files refer |
120 refer to physical file-system locations, using the path notation of the |
166 to physical file-system locations, using the path notation of the underlying |
121 underlying OS platform. Thus the project needs to be recreated whenever the |
167 OS platform. Thus the project needs to be recreated whenever the Isabelle |
122 Isabelle installation is changed or moved. |
168 installation is changed or moved. |
123 |
169 |
124 \<^medskip> By default, Scala sources are \<^emph>\<open>copied\<close> from the Isabelle distribution and |
170 \<^medskip> |
|
171 By default, Scala sources are \<^emph>\<open>copied\<close> from the Isabelle distribution and |
125 editing them within the IDE has no permanent effect. |
172 editing them within the IDE has no permanent effect. |
126 |
173 |
127 Option \<^verbatim>\<open>-L\<close> produces \<^emph>\<open>symlinks\<close> to the original files: this allows to |
174 Option \<^verbatim>\<open>-L\<close> produces \<^emph>\<open>symlinks\<close> to the original files: this allows to |
128 develop Isabelle/Scala/jEdit within an external Scala IDE. Note that |
175 develop Isabelle/Scala/jEdit within an external Scala IDE. Note that |
129 building the result always requires \<^verbatim>\<open>isabelle jedit -b\<close> on the |
176 building the result always requires \<^verbatim>\<open>isabelle jedit -b\<close> on the |
130 command-line. |
177 command-line. |
131 \<close> |
178 \<close> |
132 |
179 |
|
180 |
|
181 section \<open>Registered Isabelle/Scala functions \label{sec:scala-functions}\<close> |
|
182 |
|
183 subsection \<open>Defining functions in Isabelle/Scala\<close> |
|
184 |
|
185 text \<open> |
|
186 A Scala functions of type \<^scala_type>\<open>String => String\<close> may be wrapped as |
|
187 \<^scala_type>\<open>isabelle.Scala.Fun\<close> and collected via an instance of the |
|
188 class \<^scala_type>\<open>isabelle.Isabelle_Scala_Functions\<close>. A system component |
|
189 can then register that class via \<^bash_function>\<open>isabelle_scala_service\<close> |
|
190 in \<^path>\<open>etc/settings\<close> (\secref{sec:components}). An example is the |
|
191 predefined collection of \<^scala_type>\<open>isabelle.Functions\<close> in |
|
192 Isabelle/\<^verbatim>\<open>Pure.jar\<close> with the following line in |
|
193 \<^file>\<open>$ISABELLE_HOME/etc/settings\<close>: |
|
194 @{verbatim [display, indent = 2] \<open>isabelle_scala_service 'isabelle.Functions'\<close>} |
|
195 |
|
196 The overall list of registered functions is accessible in Isabelle/Scala as |
|
197 \<^scala_object>\<open>isabelle.Scala.functions\<close>. |
|
198 \<close> |
|
199 |
|
200 |
|
201 subsection \<open>Invoking functions in Isabelle/ML\<close> |
|
202 |
|
203 text \<open> |
|
204 Isabelle/PIDE provides a protocol to invoke registered Scala functions in |
|
205 ML: this requires a proper PIDE session context, e.g.\ within the Prover IDE |
|
206 or in batch builds via option @{system_option pide_session}. |
|
207 |
|
208 The subsequent ML antiquotations refer to Scala functions in a |
|
209 formally-checked manner. |
|
210 |
|
211 \begin{matharray}{rcl} |
|
212 @{ML_antiquotation_def "scala_function"} & : & \<open>ML_antiquotation\<close> \\ |
|
213 @{ML_antiquotation_def "scala"} & : & \<open>ML_antiquotation\<close> \\ |
|
214 \end{matharray} |
|
215 |
|
216 \<^rail>\<open> |
|
217 (@{ML_antiquotation scala_function} | @{ML_antiquotation scala}) |
|
218 @{syntax embedded} |
|
219 \<close> |
|
220 |
|
221 \<^descr> \<open>@{scala_function name}\<close> inlines the checked function name as ML string |
|
222 literal. |
|
223 |
|
224 \<^descr> \<open>@{scala name}\<close> invokes the checked function via the PIDE protocol. In |
|
225 Isabelle/ML this appears as a function of type |
|
226 \<^ML_type>\<open>string -> string\<close>, which is subject to interrupts within the ML |
|
227 runtime environment as usual. A \<^scala>\<open>null\<close> result in Scala raises an |
|
228 exception \<^ML>\<open>Scala.Null\<close> in ML. |
|
229 |
|
230 The standard approach of representing datatypes via strings works via XML in |
|
231 YXML transfer syntax. See Isabelle/ML operations and modules @{ML |
|
232 YXML.string_of_body}, @{ML YXML.parse_body}, @{ML_structure XML.Encode}, |
|
233 @{ML_structure XML.Decode}; similarly for Isabelle/Scala. Isabelle symbols |
|
234 may have to be recoded via Scala operations |
|
235 \<^scala_method>\<open>isabelle.Symbol.decode\<close> and |
|
236 \<^scala_method>\<open>isabelle.Symbol.encode\<close>. |
|
237 \<close> |
|
238 |
|
239 |
|
240 subsubsection \<open>Examples\<close> |
|
241 |
|
242 text \<open> |
|
243 Invoke a predefined Scala function that is the identity on type |
|
244 \<^ML_type>\<open>string\<close>: |
|
245 \<close> |
|
246 |
|
247 ML \<open> |
|
248 val s = "test"; |
|
249 val s' = \<^scala>\<open>echo\<close> s; |
|
250 \<^assert> (s = s') |
|
251 \<close> |
|
252 |
|
253 text \<open> |
|
254 Let the Scala compiler process some toplevel declarations, producing a list |
|
255 of errors: |
|
256 \<close> |
|
257 |
|
258 ML \<open> |
|
259 val source = "class A(a: Int, b: Boolean)" |
|
260 val errors = |
|
261 \<^scala>\<open>scala_toplevel\<close> source |
|
262 |> YXML.parse_body |
|
263 |> let open XML.Decode in list string end; |
|
264 |
|
265 \<^assert> (null errors)\<close> |
|
266 |
|
267 text \<open> |
|
268 The above is merely for demonstration. See \<^ML>\<open>Scala_Compiler.toplevel\<close> |
|
269 for a more convenient version with builtin decoding and treatment of errors. |
|
270 \<close> |
|
271 |
|
272 |
|
273 section \<open>Documenting Isabelle/Scala entities\<close> |
|
274 |
|
275 text \<open> |
|
276 The subsequent document antiquotations help to document Isabelle/Scala |
|
277 entities, with formal checking of names against the Isabelle classpath. |
|
278 |
|
279 \begin{matharray}{rcl} |
|
280 @{antiquotation_def "scala"} & : & \<open>antiquotation\<close> \\ |
|
281 @{antiquotation_def "scala_object"} & : & \<open>antiquotation\<close> \\ |
|
282 @{antiquotation_def "scala_type"} & : & \<open>antiquotation\<close> \\ |
|
283 @{antiquotation_def "scala_method"} & : & \<open>antiquotation\<close> \\ |
|
284 \end{matharray} |
|
285 |
|
286 \<^rail>\<open> |
|
287 (@@{antiquotation scala} | @@{antiquotation scala_object}) |
|
288 @{syntax embedded} |
|
289 ; |
|
290 @@{antiquotation scala_type} @{syntax embedded} types |
|
291 ; |
|
292 @@{antiquotation scala_method} class @{syntax embedded} types args |
|
293 ; |
|
294 class: ('(' @'in' @{syntax name} types ')')? |
|
295 ; |
|
296 types: ('[' (@{syntax name} ',' +) ']')? |
|
297 ; |
|
298 args: ('(' (nat | (('_' | @{syntax name}) + ',')) ')')? |
|
299 \<close> |
|
300 |
|
301 \<^descr> \<open>@{scala s}\<close> is similar to \<open>@{verbatim s}\<close>, but the given source text is |
|
302 checked by the Scala compiler as toplevel declaration (without evaluation). |
|
303 This allows to write Isabelle/Scala examples that are statically checked. |
|
304 |
|
305 \<^descr> \<open>@{scala_object x}\<close> checks the given Scala object name (simple value or |
|
306 ground module) and prints the result verbatim. |
|
307 |
|
308 \<^descr> \<open>@{scala_type T[A]}\<close> checks the given Scala type name (with optional type |
|
309 parameters) and prints the result verbatim. |
|
310 |
|
311 \<^descr> \<open>@{scala_method (in c[A]) m[B](n)}\<close> checks the given Scala method \<open>m\<close> in |
|
312 the context of class \<open>c\<close>. The method argument slots are either specified by |
|
313 a number \<open>n\<close> or by a list of (optional) argument types; this may refer to |
|
314 type variables specified for the class or method: \<open>A\<close> or \<open>B\<close> above. |
|
315 |
|
316 Everything except for the method name \<open>m\<close> is optional. The absence of the |
|
317 class context means that this is a static method. The absence of arguments |
|
318 with types means that the method can be determined uniquely as \<^verbatim>\<open>(\<close>\<open>m\<close>\<^verbatim>\<open> _)\<close> |
|
319 in Scala (no overloading). |
|
320 \<close> |
|
321 |
|
322 |
|
323 subsubsection \<open>Examples\<close> |
|
324 |
|
325 text \<open> |
|
326 Miscellaneous Isabelle/Scala entities: |
|
327 |
|
328 \<^item> object: \<^scala_object>\<open>isabelle.Isabelle_Process\<close> |
|
329 \<^item> type without parameter: @{scala_type isabelle.Console_Progress} |
|
330 \<^item> type with parameter: @{scala_type List[A]} |
|
331 \<^item> static method: \<^scala_method>\<open>isabelle.Isabelle_System.bash\<close> |
|
332 \<^item> class and method with type parameters: |
|
333 @{scala_method (in List[A]) map[B]("A => B")} |
|
334 \<^item> overloaded method with argument type: @{scala_method (in Int) "+" (Int)} |
|
335 \<close> |
|
336 |
133 end |
337 end |