The elegance of Lisp with the cold-blooded efficiency of Assembly. Tl;dr: lllm is a DSL for writing Assembly via the Lisp family of programming languages. This is the Janet -first and currently only- implementation.
debris b05333da47 Version change | 2 years ago | |
---|---|---|
examples | 2 years ago | |
graphics | 2 years ago | |
src | 2 years ago | |
test | 2 years ago | |
LICENSE | 2 years ago | |
README.md | 2 years ago | |
project.janet | 2 years ago | |
setup.sh | 2 years ago |
"Lisp is a slow language." --Famous last words
This is the Janet-flavoured implementation of lllm.
It currently focuses on the x64_86 but it would be trivial-esque to add support for other architectures.
Tl;dr: lllm is a family of DSLs for writing Assembly via the Lisp family of programming languages.
This is the Janet -first and currently only- lllm implementation*. Janet is a quite portable and embeddable pseudo-Lisp that is mostly written in standard C99; think of it as Clojure but nicer if you don't like the Java ecosystem, or, better, as Lisp with much easier UNIX-/C-y data manipulation.
lllm in itself is not a "compiler" nor is "compiled" in the standard sense.
It could be said that current compilers are built "top-down", ie. abstractions are first defined, such as arrays, and then bruteforced into fitting the architecture's machine code (or the architecture is built around the compiler, which could promote some amount of language lock-in in the worst cases)
By analogy, lllm would build itself "bottom-up": you begin by defining extremely simple abstractions (such as loops) that directly translate to a list of assembly instructions; then, you begin abstracting those abstractions, raising the level of abstraction higher (print statements, BIOS mode handling, a generic syscall function ...) as necessary, while keeping your code highly flexible and hackable.
Keep in mind lllm (and lllm-janet) is still in its infancy; while it seems to work as intended and is a very simple concept in and of itself, it and its libraries are still heavily subject to change.
With that said, you can use it to generate perfectly valid assembly code and even bootloaders.
(*: There is a systems programming lisp called Ink, which uses extremely similar concepts to lllm to write Assembly, that was independently developped for a Lisp operating system called Yalo; I did not know of it when I came up with lllm, but I find it amazing someone else thought of combining Assembly and Lisp too.)
The REAL (unless declared INTEGER) and official way.
git clone "https://notabug.org/debris/lllm-janet"
cd lllm-janet
jpm build
jpm test
doas jpm install
Alternatively, the setup.sh script should probably do most of the job itself:
git clone "https://notabug.org/debris/lllm-janet"
cd lllm-janet && sh setup.sh
No warranty, though!
Alternatively:
doas jpm install "https://notabug.org/debris/lllm-janet"
The name of the executable is lllma
, which stands for LLLM Assembler. Name may change in the future (lljm
?)
There are plenty of symbols provided as llllm
s (Libraries for LLLM). For development under x64_86 Linux, use lllm/llllnx
. For barebones x64_86 development, use lllm/lllb
.
This section is not complete.
Use (doc symbol)
in the Janet REPL after importing a llllm ((import lllm/llllnx)
for example) for the meantime.
An lllm-operation
(in lllm-janet) is data of this kind:
['operationA 'argA1 ... 'argn]
such that operationA
is a symbol that is equivalent to an assembly operation, argA1
is a argument to that operation, etc...
It will be converted to assembly as the line operationA argA1, ..., argn
.
lllm will transemble data of this kind:
@[
lllm-operation
...
lllm-operation
]
(ie. an array of lllm-operation
s of any length.)
As such, any function or macro that generates a valid lllm-operation
can be used to generate and abstract assembly away. This is where the power of lllm resides.
Inserting an indexable data structure like ["string"]
into an indexable to transemble will escape "string" into assembly code. This is your escape hatch. It's useful for defining odd macros like "$-$$" (though you could use a prefix-infix converter to write (- '$ '$$)
or something).
Also, you'll probably need some x64_86 opcodes cheat sheet like this one , and maybe another for Linux syscalls.
And maybe a guide on x64_86 too.
For OS development and lllm/lllb
, or just a really good introduction to assembly, check out this great tutorial by Daedalus Community.
I have no idea how repository management works. If you want to contribute, please contact me through the community space or directly on Matrix.
We have a space on Matrix here, feel free to join.