Janet Notes

John Gabriele

2020-12-30

(Still under construction. This article is a bit of a jumble at the moment.)

Regarding the Janet programming language.

Install

First, a few notes:

Download, Build, Install

Since the makefile comes with an uninstall target, I do the standard easy install into /usr/local. This is just a simple,

  1. download into, say ~/opt, and unpack
  2. cd janet-1.n.m
  3. make, make test, and
  4. as root, make install

Janet will be installed under /usr/local:

.
├── bin
│   ├── janet
│   └── jpm
├── include
│   └── janet
│       ├── janetconf.h
│       └── janet.h
├── lib
│   ├── janet
│   ├── libjanet.a
│   ├── libjanet.so -> libjanet.so.1.12
│   ├── libjanet.so.1.12 -> libjanet.so.1.12.1
│   ├── libjanet.so.1.12.1
│   └── pkgconfig
│       └── janet.pc
└── share
    └── man
        └── man1
            ├── janet.1
            └── jpm.1

Remember that Janet installs into a tree like that partly because you can embed Janet (as a scripting language) into a larger, compiled, C/C++ program. That big C/C++ program would incorporate the Janet header and lib files into its own build process.

Note, if you wanted to, you could have that tree installed anywhere, for example, under your own ~/opt tree (where you have ~/opt/bin, ~/opt/lib, ~/opt/include, etc.), by doing:

cd janet-n.m.o
PREFIX=$HOME/opt make
PREFIX=$HOME/opt make install

(And, if you really wanted to, you could even set that PREFIX to your unpacked Janet src directory, so that it would be installed right into its own unpacked src dir… though, I prefer to keep separate things separate.)

Once installed, try:

$ janet
Janet n.m.o-local linux/x64 - '(doc)' for help
repl:1:> (doc doc)
...
repl:2:> (doc)
...

Three Trees

Note that there are three Janet trees here:

By default, those last two are the same tree: /usr/local. But you can separate them if you like.

Personally, I think that since Janet is so easy to install and to uninstall, and since it actually doesn’t install very much to begin with, if you have root access, just go with the default and install Janet into /usr/local. That way, you don’t need to set up paths and man paths for your system to find Janet-ey things.

However, aside from that, if you like, you can have jpm install 3rd-party modules into yet a different location, say, ~/janet. More below about exactly how to do that.

Links

At the moment, I don’t see:

Janet support around the ’net

On Naming

You can’t use a single-quote (') like a “prime” in variable names, because the ' indicates a symbol is coming up next (and whitespace is allowed after it (and can be omitted before it) for some reason). You can however use a trailing * to mean the same thing.

Note that, regarding modules, there’s a module-related standard library named “module”. Of note in it are:

More on Naming

Note that a project’s name is specified at the top of its project.janet file. But it should (?) also match up with its github repo name (check on this XXX).

Yet more on naming

Note that the slash is just another character in the identifier; it’s not a special namespace indicator, but import makes it work that way in practice.

Janet doesn’t use a dot . for namespacing — it’s all slashes in Janet.

JUST A MINUTE

How janet finds modules when you import them

janet uses the JANET_PATH env var to find modules when you import them (before checking the current directory). If that env var is not set, import defaults to whatever janet was compiled with (the Janet syspath, usually /usr/local/lib/janet). Check this dynamic binding yourself:

(dyn :syspath)  # => "/usr/local/lib/janet"

Note: jpm gets this value from janet.

jpm

To learn more about jpm, always run it with --verbose.

jpm is used for:

So, that means:

janet has a concept of “syspath” (where to look for modules before checking the current directory, and can be set/overridden using JANET_PATH), and jpm gets the syspath from janet.

The directory to where jpm installs modules is a separate issue from the matter of where janet goes looking for modules at runtime when you import them. That said, in practice, both most-often just use the default syspath of /usr/local/lib/janet.

Note: jpm does lots more with putting files in places and finding files in places, because that’s a big part of its job. janet just needs to find modules so it can run them with your code.

Where jpm installs modules

Keep in mind, jpm is a Janet program (it’s written in the Janet language); the janet interpreter runs it.

jpm installs modules into JANET_MODPATH, which if (typically) it is not set is the same as JANET_PATH, which if not set is the default /usr/local/lib/janet, which is quite common.

jpm looks at a project’s project.janet file to see what the project is so it knows how to build and install its parts.

jpm has a number of paths settings configured so it knows where to install each of the bits. See jpm show-paths.

Note: jpm has command-line options for most of these paths:

--modpath=/some/path        modpath     /usr/local/lib/janet        JANET_MODPATH
--headerpath=/some/path     headerpath  /usr/local/include/janet    JANET_HEADERPATH
--binpath=/some/path        binpath     /usr/local/bin              JANET_BINPATH
--libpath=/some/path        libpath     /usr/local/lib              JANET_LIBPATH
[none]                      syspath     /usr/local/lib/janet        JANET_PATH

Note: JANET_MODPATH is where jpm is to install modules, but you usually don’t want to set that.

If you keep your own local ~/janet, with JANET_PATH set to it, you’ll want add ~/janet/bin to your PATH in ~/.bashrc.

Hang on a sec. In your project.janet, you can specify different types of artifacts for jpm to build:

declare-source      module (Janet)              goes in modpath, else syspath
declare-native      native module               goes in ... (maybe libpath? XXX)
declare-executable  standalone executable       goes in binpath

Note about installing modules into your project dir

Calvin gave this tip for installing modules via jpm directly into your current project:

cd ~/code/my_project
mkdir janet_modules
export JANET_PATH=$(pwd)/janet_modules
jpm deps
jpm build
jpm install  # Since JANET_MODPATH is not set, will default to $JANET_PATH.
janet main.janet # run program
./janet_modules/bin/mdz # run a binary or script installed from a dependency

(That would create the usual tree (bin, lib, include) under that janet_modules directory.)

Environments

Janet has a notion of “environments”. An environment is a Janet table of symbols (functions, variables, constansts) mapped to metadata and a value.

See (pp root-env), where, for example, you’ll see, for example, 'os/clock mapped to its value which is a C function.

When you import something like (import ./foo) that makes a new environment and saves it into the ’modcache table, then merges the values in that table into the current environment, along with a prefix.

Environment Variables

Janet uses JANET_PATH to know where to look for janet modules that you import (it overrides the Janet syspath).

You can programmatically see JANET_PATH via:

(os/getenv "JANET_PATH")

Core Janet functions

In the repl, to see all the current dynamic bindings, run (doc).

To see all the top-level (not in a module) functions in Janet, see misc (top-level bindings).

See also:

repl> (all-dynamics)
repl> (all-bindings)

You could also look in the src/boot/boot.janet file. Or even try:

# To print out the list of them:
(printf "%m" (filter |(not (string/find "/" $)) (all-bindings)))

# Or, to put the docs for those into a file:
(spit "./doc.txt"
      (with-dyns [:out @""]
        (each s (filter |(not (string/find "/" $)) (all-bindings)) (doc* s))
        (dyn :out)))

Modules

When using jpm (the Janet package manager), to install and use local packages (in your ~/janet tree):

export JANET_PATH="$HOME/janet"

(put that into your ~/.bashrc)

Pretty Printing

Use the function pp. You can change the format via the :pretty-format dynamic variable, e.g. (setdyn :pretty-format "%.20M")

Config file

To read in a config file:

(-> "config.janet" slurp parse)