nienor

nienor

17 devlogs
68h 36m
•  Ship certified
Created by kpm

An optimizing compiler for a lisp dialect targetting the uxn virtual machine.

Read a blog posts:
- https://krzysckh.org/b/Homegrown-closures-for-uxn.html
- https://krzysckh.org/b/Implementing-greener-threads-by-putting-uxn-in-your-uxn.html

The background image is called "uxn.crew.jpeg". As of my knowledge it was drawn by Rek Bell. Distributed by Devine Lu Linvega on wiki.xxiivv.com. Used under the BY-NC-SA4.0 License.

Timeline

added typing rules - a way to create types with value constraints,

consider this:

(define-type ZeroOrOne)
(define-typing-rules
(Number n is ZeroOrOne <=> (or
(eq? n 0)
(eq? n 1)))
(Bool is ZeroOrOne)
(ZeroOrOne is Number))

this creates a type ZeroOrOne, which will only be able to hold a value 0 or 1. other values should result in an error thrown by the compiler,

consider this function, right after the code i showed beforehand:

(define-signature f ZeroOrOne -> Number)
(define (f x) x)

it is basically a self or I function, but it does type conversion. since every ZeroOrOne is a Number, it can be freely converted that way, but because only Numbers 0 and 1 are ZeroOrOne, all invocations of f that are not (f 0) or (f 1) will error out. (i mean - they may error out, the typechecker is nowhere near good enough to do symbex to catch every single possible errors - it's a rather uncomplicated type checker)

Update attachment
kpm
kpm
4h 48m 2 days ago

the typechecker is now much smarter, now it can detect invalid return types of functions based on their body vs what signature was provided.

consider this:

(define-signature f Number -> String)
(define (f x)
x)

(define (main)
(f 10))

the compiler now is able to infer that f called as (f 10) will not return a string, but a number, and will throw a compile-time error

Update attachment

Ship 6

0 payouts of shell 0 shells

kpm

5 days ago

kpm Covers 2 devlogs and 10h 40m
kpm
kpm
4h 50m 5 days ago
Update attachment
kpm
kpm
5h 50m 6 days ago

i used quite a lot of brain power on this
- added deeper typechecking (more on that later)
- added -M to test macroexpand/optimize combo

consider this:
```
(define (g x)
(string-append x x))

(define (f x)
(g x))

(define (main)
(f 1))
```

the typechecker is now able to throw an error at compile time saying it is impossible to call string-append at 1, as the type is Number, while String is required (see the screenshot)

Update attachment

Ship 5

1 payout of shell 108.0 shells

kpm

12 days ago

kpm Covers 3 devlogs and 8h 28m
kpm
kpm
4h 15m 12 days ago
  • removed nigeb, the hack that implemented begin. it's now a builtin handled by the compiler,
  • automatically add type declarations to some functions based on their arity (this is rather stupid, it always assumes a type to be Any. it might also sometimes be wrong, for example if a function would return nothing, it still assumes it's an Any -- fixable)
  • added CI builds for windows
  • fix typechecking for tailcalls and fast tailcalls
  • add with-gensym for macros that need gensyms
  • change macros that use pus! to functions, so stack following will later be easier in the type checker
  • rewrite loopn so it doesn't use the stack explicitly, rather being a thread-unsafe mess
  • fir LTH in threaded test
  • fix constant folders for < and > as i changed them to functions
Update attachment
kpm
kpm
1h 29m 17 days ago

Added more type checking, it now accepts type signatures and will yield errors on invalid args passed to functions. Still a lot of work needs to be done on that, as right now it only can detect types if they are known in the exact place a function call takes place, so for example:

(define-signature f Number -> Number)
(f abc) ; <- this will error out
(let ((v abc))
(f v)) ; <- this will not error out, yet it should

Update attachment
kpm
kpm
2h 43m 17 days ago

Started experimenting with type checking. As of right now i can declare a functions' type and make sure that - when called as an argument - it will always return a value, as void functions as arguments cause ub (possibly stack underflows).

Update attachment

Ship 4

1 payout of shell 102.0 shells

kpm

17 days ago

kpm Covers 4 devlogs and 7h 37m
kpm
kpm
1h 5m 19 days ago
  • added multiple scheme functions: append, map, reverse
  • added memory freeing counterparts: append/, map/, reverse/
  • documented manual memory allocation, i don't think i'm going to add gc anymore. this is out of the scope of this project
Update attachment
kpm
kpm
3h 9m 20 days ago

added command line arg support, which was tricky, so it works via a callback called by (call-with-command-line ...) which accepts a lambda of 1 arg which is a list of strings. i've fallen into many traps set out by myself from the past which included a shitty allocator that can be un-stable-d by writing a byte out of bounds. but hey, wcyd, at least it was fun---ish

Update attachment
kpm
kpm
1h 55m 20 days ago
  • added failure reporting to the test runner
  • fixed defvar syntax

(defvar foo 0 1) → (defvar foo 1), it still maps to alloc!, but with extra steps to en-sugar-ify the syntax

Update attachment
kpm
kpm
1h 27m 20 days ago
  • added lists
  • added named let-loops
  • started implementing very experimental GC
Update attachment

Ship 3

1 payout of shell 30.0 shells

kpm

21 days ago

kpm Covers 1 devlog and 3h 28m
kpm
kpm
3h 28m 21 days ago
  • Add support to the console vector in the prelude
  • After some local time spent with `act' add working CI on github that tests every commit against t/
  • Add configurable uxnemu in the test runner
Update attachment

Ship 2

1 payout of shell 196.0 shells

kpm

29 days ago

kpm Covers 1 devlog and 14h 47m

demo:
* added uxn5 as an emulator
* sent patches to uxn5 mailing list regarding invalid obj references
compiler:
* string=?
* cond
* arity checking
* include libraries at compile-time
* 'symbols
* structs, packed structs
* fix malloc (of course; again)
* fix lambda rewriting
* show perf data when compiler is called with -V
* add bunnymark & tests to the web demo
* add thread test (https://krzysckh.org/b/Implementing-greener-threads-by-putting-uxn-in-your-uxn.html)
* add TCE on top of TCO (delete function frame on tail non-recursive calls -- _tailcall! & _tailcall-fast!)
* generate symbol tables for debuggers with -s
* add constant folding for more operations

Update attachment

Ship 1

1 payout of shell 182.0 shells

kpm

about 2 months ago

kpm Covers 4 devlogs and 14h 40m

after fighting with clang --target=wasm32 for literal hours, writing lots of js simulating a real environment i was finally able to create a ghetto demo website demonstrating how the compiler works. i might refine it later. for now it can compile / disassemble files. It's just a web wasm frontend. If you can, please use the normal compiler.

Also i have spent a lot of time going through a weird bug just to realize my js bump malloc is not aligning pointers. big oops

https://pub.krzysckh.org/nienor-web-demo/

Update attachment

added call-with-lines, uf2 font drawing routines, realloc, memcpy, strlen, varvara file IO (read-file, write-file), {key,button}-pressed, keypress vector, the compiler now alloc!s inline strings (there's no need to do that manually now), fixed dead code elimination for alloc! (it no longer deletes functions that are referenced only in _alloc! expressions). started working on a web demo

Update attachment

well i've worked much more than the counter shows here, just on a machine without hackatime. i've re-written the allocator because i found a fatal flaw that literally made it go boom on certain allocation sequences. i've added some utility functions, signed 16bit arithmetic emulation.
I also got heavily hackernews'd - my blog post was on the main page for some time, and my web server really struggled, as it's a tiny vps with like 300 megs of ram. in 3 hours i got twice as many requests as in the entirety of last year (only from stats from people without adblockers). feels kind of surreal.

Update attachment

what has been up to now:
- basic compilation phases & code generation
- some peephole optimizations
- tail call optimization
- closure generation (https://krzysckh.org/b/Homegrown-closures-for-uxn.html)
- runtime memory allocation (implemented malloc+free)
- variables as 1st class citizens (the compiler can recognise multiple label types)

Update attachment