Giter Site home page Giter Site logo

janet-lang / janet Goto Github PK

View Code? Open in Web Editor NEW
3.3K 65.0 213.0 12.94 MB

A dynamic language and bytecode vm

Home Page: https://janet-lang.org

License: MIT License

C 79.03% Makefile 0.79% Batchfile 0.30% Roff 0.46% Meson 0.70% Shell 0.08% Janet 18.64%
c language vm lisp macros repl interpreter functional-language imperative-language

janet's Introduction

Join the chat   builds.sr.ht status builds.sr.ht status Actions Status

Janet logo

Janet is a programming language for system scripting, expressive automation, and extending programs written in C or C++ with user scripting capabilities.

Janet makes a good system scripting language, or a language to embed in other programs. It's like Lua and GNU Guile in that regard. It has more built-in functionality and a richer core language than Lua, but smaller than GNU Guile or Python. However, it is much easier to embed and port than Python or Guile.

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 can be embedded in other programs. Try Janet in your browser at https://janet-lang.org.

If you'd like to financially support the ongoing development of Janet, consider sponsoring its primary author through GitHub.


Examples

See the examples directory for all provided example programs.

Game of Life

# John Conway's Game of Life

(def- window
  (seq [x :range [-1 2]
         y :range [-1 2]
         :when (not (and (zero? x) (zero? y)))]
       [x y]))

(defn- neighbors
  [[x y]]
  (map (fn [[x1 y1]] [(+ x x1) (+ y y1)]) window))

(defn tick
  "Get the next state in the Game Of Life."
  [state]
  (def cell-set (frequencies state))
  (def neighbor-set (frequencies (mapcat neighbors state)))
  (seq [coord :keys neighbor-set
         :let [count (get neighbor-set coord)]
         :when (or (= count 3) (and (get cell-set coord) (= count 2)))]
      coord))

(defn draw
  "Draw cells in the game of life from (x1, y1) to (x2, y2)"
  [state x1 y1 x2 y2]
  (def cellset @{})
  (each cell state (put cellset cell true))
  (loop [x :range [x1 (+ 1 x2)]
         :after (print)
         y :range [y1 (+ 1 y2)]]
    (file/write stdout (if (get cellset [x y]) "X " ". ")))
  (print))

