Tiramisu Docs

Internals

Custom Front-Ends

Build a custom compiler front-end that transforms Tiramisu AST into HTML or any output format.

Custom Compiler Front-Ends

Since the Tiramisu parser produces a generic AST, you can write your own compiler front-end to transform Tiramisu into any output format. This page walks through building a simple Tiramisu-to-HTML compiler.

Getting Started

Install the Tiramisu parser:

bash
bun add @timeleap/tiramisu

Parsing Source Text

Use the parse function to convert Tiramisu source into an AST:

typescript
import { parse } from "@timeleap/tiramisu/src/index";

const source = 'bold { Hello } world';
const ast = parse(source);

The parse function returns a Tiramisu root node containing all the parsed content.

Walking the AST

To compile the AST, walk through its nodes using instanceof checks:

typescript
import {
  Tiramisu,
  Paragraph,
  MixedText,
  PureText,
  FunctionCall,
  Parameter,
  NamedParameter,
} from "@timeleap/tiramisu/src/types/nodes";

function compile(node) {
  if (node instanceof Tiramisu) {
    return node.nodes.map(compile).join("");
  }

  if (node instanceof Paragraph) {
    const inner = node.nodes.map(compile).join("");
    return "<p>" + inner + "</p>";
  }

  if (node instanceof MixedText) {
    return node.segments.map(compile).join("");
  }

  if (node instanceof PureText) {
    return node.text;
  }

  if (node instanceof FunctionCall) {
    return handleFunction(node);
  }

  if (node instanceof Parameter) {
    return node.nodes.map(compile).join("");
  }

  return "";
}

function handleFunction(node) {
  const name = node.functionName.trim();
  const params = node.parameters?.params ?? [];
  const content = params.map(compile).join("");

  switch (name) {
    case "bold":
      return "<strong>" + content + "</strong>";
    case "italic":
      return "<em>" + content + "</em>";
    case "code":
      return "<code>" + content + "</code>";
    case "h1":
      return "<h1>" + content + "</h1>";
    case "h2":
      return "<h2>" + content + "</h2>";
    default:
      return "<div class="" + name + "">" + content + "</div>";
  }
}

Using the Compiler

typescript
const source = `
h1 { Hello World }

This is a bold { simple } example with italic { formatting }.
`;

const ast = parse(source);
const html = compile(ast);
console.log(html);
// <h1>Hello World</h1><p>This is a <strong>simple</strong> example with <em>formatting</em>.</p>

Handling Named Parameters

For more complex functions, you'll want to extract named parameters:

typescript
import { NamedParameter } from "@timeleap/tiramisu/src/types/nodes";

function getNamedParam(params, name) {
  for (const param of params) {
    if (param instanceof NamedParameter && param.name.trim() === name) {
      return param.nodes.map(compile).join("");
    }
  }
  return null;
}

// Usage in handleFunction:
case "link":
  const url = getNamedParam(params, "url");
  return '<a href="' + url + '">' + content + '</a>';

Real-World Example

Tiramisu Docs core (@tiramisu-docs/core) is a complete compiler front-end that transforms Tiramisu AST into Svelte components. It demonstrates handling of all node types, built-in function definitions, custom component resolution, and metadata extraction.