Devlog

These are my daily notes and internal conversations during development. They may be helpful to understand the larger context of decisions that were made, and how I learned and explored while building.

Devlog < 2023 < February < 27

| by date | | thread: collect |

Okay, I got the full first draft of this parsing done, and the next thing to do is actually walk through the tree and execute the work it describes. Hopefully this is the easy part…

So, the rough idea for how this will work is that is that at each layer of the tree, we will read through all the child objects and add them to a context. The context can have named blocks of text, and also a way to hold an object and its group links. At the root, we collect all the blocks and add them to the context, and we do the same for every other group of objects. When we step into an object to resolve it, we do the same thing. There are functions that get called from inside a string renderer which resolve from the context. These functions either invoke another renderer, access a value on the active object, or pick the prev/next object along a group thread (and then access a value on that object).

---

Went on a walk and was thinking about this more. Essentially, I think that every object in the tree either adds something to the context, or does some type of function in rendering a string. Most objects just get added to the context, like map, block, match, and the renderers. Some, like @render *do* something, like pass their string to the render function, and provide a resolver for their parent object. Basically, we should step through an entire object first and fill out the context layer, then execute the render. What actually kicks off “something happening” though? I don’t think we can just use render chains, because that doesn’t allow for other actions inside the loops. We can maybe ask an object to resolve itself?

One question ends up being “what is the difference between a function in the string interpolator and an object in the tree?”. Right now, the tree objects only define something that gets added to the context, and the interp functions resolve from the context. If we want to choose objects to render from the tree, we’ll need to be able to select objects from the context from the tree. technically, this is what query does? And while I’m thinking about it, you can’t call any other renderers directly. should you be able to? An object is different from a context, the context is implicit in the data structure, but the object is dynamic. A query is what lets us select objects, and a query is what will allow us to iterate through objects. An object is also really just a different part of the tree… by passing an object to another object, we are just merging two branches into a combined context, and telling one object that it is responsible for resolving. So a render is at the most abstract a pairing of two objects where one is specified as the resolver. Another part of this is that to use an object in a join like this, it must already be in the context, otherwise how would you reference it? So, again, to render something you need a source object, it’s resolving node, and an input object. With this system each object should be self identifying its “resolving” node (i.e. “@export” or similar) and so you can just apply one object to another. If we enforce global name uniqueness, we can just use two names to combine them. `@join “renderer” “object”` will pass “object” into “renderer” and then “execute” which ever self-identifying data node exists on “renderer”. At this point, what is the difference between an object’s values and the data in the context? If we just load the “object” directly into the rendering context, we would lose the additional layer of namespacing ($use for context $self for object) but we gain perhaps a new level of generality (and simplicity)? This isn’t really the point of a DSL, but it’s at least helpful for the thought exercise.

| thread: collect | | by date |