mirror of
https://github.com/janet-lang/janet
synced 2025-11-18 08:15:13 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b2169e0d1 | ||
|
|
2c927ea768 | ||
|
|
f4bbcdcbc8 | ||
|
|
79c375b1af | ||
|
|
f443a3b3a1 | ||
|
|
684d2d63f4 | ||
|
|
1900d8f843 | ||
|
|
3c2af95d21 | ||
|
|
b35414ea0f | ||
|
|
fb5b056f7b | ||
|
|
7248c1dfdb | ||
|
|
4c7ea9e893 | ||
|
|
c7801ce277 | ||
|
|
f741a8e3ff | ||
|
|
6a92e8b609 | ||
|
|
9da91a8217 | ||
|
|
69853c8e5c | ||
|
|
1f41b6c138 | ||
|
|
e001efa9fd | ||
|
|
435e64d4cf | ||
|
|
f296c8f5fb | ||
|
|
8d0e6ed32f | ||
|
|
b6a36afffe | ||
|
|
e422abc269 | ||
|
|
221d71d07b | ||
|
|
9f35f0837e | ||
|
|
515891b035 | ||
|
|
94a506876f | ||
|
|
9bde57854a | ||
|
|
f456369941 | ||
|
|
e0b7533c39 |
@@ -13,7 +13,7 @@ tasks:
|
|||||||
gmake test-install
|
gmake test-install
|
||||||
- meson_min: |
|
- meson_min: |
|
||||||
cd janet
|
cd janet
|
||||||
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dtyped_array=false -Dreduced_os=true -Dffi=false
|
meson setup build_meson_min --buildtype=release -Dsingle_threaded=true -Dnanbox=false -Ddynamic_modules=false -Ddocstrings=false -Dnet=false -Dsourcemaps=false -Dpeg=false -Dassembler=false -Dint_types=false -Dreduced_os=true -Dffi=false
|
||||||
cd build_meson_min
|
cd build_meson_min
|
||||||
ninja
|
ninja
|
||||||
- meson_prf: |
|
- meson_prf: |
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## 1.23.1 - ???
|
||||||
|
- Don't process shared object names passed to dlopen.
|
||||||
|
- Add better support for windows console in the default shell.c for autocompletion and
|
||||||
|
other shell-like input features.
|
||||||
|
- Improve default error message from `assert`.
|
||||||
|
- Add the `tabseq` macro for simpler table comprehensions.
|
||||||
|
- Allow setting `(dyn :task-id)` in fibers to improve context in supervisor messages. Prior to
|
||||||
|
this change, supverisor messages over threaded channels would be from ambiguous threads/fibers.
|
||||||
|
|
||||||
## 1.23.0 - 2022-06-20
|
## 1.23.0 - 2022-06-20
|
||||||
- Add experimental `ffi/` module for interfacing with dynamic libraries and raw function pointers. Only available
|
- Add experimental `ffi/` module for interfacing with dynamic libraries and raw function pointers. Only available
|
||||||
on 64 bit linux, mac, and bsd systems.
|
on 64 bit linux, mac, and bsd systems.
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2021 Calvin Rose
|
# Copyright (c) 2022 Calvin Rose
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to
|
# of this software and associated documentation files (the "Software"), to
|
||||||
@@ -283,7 +283,7 @@ install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc
|
|||||||
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
|
cp $(JANET_TARGET) '$(DESTDIR)$(BINDIR)/janet'
|
||||||
mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet'
|
mkdir -p '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||||
cp -r build/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet'
|
cp -r build/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet'
|
||||||
ln -sf '$(DESTDIR)$(INCLUDEDIR)/janet/janet.h' '$(DESTDIR)$(INCLUDEDIR)/janet.h'
|
ln -sf -T ./janet/janet.h '$(DESTDIR)$(INCLUDEDIR)/janet.h' || true #fixme bsd
|
||||||
mkdir -p '$(DESTDIR)$(JANET_PATH)'
|
mkdir -p '$(DESTDIR)$(JANET_PATH)'
|
||||||
mkdir -p '$(DESTDIR)$(LIBDIR)'
|
mkdir -p '$(DESTDIR)$(LIBDIR)'
|
||||||
if test $(UNAME) = Darwin ; then \
|
if test $(UNAME) = Darwin ; then \
|
||||||
@@ -300,7 +300,7 @@ install: $(JANET_TARGET) $(JANET_LIBRARY) $(JANET_STATIC_LIBRARY) build/janet.pc
|
|||||||
cp janet.1 '$(DESTDIR)$(JANET_MANPATH)'
|
cp janet.1 '$(DESTDIR)$(JANET_MANPATH)'
|
||||||
mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
|
mkdir -p '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)'
|
||||||
cp build/janet.pc '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
cp build/janet.pc '$(DESTDIR)$(JANET_PKG_CONFIG_PATH)/janet.pc'
|
||||||
[ -z '$(DESTDIR)' ] && $(LDCONFIG) || true
|
[ -z '$(DESTDIR)' ] && $(LDCONFIG) || echo "You can ignore this error for non-Linux systems or local installs"
|
||||||
|
|
||||||
install-jpm-git: $(JANET_TARGET)
|
install-jpm-git: $(JANET_TARGET)
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
project('janet', 'c',
|
project('janet', 'c',
|
||||||
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
|
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
|
||||||
version : '1.23.0')
|
version : '1.23.1')
|
||||||
|
|
||||||
# Global settings
|
# Global settings
|
||||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||||
|
|||||||
@@ -76,6 +76,11 @@
|
|||||||
[name & more]
|
[name & more]
|
||||||
~(var ,name :private ,;more))
|
~(var ,name :private ,;more))
|
||||||
|
|
||||||
|
(defmacro toggle
|
||||||
|
"Set a value to its boolean inverse. Same as `(set value (not value))`."
|
||||||
|
[value]
|
||||||
|
~(set ,value (,not ,value)))
|
||||||
|
|
||||||
(defn defglobal
|
(defn defglobal
|
||||||
"Dynamically create a global def."
|
"Dynamically create a global def."
|
||||||
[name value]
|
[name value]
|
||||||
@@ -158,7 +163,7 @@
|
|||||||
(def ,v ,x)
|
(def ,v ,x)
|
||||||
(if ,v
|
(if ,v
|
||||||
,v
|
,v
|
||||||
(,error ,(if err err "assert failure")))))
|
(,error ,(if err err (string/format "assert failure in %j" x))))))
|
||||||
|
|
||||||
(defn errorf
|
(defn errorf
|
||||||
"A combination of `error` and `string/format`. Equivalent to `(error (string/format fmt ;args))`."
|
"A combination of `error` and `string/format`. Equivalent to `(error (string/format fmt ;args))`."
|
||||||
@@ -606,13 +611,20 @@
|
|||||||
See `loop` for details.``
|
See `loop` for details.``
|
||||||
[head & body]
|
[head & body]
|
||||||
(def $accum (gensym))
|
(def $accum (gensym))
|
||||||
~(do (def ,$accum @[]) (loop ,head (array/push ,$accum (do ,;body))) ,$accum))
|
~(do (def ,$accum @[]) (loop ,head (,array/push ,$accum (do ,;body))) ,$accum))
|
||||||
|
|
||||||
|
(defmacro tabseq
|
||||||
|
``Similar to `loop`, but accumulates key value pairs into a table.
|
||||||
|
See `loop` for details.``
|
||||||
|
[head key-body & value-body]
|
||||||
|
(def $accum (gensym))
|
||||||
|
~(do (def ,$accum @{}) (loop ,head (,put ,$accum ,key-body (do ,;value-body))) ,$accum))
|
||||||
|
|
||||||
(defmacro generate
|
(defmacro generate
|
||||||
``Create a generator expression using the `loop` syntax. Returns a fiber
|
``Create a generator expression using the `loop` syntax. Returns a fiber
|
||||||
that yields all values inside the loop in order. See `loop` for details.``
|
that yields all values inside the loop in order. See `loop` for details.``
|
||||||
[head & body]
|
[head & body]
|
||||||
~(fiber/new (fn [] (loop ,head (yield (do ,;body)))) :yi))
|
~(,fiber/new (fn [] (loop ,head (yield (do ,;body)))) :yi))
|
||||||
|
|
||||||
(defmacro coro
|
(defmacro coro
|
||||||
"A wrapper for making fibers that may yield multiple values (coroutine). Same as `(fiber/new (fn [] ;body) :yi)`."
|
"A wrapper for making fibers that may yield multiple values (coroutine). Same as `(fiber/new (fn [] ;body) :yi)`."
|
||||||
@@ -2768,13 +2780,13 @@
|
|||||||
(def c ((:where p) 0))
|
(def c ((:where p) 0))
|
||||||
(def prpt (string "debug[" level "]:" c ":" status "> "))
|
(def prpt (string "debug[" level "]:" c ":" status "> "))
|
||||||
(getline prpt buf nextenv))
|
(getline prpt buf nextenv))
|
||||||
(print "entering debug[" level "] - (quit) to exit")
|
(eprint "entering debug[" level "] - (quit) to exit")
|
||||||
(flush)
|
(flush)
|
||||||
(run-context
|
(run-context
|
||||||
{:chunks debugger-chunks
|
{:chunks debugger-chunks
|
||||||
:on-status (debugger-on-status-var nextenv (+ 1 level) true)
|
:on-status (debugger-on-status-var nextenv (+ 1 level) true)
|
||||||
:env nextenv})
|
:env nextenv})
|
||||||
(print "exiting debug[" level "]")
|
(eprint "exiting debug[" level "]")
|
||||||
(flush)
|
(flush)
|
||||||
(nextenv :resume-value))
|
(nextenv :resume-value))
|
||||||
|
|
||||||
@@ -3013,7 +3025,7 @@
|
|||||||
:italics ["*" "*"]
|
:italics ["*" "*"]
|
||||||
:bold ["**" "**"]}))
|
:bold ["**" "**"]}))
|
||||||
(def modes @{})
|
(def modes @{})
|
||||||
(defn toggle [mode]
|
(defn toggle-mode [mode]
|
||||||
(def active (get modes mode))
|
(def active (get modes mode))
|
||||||
(def delims (get delimiters mode))
|
(def delims (get delimiters mode))
|
||||||
(put modes mode (not active))
|
(put modes mode (not active))
|
||||||
@@ -3123,7 +3135,7 @@
|
|||||||
(def token @"")
|
(def token @"")
|
||||||
(var token-length 0)
|
(var token-length 0)
|
||||||
(defn delim [mode]
|
(defn delim [mode]
|
||||||
(def d (toggle mode))
|
(def d (toggle-mode mode))
|
||||||
(if-not has-color (+= token-length (length d)))
|
(if-not has-color (+= token-length (length d)))
|
||||||
(buffer/push token d))
|
(buffer/push token d))
|
||||||
(defn endtoken []
|
(defn endtoken []
|
||||||
@@ -3134,16 +3146,18 @@
|
|||||||
(def b (get line i))
|
(def b (get line i))
|
||||||
(cond
|
(cond
|
||||||
(or (= b (chr "\n")) (= b (chr " "))) (endtoken)
|
(or (= b (chr "\n")) (= b (chr " "))) (endtoken)
|
||||||
(= b (chr `\`)) (do
|
|
||||||
(++ token-length)
|
|
||||||
(buffer/push token (get line (++ i))))
|
|
||||||
(= b (chr "_")) (delim :underline)
|
|
||||||
(= b (chr "`")) (delim :code)
|
(= b (chr "`")) (delim :code)
|
||||||
(= b (chr "*"))
|
(not (modes :code)) (cond
|
||||||
(if (= (chr "*") (get line (+ i 1)))
|
(= b (chr `\`)) (do
|
||||||
(do (++ i)
|
(++ token-length)
|
||||||
(delim :bold))
|
(buffer/push token (get line (++ i))))
|
||||||
(delim :italics))
|
(= b (chr "_")) (delim :underline)
|
||||||
|
(= b (chr "*"))
|
||||||
|
(if (= (chr "*") (get line (+ i 1)))
|
||||||
|
(do (++ i)
|
||||||
|
(delim :bold))
|
||||||
|
(delim :italics))
|
||||||
|
(do (++ token-length) (buffer/push token b)))
|
||||||
(do (++ token-length) (buffer/push token b))))
|
(do (++ token-length) (buffer/push token b))))
|
||||||
(endtoken)
|
(endtoken)
|
||||||
(tuple/slice tokens))
|
(tuple/slice tokens))
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#define JANET_VERSION_MAJOR 1
|
#define JANET_VERSION_MAJOR 1
|
||||||
#define JANET_VERSION_MINOR 23
|
#define JANET_VERSION_MINOR 23
|
||||||
#define JANET_VERSION_PATCH 0
|
#define JANET_VERSION_PATCH 1
|
||||||
#define JANET_VERSION_EXTRA ""
|
#define JANET_VERSION_EXTRA "-dev"
|
||||||
#define JANET_VERSION "1.23.0"
|
#define JANET_VERSION "1.23.1-dev"
|
||||||
|
|
||||||
/* #define JANET_BUILD "local" */
|
/* #define JANET_BUILD "local" */
|
||||||
|
|
||||||
|
|||||||
@@ -535,10 +535,15 @@ static int janet_channel_push(JanetChannel *channel, Janet x, int mode);
|
|||||||
static int janet_channel_pop(JanetChannel *channel, Janet *item, int is_choice);
|
static int janet_channel_pop(JanetChannel *channel, Janet *item, int is_choice);
|
||||||
|
|
||||||
static Janet make_supervisor_event(const char *name, JanetFiber *fiber, int threaded) {
|
static Janet make_supervisor_event(const char *name, JanetFiber *fiber, int threaded) {
|
||||||
Janet tup[2];
|
Janet tup[3];
|
||||||
tup[0] = janet_ckeywordv(name);
|
tup[0] = janet_ckeywordv(name);
|
||||||
tup[1] = threaded ? fiber->last_value : janet_wrap_fiber(fiber) ;
|
tup[1] = threaded ? fiber->last_value : janet_wrap_fiber(fiber) ;
|
||||||
return janet_wrap_tuple(janet_tuple_n(tup, 2));
|
if (fiber->env != NULL) {
|
||||||
|
tup[2] = janet_table_get(fiber->env, janet_ckeywordv("task-id"));
|
||||||
|
} else {
|
||||||
|
tup[2] = janet_wrap_nil();
|
||||||
|
}
|
||||||
|
return janet_wrap_tuple(janet_tuple_n(tup, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common init code */
|
/* Common init code */
|
||||||
@@ -2719,6 +2724,8 @@ JANET_CORE_FN(cfun_ev_go,
|
|||||||
return janet_wrap_fiber(fiber);
|
return janet_wrap_fiber(fiber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define JANET_THREAD_SUPERVISOR_FLAG 0x100
|
||||||
|
|
||||||
/* For ev/thread - Run an interpreter in the new thread. */
|
/* For ev/thread - Run an interpreter in the new thread. */
|
||||||
static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
|
static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
|
||||||
JanetBuffer *buffer = (JanetBuffer *) args.argp;
|
JanetBuffer *buffer = (JanetBuffer *) args.argp;
|
||||||
@@ -2741,7 +2748,7 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get supervsior */
|
/* Get supervsior */
|
||||||
if (flags & 0x8) {
|
if (flags & JANET_THREAD_SUPERVISOR_FLAG) {
|
||||||
Janet sup =
|
Janet sup =
|
||||||
janet_unmarshal(nextbytes, endbytes - nextbytes,
|
janet_unmarshal(nextbytes, endbytes - nextbytes,
|
||||||
JANET_MARSHAL_UNSAFE, NULL, &nextbytes);
|
JANET_MARSHAL_UNSAFE, NULL, &nextbytes);
|
||||||
@@ -2793,6 +2800,10 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
|
|||||||
} else {
|
} else {
|
||||||
fiber = janet_unwrap_fiber(fiberv);
|
fiber = janet_unwrap_fiber(fiberv);
|
||||||
}
|
}
|
||||||
|
if (flags & 0x8) {
|
||||||
|
if (NULL == fiber->env) fiber->env = janet_table(0);
|
||||||
|
janet_table_put(fiber->env, janet_ckeywordv("task-id"), value);
|
||||||
|
}
|
||||||
fiber->supervisor_channel = janet_vm.user;
|
fiber->supervisor_channel = janet_vm.user;
|
||||||
janet_schedule(fiber, value);
|
janet_schedule(fiber, value);
|
||||||
janet_loop();
|
janet_loop();
|
||||||
@@ -2837,6 +2848,7 @@ JANET_CORE_FN(cfun_ev_thread,
|
|||||||
"If you want to run the thread without waiting for a result, pass the `:n` flag to return nil immediately. "
|
"If you want to run the thread without waiting for a result, pass the `:n` flag to return nil immediately. "
|
||||||
"Otherwise, returns nil. Available flags:\n\n"
|
"Otherwise, returns nil. Available flags:\n\n"
|
||||||
"* `:n` - return immediately\n"
|
"* `:n` - return immediately\n"
|
||||||
|
"* `:t` - set the task-id of the new thread to value. The task-id is passed in messages to the supervisor channel.\n"
|
||||||
"* `:a` - don't copy abstract registry to new thread (performance optimization)\n"
|
"* `:a` - don't copy abstract registry to new thread (performance optimization)\n"
|
||||||
"* `:c` - don't copy cfunction registry to new thread (performance optimization)") {
|
"* `:c` - don't copy cfunction registry to new thread (performance optimization)") {
|
||||||
janet_arity(argc, 1, 4);
|
janet_arity(argc, 1, 4);
|
||||||
@@ -2844,10 +2856,10 @@ JANET_CORE_FN(cfun_ev_thread,
|
|||||||
if (!janet_checktype(argv[0], JANET_FUNCTION)) janet_getfiber(argv, 0);
|
if (!janet_checktype(argv[0], JANET_FUNCTION)) janet_getfiber(argv, 0);
|
||||||
uint64_t flags = 0;
|
uint64_t flags = 0;
|
||||||
if (argc >= 3) {
|
if (argc >= 3) {
|
||||||
flags = janet_getflags(argv, 2, "nac");
|
flags = janet_getflags(argv, 2, "nact");
|
||||||
}
|
}
|
||||||
void *supervisor = janet_optabstract(argv, argc, 3, &janet_channel_type, janet_vm.root_fiber->supervisor_channel);
|
void *supervisor = janet_optabstract(argv, argc, 3, &janet_channel_type, janet_vm.root_fiber->supervisor_channel);
|
||||||
if (NULL != supervisor) flags |= 0x8;
|
if (NULL != supervisor) flags |= JANET_THREAD_SUPERVISOR_FLAG;
|
||||||
|
|
||||||
/* Marshal arguments for the new thread. */
|
/* Marshal arguments for the new thread. */
|
||||||
JanetBuffer *buffer = janet_malloc(sizeof(JanetBuffer));
|
JanetBuffer *buffer = janet_malloc(sizeof(JanetBuffer));
|
||||||
@@ -2858,7 +2870,7 @@ JANET_CORE_FN(cfun_ev_thread,
|
|||||||
if (!(flags & 0x2)) {
|
if (!(flags & 0x2)) {
|
||||||
janet_marshal(buffer, janet_wrap_table(janet_vm.abstract_registry), NULL, JANET_MARSHAL_UNSAFE);
|
janet_marshal(buffer, janet_wrap_table(janet_vm.abstract_registry), NULL, JANET_MARSHAL_UNSAFE);
|
||||||
}
|
}
|
||||||
if (flags & 0x8) {
|
if (flags & JANET_THREAD_SUPERVISOR_FLAG) {
|
||||||
janet_marshal(buffer, janet_wrap_abstract(supervisor), NULL, JANET_MARSHAL_UNSAFE);
|
janet_marshal(buffer, janet_wrap_abstract(supervisor), NULL, JANET_MARSHAL_UNSAFE);
|
||||||
}
|
}
|
||||||
if (!(flags & 0x4)) {
|
if (!(flags & 0x4)) {
|
||||||
|
|||||||
@@ -1183,9 +1183,7 @@ JANET_CORE_FN(janet_core_raw_native,
|
|||||||
"Returns a `core/native`.") {
|
"Returns a `core/native`.") {
|
||||||
janet_arity(argc, 0, 1);
|
janet_arity(argc, 0, 1);
|
||||||
const char *path = janet_optcstring(argv, argc, 0, NULL);
|
const char *path = janet_optcstring(argv, argc, 0, NULL);
|
||||||
char *processed_name = (NULL == path) ? NULL : get_processed_name(path);
|
Clib lib = load_clib(path);
|
||||||
Clib lib = load_clib(processed_name);
|
|
||||||
if (NULL != path && path != processed_name) janet_free(processed_name);
|
|
||||||
if (!lib) janet_panic(error_clib());
|
if (!lib) janet_panic(error_clib());
|
||||||
JanetAbstractNative *anative = janet_abstract(&janet_native_type, sizeof(JanetAbstractNative));
|
JanetAbstractNative *anative = janet_abstract(&janet_native_type, sizeof(JanetAbstractNative));
|
||||||
anative->clib = lib;
|
anative->clib = lib;
|
||||||
|
|||||||
@@ -545,6 +545,16 @@ static Janet cfun_io_printf_impl_x(int32_t argc, Janet *argv, int newline,
|
|||||||
if (newline) janet_buffer_push_u8(buf, '\n');
|
if (newline) janet_buffer_push_u8(buf, '\n');
|
||||||
return janet_wrap_nil();
|
return janet_wrap_nil();
|
||||||
}
|
}
|
||||||
|
case JANET_FUNCTION: {
|
||||||
|
/* Special case function */
|
||||||
|
JanetFunction *fun = janet_unwrap_function(x);
|
||||||
|
JanetBuffer *buf = janet_buffer(0);
|
||||||
|
janet_buffer_format(buf, fmt, offset, argc, argv);
|
||||||
|
if (newline) janet_buffer_push_u8(buf, '\n');
|
||||||
|
Janet args[1] = { janet_wrap_buffer(buf) };
|
||||||
|
janet_call(fun, 1, args);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
case JANET_NIL:
|
case JANET_NIL:
|
||||||
f = dflt_file;
|
f = dflt_file;
|
||||||
if (f == NULL) janet_panic("cannot print to nil");
|
if (f == NULL) janet_panic("cannot print to nil");
|
||||||
@@ -684,6 +694,16 @@ void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...)
|
|||||||
janet_buffer_deinit(&buffer);
|
janet_buffer_deinit(&buffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case JANET_FUNCTION: {
|
||||||
|
JanetFunction *fun = janet_unwrap_function(x);
|
||||||
|
int32_t len = 0;
|
||||||
|
while (format[len]) len++;
|
||||||
|
JanetBuffer *buf = janet_buffer(len);
|
||||||
|
janet_formatbv(buf, format, args);
|
||||||
|
Janet args[1] = { janet_wrap_buffer(buf) };
|
||||||
|
janet_call(fun, 1, args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case JANET_BUFFER:
|
case JANET_BUFFER:
|
||||||
janet_formatbv(janet_unwrap_buffer(x), format, args);
|
janet_formatbv(janet_unwrap_buffer(x), format, args);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1121,8 +1121,8 @@ JANET_CORE_FN(os_spawn,
|
|||||||
"Execute a program on the system and return a handle to the process. Otherwise, takes the "
|
"Execute a program on the system and return a handle to the process. Otherwise, takes the "
|
||||||
"same arguments as `os/execute`. Does not wait for the process. "
|
"same arguments as `os/execute`. Does not wait for the process. "
|
||||||
"For each of the :in, :out, and :err keys to the `env` argument, one "
|
"For each of the :in, :out, and :err keys to the `env` argument, one "
|
||||||
"can also pass in the keyword `:pipe`"
|
"can also pass in the keyword `:pipe` "
|
||||||
"to get streams for standard IO of the subprocess that can be read from and written to."
|
"to get streams for standard IO of the subprocess that can be read from and written to. "
|
||||||
"The returned value `proc` has the fields :in, :out, :err, :return-code, and "
|
"The returned value `proc` has the fields :in, :out, :err, :return-code, and "
|
||||||
"the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
|
"the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
|
||||||
"subprocess or `(os/proc-kill proc)`.") {
|
"subprocess or `(os/proc-kill proc)`.") {
|
||||||
@@ -2036,23 +2036,23 @@ JANET_CORE_FN(os_open,
|
|||||||
"Allowed flags are as follows:\n\n"
|
"Allowed flags are as follows:\n\n"
|
||||||
" * :r - open this file for reading\n"
|
" * :r - open this file for reading\n"
|
||||||
" * :w - open this file for writing\n"
|
" * :w - open this file for writing\n"
|
||||||
" * :c - create a new file (O_CREATE)\n"
|
" * :c - create a new file (O\\_CREATE)\n"
|
||||||
" * :e - fail if the file exists (O_EXCL)\n"
|
" * :e - fail if the file exists (O\\_EXCL)\n"
|
||||||
" * :t - shorten an existing file to length 0 (O_TRUNC)\n\n"
|
" * :t - shorten an existing file to length 0 (O\\_TRUNC)\n\n"
|
||||||
"Posix-only flags:\n\n"
|
"Posix-only flags:\n\n"
|
||||||
" * :a - append to a file (O_APPEND)\n"
|
" * :a - append to a file (O\\_APPEND)\n"
|
||||||
" * :x - O_SYNC\n"
|
" * :x - O\\_SYNC\n"
|
||||||
" * :C - O_NOCTTY\n\n"
|
" * :C - O\\_NOCTTY\n\n"
|
||||||
"Windows-only flags:\n\n"
|
"Windows-only flags:\n\n"
|
||||||
" * :R - share reads (FILE_SHARE_READ)\n"
|
" * :R - share reads (FILE\\_SHARE\\_READ)\n"
|
||||||
" * :W - share writes (FILE_SHARE_WRITE)\n"
|
" * :W - share writes (FILE\\_SHARE\\_WRITE)\n"
|
||||||
" * :D - share deletes (FILE_SHARE_DELETE)\n"
|
" * :D - share deletes (FILE\\_SHARE\\_DELETE)\n"
|
||||||
" * :H - FILE_ATTRIBUTE_HIDDEN\n"
|
" * :H - FILE\\_ATTRIBUTE\\_HIDDEN\n"
|
||||||
" * :O - FILE_ATTRIBUTE_READONLY\n"
|
" * :O - FILE\\_ATTRIBUTE\\_READONLY\n"
|
||||||
" * :F - FILE_ATTRIBUTE_OFFLINE\n"
|
" * :F - FILE\\_ATTRIBUTE\\_OFFLINE\n"
|
||||||
" * :T - FILE_ATTRIBUTE_TEMPORARY\n"
|
" * :T - FILE\\_ATTRIBUTE\\_TEMPORARY\n"
|
||||||
" * :d - FILE_FLAG_DELETE_ON_CLOSE\n"
|
" * :d - FILE\\_FLAG\\_DELETE\\_ON\\_CLOSE\n"
|
||||||
" * :b - FILE_FLAG_NO_BUFFERING\n") {
|
" * :b - FILE\\_FLAG\\_NO\\_BUFFERING\n") {
|
||||||
janet_arity(argc, 1, 3);
|
janet_arity(argc, 1, 3);
|
||||||
const char *path = janet_getcstring(argv, 0);
|
const char *path = janet_getcstring(argv, 0);
|
||||||
const uint8_t *opt_flags = janet_optkeyword(argv, argc, 1, (const uint8_t *) "r");
|
const uint8_t *opt_flags = janet_optkeyword(argv, argc, 1, (const uint8_t *) "r");
|
||||||
|
|||||||
@@ -762,8 +762,7 @@ static const char *scanformat(
|
|||||||
memset(precision, '\0', 3);
|
memset(precision, '\0', 3);
|
||||||
while (*p != '\0' && strchr(FMT_FLAGS, *p) != NULL)
|
while (*p != '\0' && strchr(FMT_FLAGS, *p) != NULL)
|
||||||
p++; /* skip flags */
|
p++; /* skip flags */
|
||||||
if ((size_t)(p - strfrmt) >= sizeof(FMT_FLAGS) / sizeof(char))
|
if ((size_t)(p - strfrmt) >= sizeof(FMT_FLAGS)) janet_panic("invalid format (repeated flags)");
|
||||||
janet_panic("invalid format (repeated flags)");
|
|
||||||
if (isdigit((int)(*p)))
|
if (isdigit((int)(*p)))
|
||||||
width[0] = *p++; /* skip width */
|
width[0] = *p++; /* skip width */
|
||||||
if (isdigit((int)(*p)))
|
if (isdigit((int)(*p)))
|
||||||
|
|||||||
@@ -530,7 +530,7 @@ JANET_CORE_FN(cfun_string_join,
|
|||||||
|
|
||||||
JANET_CORE_FN(cfun_string_format,
|
JANET_CORE_FN(cfun_string_format,
|
||||||
"(string/format format & values)",
|
"(string/format format & values)",
|
||||||
"Similar to `snprintf`, but specialized for operating with Janet values. Returns "
|
"Similar to C's `snprintf`, but specialized for operating with Janet values. Returns "
|
||||||
"a new string.") {
|
"a new string.") {
|
||||||
janet_arity(argc, 1, -1);
|
janet_arity(argc, 1, -1);
|
||||||
JanetBuffer *buffer = janet_buffer(0);
|
JanetBuffer *buffer = janet_buffer(0);
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ int32_t janet_hash(Janet x) {
|
|||||||
hash = (int32_t)((hilo << 16) | (hilo >> 16));
|
hash = (int32_t)((hilo << 16) | (hilo >> 16));
|
||||||
} else {
|
} else {
|
||||||
/* Assuming 4 byte pointer (or smaller) */
|
/* Assuming 4 byte pointer (or smaller) */
|
||||||
ptrdiff_t diff = ((char *)janet_unwrap_pointer(x) - (char *)0);
|
uintptr_t diff = (uintptr_t) janet_unwrap_pointer(x);
|
||||||
uint32_t hilo = (uint32_t) diff * 2654435769u;
|
uint32_t hilo = (uint32_t) diff * 2654435769u;
|
||||||
hash = (int32_t)((hilo << 16) | (hilo >> 16));
|
hash = (int32_t)((hilo << 16) | (hilo >> 16));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -220,14 +220,14 @@
|
|||||||
/* Trace a function call */
|
/* Trace a function call */
|
||||||
static void vm_do_trace(JanetFunction *func, int32_t argc, const Janet *argv) {
|
static void vm_do_trace(JanetFunction *func, int32_t argc, const Janet *argv) {
|
||||||
if (func->def->name) {
|
if (func->def->name) {
|
||||||
janet_printf("trace (%S", func->def->name);
|
janet_eprintf("trace (%S", func->def->name);
|
||||||
} else {
|
} else {
|
||||||
janet_printf("trace (%p", janet_wrap_function(func));
|
janet_eprintf("trace (%p", janet_wrap_function(func));
|
||||||
}
|
}
|
||||||
for (int32_t i = 0; i < argc; i++) {
|
for (int32_t i = 0; i < argc; i++) {
|
||||||
janet_printf(" %p", argv[i]);
|
janet_eprintf(" %p", argv[i]);
|
||||||
}
|
}
|
||||||
janet_printf(")\n");
|
janet_eprintf(")\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke a method once we have looked it up */
|
/* Invoke a method once we have looked it up */
|
||||||
@@ -1285,6 +1285,12 @@ JanetSignal janet_step(JanetFiber *fiber, Janet in, Janet *out) {
|
|||||||
return signal;
|
return signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet void_cfunction(int32_t argc, Janet *argv) {
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
janet_panic("placeholder");
|
||||||
|
}
|
||||||
|
|
||||||
Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
||||||
/* Check entry conditions */
|
/* Check entry conditions */
|
||||||
if (!janet_vm.fiber)
|
if (!janet_vm.fiber)
|
||||||
@@ -1292,9 +1298,17 @@ Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
|||||||
if (janet_vm.stackn >= JANET_RECURSION_GUARD)
|
if (janet_vm.stackn >= JANET_RECURSION_GUARD)
|
||||||
janet_panic("C stack recursed too deeply");
|
janet_panic("C stack recursed too deeply");
|
||||||
|
|
||||||
|
/* Dirty stack */
|
||||||
|
int32_t dirty_stack = janet_vm.fiber->stacktop - janet_vm.fiber->stackstart;
|
||||||
|
if (dirty_stack) {
|
||||||
|
janet_fiber_cframe(janet_vm.fiber, void_cfunction);
|
||||||
|
}
|
||||||
|
|
||||||
/* Tracing */
|
/* Tracing */
|
||||||
if (fun->gc.flags & JANET_FUNCFLAG_TRACE) {
|
if (fun->gc.flags & JANET_FUNCFLAG_TRACE) {
|
||||||
|
janet_vm.stackn++;
|
||||||
vm_do_trace(fun, argc, argv);
|
vm_do_trace(fun, argc, argv);
|
||||||
|
janet_vm.stackn--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push frame */
|
/* Push frame */
|
||||||
@@ -1322,6 +1336,10 @@ Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv) {
|
|||||||
/* Teardown */
|
/* Teardown */
|
||||||
janet_vm.stackn = oldn;
|
janet_vm.stackn = oldn;
|
||||||
janet_gcunlock(handle);
|
janet_gcunlock(handle);
|
||||||
|
if (dirty_stack) {
|
||||||
|
janet_fiber_popframe(janet_vm.fiber);
|
||||||
|
janet_vm.fiber->stacktop += dirty_stack;
|
||||||
|
}
|
||||||
|
|
||||||
if (signal != JANET_SIGNAL_OK) {
|
if (signal != JANET_SIGNAL_OK) {
|
||||||
janet_panicv(*janet_vm.return_reg);
|
janet_panicv(*janet_vm.return_reg);
|
||||||
|
|||||||
@@ -87,8 +87,30 @@ static void simpleline(JanetBuffer *buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Windows */
|
/* State */
|
||||||
#if defined(JANET_WINDOWS) || defined(JANET_SIMPLE_GETLINE)
|
|
||||||
|
#ifndef JANET_SIMPLE_GETLINE
|
||||||
|
/* static state */
|
||||||
|
#define JANET_LINE_MAX 1024
|
||||||
|
#define JANET_MATCH_MAX 256
|
||||||
|
#define JANET_HISTORY_MAX 100
|
||||||
|
static JANET_THREAD_LOCAL int gbl_israwmode = 0;
|
||||||
|
static JANET_THREAD_LOCAL const char *gbl_prompt = "> ";
|
||||||
|
static JANET_THREAD_LOCAL int gbl_plen = 2;
|
||||||
|
static JANET_THREAD_LOCAL char gbl_buf[JANET_LINE_MAX];
|
||||||
|
static JANET_THREAD_LOCAL int gbl_len = 0;
|
||||||
|
static JANET_THREAD_LOCAL int gbl_pos = 0;
|
||||||
|
static JANET_THREAD_LOCAL int gbl_cols = 80;
|
||||||
|
static JANET_THREAD_LOCAL char *gbl_history[JANET_HISTORY_MAX];
|
||||||
|
static JANET_THREAD_LOCAL int gbl_history_count = 0;
|
||||||
|
static JANET_THREAD_LOCAL int gbl_historyi = 0;
|
||||||
|
static JANET_THREAD_LOCAL JanetByteView gbl_matches[JANET_MATCH_MAX];
|
||||||
|
static JANET_THREAD_LOCAL int gbl_match_count = 0;
|
||||||
|
static JANET_THREAD_LOCAL int gbl_lines_below = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fallback */
|
||||||
|
#if defined(JANET_SIMPLE_GETLINE)
|
||||||
|
|
||||||
void janet_line_init() {
|
void janet_line_init() {
|
||||||
;
|
;
|
||||||
@@ -105,6 +127,80 @@ void janet_line_get(const char *p, JanetBuffer *buffer) {
|
|||||||
simpleline(buffer);
|
simpleline(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rich implementation */
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Windows */
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
static void setup_console_output(void) {
|
||||||
|
/* Enable color console on windows 10 console and utf8 output and other processing */
|
||||||
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
DWORD dwMode = 0;
|
||||||
|
GetConsoleMode(hOut, &dwMode);
|
||||||
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
SetConsoleMode(hOut, dwMode);
|
||||||
|
SetConsoleOutputCP(65001);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ansi terminal raw mode */
|
||||||
|
static int rawmode(void) {
|
||||||
|
if (gbl_israwmode) return 0;
|
||||||
|
HANDLE hOut = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
DWORD dwMode = 0;
|
||||||
|
GetConsoleMode(hOut, &dwMode);
|
||||||
|
dwMode &= ~ENABLE_LINE_INPUT;
|
||||||
|
dwMode &= ~ENABLE_INSERT_MODE;
|
||||||
|
dwMode &= ~ENABLE_ECHO_INPUT;
|
||||||
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||||
|
dwMode &= ~ENABLE_PROCESSED_INPUT;
|
||||||
|
if (!SetConsoleMode(hOut, dwMode)) return 1;
|
||||||
|
gbl_israwmode = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable raw mode */
|
||||||
|
static void norawmode(void) {
|
||||||
|
if (!gbl_israwmode) return;
|
||||||
|
HANDLE hOut = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
DWORD dwMode = 0;
|
||||||
|
GetConsoleMode(hOut, &dwMode);
|
||||||
|
dwMode |= ENABLE_LINE_INPUT;
|
||||||
|
dwMode |= ENABLE_INSERT_MODE;
|
||||||
|
dwMode |= ENABLE_ECHO_INPUT;
|
||||||
|
dwMode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||||
|
dwMode |= ENABLE_PROCESSED_INPUT;
|
||||||
|
SetConsoleMode(hOut, dwMode);
|
||||||
|
gbl_israwmode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long write_console(const char *bytes, size_t n) {
|
||||||
|
DWORD nwritten = 0;
|
||||||
|
BOOL result = WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), bytes, (DWORD) n, &nwritten, NULL);
|
||||||
|
if (!result) return -1; /* error */
|
||||||
|
return (long)nwritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long read_console(char *into, size_t n) {
|
||||||
|
DWORD numread;
|
||||||
|
BOOL result = ReadConsole(GetStdHandle(STD_INPUT_HANDLE), into, (DWORD) n, &numread, NULL);
|
||||||
|
if (!result) return -1; /* error */
|
||||||
|
return (long)numread;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_simpleline(JanetBuffer *buffer) {
|
||||||
|
if (!_isatty(_fileno(stdin)) || rawmode()) {
|
||||||
|
simpleline(buffer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Posix */
|
/* Posix */
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -125,24 +221,7 @@ https://github.com/antirez/linenoise/blob/master/linenoise.c
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
/* static state */
|
|
||||||
#define JANET_LINE_MAX 1024
|
|
||||||
#define JANET_MATCH_MAX 256
|
|
||||||
#define JANET_HISTORY_MAX 100
|
|
||||||
static JANET_THREAD_LOCAL int gbl_israwmode = 0;
|
|
||||||
static JANET_THREAD_LOCAL const char *gbl_prompt = "> ";
|
|
||||||
static JANET_THREAD_LOCAL int gbl_plen = 2;
|
|
||||||
static JANET_THREAD_LOCAL char gbl_buf[JANET_LINE_MAX];
|
|
||||||
static JANET_THREAD_LOCAL int gbl_len = 0;
|
|
||||||
static JANET_THREAD_LOCAL int gbl_pos = 0;
|
|
||||||
static JANET_THREAD_LOCAL int gbl_cols = 80;
|
|
||||||
static JANET_THREAD_LOCAL char *gbl_history[JANET_HISTORY_MAX];
|
|
||||||
static JANET_THREAD_LOCAL int gbl_history_count = 0;
|
|
||||||
static JANET_THREAD_LOCAL int gbl_historyi = 0;
|
|
||||||
static JANET_THREAD_LOCAL struct termios gbl_termios_start;
|
static JANET_THREAD_LOCAL struct termios gbl_termios_start;
|
||||||
static JANET_THREAD_LOCAL JanetByteView gbl_matches[JANET_MATCH_MAX];
|
|
||||||
static JANET_THREAD_LOCAL int gbl_match_count = 0;
|
|
||||||
static JANET_THREAD_LOCAL int gbl_lines_below = 0;
|
|
||||||
|
|
||||||
/* Unsupported terminal list from linenoise */
|
/* Unsupported terminal list from linenoise */
|
||||||
static const char *badterms[] = {
|
static const char *badterms[] = {
|
||||||
@@ -152,15 +231,6 @@ static const char *badterms[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *sdup(const char *s) {
|
|
||||||
size_t len = strlen(s) + 1;
|
|
||||||
char *mem = janet_malloc(len);
|
|
||||||
if (!mem) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return memcpy(mem, s, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ansi terminal raw mode */
|
/* Ansi terminal raw mode */
|
||||||
static int rawmode(void) {
|
static int rawmode(void) {
|
||||||
struct termios t;
|
struct termios t;
|
||||||
@@ -186,13 +256,53 @@ static void norawmode(void) {
|
|||||||
gbl_israwmode = 0;
|
gbl_israwmode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int checktermsupport() {
|
||||||
|
const char *t = getenv("TERM");
|
||||||
|
int i;
|
||||||
|
if (!t) return 1;
|
||||||
|
for (i = 0; badterms[i]; i++)
|
||||||
|
if (!strcmp(t, badterms[i])) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long write_console(char *bytes, size_t n) {
|
||||||
|
return write(STDOUT_FILENO, bytes, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long read_console(char *into, size_t n) {
|
||||||
|
return read(STDIN_FILENO, into, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_simpleline(JanetBuffer *buffer) {
|
||||||
|
if (!isatty(STDIN_FILENO) || !checktermsupport()) {
|
||||||
|
simpleline(buffer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (rawmode()) {
|
||||||
|
simpleline(buffer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char *sdup(const char *s) {
|
||||||
|
size_t len = strlen(s) + 1;
|
||||||
|
char *mem = janet_malloc(len);
|
||||||
|
if (!mem) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return memcpy(mem, s, len);
|
||||||
|
}
|
||||||
|
|
||||||
static int curpos(void) {
|
static int curpos(void) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int cols, rows;
|
int cols, rows;
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) return -1;
|
if (write_console("\x1b[6n", 4) != 4) return -1;
|
||||||
while (i < sizeof(buf) - 1) {
|
while (i < sizeof(buf) - 1) {
|
||||||
if (read(STDIN_FILENO, buf + i, 1) != 1) break;
|
if (read_console(buf + i, 1) != 1) break;
|
||||||
if (buf[i] == 'R') break;
|
if (buf[i] == 'R') break;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@@ -203,18 +313,23 @@ static int curpos(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int getcols(void) {
|
static int getcols(void) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
|
||||||
|
return (int)(csbi.srWindow.Right - csbi.srWindow.Left + 1);
|
||||||
|
#else
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
|
if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
|
||||||
int start, cols;
|
int start, cols;
|
||||||
start = curpos();
|
start = curpos();
|
||||||
if (start == -1) goto failed;
|
if (start == -1) goto failed;
|
||||||
if (write(STDOUT_FILENO, "\x1b[999C", 6) != 6) goto failed;
|
if (write_console("\x1b[999C", 6) != 6) goto failed;
|
||||||
cols = curpos();
|
cols = curpos();
|
||||||
if (cols == -1) goto failed;
|
if (cols == -1) goto failed;
|
||||||
if (cols > start) {
|
if (cols > start) {
|
||||||
char seq[32];
|
char seq[32];
|
||||||
snprintf(seq, 32, "\x1b[%dD", cols - start);
|
snprintf(seq, 32, "\x1b[%dD", cols - start);
|
||||||
if (write(STDOUT_FILENO, seq, strlen(seq)) == -1) {
|
if (write_console(seq, strlen(seq)) == -1) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,10 +339,11 @@ static int getcols(void) {
|
|||||||
}
|
}
|
||||||
failed:
|
failed:
|
||||||
return 80;
|
return 80;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear(void) {
|
static void clear(void) {
|
||||||
if (write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7) <= 0) {
|
if (write_console("\x1b[H\x1b[2J", 7) <= 0) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,7 +375,7 @@ static void refresh(void) {
|
|||||||
/* Move cursor to original position. */
|
/* Move cursor to original position. */
|
||||||
snprintf(seq, 64, "\r\x1b[%dC", (int)(_pos + gbl_plen));
|
snprintf(seq, 64, "\r\x1b[%dC", (int)(_pos + gbl_plen));
|
||||||
janet_buffer_push_cstring(&b, seq);
|
janet_buffer_push_cstring(&b, seq);
|
||||||
if (write(STDOUT_FILENO, b.data, b.count) == -1) {
|
if (write_console((char *) b.data, b.count) == -1) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
janet_buffer_deinit(&b);
|
janet_buffer_deinit(&b);
|
||||||
@@ -285,7 +401,7 @@ static int insert(char c, int draw) {
|
|||||||
if (gbl_plen + gbl_len < gbl_cols) {
|
if (gbl_plen + gbl_len < gbl_cols) {
|
||||||
/* Avoid a full update of the line in the
|
/* Avoid a full update of the line in the
|
||||||
* trivial case. */
|
* trivial case. */
|
||||||
if (write(STDOUT_FILENO, &c, 1) == -1) return -1;
|
if (write_console(&c, 1) == -1) return -1;
|
||||||
} else {
|
} else {
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
@@ -312,7 +428,7 @@ static void historymove(int delta) {
|
|||||||
gbl_historyi = gbl_history_count - 1;
|
gbl_historyi = gbl_history_count - 1;
|
||||||
}
|
}
|
||||||
strncpy(gbl_buf, gbl_history[gbl_historyi], JANET_LINE_MAX - 1);
|
strncpy(gbl_buf, gbl_history[gbl_historyi], JANET_LINE_MAX - 1);
|
||||||
gbl_pos = gbl_len = strlen(gbl_buf);
|
gbl_pos = gbl_len = (int) strlen(gbl_buf);
|
||||||
gbl_buf[gbl_len] = '\0';
|
gbl_buf[gbl_len] = '\0';
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
@@ -527,6 +643,7 @@ static void check_specials(JanetByteView src) {
|
|||||||
check_cmatch(src, "unquote");
|
check_cmatch(src, "unquote");
|
||||||
check_cmatch(src, "var");
|
check_cmatch(src, "var");
|
||||||
check_cmatch(src, "while");
|
check_cmatch(src, "while");
|
||||||
|
check_cmatch(src, "upscope");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resolve_format(JanetTable *entry) {
|
static void resolve_format(JanetTable *entry) {
|
||||||
@@ -740,14 +857,14 @@ static int line() {
|
|||||||
|
|
||||||
addhistory();
|
addhistory();
|
||||||
|
|
||||||
if (write(STDOUT_FILENO, gbl_prompt, gbl_plen) == -1) return -1;
|
if (write_console((char *) gbl_prompt, gbl_plen) == -1) return -1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char c;
|
char c;
|
||||||
char seq[3];
|
char seq[3];
|
||||||
|
|
||||||
int rc;
|
int rc;
|
||||||
do {
|
do {
|
||||||
rc = read(STDIN_FILENO, &c, 1);
|
rc = read_console(&c, 1);
|
||||||
} while (rc < 0 && errno == EINTR);
|
} while (rc < 0 && errno == EINTR);
|
||||||
if (rc <= 0) return -1;
|
if (rc <= 0) return -1;
|
||||||
|
|
||||||
@@ -764,8 +881,13 @@ static int line() {
|
|||||||
kleft();
|
kleft();
|
||||||
break;
|
break;
|
||||||
case 3: /* ctrl-c */
|
case 3: /* ctrl-c */
|
||||||
|
clearlines();
|
||||||
norawmode();
|
norawmode();
|
||||||
|
#ifdef _WIN32
|
||||||
|
ExitProcess(1);
|
||||||
|
#else
|
||||||
kill(getpid(), SIGINT);
|
kill(getpid(), SIGINT);
|
||||||
|
#endif
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case 17: /* ctrl-q */
|
case 17: /* ctrl-q */
|
||||||
gbl_cancel_current_repl_form = 1;
|
gbl_cancel_current_repl_form = 1;
|
||||||
@@ -826,23 +948,25 @@ static int line() {
|
|||||||
case 23: /* ctrl-w */
|
case 23: /* ctrl-w */
|
||||||
kbackspacew();
|
kbackspacew();
|
||||||
break;
|
break;
|
||||||
|
#ifndef _WIN32
|
||||||
case 26: /* ctrl-z */
|
case 26: /* ctrl-z */
|
||||||
norawmode();
|
norawmode();
|
||||||
kill(getpid(), SIGSTOP);
|
kill(getpid(), SIGSTOP);
|
||||||
rawmode();
|
rawmode();
|
||||||
refresh();
|
refresh();
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
case 27: /* escape sequence */
|
case 27: /* escape sequence */
|
||||||
/* Read the next two bytes representing the escape sequence.
|
/* Read the next two bytes representing the escape sequence.
|
||||||
* Use two calls to handle slow terminals returning the two
|
* Use two calls to handle slow terminals returning the two
|
||||||
* chars at different times. */
|
* chars at different times. */
|
||||||
if (read(STDIN_FILENO, seq, 1) == -1) break;
|
if (read_console(seq, 1) == -1) break;
|
||||||
/* Esc[ = Control Sequence Introducer (CSI) */
|
/* Esc[ = Control Sequence Introducer (CSI) */
|
||||||
if (seq[0] == '[') {
|
if (seq[0] == '[') {
|
||||||
if (read(STDIN_FILENO, seq + 1, 1) == -1) break;
|
if (read_console(seq + 1, 1) == -1) break;
|
||||||
if (seq[1] >= '0' && seq[1] <= '9') {
|
if (seq[1] >= '0' && seq[1] <= '9') {
|
||||||
/* Extended escape, read additional byte. */
|
/* Extended escape, read additional byte. */
|
||||||
if (read(STDIN_FILENO, seq + 2, 1) == -1) break;
|
if (read_console(seq + 2, 1) == -1) break;
|
||||||
if (seq[2] == '~') {
|
if (seq[2] == '~') {
|
||||||
switch (seq[1]) {
|
switch (seq[1]) {
|
||||||
case '1': /* Home */
|
case '1': /* Home */
|
||||||
@@ -861,7 +985,7 @@ static int line() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (seq[0] == 'O') {
|
} else if (seq[0] == 'O') {
|
||||||
if (read(STDIN_FILENO, seq + 1, 1) == -1) break;
|
if (read_console(seq + 1, 1) == -1) break;
|
||||||
switch (seq[1]) {
|
switch (seq[1]) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -944,28 +1068,12 @@ void janet_line_deinit() {
|
|||||||
gbl_historyi = 0;
|
gbl_historyi = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checktermsupport() {
|
|
||||||
const char *t = getenv("TERM");
|
|
||||||
int i;
|
|
||||||
if (!t) return 1;
|
|
||||||
for (i = 0; badterms[i]; i++)
|
|
||||||
if (!strcmp(t, badterms[i])) return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void janet_line_get(const char *p, JanetBuffer *buffer) {
|
void janet_line_get(const char *p, JanetBuffer *buffer) {
|
||||||
gbl_prompt = p;
|
gbl_prompt = p;
|
||||||
buffer->count = 0;
|
buffer->count = 0;
|
||||||
gbl_historyi = 0;
|
gbl_historyi = 0;
|
||||||
|
if (check_simpleline(buffer)) return;
|
||||||
FILE *out = janet_dynfile("err", stderr);
|
FILE *out = janet_dynfile("err", stderr);
|
||||||
if (!isatty(STDIN_FILENO) || !checktermsupport()) {
|
|
||||||
simpleline(buffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rawmode()) {
|
|
||||||
simpleline(buffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (line()) {
|
if (line()) {
|
||||||
norawmode();
|
norawmode();
|
||||||
fputc('\n', out);
|
fputc('\n', out);
|
||||||
@@ -981,6 +1089,13 @@ void janet_line_get(const char *p, JanetBuffer *buffer) {
|
|||||||
replacehistory();
|
replacehistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clear_at_exit(void) {
|
||||||
|
if (!gbl_israwmode) {
|
||||||
|
clearlines();
|
||||||
|
norawmode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -993,18 +1108,11 @@ int main(int argc, char **argv) {
|
|||||||
JanetTable *env;
|
JanetTable *env;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* Enable color console on windows 10 console and utf8 output. */
|
setup_console_output();
|
||||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
DWORD dwMode = 0;
|
|
||||||
GetConsoleMode(hOut, &dwMode);
|
|
||||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
||||||
SetConsoleMode(hOut, dwMode);
|
|
||||||
SetConsoleOutputCP(65001);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(JANET_WINDOWS) && !defined(JANET_SIMPLE_GETLINE)
|
#if !defined(JANET_SIMPLE_GETLINE)
|
||||||
/* Try and not leave the terminal in a bad state */
|
atexit(clear_at_exit);
|
||||||
atexit(norawmode);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(JANET_PRF)
|
#if defined(JANET_PRF)
|
||||||
|
|||||||
@@ -93,5 +93,14 @@
|
|||||||
|
|
||||||
(assert (= 10 (named-opt-arguments 1 :a 2 :b 3 :c 4)) "named arguments 2")
|
(assert (= 10 (named-opt-arguments 1 :a 2 :b 3 :c 4)) "named arguments 2")
|
||||||
|
|
||||||
|
(let [b @""]
|
||||||
|
(defn dummy [a b c]
|
||||||
|
(+ a b c))
|
||||||
|
(trace dummy)
|
||||||
|
(defn errout [arg]
|
||||||
|
(buffer/push b arg))
|
||||||
|
(assert (= 6 (with-dyns [*err* errout] (dummy 1 2 3))) "trace to custom err function")
|
||||||
|
(assert (deep= @"trace (dummy 1 2 3)\n" b) "trace buffer correct"))
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
|
||||||
|
|||||||
30
test/suite0013.janet
Normal file
30
test/suite0013.janet
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Copyright (c) 2022 Calvin Rose & 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.
|
||||||
|
|
||||||
|
(import ./helper :prefix "" :exit true)
|
||||||
|
(start-suite 13)
|
||||||
|
|
||||||
|
(assert (deep= (tabseq [i :in (range 3)] i (* 3 i))
|
||||||
|
@{0 0 1 3 2 6}))
|
||||||
|
|
||||||
|
(assert (deep= (tabseq [i :in (range 3)] i)
|
||||||
|
@{}))
|
||||||
|
|
||||||
|
(end-suite)
|
||||||
0
tools/format.sh
Executable file → Normal file
0
tools/format.sh
Executable file → Normal file
Reference in New Issue
Block a user