Skip to content

Flexmi: new version of the YAML flavour#222

Merged
agarciadom merged 9 commits into
mainfrom
new-flexmi-yaml
Jun 29, 2026
Merged

Flexmi: new version of the YAML flavour#222
agarciadom merged 9 commits into
mainfrom
new-flexmi-yaml

Conversation

@agarciadom

Copy link
Copy Markdown
Contributor

Closes #21

This PR changes the way we parse YAML, by using yaml.load instead of yaml.compose (using a custom SafeConstructor to track the original locations in the YAML file that the deserialised maps, lists, and their elements come from). This makes it possible to use some nice YAML features like merge tags (<<: *foo) and anchors/references.

It also changes the style to match that of #21. The main features of the new style are as follows:

  • At the root of the document, you can have either a mapping, or a sequence of mappings:
    • A sequence of mappings is turned into <root><elem1/>...<elemN/></root>.
    • A mapping is turned into <__ attributes>...children...</__>. The aim would be to have YAML guess the type based on the names of the features in the future, but for now you can use the $type key to specify the name of the XML element that would be generated.
  • Mapping keys are turned to different things:
    • If a key starts with ? or $, it is turned into a processing instruction (unless it's $type). If it's $nsuri or ?nsuri, it is added as a sibling of the element being built from the mapping. Otherwise, it becomes a child of the element being built.
    • If the value is a scalar, it becomes the value of the attribute.
    • If the value is a list of scalars, it becomes a sequence of XML elements whose text content are the scalars.
    • If the value is a map, it becomes a nested XML element: the tag name is the key, unless the map uses the $type key, in which case that is used.
    • If the value is a list of maps, it becomes a sequence of XML elements following the same rule as above.

This has been enough to pass all the tests in the Flexmi test suite (after rewriting the YAML files). In fact, from my testing, I think $type is usually only needed for the root mapping, and for templates (where the context is harder to control).

@agarciadom

agarciadom commented May 22, 2026

Copy link
Copy Markdown
Contributor Author

I slept on this, and realised it would be possible to simplify the flavour (and avoid $type altogether) if we just assume that we will always have a YAML map at the root, and that the resulting XML document will always have a <_ /> at the root. If we do this, the mapping becomes much more straightforward:

  • Maps become XML elements.
  • There must be a map at the root of the YAML document, which will become an XML <_ /> element.
  • Keys in a map are transformed as follows:
    • A $key: scalar or ?key: scalar pair becomes <?key value?> in the XML element.
    • Any other key: scalar pair becomes key="value" in the XML element.
    • A key: [scalars] pair becomes <key>v1</key>...<key>vN</key> in the XML element.
    • A key: map pair becomes <key .../> in the XML element (the contents of the child are built from map, recursively).
    • A key: [maps] pair becomes <key .../>...<key .../> in the XML element (again, the children are built recursively from each m in maps).

This is much easier to explain, and the YAML docs look pretty natural to me. This is an example of a small Ecore model with an EPackage and two EClasses:

$nsuri: http://www.eclipse.org/emf/2002/Ecore
package:
  name: myPackage
  classes:
    - name: Sport
    - name: Basketball
      supertype: Sport

@agarciadom agarciadom force-pushed the new-flexmi-yaml branch 3 times, most recently from bb9db28 to 9514761 Compare May 22, 2026 05:52
@agarciadom agarciadom added this to the 2.9.0 milestone May 22, 2026
@agarciadom agarciadom requested a review from kolovos May 22, 2026 18:03

@kolovos kolovos left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@agarciadom

agarciadom commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

On further thought, the fact that we cannot repeat keys in YAML means that without $type, we wouldn't be able to replicate this example from the XML flavour:

<?xml version="1.0"?>
<?nsuri http://www.eclipse.org/emf/2002/Ecore?>
<class name="c1">
  <eref name="r1" />
  <eattr name="a1" />
  <eref name="r2" />
</class>

I have pushed a change reimplementing $type and adding a test case for this scenario. The equivalent to the above in the YAML flavour would be:

$nsuri: http://www.eclipse.org/emf/2002/Ecore
class:
  name: c1
  features:
    - $type: eref
      name: r1
    - $type: eattr
      name: a1
    - $type: eref
      name: r2

Note that the use of the features key is irrelevant: $type overrides the names of the XML tags that would be produced (we'll get an equivalent XML document to the above).

If we didn't care about a1 being right in the middle of the two references, we could write a more natural-looking YAML document:

$nsuri: http://www.eclipse.org/emf/2002/Ecore
class:
  name: c1
  eref:
    - name: r1
    - name: r2
  eattr:
    - name: a1

@agarciadom

Copy link
Copy Markdown
Contributor Author

Likewise, for this metamodel:

@namespace(uri="comps", prefix="")
package comps;

class Component {
	attr String name;
	val Port[*] in;
	val Port[*] out;
}

abstract class Port {
	attr String name;
}

class IntegerPort extends Port {}

class BooleanPort extends Port {}

And this XML example:

<?nsuri comps?>
<component>
	<in>
		<integer name="p1"/>
		<boolean name="p2"/>
	</in>
	<out>
		<integer name="p3"/>
		<boolean name="p4"/>
		<integer name="p5"/>
	</out>
</component>

It could be written in the YAML flavour like this:

?nsuri: comps
component:
  in:
    integer: {name: p1}
    boolean: {name: p2}
  out:
    ports:
     - $type: integer
       name: p3
     - $type: boolean
       name: p4
     - $type: integer
       name: p5

Alternatively, to save some space, we could assume most of the out ports are integer ones, and shorten the YAML to:

?nsuri: comps
component:
  in:
    integer: {name: p1}
    boolean: {name: p2}
  out:
    integer:
     - name: p3
     - $type: boolean
       name: p4
     - name: p5

@agarciadom agarciadom merged commit 7a9a40b into main Jun 29, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Making Flexmi YAML flavour more natural

2 participants