# Print the first 20 generations of a glider
(var *state* '[(0 0) (-1 0) (1 0) (1 1) (0 2)])
(for i 0 20
  (print "generation " i)
  (draw *state* -7 -7 7 7)
  (set *state* (tick *state*)))

TCP Echo Server

# A simple TCP echo server using the built-in socket networking and event loop.

(defn handler
  "Simple handler for connections."
  [stream]
  (defer (:close stream)
    (def id (gensym))
    (def b @"")
    (print "Connection " id "!")
    (while (:read stream 1024 b)
      (printf " %v -> %v" id b)
      (:write stream b)
      (buffer/clear b))
    (printf "Done %v!" id)
    (ev/sleep 0.5)))

(net/server "127.0.0.1" "8000" handler)

Windows FFI Hello, World!

# Use the FFI to popup a Windows message box - no C required

(ffi/context "user32.dll")

(ffi/defbind MessageBoxA :int
  [w :ptr text :string cap :string typ :int])

(MessageBoxA nil "Hello, World!" "Test" 0)

Language Features

  • 600+ functions and macros in the core library
  • Built-in socket networking, threading, subprocesses, and file system functions.
  • Parsing Expression Grammars (PEG) engine as a more robust Regex alternative
  • Macros and compile-time computation
  • Per-thread event loop for efficient IO (epoll/IOCP/kqueue)
  • First-class green threads (continuations) as well as OS threads
  • Erlang-style supervision trees that integrate with the event loop
  • First-class closures
  • Garbage collection
  • Distributed as janet.c and janet.h for embedding into a larger program.
  • Python-style generators (implemented as a plain macro)
  • Mutable and immutable arrays (array/tuple)
  • Mutable and immutable hashtables (table/struct)
  • Mutable and immutable strings (buffer/string)
  • Tail recursion
  • Interface with C functions and dynamically load plugins ("natives").
  • Built-in C FFI for when the native bindings are too much work
  • REPL development with debugger and inspectable runtime

Documentation

Documentation is also available locally in the REPL. Use the (doc symbol-name) macro to get API documentation for symbols in the core library. For example,

(doc apply)

shows documentation for the apply function.

To get a list of all bindings in the default 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

You can get the source on GitHub or SourceHut. While the GitHub repo is the official repo, the SourceHut mirror is actively maintained.

Building

macOS and Unix-like

The Makefile is non-portable and requires GNU-flavored make.

cd somewhere/my/projects/janet
make
make test
make repl
make install
make install-jpm-git

Find out more about the available make targets by running make help.

32-bit Haiku

32-bit Haiku build instructions are the same as the UNIX-like build instructions, but you need to specify an alternative compiler, such as gcc-x86.

cd somewhere/my/projects/janet
make CC=gcc-x86
make test
make repl
make install
make install-jpm-git

FreeBSD

FreeBSD build instructions are the same as the UNIX-like build instructions, but you need gmake to compile. Alternatively, install the package directly with pkg install lang/janet.

cd somewhere/my/projects/janet
gmake
gmake test
gmake repl
gmake install
gmake install-jpm-git

NetBSD

NetBSD build instructions are the same as the FreeBSD build instructions. Alternatively, install the package directly with pkgin install janet.

Windows

  1. Install Visual Studio or Visual Studio Build Tools.
  2. Run a Visual Studio Command Prompt (cl.exe and link.exe need to be on your PATH) and cd to the directory with Janet.
  3. Run build_win to compile Janet.
  4. Run build_win test to make sure everything is working.

To build an .msi installer executable, in addition to the above steps, you will have to:

  1. Install, or otherwise add to your PATH the WiX 3.11 Toolset.
  2. Run build_win dist.

Now you should have an .msi. You can run build_win install to install the .msi, or execute the file itself.

Meson

Janet also has a build file for Meson, a cross-platform build system. Although Meson has a Python dependency, Meson is a very complete build system that 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 follows. The options provided to meson setup below emulate Janet's Makefile.

git clone https://github.com/janet-lang/janet.git
cd janet
meson setup build \
          --buildtype release \
          --optimization 2 \
          --libdir /usr/local/lib \
          -Dgit_hash=$(git log --pretty=format:'%h' -n 1)
ninja -C build

# Run the binary
build/janet

# Installation
ninja -C build install

Development

Janet can be hacked on with pretty much any environment you like, but for IDE lovers, Gnome Builder is probably the best option, as it has excellent Meson integration. It also offers code completion for Janet's C API right out of the box, which is very useful for exploring. VSCode, Vim, Emacs, and Atom each have syntax packages for the Janet language, though.

Installation

See the Introduction for more details. If you just want 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

A REPL is launched when the binary is invoked with no arguments. Pass the -h flag to display the usage information. Individual scripts can be run with ./janet myscript.janet.

If you are looking to explore, you can print a list of all available macros, functions, and constants by entering the command (all-bindings) into the REPL.

$ 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] script args...
Options are:
  -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
  -E code arguments... : Evaluate an expression as a short-fn with arguments
  -d : Set the debug flag in the REPL
  -r : Enter the REPL after running all scripts
  -R : Disables loading profile.janet when JANET_PROFILE is present
  -p : Keep on executing if there is a top-level error (persistent)
  -q : Hide logo (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
  -i : Load the script argument as an image file instead of source code
  -n : Disable ANSI color output in the REPL
  -l lib : Use a module before processing more arguments
  -w level : Set the lint warning level - default is "normal"
  -x level : Set the lint error level - default is "none"
  -- : Stop handling options

If installed, you can also run man janet to get usage information.

Embedding

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/conf/janetconf.h, can be dragged into any C project and compiled into it. Janet should be compiled with -std=c99 on most compilers, and will need to be linked to the math library, -lm, and 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 on the website for more information.

Discussion

Feel free to ask questions and join the discussion on the Janet Gitter channel. Gitter provides Matrix and IRC bridges as well.

FAQ

How fast is it?

It is about the same speed as most interpreted languages without a JIT compiler. Tight, critical loops should probably be written in C or C++ . Programs tend to be a bit faster than they would be in a language like Python due to the discouragement of slow Object-Oriented abstraction with lots of hash-table lookups, and making late-binding explicit. All values are boxed in an 8-byte representation by default and allocated on the heap, with the exception of numbers, nils and booleans. The PEG engine is a specialized interpreter that can efficiently process string and buffer data.

The GC is simple and stop-the-world, but GC knobs are exposed in the core library and separate threads have isolated heaps and garbage collectors. Data that is shared between threads is reference counted.

YMMV.

Where is (favorite feature from other language)?

It may exist, it may not. If you want to propose a major language feature, go ahead and open an issue, but it will likely be closed as "will not implement". Often, such features make one usecase simpler at the expense of 5 others by making the language more complicated.

Is there a language spec?

There is not currently a spec besides the documentation at https://janet-lang.org.

Is this Scheme/Common Lisp? Where are the cons cells?

Nope. There are no cons cells here.

Is this a Clojure port?

No. It's similar to Clojure superficially because I like Lisps and I like the aesthetics. Internally, Janet is not at all like Clojure, Scheme, or Common Lisp.

Are the immutable data structures (tuples and structs) implemented as hash tries?

No. They are immutable arrays and hash tables. Don't try and use them like Clojure's vectors and maps, instead they work well as table keys or other identifiers.

Can I do object-oriented programming with Janet?

To some extent, yes. However, it is not the recommended method of abstraction, and performance may suffer. That said, tables can be used to make mutable objects with inheritance and polymorphism, where object methods are implemented with keywords.

(def Car @{:honk (fn [self msg] (print "car " self " goes " msg)) })
(def my-car (table/setproto @{} Car))
(:honk my-car "Beep!")

Why can't we add (feature from Clojure) into the core?

Usually, one of a few reasons:

  • Often, it already exists in a different form and the Clojure port would be redundant.
  • Clojure programs often generate a lot of garbage and rely on the JVM to clean it up. Janet does not run on the JVM and has a more primitive garbage collector.
  • We want to keep the Janet core small. With Lisps, a feature can usually be added as a library without feeling "bolted on", especially when compared to ALGOL-like languages. Adding features to the core also makes it a bit more difficult to keep Janet maximally portable.

Can I bind to Rust/Zig/Go/Java/Nim/C++/D/Pascal/Fortran/Odin/Jai/(Some new "Systems" Programming Language)?

Probably, if that language has a good interface with C. But the programmer may need to do some extra work to map Janet's internal memory model to that of the bound language. Janet also uses setjmp/longjmp for non-local returns internally. This approach is out of favor with many programmers now and doesn't always play well with other languages that have exceptions or stack-unwinding.

Why is my terminal spitting out junk when I run the REPL?

Make sure your terminal supports ANSI escape codes. Most modern terminals will support these, but some older terminals, Windows consoles, or embedded terminals will not. If your terminal does not support ANSI escape codes, run the REPL with the -n flag, which disables color output. You can also try the -s flag if further issues ensue.

Why is it called "Janet"?

Janet is named after the almost omniscient and friendly artificial being in The Good Place.

janet's People

Contributors

ahgamut avatar andrewchambers avatar bakpakin avatar cellularmitosis avatar chris-chambers avatar cosmictoast avatar curist avatar dressupgeekout avatar felixr avatar harryvederci avatar honix avatar iacore avatar ianthehenry avatar ishehadeh avatar leafgarland avatar leahneukirchen avatar llmii avatar louisjackman avatar mikebeller avatar pepe avatar primo-ppcg avatar pyrmont avatar rick2600 avatar saikyun avatar subsetpark avatar techcable avatar tionis avatar uvtc avatar yumaikas avatar zevv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

janet's Issues

Custom print method for abstract types.

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.

Invalid fiber when deserializing

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)

