mirror of
https://github.com/janet-lang/janet
synced 2025-11-09 03:53:06 +00:00
Compare commits
38 Commits
circleci-p
...
sortkeys
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa163093d2 | ||
|
|
e70f64e23d | ||
|
|
6f605f8141 | ||
|
|
d9419ef994 | ||
|
|
7e8639a682 | ||
|
|
452b303b4c | ||
|
|
b0f1a4967d | ||
|
|
9eb4c59c04 | ||
|
|
0d42506cde | ||
|
|
c8a13ce475 | ||
|
|
05e3467d09 | ||
|
|
90639e5068 | ||
|
|
73c7711c78 | ||
|
|
78f6b6a507 | ||
|
|
84f0ab5356 | ||
|
|
546437d799 | ||
|
|
0f05aec563 | ||
|
|
c9097623d6 | ||
|
|
6392b37c47 | ||
|
|
4fcc8075d4 | ||
|
|
b2d6a55335 | ||
|
|
1fea5f8fe7 | ||
|
|
d3e52a2afb | ||
|
|
d6ea1989cc | ||
|
|
96513665d6 | ||
|
|
b795d13f61 | ||
|
|
970f9b3981 | ||
|
|
be7dab4d17 | ||
|
|
0e44ce5cba | ||
|
|
1f8c2781dd | ||
|
|
f381a9c773 | ||
|
|
855a9a01fc | ||
|
|
a5f237993d | ||
|
|
c68264802a | ||
|
|
742469a8bc | ||
|
|
92928d5c4f | ||
|
|
8320e25d64 | ||
|
|
c16a9d8463 |
@@ -1,14 +0,0 @@
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
# for later
|
||||
windows: circleci/windows@2.2.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
macos:
|
||||
xcode: 11.3.0
|
||||
steps:
|
||||
- checkout
|
||||
- run: make
|
||||
- run: make test
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,6 +1,18 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## Unreleased - ???
|
||||
- Increase default nesting depth of pretty printing to `JANET_RECURSION_GUARD`
|
||||
- Update meson.build
|
||||
- Add option to automatically add shebang line in installed scripts with `jpm`.
|
||||
- Add `partition-by` and `group-by` to the core.
|
||||
- Sort keys in pretty printing output.
|
||||
|
||||
## 1.15.3 - 2021-02-28
|
||||
- Fix a fiber bug that occured in deeply nested fibers
|
||||
- Add `unref` combinator to pegs.
|
||||
- Small docstring changes.
|
||||
|
||||
## 1.15.2 - 2021-02-15
|
||||
- Fix bug in windows version of `os/spawn` and `os/execute` with setting environment variables.
|
||||
- Fix documentation typos.
|
||||
|
||||
2
Makefile
2
Makefile
@@ -27,7 +27,7 @@ PREFIX?=/usr/local
|
||||
INCLUDEDIR?=$(PREFIX)/include
|
||||
BINDIR?=$(PREFIX)/bin
|
||||
LIBDIR?=$(PREFIX)/lib
|
||||
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 2> /dev/null || echo local)\""
|
||||
JANET_BUILD?="\"$(shell git log --pretty=format:'%h' -n 1 2> /dev/null || echo local)\""
|
||||
CLIBS=-lm -lpthread
|
||||
JANET_TARGET=build/janet
|
||||
JANET_LIBRARY=build/libjanet.so
|
||||
|
||||
71
jpm
71
jpm
@@ -23,12 +23,12 @@
|
||||
|
||||
# Overriden on some installs.
|
||||
# To configure this script, replace the code between
|
||||
# the START and END comments and define a function
|
||||
# the START and END comments and define a function
|
||||
# (install-paths) that gives the the default paths
|
||||
# to use. Trailing directory separator not expected.
|
||||
#
|
||||
# Example.
|
||||
#
|
||||
#
|
||||
# (defn- install-paths []
|
||||
# {:headerpath "/usr/local/include/janet"
|
||||
# :libpath "/usr/local/lib/janet"
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
(defn- try-real [path]
|
||||
"If os/realpath fails just use normal path."
|
||||
(try (os/realpath) ([_] path)))
|
||||
(try (os/realpath path) ([_] path)))
|
||||
|
||||
(defn- install-paths []
|
||||
{:headerpath (try-real (string exe-dir "/../include/janet"))
|
||||
@@ -169,9 +169,7 @@
|
||||
[& args]
|
||||
(if (dyn :verbose)
|
||||
(print ;(interpose " " args)))
|
||||
(def res (os/execute args :p))
|
||||
(unless (zero? res)
|
||||
(error (string "command exited with status " res))))
|
||||
(os/execute args :px))
|
||||
|
||||
(defn copy
|
||||
"Copy a file or directory recursively from one location to another."
|
||||
@@ -1082,12 +1080,15 @@ int main(int argc, const char **argv) {
|
||||
(install-rule dest (dyn :binpath JANET_BINPATH))))))
|
||||
|
||||
(defn declare-binscript
|
||||
"Declare a janet file to be installed as an executable script. Creates
|
||||
``Declare a janet file to be installed as an executable script. Creates
|
||||
a shim on windows. If hardcode is true, will insert code into the script
|
||||
such that it will run correctly even when JANET_PATH is changed."
|
||||
[&keys {:main main :hardcode-syspath hardcode}]
|
||||
such that it will run correctly even when JANET_PATH is changed. if auto-shebang
|
||||
is truthy, will also automatically insert a correct shebang line.
|
||||
``
|
||||
[&keys {:main main :hardcode-syspath hardcode :is-janet is-janet}]
|
||||
(def binpath (dyn :binpath JANET_BINPATH))
|
||||
(if hardcode
|
||||
(def auto-shebang (and is-janet (dyn :auto-shebang)))
|
||||
(if (or auto-shebang hardcode)
|
||||
(let [syspath (dyn :modpath JANET_MODPATH)]
|
||||
(def parts (peg/match path-splitter main))
|
||||
(def name (last parts))
|
||||
@@ -1099,7 +1100,9 @@ int main(int argc, const char **argv) {
|
||||
(def first-line (:read f :line))
|
||||
(def second-line (string/format "(put root-env :syspath %v)\n" syspath))
|
||||
(def rest (:read f :all))
|
||||
(string first-line second-line rest)))
|
||||
(string (if auto-shebang
|
||||
(string "#!" (dyn :binpath JANET_BINPATH) "/janet\n"))
|
||||
first-line (if hardcode second-line) rest)))
|
||||
(create-dirs path)
|
||||
(spit path contents)
|
||||
(unless is-win (shell "chmod" "+x" path))))
|
||||
@@ -1424,26 +1427,30 @@ Flags are:
|
||||
"load-lockfile" load-lockfile
|
||||
"quickbin" quickbin})
|
||||
|
||||
(def- args (tuple/slice (dyn :args) 1))
|
||||
(def- len (length args))
|
||||
(var i :private 0)
|
||||
(defn- main
|
||||
"Script entry."
|
||||
[& argv]
|
||||
|
||||
# Get flags
|
||||
(while (< i len)
|
||||
(if-let [m (peg/match argpeg (args i))]
|
||||
(if (= 2 (length m))
|
||||
(let [[key value] m]
|
||||
(setdyn (keyword key) value))
|
||||
(setdyn (keyword (m 0)) true))
|
||||
(break))
|
||||
(++ i))
|
||||
(def- args (tuple/slice argv 1))
|
||||
(def- len (length args))
|
||||
(var i :private 0)
|
||||
|
||||
# Run subcommand
|
||||
(if (= i len)
|
||||
(help)
|
||||
(do
|
||||
(if-let [com (subcommands (args i))]
|
||||
(com ;(tuple/slice args (+ i 1)))
|
||||
(do
|
||||
(print "invalid command " (args i))
|
||||
(help)))))
|
||||
# Get flags
|
||||
(while (< i len)
|
||||
(if-let [m (peg/match argpeg (args i))]
|
||||
(if (= 2 (length m))
|
||||
(let [[key value] m]
|
||||
(setdyn (keyword key) value))
|
||||
(setdyn (keyword (m 0)) true))
|
||||
(break))
|
||||
(++ i))
|
||||
|
||||
# Run subcommand
|
||||
(if (= i len)
|
||||
(help)
|
||||
(do
|
||||
(if-let [com (subcommands (args i))]
|
||||
(com ;(tuple/slice args (+ i 1)))
|
||||
(do
|
||||
(print "invalid command " (args i))
|
||||
(help))))))
|
||||
|
||||
4
jpm.1
4
jpm.1
@@ -42,6 +42,10 @@ Prevents jpm from going to network to get dependencies - all dependencies should
|
||||
Use this flag with the deps and update-pkgs subcommands. This is not a surefire way to prevent a build script from accessing
|
||||
the network, for example, a build script that invokes curl will still have network access.
|
||||
|
||||
.TP
|
||||
.BR \-\-auto\-shebang
|
||||
Prepends installed scripts with a generated shebang line, such that they will use a janet binary located in JANET_BINPATH.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
project('janet', 'c',
|
||||
default_options : ['c_std=c99', 'b_lundef=false', 'default_library=both'],
|
||||
version : '1.15.2')
|
||||
default_options : ['c_std=c99', 'build.c_std=c99', 'b_lundef=false', 'default_library=both'],
|
||||
version : '1.15.3')
|
||||
|
||||
# Global settings
|
||||
janet_path = join_paths(get_option('prefix'), get_option('libdir'), 'janet')
|
||||
@@ -33,7 +33,7 @@ dl_dep = cc.find_library('dl', required : false)
|
||||
thread_dep = dependency('threads')
|
||||
|
||||
# Link options
|
||||
if build_machine.system() != 'windows'
|
||||
if get_option('default_library') != 'static' and build_machine.system() != 'windows'
|
||||
add_project_link_arguments('-rdynamic', language : 'c')
|
||||
endif
|
||||
|
||||
@@ -244,6 +244,7 @@ janet_dep = declare_dependency(include_directories : incdir,
|
||||
# pkgconfig
|
||||
pkg = import('pkgconfig')
|
||||
pkg.generate(libjanet,
|
||||
subdirs: 'janet',
|
||||
description: 'Library for the Janet programming language.')
|
||||
|
||||
# Installation
|
||||
|
||||
@@ -277,7 +277,7 @@
|
||||
[& forms]
|
||||
(def len (length forms))
|
||||
(var i (- len 1))
|
||||
(var ret (in forms i))
|
||||
(var ret (get forms i))
|
||||
(while (> i 0)
|
||||
(-- i)
|
||||
(def fi (in forms i))
|
||||
@@ -778,24 +778,28 @@
|
||||
a)
|
||||
|
||||
(defn sort
|
||||
"Sort an array in-place. Uses quick-sort and is not a stable sort."
|
||||
[a &opt before?]
|
||||
(sort-help a 0 (- (length a) 1) (or before? <)))
|
||||
``Sort `ind` in-place, and return it. Uses quick-sort and is not a stable sort.
|
||||
If a `before?` comparator function is provided, sorts elements using that,
|
||||
otherwise uses `<`.``
|
||||
[ind &opt before?]
|
||||
(sort-help ind 0 (- (length ind) 1) (or before? <)))
|
||||
|
||||
(defn sort-by
|
||||
``Returns `ind` sorted by calling
|
||||
a function `f` on each element and comparing the result with <.``
|
||||
a function `f` on each element and comparing the result with `<`.``
|
||||
[f ind]
|
||||
(sort ind (fn [x y] (< (f x) (f y)))))
|
||||
|
||||
(defn sorted
|
||||
"Returns a new sorted array without modifying the old one."
|
||||
``Returns a new sorted array without modifying the old one.
|
||||
If a `before?` comparator function is provided, sorts elements using that,
|
||||
otherwise uses `<`.``
|
||||
[ind &opt before?]
|
||||
(sort (array/slice ind) before?))
|
||||
|
||||
(defn sorted-by
|
||||
``Returns a new sorted array that compares elements by invoking
|
||||
a function `f` on each element and comparing the result with <.``
|
||||
a function `f` on each element and comparing the result with `<`.``
|
||||
[f ind]
|
||||
(sorted ind (fn [x y] (< (f x) (f y)))))
|
||||
|
||||
@@ -1447,6 +1451,36 @@
|
||||
(set (freqs x) (if n (+ 1 n) 1)))
|
||||
freqs)
|
||||
|
||||
(defn group-by
|
||||
``Group elements of `ind` by a function `f` and put the results into a table. The keys of
|
||||
the table are the distinct return values of `f`, and the values are arrays of all elements of `ind`
|
||||
that are equal to that value.``
|
||||
[f ind]
|
||||
(def ret @{})
|
||||
(each x ind
|
||||
(def y (f x))
|
||||
(if-let [arr (get ret y)]
|
||||
(array/push arr x)
|
||||
(put ret y @[x])))
|
||||
ret)
|
||||
|
||||
(defn partition-by
|
||||
``Partition elements of a sequential data structure by a representative function `f`. Partitions
|
||||
split when `(f x)` changes values when iterating to the next element `x` of `ind`. Returns a new array
|
||||
of arrays.``
|
||||
[f ind]
|
||||
(def ret @[])
|
||||
(var span nil)
|
||||
(var category nil)
|
||||
(var is-new true)
|
||||
(each x ind
|
||||
(def y (f x))
|
||||
(cond
|
||||
is-new (do (set is-new false) (set category y) (set span @[x]) (array/push ret span))
|
||||
(= y category) (array/push span x)
|
||||
(do (set category y) (set span @[x]) (array/push ret span))))
|
||||
ret)
|
||||
|
||||
(defn interleave
|
||||
"Returns an array of the first elements of each col, then the second, etc."
|
||||
[& cols]
|
||||
@@ -2098,7 +2132,7 @@
|
||||
:on-parse-error on-parse-error
|
||||
:fiber-flags guard
|
||||
:evaluator evaluator
|
||||
:source where
|
||||
:source default-where
|
||||
:parser parser
|
||||
:read read
|
||||
:expander expand} opts)
|
||||
@@ -2108,9 +2142,11 @@
|
||||
(default on-compile-error bad-compile)
|
||||
(default on-parse-error bad-parse)
|
||||
(default evaluator (fn evaluate [x &] (x)))
|
||||
(default where "<anonymous>")
|
||||
(default default-where "<anonymous>")
|
||||
(default guard :ydt)
|
||||
|
||||
(var where default-where)
|
||||
|
||||
# Evaluate 1 source form in a protected manner
|
||||
(defn eval1 [source &opt l c]
|
||||
(def source (if expand (expand source) source))
|
||||
@@ -2163,11 +2199,18 @@
|
||||
(while parser-not-done
|
||||
(if (env :exit) (break))
|
||||
(buffer/clear buf)
|
||||
(if (= (chunks buf p) :cancel)
|
||||
(match (chunks buf p)
|
||||
:cancel
|
||||
(do
|
||||
# A :cancel chunk represents a cancelled form in the REPL, so reset.
|
||||
(:flush p)
|
||||
(buffer/clear buf))
|
||||
|
||||
[:source new-where]
|
||||
(if (string? new-where)
|
||||
(set where new-where)
|
||||
(set where default-where))
|
||||
|
||||
(do
|
||||
(var pindex 0)
|
||||
(var pstatus nil)
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
#define JANET_VERSION_MAJOR 1
|
||||
#define JANET_VERSION_MINOR 15
|
||||
#define JANET_VERSION_PATCH 2
|
||||
#define JANET_VERSION_PATCH 3
|
||||
#define JANET_VERSION_EXTRA ""
|
||||
#define JANET_VERSION "1.15.2"
|
||||
#define JANET_VERSION "1.15.3"
|
||||
|
||||
/* #define JANET_BUILD "local" */
|
||||
|
||||
|
||||
@@ -2085,7 +2085,7 @@ static const JanetReg os_cfuns[] = {
|
||||
#ifndef JANET_NO_PROCESSES
|
||||
{
|
||||
"os/execute", os_execute,
|
||||
JDOC("(os/execute args &opts flags env)\n\n"
|
||||
JDOC("(os/execute args &opt flags env)\n\n"
|
||||
"Execute a program on the system and pass it string arguments. `flags` "
|
||||
"is a keyword that modifies how the program will execute.\n\n"
|
||||
"* :e - enables passing an environment to the program. Without :e, the "
|
||||
@@ -2105,7 +2105,7 @@ static const JanetReg os_cfuns[] = {
|
||||
},
|
||||
{
|
||||
"os/spawn", os_spawn,
|
||||
JDOC("(os/spawn args &opts flags env)\n\n"
|
||||
JDOC("(os/spawn args &opt 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.")
|
||||
},
|
||||
|
||||
@@ -286,7 +286,7 @@ tail:
|
||||
const uint8_t *next_text;
|
||||
CapState cs = cap_save(s);
|
||||
down1(s);
|
||||
while (text < s->text_end) {
|
||||
while (text <= s->text_end) {
|
||||
CapState cs2 = cap_save(s);
|
||||
next_text = peg_rule(s, rule_a, text);
|
||||
if (next_text) {
|
||||
@@ -296,7 +296,7 @@ tail:
|
||||
text++;
|
||||
}
|
||||
up1(s);
|
||||
if (text >= s->text_end) {
|
||||
if (text > s->text_end) {
|
||||
cap_load(s, cs);
|
||||
return NULL;
|
||||
}
|
||||
@@ -596,6 +596,30 @@ tail:
|
||||
return text + width;
|
||||
}
|
||||
|
||||
case RULE_UNREF: {
|
||||
int32_t tcap = s->tags->count;
|
||||
down1(s);
|
||||
const uint8_t *result = peg_rule(s, s->bytecode + rule[1], text);
|
||||
up1(s);
|
||||
if (!result) return NULL;
|
||||
int32_t final_tcap = s->tags->count;
|
||||
/* Truncate tagged captures to not include items of the given tag */
|
||||
int32_t w = tcap;
|
||||
/* If no tag is given, drop ALL tagged captures */
|
||||
if (rule[2]) {
|
||||
for (int32_t i = tcap; i < final_tcap; i++) {
|
||||
if (s->tags->data[i] != (0xFF & rule[2])) {
|
||||
s->tags->data[w] = s->tags->data[i];
|
||||
s->tagged_captures->data[w] = s->tagged_captures->data[i];
|
||||
w++;
|
||||
}
|
||||
}
|
||||
}
|
||||
s->tags->count = w;
|
||||
s->tagged_captures->count = w;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,15 +943,15 @@ static void spec_error(Builder *b, int32_t argc, const Janet *argv) {
|
||||
spec_onerule(b, argc, argv, RULE_ERROR);
|
||||
}
|
||||
}
|
||||
static void spec_drop(Builder *b, int32_t argc, const Janet *argv) {
|
||||
spec_onerule(b, argc, argv, RULE_DROP);
|
||||
}
|
||||
static void spec_to(Builder *b, int32_t argc, const Janet *argv) {
|
||||
spec_onerule(b, argc, argv, RULE_TO);
|
||||
}
|
||||
static void spec_thru(Builder *b, int32_t argc, const Janet *argv) {
|
||||
spec_onerule(b, argc, argv, RULE_THRU);
|
||||
}
|
||||
static void spec_drop(Builder *b, int32_t argc, const Janet *argv) {
|
||||
spec_onerule(b, argc, argv, RULE_DROP);
|
||||
}
|
||||
|
||||
/* Rule of the form [rule, tag] */
|
||||
static void spec_cap1(Builder *b, int32_t argc, const Janet *argv, uint32_t op) {
|
||||
@@ -947,6 +971,9 @@ static void spec_accumulate(Builder *b, int32_t argc, const Janet *argv) {
|
||||
static void spec_group(Builder *b, int32_t argc, const Janet *argv) {
|
||||
spec_cap1(b, argc, argv, RULE_GROUP);
|
||||
}
|
||||
static void spec_unref(Builder *b, int32_t argc, const Janet *argv) {
|
||||
spec_cap1(b, argc, argv, RULE_UNREF);
|
||||
}
|
||||
|
||||
static void spec_reference(Builder *b, int32_t argc, const Janet *argv) {
|
||||
peg_arity(b, argc, 1, 2);
|
||||
@@ -1104,6 +1131,7 @@ static const SpecialPair peg_specials[] = {
|
||||
{"to", spec_to},
|
||||
{"uint", spec_uint_le},
|
||||
{"uint-be", spec_uint_be},
|
||||
{"unref", spec_unref},
|
||||
};
|
||||
|
||||
/* Compile a janet value into a rule and return the rule index. */
|
||||
@@ -1392,6 +1420,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
|
||||
case RULE_ACCUMULATE:
|
||||
case RULE_GROUP:
|
||||
case RULE_CAPTURE:
|
||||
case RULE_UNREF:
|
||||
/* [rule, tag] */
|
||||
if (rule[1] >= blen) goto bad;
|
||||
op_flags[rule[1]] |= 0x01;
|
||||
|
||||
@@ -351,6 +351,9 @@ struct pretty {
|
||||
int indent;
|
||||
int flags;
|
||||
int32_t bufstartlen;
|
||||
int32_t *keysort_buffer;
|
||||
int32_t keysort_capacity;
|
||||
int32_t keysort_start;
|
||||
JanetTable seen;
|
||||
};
|
||||
|
||||
@@ -594,31 +597,55 @@ static void janet_pretty_one(struct pretty *S, Janet x, int is_dict_value) {
|
||||
janet_buffer_push_cstring(S->buffer, "...");
|
||||
} else {
|
||||
int32_t i = 0, len = 0, cap = 0;
|
||||
int first_kv_pair = 1;
|
||||
const JanetKV *kvs = NULL;
|
||||
int counter = 0;
|
||||
janet_dictionary_view(x, &kvs, &len, &cap);
|
||||
if (!istable && !(S->flags & JANET_PRETTY_ONELINE) && len >= JANET_PRETTY_DICT_ONELINE)
|
||||
janet_buffer_push_u8(S->buffer, ' ');
|
||||
if (is_dict_value && len >= JANET_PRETTY_DICT_ONELINE) print_newline(S, 0);
|
||||
for (i = 0; i < cap; i++) {
|
||||
if (!janet_checktype(kvs[i].key, JANET_NIL)) {
|
||||
if (counter == JANET_PRETTY_DICT_LIMIT && !(S->flags & JANET_PRETTY_NOTRUNC)) {
|
||||
print_newline(S, 0);
|
||||
janet_buffer_push_cstring(S->buffer, "...");
|
||||
break;
|
||||
}
|
||||
if (first_kv_pair) {
|
||||
first_kv_pair = 0;
|
||||
} else {
|
||||
print_newline(S, len < JANET_PRETTY_DICT_ONELINE);
|
||||
}
|
||||
janet_pretty_one(S, kvs[i].key, 0);
|
||||
janet_buffer_push_u8(S->buffer, ' ');
|
||||
janet_pretty_one(S, kvs[i].value, 1);
|
||||
counter++;
|
||||
int32_t ks_start = S->keysort_start;
|
||||
|
||||
/* Ensure buffer is large enough to sort keys. */
|
||||
int truncated = 0;
|
||||
int64_t mincap = (int64_t) len + (int64_t) ks_start;
|
||||
if (mincap > INT32_MAX) {
|
||||
truncated = 1;
|
||||
len = 0;
|
||||
mincap = ks_start;
|
||||
}
|
||||
|
||||
if (S->keysort_capacity < mincap) {
|
||||
if (mincap >= INT32_MAX / 2) {
|
||||
S->keysort_capacity = INT32_MAX;
|
||||
} else {
|
||||
S->keysort_capacity = mincap * 2;
|
||||
}
|
||||
S->keysort_buffer = janet_srealloc(S->keysort_buffer, sizeof(int32_t) * S->keysort_capacity);
|
||||
if (NULL == S->keysort_buffer) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
janet_sorted_keys(kvs, cap, S->keysort_buffer + ks_start);
|
||||
S->keysort_start += len;
|
||||
if (!(S->flags & JANET_PRETTY_NOTRUNC) && (len > JANET_PRETTY_DICT_LIMIT)) {
|
||||
len = JANET_PRETTY_DICT_LIMIT;
|
||||
truncated = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i) print_newline(S, len < JANET_PRETTY_DICT_ONELINE);
|
||||
int32_t j = S->keysort_buffer[i + ks_start];
|
||||
janet_pretty_one(S, kvs[j].key, 0);
|
||||
janet_buffer_push_u8(S->buffer, ' ');
|
||||
janet_pretty_one(S, kvs[j].value, 1);
|
||||
}
|
||||
|
||||
if (truncated) {
|
||||
print_newline(S, 0);
|
||||
janet_buffer_push_cstring(S->buffer, "...");
|
||||
}
|
||||
|
||||
S->keysort_start = ks_start;
|
||||
}
|
||||
S->indent -= 2;
|
||||
S->depth++;
|
||||
@@ -641,6 +668,9 @@ static JanetBuffer *janet_pretty_(JanetBuffer *buffer, int depth, int flags, Jan
|
||||
S.indent = 0;
|
||||
S.flags = flags;
|
||||
S.bufstartlen = startlen;
|
||||
S.keysort_capacity = 0;
|
||||
S.keysort_buffer = NULL;
|
||||
S.keysort_start = 0;
|
||||
janet_table_init(&S.seen, 10);
|
||||
janet_pretty_one(&S, x, 0);
|
||||
janet_table_deinit(&S.seen);
|
||||
@@ -663,6 +693,9 @@ static JanetBuffer *janet_jdn_(JanetBuffer *buffer, int depth, Janet x, int32_t
|
||||
S.indent = 0;
|
||||
S.flags = 0;
|
||||
S.bufstartlen = startlen;
|
||||
S.keysort_capacity = 0;
|
||||
S.keysort_buffer = NULL;
|
||||
S.keysort_start = 0;
|
||||
janet_table_init(&S.seen, 10);
|
||||
int res = print_jdn_one(&S, x, depth);
|
||||
janet_table_deinit(&S.seen);
|
||||
@@ -822,7 +855,7 @@ void janet_formatbv(JanetBuffer *b, const char *format, va_list args) {
|
||||
case 'P':
|
||||
case 'p': { /* janet pretty , precision = depth */
|
||||
int depth = atoi(precision);
|
||||
if (depth < 1) depth = 4;
|
||||
if (depth < 1) depth = JANET_RECURSION_GUARD;
|
||||
char d = c[-1];
|
||||
int has_color = (d == 'P') || (d == 'Q') || (d == 'M') || (d == 'N');
|
||||
int has_oneline = (d == 'Q') || (d == 'q') || (d == 'N') || (d == 'n');
|
||||
@@ -974,7 +1007,7 @@ void janet_buffer_format(
|
||||
case 'P':
|
||||
case 'p': { /* janet pretty , precision = depth */
|
||||
int depth = atoi(precision);
|
||||
if (depth < 1) depth = 4;
|
||||
if (depth < 1) depth = JANET_RECURSION_GUARD;
|
||||
char d = strfrmt[-1];
|
||||
int has_color = (d == 'P') || (d == 'Q') || (d == 'M') || (d == 'N');
|
||||
int has_oneline = (d == 'Q') || (d == 'q') || (d == 'N') || (d == 'n');
|
||||
|
||||
@@ -602,6 +602,38 @@ JanetTable *janet_get_core_table(const char *name) {
|
||||
return janet_unwrap_table(out);
|
||||
}
|
||||
|
||||
/* Sort keys of a dictionary type */
|
||||
int32_t janet_sorted_keys(const JanetKV *dict, int32_t cap, int32_t *index_buffer) {
|
||||
|
||||
/* First, put populated indices into index_buffer */
|
||||
int32_t next_index = 0;
|
||||
for (int32_t i = 0; i < cap; i++) {
|
||||
if (!janet_checktype(dict[i].key, JANET_NIL)) {
|
||||
index_buffer[next_index++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next, sort those (simple insertion sort here for now) */
|
||||
for (int32_t i = 1; i < next_index; i++) {
|
||||
int32_t index_to_insert = index_buffer[i];
|
||||
Janet lhs = dict[index_to_insert].key;
|
||||
for (int32_t j = i - 1; j >= 0; j--) {
|
||||
index_buffer[j + 1] = index_buffer[j];
|
||||
Janet rhs = dict[index_buffer[j]].key;
|
||||
if (janet_compare(lhs, rhs) >= 0) {
|
||||
index_buffer[j + 1] = index_to_insert;
|
||||
break;
|
||||
} else if (j == 0) {
|
||||
index_buffer[0] = index_to_insert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return number of indices found */
|
||||
return next_index;
|
||||
|
||||
}
|
||||
|
||||
/* Clock shims for various platforms */
|
||||
#ifdef JANET_GETTIME
|
||||
/* For macos */
|
||||
|
||||
@@ -1378,6 +1378,7 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
||||
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
|
||||
if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) {
|
||||
*out = in;
|
||||
janet_fiber_set_status(fiber, sig);
|
||||
return sig;
|
||||
}
|
||||
/* Check if we need any special handling for certain opcodes */
|
||||
@@ -1417,23 +1418,23 @@ static JanetSignal janet_continue_no_check(JanetFiber *fiber, Janet in, Janet *o
|
||||
|
||||
/* Save global state */
|
||||
JanetTryState tstate;
|
||||
JanetSignal signal = janet_try(&tstate);
|
||||
if (!signal) {
|
||||
JanetSignal sig = janet_try(&tstate);
|
||||
if (!sig) {
|
||||
/* Normal setup */
|
||||
if (janet_vm_root_fiber == NULL) janet_vm_root_fiber = fiber;
|
||||
janet_vm_fiber = fiber;
|
||||
janet_fiber_set_status(fiber, JANET_STATUS_ALIVE);
|
||||
signal = run_vm(fiber, in);
|
||||
sig = run_vm(fiber, in);
|
||||
}
|
||||
|
||||
/* Restore */
|
||||
if (janet_vm_root_fiber == fiber) janet_vm_root_fiber = NULL;
|
||||
janet_fiber_set_status(fiber, signal);
|
||||
janet_fiber_set_status(fiber, sig);
|
||||
janet_restore(&tstate);
|
||||
fiber->last_value = tstate.payload;
|
||||
*out = tstate.payload;
|
||||
|
||||
return signal;
|
||||
return sig;
|
||||
}
|
||||
|
||||
/* Enter the main vm loop */
|
||||
|
||||
@@ -1630,6 +1630,7 @@ JANET_API Janet janet_wrap_number_safe(double x);
|
||||
JANET_API int janet_keyeq(Janet x, const char *cstring);
|
||||
JANET_API int janet_streq(Janet x, const char *cstring);
|
||||
JANET_API int janet_symeq(Janet x, const char *cstring);
|
||||
JANET_API int32_t janet_sorted_keys(const JanetKV *dict, int32_t cap, int32_t *index_buffer);
|
||||
|
||||
/* VM functions */
|
||||
JANET_API int janet_init(void);
|
||||
@@ -1841,7 +1842,8 @@ typedef enum {
|
||||
RULE_LENPREFIX, /* [rule_a, rule_b (repeat rule_b rule_a times)] */
|
||||
RULE_READINT, /* [(signedness << 4) | (endianess << 5) | bytewidth, tag] */
|
||||
RULE_LINE, /* [tag] */
|
||||
RULE_COLUMN /* [tag] */
|
||||
RULE_COLUMN, /* [tag] */
|
||||
RULE_UNREF /* [rule, tag] */
|
||||
} JanetPegOpcod;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -294,4 +294,25 @@
|
||||
(sort (mapcat (fn [[x y z]] [z y x]) (partition 3 (range 99))))) "sort 5")
|
||||
(assert (<= ;(sort (map (fn [x] (math/random)) (range 1000)))) "sort 6")
|
||||
|
||||
# And and or
|
||||
|
||||
(assert (= (and true true) true) "and true true")
|
||||
(assert (= (and true false) false) "and true false")
|
||||
(assert (= (and false true) false) "and false true")
|
||||
(assert (= (and true true true) true) "and true true true")
|
||||
(assert (= (and 0 1 2) 2) "and 0 1 2")
|
||||
(assert (= (and 0 1 nil) nil) "and 0 1 nil")
|
||||
(assert (= (and 1) 1) "and 1")
|
||||
(assert (= (and) true) "and with no arguments")
|
||||
|
||||
(assert (= (or true true) true) "or true true")
|
||||
(assert (= (or true false) true) "or true false")
|
||||
(assert (= (or false true) true) "or false true")
|
||||
(assert (= (or false false) false) "or false true")
|
||||
(assert (= (or true true false) true) "or true true false")
|
||||
(assert (= (or 0 1 2) 0) "or 0 1 2")
|
||||
(assert (= (or nil 1 2) 1) "or nil 1 2")
|
||||
(assert (= (or 1) 1) "or 1")
|
||||
(assert (= (or) nil) "or with no arguments")
|
||||
|
||||
(end-suite)
|
||||
|
||||
@@ -473,4 +473,24 @@
|
||||
|
||||
(check-deep '(* (int 2) -1) "123" nil)
|
||||
|
||||
# to/thru bug
|
||||
(check-deep '(to -1) "aaaa" @[])
|
||||
(check-deep '(thru -1) "aaaa" @[])
|
||||
(check-deep ''(to -1) "aaaa" @["aaaa"])
|
||||
(check-deep ''(thru -1) "aaaa" @["aaaa"])
|
||||
(check-deep '(to "b") "aaaa" nil)
|
||||
(check-deep '(thru "b") "aaaa" nil)
|
||||
|
||||
# unref
|
||||
(def grammar
|
||||
(peg/compile
|
||||
~{:main (* :tagged -1)
|
||||
:tagged (unref (replace (* :open-tag :value :close-tag) ,struct))
|
||||
:open-tag (* (constant :tag) "<" (capture :w+ :tag-name) ">")
|
||||
:value (* (constant :value) (group (any (+ :tagged :untagged))))
|
||||
:close-tag (* "</" (backmatch :tag-name) ">")
|
||||
:untagged (capture (any (if-not "<" 1)))}))
|
||||
(check-deep grammar "<p><em>foobar</em></p>" @[{:tag "p" :value @[{:tag "em" :value @["foobar"]}]}])
|
||||
(check-deep grammar "<p>foobar</p>" @[{:tag "p" :value @["foobar"]}])
|
||||
|
||||
(end-suite)
|
||||
|
||||
@@ -146,4 +146,19 @@
|
||||
# os/execute with environment variables
|
||||
(assert (= 0 (os/execute [(dyn :executable) "-e" "(+ 1 2 3)"] :pe {"HELLO" "WORLD"})) "os/execute with env")
|
||||
|
||||
# Regression #638
|
||||
(compwhen
|
||||
(dyn 'ev/go)
|
||||
(assert
|
||||
(= [true :caught]
|
||||
(protect
|
||||
(try
|
||||
(do
|
||||
(ev/sleep 0)
|
||||
(with-dyns []
|
||||
(ev/sleep 0)
|
||||
(error "oops")))
|
||||
([err] :caught))))
|
||||
"regression #638"))
|
||||
|
||||
(end-suite)
|
||||
|
||||
Reference in New Issue
Block a user