mirror of
https://github.com/janet-lang/janet
synced 2024-12-29 18:00:26 +00:00
Merge branch 'master' into net
This commit is contained in:
commit
90b3730a0a
@ -1,12 +0,0 @@
|
||||
image: freebsd/latest
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
- gmake
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake
|
||||
gmake test
|
||||
sudo gmake install
|
||||
gmake test-install
|
@ -1,12 +0,0 @@
|
||||
image: openbsd/6.5
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
- gmake
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake
|
||||
gmake test
|
||||
doas gmake install
|
||||
gmake test-install
|
12
.builds/freebsd.yml
Normal file
12
.builds/freebsd.yml
Normal file
@ -0,0 +1,12 @@
|
||||
image: freebsd/12.x
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
- gmake
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake
|
||||
gmake test
|
||||
sudo gmake install
|
||||
gmake test-install
|
12
.builds/openbsd.yml
Normal file
12
.builds/openbsd.yml
Normal file
@ -0,0 +1,12 @@
|
||||
image: openbsd/latest
|
||||
sources:
|
||||
- https://git.sr.ht/~bakpakin/janet
|
||||
packages:
|
||||
- gmake
|
||||
tasks:
|
||||
- build: |
|
||||
cd janet
|
||||
gmake
|
||||
gmake test
|
||||
doas gmake install
|
||||
gmake test-install
|
@ -2,6 +2,11 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## Unreleased
|
||||
- Allow `_` in the `match` macro to match anything without creating a binding
|
||||
or doing unification.
|
||||
- Add `:range-to` and `:down-to` verbs in the `loop` macro.
|
||||
- Fix `and` and `or` macros returning nil instead of false in some cases.
|
||||
- Allow matching successfully against nil values in the `match` macro.
|
||||
- Improve `janet_formatc` and `janet_panicf` formatters to be more like `string/format`.
|
||||
This makes it easier to make nice error messages from C.
|
||||
- Add `signal`
|
||||
@ -12,6 +17,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Correct arity for `marshal`
|
||||
- Add `flush` and `eflush`
|
||||
- Add `prompt` and `return` on top of signal for user friendly delimited continuations.
|
||||
- Fix possible segfault with malformed pegs.
|
||||
|
||||
## 1.7.0 - 2020-02-01
|
||||
- Remove `file/fileno` and `file/fdopen`.
|
||||
|
49
README.md
49
README.md
@ -14,7 +14,7 @@ The language also supports bridging to native code written in C, meta-programmin
|
||||
|
||||
There is a repl for trying out the language, as well as the ability
|
||||
to run script files. This client program is separate from the core runtime, so
|
||||
janet could be embedded into other programs. Try janet in your browser at
|
||||
janet can be embedded into other programs. Try janet in your browser at
|
||||
[https://janet-lang.org](https://janet-lang.org).
|
||||
|
||||
<br>
|
||||
@ -61,7 +61,9 @@ documentation for symbols in the core library. For example,
|
||||
Shows documentation for the doc macro.
|
||||
|
||||
To get a list of all bindings in the default
|
||||
environment, use the `(all-bindings)` function.
|
||||
environment, use the `(all-bindings)` function. You
|
||||
can also use the `(doc)` macro with no arguments if you are in the repl
|
||||
to show bound symbols.
|
||||
|
||||
## Source
|
||||
|
||||
@ -122,7 +124,7 @@ is maybe more convenient and flexible for integrating into existing pipelines.
|
||||
Meson also provides much better IDE integration than Make or batch files, as well as support
|
||||
for cross compilation.
|
||||
|
||||
For the impatient, building with Meson is as simple as follows. The options provided to
|
||||
For the impatient, building with Meson is as follows. The options provided to
|
||||
`meson setup` below emulate Janet's Makefile.
|
||||
|
||||
```sh
|
||||
@ -152,7 +154,7 @@ Emacs, and Atom will have syntax packages for the Janet language, though.
|
||||
## Installation
|
||||
|
||||
See [the Introduction](https://janet-lang.org/introduction.html) for more details. If you just want
|
||||
to try out the language, you don't need to install anything. You can also simply move the `janet` executable wherever you want on your system and run it.
|
||||
to try out the language, you don't need to install anything. You can also move the `janet` executable wherever you want on your system and run it.
|
||||
|
||||
## Usage
|
||||
|
||||
@ -163,35 +165,38 @@ If you are looking to explore, you can print a list of all available macros, fun
|
||||
by entering the command `(all-bindings)` into the repl.
|
||||
|
||||
```
|
||||
$ ./janet
|
||||
Janet 0.0.0 alpha Copyright (C) 2017-2018 Calvin Rose
|
||||
$ janet
|
||||
Janet 1.7.1-dev-951e10f Copyright (C) 2017-2020 Calvin Rose
|
||||
janet:1:> (+ 1 2 3)
|
||||
6
|
||||
janet:2:> (print "Hello, World!")
|
||||
Hello, World!
|
||||
nil
|
||||
janet:3:> (os/exit)
|
||||
$ ./janet -h
|
||||
usage: ./janet [options] scripts...
|
||||
$ janet -h
|
||||
usage: build/janet [options] script args...
|
||||
Options are:
|
||||
-h Show this help
|
||||
-v Print the version string
|
||||
-s Use raw stdin instead of getline like functionality
|
||||
-e Execute a string of janet
|
||||
-r Enter the repl after running all scripts
|
||||
-p Keep on executing if there is a top level error (persistent)
|
||||
-- Stop handling option
|
||||
$
|
||||
-h : Show this help
|
||||
-v : Print the version string
|
||||
-s : Use raw stdin instead of getline like functionality
|
||||
-e code : Execute a string of janet
|
||||
-r : Enter the repl after running all scripts
|
||||
-p : Keep on executing if there is a top level error (persistent)
|
||||
-q : Hide prompt, logo, and repl output (quiet)
|
||||
-k : Compile scripts but do not execute (flycheck)
|
||||
-m syspath : Set system path for loading global modules
|
||||
-c source output : Compile janet source code into an image
|
||||
-n : Disable ANSI color output in the repl
|
||||
-l path : Execute code in a file before running the main script
|
||||
-- : Stop handling options
|
||||
```
|
||||
|
||||
If installed, you can also run `man janet` to get usage information.
|
||||
If installed, you can also run `man janet` and `man jpm` to get usage information.
|
||||
|
||||
## Embedding
|
||||
|
||||
The C API for Janet is not yet documented but coming soon.
|
||||
|
||||
Janet can be embedded in a host program very easily. There is a make target
|
||||
`make amalg` which creates the file `build/janet.c`, which is a single C file
|
||||
Janet can be embedded in a host program very easily. The normal build
|
||||
will create a file `build/janet.c`, which is a single C file
|
||||
that contains all the source to Janet. This file, along with
|
||||
`src/include/janet.h` and `src/include/janetconf.h` can dragged into any C
|
||||
project and compiled into the project. Janet should be compiled with `-std=c99`
|
||||
@ -200,6 +205,8 @@ the dynamic linker, `-ldl`, if one wants to be able to load dynamic modules. If
|
||||
there is no need for dynamic modules, add the define
|
||||
`-DJANET_NO_DYNAMIC_MODULES` to the compiler options.
|
||||
|
||||
See the [Embedding Section](https://janet-lang.org/capi/embedding.html) on the website for more information.
|
||||
|
||||
## Examples
|
||||
|
||||
See the examples directory for some example janet code.
|
||||
|
@ -244,26 +244,30 @@
|
||||
[(,not= :error (,fiber/status ,f)) ,r])))
|
||||
|
||||
(defmacro and
|
||||
"Evaluates to the last argument if all preceding elements are true, otherwise
|
||||
evaluates to false."
|
||||
"Evaluates to the last argument if all preceding elements are truthy, otherwise
|
||||
evaluates to the first falsey argument."
|
||||
[& forms]
|
||||
(var ret true)
|
||||
(def len (length forms))
|
||||
(var i len)
|
||||
(while (> i 0)
|
||||
(-- i)
|
||||
(def v (in forms i))
|
||||
(set ret (if (= ret true)
|
||||
(in forms i)
|
||||
(tuple 'if (in forms i) ret))))
|
||||
v
|
||||
(if (idempotent? v)
|
||||
['if v ret v]
|
||||
(do (def s (gensym))
|
||||
['if ['def s v] ret s])))))
|
||||
ret)
|
||||
|
||||
(defmacro or
|
||||
"Evaluates to the last argument if all preceding elements are false, otherwise
|
||||
evaluates to true."
|
||||
"Evaluates to the last argument if all preceding elements are falsey, otherwise
|
||||
evaluates to the first truthy element."
|
||||
[& forms]
|
||||
(var ret nil)
|
||||
(def len (length forms))
|
||||
(var i len)
|
||||
(var i (- len 1))
|
||||
(var ret (in forms i))
|
||||
(while (> i 0)
|
||||
(-- i)
|
||||
(def fi (in forms i))
|
||||
@ -362,6 +366,16 @@
|
||||
,;body
|
||||
(set ,i (,delta ,i ,step))))))
|
||||
|
||||
(defn- check-indexed [x]
|
||||
(if (indexed? x)
|
||||
x
|
||||
(error (string "expected tuple for range, got " x))))
|
||||
|
||||
(defn- range-template
|
||||
[binding object rest op comparison]
|
||||
(let [[start stop step] (check-indexed object)]
|
||||
(for-template binding start stop (or step 1) comparison op [rest])))
|
||||
|
||||
(defn- each-template
|
||||
[binding inx body]
|
||||
(with-syms [k]
|
||||
@ -395,11 +409,6 @@
|
||||
(def ,binding ,i)
|
||||
,body))))
|
||||
|
||||
(defn- check-indexed [x]
|
||||
(if (indexed? x)
|
||||
x
|
||||
(error (string "expected tuple for range, got " x))))
|
||||
|
||||
(defn- loop1
|
||||
[body head i]
|
||||
|
||||
@ -429,12 +438,12 @@
|
||||
(def {(+ i 2) object} head)
|
||||
(let [rest (loop1 body head (+ i 3))]
|
||||
(case verb
|
||||
:range (let [[start stop step] (check-indexed object)]
|
||||
(for-template binding start stop (or step 1) < + [rest]))
|
||||
:range (range-template binding object rest + <)
|
||||
:range-to (range-template binding object rest + <=)
|
||||
:down (range-template binding object rest - >)
|
||||
:down-to (range-template binding object rest - >=)
|
||||
:keys (keys-template binding object false [rest])
|
||||
:pairs (keys-template binding object true [rest])
|
||||
:down (let [[start stop step] (check-indexed object)]
|
||||
(for-template binding start stop (or step 1) > - [rest]))
|
||||
:in (each-template binding object [rest])
|
||||
:iterate (iterate-template binding object rest)
|
||||
:generate (with-syms [f s]
|
||||
@ -477,11 +486,14 @@
|
||||
\t:iterate - repeatedly evaluate and bind to the expression while it is truthy.\n
|
||||
\t:range - loop over a range. The object should be two element tuple with a start
|
||||
and end value, and an optional positive step. The range is half open, [start, end).\n
|
||||
\t:down - Same as range, but loops in reverse.\n
|
||||
\t:keys - Iterate over the keys in a data structure.\n
|
||||
\t:pairs - Iterate over the keys value pairs in a data structure.\n
|
||||
\t:in - Iterate over the values in an indexed data structure or byte sequence.\n
|
||||
\t:generate - Iterate over values yielded from a fiber. Can be paired with the generator
|
||||
\t:range-to - same as :range, but the range is inclusive [start, end].\n
|
||||
\t:down - loop over a range, stepping downwards. The object should be two element tuple
|
||||
with a start and (exclusive) end value, and an optional (positive!) step size.\n
|
||||
\t:down-to - same :as down, but the range is inclusive [start, end].\n
|
||||
\t:keys - iterate over the keys in a data structure.\n
|
||||
\t:pairs - iterate over the keys value pairs as tuples in a data structure.\n
|
||||
\t:in - iterate over the values in a data structure.\n
|
||||
\t:generate - iterate over values yielded from a fiber. Can be paired with the generator
|
||||
function for the producer/consumer pattern.\n\n
|
||||
loop also accepts conditionals to refine the looping further. Conditionals are of
|
||||
the form:\n\n
|
||||
@ -505,6 +517,7 @@
|
||||
(put _env 'iterate-template nil)
|
||||
(put _env 'each-template nil)
|
||||
(put _env 'keys-template nil)
|
||||
(put _env 'range-template nil)
|
||||
|
||||
(defmacro seq
|
||||
"Similar to loop, but accumulates the loop body into an array and returns that.
|
||||
@ -1276,7 +1289,7 @@
|
||||
nil)
|
||||
|
||||
(defn pp
|
||||
"Pretty print to stdout or (dyn :out)."
|
||||
`Pretty print to stdout or (dyn :out). The format string used is (dyn :pretty-format "%q").`
|
||||
[x]
|
||||
(printf (dyn :pretty-format "%q") x)
|
||||
(flush))
|
||||
@ -1312,6 +1325,9 @@
|
||||
[pattern expr onmatch seen]
|
||||
(cond
|
||||
|
||||
(= '_ pattern)
|
||||
(onmatch)
|
||||
|
||||
(symbol? pattern)
|
||||
(if (in seen pattern)
|
||||
~(if (= ,pattern ,expr) ,(onmatch) ,sentinel)
|
||||
@ -1352,23 +1368,26 @@
|
||||
~(if (,dictionary? ,$dict)
|
||||
,((fn aux []
|
||||
(set key (next pattern key))
|
||||
(def $val (gensym))
|
||||
(if (= key nil)
|
||||
(onmatch)
|
||||
(match-1 [(in pattern key) [not= (in pattern key) nil]] [in $dict key] aux seen))))
|
||||
~(do (def ,$val (,get ,$dict ,key))
|
||||
,(match-1 [(in pattern key) [not= nil $val]] $val aux seen)))))
|
||||
,sentinel)))
|
||||
|
||||
:else ~(if (= ,pattern ,expr) ,(onmatch) ,sentinel)))
|
||||
|
||||
(defmacro match
|
||||
"Pattern matching. Match an expression x against
|
||||
any number of cases. Easy case is a pattern to match against, followed
|
||||
any number of cases. Each case is a pattern to match against, followed
|
||||
by an expression to evaluate to if that case is matched. A pattern that is
|
||||
a symbol will match anything, binding x's value to that symbol. An array
|
||||
will match only if all of it's elements match the corresponding elements in
|
||||
x. A table or struct will match if all values match with the corresponding
|
||||
values in x. A tuple pattern will match if it's first element matches, and the following
|
||||
elements are treated as predicates and are true. Any other value pattern will only
|
||||
match if it is equal to x."
|
||||
elements are treated as predicates and are true. The last special case is
|
||||
the '_ symbol, which is a wildcard that will match any value without creating a binding.
|
||||
Any other value pattern will only match if it is equal to x."
|
||||
[x & cases]
|
||||
(with-idemp $x x
|
||||
(def len (length cases))
|
||||
|
@ -369,19 +369,23 @@ tail:
|
||||
s->mode = oldmode;
|
||||
if (!result) return NULL;
|
||||
|
||||
Janet cap;
|
||||
Janet cap = janet_wrap_nil();
|
||||
Janet constant = s->constants[rule[2]];
|
||||
switch (janet_type(constant)) {
|
||||
default:
|
||||
cap = constant;
|
||||
break;
|
||||
case JANET_STRUCT:
|
||||
cap = janet_struct_get(janet_unwrap_struct(constant),
|
||||
s->captures->data[s->captures->count - 1]);
|
||||
if (s->captures->count) {
|
||||
cap = janet_struct_get(janet_unwrap_struct(constant),
|
||||
s->captures->data[s->captures->count - 1]);
|
||||
}
|
||||
break;
|
||||
case JANET_TABLE:
|
||||
cap = janet_table_get(janet_unwrap_table(constant),
|
||||
s->captures->data[s->captures->count - 1]);
|
||||
if (s->captures->count) {
|
||||
cap = janet_table_get(janet_unwrap_table(constant),
|
||||
s->captures->data[s->captures->count - 1]);
|
||||
}
|
||||
break;
|
||||
case JANET_CFUNCTION:
|
||||
cap = janet_unwrap_cfunction(constant)(s->captures->count - cs.cap,
|
||||
|
@ -765,6 +765,9 @@ static int line() {
|
||||
case '.': /* Alt-. */
|
||||
historymove(-JANET_HISTORY_MAX);
|
||||
break;
|
||||
case 127: /* Alt-backspace */
|
||||
kbackspacew();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -212,13 +212,17 @@
|
||||
|
||||
(assert (= 7 (case :a :b 5 :c 6 :u 10 7)) "case with default")
|
||||
|
||||
# Testing the loop and for macros
|
||||
# Testing the loop and seq macros
|
||||
(def xs (apply tuple (seq [x :range [0 10] :when (even? x)] (tuple (/ x 2) x))))
|
||||
(assert (= xs '((0 0) (1 2) (2 4) (3 6) (4 8))) "seq macro 1")
|
||||
|
||||
(def xs (apply tuple (seq [x :down [8 -2] :when (even? x)] (tuple (/ x 2) x))))
|
||||
(assert (= xs '((4 8) (3 6) (2 4) (1 2) (0 0))) "seq macro 2")
|
||||
|
||||
# :range-to and :down-to
|
||||
(assert (deep= (seq [x :range-to [0 10]] x) (seq [x :range [0 11]] x)) "loop :range-to")
|
||||
(assert (deep= (seq [x :down-to [10 0]] x) (seq [x :down [10 -1]] x)) "loop :down-to")
|
||||
|
||||
# Some testing for not=
|
||||
(assert (not= 1 1 0) "not= 1")
|
||||
(assert (not= 0 1 1) "not= 2")
|
||||
|
@ -107,4 +107,23 @@
|
||||
(assert (= nil (match [1 2] [a b c] a)) "match 4")
|
||||
(assert (= 2 (match [1 2] [a b] b)) "match 5")
|
||||
|
||||
# And/or checks
|
||||
|
||||
(assert (= false (and false false)) "and 1")
|
||||
(assert (= false (or false false)) "or 1")
|
||||
|
||||
# #300 Regression test
|
||||
|
||||
# Just don't segfault
|
||||
(assert (peg/match '{:main (replace "S" {"S" :spade})} "S7") "regression #300")
|
||||
|
||||
# Test cases for #293
|
||||
(assert (= :yes (match [1 2 3] [_ a _] :yes :no)) "match wildcard 1")
|
||||
(assert (= :no (match [1 2 3] [__ a __] :yes :no)) "match wildcard 2")
|
||||
(assert (= :yes (match [1 2 [1 2 3]] [_ a [_ _ _]] :yes :no)) "match wildcard 3")
|
||||
(assert (= :yes (match [1 2 3] (_ (even? 2)) :yes :no)) "match wildcard 4")
|
||||
(assert (= :yes (match {:a 1} {:a _} :yes :no)) "match wildcard 5")
|
||||
(assert (= false (match {:a 1 :b 2 :c 3} {:a a :b _ :c _ :d _} :no {:a _ :b _ :c _} false :no)) "match wildcard 6")
|
||||
(assert (= nil (match {:a 1 :b 2 :c 3} {:a a :b _ :c _ :d _} :no {:a _ :b _ :c _} nil :no)) "match wildcard 7")
|
||||
|
||||
(end-suite)
|
||||
|
Loading…
Reference in New Issue
Block a user