Skip to content
Kavachकवच

Tagged Literals

● Intermediate5 minBefore this: Packages, Modules: pubSpec 10.15

A package can give text a meaning the compiler checks: sql"…" is a Query, and a misspelled keyword in it is a compile error, not a failure in production.

A package declares a tag with literal: its name, the type a literal of it makes, and the function that checks its text.

pub literal name: T check f language "x"
syntax: Kavach code

Here the package pg declares sql. A Query's text isn't pub, so outside pg a Query comes only from a sql"…" literal:

use pg
use pg.{sql}

fn main() {
    const recent = sql"select id, item from orders where owner = $1"
    print(pg.text_of(recent))
    const paid = pg.sql"update orders set paid = true where id = $1"
    print(pg.text_of(paid))
}

The program ran and printed:

kavach run

select id, item from orders where owner = $1update orders set paid = true where id = $1
src/main.kav: Kavach code, then what running it prints
  • T is a record whose first field is a String. The literal's value is a T holding its text; its other fields take their defaults.
  • The tag is written right before the quote, with no space: sql"…" after use pg.{sql}, or pg.sql"…" through the package.
  • language "sql" is optional. It tells editors which language to colour inside the literal, as the window above does.

Checked when the program is compiled

The compiler runs the checker on each literal's text. Each problem it gives is reported at its place in the literal: an error, or a warning when its warning is true.

use pg.{sql, text_of}

fn main() {
    const all = sql"select * from orders"
    const recent = sql"selct id from orders where owner = $1"
    const paid = sql"""
        updte orders set paid = true
        where day = current_date
        """
    print(text_of(all))
    print(text_of(recent))
    print(text_of(paid))
}
src/main.kav: Kavach code
terminal
kavach run src/main.kav
warning: sql: `*` gets every column, even ones added later (name the columns you need)
 --> src/main.kav:4:28
  |
4 |     const all = sql"select * from orders"
  |                            ^

error: sql: a query starts with select, insert, update or delete (is `selct` misspelled?)
 --> src/main.kav:5:24
  |
5 |     const recent = sql"selct id from orders where owner = $1"
  |                        ^^^^^

error: sql: a query starts with select, insert, update or delete (is `updte` misspelled?)
 --> src/main.kav:7:9
  |
7 |         updte orders set paid = true
  |         ^^^^^

The checker gives a LiteralProblem for each mistake. Every program has the type; it needs no use:

/// One problem a tag's checker found (built in, every program has it).
pub type LiteralProblem {
    pub at: Int                // a character index into the text
    pub length: Int = 1
    pub message: String
    pub hint: String = ""
    pub warning: Bool = false
}
std.literals: Kavach code
  • at counts characters of the text as written, from 0; length is how many the mark covers.
  • In a literal over lines, at counts the text the checker gets, with the indentation the lines share removed. The problem is shown on its own line, as updte is above.
  • The checker runs while the program is compiled, so it must be pure: fn(text: String) -> [LiteralProblem], with no ! and no uses (capabilities). One that reads a file is refused.
  • A checker that panics or runs longer than a second is a compile error that names the tag.

The text is raw

Inside a tagged literal, \ and { are characters like any other: no escapes and no interpolation, so values can't be pasted into it. Values go in separately, as $1 does in SQL. Three quotes let a literal span lines, as other text does:

type Query {
    text: String
}

literal sql: Query check check_sql

fn check_sql(text: String) -> [LiteralProblem] {
    []
}

fn main() {
    const q = sql"select name from files where name = '{name}' and dir = 'C:\new'"
    print(q.text)
    const long = sql"""
        select id, item
        from orders
        """
    print(long.text)
}

The program ran and printed:

kavach run raw.kav

select name from files where name = '{name}' and dir = 'C:\new'select id, itemfrom orders
raw.kav: Kavach code, then what running it prints
tested

Text known only when the program runs

Inside its package, code may still build a T from any text. A function that does so for text known only when the program runs, such as a migration read from a file, is marked audited fn. kavach audit lists each call of it, as it lists reveal and unsafe:

use pg.{sql, text_of, unchecked}

fn main() {
    const recent = sql"select id from orders where owner = $1"
    print(text_of(recent))
    const table = "orders_2026"
    const copy = unchecked("select id from {table}")
    print(text_of(copy))
}
src/main.kav: Kavach code
terminal
kavach run src/main.kav
select id from orders where owner = $1
select id from orders_2026
kavach audit
unsafe code:
  nothing
revealed secrets:
  nothing
audited calls:
  src/main.kav:7  unchecked(…)
capability use:
  src/main.kav:3  fn main: Console
  • Generated tests (tests from types) don't make a T from made-up text. A function that takes one is tested through its example clauses and test blocks, which write literals.
  • Joining two literals, sql"…" + sql"…", is not part of this version.