mirror of
https://github.com/janet-lang/janet
synced 2024-12-26 00:10:27 +00:00
Merge branch 'master' into ev
Also add poll implementation for ev.
This commit is contained in:
commit
babfe50550
4
.gitignore
vendored
4
.gitignore
vendored
@ -66,6 +66,10 @@ tags
|
|||||||
vgcore.*
|
vgcore.*
|
||||||
*.out.*
|
*.out.*
|
||||||
|
|
||||||
|
# Wix artifacts
|
||||||
|
*.msi
|
||||||
|
*.wixpdb
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/c
|
# Created by https://www.gitignore.io/api/c
|
||||||
|
|
||||||
### C ###
|
### C ###
|
||||||
|
12
CHANGELOG.md
12
CHANGELOG.md
@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
## Unreleased - ???
|
## Unreleased - ???
|
||||||
- Silence warnings in some compilers.
|
- Silence warnings in some compilers.
|
||||||
|
- Add C++ support to jpm and improve C++ interop in janet.h.
|
||||||
|
- Add `%t` formatter to `printf`, `string/format`, and other formatter functions.
|
||||||
|
- Expose `janet_cfuns_prefix` in C API.
|
||||||
|
- Add `os/proc-wait` and `os/proc-kill` for interacting with processes.
|
||||||
|
- Add `janet_getjfile` to C API.
|
||||||
|
- Allow redirection of stdin, stdout, and stderr by passing keywords in the env table in `os/spawn` and `os/execute`.
|
||||||
|
- Add `os/spawn` to get a core/process back instead of an exit code as in `os/execute`.
|
||||||
|
When called like this, `os/execute` returns immediately.
|
||||||
|
- Add `:x` flag to os/execute to raise error when exit code is non-zero.
|
||||||
|
- Don't run `main` when flychecking.
|
||||||
|
- Add `:n` flag to `file/open` to raise an error if file cannot be opened.
|
||||||
|
- Fix import macro to not try and coerce everything to a string.
|
||||||
- Allow passing a second argument to `disasm`.
|
- Allow passing a second argument to `disasm`.
|
||||||
- Add `cancel`. Resumes a fiber but makes it immediately error at the yield point.
|
- Add `cancel`. Resumes a fiber but makes it immediately error at the yield point.
|
||||||
- Allow multi-line paste into built in repl.
|
- Allow multi-line paste into built in repl.
|
||||||
|
3
Makefile
3
Makefile
@ -150,7 +150,8 @@ build/janet_boot: $(JANET_BOOT_OBJECTS)
|
|||||||
|
|
||||||
# Now the reason we bootstrap in the first place
|
# Now the reason we bootstrap in the first place
|
||||||
build/janet.c: build/janet_boot src/boot/boot.janet
|
build/janet.c: build/janet_boot src/boot/boot.janet
|
||||||
build/janet_boot . JANET_PATH '$(JANET_PATH)' JANET_HEADERPATH '$(INCLUDEDIR)/janet' > $@
|
build/janet_boot . JANET_PATH '$(JANET_PATH)' > $@
|
||||||
|
cksum $@
|
||||||
|
|
||||||
########################
|
########################
|
||||||
##### Amalgamation #####
|
##### Amalgamation #####
|
||||||
|
136
jpm
136
jpm
@ -132,6 +132,15 @@
|
|||||||
"Convert url with potential bad characters into a file path element."
|
"Convert url with potential bad characters into a file path element."
|
||||||
(peg/compile ~(% (any (+ (/ '(set "<>:\"/\\|?*") "_") '1)))))
|
(peg/compile ~(% (any (+ (/ '(set "<>:\"/\\|?*") "_") '1)))))
|
||||||
|
|
||||||
|
(def- entry-replacer
|
||||||
|
"Convert url with potential bad characters into an entry-name"
|
||||||
|
(peg/compile ~(% (any (+ '(range "AZ" "az" "09" "__") (/ '1 ,|(string "_" ($ 0) "_")))))))
|
||||||
|
|
||||||
|
(defn entry-replace
|
||||||
|
"Escape special characters in the entry-name"
|
||||||
|
[name]
|
||||||
|
(get (peg/match entry-replacer name) 0))
|
||||||
|
|
||||||
(defn filepath-replace
|
(defn filepath-replace
|
||||||
"Remove special characters from a string or path
|
"Remove special characters from a string or path
|
||||||
to make it into a path segment."
|
to make it into a path segment."
|
||||||
@ -323,7 +332,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
(def default-compiler (or (os/getenv "CC") (if is-win "cl.exe" "cc")))
|
(def default-compiler (or (os/getenv "CC") (if is-win "cl.exe" "cc")))
|
||||||
|
(def default-cpp-compiler (or (os/getenv "CXX") (if is-win "cl.exe" "c++")))
|
||||||
(def default-linker (or (os/getenv "CC") (if is-win "link.exe" "cc")))
|
(def default-linker (or (os/getenv "CC") (if is-win "link.exe" "cc")))
|
||||||
|
(def default-cpp-linker (or (os/getenv "CXX") (if is-win "link.exe" "c++")))
|
||||||
(def default-archiver (or (os/getenv "AR") (if is-win "lib.exe" "ar")))
|
(def default-archiver (or (os/getenv "AR") (if is-win "lib.exe" "ar")))
|
||||||
|
|
||||||
# Detect threads
|
# Detect threads
|
||||||
@ -352,6 +363,10 @@
|
|||||||
(if is-win
|
(if is-win
|
||||||
["/nologo" "/MD"]
|
["/nologo" "/MD"]
|
||||||
["-std=c99" "-Wall" "-Wextra"]))
|
["-std=c99" "-Wall" "-Wextra"]))
|
||||||
|
(def default-cppflags
|
||||||
|
(if is-win
|
||||||
|
["/nologo" "/MD" "/EHsc"]
|
||||||
|
["-std=c++11" "-Wall" "-Wextra"]))
|
||||||
(def default-ldflags [])
|
(def default-ldflags [])
|
||||||
|
|
||||||
# Required flags for dynamic libraries. These
|
# Required flags for dynamic libraries. These
|
||||||
@ -424,29 +439,54 @@
|
|||||||
(string "-I" (dyn :headerpath JANET_HEADERPATH))
|
(string "-I" (dyn :headerpath JANET_HEADERPATH))
|
||||||
(string "-O" (opt opts :optimize 2))])
|
(string "-O" (opt opts :optimize 2))])
|
||||||
|
|
||||||
|
(defn- getcppflags
|
||||||
|
"Generate the cpp flags from the input options."
|
||||||
|
[opts]
|
||||||
|
@[;(opt opts :cppflags default-cppflags)
|
||||||
|
(string "-I" (dyn :headerpath JANET_HEADERPATH))
|
||||||
|
(string "-O" (opt opts :optimize 2))])
|
||||||
|
|
||||||
(defn- entry-name
|
(defn- entry-name
|
||||||
"Name of symbol that enters static compilation of a module."
|
"Name of symbol that enters static compilation of a module."
|
||||||
[name]
|
[name]
|
||||||
(string "janet_module_entry_" (filepath-replace name)))
|
(string "janet_module_entry_" (entry-replace name)))
|
||||||
|
|
||||||
(defn- compile-c
|
(defn- compile-c
|
||||||
"Compile a C file into an object file."
|
"Compile a C file into an object file."
|
||||||
[opts src dest &opt static?]
|
[opts src dest &opt static?]
|
||||||
(def cc (opt opts :compiler default-compiler))
|
(def cc (opt opts :compiler default-compiler))
|
||||||
(def cflags [;(getcflags opts) ;(if static? [] dynamic-cflags)])
|
(def cflags [;(getcflags opts) ;(if static? [] dynamic-cflags)])
|
||||||
(def entry-defines (if-let [n (opts :entry-name)]
|
(def entry-defines (if-let [n (and static? (opts :entry-name))]
|
||||||
[(make-define "JANET_ENTRY_NAME" n)]
|
[(make-define "JANET_ENTRY_NAME" n)]
|
||||||
[]))
|
[]))
|
||||||
(def defines [;(make-defines (opt opts :defines {})) ;entry-defines])
|
(def defines [;(make-defines (opt opts :defines {})) ;entry-defines])
|
||||||
(def headers (or (opts :headers) []))
|
(def headers (or (opts :headers) []))
|
||||||
(rule dest [src ;headers]
|
(rule dest [src ;headers]
|
||||||
(check-cc)
|
(check-cc)
|
||||||
(print "compiling " dest "...")
|
(print "compiling " src " to " dest "...")
|
||||||
(create-dirs dest)
|
(create-dirs dest)
|
||||||
(if is-win
|
(if is-win
|
||||||
(shell cc ;defines "/c" ;cflags (string "/Fo" dest) src)
|
(shell cc ;defines "/c" ;cflags (string "/Fo" dest) src)
|
||||||
(shell cc "-c" src ;defines ;cflags "-o" dest))))
|
(shell cc "-c" src ;defines ;cflags "-o" dest))))
|
||||||
|
|
||||||
|
(defn- compile-cpp
|
||||||
|
"Compile a C++ file into an object file."
|
||||||
|
[opts src dest &opt static?]
|
||||||
|
(def cpp (opt opts :cpp-compiler default-cpp-compiler))
|
||||||
|
(def cflags [;(getcppflags opts) ;(if static? [] dynamic-cflags)])
|
||||||
|
(def entry-defines (if-let [n (and static? (opts :entry-name))]
|
||||||
|
[(make-define "JANET_ENTRY_NAME" n)]
|
||||||
|
[]))
|
||||||
|
(def defines [;(make-defines (opt opts :defines {})) ;entry-defines])
|
||||||
|
(def headers (or (opts :headers) []))
|
||||||
|
(rule dest [src ;headers]
|
||||||
|
(check-cc)
|
||||||
|
(print "compiling " src " to " dest "...")
|
||||||
|
(create-dirs dest)
|
||||||
|
(if is-win
|
||||||
|
(shell cpp ;defines "/c" ;cflags (string "/Fo" dest) src)
|
||||||
|
(shell cpp "-c" src ;defines ;cflags "-o" dest))))
|
||||||
|
|
||||||
(defn- libjanet
|
(defn- libjanet
|
||||||
"Find libjanet.a (or libjanet.lib on windows) at compile time"
|
"Find libjanet.a (or libjanet.lib on windows) at compile time"
|
||||||
[]
|
[]
|
||||||
@ -466,7 +506,7 @@
|
|||||||
(string hpath `\\janet.lib`))
|
(string hpath `\\janet.lib`))
|
||||||
|
|
||||||
(defn- link-c
|
(defn- link-c
|
||||||
"Link object files together to make a native module."
|
"Link C object files together to make a native module."
|
||||||
[opts target & objects]
|
[opts target & objects]
|
||||||
(def linker (opt opts (if is-win :linker :compiler) default-linker))
|
(def linker (opt opts (if is-win :linker :compiler) default-linker))
|
||||||
(def cflags (getcflags opts))
|
(def cflags (getcflags opts))
|
||||||
@ -481,6 +521,22 @@
|
|||||||
(shell linker ;ldflags (string "/OUT:" target) ;objects (win-import-library) ;lflags)
|
(shell linker ;ldflags (string "/OUT:" target) ;objects (win-import-library) ;lflags)
|
||||||
(shell linker ;cflags ;ldflags `-o` target ;objects ;lflags))))
|
(shell linker ;cflags ;ldflags `-o` target ;objects ;lflags))))
|
||||||
|
|
||||||
|
(defn- link-cpp
|
||||||
|
"Link C++ object files together to make a native module."
|
||||||
|
[opts target & objects]
|
||||||
|
(def linker (opt opts (if is-win :cpp-linker :cpp-compiler) default-cpp-linker))
|
||||||
|
(def cflags (getcppflags opts))
|
||||||
|
(def lflags [;(opt opts :lflags default-lflags)
|
||||||
|
;(if (opts :static) [] dynamic-lflags)])
|
||||||
|
(def ldflags [;(opt opts :ldflags [])])
|
||||||
|
(rule target objects
|
||||||
|
(check-cc)
|
||||||
|
(print "linking " target "...")
|
||||||
|
(create-dirs target)
|
||||||
|
(if is-win
|
||||||
|
(shell linker ;ldflags (string "/OUT:" target) ;objects (win-import-library) ;lflags)
|
||||||
|
(shell linker ;cflags ;ldflags `-o` target ;objects ;lflags))))
|
||||||
|
|
||||||
(defn- archive-c
|
(defn- archive-c
|
||||||
"Link object files together to make a static library."
|
"Link object files together to make a static library."
|
||||||
[opts target & objects]
|
[opts target & objects]
|
||||||
@ -655,10 +711,12 @@ int main(int argc, const char **argv) {
|
|||||||
(table/setproto m oldproto))
|
(table/setproto m oldproto))
|
||||||
|
|
||||||
# Find static modules
|
# Find static modules
|
||||||
|
(var has-cpp false)
|
||||||
(def declarations @"")
|
(def declarations @"")
|
||||||
(def lookup-into-invocations @"")
|
(def lookup-into-invocations @"")
|
||||||
(loop [[prefix name] :pairs prefixes]
|
(loop [[prefix name] :pairs prefixes]
|
||||||
(def meta (eval-string (slurp (modpath-to-meta name))))
|
(def meta (eval-string (slurp (modpath-to-meta name))))
|
||||||
|
(if (meta :cpp) (set has-cpp true))
|
||||||
(buffer/push-string lookup-into-invocations
|
(buffer/push-string lookup-into-invocations
|
||||||
" temptab = janet_table(0);\n"
|
" temptab = janet_table(0);\n"
|
||||||
" temptab->proto = env;\n"
|
" temptab->proto = env;\n"
|
||||||
@ -681,17 +739,33 @@ int main(int argc, const char **argv) {
|
|||||||
(create-buffer-c-impl image cimage_dest "janet_payload_image")
|
(create-buffer-c-impl image cimage_dest "janet_payload_image")
|
||||||
# Append main function
|
# Append main function
|
||||||
(spit cimage_dest (make-bin-source declarations lookup-into-invocations) :ab)
|
(spit cimage_dest (make-bin-source declarations lookup-into-invocations) :ab)
|
||||||
|
(def oimage_dest (out-path cimage_dest ".c" ".o"))
|
||||||
# Compile and link final exectable
|
# Compile and link final exectable
|
||||||
(unless no-compile
|
(unless no-compile
|
||||||
(def cc (opt opts :compiler default-compiler))
|
|
||||||
(def ldflags [;dep-ldflags ;(opt opts :ldflags []) ;janet-ldflags])
|
(def ldflags [;dep-ldflags ;(opt opts :ldflags []) ;janet-ldflags])
|
||||||
(def lflags [;static-libs (libjanet) ;dep-lflags ;(opt opts :lflags default-lflags) ;janet-lflags])
|
(def lflags [;static-libs (libjanet) ;dep-lflags ;(opt opts :lflags default-lflags) ;janet-lflags])
|
||||||
(def cflags [;(getcflags opts) ;janet-cflags])
|
|
||||||
(def defines (make-defines (opt opts :defines {})))
|
(def defines (make-defines (opt opts :defines {})))
|
||||||
(print "compiling and linking " dest "...")
|
(def cc (opt opts :compiler default-compiler))
|
||||||
|
(def cflags [;(getcflags opts) ;janet-cflags])
|
||||||
|
(check-cc)
|
||||||
|
(print "compiling " cimage_dest " to " oimage_dest "...")
|
||||||
|
(create-dirs oimage_dest)
|
||||||
(if is-win
|
(if is-win
|
||||||
(shell cc ;cflags ;ldflags cimage_dest ;lflags `/link` (string "/OUT:" dest))
|
(shell cc ;defines "/c" ;cflags (string "/Fo" oimage_dest) cimage_dest)
|
||||||
(shell cc ;cflags ;ldflags `-o` dest cimage_dest ;lflags)))))
|
(shell cc "-c" cimage_dest ;defines ;cflags "-o" oimage_dest))
|
||||||
|
(if has-cpp
|
||||||
|
(let [linker (opt opts (if is-win :cpp-linker :cpp-compiler) default-cpp-linker)
|
||||||
|
cppflags [;(getcppflags opts) ;janet-cflags]]
|
||||||
|
(print "linking " dest "...")
|
||||||
|
(if is-win
|
||||||
|
(shell linker ;ldflags (string "/OUT:" dest) oimage_dest ;lflags)
|
||||||
|
(shell linker ;cppflags ;ldflags `-o` dest oimage_dest ;lflags)))
|
||||||
|
(let [linker (opt opts (if is-win :linker :compiler) default-linker)]
|
||||||
|
(print "linking " dest "...")
|
||||||
|
(create-dirs dest)
|
||||||
|
(if is-win
|
||||||
|
(shell linker ;ldflags (string "/OUT:" dest) oimage_dest ;lflags)
|
||||||
|
(shell linker ;cflags ;ldflags `-o` dest oimage_dest ;lflags)))))))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Installation and Dependencies
|
# Installation and Dependencies
|
||||||
@ -853,9 +927,23 @@ int main(int argc, const char **argv) {
|
|||||||
|
|
||||||
# Make dynamic module
|
# Make dynamic module
|
||||||
(def lname (string "build" sep name modext))
|
(def lname (string "build" sep name modext))
|
||||||
(loop [src :in sources]
|
|
||||||
(compile-c opts src (out-path src ".c" objext)))
|
# Get objects to build with
|
||||||
(def objects (map (fn [path] (out-path path ".c" objext)) sources))
|
(var has-cpp false)
|
||||||
|
(def objects
|
||||||
|
(seq [src :in sources]
|
||||||
|
(cond
|
||||||
|
(string/has-suffix? ".cpp" src)
|
||||||
|
(let [op (out-path src ".cpp" objext)]
|
||||||
|
(compile-cpp opts src op)
|
||||||
|
(set has-cpp true)
|
||||||
|
op)
|
||||||
|
(string/has-suffix? ".c" src)
|
||||||
|
(let [op (out-path src ".c" objext)]
|
||||||
|
(compile-c opts src op)
|
||||||
|
op)
|
||||||
|
(errorf "unknown source file type: %s, expected .c or .cpp"))))
|
||||||
|
|
||||||
(when-let [embedded (opts :embedded)]
|
(when-let [embedded (opts :embedded)]
|
||||||
(loop [src :in embedded]
|
(loop [src :in embedded]
|
||||||
(def c-src (out-path src ".janet" ".janet.c"))
|
(def c-src (out-path src ".janet" ".janet.c"))
|
||||||
@ -863,7 +951,7 @@ int main(int argc, const char **argv) {
|
|||||||
(array/push objects o-src)
|
(array/push objects o-src)
|
||||||
(create-buffer-c src c-src (embed-name src))
|
(create-buffer-c src c-src (embed-name src))
|
||||||
(compile-c opts c-src o-src)))
|
(compile-c opts c-src o-src)))
|
||||||
(link-c opts lname ;objects)
|
((if has-cpp link-cpp link-c) opts lname ;objects)
|
||||||
(add-dep "build" lname)
|
(add-dep "build" lname)
|
||||||
(install-rule lname path)
|
(install-rule lname path)
|
||||||
|
|
||||||
@ -876,6 +964,7 @@ int main(int argc, const char **argv) {
|
|||||||
"# Metadata for static library %s\n\n%.20p"
|
"# Metadata for static library %s\n\n%.20p"
|
||||||
(string name statext)
|
(string name statext)
|
||||||
{:static-entry ename
|
{:static-entry ename
|
||||||
|
:cpp has-cpp
|
||||||
:ldflags ~',(opts :ldflags)
|
:ldflags ~',(opts :ldflags)
|
||||||
:lflags ~',(opts :lflags)})))
|
:lflags ~',(opts :lflags)})))
|
||||||
(add-dep "build" metaname)
|
(add-dep "build" metaname)
|
||||||
@ -887,9 +976,21 @@ int main(int argc, const char **argv) {
|
|||||||
(def opts (merge @{:entry-name ename} opts))
|
(def opts (merge @{:entry-name ename} opts))
|
||||||
(def sobjext (string ".static" objext))
|
(def sobjext (string ".static" objext))
|
||||||
(def sjobjext (string ".janet" sobjext))
|
(def sjobjext (string ".janet" sobjext))
|
||||||
(loop [src :in sources]
|
|
||||||
(compile-c opts src (out-path src ".c" sobjext) true))
|
# Get static objects
|
||||||
(def sobjects (map (fn [path] (out-path path ".c" sobjext)) sources))
|
(def sobjects
|
||||||
|
(seq [src :in sources]
|
||||||
|
(cond
|
||||||
|
(string/has-suffix? ".cpp" src)
|
||||||
|
(let [op (out-path src ".cpp" sobjext)]
|
||||||
|
(compile-cpp opts src op true)
|
||||||
|
op)
|
||||||
|
(string/has-suffix? ".c" src)
|
||||||
|
(let [op (out-path src ".c" sobjext)]
|
||||||
|
(compile-c opts src op true)
|
||||||
|
op)
|
||||||
|
(errorf "unknown source file type: %s, expected .c or .cpp"))))
|
||||||
|
|
||||||
(when-let [embedded (opts :embedded)]
|
(when-let [embedded (opts :embedded)]
|
||||||
(loop [src :in embedded]
|
(loop [src :in embedded]
|
||||||
(def c-src (out-path src ".janet" ".janet.c"))
|
(def c-src (out-path src ".janet" ".janet.c"))
|
||||||
@ -1139,7 +1240,8 @@ Keys are:
|
|||||||
--binpath : The directory to install binaries and scripts. Defaults to $JANET_BINPATH.
|
--binpath : The directory to install binaries and scripts. Defaults to $JANET_BINPATH.
|
||||||
--libpath : The directory containing janet C libraries (libjanet.*). Defaults to $JANET_LIBPATH.
|
--libpath : The directory containing janet C libraries (libjanet.*). Defaults to $JANET_LIBPATH.
|
||||||
--compiler : C compiler to use for natives. Defaults to $CC or cc (cl.exe on windows).
|
--compiler : C compiler to use for natives. Defaults to $CC or cc (cl.exe on windows).
|
||||||
--archiver : C compiler to use for static libraries. Defaults to $AR ar (lib.exe on windows).
|
--cpp-compiler : C++ compiler to use for natives. Defaults to $CXX or c++ (cl.exe on windows).
|
||||||
|
--archiver : C archiver to use for static libraries. Defaults to $AR ar (lib.exe on windows).
|
||||||
--linker : C linker to use for linking natives. Defaults to link.exe on windows, not used on
|
--linker : C linker to use for linking natives. Defaults to link.exe on windows, not used on
|
||||||
other platforms.
|
other platforms.
|
||||||
--pkglist : URL of git repository for package listing. Defaults to $JANET_PKGLIST or https://github.com/janet-lang/pkgs.git
|
--pkglist : URL of git repository for package listing. Defaults to $JANET_PKGLIST or https://github.com/janet-lang/pkgs.git
|
||||||
|
6
jpm.1
6
jpm.1
@ -71,9 +71,13 @@ $JANET_LIBPATH, or a reasonable default. See JANET_LIBPATH for more.
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-\-compiler=$CC
|
.BR \-\-compiler=$CC
|
||||||
Sets the compiler used for compiling native modules and standalone executables. Defaults
|
Sets the C compiler used for compiling native modules and standalone executables. Defaults
|
||||||
to cc.
|
to cc.
|
||||||
|
|
||||||
|
.BR \-\-cpp\-compiler=$CXX
|
||||||
|
Sets the C++ compiler used for compiling native modules and standalone executables. Defaults
|
||||||
|
to c++..
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-\-linker
|
.BR \-\-linker
|
||||||
Sets the linker used to create native modules and executables. Only used on windows, where
|
Sets the linker used to create native modules and executables. Only used on windows, where
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
###
|
###
|
||||||
###
|
###
|
||||||
|
|
||||||
|
(def root-env "The root environment used to create environments with (make-env)" _env)
|
||||||
|
|
||||||
(def defn :macro
|
(def defn :macro
|
||||||
"(defn name & more)\n\nDefine a function. Equivalent to (def name (fn name [args] ...))."
|
"(defn name & more)\n\nDefine a function. Equivalent to (def name (fn name [args] ...))."
|
||||||
(fn defn [name & more]
|
(fn defn [name & more]
|
||||||
@ -81,10 +83,6 @@
|
|||||||
(defn nan? "Check if x is NaN" [x] (not= x x))
|
(defn nan? "Check if x is NaN" [x] (not= x x))
|
||||||
(defn even? "Check if x is even." [x] (= 0 (mod x 2)))
|
(defn even? "Check if x is even." [x] (= 0 (mod x 2)))
|
||||||
(defn odd? "Check if x is odd." [x] (= 1 (mod x 2)))
|
(defn odd? "Check if x is odd." [x] (= 1 (mod x 2)))
|
||||||
(defn zero? "Check if x is zero." [x] (= x 0))
|
|
||||||
(defn pos? "Check if x is greater than 0." [x] (> x 0))
|
|
||||||
(defn neg? "Check if x is less than 0." [x] (< x 0))
|
|
||||||
(defn one? "Check if x is equal to 1." [x] (= x 1))
|
|
||||||
(defn number? "Check if x is a number." [x] (= (type x) :number))
|
(defn number? "Check if x is a number." [x] (= (type x) :number))
|
||||||
(defn fiber? "Check if x is a fiber." [x] (= (type x) :fiber))
|
(defn fiber? "Check if x is a fiber." [x] (= (type x) :fiber))
|
||||||
(defn string? "Check if x is a string." [x] (= (type x) :string))
|
(defn string? "Check if x is a string." [x] (= (type x) :string))
|
||||||
@ -567,15 +565,6 @@
|
|||||||
[head & body]
|
[head & body]
|
||||||
(loop1 body head 0))
|
(loop1 body head 0))
|
||||||
|
|
||||||
(put _env 'loop1 nil)
|
|
||||||
(put _env 'check-indexed nil)
|
|
||||||
(put _env 'for-template nil)
|
|
||||||
(put _env 'for-var-template nil)
|
|
||||||
(put _env 'iterate-template nil)
|
|
||||||
(put _env 'each-template nil)
|
|
||||||
(put _env 'range-template nil)
|
|
||||||
(put _env 'loop-fiber-template nil)
|
|
||||||
|
|
||||||
(defmacro seq
|
(defmacro seq
|
||||||
"Similar to loop, but accumulates the loop body into an array and returns that.
|
"Similar to loop, but accumulates the loop body into an array and returns that.
|
||||||
See loop for details."
|
See loop for details."
|
||||||
@ -594,6 +583,16 @@
|
|||||||
[& body]
|
[& body]
|
||||||
(tuple fiber/new (tuple 'fn '[] ;body) :yi))
|
(tuple fiber/new (tuple 'fn '[] ;body) :yi))
|
||||||
|
|
||||||
|
(defmacro- undef
|
||||||
|
"Remove binding from root-env"
|
||||||
|
[& syms]
|
||||||
|
~(do ,;(seq [s :in syms] ~(put root-env ',s nil))))
|
||||||
|
|
||||||
|
(undef _env)
|
||||||
|
|
||||||
|
(undef loop1 check-indexed for-template for-var-template iterate-template
|
||||||
|
each-template range-template loop-fiber-template)
|
||||||
|
|
||||||
(defn sum
|
(defn sum
|
||||||
"Returns the sum of xs. If xs is empty, returns 0."
|
"Returns the sum of xs. If xs is empty, returns 0."
|
||||||
[xs]
|
[xs]
|
||||||
@ -619,7 +618,7 @@
|
|||||||
the fal form. Bindings have the same syntax as the let macro."
|
the fal form. Bindings have the same syntax as the let macro."
|
||||||
[bindings tru &opt fal]
|
[bindings tru &opt fal]
|
||||||
(def len (length bindings))
|
(def len (length bindings))
|
||||||
(if (zero? len) (error "expected at least 1 binding"))
|
(if (= 0 len) (error "expected at least 1 binding"))
|
||||||
(if (odd? len) (error "expected an even number of bindings"))
|
(if (odd? len) (error "expected an even number of bindings"))
|
||||||
(defn aux [i]
|
(defn aux [i]
|
||||||
(if (>= i len)
|
(if (>= i len)
|
||||||
@ -749,7 +748,12 @@
|
|||||||
[& xs]
|
[& xs]
|
||||||
(compare-reduce >= xs))
|
(compare-reduce >= xs))
|
||||||
|
|
||||||
(put _env 'compare-reduce nil)
|
(defn zero? "Check if x is zero." [x] (= (compare x 0) 0))
|
||||||
|
(defn pos? "Check if x is greater than 0." [x] (= (compare x 0) 1))
|
||||||
|
(defn neg? "Check if x is less than 0." [x] (= (compare x 0) -1))
|
||||||
|
(defn one? "Check if x is equal to 1." [x] (= (compare x 1) 0))
|
||||||
|
|
||||||
|
(undef compare-reduce)
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@ -785,8 +789,8 @@
|
|||||||
[a &opt by]
|
[a &opt by]
|
||||||
(sort-help a 0 (- (length a) 1) (or by <)))
|
(sort-help a 0 (- (length a) 1) (or by <)))
|
||||||
|
|
||||||
(put _env 'sort-part nil)
|
(undef sort-part)
|
||||||
(put _env 'sort-help nil)
|
(undef sort-help)
|
||||||
|
|
||||||
(defn sort-by
|
(defn sort-by
|
||||||
"Returns a new sorted array that compares elements by invoking
|
"Returns a new sorted array that compares elements by invoking
|
||||||
@ -1140,8 +1144,8 @@
|
|||||||
:tuple (tuple/slice (walk-ind f form))
|
:tuple (tuple/slice (walk-ind f form))
|
||||||
form))
|
form))
|
||||||
|
|
||||||
(put _env 'walk-ind nil)
|
(undef walk-ind)
|
||||||
(put _env 'walk-dict nil)
|
(undef walk-dict)
|
||||||
|
|
||||||
(defn postwalk
|
(defn postwalk
|
||||||
"Do a post-order traversal of a data structure and call (f x)
|
"Do a post-order traversal of a data structure and call (f x)
|
||||||
@ -1350,7 +1354,7 @@
|
|||||||
[tab & colls]
|
[tab & colls]
|
||||||
(loop [c :in colls
|
(loop [c :in colls
|
||||||
key :keys c]
|
key :keys c]
|
||||||
(set (tab key) (in c key)))
|
(put tab key (in c key)))
|
||||||
tab)
|
tab)
|
||||||
|
|
||||||
(defn merge
|
(defn merge
|
||||||
@ -1361,7 +1365,7 @@
|
|||||||
(def container @{})
|
(def container @{})
|
||||||
(loop [c :in colls
|
(loop [c :in colls
|
||||||
key :keys c]
|
key :keys c]
|
||||||
(set (container key) (in c key)))
|
(put container key (in c key)))
|
||||||
container)
|
container)
|
||||||
|
|
||||||
(defn keys
|
(defn keys
|
||||||
@ -1615,9 +1619,9 @@
|
|||||||
,(aux (+ 2 i))
|
,(aux (+ 2 i))
|
||||||
,$res)))) 0)))
|
,$res)))) 0)))
|
||||||
|
|
||||||
(put _env 'sentinel nil)
|
(undef sentinel)
|
||||||
(put _env 'match-1 nil)
|
(undef match-1)
|
||||||
(put _env 'with-idemp nil)
|
(undef with-idemp)
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@ -1742,8 +1746,8 @@
|
|||||||
[&opt sym]
|
[&opt sym]
|
||||||
~(,doc* ',sym))
|
~(,doc* ',sym))
|
||||||
|
|
||||||
(put _env 'env-walk nil)
|
(undef env-walk)
|
||||||
(put _env 'print-index nil)
|
(undef print-index)
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@ -1877,7 +1881,7 @@
|
|||||||
(case tx
|
(case tx
|
||||||
:tuple (or (not= (length x) (length y)) (some identity (map deep-not= x y)))
|
:tuple (or (not= (length x) (length y)) (some identity (map deep-not= x y)))
|
||||||
:array (or (not= (length x) (length y)) (some identity (map deep-not= x y)))
|
:array (or (not= (length x) (length y)) (some identity (map deep-not= x y)))
|
||||||
:struct (deep-not= (pairs x) (pairs y))
|
:struct (deep-not= (kvs x) (kvs y))
|
||||||
:table (deep-not= (table/to-struct x) (table/to-struct y))
|
:table (deep-not= (table/to-struct x) (table/to-struct y))
|
||||||
:buffer (not= (string x) (string y))
|
:buffer (not= (string x) (string y))
|
||||||
(not= x y))))
|
(not= x y))))
|
||||||
@ -2032,7 +2036,7 @@
|
|||||||
will inherit bindings from the parent environment, but new
|
will inherit bindings from the parent environment, but new
|
||||||
bindings will not pollute the parent environment."
|
bindings will not pollute the parent environment."
|
||||||
[&opt parent]
|
[&opt parent]
|
||||||
(def parent (if parent parent _env))
|
(def parent (if parent parent root-env))
|
||||||
(def newenv (table/setproto @{} parent))
|
(def newenv (table/setproto @{} parent))
|
||||||
newenv)
|
newenv)
|
||||||
|
|
||||||
@ -2248,10 +2252,11 @@
|
|||||||
by make-image, such that (load-image bytes) is the same as (unmarshal bytes load-image-dict)."
|
by make-image, such that (load-image bytes) is the same as (unmarshal bytes load-image-dict)."
|
||||||
@{})
|
@{})
|
||||||
|
|
||||||
(def comptime
|
(defmacro comptime
|
||||||
"(comptime x)\n\n
|
"(comptime x)\n\n
|
||||||
Evals x at compile time and returns the result. Similar to a top level unquote."
|
Evals x at compile time and returns the result. Similar to a top level unquote."
|
||||||
:macro eval)
|
[x]
|
||||||
|
(eval x))
|
||||||
|
|
||||||
(defn make-image
|
(defn make-image
|
||||||
"Create an image from an environment returned by require.
|
"Create an image from an environment returned by require.
|
||||||
@ -2305,7 +2310,7 @@
|
|||||||
(module/add-paths ".jimage" :image)
|
(module/add-paths ".jimage" :image)
|
||||||
|
|
||||||
# Version of fexists that works even with a reduced OS
|
# Version of fexists that works even with a reduced OS
|
||||||
(if-let [has-stat (_env 'os/stat)]
|
(if-let [has-stat (root-env 'os/stat)]
|
||||||
(let [stat (has-stat :value)]
|
(let [stat (has-stat :value)]
|
||||||
(defglobal "fexists" (fn fexists [path] (= :file (stat path :mode)))))
|
(defglobal "fexists" (fn fexists [path] (= :file (stat path :mode)))))
|
||||||
(defglobal "fexists"
|
(defglobal "fexists"
|
||||||
@ -2352,10 +2357,10 @@
|
|||||||
str-parts (interpose "\n " paths)]
|
str-parts (interpose "\n " paths)]
|
||||||
[nil (string "could not find module " path ":\n " ;str-parts)])))
|
[nil (string "could not find module " path ":\n " ;str-parts)])))
|
||||||
|
|
||||||
(put _env 'fexists nil)
|
(undef fexists)
|
||||||
(put _env 'mod-filter nil)
|
(undef mod-filter)
|
||||||
(put _env 'check-. nil)
|
(undef check-.)
|
||||||
(put _env 'not-check-. nil)
|
(undef not-check-.)
|
||||||
|
|
||||||
(def module/cache
|
(def module/cache
|
||||||
"Table mapping loaded module identifiers to their environments."
|
"Table mapping loaded module identifiers to their environments."
|
||||||
@ -2463,7 +2468,7 @@
|
|||||||
(def newv (table/setproto @{:private (not ep)} v))
|
(def newv (table/setproto @{:private (not ep)} v))
|
||||||
(put env (symbol prefix k) newv)))
|
(put env (symbol prefix k) newv)))
|
||||||
|
|
||||||
(put _env 'require-1 nil)
|
(undef require-1)
|
||||||
|
|
||||||
(defmacro import
|
(defmacro import
|
||||||
"Import a module. First requires the module, and then merges its
|
"Import a module. First requires the module, and then merges its
|
||||||
@ -2530,7 +2535,7 @@
|
|||||||
(in (.slots frame-idx) (or nth 0)))
|
(in (.slots frame-idx) (or nth 0)))
|
||||||
|
|
||||||
# Conditional compilation for disasm
|
# Conditional compilation for disasm
|
||||||
(def disasm-alias (if-let [x (_env 'disasm)] (x :value)))
|
(def disasm-alias (if-let [x (root-env 'disasm)] (x :value)))
|
||||||
|
|
||||||
(defn .disasm
|
(defn .disasm
|
||||||
"Gets the assembly for the current function."
|
"Gets the assembly for the current function."
|
||||||
@ -2592,13 +2597,9 @@
|
|||||||
(debug/unfbreak fun i))
|
(debug/unfbreak fun i))
|
||||||
(print "Cleared " (length bytecode) " breakpoints in " fun))
|
(print "Cleared " (length bytecode) " breakpoints in " fun))
|
||||||
|
|
||||||
(unless (get _env 'disasm)
|
(unless (get root-env 'disasm)
|
||||||
(put _env '.disasm nil)
|
(undef .disasm .bytecode .breakall .clearall .ppasm))
|
||||||
(put _env '.bytecode nil)
|
(undef disasm-alias)
|
||||||
(put _env '.breakall nil)
|
|
||||||
(put _env '.clearall nil)
|
|
||||||
(put _env '.ppasm nil))
|
|
||||||
(put _env 'disasm-alias nil)
|
|
||||||
|
|
||||||
(defn .source
|
(defn .source
|
||||||
"Show the source code for the function being debugged."
|
"Show the source code for the function being debugged."
|
||||||
@ -2652,9 +2653,9 @@
|
|||||||
"An environment that contains dot prefixed functions for debugging."
|
"An environment that contains dot prefixed functions for debugging."
|
||||||
@{})
|
@{})
|
||||||
|
|
||||||
(def- debugger-keys (filter (partial string/has-prefix? ".") (keys _env)))
|
(def- debugger-keys (filter (partial string/has-prefix? ".") (keys root-env)))
|
||||||
(each k debugger-keys (put debugger-env k (_env k)) (put _env k nil))
|
(each k debugger-keys (put debugger-env k (root-env k)) (put root-env k nil))
|
||||||
(put _env 'debugger-keys nil)
|
(undef debugger-keys)
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@ -2750,7 +2751,7 @@
|
|||||||
(each a args (import* (string a) :prefix "" :evaluator evaluator)))
|
(each a args (import* (string a) :prefix "" :evaluator evaluator)))
|
||||||
|
|
||||||
# conditional compilation for reduced os
|
# conditional compilation for reduced os
|
||||||
(def- getenv-alias (if-let [entry (in _env 'os/getenv)] (entry :value) (fn [&])))
|
(def- getenv-alias (if-let [entry (in root-env 'os/getenv)] (entry :value) (fn [&])))
|
||||||
|
|
||||||
(defn cli-main
|
(defn cli-main
|
||||||
"Entrance for the Janet CLI tool. Call this functions with the command line
|
"Entrance for the Janet CLI tool. Call this functions with the command line
|
||||||
@ -2859,9 +2860,10 @@
|
|||||||
(def subargs (array/slice args i))
|
(def subargs (array/slice args i))
|
||||||
(put env :args subargs)
|
(put env :args subargs)
|
||||||
(dofile arg :prefix "" :exit *exit-on-error* :evaluator evaluator :env env)
|
(dofile arg :prefix "" :exit *exit-on-error* :evaluator evaluator :env env)
|
||||||
|
(unless *compile-only*
|
||||||
(if-let [main (get (in env 'main) :value)]
|
(if-let [main (get (in env 'main) :value)]
|
||||||
(let [thunk (compile [main ;(tuple/slice args i)] env arg)]
|
(let [thunk (compile [main ;(tuple/slice args i)] env arg)]
|
||||||
(if (function? thunk) (thunk) (error (thunk :error)))))
|
(if (function? thunk) (thunk) (error (thunk :error))))))
|
||||||
(set i lenargs))))
|
(set i lenargs))))
|
||||||
|
|
||||||
(when (and (not *compile-only*) (or *should-repl* *no-file*))
|
(when (and (not *compile-only*) (or *should-repl* *no-file*))
|
||||||
@ -2884,12 +2886,7 @@
|
|||||||
(setdyn :err-color (if *colorize* true))
|
(setdyn :err-color (if *colorize* true))
|
||||||
(repl getchunk nil env)))
|
(repl getchunk nil env)))
|
||||||
|
|
||||||
(put _env 'no-side-effects nil)
|
(undef no-side-effects is-safe-def safe-forms importers use-2 getenv-alias)
|
||||||
(put _env 'is-safe-def nil)
|
|
||||||
(put _env 'safe-forms nil)
|
|
||||||
(put _env 'importers nil)
|
|
||||||
(put _env 'use-2 nil)
|
|
||||||
(put _env 'getenv-alias nil)
|
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@ -2897,12 +2894,13 @@
|
|||||||
###
|
###
|
||||||
###
|
###
|
||||||
|
|
||||||
(def root-env "The root environment used to create environments with (make-env)" _env)
|
|
||||||
|
|
||||||
(do
|
(do
|
||||||
(put _env 'boot/opts nil)
|
(undef boot/opts undef)
|
||||||
(put _env '_env nil)
|
(def load-dict (env-lookup root-env))
|
||||||
(def load-dict (env-lookup _env))
|
(put load-dict 'boot/config nil)
|
||||||
|
(put load-dict 'boot/args nil)
|
||||||
|
(each [k v] (pairs load-dict)
|
||||||
|
(if (number? v) (put load-dict k nil)))
|
||||||
(merge-into load-image-dict load-dict)
|
(merge-into load-image-dict load-dict)
|
||||||
(merge-into make-image-dict (invert load-dict)))
|
(merge-into make-image-dict (invert load-dict)))
|
||||||
|
|
||||||
@ -2923,25 +2921,29 @@
|
|||||||
(put into k (x k))))
|
(put into k (x k))))
|
||||||
into)
|
into)
|
||||||
|
|
||||||
(def env (fiber/getenv (fiber/current)))
|
|
||||||
|
|
||||||
# Modify env based on some options.
|
# Modify env based on some options.
|
||||||
(loop [[k v] :pairs env
|
(loop [[k v] :pairs root-env
|
||||||
:when (symbol? k)]
|
:when (symbol? k)]
|
||||||
(def flat (proto-flatten @{} v))
|
(def flat (proto-flatten @{} v))
|
||||||
(when (boot/config :no-docstrings)
|
(when (boot/config :no-docstrings)
|
||||||
(put flat :doc nil))
|
(put flat :doc nil))
|
||||||
(when (boot/config :no-sourcemaps)
|
(when (boot/config :no-sourcemaps)
|
||||||
(put flat :source-map nil))
|
(put flat :source-map nil))
|
||||||
(put env k flat))
|
(put root-env k flat))
|
||||||
|
|
||||||
(put env 'boot/config nil)
|
(put root-env 'boot/config nil)
|
||||||
(put env 'boot/args nil)
|
(put root-env 'boot/args nil)
|
||||||
(def image (let [env-pairs (pairs (env-lookup env))
|
|
||||||
|
(def image (let [env-pairs (pairs (env-lookup root-env))
|
||||||
essential-pairs (filter (fn [[k v]] (or (cfunction? v) (abstract? v))) env-pairs)
|
essential-pairs (filter (fn [[k v]] (or (cfunction? v) (abstract? v))) env-pairs)
|
||||||
lookup (table ;(mapcat identity essential-pairs))
|
lookup (table ;(mapcat identity essential-pairs))
|
||||||
reverse-lookup (invert lookup)]
|
reverse-lookup (invert lookup)]
|
||||||
(marshal env reverse-lookup)))
|
# Check no duplicate values
|
||||||
|
(def temp @{})
|
||||||
|
(eachp [k v] lookup
|
||||||
|
(if (in temp v) (errorf "duplicate value: %v" v))
|
||||||
|
(put temp v k))
|
||||||
|
(marshal root-env reverse-lookup)))
|
||||||
|
|
||||||
# Create amalgamation
|
# Create amalgamation
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <janet.h>
|
#include <janet.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
@ -44,6 +45,11 @@ int system_test() {
|
|||||||
assert(janet_equals(janet_wrap_integer(INT32_MIN), janet_wrap_integer(INT32_MIN)));
|
assert(janet_equals(janet_wrap_integer(INT32_MIN), janet_wrap_integer(INT32_MIN)));
|
||||||
assert(janet_equals(janet_wrap_number(1.4), janet_wrap_number(1.4)));
|
assert(janet_equals(janet_wrap_number(1.4), janet_wrap_number(1.4)));
|
||||||
assert(janet_equals(janet_wrap_number(3.14159265), janet_wrap_number(3.14159265)));
|
assert(janet_equals(janet_wrap_number(3.14159265), janet_wrap_number(3.14159265)));
|
||||||
|
#ifdef NAN
|
||||||
|
assert(janet_checktype(janet_wrap_number(NAN), JANET_NUMBER));
|
||||||
|
#else
|
||||||
|
assert(janet_checktype(janet_wrap_number(0.0 / 0.0), JANET_NUMBER));
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(NULL != &janet_wrap_nil);
|
assert(NULL != &janet_wrap_nil);
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@
|
|||||||
/* #define JANET_STACK_MAX 16384 */
|
/* #define JANET_STACK_MAX 16384 */
|
||||||
/* #define JANET_OS_NAME my-custom-os */
|
/* #define JANET_OS_NAME my-custom-os */
|
||||||
/* #define JANET_ARCH_NAME pdp-8 */
|
/* #define JANET_ARCH_NAME pdp-8 */
|
||||||
|
/* #define JANET_EV_EPOLL */
|
||||||
|
|
||||||
/* Main client settings, does not affect library code */
|
/* Main client settings, does not affect library code */
|
||||||
/* #define JANET_SIMPLE_GETLINE */
|
/* #define JANET_SIMPLE_GETLINE */
|
||||||
|
@ -1221,7 +1221,7 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load core cfunctions (and some built in janet assembly functions) */
|
/* Load core cfunctions (and some built in janet assembly functions) */
|
||||||
JanetTable *dict = janet_table(300);
|
JanetTable *dict = janet_table(512);
|
||||||
janet_load_libs(dict);
|
janet_load_libs(dict);
|
||||||
|
|
||||||
/* Add replacements */
|
/* Add replacements */
|
||||||
|
144
src/core/ev.c
144
src/core/ev.c
@ -237,6 +237,7 @@ static JanetListenerState *janet_listen_impl(JanetPollable *pollable, JanetListe
|
|||||||
mask |= JANET_ASYNC_LISTEN_SPAWNER;
|
mask |= JANET_ASYNC_LISTEN_SPAWNER;
|
||||||
state->pollable = pollable;
|
state->pollable = pollable;
|
||||||
state->_mask = mask;
|
state->_mask = mask;
|
||||||
|
state->_index = 0;
|
||||||
pollable->_mask |= mask;
|
pollable->_mask |= mask;
|
||||||
janet_vm_active_listeners++;
|
janet_vm_active_listeners++;
|
||||||
/* Prepend to linked list */
|
/* Prepend to linked list */
|
||||||
@ -617,7 +618,7 @@ void janet_loop(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JANET_LINUX
|
#ifdef JANET_EV_EPOLL
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start linux/epoll implementation
|
* Start linux/epoll implementation
|
||||||
@ -683,7 +684,6 @@ static void janet_unlisten(JanetListenerState *state) {
|
|||||||
janet_unlisten_impl(state);
|
janet_unlisten_impl(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Replace janet_loop with this */
|
|
||||||
#define JANET_EPOLL_MAX_EVENTS 64
|
#define JANET_EPOLL_MAX_EVENTS 64
|
||||||
void janet_loop1_impl(void) {
|
void janet_loop1_impl(void) {
|
||||||
/* Set timer */
|
/* Set timer */
|
||||||
@ -771,10 +771,148 @@ void janet_ev_deinit(void) {
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
/* Poll implementation */
|
||||||
|
|
||||||
|
static JanetTimestamp ts_now(void) {
|
||||||
|
struct timespec now;
|
||||||
|
janet_assert(-1 != clock_gettime(CLOCK_REALTIME, &now), "failed to get time");
|
||||||
|
uint64_t res = 1000 * now.tv_sec;
|
||||||
|
res += now.tv_nsec / 1000000;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Epoll global data */
|
||||||
|
JANET_THREAD_LOCAL struct pollfd *janet_vm_fds = NULL;
|
||||||
|
JANET_THREAD_LOCAL JanetListenerState **janet_vm_listener_map = NULL;
|
||||||
|
JANET_THREAD_LOCAL size_t janet_vm_fdcap = 0;
|
||||||
|
JANET_THREAD_LOCAL size_t janet_vm_fdcount = 0;
|
||||||
|
|
||||||
|
static int make_poll_events(int mask) {
|
||||||
|
int events = 0;
|
||||||
|
if (mask & JANET_ASYNC_LISTEN_READ)
|
||||||
|
events |= POLLIN;
|
||||||
|
if (mask & JANET_ASYNC_LISTEN_WRITE)
|
||||||
|
events |= POLLOUT;
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void janet_push_pollfd(struct pollfd pfd) {
|
||||||
|
if (janet_vm_fdcap == janet_vm_fdcount) {
|
||||||
|
size_t newcap = janet_vm_fdcount ? janet_vm_fdcount * 2 : 16;
|
||||||
|
janet_vm_fds = realloc(janet_vm_fds, newcap * sizeof(struct pollfd));
|
||||||
|
if (NULL == janet_vm_fds) {
|
||||||
|
JANET_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
janet_vm_listener_map = realloc(janet_vm_listener_map, newcap * sizeof(JanetListenerState *));
|
||||||
|
if (NULL == janet_vm_listener_map) {
|
||||||
|
JANET_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
janet_vm_fdcap = newcap;
|
||||||
|
}
|
||||||
|
janet_vm_fds[janet_vm_fdcount++] = pfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for the next event */
|
||||||
|
JanetListenerState *janet_listen(JanetPollable *pollable, JanetListener behavior, int mask, size_t size) {
|
||||||
|
JanetListenerState *state = janet_listen_impl(pollable, behavior, mask, size);
|
||||||
|
struct pollfd ev;
|
||||||
|
ev.fd = pollable->handle;
|
||||||
|
ev.events = make_poll_events(state->pollable->_mask);
|
||||||
|
ev.revents = 0;
|
||||||
|
state->_index = janet_vm_fdcount;
|
||||||
|
janet_push_pollfd(ev);
|
||||||
|
janet_vm_listener_map[state->_index] = state;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell system we are done listening for a certain event */
|
||||||
|
static void janet_unlisten(JanetListenerState *state) {
|
||||||
|
janet_vm_fds[state->_index] = janet_vm_fds[--janet_vm_fdcount];
|
||||||
|
JanetListenerState *replacer = janet_vm_listener_map[janet_vm_fdcount];
|
||||||
|
janet_vm_listener_map[state->_index] = replacer;
|
||||||
|
/* Update pointers in replacer */
|
||||||
|
replacer->_index = state->_index;
|
||||||
|
/* Destroy state machine and free memory */
|
||||||
|
janet_unlisten_impl(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void janet_loop1_impl(void) {
|
||||||
|
/* Set timer */
|
||||||
|
JanetTimeout to;
|
||||||
|
memset(&to, 0, sizeof(to));
|
||||||
|
int has_timeout = peek_timeout(&to);
|
||||||
|
|
||||||
|
/* Poll for events */
|
||||||
|
int ready;
|
||||||
|
do {
|
||||||
|
if (has_timeout) {
|
||||||
|
int64_t diff = to.when - ts_now();
|
||||||
|
ready = poll(janet_vm_fds, janet_vm_fdcount, diff < 0 ? 0 : (int) diff);
|
||||||
|
} else {
|
||||||
|
ready = poll(janet_vm_fds, janet_vm_fdcount, -1);
|
||||||
|
}
|
||||||
|
} while (ready == -1 && errno == EINTR);
|
||||||
|
if (ready == -1) {
|
||||||
|
JANET_EXIT("failed to poll events");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step state machines */
|
||||||
|
int did_handle_something = 0;
|
||||||
|
for (size_t i = 0; i < janet_vm_fdcount; i++) {
|
||||||
|
struct pollfd *pfd = janet_vm_fds + i;
|
||||||
|
did_handle_something |= pfd->revents;
|
||||||
|
/* Skip fds where nothing interesting happened */
|
||||||
|
if (!(pfd->revents & (pfd->events | POLLHUP | POLLERR | POLLNVAL))) continue;
|
||||||
|
JanetListenerState *state = janet_vm_listener_map[i];
|
||||||
|
/* Normal event */
|
||||||
|
int mask = janet_vm_fds[i].revents;
|
||||||
|
JanetAsyncStatus status1 = JANET_ASYNC_STATUS_NOT_DONE;
|
||||||
|
JanetAsyncStatus status2 = JANET_ASYNC_STATUS_NOT_DONE;
|
||||||
|
if (mask & POLLOUT)
|
||||||
|
status1 = state->machine(state, JANET_ASYNC_EVENT_WRITE);
|
||||||
|
if (mask & POLLIN)
|
||||||
|
status2 = state->machine(state, JANET_ASYNC_EVENT_READ);
|
||||||
|
if (status1 == JANET_ASYNC_STATUS_DONE || status2 == JANET_ASYNC_STATUS_DONE)
|
||||||
|
janet_unlisten(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If nothing was handled and poll returned, then we know that it timedout and we should trigger
|
||||||
|
* one of our timers. */
|
||||||
|
if (!did_handle_something) {
|
||||||
|
/* Timer event */
|
||||||
|
pop_timeout(0);
|
||||||
|
/* Cancel waiters for this fiber */
|
||||||
|
if (to.is_error) {
|
||||||
|
janet_cancel(to.fiber, janet_cstringv("timeout"));
|
||||||
|
} else {
|
||||||
|
janet_schedule(to.fiber, janet_wrap_nil());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void janet_ev_init(void) {
|
||||||
|
janet_ev_init_common();
|
||||||
|
janet_vm_fds = NULL;
|
||||||
|
janet_vm_listener_map = NULL;
|
||||||
|
janet_vm_fdcap = 0;
|
||||||
|
janet_vm_fdcount = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void janet_ev_deinit(void) {
|
||||||
|
janet_ev_deinit_common();
|
||||||
|
free(janet_vm_fds);
|
||||||
|
free(janet_vm_listener_map);
|
||||||
|
janet_vm_fds = NULL;
|
||||||
|
janet_vm_listener_map = NULL;
|
||||||
|
janet_vm_fdcap = 0;
|
||||||
|
janet_vm_fdcount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* C functions */
|
/* C functions */
|
||||||
|
|
||||||
static Janet cfun_ev_go(int32_t argc, Janet *argv) {
|
static Janet cfun_ev_go(int32_t argc, Janet *argv) {
|
||||||
|
@ -56,8 +56,8 @@ static int32_t checkflags(const uint8_t *str) {
|
|||||||
int32_t flags = 0;
|
int32_t flags = 0;
|
||||||
int32_t i;
|
int32_t i;
|
||||||
int32_t len = janet_string_length(str);
|
int32_t len = janet_string_length(str);
|
||||||
if (!len || len > 3)
|
if (!len || len > 10)
|
||||||
janet_panic("file mode must have a length between 1 and 3");
|
janet_panic("file mode must have a length between 1 and 10");
|
||||||
switch (*str) {
|
switch (*str) {
|
||||||
default:
|
default:
|
||||||
janet_panicf("invalid flag %c, expected w, a, or r", *str);
|
janet_panicf("invalid flag %c, expected w, a, or r", *str);
|
||||||
@ -75,7 +75,7 @@ static int32_t checkflags(const uint8_t *str) {
|
|||||||
for (i = 1; i < len; i++) {
|
for (i = 1; i < len; i++) {
|
||||||
switch (str[i]) {
|
switch (str[i]) {
|
||||||
default:
|
default:
|
||||||
janet_panicf("invalid flag %c, expected + or b", str[i]);
|
janet_panicf("invalid flag %c, expected +, b, or n", str[i]);
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
if (flags & JANET_FILE_UPDATE) return -1;
|
if (flags & JANET_FILE_UPDATE) return -1;
|
||||||
@ -85,6 +85,10 @@ static int32_t checkflags(const uint8_t *str) {
|
|||||||
if (flags & JANET_FILE_BINARY) return -1;
|
if (flags & JANET_FILE_BINARY) return -1;
|
||||||
flags |= JANET_FILE_BINARY;
|
flags |= JANET_FILE_BINARY;
|
||||||
break;
|
break;
|
||||||
|
case 'n':
|
||||||
|
if (flags & JANET_FILE_NONIL) return -1;
|
||||||
|
flags |= JANET_FILE_NONIL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
@ -112,11 +116,11 @@ static Janet cfun_io_popen(int32_t argc, Janet *argv) {
|
|||||||
int32_t flags;
|
int32_t flags;
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
fmode = janet_getkeyword(argv, 1);
|
fmode = janet_getkeyword(argv, 1);
|
||||||
if (janet_string_length(fmode) != 1 ||
|
flags = JANET_FILE_PIPED | checkflags(fmode);
|
||||||
!(fmode[0] == 'r' || fmode[0] == 'w')) {
|
if (flags & (JANET_FILE_UPDATE | JANET_FILE_BINARY | JANET_FILE_APPEND)) {
|
||||||
janet_panicf("invalid file mode :%S, expected :r or :w", fmode);
|
janet_panicf("invalid popen file mode :%S, expected :r or :w", fmode);
|
||||||
}
|
}
|
||||||
flags = JANET_FILE_PIPED | (fmode[0] == 'r' ? JANET_FILE_READ : JANET_FILE_WRITE);
|
fmode = (const uint8_t *)((fmode[0] == 'r') ? "r" : "w");
|
||||||
} else {
|
} else {
|
||||||
fmode = (const uint8_t *)"r";
|
fmode = (const uint8_t *)"r";
|
||||||
flags = JANET_FILE_PIPED | JANET_FILE_READ;
|
flags = JANET_FILE_PIPED | JANET_FILE_READ;
|
||||||
@ -126,6 +130,8 @@ static Janet cfun_io_popen(int32_t argc, Janet *argv) {
|
|||||||
#endif
|
#endif
|
||||||
FILE *f = popen((const char *)fname, (const char *)fmode);
|
FILE *f = popen((const char *)fname, (const char *)fmode);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
|
if (flags & JANET_FILE_NONIL)
|
||||||
|
janet_panicf("failed to popen %s: %s", fname, strerror(errno));
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
return janet_makefile(f, flags);
|
return janet_makefile(f, flags);
|
||||||
@ -155,7 +161,9 @@ static Janet cfun_io_fopen(int32_t argc, Janet *argv) {
|
|||||||
flags = JANET_FILE_READ;
|
flags = JANET_FILE_READ;
|
||||||
}
|
}
|
||||||
FILE *f = fopen((const char *)fname, (const char *)fmode);
|
FILE *f = fopen((const char *)fname, (const char *)fmode);
|
||||||
return f ? janet_makefile(f, flags) : janet_wrap_nil();
|
return f ? janet_makefile(f, flags)
|
||||||
|
: (flags & JANET_FILE_NONIL) ? (janet_panicf("failed to open file %s: %s", fname, strerror(errno)), janet_wrap_nil())
|
||||||
|
: janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read up to n bytes into buffer. */
|
/* Read up to n bytes into buffer. */
|
||||||
@ -720,7 +728,8 @@ static const JanetReg io_cfuns[] = {
|
|||||||
"\tw - allow writing to the file\n"
|
"\tw - allow writing to the file\n"
|
||||||
"\ta - append to the file\n"
|
"\ta - append to the file\n"
|
||||||
"\tb - open the file in binary mode (rather than text mode)\n"
|
"\tb - open the file in binary mode (rather than text mode)\n"
|
||||||
"\t+ - append to the file instead of overwriting it")
|
"\t+ - append to the file instead of overwriting it\n"
|
||||||
|
"\tn - error if the file cannot be opened instead of returning nil")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file/close", cfun_io_fclose,
|
"file/close", cfun_io_fclose,
|
||||||
@ -780,6 +789,10 @@ static const JanetReg io_cfuns[] = {
|
|||||||
|
|
||||||
/* C API */
|
/* C API */
|
||||||
|
|
||||||
|
JanetFile *janet_getjfile(const Janet *argv, int32_t n) {
|
||||||
|
return janet_getabstract(argv, n, &janet_file_type);
|
||||||
|
}
|
||||||
|
|
||||||
FILE *janet_getfile(const Janet *argv, int32_t n, int *flags) {
|
FILE *janet_getfile(const Janet *argv, int32_t n, int *flags) {
|
||||||
JanetFile *iof = janet_getabstract(argv, n, &janet_file_type);
|
JanetFile *iof = janet_getabstract(argv, n, &janet_file_type);
|
||||||
if (NULL != flags) *flags = iof->flags;
|
if (NULL != flags) *flags = iof->flags;
|
||||||
@ -804,17 +817,18 @@ FILE *janet_unwrapfile(Janet j, int *flags) {
|
|||||||
void janet_lib_io(JanetTable *env) {
|
void janet_lib_io(JanetTable *env) {
|
||||||
janet_core_cfuns(env, NULL, io_cfuns);
|
janet_core_cfuns(env, NULL, io_cfuns);
|
||||||
janet_register_abstract_type(&janet_file_type);
|
janet_register_abstract_type(&janet_file_type);
|
||||||
|
int default_flags = JANET_FILE_NOT_CLOSEABLE | JANET_FILE_SERIALIZABLE;
|
||||||
/* stdout */
|
/* stdout */
|
||||||
janet_core_def(env, "stdout",
|
janet_core_def(env, "stdout",
|
||||||
janet_makefile(stdout, JANET_FILE_APPEND | JANET_FILE_NOT_CLOSEABLE | JANET_FILE_SERIALIZABLE),
|
janet_makefile(stdout, JANET_FILE_APPEND | default_flags),
|
||||||
JDOC("The standard output file."));
|
JDOC("The standard output file."));
|
||||||
/* stderr */
|
/* stderr */
|
||||||
janet_core_def(env, "stderr",
|
janet_core_def(env, "stderr",
|
||||||
janet_makefile(stderr, JANET_FILE_APPEND | JANET_FILE_NOT_CLOSEABLE | JANET_FILE_SERIALIZABLE),
|
janet_makefile(stderr, JANET_FILE_APPEND | default_flags),
|
||||||
JDOC("The standard error file."));
|
JDOC("The standard error file."));
|
||||||
/* stdin */
|
/* stdin */
|
||||||
janet_core_def(env, "stdin",
|
janet_core_def(env, "stdin",
|
||||||
janet_makefile(stdin, JANET_FILE_READ | JANET_FILE_NOT_CLOSEABLE | JANET_FILE_SERIALIZABLE),
|
janet_makefile(stdin, JANET_FILE_READ | default_flags),
|
||||||
JDOC("The standard input file."));
|
JDOC("The standard input file."));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
298
src/core/os.c
298
src/core/os.c
@ -24,6 +24,7 @@
|
|||||||
#include "features.h"
|
#include "features.h"
|
||||||
#include <janet.h>
|
#include <janet.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "gc.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef JANET_REDUCED_OS
|
#ifndef JANET_REDUCED_OS
|
||||||
@ -36,6 +37,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#ifdef JANET_APPLE
|
#ifdef JANET_APPLE
|
||||||
#include <AvailabilityMacros.h>
|
#include <AvailabilityMacros.h>
|
||||||
@ -312,13 +314,149 @@ static JanetBuffer *os_exec_escape(JanetView args) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Janet os_execute(int32_t argc, Janet *argv) {
|
/* Process type for when running a subprocess and not immediately waiting */
|
||||||
|
static const JanetAbstractType ProcAT;
|
||||||
|
#define JANET_PROC_CLOSED 1
|
||||||
|
#define JANET_PROC_WAITED 2
|
||||||
|
typedef struct {
|
||||||
|
int flags;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
HANDLE pHandle;
|
||||||
|
HANDLE tHandle;
|
||||||
|
#else
|
||||||
|
int pid;
|
||||||
|
#endif
|
||||||
|
int return_code;
|
||||||
|
JanetFile *in;
|
||||||
|
JanetFile *out;
|
||||||
|
JanetFile *err;
|
||||||
|
} JanetProc;
|
||||||
|
|
||||||
|
static int janet_proc_gc(void *p, size_t s) {
|
||||||
|
(void) s;
|
||||||
|
JanetProc *proc = (JanetProc *) p;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
if (!(proc->flags & JANET_PROC_CLOSED)) {
|
||||||
|
CloseHandle(proc->pHandle);
|
||||||
|
CloseHandle(proc->tHandle);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!(proc->flags & JANET_PROC_WAITED)) {
|
||||||
|
/* Kill and wait to prevent zombies */
|
||||||
|
kill(proc->pid, SIGKILL);
|
||||||
|
int status;
|
||||||
|
waitpid(proc->pid, &status, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int janet_proc_mark(void *p, size_t s) {
|
||||||
|
(void) s;
|
||||||
|
JanetProc *proc = (JanetProc *)p;
|
||||||
|
if (NULL != proc->in) janet_mark(janet_wrap_abstract(proc->in));
|
||||||
|
if (NULL != proc->out) janet_mark(janet_wrap_abstract(proc->out));
|
||||||
|
if (NULL != proc->err) janet_mark(janet_wrap_abstract(proc->err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_proc_wait_impl(JanetProc *proc) {
|
||||||
|
if (proc->flags & JANET_PROC_WAITED) {
|
||||||
|
janet_panicf("cannot wait on process that has already finished");
|
||||||
|
}
|
||||||
|
proc->flags |= JANET_PROC_WAITED;
|
||||||
|
int status = 0;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
WaitForSingleObject(proc->pHandle, INFINITE);
|
||||||
|
GetExitCodeProcess(proc->pHandle, &status);
|
||||||
|
if (!(proc->flags & JANET_PROC_CLOSED)) {
|
||||||
|
proc->flags |= JANET_PROC_CLOSED;
|
||||||
|
CloseHandle(proc->pHandle);
|
||||||
|
CloseHandle(proc->tHandle);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
waitpid(proc->pid, &status, 0);
|
||||||
|
#endif
|
||||||
|
proc->return_code = (int32_t) status;
|
||||||
|
return janet_wrap_integer(proc->return_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_proc_wait(int32_t argc, Janet *argv) {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||||
|
return os_proc_wait_impl(proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_proc_kill(int32_t argc, Janet *argv) {
|
||||||
|
janet_arity(argc, 1, 2);
|
||||||
|
JanetProc *proc = janet_getabstract(argv, 0, &ProcAT);
|
||||||
|
if (proc->flags & JANET_PROC_WAITED) {
|
||||||
|
janet_panicf("cannot kill process that has already finished");
|
||||||
|
}
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
if (proc->flags & JANET_PROC_CLOSED) {
|
||||||
|
janet_panicf("cannot close process handle that is already closed");
|
||||||
|
}
|
||||||
|
proc->flags |= JANET_PROC_CLOSED;
|
||||||
|
CloseHandle(proc->pHandle);
|
||||||
|
CloseHandle(proc->tHandle);
|
||||||
|
#else
|
||||||
|
int status = kill(proc->pid, SIGKILL);
|
||||||
|
if (status) {
|
||||||
|
janet_panic(strerror(errno));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* After killing process we wait on it. */
|
||||||
|
if (argc > 1 && janet_truthy(argv[1])) {
|
||||||
|
return os_proc_wait_impl(proc);
|
||||||
|
} else {
|
||||||
|
return argv[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const JanetMethod proc_methods[] = {
|
||||||
|
{"wait", os_proc_wait},
|
||||||
|
{"kill", os_proc_kill},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int janet_proc_get(void *p, Janet key, Janet *out) {
|
||||||
|
JanetProc *proc = (JanetProc *)p;
|
||||||
|
if (janet_keyeq(key, "in")) {
|
||||||
|
*out = (NULL == proc->in) ? janet_wrap_nil() : janet_wrap_abstract(proc->in);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (janet_keyeq(key, "out")) {
|
||||||
|
*out = (NULL == proc->out) ? janet_wrap_nil() : janet_wrap_abstract(proc->out);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (janet_keyeq(key, "err")) {
|
||||||
|
*out = (NULL == proc->out) ? janet_wrap_nil() : janet_wrap_abstract(proc->err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((-1 != proc->return_code) && janet_keyeq(key, "return-code")) {
|
||||||
|
*out = janet_wrap_integer(proc->return_code);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!janet_checktype(key, JANET_KEYWORD)) return 0;
|
||||||
|
return janet_getmethod(janet_unwrap_keyword(key), proc_methods, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const JanetAbstractType ProcAT = {
|
||||||
|
"core/process",
|
||||||
|
janet_proc_gc,
|
||||||
|
janet_proc_mark,
|
||||||
|
janet_proc_get,
|
||||||
|
JANET_ATEND_GET
|
||||||
|
};
|
||||||
|
|
||||||
|
static Janet os_execute_impl(int32_t argc, Janet *argv, int is_async) {
|
||||||
janet_arity(argc, 1, 3);
|
janet_arity(argc, 1, 3);
|
||||||
|
|
||||||
/* Get flags */
|
/* Get flags */
|
||||||
uint64_t flags = 0;
|
uint64_t flags = 0;
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
flags = janet_getflags(argv, 1, "ep");
|
flags = janet_getflags(argv, 1, "epx");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get environment */
|
/* Get environment */
|
||||||
@ -330,43 +468,76 @@ static Janet os_execute(int32_t argc, Janet *argv) {
|
|||||||
janet_panic("expected at least 1 command line argument");
|
janet_panic("expected at least 1 command line argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Optional stdio redirections */
|
||||||
|
JanetFile *new_in = NULL, *new_out = NULL, *new_err = NULL;
|
||||||
|
|
||||||
|
/* Get optional redirections */
|
||||||
|
if (argc > 2) {
|
||||||
|
JanetDictView tab = janet_getdictionary(argv, 2);
|
||||||
|
Janet maybe_stdin = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("in"));
|
||||||
|
Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out"));
|
||||||
|
Janet maybe_stderr = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("err"));
|
||||||
|
if (!janet_checktype(maybe_stdin, JANET_NIL)) new_in = janet_getjfile(&maybe_stdin, 0);
|
||||||
|
if (!janet_checktype(maybe_stdout, JANET_NIL)) new_out = janet_getjfile(&maybe_stdout, 0);
|
||||||
|
if (!janet_checktype(maybe_stderr, JANET_NIL)) new_err = janet_getjfile(&maybe_stderr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Result */
|
/* Result */
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
|
|
||||||
|
HANDLE pHandle, tHandle;
|
||||||
|
PROCESS_INFORMATION processInfo;
|
||||||
|
STARTUPINFO startupInfo;
|
||||||
|
memset(&processInfo, 0, sizeof(processInfo));
|
||||||
|
memset(&startupInfo, 0, sizeof(startupInfo));
|
||||||
|
startupInfo.cb = sizeof(startupInfo);
|
||||||
|
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
|
||||||
|
|
||||||
JanetBuffer *buf = os_exec_escape(exargs);
|
JanetBuffer *buf = os_exec_escape(exargs);
|
||||||
if (buf->count > 8191) {
|
if (buf->count > 8191) {
|
||||||
janet_panic("command line string too long (max 8191 characters)");
|
janet_panic("command line string too long (max 8191 characters)");
|
||||||
}
|
}
|
||||||
const char *path = (const char *) janet_unwrap_string(exargs.items[0]);
|
const char *path = (const char *) janet_unwrap_string(exargs.items[0]);
|
||||||
char *cargv[2] = {(char *) buf->data, NULL};
|
|
||||||
|
/* Do IO redirection */
|
||||||
|
startupInfo.hStdInput = (HANDLE) _get_osfhandle((new_in == NULL) ? 0 : _fileno(new_in->file));
|
||||||
|
startupInfo.hStdOutput = (HANDLE) _get_osfhandle((new_out == NULL) ? 1 : _fileno(new_out->file));
|
||||||
|
startupInfo.hStdError = (HANDLE) _get_osfhandle((new_err == NULL) ? 2 : _fileno(new_err->file));
|
||||||
|
|
||||||
/* Use _spawn family of functions. */
|
/* Use _spawn family of functions. */
|
||||||
/* Windows docs say do this before any spawns. */
|
/* Windows docs say do this before any spawns. */
|
||||||
_flushall();
|
_flushall();
|
||||||
|
|
||||||
/* Use an empty env instead when envp is NULL to be consistent with other implementation. */
|
/* TODO - redirection, :p flag */
|
||||||
char *empty_env[1] = {NULL};
|
if (!CreateProcess(janet_flag_at(flags, 1) ? NULL : path, /* NULL? */
|
||||||
char **envp1 = (NULL == envp) ? empty_env : envp;
|
(char *) buf->data, /* Single CLI argument */
|
||||||
|
NULL, /* no proc inheritance */
|
||||||
if (janet_flag_at(flags, 1) && janet_flag_at(flags, 0)) {
|
NULL, /* no thread inheritance */
|
||||||
status = (int) _spawnvpe(_P_WAIT, path, cargv, envp1);
|
TRUE, /* handle inheritance */
|
||||||
} else if (janet_flag_at(flags, 1)) {
|
0, /* flags */
|
||||||
status = (int) _spawnvp(_P_WAIT, path, cargv);
|
envp, /* pass in environment */
|
||||||
} else if (janet_flag_at(flags, 0)) {
|
NULL, /* use parents starting directory */
|
||||||
status = (int) _spawnve(_P_WAIT, path, cargv, envp1);
|
&startupInfo,
|
||||||
} else {
|
&processInfo)) {
|
||||||
status = (int) _spawnv(_P_WAIT, path, cargv);
|
janet_panic("failed to create process");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pHandle = processInfo.hProcess;
|
||||||
|
tHandle = processInfo.hThread;
|
||||||
|
|
||||||
os_execute_cleanup(envp, NULL);
|
os_execute_cleanup(envp, NULL);
|
||||||
|
|
||||||
/* Check error */
|
/* Wait and cleanup immedaitely */
|
||||||
if (-1 == status) {
|
if (!is_async) {
|
||||||
janet_panicf("%p: %s", argv[0], strerror(errno));
|
DWORD code;
|
||||||
|
WaitForSingleObject(pHandle, INFINITE);
|
||||||
|
GetExitCodeProcess(pHandle, &code);
|
||||||
|
status = (int) code;
|
||||||
|
CloseHandle(pHandle);
|
||||||
|
CloseHandle(tHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return janet_wrap_integer(status);
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
const char **child_argv = janet_smalloc(sizeof(char *) * ((size_t) exargs.len + 1));
|
const char **child_argv = janet_smalloc(sizeof(char *) * ((size_t) exargs.len + 1));
|
||||||
@ -385,17 +556,32 @@ static Janet os_execute(int32_t argc, Janet *argv) {
|
|||||||
janet_lock_environ();
|
janet_lock_environ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Posix spawn setup */
|
||||||
|
posix_spawn_file_actions_t actions;
|
||||||
|
posix_spawn_file_actions_init(&actions);
|
||||||
|
if (new_in != NULL) {
|
||||||
|
posix_spawn_file_actions_adddup2(&actions, fileno(new_in->file), 0);
|
||||||
|
}
|
||||||
|
if (new_out != NULL) {
|
||||||
|
posix_spawn_file_actions_adddup2(&actions, fileno(new_out->file), 1);
|
||||||
|
}
|
||||||
|
if (new_err != NULL) {
|
||||||
|
posix_spawn_file_actions_adddup2(&actions, fileno(new_err->file), 2);
|
||||||
|
}
|
||||||
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
if (janet_flag_at(flags, 1)) {
|
if (janet_flag_at(flags, 1)) {
|
||||||
status = posix_spawnp(&pid,
|
status = posix_spawnp(&pid,
|
||||||
child_argv[0], NULL, NULL, cargv,
|
child_argv[0], &actions, NULL, cargv,
|
||||||
use_environ ? environ : envp);
|
use_environ ? environ : envp);
|
||||||
} else {
|
} else {
|
||||||
status = posix_spawn(&pid,
|
status = posix_spawn(&pid,
|
||||||
child_argv[0], NULL, NULL, cargv,
|
child_argv[0], &actions, NULL, cargv,
|
||||||
use_environ ? environ : envp);
|
use_environ ? environ : envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
posix_spawn_file_actions_destroy(&actions);
|
||||||
|
|
||||||
if (use_environ) {
|
if (use_environ) {
|
||||||
janet_unlock_environ();
|
janet_unlock_environ();
|
||||||
}
|
}
|
||||||
@ -404,22 +590,51 @@ static Janet os_execute(int32_t argc, Janet *argv) {
|
|||||||
if (status) {
|
if (status) {
|
||||||
os_execute_cleanup(envp, child_argv);
|
os_execute_cleanup(envp, child_argv);
|
||||||
janet_panicf("%p: %s", argv[0], strerror(errno));
|
janet_panicf("%p: %s", argv[0], strerror(errno));
|
||||||
|
} else if (is_async) {
|
||||||
|
/* Get process handle */
|
||||||
|
os_execute_cleanup(envp, child_argv);
|
||||||
} else {
|
} else {
|
||||||
|
/* Wait to complete */
|
||||||
waitpid(pid, &status, 0);
|
waitpid(pid, &status, 0);
|
||||||
}
|
|
||||||
|
|
||||||
os_execute_cleanup(envp, child_argv);
|
os_execute_cleanup(envp, child_argv);
|
||||||
/* Use POSIX shell semantics for interpreting signals */
|
/* Use POSIX shell semantics for interpreting signals */
|
||||||
int ret;
|
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
ret = WEXITSTATUS(status);
|
status = WEXITSTATUS(status);
|
||||||
} else if (WIFSTOPPED(status)) {
|
} else if (WIFSTOPPED(status)) {
|
||||||
ret = WSTOPSIG(status) + 128;
|
status = WSTOPSIG(status) + 128;
|
||||||
} else {
|
} else {
|
||||||
ret = WTERMSIG(status) + 128;
|
status = WTERMSIG(status) + 128;
|
||||||
}
|
}
|
||||||
return janet_wrap_integer(ret);
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
if (is_async) {
|
||||||
|
JanetProc *proc = janet_abstract(&ProcAT, sizeof(JanetProc));
|
||||||
|
proc->return_code = -1;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
proc->pHandle = pHandle;
|
||||||
|
proc->tHandle = tHandle;
|
||||||
|
#else
|
||||||
|
proc->pid = pid;
|
||||||
|
#endif
|
||||||
|
proc->in = new_in;
|
||||||
|
proc->out = new_out;
|
||||||
|
proc->err = new_err;
|
||||||
|
proc->flags = 0;
|
||||||
|
return janet_wrap_abstract(proc);
|
||||||
|
} else if (janet_flag_at(flags, 2) && status) {
|
||||||
|
janet_panicf("command failed with non-zero exit code %d", status);
|
||||||
|
} else {
|
||||||
|
return janet_wrap_integer(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_execute(int32_t argc, Janet *argv) {
|
||||||
|
return os_execute_impl(argc, argv, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet os_spawn(int32_t argc, Janet *argv) {
|
||||||
|
return os_execute_impl(argc, argv, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet os_shell(int32_t argc, Janet *argv) {
|
static Janet os_shell(int32_t argc, Janet *argv) {
|
||||||
@ -1334,10 +1549,19 @@ static const JanetReg os_cfuns[] = {
|
|||||||
"\t:e - enables passing an environment to the program. Without :e, the "
|
"\t:e - enables passing an environment to the program. Without :e, the "
|
||||||
"current environment is inherited.\n"
|
"current environment is inherited.\n"
|
||||||
"\t:p - allows searching the current PATH for the binary to execute. "
|
"\t:p - allows searching the current PATH for the binary to execute. "
|
||||||
"Without this flag, binaries must use absolute paths.\n\n"
|
"Without this flag, binaries must use absolute paths.\n"
|
||||||
"env is a table or struct mapping environment variables to values. "
|
"\t:x - raise error if exit code is non-zero.\n"
|
||||||
|
"env is a table or struct mapping environment variables to values. It can also "
|
||||||
|
"contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
|
||||||
|
"These arguments should be core/file values. "
|
||||||
"Returns the exit status of the program.")
|
"Returns the exit status of the program.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"os/spawn", os_spawn,
|
||||||
|
JDOC("(os/spawn args &opts flags env)\n\n"
|
||||||
|
"Execute a program on the system and return a handle to the process. Otherwise, the "
|
||||||
|
"same arguments as os/execute. Does not wait for the process.")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"os/shell", os_shell,
|
"os/shell", os_shell,
|
||||||
JDOC("(os/shell str)\n\n"
|
JDOC("(os/shell str)\n\n"
|
||||||
@ -1428,6 +1652,18 @@ static const JanetReg os_cfuns[] = {
|
|||||||
JDOC("(os/perm-int bytes)\n\n"
|
JDOC("(os/perm-int bytes)\n\n"
|
||||||
"Parse a 9 character permission string and return an integer that can be used by chmod.")
|
"Parse a 9 character permission string and return an integer that can be used by chmod.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"os/proc-wait", os_proc_wait,
|
||||||
|
JDOC("(os/proc-wait proc)\n\n"
|
||||||
|
"Block until the subprocess completes. Returns the subprocess return code.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os/proc-kill", os_proc_kill,
|
||||||
|
JDOC("(os/proc-kill proc &opt wait)\n\n"
|
||||||
|
"Kill a subprocess by sending SIGKILL to it on posix systems, or by closing the process "
|
||||||
|
"handle on windows. If wait is truthy, will wait for the process to finsih and "
|
||||||
|
"returns the exit code. Otherwise, returns proc.")
|
||||||
|
},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
@ -955,6 +955,9 @@ void janet_buffer_format(
|
|||||||
janet_description_b(b, argv[arg]);
|
janet_description_b(b, argv[arg]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 't':
|
||||||
|
janet_buffer_push_cstring(b, typestr(argv[arg]));
|
||||||
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
case 'm':
|
case 'm':
|
||||||
case 'N':
|
case 'N':
|
||||||
|
@ -76,7 +76,6 @@ int32_t janet_tablen(int32_t n);
|
|||||||
void safe_memcpy(void *dest, const void *src, size_t len);
|
void safe_memcpy(void *dest, const void *src, size_t len);
|
||||||
void janet_buffer_push_types(JanetBuffer *buffer, int types);
|
void janet_buffer_push_types(JanetBuffer *buffer, int types);
|
||||||
const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key);
|
const JanetKV *janet_dict_find(const JanetKV *buckets, int32_t cap, Janet key);
|
||||||
Janet janet_dict_get(const JanetKV *buckets, int32_t cap, Janet key);
|
|
||||||
void janet_memempty(JanetKV *mem, int32_t count);
|
void janet_memempty(JanetKV *mem, int32_t count);
|
||||||
void *janet_memalloc_empty(int32_t count);
|
void *janet_memalloc_empty(int32_t count);
|
||||||
JanetTable *janet_get_core_table(const char *name);
|
JanetTable *janet_get_core_table(const char *name);
|
||||||
|
@ -274,10 +274,9 @@ int32_t janet_hash(Janet x) {
|
|||||||
if (sizeof(double) == sizeof(void *)) {
|
if (sizeof(double) == sizeof(void *)) {
|
||||||
/* Assuming 8 byte pointer */
|
/* Assuming 8 byte pointer */
|
||||||
uint64_t i = janet_u64(x);
|
uint64_t i = janet_u64(x);
|
||||||
hash = (int32_t)(i & 0xFFFFFFFF);
|
uint32_t lo = (uint32_t)(i & 0xFFFFFFFF);
|
||||||
/* Get a bit more entropy by shifting the low bits out */
|
uint32_t hi = (uint32_t)(i >> 32);
|
||||||
hash >>= 3;
|
hash = (int32_t)(hi ^ (lo >> 3));
|
||||||
hash ^= (int32_t)(i >> 32);
|
|
||||||
} else {
|
} else {
|
||||||
/* Assuming 4 byte pointer (or smaller) */
|
/* Assuming 4 byte pointer (or smaller) */
|
||||||
hash = (int32_t)((char *)janet_unwrap_pointer(x) - (char *)0);
|
hash = (int32_t)((char *)janet_unwrap_pointer(x) - (char *)0);
|
||||||
|
@ -206,7 +206,7 @@ extern "C" {
|
|||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
#define JANET_NO_RETURN __declspec(noreturn)
|
#define JANET_NO_RETURN __declspec(noreturn)
|
||||||
#else
|
#else
|
||||||
#define JANET_NO_RETURN __attribute__ ((noreturn))
|
#define JANET_NO_RETURN __attribute__((noreturn))
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -272,11 +272,22 @@ typedef struct {
|
|||||||
} JanetBuildConfig;
|
} JanetBuildConfig;
|
||||||
|
|
||||||
/* Get config of current compilation unit. */
|
/* Get config of current compilation unit. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
/* C++11 syntax */
|
||||||
|
#define janet_config_current() (JanetBuildConfig { \
|
||||||
|
JANET_VERSION_MAJOR, \
|
||||||
|
JANET_VERSION_MINOR, \
|
||||||
|
JANET_VERSION_PATCH, \
|
||||||
|
JANET_CURRENT_CONFIG_BITS })
|
||||||
|
#else
|
||||||
|
/* C99 syntax */
|
||||||
#define janet_config_current() ((JanetBuildConfig){ \
|
#define janet_config_current() ((JanetBuildConfig){ \
|
||||||
JANET_VERSION_MAJOR, \
|
JANET_VERSION_MAJOR, \
|
||||||
JANET_VERSION_MINOR, \
|
JANET_VERSION_MINOR, \
|
||||||
JANET_VERSION_PATCH, \
|
JANET_VERSION_PATCH, \
|
||||||
JANET_CURRENT_CONFIG_BITS })
|
JANET_CURRENT_CONFIG_BITS })
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/***** END SECTION CONFIG *****/
|
/***** END SECTION CONFIG *****/
|
||||||
|
|
||||||
@ -526,6 +537,7 @@ struct JanetListenerState {
|
|||||||
JanetFiber *fiber;
|
JanetFiber *fiber;
|
||||||
JanetPollable *pollable;
|
JanetPollable *pollable;
|
||||||
/* internal */
|
/* internal */
|
||||||
|
int _index; /* not used in all implementations */
|
||||||
int _mask;
|
int _mask;
|
||||||
JanetListenerState *_next;
|
JanetListenerState *_next;
|
||||||
};
|
};
|
||||||
@ -620,14 +632,14 @@ JANET_API Janet janet_wrap_integer(int32_t x);
|
|||||||
#define janet_nanbox_tag(type) (janet_nanbox_lowtag(type) << 47)
|
#define janet_nanbox_tag(type) (janet_nanbox_lowtag(type) << 47)
|
||||||
#define janet_type(x) \
|
#define janet_type(x) \
|
||||||
(isnan((x).number) \
|
(isnan((x).number) \
|
||||||
? (((x).u64 >> 47) & 0xF) \
|
? (JanetType) (((x).u64 >> 47) & 0xF) \
|
||||||
: JANET_NUMBER)
|
: JANET_NUMBER)
|
||||||
|
|
||||||
#define janet_nanbox_checkauxtype(x, type) \
|
#define janet_nanbox_checkauxtype(x, type) \
|
||||||
(((x).u64 & JANET_NANBOX_TAGBITS) == janet_nanbox_tag((type)))
|
(((x).u64 & JANET_NANBOX_TAGBITS) == janet_nanbox_tag((type)))
|
||||||
|
|
||||||
#define janet_nanbox_isnumber(x) \
|
#define janet_nanbox_isnumber(x) \
|
||||||
(!isnan((x).number) || janet_nanbox_checkauxtype((x), JANET_NUMBER))
|
(!isnan((x).number) || ((((x).u64 >> 47) & 0xF) == JANET_NUMBER))
|
||||||
|
|
||||||
#define janet_checktype(x, t) \
|
#define janet_checktype(x, t) \
|
||||||
(((t) == JANET_NUMBER) \
|
(((t) == JANET_NUMBER) \
|
||||||
@ -699,7 +711,7 @@ JANET_API Janet janet_nanbox_from_bits(uint64_t bits);
|
|||||||
#define JANET_DOUBLE_OFFSET 0xFFFF
|
#define JANET_DOUBLE_OFFSET 0xFFFF
|
||||||
|
|
||||||
#define janet_u64(x) ((x).u64)
|
#define janet_u64(x) ((x).u64)
|
||||||
#define janet_type(x) (((x).tagged.type < JANET_DOUBLE_OFFSET) ? (x).tagged.type : JANET_NUMBER)
|
#define janet_type(x) (((x).tagged.type < JANET_DOUBLE_OFFSET) ? (JanetType)((x).tagged.type) : JANET_NUMBER)
|
||||||
#define janet_checktype(x, t) ((t) == JANET_NUMBER \
|
#define janet_checktype(x, t) ((t) == JANET_NUMBER \
|
||||||
? (x).tagged.type >= JANET_DOUBLE_OFFSET \
|
? (x).tagged.type >= JANET_DOUBLE_OFFSET \
|
||||||
: (x).tagged.type == (t))
|
: (x).tagged.type == (t))
|
||||||
@ -1525,6 +1537,7 @@ typedef enum {
|
|||||||
JANET_API void janet_def(JanetTable *env, const char *name, Janet val, const char *documentation);
|
JANET_API void janet_def(JanetTable *env, const char *name, Janet val, const char *documentation);
|
||||||
JANET_API void janet_var(JanetTable *env, const char *name, Janet val, const char *documentation);
|
JANET_API void janet_var(JanetTable *env, const char *name, Janet val, const char *documentation);
|
||||||
JANET_API void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns);
|
JANET_API void janet_cfuns(JanetTable *env, const char *regprefix, const JanetReg *cfuns);
|
||||||
|
JANET_API void janet_cfuns_prefix(JanetTable *env, const char *regprefix, const JanetReg *cfuns);
|
||||||
JANET_API JanetBindingType janet_resolve(JanetTable *env, JanetSymbol sym, Janet *out);
|
JANET_API JanetBindingType janet_resolve(JanetTable *env, JanetSymbol sym, Janet *out);
|
||||||
JANET_API void janet_register(const char *name, JanetCFunction cfun);
|
JANET_API void janet_register(const char *name, JanetCFunction cfun);
|
||||||
|
|
||||||
@ -1534,14 +1547,19 @@ JANET_API Janet janet_resolve_core(const char *name);
|
|||||||
/* New C API */
|
/* New C API */
|
||||||
|
|
||||||
/* Allow setting entry name for static libraries */
|
/* Allow setting entry name for static libraries */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define JANET_MODULE_PREFIX extern "C"
|
||||||
|
#else
|
||||||
|
#define JANET_MODULE_PREFIX
|
||||||
|
#endif
|
||||||
#ifndef JANET_ENTRY_NAME
|
#ifndef JANET_ENTRY_NAME
|
||||||
#define JANET_MODULE_ENTRY \
|
#define JANET_MODULE_ENTRY \
|
||||||
JANET_API JanetBuildConfig _janet_mod_config(void) { \
|
JANET_MODULE_PREFIX JANET_API JanetBuildConfig _janet_mod_config(void) { \
|
||||||
return janet_config_current(); \
|
return janet_config_current(); \
|
||||||
} \
|
} \
|
||||||
JANET_API void _janet_init
|
JANET_MODULE_PREFIX JANET_API void _janet_init
|
||||||
#else
|
#else
|
||||||
#define JANET_MODULE_ENTRY JANET_API void JANET_ENTRY_NAME
|
#define JANET_MODULE_ENTRY JANET_MODULE_PREFIX JANET_API void JANET_ENTRY_NAME
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JANET_NO_RETURN JANET_API void janet_signalv(JanetSignal signal, Janet message);
|
JANET_NO_RETURN JANET_API void janet_signalv(JanetSignal signal, Janet message);
|
||||||
@ -1626,10 +1644,12 @@ extern JANET_API const JanetAbstractType janet_file_type;
|
|||||||
#define JANET_FILE_BINARY 64
|
#define JANET_FILE_BINARY 64
|
||||||
#define JANET_FILE_SERIALIZABLE 128
|
#define JANET_FILE_SERIALIZABLE 128
|
||||||
#define JANET_FILE_PIPED 256
|
#define JANET_FILE_PIPED 256
|
||||||
|
#define JANET_FILE_NONIL 512
|
||||||
|
|
||||||
JANET_API Janet janet_makefile(FILE *f, int32_t flags);
|
JANET_API Janet janet_makefile(FILE *f, int32_t flags);
|
||||||
JANET_API FILE *janet_getfile(const Janet *argv, int32_t n, int32_t *flags);
|
JANET_API FILE *janet_getfile(const Janet *argv, int32_t n, int32_t *flags);
|
||||||
JANET_API FILE *janet_dynfile(const char *name, FILE *def);
|
JANET_API FILE *janet_dynfile(const char *name, FILE *def);
|
||||||
|
JANET_API JanetFile *janet_getjfile(const Janet *argv, int32_t n);
|
||||||
JANET_API JanetAbstract janet_checkfile(Janet j);
|
JANET_API JanetAbstract janet_checkfile(Janet j);
|
||||||
JANET_API FILE *janet_unwrapfile(Janet j, int32_t *flags);
|
JANET_API FILE *janet_unwrapfile(Janet j, int32_t *flags);
|
||||||
|
|
||||||
|
@ -763,7 +763,7 @@ static int line() {
|
|||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
default:
|
default:
|
||||||
if (c < 0x20) break;
|
if ((unsigned char) c < 0x20) break;
|
||||||
if (insert(c, 1)) return -1;
|
if (insert(c, 1)) return -1;
|
||||||
break;
|
break;
|
||||||
case 1: /* ctrl-a */
|
case 1: /* ctrl-a */
|
||||||
|
@ -9,6 +9,14 @@
|
|||||||
:name "testmod2"
|
:name "testmod2"
|
||||||
:source @["testmod2.c"])
|
:source @["testmod2.c"])
|
||||||
|
|
||||||
|
(declare-native
|
||||||
|
:name "testmod3"
|
||||||
|
:source @["testmod3.cpp"])
|
||||||
|
|
||||||
|
(declare-native
|
||||||
|
:name "test-mod-4"
|
||||||
|
:source @["testmod4.c"])
|
||||||
|
|
||||||
(declare-executable
|
(declare-executable
|
||||||
:name "testexec"
|
:name "testexec"
|
||||||
:entry "testexec.janet")
|
:entry "testexec.janet")
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
(use build/testmod)
|
(use build/testmod)
|
||||||
(use build/testmod2)
|
(use build/testmod2)
|
||||||
|
(use build/testmod3)
|
||||||
|
(use build/test-mod-4)
|
||||||
|
|
||||||
(defn main [&]
|
(defn main [&]
|
||||||
(print "Hello from executable!")
|
(print "Hello from executable!")
|
||||||
(print (+ (get5) (get6))))
|
(print (+ (get5) (get6) (get7) (get8))))
|
||||||
|
42
test/install/testmod3.cpp
Normal file
42
test/install/testmod3.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Calvin Rose and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* A very simple native module */
|
||||||
|
|
||||||
|
#include <janet.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static Janet cfun_get_seven(int32_t argc, Janet *argv) {
|
||||||
|
(void) argv;
|
||||||
|
janet_fixarity(argc, 0);
|
||||||
|
std::cout << "Hello!" << std::endl;
|
||||||
|
return janet_wrap_number(7.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const JanetReg array_cfuns[] = {
|
||||||
|
{"get7", cfun_get_seven, NULL},
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
JANET_MODULE_ENTRY(JanetTable *env) {
|
||||||
|
janet_cfuns(env, NULL, array_cfuns);
|
||||||
|
}
|
40
test/install/testmod4.c
Normal file
40
test/install/testmod4.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Calvin Rose and contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* A very simple native module */
|
||||||
|
|
||||||
|
#include <janet.h>
|
||||||
|
|
||||||
|
static Janet cfun_get_eight(int32_t argc, Janet *argv) {
|
||||||
|
(void) argv;
|
||||||
|
janet_fixarity(argc, 0);
|
||||||
|
return janet_wrap_number(8.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const JanetReg array_cfuns[] = {
|
||||||
|
{"get8", cfun_get_eight, NULL},
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
JANET_MODULE_ENTRY(JanetTable *env) {
|
||||||
|
janet_cfuns(env, NULL, array_cfuns);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user