Grammars and Structures

We’ve been busy getting a couple of different things done. These will show up in the next releases of the core Fabulator gem and the grammar gem.

Grammars

The following test grammar works.

This is a little different than what I mentioned in the previous post. Tokens are the same, but the rules are very different. They borrow some ideas from the Perl Parse::RecDescent module with a little Perl 6 thrown in.

None of the rules are anchored, so they will skip any leading text until they find something that matches.

The ‘something’ rule will match any sequence of letter-number-letter and return a structure representing the matches. For example, matching ‘a1c’ will result in ./LETTER equalling ‘a’ and ‘c’ and ./NUMBER equalling ‘1’.

The ‘other’ rule will match the same sequence as the ‘something’ rule, but instead of naming the resulting values LETTER and NUMBER, it will use ‘a’, ‘b’, ‘c’ as the names (the := construct). In the case of matching against ‘a1c’, the result is ./a = ‘a’, ./b = ‘1’, ./c = ‘c’.

Things start getting interesting with the ‘or’ rule. This will match any sequence of one or more ‘other’ rules followed by one or more LETTER tokens.

Finally, the ‘ooor’ rule will match one or more ‘other’ rules that are separated by commas followed by one or more LETTER tokens.

We’ll start getting modes and additional quantifiers working next.

Structure

We’ve had the Fabulator::Action class for a while for defining new actions, but structural elements have still been hand-coded with a lot of duplicated code. Today’s work changes that.

The first thing is that in the action lib class that defines all of the components of the library (and we’ll probably be changing ‘ActionLib’ to ‘TagLib’), you specify that an element is structural like so (borrowed from the core library):

Each of these can be used in an action or structural class as a structural element instead of an action.

For example, the view element class is defined as follows (minus some run-time stuff):

Parameters (the ‘param’ element):

By default, the contained structural elements are stored in an instance variable named after the element, but pluralized (e.g., ‘constraint’ elements will be stored in @constraints). By default, this is an array. It can be a hash if the ‘:storage => :hash’ option is set. If no ‘:name => :method’ (for whichever method is appropriate) option is given, it defaults to the ‘name’ method to determine the key for the hash. If two structural elements are assigned to the same variable, they are combined instead of one overwriting the other.

This gets us a little closer to being able to have libraries or packages as useful concepts in the Fabulator+Radiant system.