lang — Code Generation Templates
The lang template type generates source code in any target language. The body uses a set of structural directives that map to code concepts: packages, classes, methods, fields, and control flow. The chosen generator translates these to the target syntax.
Generator Import
lang templates require a generator import. The import declares an alias that becomes the format name.
use KotlinGen as kotlin
use JavaGen as java
use TypescriptGenerator as ts
The format name in the brackets must match the alias.
lang [kotlin] entity(pkg: String, cls: String) {
pkg $${pkg}
impl[data class] $${cls} { }
}
lang [kotlin, java] service(pkg: String, cls: String) {
pkg $${pkg}
impl[interface] $${cls}Service {
func find(id: Long): $${cls}
}
}
Directives
Inside a lang template body, directives map to structural code elements. pkg declares the package or namespace for the generated file.
lang [kotlin] entity(pkg: String, cls: String) {
pkg $${pkg}
impl[data class] $${cls} { }
}
impl declares a class, interface, or object. The modifier in brackets controls the keyword or annotation used.
lang [kotlin] repo(pkg: String, cls: String) {
pkg $${pkg}
impl[interface] $${cls}Repository {
func findById(id: Long): $${cls}?
func save(entity: $${cls}): $${cls}
func delete(id: Long)
}
}
func declares a method inside an impl block.
lang [kotlin] service(pkg: String, cls: String, rec: String) {
pkg $${pkg}
impl[class] $${cls}Service(
val repo: $${rec}Repository
) {
func findAll(): List<$${rec}> {
return repo.findAll()
}
func save(entity: $${rec}): $${rec} {
return repo.save(entity)
}
}
}
var declares a field or property.
lang [kotlin] config(pkg: String) {
pkg $${pkg}
impl[data class] AppConfig(
var host: String = "localhost",
var port: Int = 8080
)
}
comment emits a line comment in the target language.
lang [kotlin] entity(pkg: String, cls: String) {
pkg $${pkg}
comment: Generated — do not edit
impl[data class] $${cls} { }
}
raw emits a line of text verbatim — no directive parsing, no substitution.
lang [kotlin] imports(pkg: String) {
pkg $${pkg}
raw: import com.example.base.BaseEntity
raw: import jakarta.persistence.*
}
spec Fragments
A template marked spec produces a fragment (inner content) rather than a complete file. Use spec templates to compose larger templates via includes.
lang [kotlin] field(name: String, type: String) spec {
var $${name}: $${type}
}
lang [kotlin] entity(pkg: String, cls: String, fields: List) {
pkg $${pkg}
impl[data class] $${cls} {
<[ renderFields(fields) ]>
}
}
func renderFields(fields: List): List {
let out = List.create()
for (f in fields) {
let name = Map.get(f, "name")
let type = Map.get(f, "type")
let out = List.push(out, field(name, type))
}
return out
}
Escaping
Use $$ to produce a literal dollar sign in the output. Use $$ to escape braces. The pattern $$ followed by an opening brace prevents substitution: $${ name } renders literally as ${ name } in the output. Prefix a line with raw: to emit it verbatim without any directive or substitution processing.
lang [kotlin] template(pkg: String) {
pkg $${pkg}
raw: val raw = "$${literal}" // output: val raw = "${literal}"
raw: return $$value // output: return $value
}
Inline Includes
The <[ call() ]> syntax splices another template's output at that position inside the template body.
lang [kotlin] method(name: String, body: String) spec {
func $${name}(): String {
<[ bodyLines(body) ]>
}
}
lang [kotlin] cls(pkg: String, cls: String, methods: List) {
pkg $${pkg}
impl[class] $${cls} {
<[ renderMethods(methods) ]>
}
}
Full Example
A Quarkus repository interface generated for each model entity.
use TLang.Generator
use TLang.File
use TLang.Leaf
use KotlinGen as kotlin
lang [kotlin] repository(pkg: String, cls: String) {
pkg $${pkg}.repository
raw: import io.quarkus.hibernate.orm.panache.PanacheRepository
raw: import jakarta.enterprise.context.ApplicationScoped
impl[@ApplicationScoped class] $${cls}Repository :
PanacheRepository<$${cls}> {
func findByName(name: String): $${cls}? {
return find("name", name).firstResult()
}
}
}
model {
set User { pkg: "com.example", cls: "User" }
set Product { pkg: "com.example", cls: "Product" }
}
func main(): String {
let model = Leaf.model()
for (k in Leaf.keys(model)) {
let e = Leaf.get(model, k)
let pkg = e.pkg
let cls = e.cls
let code = Generator.generate(repository(pkg, cls))
File.write("output/" + cls + "Repository.kt", code, true)
}
return "done"
}