💾 Archived View for tilde.cafe › ~stack › gemlog › 2022-12-11.harn.gmi captured on 2023-07-22 at 17:24:31. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
I really like the interaction of the Forth REPL, and I've written many forths... But at the end of the day, all you have is a Forth, syntactically annoying, and you kind of need to reinvent the wheel every time you want to do anything. On the other end of the spectrum, Lisp is great, but binding to the C infrastructure is a challenge, and you wind up with 100MB of code.
So why not use the C compiler to generate code, but keep a Forth-like interactive environment in which compiled C functions and data live? Actually, not quite: when functions are edited, the new one supersedes the old one, and all callers are automatically updated. And yes, the source for every compiled function is there, to be looked at or edited.
In the end I wound up with something between Lisp, Forth and Smalltalk, but C. There is an image, there is a sources file. There is a REPL - you can debug, list symbols, see the source of symbols, and execute C functions. Or you can invoke an editor and edit functions one at a time. Oh, and you can save the image as a file and restore it later.
harn - an interactive C environment. (c) 2022 StackSmith ...try 'help<cr>', or 'printf("Hello World!\n")<cr>' >
So it's an interactive linker toy. What? When you edit a function, the system wraps some generated includes for visible symbols, and invokes gcc. The resultant ELF object file is ingested; the code or data is yanked out, relocations are permanently recorded along with source. All dependencies are resolved - currently I import stdlib but there will be a generic mechanism for linking to libraries... Stuff is sorted into three segments: code, data, and metadata. Each segment has some magic relocation bits so that referential integrity is always maintained -- even if the functions or data are moved around. It's kind of nuts, but it works.
You see, normally the compiler chugs out the code, the linker statically resolves dependencies, the loader hooks up to the runtime environment, and some more linkage may occur later, dynamically, but really, it's game over when you compile. The code is vitrified. And I want interactivity. I want to start small and beef up the application, testing unfinished code on the command line. I want to build jigs, test ideas, and dick around with my code. Normally with C you get some text files or a big black box. I want everything in between.
Right now, that is all it does. I envision being able to extract applications by tree-shaking, and export C code out to a more standard environment, since it's all there.
And you can write tools - since you can call C code from the command line... The whole system is a debugger...
There are some issues, of course. C is not really meant for this kind of interaction, and compiling a function at a time changes semantics somewhat. But honestly, I don't care - I think of it as a kind of Forth with a decent compiler. Oh, and the old versions are not yet removed after edditing - I need a garbage collector. A day's work. After I sleep. I think I forgot to sleep for a few days...
If you want to take a look at it (and it is rough, and it is a toy!), it's on github (yeah, I know, but...)
https://github.com/stacksmith/harn
I will be writing about it, and writing it...
Oh, the binary is under 50KB. Heh.