Feeling pretty good about this system after sleeping on it. With some small refinements, I don’t even think we’ll need to rely on indentation for structure, we can just add close tags for the very few open ended structures.
Let’s describe the system. At the root of the system, there will be a set of commands that define data objects, identified with an @ symbol. These objects will be parsed and added to a library. These objects can take parameters which are strings or ints, and they can also have children objects, and each object type has its own set of legal children. The children can also take parameters since they are objects too. Once the library is built, we look for all the objects that export back into the library and render those into the parser, repeating until there are none left. Then we can assume the library is complete, and start rendering all of the export objects. When an object is rendered, the global context is carried in and its child objects are loaded into a new context layer. The @render object has a string that is passed through the string parser, and any $ commands are interpreted by the string parser and use data from the context. When the contexts are resolving a name (for example by inserting a block with the $use command), the names are searched from the most local layer out to the global context. Strings are only resolved at the time of rendering, not during library assembly.
—
This was a good description of the mental model, but now I have to implement this in code. The first module must read through text files and extract the data model from the characters. I need to represent the “types” of structures that are allowed, and then I need to use those type definitions to read through the input and generate an actual instance of a data tree. I should probably represent the data structure types with Rust structs. Then, each type should be able to take in a char iterator and parse itself from the chars. This will have a lot of code duplication, because every type will need to be doing the exact same things, just with different number of parameters and a different set of valid children. How can I minimize this?
—
On a walk, I decided that each object type should just be passed the char iterator, and then it can extract its needed strings (or error), and then switch on the string after the next @ to pass it off to the next parser. This should be fairly minimal, with the main “redundancy” being the assembly of the given struct, which I think makes sense.