Dragon

Keywords

This appendix is the authoritative list of every word the Dragon compiler reserves. It is drawn directly from the lexer's keyword table, so it reflects what the compiler actually treats specially - nothing more, nothing less. Two kinds of word appear here: reserved keywords, which the lexer recognises everywhere and which you can never use as a name; and contextual keywords, which the lexer hands through as ordinary identifiers and which the parser only treats specially in one position - so thread, match, case, and template are still legal variable names anywhere else.

Dragon is inspired by Python, not a superset of it. The keyword set overlaps with Python's by design, but it adds its own (const, static, extern, fire, catch, template) and drops Python words that have no place in a typed, compiled language. Where a word behaves differently in .dr files versus .py files, the difference is noted in the table.

Declarations and storage

These introduce names - functions, classes, and the storage class of a binding. See Functions and Classes.

KeywordMeaning
defDeclares a function or method. In .dr source, a class constructor is the nameless def() { ... }; the __init__ spelling is .py-mode only (both normalise to the same constructor internally).
classDeclares a class: class Point { x: int = 0 }.
lambdaAn inline anonymous function: f: ... = lambda x: x + 1.
constMarks an immutable binding (Dragon extension): const PI: float = 3.14159. Reassignment is a compile error.
staticA class-body field shared across all instances, or a module-level singleton (Dragon extension). Contrast a non-static field, which is a fresh per-instance default.
externDeclares a C FFI binding: extern "C" { ... } (Dragon extension). See FFI.
globalInside a function, opts into assigning a module-level global. Required to write a module global from a function - without it, a bare = or += is a compile error (not a silent new local) - in both .dr and .py. Reading a global needs no keyword in either mode. For rebinding an enclosing function's variable (not a module global), use nonlocal.
nonlocalInside a nested function, opts into rebinding a variable owned by an enclosing function (for closures). Required: without it, a bare = or += to such a name is a compile error - not a silent new local - in both .dr and .py. Reading an enclosing variable needs no keyword; only rebinding does. Blocks (if/for/…) inside the same function are not a boundary and need no keyword. Cannot reach module globals - use global for those.

Control flow

The branching, looping, and jump statements. See Control flow.

KeywordMeaning
ifConditional branch.
elifChained alternative branch (Python spelling, not else if).
elseFallback branch; also the trailing clause on for/while/try.
whileLoop while a condition holds.
forIterate over an iterable: for x in items { ... }.
breakExit the innermost loop.
continueSkip to the next loop iteration.
returnReturn a value from a function.
passA statement that does nothing (an explicit empty body).
withContext-manager block: with open(path) as f { ... }.
yieldProduce a value from a generator function.

Pattern matching

Structural pattern matching. match and case are contextual - the lexer treats them as identifiers, and the parser only recognises them at the start of a match statement / a case clause, so they stay usable as ordinary names. The .dr form uses braces and no colon after the pattern:

match command {
    case "start" {
        print("starting")
    }
    case _ {
        print("unknown")
    }
}
KeywordMeaning
matchBegins a structural match over a subject value (contextual).
caseA pattern clause inside a match block (contextual). An optional if guard may follow the pattern.

Exceptions

Raising and handling errors. See Errors.

KeywordMeaning
tryBegins a block whose exceptions may be caught.
exceptHandles a matching exception type: except ValueError as e { ... }.
catchA Dragon-extension synonym usable in place of except.
finallyA block that always runs, whether or not an exception occurred.
raiseThrows an exception: raise ValueError("bad input").
assertRaises AssertionError if a condition is false: assert n > 0.

Operators that are keywords

These are spelled as words rather than symbols. The logical operators are short-circuiting; in/not in test membership and is/is not test identity. See Expressions.

KeywordMeaning
andLogical AND (short-circuiting).
orLogical OR (short-circuiting).
notLogical negation; also the second word of not in.
inMembership test: x in items. Also drives for ... in.
isIdentity test: x is None. Combines as is not.

Imports

Bringing names in from other modules. See Modules.

KeywordMeaning
importImports a module: import os.path.
fromImports specific names: from os.path import join. Also opens an extern "C" from "..." block.
asBinds an alias: import numpy as np, except E as e, with ctx as c.

Concurrency

Dragon's concurrency keywords are colorless - there is no async/sync function split. See Concurrency.

KeywordMeaning
fireSpawns a green-thread (vthread) task: t: Task[int] = fire work(), or fire-and-forget fire { ... }.
threadA scoped OS-thread block that auto-joins at scope exit: thread { ... } (contextual keyword - only special at statement start).
asyncMarks a function whose call yields a Task[T].
awaitAwaits a Task[T], yielding to the scheduler when the awaiter is itself a vthread. Awaiting a non-Task is a compile error.

Templates

Compile-time text templating. template is contextual - special only when it opens a template { ... } or template[X] { ... } block, and a plain identifier everywhere else. See Templates.

KeywordMeaning
templateOpens a compile-time template block: s: str = template {Hello !{name}}.

Ownership

Three keywords manage a value's lifetime at compile time. See Ownership for the full model, including the three places they are mandatory.

KeywordMeaning
delEnds a value's life early: del buf frees the value on that line and compiles only when the compiler can prove buf is the sole owner (nothing aliased, stored, or captured it - otherwise the error names the escape). Locals only; using the name afterwards is a compile error. Mandatory to close the un-moved path of a conditional move. Also deletes a container entry (del d["key"]), a separate operation with no proof involved.
ownSole ownership. On a field (own _ctx: TlsCtx), the instance owns the value and the generated cleanup releases it when the instance dies - mandatory for fields holding raw resource types like Lock or engine handles. On a parameter and at the call site (def f(own d: T) / f(own d), both ends required), it transfers ownership; the source name is dead after the call.
dubExplicit copy, the only way to mint a second independent owner: mine: dict[str, str] = dub base. The cost sits on the line you wrote. Mandatory to iterate a container the loop body mutates: for x in dub xs { xs.remove(x) }. Non-copyable types (Lock, handle-holding classes) refuse at compile time.

Constants

The three literal values. In .dr source the lowercase aliases true, false, and none are also accepted and mean exactly the same thing as their capitalised forms.

KeywordMeaning
TrueBoolean true (.dr alias: true).
FalseBoolean false (.dr alias: false).
NoneThe absence of a value (.dr alias: none).

Not keywords

A few words that exist in Python (or look like they might be reserved here) are not Dragon keywords, and are perfectly legal identifiers:

WordStatus
Ellipsis, NotImplementedOrdinary names - not reserved (despite appearing in editor highlighting).
match, case, thread, templateContextual only - reserved at one position, free everywhere else.
async, awaitReserved, but do not split functions into colors; every def is awaitable-agnostic.
print, len, range, int, str, …Builtins, not keywords - they live in an outer namespace and may be shadowed by a fresh declaration.