So where does this all leave me? The goal of this tiny language is to make it easy to render collections of structured text. A super generic and approaching general purpose system that I was exploring last night would not make this as simple as the goal, but led to some good ideas about architecture. From a user standpoint, I want it to be easy to access values on the active object when rendering a string, and I want it to be possible to have multiple layers of objects in the context (a tag inside a post). Perhaps when an object gets added to the context, it is added by type. Referencing an object value would be $obj(type)(key) or $next(type)(group)(key). This I think is a sane limitation, because I think it would be rare to want two active objects of the same type at the same time. This also means that we will have objects separated in the context… though if their type is ‘object’ then maybe that makes sense? If the context groups by type, then it might already be “separated”.
Does this mean that the context is grouped by data type? When it parses an object in the tree, its data type (query, map, block, etc) is the bucket it is placed in. This means that some operations can have an implicit type that they operate on, and look in that bucket in the context.
So far, I think this also eliminates the idea of different kinds of renderers. There is just a “renderer” which is passed in each object in a list of objects, either generated from a query or explicitly created as part of an object map. This means that a “@query” should really be generating a “@list” to simplify things. Should a list then also have groups inside it? No, the groups are inherent to the object, any object can have its groups queried. Should every object just automatically have “group” pointers built into them? So each object can be asked $obj(group.next.value)? Or even $obj(group.next.next.value)? We’re really starting to get into a robust and simple system here, if everything is compiled into a tree and the interpolation functions just access tree paths. At this point, the control flow would just be checking for the existence of a path.
---
Ok. So we have this ‘@‘ object tree syntax that defines a tree of strings. At each level of the tree, we collect all of the children into buckets of their type, and this becomes a context. Then, we “execute” the context, which basically means that some of those keywords have a specific meaning and the executor knows to grab those objects and do something with them. When we select an object for execution, we then load all of that object’s children into a new layer in the context.
How do we handle the groups? Groups have two aspects to them. First, they must be assembled and sorted during context building. The second is that any map loaded as an object must have its groups inserted into its tree so that group.prev|next are available. So at each layer we need to create a new vector for any groups that are encountered, fill it with the previous layer’s elements, add any new ones, and then sort it. This seems kinda expensive, but whatever.
At this point, maybe I should just start building to see what new questions arise.