Documentation and web-site

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?

Shorthand array access

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

New name

Dst is not a descriptive, meaningful, or memorable name that unfortunately is also short for Day Savings Time.

Some ideas:

  • mite, or mitelang
  • dust, similar to dst, a project with this name already exists
  • Tupper, short for TUPle PRocessing instead of lisp processing

Very open to new ideas.

Initial Tutorial/Getting Started

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.

Experiments with JS style Binary Typed Array in Janet

As a proof of concept, I've tried to implement Typed Array (JS like) in janet.

The main objectives are :

  • Providing a "safe",efficient and "standard" way to manipulate "C compatible" binary data in janet.
  • Manipulate potentially big binary chunks without stressing the GC too much.
  • Make C module interfacing easier and efficient by a group of "standard" CAPI functions.
  • Allowing these binary data to be marshalled/unmarshalled in the same way as standard janet objects (not yet implemented).
  • Giving Janet some potential capabilities for "number-crunching" applications.
  • ...

Some implementation choices :

  • Fixed size array buffers (no reallocation after construction)
  • TA are view of shared buffers (cheap objects, intern allocation/deallocation free)
  • Trying to make it "GC friendly" (tests and benchmarks needed)
  • buffers and TA are standard abstract types.
  • Implemented in janet corelibs to provide (future) marshalling capabilities.

