1
0
mirror of https://github.com/janet-lang/janet synced 2025-11-18 08:15:13 +00:00

Compare commits

..

31 Commits

Author SHA1 Message Date
Calvin Rose
5b2169e0d1 Fix docstring. 2022-08-02 14:58:32 -05:00
Calvin Rose
2c927ea768 Add testcase for issue #1005 2022-08-02 12:34:24 -05:00
Calvin Rose
f4bbcdcbc8 Get rid of disabled tracing. #1005 2022-08-02 12:19:22 -05:00
Calvin Rose
79c375b1af Address #1005 - Fix janet_call stack clobbering on dirty stack. 2022-08-02 12:13:56 -05:00
Calvin Rose
f443a3b3a1 Remove type_array option to meson_min build 2022-07-26 14:27:22 -05:00
Calvin Rose
684d2d63f4 Emphasize the ldconfig error is expected. 2022-07-20 11:19:09 -05:00
Calvin Rose
1900d8f843 Fix build warnings on Linux GCC version 12.1.0 x64 2022-07-20 08:04:03 -05:00
Calvin Rose
3c2af95d21 Update CHANGELOG.md 2022-07-19 20:05:21 -05:00
Calvin Rose
b35414ea0f Merge branch 'master' of github.com:janet-lang/janet 2022-07-19 20:04:44 -05:00
Calvin Rose
fb5b056f7b Address #1001 - don't process names passed to dlopen. 2022-07-19 20:04:17 -05:00
bakpakin
7248c1dfdb Give up if ln fail. 2022-07-09 19:10:25 -05:00
bakpakin
4c7ea9e893 Merge branch 'master' of github.com:janet-lang/janet 2022-07-09 11:44:20 -05:00
bakpakin
c7801ce277 Address #997 - clang undefined behavior warning. 2022-07-09 11:43:51 -05:00
Calvin Rose
f741a8e3ff Merge pull request #998 from autumnull/master
stop doc-format detecting other modes within code blocks
2022-07-09 11:40:51 -05:00
bakpakin
6a92e8b609 Update CHANGELOG and make tweaks to win32 shell 2022-07-09 11:39:06 -05:00
bakpakin
9da91a8217 Update shell.c to have smart behavior on windows. 2022-07-09 11:23:02 -05:00
bakpakin
69853c8e5c Merge branch 'master' of github.com:janet-lang/janet 2022-07-08 09:49:56 -05:00
Autumn!
1f41b6c138 doc-format no longer detects other modes within code blocks 2022-07-07 14:41:46 +01:00
Calvin Rose
e001efa9fd Fix #996 - linking command works on busybox. 2022-07-04 16:48:07 -05:00
Calvin Rose
435e64d4cf Allow shorthand for setting task-id on new threads with flag.
Avoids the need to wrap function bodies in closures in many cases.
2022-07-03 12:08:21 -05:00
Calvin Rose
f296c8f5fb Merge branch 'master' of github.com:janet-lang/janet 2022-07-02 21:11:55 -05:00
Calvin Rose
8d0e6ed32f Fix function handlers for :out and :err.
They were not properly handled for formatting functions.
2022-07-02 21:11:05 -05:00
Calvin Rose
b6a36afffe Merge pull request #994 from shassard/master
Use relative path for include/janet.h symlink
2022-07-02 12:30:39 -05:00
Stephen Hassard
e422abc269 Use relative path for include/janet.h symlink
When using make to build an rpm, the current symlink is
created with an absolute path to the buildroot as causes
the make install target to fail with:

error: Symlink points to BuildRoot: /usr/include/janet.h -> /home/stephen/rpmbuild/BUILDROOT/janet-1.23.0-3.x86_64/usr/include/janet/janet.h

We can create the link relatively which makes this more
portable, where:

ln -sf -t '/home/stephen/rpmbuild/BUILDROOT/janet-1.23.0-3.x86_64/usr/include' janet.h janet/janet.h

Resulting in the following symlink:

ls -la BUILDROOT/usr/include/janet.h
lrwxrwxrwx. 1 stephen stephen 13 Jul  2 08:17 BUILDROOT/usr/include/janet.h -> janet/janet.h

This symlink can then be properly packaged without path
issues.

Signed-off-by: Stephen Hassard <steve@hassard.net>
2022-07-02 08:52:17 -07:00
Calvin Rose
221d71d07b Merge pull request #993 from pepe/test-tabseq
Add basic test for tabseq
2022-07-02 09:30:59 -05:00
Calvin Rose
9f35f0837e Merge pull request #991 from pepe/master
Trace function to the stderr
2022-07-02 09:29:18 -05:00
Josef Pospíšil
515891b035 Add basic test for tabseq 2022-07-02 07:43:28 +02:00
Josef Pospíšil
94a506876f Trace function to the stderr 2022-07-01 12:23:25 +02:00
Calvin Rose
9bde57854a Add tabseq macro. 2022-06-28 22:51:41 -05:00
Calvin Rose
f456369941 Add support for a dyn :task-id
Adds extra information to default information from supervisor
channels. For threaded channels as supervisors, we don't get
the source fiber so identifying the source of messages was not
possible. This change allows better multithreading with  supervisors.
2022-06-25 18:51:21 -05:00
bakpakin
e0b7533c39 Add toggle macro. 2022-05-12 15:36:29 -05:00
18 changed files with 344 additions and 127 deletions

View File

@@ -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: |

View File

@@ -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.

View File

@@ -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

View File

@@ -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')

View File

@@ -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))

View File

@@ -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" */

View File

@@ -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)) {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");

View File

@@ -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)))

View File

@@ -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);

View File

@@ -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));
} }

View File

@@ -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);

View File

@@ -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)

View File

@@ -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
View 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
View File