At first my plan was to just do something simple, like adding numbers. However, I decided to instead try something a little more useful, so I implemented a map function. I did so in just about the most naive way possible. I walk the tree, look for a specific keyword ('!map') at the start of a list and run some javascript code
if(command.value === '!map') { let array = ast[1] let mapFunction = ast[2] if(array.type === 'atom' || mapFunction.type === 'atom') throw Error() let variable = mapFunction.children[0] let template = mapFunction.children[1] if(template.type !== 'list') throw Error() if(variable.type !== 'atom') throw Error() const replace = (nodes:AST, value: AST[0]):AST=> { if(variable.type !== 'atom') throw Error() let result = [] for(let node of nodes) { if(node.type === 'list') result.push({type:'list', children: replace(node.children, value)} as const) if(node.type === 'atom' && node.value === variable.value) result.push(value) else result.push(node) } return result } output = array.children.map(child => { if(template.type !== 'list') throw Error() return {type: 'list', children: replace(template.children, child)} }) }
I can use this to remove some repetetive structure, and make it easier to add things to pages. It'll work especially well for making index pages of content, like the top level index of this site and the worklog index.
Well a lot. I have to make this generic enough to implement any kind of function. I have to figure out the syntax for generically handling these things.
Most importantly, I currently have a lot of issues stemming from the dual needs to output nice html and text, AND have a clean AST for executing code. The former means I need to leave in formating data like where newlines and such are, while the latter needs no hidden characters or anything.
I could store display information seperately from the AST as metadata around tokens. Or, I could strip away the annoying tokens (newlines and spaces) while processing executable blocks. I'm not sure which is more useful. I probably need to store positions as metadata anyways for good error messages.
I looked over my prompts from my journalling practice (which I really should move over to fancynote soon), and decided to write about the programming tooling that inspires me. I've got a draft sitting here .
It is very much a draft, but it's nice to start writing some longer form things in fancynote.
There was a bug that made inputs that were a single atom that didn't terminate fail in the repl. It turned out to be a bug in the lexer. This led to some gnarly edge-cases when processing partial inputs. It was a simple fix in the parseAtom function.