Skip to main content
This is the authoritative grammar as implemented in src/sense_lang/parser.py and src/sense_lang/lexer.py. It’s kept in sync with the source, not aspirational — if a construct isn’t here, it isn’t implemented.

Layout tokens

Blocks are indentation, not braces. The lexer produces NEWLINE, INDENT, and DEDENT tokens from leading whitespace (spaces only — a leading tab is a SenseSyntaxError) before the parser ever runs; see Indentation-Sensitive Lexing for the algorithm. Newlines and indentation are both suppressed inside ( ) / [ ].

Full grammar

How the parser resolves ambiguity

A function declaration itself is unambiguous — def is a dedicated keyword, so a call expression (square(5)) is never confused with a declaration. (A leftover square(x) returns Int: with no def — the syntax’s first, since-replaced shape — is specifically detected and raises an error naming def, rather than a generic parse failure; see Functions.) Three other constructs still share a token prefix with something else, resolved by lookahead rather than a dedicated keyword:
A capability_path segment accepts any keyword’s own lexeme, not just IDENT — a capability path (model.anthropic, payment.execute, …) is a free-form dotted namespace label, not a Sense variable, so reserving a word as a language keyword (model, action, tool, …) must not retroactively break an already-established capability name that happens to use it.

Keywords

Every keyword is a plain lowercase word — no reserved punctuation beyond what’s shown in the grammar above.

File extension and comments

Sense source files use .sns. Comments start with # and run to end of line; there’s no block-comment syntax.

Continue

Builtins reference

Every built-in function, with signatures.

Error reference

The error hierarchy and when each one fires.