Refactor using reflection support (#110)

This commit is contained in:
Michiel Borkent 2019-11-16 00:25:36 +01:00 committed by GitHub
parent a9347c7753
commit a0fa854969
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 130 additions and 262 deletions

View file

@ -162,24 +162,26 @@ namespaces. If not all vars are available, they are enumerated explicitly.
- [`clojure.tools.cli`](https://github.com/clojure/tools.cli) aliased as `tools.cli`
- [`clojure.data.csv`](https://github.com/clojure/data.csv) aliased as `csv`
From Java the following is available:
The following Java classes are available:
- `Integer`:
- static methods: `parseInt`
- `File`:
- static methods: `createTempFile`
- instance methods: `.canRead`, `.canWrite`, `.delete`,
`.deleteOnExit`, `.exists`, `.getAbsoluteFile`, `.getCanonicalFile`,
`.getCanonicalPath`, `.getName`, `.getParent`, `.getParentFile`,
`.getPath`, `.isAbsolute`, `.isDirectory`, `.isFile`, `.isHidden`,
`.lastModified`, `.length`, `.list`, `.listFiles`, `.mkdir`,
`.mkdirs`, `.renameTo`, `.setLastModified`, `.setReadOnly`,
`.setReadable`, `.toPath`, `.toURI`.
- `System`:
- static methods: `exit`, `getProperty`, `setProperty`, `getProperties`, `getenv`
- `Thread`:
- static methods: `sleep`
- `java.util.regex.Pattern` (all static and instance methods and constants)
```
ArithmeticException
AssertionError
Boolean
Class
Double
Exception
clojure.lang.ExceptionInfo
java.io.File
Integer
java.io.File
java.util.regex.Pattern
String
System
Thread
```
More classes can be added by request.
Special vars:
@ -442,8 +444,7 @@ Differences with Clojure:
- No first class vars. Note that you can define and redefine global values with
`def` / `defn`, but there is no `var` indirection.
- Java classes and interop are not available. For a selection of classes we mimic constructors and interop by having
functions like `Exception.` and `.getCanonicalPath`.
- A subset of Java classes are supported.
- Only the `clojure.core`, `clojure.set` and `clojure.string` namespaces are
available from Clojure.

View file

@ -1,4 +1,26 @@
[
{
"name":"java.lang.ArithmeticException",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.lang.AssertionError",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.lang.Boolean",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.io.BufferedReader",
"allPublicMethods":true
},
{
"name": "java.lang.Class",
"allDeclaredConstructors": true,
@ -7,9 +29,45 @@
"allPublicMethods": true
},
{
"name":"java.io.BufferedReader",
"name":"java.lang.Double",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.lang.Exception",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name": "clojure.lang.ExceptionInfo",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.lang.Integer",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.io.File",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.util.concurrent.LinkedBlockingQueue",
"allPublicMethods":true
},
{
"name":"java.util.regex.Pattern",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.lang.Process",
"allPublicMethods":true
@ -20,14 +78,25 @@
},
{
"name":"java.lang.String",
"allPublicMethods":true
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
}
,
{
"name":"java.lang.System",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.lang.Thread",
"allPublicMethods":true,
"allPublicFields": true,
"allPublicConstructors": true
},
{
"name":"java.lang.UNIXProcess",
"allPublicMethods":true
},
{
"name":"java.util.concurrent.LinkedBlockingQueue",
"allPublicMethods":true
}
]

2
sci

@ -1 +1 @@
Subproject commit cb1dc3139a53c680b2bdc1038d2c6e26b975ee8e
Subproject commit 419d39d24f9e3676d9922218e747fc277a921a72

View file

@ -1,87 +0,0 @@
(ns babashka.impl.File
{:no-doc true}
(:refer-clojure :exclude [list])
(:require [clojure.java.io :as io]
[clojure.string :as str]))
(set! *warn-on-reflection* true)
;; also see https://gist.github.com/plexus/68594ba9b5e3f0d63fe84dcae31c4a53
(defmacro gen-wrapper-fn [method-name]
`(defn ~method-name {:bb/export true}
[~(with-meta 'x {:tag 'java.io.File})]
(~(symbol (str "." method-name)) ~'x)))
(defmacro gen-wrapper-fn-2 [method-name]
`(defn ~method-name {:bb/export true}
[~(with-meta 'x {:tag 'java.io.File}) ~'y]
(~(symbol (str "." method-name)) ~'x ~'y)))
(gen-wrapper-fn canExecute)
(gen-wrapper-fn canRead)
(gen-wrapper-fn canWrite)
(defn createTempFile
([^String prefix ^String suffix]
(java.io.File/createTempFile prefix suffix))
([^String prefix ^String suffix ^java.io.File dir]
(java.io.File/createTempFile prefix suffix dir)))
(gen-wrapper-fn delete)
(gen-wrapper-fn deleteOnExit)
(gen-wrapper-fn exists)
(gen-wrapper-fn getAbsoluteFile)
(gen-wrapper-fn getCanonicalFile)
(gen-wrapper-fn getCanonicalPath)
(gen-wrapper-fn getName)
(gen-wrapper-fn getParent)
(gen-wrapper-fn getParentFile)
(gen-wrapper-fn getPath)
(gen-wrapper-fn isAbsolute)
(gen-wrapper-fn isDirectory)
(gen-wrapper-fn isFile)
(gen-wrapper-fn isHidden)
(gen-wrapper-fn lastModified)
(gen-wrapper-fn length)
(gen-wrapper-fn list)
(gen-wrapper-fn listFiles)
(gen-wrapper-fn mkdir)
(gen-wrapper-fn mkdirs)
(gen-wrapper-fn-2 renameTo)
(defn ^:bb/export setExecutable
([^java.io.File f b]
(.setExecutable f b))
([^java.io.File f b ownerOnly]
(.setExecutable f b ownerOnly)))
(gen-wrapper-fn-2 setLastModified)
(gen-wrapper-fn-2 setReadable)
(gen-wrapper-fn setReadOnly)
(defn ^:bb/export setWritable
([^java.io.File f b]
(.setWritable f b))
([^java.io.File f b ownerOnly]
(.setWritable f b ownerOnly)))
(gen-wrapper-fn toPath)
(gen-wrapper-fn toURI)
(def file-bindings
(-> (reduce (fn [acc [k v]]
(if (-> v meta :bb/export)
(assoc acc (symbol (str "." k))
@v)
acc))
{}
(ns-publics *ns*))
;; static methods
(assoc (symbol "File/createTempFile") createTempFile)
(assoc (symbol "java.io.File/createTempFile") createTempFile)))
(comment
(canRead (clojure.java.io/file "README.md"))
(canWrite (clojure.java.io/file "README.md"))
(exists (clojure.java.io/file "README.md"))
(renameTo (io/file "/tmp/script2.clj") (io/file "/tmp/script.clj"))
(.setWritable (io/file "/tmp/script.clj") true true)
(meta #'toURI)
(meta #'canWrite)
;; for README.md:
(str/join ", " (map #(format "`%s`" %) (sort (keys file-bindings))))
)

View file

@ -1,17 +0,0 @@
(ns babashka.impl.Integer
{:no-doc true}
(:refer-clojure :exclude [list]))
(set! *warn-on-reflection* true)
(defn parseInt
([^String x] (Integer/parseInt x))
([^String x ^long radix]
(Integer/parseInt x radix)))
(def integer-bindings
{'Integer/parseInt parseInt})
(comment
)

View file

@ -1,72 +0,0 @@
(ns babashka.impl.Pattern
{:no-doc true})
(set! *warn-on-reflection* true)
(defmacro gen-wrapper-fn [method-name]
`(defn ~method-name {:bb/export true}
[~(with-meta 'x {:tag 'java.util.regex.Pattern})]
(~(symbol (str "." method-name)) ~'x)))
(defmacro gen-wrapper-fn-2 [method-name]
`(defn ~method-name {:bb/export true}
[~(with-meta 'x {:tag 'java.util.regex.Pattern}) ~'y]
(~(symbol (str "." method-name)) ~'x ~'y)))
(defmacro gen-constants [& constant-names]
(let [defs (for [constant-name constant-names
:let [full-name (symbol (str "java.util.regex.Pattern/" constant-name))
meta {:bb/export-constant true
:bb/full-name (list 'quote full-name)}
constant-name (with-meta constant-name meta)]]
`(def ~constant-name
~full-name))]
`(do ~@defs)))
(gen-constants CANON_EQ CASE_INSENSITIVE COMMENTS DOTALL LITERAL MULTILINE
UNICODE_CASE UNICODE_CHARACTER_CLASS UNIX_LINES)
(gen-wrapper-fn asPredicate)
(defn compile*
([^String s]
(java.util.regex.Pattern/compile s))
([^String s ^long flags]
(java.util.regex.Pattern/compile s flags)))
(gen-wrapper-fn flags)
(gen-wrapper-fn-2 matcher)
(defn matches [^String regex ^CharSequence input]
(java.util.regex.Pattern/matches regex input))
(gen-wrapper-fn pattern)
(defn pattern-quote [s]
(java.util.regex.Pattern/quote s))
(defn ^:bb/export split
([^java.util.regex.Pattern p ^CharSequence input]
(.split p input))
([^java.util.regex.Pattern p ^CharSequence input ^long limit]
(.split p input limit)))
(gen-wrapper-fn-2 splitAsStream)
(def pattern-bindings
(-> (reduce (fn [acc [k v]]
(let [m (meta v)]
(cond (:bb/export m)
(assoc acc (symbol (str "." k))
@v),
(:bb/export-constant m)
(assoc acc (symbol (:bb/full-name m))
@v)
:else acc)))
{}
(ns-publics *ns*))
;; static method
(assoc (symbol "java.util.regex.Pattern/compile") compile*)
(assoc (symbol "java.util.regex.Pattern/quote") pattern-quote)
(assoc (symbol "java.util.regex.Pattern/matches") matches)))

View file

@ -1,28 +0,0 @@
(ns babashka.impl.System
{:no-doc true})
(defn get-env
([] (System/getenv))
([s] (System/getenv s)))
(defn get-property
([s]
(System/getProperty s))
([s d]
(System/getProperty s d)))
(defn set-property [k v]
(System/setProperty k v))
(defn get-properties []
(System/getProperties))
(defn exit [n]
(throw (ex-info "" {:bb/exit-code n})))
(def system-bindings
{'System/getenv get-env
'System/getProperty get-property
'System/setProperty set-property
'System/getProperties get-properties
'System/exit exit})

View file

@ -1,9 +0,0 @@
(ns babashka.impl.Thread
{:no-doc true})
(defn sleep
([millis] (Thread/sleep millis))
([millis nanos] (Thread/sleep millis nanos)))
(def thread-bindings
{'Thread/sleep sleep})

View file

@ -1,20 +1,12 @@
(ns babashka.main
{:no-doc true}
(:require
[babashka.impl.File :refer [file-bindings]]
[babashka.impl.Integer :refer [integer-bindings]]
[babashka.impl.Double :refer [double-bindings]]
[babashka.impl.Boolean :refer [boolean-bindings]]
[babashka.impl.Pattern :refer [pattern-bindings]]
[babashka.impl.System :refer [system-bindings]]
[babashka.impl.Thread :refer [thread-bindings]]
[babashka.impl.async :refer [async-namespace]]
[babashka.impl.clojure.core :refer [core-extras]]
[babashka.impl.clojure.java.io :refer [io-namespace]]
[babashka.impl.clojure.stacktrace :refer [print-stack-trace]]
[babashka.impl.conch :refer [conch-namespace]]
[babashka.impl.csv :as csv]
[babashka.impl.exceptions :refer [exception-bindings]]
[babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]]
[babashka.impl.socket-repl :as socket-repl]
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
@ -150,16 +142,6 @@ Everything after that is bound to *command-line-args*."))
(str/replace x #"^#!.*" ""))
(throw (Exception. (str "File does not exist: " file))))))
(def bindings
(merge system-bindings
file-bindings
thread-bindings
integer-bindings
double-bindings
boolean-bindings
exception-bindings
pattern-bindings))
(defn read-edn []
(edn/read {;;:readers *data-readers*
:eof ::EOF} *in*))
@ -180,6 +162,9 @@ Everything after that is bound to *command-line-args*."))
;; hang until SIGINT
@(promise)))
(defn exit [n]
(throw (ex-info "" {:bb/exit-code n})))
(defn main
[& args]
(handle-pipe!)
@ -223,9 +208,35 @@ Everything after that is bound to *command-line-args*."))
'me.raynes.conch.low-level conch-namespace
'clojure.core.async async-namespace
'clojure.data.csv csv/csv-namespace}
:bindings (assoc bindings '*command-line-args* command-line-args)
:bindings {'*command-line-args* command-line-args
'java.lang.System/exit exit ;; override exit, so we have more control
'System/exit exit}
:env env
:features #{:bb}}
:features #{:bb}
:classes {'java.lang.ArithmeticException ArithmeticException
'java.lang.AssertionError AssertionError
'java.lang.Boolean Boolean
'java.lang.Class Class
'java.lang.Double Double
'java.lang.Exception Exception
'clojure.lang.ExceptionInfo clojure.lang.ExceptionInfo
'java.lang.Integer Integer
'java.io.File java.io.File
'java.util.regex.Pattern java.util.regex.Pattern
'java.lang.String String
'java.lang.System System
'java.lang.Thread Thread}
:imports '{ArithmeticException java.lang.ArithmeticException
AssertionError java.lang.AssertionError
Boolean java.lang.Boolean
Class java.lang.Class
Double java.lang.Double
Exception java.lang.Exception
Integer java.lang.Integer
File java.io.File
String java.lang.String
System java.lang.System
Thread java.lang.Thread}}
ctx (update ctx :bindings assoc 'eval #(eval* ctx %)
'load-file #(load-file* ctx %))
_preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim) (sci/eval-string ctx))