Compiler code generation strategies other than string templating

(The question is not really specific to Rust. Asking here since a quite a few FMs here seem to be familiar with PL programming and, anyways, the tooling/platform used in this case is Rust.)

I am attempting to write a small DSL which emits (compiles to?) SQL DDL statements. I am using pest-parser to generate the parser. This parser is used to transform code in the DSL into Rust data-structures (structs). The data in these structs is then used to emit the target code using askama templates which are pre-defined.

The approach is working fine but it is getting tedious with lots of if, else branching and looping as I extend the language with more capabilities.

What are ways in which I can better handle code-generation keeping maintainability and ability to extend in perspective?

You could build the Rust code as an AST and then render that to a string. See syn and quote.

It will be great if you can elaborate? Just to be clear: neither the source nor the target language is Rust. Rust is the "glue language" in that it reads the source language and transforms it to the target language.

Oh oops. I misread your post. I thought Rust was the target language.

My point still stands but you'd need to write a Rust implementation of the target language's AST.

Alternatively, using someone else's AST crate might be a viable option. sqlparser's AST types seem to have implementions of Display that can write out queries/statements.

1 Like

Thanks! This is almost what I am doing as of now. The main difference being the authors of sqlparse have used the write! macro whereas I am using a full blown string template library.

And not surprisingly, the authors there have similar problem as noted in the comment at the top of the function linked in your post. :sweat_smile:

// Clippy thinks this function is too complicated, but it is painful to
// split up without extracting structs for each Statement variant.

Nevertheless, will investigate further into transforming my structs into their AST.

1 Like

@17cupsofcoffee Thanks! It turned out be a solid suggestion. I just need to transform between trees. This is cleaner and way less prone to bugs than custom conditionals or templates. :+1:

The flow now looks like:

  • DSL is parsed into a local AST used for semantic validation
  • The local AST is then transformed into sqlparser::ast::Statement
  • Then all that is needed is format! to generate the query

A shout-out to the people (not sure if they hangout here) behind the library sqlparser as well. It's pretty neat and structured in a way that enables such a use case very elegantly even though it's not the main goal of the library.


This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.