# Pragmas and feature settings A pragma is a set of module-scoped switches that tune how the reader and compiler treat your source. Koskari's optional features -- bracket-call checking, name-resolution mode, layout reading, and so on -- are all controlled through the pragma. A pragma affects only the code that comes after it in the same module, and never leaks into modules you import. ## Setting a pragma Use the `pragma` form. Each setting is a bracketed list: a slash-namespaced key followed by its value(s). A bare `[key]` uses the setting's default value. ```koskari (pragma [compiler/call-brackets 'error] [compiler/resolution 'scheme] [reader/brackets False]) ``` - Values are ordinary expressions, so a literal symbol must be quoted -- `'error`, `'scheme`, `'warn`. Booleans (`True` / `False`), numbers, and strings are self-carrying and need no quote, and a computed value (a variable or call) works too. - The change is forward-only: it applies to everything read and compiled after the form, not retroactively, and not to modules you import. - You may set a pragma more than once; a later setting replaces the earlier one. ## Reading a pragma The same `pragma` form reads the current state: ```koskari (pragma compiler/call-brackets) ; the current value of one setting (pragma) ; the whole pragma object ``` And `help` describes it: ```koskari (help pragma) ; current values + every setting's default (help (pragma compiler/call-brackets)) ; one setting: its signature and doc ``` `(help pragma)` lists the current values alongside every registered setting and its default; `(help (pragma KEY))` shows the accepted arguments and documentation for a single setting. A second read form exists for code that runs during compilation: ```koskari (active-pragma) ; the pragma of the module being compiled (active-pragma compiler/enable-asserts) ; one of its settings ``` `(pragma KEY)` reads the pragma of the module the form is written in. A macro body, though, is a closure over the module that defined it, while it runs while some other module compiles -- so inside a macro, `(pragma KEY)` would answer for the wrong module. `(active-pragma KEY)` reads the pragma the compiler has bound for the current compilation turn instead, so a macro's expansion is governed by the settings of the module using it. Outside a compilation turn no pragma is bound, and `(active-pragma)` answers a default pragma carrying every setting's baseline value. ## What each setting means Settings are grouped by what they affect: the reader (`reader/*`), the compiler (`compiler/*`), and the pragma machinery itself (`pragma/*`). ### Reader `reader/index-brackets`, `reader/dot-attrs`, and `reader/string-segments` govern the three suffix syntaxes; [Grammar](../reference/grammar.md#suffix-syntax) states their rules, and turning one off makes its character inert in the reader. - `reader/brackets`, default on: whether `[ ]` reads into a distinct bracket-pair value that remembers its origin, rather than a plain pair. Off makes `[ ]` and `( )` completely indistinguishable. See [Brackets and the call convention](brackets-and-call-convention.md). - `reader/index-brackets`, default on: whether `data["bar"]` reads as `(item data "bar")`. - `reader/dot-attrs`, default on: whether `obj.value` reads as `(attr obj value)`. - `reader/string-segments`, default on: whether a `-` on a string literal's closing quote continues it into the next quoted segment. - `reader/unary`, default on: whether `-`, `+`, and `~` attached to the front of a name, a digit, or a delimited form read as the unary call: `-x` is `(- x)`, `+x` is `(+ x)`, `~(f y)` is `(~ (f y))`. A signed number keeps its sign as part of the literal, and `->` or a bare operator stay ordinary symbols. - `reader/layout`, default on: whether indentation-based layout blocks are read. Off leaves only s-expression syntax. - `reader/implicit-calls`, default on: whether several values on one layout line form an implicit call. Off makes more than one value on a line an error. - `reader/indent`, default `error`: what the layout reader does with a content line whose indent does not match its block: the first line of a body sets the body's indent, every later line must start at that column, and a top-level line starts at column 0. `error` raises a `ReaderSyntaxError`, `warn` emits a `SyntaxWarning` and reads the line as a sibling form, `ignore` reads it as a sibling form silently. - `reader/fences`, default on: whether triple-backtick fences read into `compile/apply-fence` forms. Off, backtick keeps only its quote and quasiquote readings. See [compile/apply-fence](../reference/specials/compile-apply-fence.md). - `reader/decorators`, default on: whether leading `@` layout lines read as decorators, lowering the decorated form to `compile/decorate`. Off, `@` has no layout meaning and reads through the ordinary atom rules. This gates the reader surface only; `(decorate ...)` remains available as a macro regardless. ### Compiler - `compiler/resolution`, default `koskari`: how writes to names resolve. The value is required, one of: - `koskari` -- strict: a write to an undeclared name is a compile error. - `scheme` -- an unsatisfied write promotes to a module global. - `python` -- a first write creates an implicit local unless declared global. - `compiler/call-brackets`, default `warn`: what happens when a bracket-pair `[ ]` reaches call position, where `( )` is conventionally expected. One of: - `warn` -- emit a `SyntaxWarning`. - `error` -- raise a compile error. - `ignore` -- nothing; the convention is unenforced. A bare `[compiler/call-brackets]` selects `warn`. See [Brackets and the call convention](brackets-and-call-convention.md). - `compiler/stray-colon`, default `warn`: what happens when a bare `:` symbol is compiled as a name. Nothing binds `:`, so this is always a mistake; it most often comes from a layout form half-converted to s-expressions, where the trailing block colon of ``` for-each [x (xs)]: body ``` survives the rewrite as `(for-each [x (xs)]: body)` -- which reads as `(for-each [x (xs)] : body)` and fails at runtime with a `NameError`. One of: - `warn` -- emit a `SyntaxWarning`. - `error` -- raise a compile error. - `allow` -- nothing; the `:` compiles as an ordinary name lookup. A bare `[compiler/stray-colon]` selects `warn`. A trailing colon attached to a name is a keyword, not a stray colon: `(when foo: (foo))` passes the keyword `foo:`, which `compiler/keyword-literals` covers instead. - `compiler/stray-hash`, default `warn`: what happens when a bare `#` symbol is compiled as a name. A `#` prefixes a collection opener (`#(`, `#[`, `#{`) or a syntax quote (`#'`, ``#` ``); followed by a space or the end of the form it reads as the symbol `#`, so `# [1 2]` is a name lookup of `#` followed by a list rather than the list literal `#[1 2]`. One of: - `warn` -- emit a `SyntaxWarning`. - `error` -- raise a compile error. - `allow` -- nothing; the `#` compiles as an ordinary name lookup. A bare `[compiler/stray-hash]` selects `warn`. A `#` that begins a longer name, such as `#tuple`, is not a stray hash, and a quoted `'#` is data and never flagged. - `compiler/keyword-literals`, default `warn`: what happens when an unquoted keyword is compiled as a literal value. A keyword evaluates to itself, which is legal but is more often a typo: `(if foo: 1 2)` tests the keyword `foo:` for truthiness -- always true -- rather than reading the variable `foo`. One of: - `warn` -- emit a `SyntaxWarning`. - `error` -- raise a compile error. - `allow` -- nothing; the keyword compiles to itself. Quote the keyword to state that the literal is what you meant; `'foo:` compiles through the quote special and is always exempt. Two other uses are structural rather than value positions, so they are never flagged: keyword arguments (`(print 1 sep: "-")`) and keyword markers consumed by a form (`(cond [(> x 1) 'big] [else: 'small])`). - `compiler/enable-asserts`, default on: whether `(assert ...)` forms expand to their check. Off, an `assert` compiles away entirely: neither the condition nor the message is compiled or evaluated, mirroring Python's `-O` behavior. The gate is consulted as each `assert` is compiled, so a change affects only the asserts that appear after it. See [compile/assert](../reference/macros/compile-assert.md). - `compiler/bare-control-words`, default `convert`: what happens when a bare `return`, `continue`, `break`, `raise`, `yield`, or `pass` symbol is compiled. These statement words are call forms in Koskari, and their bare forms expand the lone symbol into its call form -- `return` becomes `(return)` -- matching the Python-style spelling. `pass` expands to `(begin)`, a no-op that evaluates to `None`. One of: - `convert` -- expand silently. - `warn` -- emit a `SyntaxWarning`, then expand. - `error` -- refuse with a compile error naming the corrective spelling. Each module answers for its own setting: the gate reads the pragma of the module being compiled, so a strict module does not harden its neighbors. The cost of conversion is that these six names always expand and can never name a variable. See [compile/return](../reference/specials/compile-return.md), [compile/continue](../reference/specials/compile-continue.md), [compile/break](../reference/specials/compile-break.md), [compile/raise](../reference/specials/compile-raise.md), [compile/yield](../reference/specials/compile-yield.md), and [compile/begin](../reference/specials/compile-begin.md) (`pass`). - `compiler/rewrite-limit`, default 32: how many macro-expansion rewrites a single form may take before the compiler reports it as divergent. A macro that expands into an ever-growing form stops with a compile error instead of hanging. An expansion that repeats an earlier form is reported immediately as a cycle, regardless of this setting. `0` removes the limit; legitimate expansion chains are only a few rewrites deep, so the default leaves generous headroom. - `compiler/tco-enable`, default on: whether tail calls are optimized. - `compiler/convert-fast`, default on: whether the compiler lowers local variable access to its fast form. Off disables that optimization. - `compiler/compress`, default off: reserved for a future bytecode compression pass; currently inert. - `compiler/cache-function`, default on: whether function and lambda bodies attach a per-site cache to attribute and method-call instructions, so a repeated access with the same receiver type skips the resolution walk. On is the baseline; the reused code that loops flow through is where it pays. See [Attribute and method caching](runtime-tuning.md#attribute-and-method-caching). - `compiler/cache-expression`, default off: the same caching for top-level module and REPL expressions. Off by default because top-level code usually runs once as it loads, so a cache would not amortize. A bare `[compiler/cache-expression]` turns it on. See [Attribute and method caching](runtime-tuning.md#attribute-and-method-caching). - `compiler/protect-code`, default off: whether each compiled code object that `compiler/pack-module` leaves alone has its bytecode sealed read-only the moment it is built. On, a stray or hostile write to that bytecode faults instead of corrupting the interpreter, at the cost of a full memory page per code object. A bare `[compiler/protect-code]` turns it on. See [Code sealing](runtime-tuning.md#code-sealing). - `compiler/pack-module`, default on: whether the function code a module compiles while it loads is sealed read-only when the module finishes loading. On -- the baseline -- a loaded module's functions are read-only at no per-object cost. Top-level expressions are not covered. ``` (pragma [compiler/pack-module False]) ``` See [Code sealing](runtime-tuning.md#code-sealing) for the model and its tradeoffs. ### Pragma machinery - `pragma/strict-settings`, default on: when on, naming a setting that is not registered is an error; off downgrades it to a warning. - `pragma/strict-watchers`, default on: when on, an error while applying a pragma change is raised; off downgrades it to a warning. ## See also - [Brackets and the call convention](brackets-and-call-convention.md) -- the convention `compiler/call-brackets` enforces. - [Grammar](../reference/grammar.md) -- the reader grammar the `reader/*` settings gate.