No description
  • Cool 90.2%
  • Common Lisp 4.7%
  • C 2.9%
  • Just 2.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-11 17:13:53 -05:00
demo nikki1(eval): read defn form 2026-09-11 16:01:31 -05:00
nikki0 nikki1: lay ot plan 2026-08-28 19:48:56 -05:00
nikki1 nikki1: work on linear map 2026-09-11 17:13:53 -05:00
.gitignore demo: manual error throwing for showcasing stack traces 2026-09-05 19:46:37 -05:00
Justfile nikki1: work on linear map 2026-09-11 17:13:53 -05:00
README.md nikki0: docs on versions & add binary 2026-08-28 18:38:49 -05:00

Nikki

First implementation of a LISP-like asm layer for nara.

Plan

To have a series of LISPs bootstraping themselves up

Nikki0

A handwritten binary file that does only this from the input file:

  • ignore whitespace
  • lexes a number - parses it - writes it back as a u8
  • any other byte it just writes it

The minimal way to have some sort of "human readable" assembly

Nikki1

The same as nikki0, written in nikki0 & with this:

  • Comment support: from ; until LF or EOF

Nikki2

Nikki1 is LISP, but now includes conveniences for constants & functions:

  • (defmod <module-name> <major> <minor>): declares the module.

  • (def <name> <constant>): generates a constant in the constant table, where <constant> is:

    • (u64 <value>)
    • (string {[value]}): value may be a raw string or a number (interpreted as u8)
    • (function <module> <name>): a function constant. module and name are string literals.
  • (defn <name> ...): creates a function with the name. All its following values are treated as nikki0 values. :

Nikki1 generates Nikki0 files, so those have to go through to reach a executable vmfile.

Nikki3

Same thing, now with more conveniences:

  • (call <function-name> (...refs) (...values)): calls function-name with ref & value arguments, by copying those to their needed registers

  • (let [...bindings] ...instructions): assigns a name to a reference/value register, like:

(let [name rf1
      age rv1]
  25 name age 0)  ; under the scope, `name` is replaced by `rf1` and so on
  • (if <bool> ...): Easier conditional on the eyes. Still have to compute the condition outside
  • (ifnot <bool> ...)
.eq rv5 rv0 rv1
(if rv5
  do stuff
  do more stuff)

->

.eq rv5 rv0 rv1
.jz rv5 :label-cont
do stuff
do more stuff
:label-cont