Skip to content

linabutler/quasiquodo

Repository files navigation

Quasiquodo

Compile-time quasi-quoting for typed languages.

crates.io Build status Documentation

Quasiquodo is a family of Rust macros that parse TypeScript and Python strings into correct-by-construction syntax trees at compile time.

Instead of building syntax trees by hand:

let ts = TsType::TsUnionOrIntersectionType(
    TsUnionOrIntersectionType::TsUnionType(TsUnionType {
        span: DUMMY_SP,
        types: vec![
            Box::new(TsType::TsKeywordType(TsKeywordType {
                span: DUMMY_SP,
                kind: TsKeywordTypeKind::TsStringKeyword,
            })),
            Box::new(TsType::TsKeywordType(TsKeywordType {
                span: DUMMY_SP,
                kind: TsKeywordTypeKind::TsNullKeyword,
            })),
        ],
    }),
);

let py = Expr::BinOp(ExprBinOp {
    node_index: AtomicNodeIndex::NONE,
    range: TextRange::default(),
    left: Box::new(Expr::Name(ExprName {
        node_index: AtomicNodeIndex::NONE,
        range: TextRange::default(),
        id: Name::new_static("x"),
        ctx: ExprContext::Load,
    })),
    op: Operator::Add,
    right: Box::new(Expr::NumberLiteral(ExprNumberLiteral {
        node_index: AtomicNodeIndex::NONE,
        range: TextRange::default(),
        value: Number::Int(Int::ONE),
    })),
});

...Quasiquodo lets you write:

let ts = ts_quote!("string | null" as TsType);

let py = py_quote!("x + 1" as Expr);

Getting Started

Quasiquodo provides language-specific crates, each with their own macro and documentation:

The quasiquodo umbrella crate re-exports quasiquodo-ts behind the ts feature flag, enabled by default. quasiquodo-py depends on Ruff, which isn't published to crates.io, so it must be added as a separate Git dependency.

How It Works

The Quasiquodo macros expand into pure Rust block expressions—no runtime parsing, just construction code.

When one of these macros runs, it replaces #{var} placeholders with syntactically appropriate stand-ins, so that the result is valid source code in the target language. It then parses that source with the language's parser, and extracts the requested output type from the AST. If the source contains invalid syntax, the macro reports the error as a compile-time diagnostic.

Quasiquodo then unparses the AST, turning each node into a Rust expression that constructs the equivalent node in your program. Along the way, it replaces the stand-ins with the bound variables. The result is Rust code that builds the AST directly.

Contributing

We love contributions!

If you find a case where Quasiquodo fails, generates incorrect output, or lacks an output kind you need, please open an issue with a minimal reproducing macro invocation.

For questions or larger contributions, please start a discussion.

Quasiquodo follows the Ghostty project's AI Usage policy.

Acknowledgments

Quasiquodo builds on:

  • Ruff, whose parser and AST make quasiquodo-py possible.
  • SWC, whose parser and AST make quasiquodo-ts possible, and whose quasi-quotation macro for JavaScript inspired Quasiquodo's design.

About

Compile-time quasi-quoting for typed languages in Rust.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages