Skip to content

Mapping

Tristin Porter edited this page Jan 12, 2026 · 4 revisions

Mapping in CDTk

CDTk provides a powerful yet intuitive system for transforming Abstract Syntax Trees (ASTs) into target code. With its strongly-typed, field-based mapping rules and integration with the Model System, CDTk supports generating flexible and efficient outputs for any target language.


What Is Mapping?

Mapping is the process of converting an AST into a structured output, such as source code or data, using predefined patterns.

  • Map: Defines how a specific AST node type is rendered.
  • MapSet: Groups multiple mappings into one cohesive framework.

Example

class Maps : MapSet
{
    public Map AssignmentNode = "let {variable} = {value};";
}

For this AST:

{
    "type": "AssignmentNode",
    "fields": {
        "variable": "x",
        "value": 42
    }
}

The resulting output will be:

let x = 42;

Key Features

  1. Field-Based Mapping: Directly reference AST fields using a clean template syntax ({fieldName}).
  2. Integration with Models: Extend mapping functionality with semantic data from models.
  3. Validation: Ensure all mappings are defined and consistent with your AST structure.
  4. Multi-Target Support: Generate output for multiple languages or formats simultaneously.

Creating and Using a MapSet

A MapSet holds all mappings for your project and ensures modular, clean mapping definitions.

Defining a MapSet

Create a class inheriting from MapSet and populate it with Map fields:

class Maps : MapSet
{
    public Map AssignmentNode = "let {variable} = {value};";
    public Map BinaryOpNode = "({left} {operator} {right})";
    public Map IfNode = "if ({condition}) {body}";
}

Template-Based Code Generation

Placeholders

Placeholders ({fieldName}) substitute AST fields into the output:

public Map BinaryOpNode = "({left} {operator} {right})";

Given this AST:

{
    "type": "BinaryOpNode",
    "fields": {
        "left": "x",
        "operator": "+",
        "right": "y"
    }
}

The resulting output is:

(x + y)

Using Models with Mapping

Models integrate seamlessly with MapSet to extend functionality for semantic transformations.

Defining and Integrating Models

class Maps : MapSet
{
    public MyModel Model => new MyModel(__AllRules, __Ast);
    public Map AssignmentNode = "let {variable} = {value};";
}

Example: Model-Powered Mapping

class MyModel : Model
{
    private readonly __AllRules _rules;
    private readonly __Ast _ast;

    public MyModel(__AllRules rules, __Ast ast)
    {
        _rules = rules;
        _ast = ast;
    }

    public override object Build(object input)
    {
        if (input is AstNode node)
        {
            return new { ProcessedValue = Transform(node) };
        }
        return input;
    }

    private object Transform(AstNode node)
    {
        return node.GetFields(); // Perform semantic transformations
    }
}

Benefits:

  • Decouple intermediate AST processing from template rendering.
  • Simplify mapping logic for complex transformations.

Advanced Mapping Techniques

Fallback Mapping

Guarantee all nodes are handled by defining a fallback rule:

public Map Fallback = "// TODO: Handle {type}";

This flags unmapped nodes for further debugging.


Multi-Target Output

Generate outputs for multiple languages or use cases:

var compiler = new Compiler()
    .WithTokens(new Tokens())
    .WithRules(new Rules())
    .WithTargets(
        ("C", new CMapping()),
        ("Python", new PythonMapping()),
        ("JavaScript", new JavaScriptMapping())
    )
    .Build();

Compile once and access different outputs:

var result = compiler.Compile(inputSource);
Console.WriteLine(result.Outputs["C"]);
Console.WriteLine(result.Outputs["Python"]);
Console.WriteLine(result.Outputs["JavaScript"]);

Validating Mappings

Ensure your MapSet adheres to your defined grammar and AST structure:

var diagnostics = mapSet.Validate();
if (diagnostics.HasErrors)
{
    foreach (var diagnostic in diagnostics.Items)
    {
        Console.WriteLine($"{diagnostic.Level}: {diagnostic.Message}");
    }
}

Validation detects:

  • Undefined placeholders in templates.
  • Missing mappings for certain AST nodes.

Error Handling and Diagnostics

CDTk’s diagnostics aid in debugging mapping issues:

diagnostics.Add(
    Stage.Mapping,
    DiagnosticLevel.Error,
    "Mapping failed at node {type}",
    SourceSpan.Unknown
);

Enable deduplication to reduce redundant diagnostics:

diagnostics.Deduplicate = true;

Best Practices

  1. Always Include a Fallback: Ensure unmapped nodes don’t crash the pipeline:

    public Map UnknownNode = "// TODO: Handle {type}";
  2. Leverage Models: Use models for complex semantic transformations that simplify your mapping templates.

  3. Modularize Maps: Break down large mapping logic into smaller, intuitive templates.

  4. Test Incrementally: Validate mapping outputs with diverse sample ASTs to catch potential issues early.

  5. Use Descriptive Names: Make templates clear and maintainable:

    public Map VariableDeclaration = "let {name} = {value};";

Next Steps

Now that you’re familiar with mapping:

  • Explore Rules: Learn how ASTs are built from rules.
  • Learn Validation: Prevent errors before compilation.
  • Study Models: Add semantic transformations to your pipeline.

Clone this wiki locally