TODO :

  • Coding Marshal/Unmarshal. (IMO a key feature)
  • Provide a set of public CAPI functions.
  • Test and benchmarks.
  • Finding a "decent way" to manipulate int64 data with janet.
  • Some helper functions to manipulate "C struct" data arrays.
  • ...

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 ?

Excellent language

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

make install fails on some platforms when calling mandb

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.

Move Appveyor stuff to Travis

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.

test failed on SPARC

solaris, sparc

janet:1255:> (assert (= (length (table (/ 0 0) 2 1 3)) 1) "nan key table ctor")
 
✘  nan key table ctor
false

linux, x64

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

Range function with negative step

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

Is there a common way to distribute software written in Janet?

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?

Interpret (key container) access as a function call

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)

uint64 & int64 Typed Arrays

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.

Janet LuaJIT Bridge

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

Crash on SPARC

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

string/match function

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.

Initial Documentation

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.

Bug in buffer/push-word

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

Cannot build emscripten on macos

On macos High Sierra,

  1. clone repo
  2. brew install emscripten
  3. Restart IDE
  4. 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?

unmarshal nested fiber

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)

Strange behaviour of put function

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

Function Index

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.

Problem with cook/make-native

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 " ]"))))))

tools/bars - 'could not compile template'

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

Function call crash the interpreter

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)

more testing for PEG

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"]

Document the C API

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

find function cause error when not found

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

String interpolation

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.

Set data structures

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?

`make install` does not respect PREFIX

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.

repl.js redefining global methods

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.

Missing ")" -> missing error message

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.

Accessing tuples []

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

range with step

> (range 0 10 3)
@[0                                                                        
  nil                                                                                                       
  nil                                                                                        
  3                                                                         
  nil                                                                       
  nil                                                                                   
  6                                                                                                          
  nil                                                                                   
  nil                                                                                                        
  9]

is this correct ?

Calling the same Janet function multiple times from C efficiently ?

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.

string/trim functions

Can we add the string/buffer trim triml trimr into core. I see currently it's missing.

Concurrency

Are there plans for threading or concurrency of any kind?

Marshal limits

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

feature request

Provide line numbers (in parser at least) and stack traces on errors please.

math/pi

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.