EasyAM 2 Language Spec
NOTE: This spec is evolving as the app is being coded. Check the GitHub repository for the latest spec.
- 1 Design Philosophy
- 1.1 Readable without processing
- 1.2 Line-based compilation
- 1.3 Indentation for clarity only
- 1.4 The Six Types of text
- 1.4.1 Freeform text
- 1.4.2 Compiler Directive
- 1.4.3 Compiler directive with item
- 1.4.4 New Item in Markdown List Format
- 1.4.5 Tags
- 1.4.6 Markdown New Item + JoinType + NewItem
- 1.5 Implied Language Rules
- 1.6 Programming Thoughts
Provide a zero-training system that easily organizes conversation notes, becoming more useful the more the user understands the rules.
Readable without processing
All notes are taken in plaintext format. Anything should compile into -- something. If nothing else, just concatenate.
File order is important.
No complex constructs in data entry. (Reporting is a different matter entirely)
EasyAM compiles line-by-line.
There is a context that is updated as the lines are processed. The context is last item and current join type.
At the top of each new file the context resets.
Indentation for clarity only
For the most part, the compiler does not care in which column lines start. (We're stuck with caring in certain circumstances, outlined below)
The only exception (kinda) for that is Freeform/Markdown. Since the markdown parser _does_ care which column things start on, if you start a new section of markdown text on column X, any subsequent freeform text that starts at greater then column X will have the first X spaces stripped off, as if column X were column 1 and the text was flush left. If the indentation _decreases_ on a line to X-n or something, then the "new" left side will now by X-n. If it increases, nothing happens, since we don't know why it may be increasing.
There's also a situation where you have a section, then items, then a jointype, then new jointype items. In this case, indentation can tell you whether new subsequent items are new joins or continuing with the previous section items. New jointype items cannot have children, because then tracking indentation becomes a nightmare.
The Six Types of text
Default format. Anything in markdown+ format. Capture what column it starts on in order to allow markdown to be indented while still working correctly If the column decreases in subsequent lines, adjust to new starting column (see above). If it increases or stays the same, ignore the change. It is probably markdown-related.
Text on a line by itself that sets the context for any future items.
With the exception of tags, which are prefixed with the # or @ character, Compiler Directives are always in ALL CAPS, in order to distinguish them from the rest of the notes
There are four types of compiler directives:
Compiler Section Directive
This gives the Structured Analysis model "location" for any subsequent text -- until a new Section Directive is met
There are default Structured Analysis locations for any not provided. The defaults are BUSINESS, BEHAVIOR, ABSTRACT, and TO-BE. (This means that an item list just by itself would default to user stories)
Section Directives can be relative to whatever the previous directive was. So you can have a BEHAVIOR tag (which would default to BUSINESS BEHAVIOR ABSTRACT TO-BE), later you might have a REALIZED tag, which would only replace the ABSTRACT tag, leaving the others in place
Compiler Tag Directive
Tags are for reporting and data synchronization only. They do not affect the operation of the compiler aside from that.
(PoundTags and NameValueTags) PoundTags are like Twitter tags. #important_stuff, #verycool, and so forth
NameValueTags have values. @dogcount=8, @status=done
Compiler JoinType Directive
Creates a new join type for all future list items making them types of that join to the last item added.
Join Types have to be at the same indentation level as the last join type for this section, if there has been a jointype. If not, they need to be at the same or greater indentation as the last item added for this section, if there was an item. If there's no item, they need to be at the same or greater indentation level as the Section Directive. This is for clarity's sake.
Join types that are at a greater indentation level than the previous join types for this section are either a warning or an error, as they might indicate that future joins belong on things they don't (see below)
USER STORIES (Section heading. Anything in a markdown list format after this is a new/referenced item in this section) * Grandpa (New item Grandpa. He's a USER STORY because of the heading above) * Dad PARENT Grandpa (new item Dad, join PARENT, reference item Grandpa. jointype PARENT is forgotten) * Mom PARENT Mother-in-law (new item, join, new item. jointype PARENT is forgotten. Also Mother-in-law. Last added item is Mom) CHILDREN (new join type by itself, signifying to remember the join type. Any list items now at this indentation or greater will be children of Mom) * Mary (new markdown item. Creates or references the item Mary and gives it a parent of Mom) * Sue (new markdown item. Creates or references the item Sue and gives it a parent of Mom) * Mary (Note we don't care if Mary is mentioned again. Just references previous Mary. They're all the same Mary.) QUESTION: Mary, Mary, why does your garden grow? (New jointype. GOES ON Mom, not Mary! Compiler should provide a warning - error?- that the indentation is misleading. You can't continue nesting down. Once you have a jointype with new items, any future jointype is a sibling of that jointype not a child of any of those items. If you have a lot of questions about Mary, or Mom and Mary's relationship, make a separate section) Why did they have kids with such bland names? (freeform text. Associates with last section item added, not last join item added. In this case, Mom) * Oscar (Oscar has less of an indent than Mary and Sue, indicating that he's a User Story, not a join item. Forget all about any join types. Go back to NO_JOIN_SIBLING)
If no jointype has been encountered, the default jointype is NOJOIN_MAKE_SIBLING_ITEM, which means either make a new item or freeform text. There is no join relationship implied for any new text. (Joins only apply for future text that's a list item. For free text, it attaches as a child of the last item added on a line by itself (in the item-join-item format, this would be the first item)
Once a new JoinType Directive happens, the join type changes but the parent item remains the same Once a jointype happens, pay attention to the column number. future items at that column number or greater are new types of that join. Future items at less than that column, no matter what the column number reset the jointype and are new items for the last section (or the default section)
Section directives and Section New Items reset jointype to NOJOIN
Compiler directive with item
Both a section directive and a new/referenced item are provided on the same line.
Compiler section directive with item
- makes a new item in that section. The directive is not remembered
Compiler namespace directive with item
- doesn't mean anything. Just a new namespace for rest of file
Compiler tag directive with item
- tags that particular item wherever it's found in the current section
Compiler join type with item
- creates a new join of that type to the last created/referenced item. forgets join type
Any markdown lists underneath this are considered child items. See below.
New Item in Markdown List Format
Creates new/references items in the last section previously identified. If no section directive has been used in the file so far, then the parent is project root using the filename as a tag and the section type is assumed to be Business/Abstract/Behavior.
New Section Item
New item for whatever section we're in.
New Joined Item
New join for the last join type. Can't have this without a Compiler Jointype Directive somewhere previously. If it's a new item, it's a joined item if there was a jointype directive and this item begins at the same indentation or more. Otherwise new items are section items
Two items on a line with a jointype between them
If there's a join type and no section (such as an empty file with a TO-DO list), then the new/referenced items are hooked up to the root item as children
List in markdown list format.
If there has been a jointype directive on a line by itself since the last section, then each item is a child of type jointype to whatever the last item added of that section type was. If there's been a section and no join type, then each item is a new/referenced item of that section
If there was no last item added, the parent is the file/project root. If there is no item added Markdown list item. A list of things join to the last item based on the current join type. Join type defaults to Parent-Child but can be set by a compiler directive. Join type resets to Parent-Child with each new section heading.
The tagging system is the key to making Info-Ops work alongside systems of any degree of complexity. With tags, you can associate people, tags, and values to model items.
Unlike all other compiler directives, you can have multiple tags on the same line. This is to facilitate brevity.
Pound Tags '#'
Assign a flag to all following items.
Name-Value Tags '&
Associate a name-value pair to all following items
Mention Tags '@'
Like many systems, the @ tag is used to identify people
Tag Modifier '+'
The plus sign at the end of a tag is used to tell the compiler to continue adding tags with this name. Without it, tags with this name are replaced.
Tag Reset Combination '#@' or '@#'
Tags are only good until they're replaced or the file ends. To reset them early, use the Tag Reset Combination.
Markdown New Item + JoinType + NewItem
A new item which both adds/references the item and adds a one-item join with another added/referenced item. The jointype is not remembered after that line for future new items. (as opposed to a jointype directive on a line by itself, which is remembered and applies to any future/subsequent new item lines (at least until a new directive comes along)
The jointype is remembered as a parent item, not as a compiler directive. So 'Jim CHILDOF Ness' on a line creates or references the two items (in reverse order, the second being created or referenced before the first one). Then it joins the two. Finally that join becomes a parent for any subsequent text
In this fashion, comments, notes, questions, and so forth can be created about the joins themselves
Certain jointypes can be the parent of certain other ones. There needs to be a truth table.
Implied Language Rules
- Markdown lists cannot be used in the text for an item. Instead they'll create new child items.
- If your provide detailed sub-details about an item, you have to provide a new section heading for the next item. Otherwise any new markdown list items in the subsequent text don't know what to attach to.
- Markdown lists/markdown text can be be nested? A list (items) can have comments, then sub-lists, with more comments, and so-on. As long as it's not a compiler directive, that should work. ???
- For Joins, they are directional. There's a LHS and a RHS. Parent-Child is the root type, with the parent "pointing" to the child. Everything else is a specialized type of that
- This means in many cases, the generic parent or child might suffice, with the compiler making the inference to the specific type based on the kinds of items involved (if the items already exist). In other cases not so much
- It also means that a join type can only point into an item with the same or more detail as it has, more tags, more namespaces, etc. So while a root System Abstract Behavior with a "dans/team1" namespace can have child behaviors in the "dans/team1/sprints" namespace, it can't have them in the "dans" namespace. This is to prevent some gnarly collisions and loops otherwise. (And of course you can't point higher in the pyramid. A System Abstract could never have a Business Realized as a child)
- The same item _can_ exist in multiple places with different tags applied, of course, as the tags are for reporting/external sync only. Once tags are added/replaced, they are added/replaced universally for that item throughout the model. So a team might have the final file in their build being their sprint stories with tags for status. That build is created and some of the results sent off to the PM tracking system. The same build with a new last file might have tags for the documentation team. That would involve a new build with new outputs. File order matters, and tags should be added/used with that in mind.
- Tags do not transfer automatically across joins. If a Sys/Beh/Abs item has 3 tags and creates 3 new kids, they don't have the tags. Think of tags like attributes on an html element. (Should EAR/query engines use a form of XPath? )
- This also means that the same item can exist in different namespaces (and with different tags??) and be considered two separate items. This makes sense from a BigCorp standpoint when dupe terms and phrases will probably be all over the place
Figure out the type of text first. Create a vector with text type, source location (for later debugging), and original text.
Processing precedence for text type: it's a directive (or directive/item), it's a markdown list type. Everything else is freeform/markdown. That should be enough for processing.
The riskiest so far might be the markdown translating either into an item or a join, then doing that with nested stuff.
Compilation would just involve taking the previous vector and adding last item and join type, then building the tree.
"Parent", being the universal join type, should work with any parent that already exists. We can figure out the exact relationship name based on the types of items involved. But not for new items. In that case it's just the same item type.
Because of that, every new item needs a dupe/new check. Every new item needs a model DAG check.