Skip to content

Advanced

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

Advanced Topics in CDTk

This page explores advanced topics in CDTk, including multi-target compilation, error handling, models, and writing custom validation rules. These features enhance the flexibility, robustness, and usability of your compilers.


Multi-Target Compilation

Multi-target compilation allows you to generate output for multiple target languages or formats in a single compilation pass.

When to Use:

  • You want the same source language to transpile into multiple output formats (e.g., C, Python, JavaScript).
  • You want code generation and related tasks (such as linting or debugging comments) to happen simultaneously for multiple outputs.

Defining Multi-Target Mappings

In CDTk, you define a MapSet for each target language:

// Mapping for C
class CMapping : MapSet
{
    public Map AssignmentNode = "int {variable} = {value};";
}

// Mapping for Python
class PythonMapping : MapSet
{
    public Map AssignmentNode = "{variable} = {value}";
}

// Mapping for JavaScript
class JavaScriptMapping : MapSet
{
    public Map AssignmentNode = "let {variable} = {value};";
}

Configuring Multi-Target Compiler

Use .WithTargets() to specify all the mappings for your targets:

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

Accessing Results by Target Name

After compilation, you can access each target's generated output via result.Outputs:

var result = compiler.Compile(sourceCode);

if (result.Success)
{
    Console.WriteLine("// C Output:");
    Console.WriteLine(result.Outputs["C"]);

    Console.WriteLine("// Python Output:");
    Console.WriteLine(result.Outputs["Python"]);

    Console.WriteLine("// JavaScript Output:");
    Console.WriteLine(result.Outputs["JavaScript"]);
}
else
{
    Console.WriteLine("Compilation failed.");
}

Best Practice: Consistent Mapping Names

Ensure that:

  1. MapSet variables are named clearly (e.g., CMapping, JavaScriptMapping).
  2. Target names specified in .WithTargets() match user expectations (e.g., "C", "Python").

Using Models for Semantic Transformations

Models in CDTk allow semantic enhancements and transformations to be applied to the Abstract Syntax Tree (AST). This provides a powerful mechanism to perform intermediate processing beyond tokenization, parsing, and code generation.

Defining a Model

A model extends the base Model class and explicitly declares the data it requires (e.g., rules, AST, diagnostics).

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

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

    public override object Build(object input)
    {
        if (input is AstNode astNode)
        {
            Console.WriteLine($"Processing Node: {astNode.Type}");
            return new { TransformedData = astNode.GetString("name") };
        }
        return input;
    }
}

Integrating Models into MapSet

Models can be tied directly to your MapSet:

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

Example: Semantic Transformation via Models

Assume an AST node for a variable incorrectly includes a reserved prefix. The model can sanitize the name dynamically:

class VariableModel : Model
{
    public override object Build(object input)
    {
        if (input is AstNode node && node.Type == "VariableDecl")
        {
            var name = node.GetString("name");
            return name.StartsWith("_")
                ? new { ProcessedVariable = name.Substring(1) }
                : node;
        }
        return input;
    }
}

Benefits of using models:

  • Customizable transformations for specific node types.
  • Decouples semantic logic from mapping templates.
  • Enables dynamic adjustments based on AST structure.

Error Handling in CDTk

CDTk uses a robust diagnostics system to catch, report, and handle errors during all compilation stages.

Stages of Error Handling

  1. Tokenization Errors:
    • Reported during lexical analysis (e.g., when input text doesn’t match any token).
  2. Parsing Errors:
    • Occur when tokens violate your grammar rules.
  3. Validation Errors:
    • Semantic errors detected via custom validation logic.

Adding Errors Programmatically

You can report errors programmatically within models, rules, or validation contexts:

ctx.Report(
    DiagnosticLevel.Error,
    $"Variable '{variable}' not declared.",
    astNode.Span
);

Error Severity Levels

  • Info: Informational messages.
  • Warning: Recoverable issues.
  • Error: Prevents further compilation.
diagnostics.Add(Stage.SemanticAnalysis, DiagnosticLevel.Warning, "This is a warning.");
diagnostics.Add(Stage.LexicalAnalysis, DiagnosticLevel.Error, "Critical error encountered.");

Writing Custom Validation Rules

Custom validation rules are useful for enforcing semantic constraints that grammar alone cannot handle.


Adding Validation Logic

Attach custom validation logic to a rule via .Validate():

new Rule("Assignment", "@Identifier '=' Expression")
    .Returns("AssignmentNode", "variable", "value")
    .Validate((ctx, node, token) =>
    {
        var variable = node["variable"]?.ToString();

        if (!ctx.IsDeclared(variable))
        {
            ctx.Report(DiagnosticLevel.Error, $"Variable '{variable}' not declared.");
        }
    });

Validation Context (ctx)

The validation context provides:

  • Scoping Information: Check variable and type declarations.
  • Diagnostics Reporting: Add warnings or errors programmatically during validation.

Conclusion

These advanced topics unlock the full potential of CDTk:

  • Multi-target compilation simplifies producing multiple outputs from a single source.
  • Models bring semantic adjustments and transformations into your compilation pipeline.
  • Error Handling ensures robust feedback for developers and users.
  • Custom validation adds semantic awareness to your compiler.

Explore these features to handle more complex and diverse requirements in your compilers.

Clone this wiki locally