Overview

Discovered fennel pretty recently and thought it’d be pretty neat if I could use it for scripting Norns.


Note: For debugging right now, the Lua script it generates is being logged.

Setup

If you want to try it out here are the steps.

Summary

Matron setup

  • ssh into your Norns and cd into the norns directory
  • Add my fork as a remote git remote add fennel_fork https://github.com/pcvonz/norns
  • run git fetch fennel_fork
  • Checkout the branch matron-fennel from my fork
    git checkout matron-fennel
  • run ./waf clean && ./waf build in the ~/norns directory.
  • Grab a copy of the fennel compiler:
    sudo curl https://fennel-lang.org/downloads/fennel-0.6.0 > /usr/local/share/lua/5.1/fennel.lua
  • [optional] If you want to use Fennel in the REPL, add the flag --fennel to matron.sh:
    ./build/ws-wrapper/ws-wrapper ws://*:5555 ./build/matron/matron --fennel &
  • Creating a new script with the extension .fnl in Maiden should convert it to Lua and run it like a regular norns script.

Maiden setup

  • Navigate to the maiden directory cd ~/maiden/app
  • Run curl -L https://github.com/pcvonz/maiden/releases/download/v1.0.2-fennel/build.tar.gz | tar xz
  • Refresh maiden

Uninstalling

Uninstalling Matron Fennel

  • cd into norns and run
  • Run git checkout main
  • Run git reset --hard origin/main (This will remove any uncommitted changes, best to do a git status to make sure there aren’t any uncommitted files you care about!)
  • ./waf clean && ./waf build
  • Reboot norns

Uninstalling Maiden Fennel

  • Head over to the releases page of Maiden: https://github.com/monome/maiden/releases
  • Download the tar.gz and extract it
  • Replace the ~/maiden/app/build folder with the one from the tar file.

TODO:

  • [x] Run fennel scripts via Maiden
  • [x] Add syntax highlighting to maiden (in progress)
  • [x] Add REPL support via matron (???)
  • [ ] Figure out clean way to have both the regular lua repl and fennel repl available via maiden.
9 Likes

Nice! There is also similar project by @ngwese - https://github.com/ngwese/siren

2 Likes

That’s super cool!
The advantage of using fennel though is that creating bindings to the current monome stuff isn’t necessary since it’s completely compatible with Lua. Translating the norns studies have been a breeze.

Also, I got syntax highlighting working in Maiden (still pretty rough). :rainbow:

3 Likes

I’ve been looking into the possibility of running fennel through the Matron REPL, but I’m not well versed in C (or even Lua for that matter).

Does anyone have any tips, pointers, or a general direction on where to start?

Matron evaluates a line of Lua from the REPL with l_handle_line, which interacts with the Lua C API to put the input line on the stack and evaluate it. A lot of the evaluation code is basically the same as the code for the lua repl that’s part of the main Lua distribution.

It might be that the simplest thing to do here is to have a small script or program which turns a line of Fennel input into a line of Lua and feeds it to matron on stdin. Matron already runs with stdin wrapped by the ws-wrapper program which allows interacting with matron’s stdio over a websocket – this is how the maiden browser app and the maiden repl CLI interact with matron, so you would then just need to have ws-wrapper wrap your Fennel-to-Lua translator.

Cool project!

1 Like

Alright, I managed to get something working with the matron REPL based on @csboling’s advice (thank you!).

Running into some issues now. For example, when trying to write a simple for loop the value that’s returned is nil (instead of printing n):

(for [n 1 5] (print n))

I believe this is happening because the fennel compiler turns that bit of code into this:

for n = 1, 5 do
  print(n)
end
return nil -- <- The problem??

I’m not totally sure.

The second obstacle is the way I’m processing the code from Maiden. I wrote a little Lua script to compile the code:

#!/usr/bin/env lua                                                                                                                                                                 [0/1893]
f = require("fennel")
local lua = f.compileString(arg[1])
print(lua)

And it’s called in C like so:
(pardon the horrendous code, I don’t really program in C. A lot of this was copied :sweat_smile:)

int l_handle_line(lua_State *L, char *line) {
        size_t l;
        int status;
        char *command = "/home/we/Fennel/compile_fennel_string.lua ";
        char *str = (char *)malloc(sizeof(char)*(strlen(line) + strlen(command + 4)));
        strcpy(str, command);
        strcat(str, "\'");
        strcat(str, line);
        strcat(str, "\'");
        FILE* f = popen(str, "r");
        if (f == NULL) {
                fprintf(stderr, "l_handle_line: Failed at parsing fennel.");
                exit(1);
        }
        char *output = NULL;
        size_t len = 0;
        while (getline(&output, &len, f) != -1)
                    fputs(output, stdout);
...
}

The problem I’m running into is if I pass in something that contains ' then that’s going to break the compilation step because the string of Fennel code will be terminated prematurely. Example:

(print "it's not ok")
is basically like running this in bash:
./compile_fennel_string.lua '(print "it's not ok")'

Not an insurmountable problem, but it feels hacky that I have to deal with it.

Ok, collapsing the generated lua to a single line fixed the first problem :upside_down_face:
Peek 2020-09-04 01-08

1 Like

Made some breakthroughs this weekend and a hit another roadblock. I’ll add an update on how to get this running in the original post.

  • For the REPL: I’m now evaluating the incoming string of fennel through the Lua C API.
  • Maiden now supports decent syntax highlighting for fennel. Still could use some tweaks.
  • It’s possible to load both Lua files and Fennel files through Maiden.

I thought it’d be nice to be able to switch the REPL between Lua and Fennel, but I can’t find a decent way to got about this. For now, there is a flag you can add to matron.sh to start the REPL in fennel mode:

#!/bin/bash                                                                                                  
./build/ws-wrapper/ws-wrapper ws://*:5555 ./build/matron/matron --fennel &                                                                               

In the future I might take what I did in lua_eval.c out into a separate program that can be wrapped by ws-wrapper. I think that’s probably the way it should be done :thinking:.

Pretty stoked where it is right now.

4 Likes

This is super interesting, the buzz around lisp has always caught my attention but in the several attempts to get more familiar with it I’ve not really understood why it has this hype as such a good language, maybe some norns apps will give me a change to compare the code and see for myself if and how it offers something more powerful and elegant than a more recent language :slight_smile:

Following this with excitement! Did a tiny bit of Fennel for the Advent of Code last December and liked it!