Coding 2022-09-21
All right, let's see what I can manage for the Earley parser setup. I'm focusing on how to represent the rules, which is basically the following structure:
- symbols are either nonterminals or terminals.
- terminals are token types, and this might finally be what convinces me to try to wire up enum and class stuff.
- nonterminals are keys in the rules table, where the corresponding values are ordered tables of key arrays mapped to semantic actions.
- semantic actions are just callbacks that take the corresponding matches and return something, which is considered to be the value of whatever matches.
Well then. If I think I need to combine enums and classes, let's see how that looks...
There are some other uses of enums that would be simplified if I could figure out some way to pass arguments to the constructor.
The conclusion that I ultimately come to is that my current enum implementation is placing too much effort on semantic minimalism in the calling context. It can express one style of things very concisely, but it's very difficult to deviate from this.
I'm going to try prototyping something that requires a little more syntax, but should work better with the general code base.
Hm, something's not clicking for me, and I think I need to work through some logic. There are basically several different ways to assign values to the members of an enum:
- The value is a function of just the member's name
- The value is a function of the member's position in the overall sequence of members
- The value is a function of arbitrary data associated with the member
Now, if I want to keep up with my motif of "use iterators a bunch", I could say "instead of a table, the enum constructor should take an iterator, that produces indices, names, and optionally values; if the value is absent, it uses the name". Then, I can split the current syntactic sugar into a table that accumulates names into an array, a normal table, and applying iterator combinators over existing iterators.
Then, the question is, what combining this decomposed concept with the class code looks like.
So, the New Enum doesn't take an argument, it just returns a table that can be called, exactly once. This table, and the return value of calling it, is the enum. It needs to be smuggled into the class creation function, so it can be marked as the type of the instances that will be created when it is called, but it needs to be delegating to the original constructor.
- Create the enum constructor
- Allocate a local to hold the original class constructor
- Write a function to store the constructor in the local, and return the enum constructor
- Add this constructor to the class creation arguments, and then return the resulting class, which is actually the enum constructor (which is actually the enum)
- The caller must now invoke the constructor with an iterator that provides triples of the form index, name, {args}
I guess it would kind of make sense for the enum constructor to set itself up like an ordered table, so that the opairs function I wrote can iterate over its members in order.
So, here are the things I need to write:
- Helper function to create a table that adds names in order, and can optionally associate values to those names
- New enum module that is based around a callable-once table that takes an iterator
- Prove these out by replacing the existing enum usages; write any necessary helper functions
- New enum class module that properly combines classes and the new enum
- Update the usages to switch to the class-based enum
Sadly, I was a bit out of it today, so I've once again just got planning, and I don't feel like trying to actually care out these plans right now. We'll see how tomorrow goes.
Good night.