janet-lang / janet Goto Github PK
View Code? Open in Web Editor NEWA dynamic language and bytecode vm
Home Page: https://janet-lang.org
License: MIT License
A dynamic language and bytecode vm
Home Page: https://janet-lang.org
License: MIT License
Using the following example:
(defn sync [& coros]
(var coros (map fiber/new coros))
(var done false)
(while (not done)
(set coros (filter (fn [coro]
(resume coro)
(= (fiber/status coro) :pending)) coros))
(if (> (length coros) 0) (yield) (set done true))))
(var x
(fiber/new
(fn [] (sync
(fn []
(print "1")
(yield)
(print "2"))
(fn []
(print "1")
(yield)
(print "2")
(yield)
(print "3"))))))
(resume x)
(load-image (make-image x))
If I don't call (resume x)
, the fiber is able to be serialized/deserialized, if I call it I get the following error:
error: invalid fiber
in unmarshal
in load-image [core.janet] at (48009:48043)
in _thunk [demo/test4.janet] (tailcall) at (490:516)
janet:74:> (find (fn (x) (= x 'k)) '(a b c))
error in repl: expected integer key
in find [core.janet] at (25096:25126)
in _thunk [repl] at (75:107) (tailcall)
should return nil
a patch :
diff --git a/src/core/core.janet b/src/core/core.janet
index ca32b22..a155eaa 100644
--- a/src/core/core.janet
+++ b/src/core/core.janet
@@ -723,7 +723,8 @@
nil if not found. Note their is no way to differentiate a nil from the indexed collection
and a not found. Consider find-index if this is an issue."
[pred ind]
- (get ind (find-index pred ind)))
+ (def i (find-index pred ind))
+ (if (= i nil) nil (get ind i)))
(defn take-until
"Given a predicate, take only elements from an indexed type that satisfy
Since 0382dc9 commit, uint64_t & int64_t typed arrays support have been removed.
Why ?
I know we don't have (yet ?) full proper way to manipulate 64bit integers directly in janet (without truncation) but a lot of numerical C libraries use 64bit integers arrays and it's handy (and efficient) to be able to pass directly such binary data as "standard" janet objects to them.
Although Dst is in alpha (no feature is safe from being changed/deleted), some preliminary documentation is needed. Both the Dst language and the C source code need lots of documentation to help new contributors to the project.
Janet has a defacto C API defined by all functions exposed in janet.h, but they are not well documented. These functions need to be documented in a way that is readable for people who are trying to embed Janet.
Some options for writing this documentation are Doxygen or handwritten documentation. I'm leaning towards Doxygen for the C API doc, as it does C documentation out of the box and we really only need to make public facing docs for one file, janet.h
Currently the only way to have this is use keys from table
data structures with unused values.
Is there any plan to support Set data structure in the core?
Janet currently has a listing of all functions in the Core API at https://janet-lang.org/doc.html, but no easy way of exploring functions in the Core Library in a fashion that is more easily accesible, such as a function index. Janet needs a listing of all functions and macros in the core library grouped by functionality. Items in the list should ideally fit on one browser page and link to the fuller documentation.
I get an unmarshal error when running the following script:
(def x
(fiber/new
(fn []
(var y (fiber/new (fn [] (print "1") (yield) (print "2"))))
)))
(load-image (make-image x))
error: expected string
in unmarshal
in load-image [core.janet] at (48135:48169)
in _thunk [demo/teste3.janet] (tailcall) at (125:151)
In a different test also involving nested fibers (an array of them) I also got a different error but I could not create a minimal reproducing script.
rror: invalid reference
in unmarshal
in load-image [core.janet] at (48135:48169)
in _thunk [demo/teste2.janet] (tailcall) at (1772:1799)
Would you like to add more error handling for return values from functions like the following?
(def f (fiber/new (fn @[]
(yield 1)
(yield 2)
(yield 3)
(yield 4)
5)))
causes compile error in repl: expected function parameters
.
Seems like @[]
-> []
works.
suite4.janet can pass only 10 of 22 tests on SPARC.
it cant pass this trivial assert for example:
(assert (= (string (buffer/format @"" "pi = %6.3f" math/pi)) "pi = 3.142") "%6.3f")
SPARC:
janet:50:> (buffer/format @"" "pi = %6.3f" math/pi)
@"pi = 3.141"
janet:91:>
LINUX:
Janet 0.4.0-4a2d4f5 Copyright (C) 2017-2019 Calvin Rose
janet:0:> (buffer/format @"" "pi = %6.3f" math/pi)
@"pi = 3.142"
janet:41:>
mandb is used on many but not all linux distributions and infrequently outside of linux distributions to maintain the man page index files. For example mandb will fail causing an error when running make install
on macOS.
Depending on the platform or distribution mandb
, makemandb
or /usr/libexec/makewhatis
may be the appropriate command for maintaining the index files. Given the disparity between linux distributions and platforms I suggest doing as most projects and not trying to update the man page indexes during install.
There are some issues on SPARC. The following stack trace was generated when running on sparc. The cause of this issue needs to be investigated.
# pstack ./core
core './core' of 26184: build/janet_boot
00000001000317a8 root (ffffffff7ffff678, 100160b00, 74, 2f, 4, 4) + 324
000000010003230c janet_parser_consume (ffffffff7ffff678, 29, 100, 0, 1, 0) + 4c
0000000100036e30 janet_dobytes (100148230, 100008b28, d49f, 10001f7f0, ffffffff7ffff678, 0) + 220
00000001000296d4 janet_core_env (100148230, 1, ffffffff7f5c0100, 0, 7ffd400, 3fff400) + 5e8
0000000100041460 main (1, ffffffff7ffff948, ffffffff7ffff958, 100000, 0, 0) + 18
0000000100020bc4 _start (0, 0, 0, 0, 0, 0) + 64
janet:1255:> (assert (= (length (table (/ 0 0) 2 1 3)) 1) "nan key table ctor")
✘ nan key table ctor
false
janet:110:> (assert (= (length (table (/ 0 0) 2 1 3)) 1) "nan key table ctor")
src/core/vm.c:340:5: runtime error: division by zero
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/core/vm.c:340:5 in
✔true
i want both sparc and linux return true on this test from suite0.janet
What are the current limitations of the marshal
function?
I’ve tried serializing/deserializing a simple fiber and it works as expected, but if I use functions like not
, filter
or map
, they all error with no registry value for <cfunction “name”>
.
Are there plans for threading or concurrency of any kind?
Exploring janet, I've experimented this interpreter crash :
Janet 0.3.0-d5bab72 Copyright (C) 2017-2018 Calvin Rose
janet:0:> (os/shell "uname -a")
Linux mbi7 4.15.0-43-generic #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018
x86_64 x86_64 x86_64 GNU/Linux
0
janet:22:> ((fn (x y &) (+ x y)) 1 2 3)
3
janet:51:> ((fn (x & y) (+ x y)) 1 2 3)
Segmentation fault (core dumped)
Provide line numbers (in parser at least) and stack traces on errors please.
(get (tuple "a" "b" "c") 1) # -> "a"
Evaluates to "b"
instead of "a"
.
I have just added a PEG implementation to Janet. It is similar in scope and interface to LPeg, although probably slower as it is implemented as a tree-walk interpreter over Janet data structures. The PEG needs more documentation and testing as well as an eventual compiler.
The PEG can be used with (peg/match pattern text [,start=0])
.
An example from the test suite. This example is translated from the LPeg csv example.
(def csv
'{:field (+
(* `"` (<-s (at-least 0 (+ (- 1 `"`) (/ `""` `"`)))) `"`)
(<- (at-least 0 (- 1 (set ",\n")))))
:main (* :field (at-least 0 (* "," :field)) (+ "\n" -1))})
(peg/match csv "1,2,3") # -> @["1" "2" "3"]
Dst needs an on-ramp for new contributors and users getting started. A simple tutorial for setting up Dst, using the repl, writing programs, and using the core functions would help newcomers understand the language without looking at all of the source code.
In Common Lisp for instance you can load your own code into your REPL and make a binary dump. After that you can use this dump binary as your own executable software and it's possible distribute in this fashion. This is common in game development for CL enthusiasts.
In Clojure there is the .jar stuff from Java, it's tied to JVM, but at least it's something.
So... There is a way to embed a janet software as a standalone executable, portable at same operating-system wise? Like Golang builds: a executable statically linked.
If don't have, is there any plan to develop something like that?
Currently Janet don't support range with negative step, I think it could be nice to have it :D
$ janet
Janet 0.4.0-235019e
> (range 10 0 -1)
@[]
I get this error:
(get [1 34 3 4 52 31] 0)
runtime error: "expected function"
in <function 0x55AF7B5DD3C0> (pc=8) (tailcall)
while:
(get @[1 34 3 4 52 31] 0)
1
(get (tuple 1 34 3 4 52 31) 0)
1
work fine
I am trying to build numarray.c
from the examples, but it tries to include janet/janet.h
from the system include path. On my system, Janet is installed in ~/.local/
. As far as I can tell, build.janet
does not support getting exported CFLAGS
, nor does it read from the PREFIX
, so I can't get that file to build.
Are
you planning in releasing you project ? It is very interesting, I would like to toy with it.
Even without documentation is quite easy to write some code. Reduce took like a minute.
(defn fold [f s]
"folds a sequence onto function f"
(var tail-tail (tail (tail s)) )
(if (empty? tail-tail)
(f (head s) (head (tail s)))
(fold f (cons (f (head s) (head (tail s))) tail-tail))))
If a )
is missing in a script, e.g. at the end of a function, then janet will do nothing and give no error message when trying to execute the script.
On macos High Sierra,
brew install emscripten
make emscripten
➜ janet git:(master) make emscripten
emcc -std=c99 -Wall -Wextra -Isrc/include -O2 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' -s ALLOW_MEMORY_GROWTH=1 -s AGGRESSIVE_VARIABLE_ELIMINATION=1 -DJANET_BUILD="\"44e31ca\"" -o build/core/abstract.bc -c src/core/abstract.c
shared:WARNING: LLVM version appears incorrect (seeing "10.0", expected "6.0")
shared:CRITICAL: fastcomp in use, but LLVM has not been built with the JavaScript backend as a target, llc reports:
===========================================================================
(no targets could be identified: [Errno 2] No such file or directory)
===========================================================================
shared:CRITICAL: you can fall back to the older (pre-fastcomp) compiler core, although that is not recommended, see http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html
shared:ERROR: failing sanity checks due to previous llvm failure
make: *** [build/core/abstract.bc] Error 1
What should I do next?
From issue #17.
(container key)
will get value of key
from container
, if value is a callable to call we can try ((container key) args)
but this is little messy syntax.
So there is hacky solution:
(key container args) => ((container key) args)
This makes key looks like method name, which is good to read, and drops one pair of parentheses.
Example:
janet:24:> (def obj {:wof (fn () (print "wof-wof"))})
{:wof <function 0x00574D80>}
# arg access (get value)
janet:74:> (obj :wof)
<function 0x00574D80>
# call access (get and call value-function)
janet:63:> (:wof obj)
wof-wof
nil
Bakpakin's class example:
# Create a 'class'
(def Car @{:honk (fn [self] (print "I am a " (self :maker)))})
# Create an 'instance'
(def mycar (table/setproto @{:maker "Subaru"} Car))
# Make a 'method call'
(:honk mycar)
I suggest to reuse a higher level build system than your current make script so that powerful checks for software features will become easier.
Can we add the string/buffer trim
triml
trimr
into core. I see currently it's missing.
I like those container:key shorthand for structs and tables. (This is not documented feature as I see)
(def x @{:key 'value})
x:key => value
(set x:anotherkey 'anothervalue)
x => @{:key value :anotherkey anothervalue}
But why it is doesn't works with tuples and arrays?
(def x @[1 2 3])
x:0 => error in repl: expected integer key for data structure
(set x:0 -1) => error in repl: expected integer key for data structure
Some experiments with Janet - LuaJIT bindings
I've created a little janet native module to be able to use LuaJIT from Janet.
This is very experimental code (It's just a proof of concept)
But it seems to work and it opens an easy way to use the awesome LuaJIT ffi capabilities from Janet ...
If you want to play, the module is here : https://github.com/jfcap/janet-luajit.git
janet:0:> (import build/lua :prefix "")
nil
janet:30:> (def lua (lua/new))
<lua/vm 0x55A8390827E0>
janet:50:> (def l-table (lua @[1 2 3]))
<lua/object table 1>
janet:79:> (l-table 1)
1
janet:91:> (set (l-table 1) 10)
10
janet:112:> ((lua :print) "hello janet!")
hello janet!
nil
janet:142:> (def l-chunk ((lua :loadstring) "print('hello janet!')"))
<lua/object function 4>
janet:200:> (l-chunk nil)
hello janet!
nil
janet:214:> (def lua-ffi ((lua :require) :ffi))
<lua/object table 6>
janet:250:> ((lua-ffi :cdef) "int printf(const char *fmt, ...);")
nil
janet:304:> (lua/call ((lua-ffi :C) :printf) ["Hello %s!\n" "world"])
Hello world!
13
janet:362:> (def buf ((lua-ffi :new) ["uint8_t[?]" 10]))
<lua/object cdata b>
janet:407:> (for i 0 10 (set (buf i) (* 10 i)))
nil
janet:443:> (pp buf)
<lua/object cdata b>
nil
janet:452:> (pp (buf 5))
50
nil
(import bars)
(bars/template "foobar a b c")
error: could not compile template
in template [/home/ac/src/janet/tools/bars.janet] at (1473:1517)
in _thunk [./test.janet] (tailcall) at (16:45)
Abstract types cannot currently control how they print in the repl (what they return from the describe function). It would be nice to be able to override the default print functionality with custom printing functionality for debugging. This way, something like:
(int/s64 "123")
could display as
<core/s64 123>
or the like.
I'm curious about the possibility of the compiler targeting the jvm. I asked this question on reddit a while back and the amount of upvotes surprised me: https://www.reddit.com/r/Clojure/comments/aluoar/what_is_the_status_of_some_of_the_clojure_static/
What happens here ?
Janet 0.3.0-38a7e4f Copyright (C) 2017-2019 Calvin Rose
janet:0:> (def t (put @{} :a 1))
@{:source-map ("repl" 1 22) :value <cycle 0>}
janet:23:> (put (put @{} :a 1) :b 2)
error in repl: expected array|table|buffer, got :b
in _thunk [repl] at (24:48) (tailcall)
same problem with array
janet:50:> (def a (put @[] 0 1))
@{:source-map ("repl" 51 71) :value <cycle 0>}
It looks like make install
does not respect the PREFIX
, particularly when installing the man page to /usr/local/...
and tools to JANET_PATH
. This is not ideal; I'd like to have an installation of Janet in my ~/.local
folder.
Is there a better way to call a janet function from C when the same function is called multiple times in a loop?
For example this (naive ?) code is working
static Janet num_vector_ctransform(int32_t argc, Janet *argv) {
janet_fixarity(argc, 2);
Janet jarg[2];
JanetFunction * fun=janet_getfunction(argv,0);
num_vector * vector = (num_vector *)janet_getabstract(argv,1,&num_vector_type);
size_t i;
jarg[2]=argv[1];
for (i=0;i<vector->size;i++) {
jarg[0]=janet_wrap_number(vector->data[i*vector->stride]);
jarg[1]=janet_wrap_number(i);
vector->data[i*vector->stride]=janet_unwrap_number(janet_call(fun,3,jarg));
}
return argv[1];
}
... but seems rather "inefficient".
If I compare (basic benchmark) this to the "equivalent" janet function (vector/get, vector/set are cfuns)
(defn vector/transform [f v]
(def size (vector/size v))
(var i 0)
(while (< i size)
(vector/set v i (f (vector/get v i) i v))
(++ i))
v)
the C version is running more than 2 times slower that the janet version (for "big" vectors) ...
I suspect that all the operations behind janet_call may be probably simplified (or not repeated) in such a case ...
(something like "using the same fiber" multiple times in the loop ? ...)
My lack of deep understanding of janet vm prevent me to go further without help ...
Sorry to bother you with such question.
What bothers me here is not really "performance" but I just want to better understand janet and avoid writing really "stupid code".
Side question : Is there a better way to ask such question than opening a "issue" ?
Thanks in advance.
I've ported Lua string.match function to janet.
(It was not a lot of work, mostly copy/paste)
I know we have pegs, and it's really great and powerful.
But for basic pattern matching, I've always found that simple lua style regex are very handy.
janet:210:> (string/match "hello janet 123" "(%w+)%s*(%w+).-(%d+)")
@["hello" "janet" "123"]
If you are interested the patch is here :
https://github.com/jfcap/janet.git (branch string-match)
The code needs probably some cleanup (useless unsigned/signed char conversions, ...)
Not sure it must be included in core (an extern module can do the job).
This can be adapted to "upgrade" the string/find function.
> (range 0 10 3)
@[0
nil
nil
3
nil
nil
6
nil
nil
9]
is this correct ?
I've found a little bug in buffer.c
janet:353:> (buffer/push-word @"" 1)
error in repl: bad slot #0, expected number, got @""
in cfunction buffer/push-word
in _thunk [repl] at (354:377) (tailcall)
Here is a patch
diff --git a/src/core/buffer.c b/src/core/buffer.c
index d318a6e..7987d79 100644
--- a/src/core/buffer.c
+++ b/src/core/buffer.c
@@ -192,7 +192,7 @@ static Janet cfun_buffer_word(int32_t argc, Janet *argv) {
janet_arity(argc, 1, -1);
JanetBuffer *buffer = janet_getbuffer(argv, 0);
for (i = 1; i < argc; i++) {
- double number = janet_getnumber(argv, 0);
+ double number = janet_getnumber(argv, i);
uint32_t word = (uint32_t) number;
if (word != number)
janet_panicf("cannot convert %v to machine word", argv[0]);
On https://janet-lang.org/ repl.js defines methods in the global scope. In particular print()
which ends up overriding window.print()
. This probably wont break printing the page in browsers because they wouldn't use the JS API but it might break peoples custom scripts and is not good practice. Everything should be wrapped in an IIFE and anything you need accessable on window
from elsewhere should be put there explicitly.
(print "hello"))
(print "world")
$ janet test.janet
hello
parse error in ./tools/test.janet around byte 17: unexpected delimiter
world
As a proof of concept, I've tried to implement Typed Array (JS like) in janet.
The main objectives are :
Some implementation choices :
TODO :
For the curious ones : typed-array branch on my janet fork
https://github.com/jfcap/janet.git (branch typed-array)
janet:0:> (def buf (tarray/buffer 2000))
<ta/buffer 0x000005CA3C20>
janet:31:> (def a (tarray/new :float64 10 1 0 buf))
<ta/float64 0x000005CA61A0>
janet:153:> (print (string/format "%p" (tarray/properties a)))
{ :buffer <ta/buffer 0x000005CA3C20>
:size 10
:stride 1
:type :float64
:byte-offset 0
:type-size 8}
nil
janet:204:> (set (a 1) math/pi)
3.14159
janet:224:> (a 1)
3.14159
Any thoughts about this idea ?
Something that made me avoid lua in the past as a configuration language was lack of string interpolation, perhaps it is something you would consider in the core reader, though I suppose it can be done as a macro, feel free to close this if it's something you thought about.
As of 2018, Travis supports Windows. I would be really happy if we could ditch appveyor for a single CI platform, as our windows needs are quite basic. As an aside, the FreeBSD build is tested on sr.ht, and travis unfortunately will not support FreeBSD.
Having never done this before, I don't know if this actually a good idea or if Travis's windows support will really remove much duplication.
Dst is not a descriptive, meaningful, or memorable name that unfortunately is also short for Day Savings Time.
Some ideas:
Very open to new ideas.
The test older-than
always fail when f1 or f2 does not exist (which is the case on fresh module build)
(defn- older-than
[f1 f2]
"Check if f1 is newer than f2. Used for checking if a file should be updated."
(if is-win true
(zero? (os/shell (string "[ " f1 " -ot " f2 " ]")))))
This simple fix works for me
(defn- older-than
[f1 f2]
"Check if f1 is newer than f2. Used for checking if a file should be updated."
(if is-win true
(not (zero? (os/shell (string "[ " f1 " -nt " f2 " ]"))))))
I think wiki docs will be moved to the https://janet-lang.org and web-site as well will become open source. Maybe it means janet (janet-lang) namespace on github.
I also want to help you with presentation of the language and draw a logo. If you have some thoughts on that?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.