1
0
mirror of https://github.com/janet-lang/janet synced 2025-02-03 02:39:09 +00:00

Make require simpler and module/find more useful.

This replaces a lot of the functionality in require by moving
it to module/find. module/native-paths and module/image-paths are also
merged into the one module/paths to make it easier to extend. This of
course breaks some of the less important API - module/native-paths no
longer exists.
This commit is contained in:
Calvin Rose 2019-02-16 13:21:29 -05:00
parent ec02d55145
commit 1f91ee30fe
2 changed files with 81 additions and 86 deletions

View File

@ -2,8 +2,9 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## 0.4.0 - ?? ## 0.4.0 - ??
- `write-image` function creates pre compiled images for janet. These images - `make-image` function creates pre compiled images for janet. These images
link to the core library. They can be loaded via require. link to the core library. They can be loaded via require or manually via
`load-image`.
- Add bracketed tuples as tuple constructor. - Add bracketed tuples as tuple constructor.
- Add partition function to core library. - Add partition function to core library.
- Pre-compile core library into an image for faster startup. - Pre-compile core library into an image for faster startup.

View File

@ -1565,32 +1565,39 @@ value, one key will be ignored."
(res) (res)
(error (res :error)))) (error (res :error))))
(defn make-image
"Create an image from an environment returned by require.
Returns the image source as a string."
[env]
(marshal env (invert (env-lookup _env))))
(defn load-image
"The inverse operation to make-image. Returns an environment."
[image]
(unmarshal image (env-lookup _env)))
(def module/paths (def module/paths
"The list of paths to look for modules. The following "The list of paths to look for modules. The following
substitutions are preformed on each path. :sys: becomes substitutions are preformed on each path. :sys: becomes
module/*syspath*, :name: becomes the last part of the module module/*syspath*, :name: becomes the last part of the module
name after the last /, and :all: is the module name literally. name after the last /, and :all: is the module name literally.
:native: becomes the dynamic library file extension, usually dll :native: becomes the dynamic library file extension, usually dll
or so." or so. Each element is a two element tuple, containing the path
@["./:all:.janet" template and a keyword :source, :native, or :image indicating how
"./:all:/init.janet" require should load files found at these paths."
":sys:/:all:.janet" @[["./:all:.janet" :source]
":sys:/:all:/init.janet" ["./:all:/init.janet" :source]
":all:"]) [":sys:/:all:.janet" :source]
[":sys:/:all:/init.janet" :source]
(def module/native-paths ["./:all:.:native:" :native]
"See doc for module/paths" ["./:all:/:name:.:native:" :native]
@["./:all:.:native:" [":sys:/:all:.:native:" :native]
"./:all:/:name:.:native:" [":sys:/:all:/:name:.:native:" :native]
":sys:/:all:.:native:" ["./:all:.jimage" :image]
":sys:/:all:/:name:.:native:"]) ["./:all:.:name:.jimage" :image]
[":sys:/:all:.jimage" :image]
(def module/image-paths [":sys:/:all:/:name:.jimage" :image]
"See doc for module/paths" [":all:" :source]])
@["./:all:.jimage"
"./:all:.:name:.jimage"
":sys:/:all:.jimage"
":sys:/:all:/:name:.jimage"])
(var module/*syspath* (var module/*syspath*
"The path where globally installed libraries are located. "The path where globally installed libraries are located.
@ -1600,20 +1607,36 @@ value, one key will be ignored."
(or (os/getenv "JANET_PATH") (or (os/getenv "JANET_PATH")
(if (= :windows (os/which)) "" "/usr/local/lib/janet"))) (if (= :windows (os/which)) "" "/usr/local/lib/janet")))
(defn- fexists [path]
(def f (file/open path))
(if f (do (file/close f) path)))
(defn module/find (defn module/find
"Try to match a module or path name from the patterns in paths." "Try to match a module or path name from the patterns in module/paths.
[path paths] Returns a tuple (fullpath kind) where the kind is one of :source, :native,
or image if the module is found, otherise a tuple with nil followed by
an error message."
[path]
(def parts (string/split "/" path)) (def parts (string/split "/" path))
(def name (get parts (- (length parts) 1))) (def name (get parts (- (length parts) 1)))
(def nati (if (= :windows (os/which)) "dll" "so")) (def nati (if (= :windows (os/which)) "dll" "so"))
(defn sub-path (defn make-full
[p] [[p mod-kind]]
(->> p (def fullpath (->> p
(string/replace ":name:" name) (string/replace ":name:" name)
(string/replace ":sys:" module/*syspath*) (string/replace ":sys:" module/*syspath*)
(string/replace ":native:" nati) (string/replace ":native:" nati)
(string/replace ":all:" path))) (string/replace ":all:" path)))
(map sub-path paths)) [fullpath mod-kind])
(defn check-path [x] (if (fexists (x 0)) x))
(def paths (map make-full module/paths))
(def res (find check-path paths))
(if res res [nil (string "could not find module "
path
":\n "
;(interpose "\n " (map 0 paths)))]))
(put _env 'fexists nil)
(def module/cache (def module/cache
"Table mapping loaded module identifiers to their environments." "Table mapping loaded module identifiers to their environments."
@ -1624,11 +1647,6 @@ value, one key will be ignored."
circular dependencies." circular dependencies."
@{}) @{})
# Require helpers
(defn- fexists [path]
(def f (file/open path))
(if f (do (file/close f) path)))
(defn require (defn require
"Require a module with the given name. Will search all of the paths in "Require a module with the given name. Will search all of the paths in
module/paths, then the path as a raw file path. Returns the new environment module/paths, then the path as a raw file path. Returns the new environment
@ -1637,55 +1655,31 @@ value, one key will be ignored."
(def {:exit exit-on-error} (table ;args)) (def {:exit exit-on-error} (table ;args))
(if-let [check (get module/cache path)] (if-let [check (get module/cache path)]
check check
(if-let [modpath (find fexists (module/find path module/paths))] (do
(do (def [fullpath mod-kind] (module/find path))
(when (get module/loading modpath) (unless fullpath (error mod-kind))
(error (string "circular dependency: file " modpath " is loading"))) (def env (case mod-kind
# Normal janet module :source (do
(def f (file/open modpath)) # Normal janet module
(def newenv (make-env)) (def f (file/open fullpath))
(put module/loading modpath true) (def newenv (make-env))
(defn chunks [buf _] (file/read f 2048 buf)) (put module/loading fullpath true)
(run-context {:env newenv (defn chunks [buf _] (file/read f 2048 buf))
:chunks chunks (run-context {:env newenv
:on-status (fn [f x] :chunks chunks
(when (not= (fiber/status f) :dead) :on-status (fn [f x]
(debug/stacktrace f x) (when (not= (fiber/status f) :dead)
(if exit-on-error (os/exit 1)))) (debug/stacktrace f x)
:source modpath}) (if exit-on-error (os/exit 1))))
(file/close f) :source fullpath})
(table/setproto newenv nil) (file/close f)
(put module/loading modpath false) (put module/loading fullpath nil)
(put module/cache modpath newenv) (table/setproto newenv nil))
(put module/cache path newenv) :native (native fullpath (make-env))
newenv) :image (load-image (slurp fullpath))))
(if-let [imgpath (find fexists (module/find path module/image-paths))] (put module/cache fullpath env)
(do (put module/cache path env)
# Try image env)))
(def imgsource (slurp imgpath))
(def img (unmarshal imgsource (env-lookup *env*)))
img)
(do
# Try native module
(def n (find fexists (module/find path module/native-paths)))
(if (not n)
(error (string "could not open file for module " path)))
(def e (make-env))
(native n e)
(put module/cache n e)
(put module/cache path e)
e)))))
(put _env 'fexists nil)
(defn write-image
"Create an image from the file at path. Writes the output
image to a file at out."
[path out]
(def env (require path))
(def img (marshal env (invert (env-lookup _env))))
(spit out img)
img)
(defn import* (defn import*
"Import a module into a given environment table. This is the "Import a module into a given environment table. This is the