Domain Specific Languages #3 | From Syntax to Structure: Generating Data Models

Intro & Quick Recap

In the previous posts:

Now that we have a working syntax, it’s time to represent it in code.

Why Data Structures Matter

The DSL syntax is just text — it needs structure before it becomes useful. That’s where data models come in. They serve as the backbone of the language, bridging the gap between the written syntax and the C# code we’ll eventually generate.

Think of them as the abstract syntax tree (AST) for our DSL — the structured representation of everything we write.

Designing the Core Data Model

We’ll start small and build only what we need for now:

  • TypeDefinition → represents a type (e.g., Book)
  • PropertyDefinition → represents a property (e.g., Title text)

Example in C#

 1public class TypeDefinition
 2{
 3    public string Name { get; set; }
 4    public List<PropertyDefinition> Properties { get; set; } = new();
 5}
 6
 7public class PropertyDefinition
 8{
 9    public string Name { get; set; }
10    public string Type { get; set; }
11}

Mapping Syntax → Data Model

Let’s revisit our Book definition:

1Book {
2    Title text
3    Author text
4    Pages number
5    Lendable yn
6}

This DSL snippet can be represented in C# like this:

 1var book = new TypeDefinition
 2{
 3    Name = "Book",
 4    Properties =
 5    {
 6        new PropertyDefinition { Name = "Title", Type = "text" },
 7        new PropertyDefinition { Name = "Author", Type = "text" },
 8        new PropertyDefinition { Name = "Pages", Type = "number" },
 9        new PropertyDefinition { Name = "Lendable", Type = "yn" }
10    }
11};

Why This Matters

These data structures form the foundation of the Abstract Syntax Tree (AST). They’ll make it easier to:

  • Parse DSL syntax into structured objects
  • Generate code from those structures
  • Validate syntax and enforce rules
  • Build tooling around the language

In short, this is where our DSL starts coming to life.

Closing

With these core models in place, we now have a structured representation of our syntax — the first tangible bridge between the DSL text and executable C#.

In the next post, we’ll take the next step: generating real C# types from these definitions.

See you there.