Skip to main content
View

Lexicon & Literals

This page covers the fundamental tokens and literal types in TypR.

Semicolons​

Every top-level instruction ends with ;. The parser tolerates missing semicolons (emitting a SyntaxError::ForgottenSemicolon warning), except for the last expression in a block, which acts as an implicit return value — just like in R.

let x <- 42;        # explicit semicolon
let y <- 42         # tolerated, warning emitted

Literals​

LiteralSyntaxNote
Integer42, -7Lang::Integer
Number3.14, -0.5a decimal point is required for Number; otherwise it's an Integer
String"text" or 'text'single and double quotes are interchangeable; escapes: \" \' \\ \n \t
Booleantrue / TRUE, false / FALSEboth lowercase and uppercase forms accepted
Nullnull / NULLLang::Null — distinct from NA
Missingna / NALang::NA — distinct from null

Literal types​

Literals can also appear as types (singleton types): 3, 3.14, true, "chat" are valid types, more precise than int/num/bool/char.

caution

na/NA and null/NULL are not literal types. The type for missing values is na (not NA); NA is only the R spelling of the na constant. Likewise, null is the type, and NULL is its R spelling.


Identifiers​

KindConventionExampleEnforcement
Variablesnake_casemy_varmust start with a-z or _
TypePascalCaseMyTyperequired for type/opaque/alias declarations
Quotedbackticks`+`, `weird name`useful for naming custom operators

The parser explicitly rejects casing mistakes:

  • let PascalCase <- ... triggers LetInsteadOfType
  • type snake_case <- ... triggers TypeInsteadOfLet

Comments​

# This is a comment

Only # is recognized. There is no // syntax — a .ty file containing // will fail silently (see Known Pitfalls).


Reserved words​

Everything below is generated from the compiler's syntax manifest, the same single source of truth the editor grammars are built from. A keyword that is not in this list is not a keyword: it is an ordinary identifier. See Where these tables come from.

Control-flow keywords​

KeywordMeaning
ifConditional. An expression, not a statement — it returns the value of the taken branch.
elseAlternative branch of an if; chains as else if.
matchExhaustive pattern match over tags, types, records, tuples and _.
forIteration over a collection: for (item in items) { ... };.
whileLoop while a condition holds.
loopUnconditional loop, left with break.
breakLeaves the innermost loop.
nextSkips to the next iteration. The R spelling — TypR has no continue.
returnEarly return. The last expression of a block is already its value, so it is rarely needed.

Declaration keywords​

KeywordMeaning
letBinds a value. The name must be snake_case.
fnTyped function literal — the return type is mandatory: fn(x: int): int { ... }.
functionR's untyped function form. Accepted, and typed as UnknownFunction.
typeTransparent type alias. The name must be PascalCase.
opaqueOpaque alias: the underlying type is hidden from callers.
typeconstructorRegisters a generic record/recursive constructor: typeconstructor Tibble[N] record;.
recursiveKind of a typeconstructor whose parameters may recur: typeconstructor Matrix[N, M, T] recursive;.
interfaceStructural capability: any type carrying the listed functions satisfies it.
recordRecord literal type (record { x: int }), and the record kind of a typeconstructor.
objectThird spelling of the record literal type, alongside list { ... } and record { ... }.
moduleDeclares a module, transpiled to an R environment.
modPulls in a module held in another file: mod utils;.
importImports a module as a whole: import Math;, import Math as M;.
useFour grammars in one keyword: use M::f;, use M::{f, g as h};, use M::*; and the legacy R adapter use("dplyr", c("filter"));.
externOpens a raw R body whose signature TypR checks: extern (x: int) -> int r#"..."#.
embedNamed type embedding on a record field: list { embed coords: Position }. A soft keyword — a field genuinely named embed still parses.

Block heads​

FormMeaning
R { ... }Escape hatch: a block of raw R, left untouched by the transpiler.
JS { ... }Escape hatch for the JavaScript target.
Test { ... }Test block, transpiled to testthat. Test[...] is the file-level form.

Annotations​

AnnotationMeaning
@exportExports the binding from the generated R package (roxygen2 @export).
@pubMakes a module member visible outside its module.
@testableExposes a private member as M$.test_<name> under typr build --test only.
@externDeclares an R function that already exists: @extern stats::sd: (x: [Any, num]) -> num;.
@importFromHoists a roxygen2 @importFrom: @importFrom dplyr filter select;.

Constants​

ConstantMeaning
trueBoolean truth. TRUE is the R spelling of the same value.
TRUER spelling of true.
falseBoolean falsity. FALSE is the R spelling of the same value.
FALSER spelling of false.
nullAbsence of a value (R's NULL) — distinct from na.
NULLR spelling of null.
naMissing value (R's NA) — distinct from null.
NAR spelling of na.

Primitive types​

TypeMeaning
intInteger.
numFloating-point number.
charCharacter string.
boolBoolean.
logicAccepted alias of bool.
AnyTop type — every value satisfies it.
EmptyBottom type — no value satisfies it. The return type of a side-effect-only function.
SelfInside an interface, the type that implements it.

Built-in type names​

TypeMeaning
Vec[...]Native R vector: Vec[num], Vec[#N, num].
Array[...]S3 array with an indexed size: Array[3, int]. Short form: [#N, int].
Tuple[...]Positional tuple: Tuple[int, char], variadic Tuple[T..., U].
Record[...]Bracket record type: Record[name: char], variadic Record[Fs..., id: int].
UnknownFunctionThe type given to an R function TypR knows nothing about.
dataframe[...]{...}Data frame with typed columns: dataframe[#N]{ name: char }.
data.frameR's own data-frame name, accepted as a type.
data__frameThe __ spelling of data.frame — __ becomes . in the emitted R.
list { ... }Record literal type: list { x: int, y: int }.
tuple { ... }Tuple literal type: tuple { int, char }.
df[...]{...}Short spelling of dataframe.

Built-in constructors​

FormMeaning
c(...)R's vector constructor.
seq[...]Sequence literal. The range sugar 1:10 desugars to the R seq(1, 10, 1).
Class(...)Type denoting an existing R class: Class("data.frame", "tbl").
library(...)Declares an R package dependency, as in R.

Type refinements​

FormMeaning
length(n)Refinement, only in a type: [int] & length(5) is a vector of exactly 5 elements. Also takes a range: length(> 0). Glued to (<digit> or (<comparison> — length(x) stays R's function.

Kind sigils​

A sigil prefixes a single-uppercase-letter generic to fix its kind.

ExampleKindSigil
#NNumber#
%RRecord%
@IInterface@
^SString^
?BBoolean?
$LLabel$

Reserved for future kinds and not parsed today: ~, &, !. Each is already a live operator, so writing one as a sigil does not do what it looks like.


Where these tables come from​

TypR's lexemes are described once, in the compiler (components/syntax/mod.rs), and every grammar is generated from that manifest — VS Code, Vim, the playground, and this site's own syntax colouring. The tables above are generated from the very same file, so a keyword cannot exist in the compiler and be missing here, nor survive here after the language drops it: the check runs in CI, in both directions.

What the manifest does not hold is what each lexeme means. Those one-line glosses live in this repository (scripts/syntax-glossary.mjs), and adding a keyword to TypR without writing its line of documentation fails this site's build.