Grammar And Language Status
Nilakan is a small language with Python-like tokens, not a Python implementation. Similar spelling does not imply that a Python construct is supported. This page records the accepted surface grammar and the important parser/static-check restrictions in the current release.
The notation below uses ? for optional, * for repetition, + for one-or-more, and | for
alternatives. Newlines and indentation delimit a block; a block may instead contain simple
statements on the header line separated by semicolons.
Program And Statements
Section titled “Program And Statements”program := (function_def | if_stmt | pragma_stmt | simple_stmt)*function_def := "def" NAME "(" parameters? ")" ("->" type)? ":" blockparameters := parameter ("," parameter)*parameter := NAME (":" type)? ("=" expression)?
if_stmt := "if" expression ":" block ("elif" expression ":" block)* ("else" ":" block)?init_stmt := "init" ":" init_blockpragma_stmt := "pragma" NAME ":" NAMEwhile_stmt := "while" expression ":" block
simple_stmt := "return" expression ("," expression)* ","? | NAME call | target ("[" expression "]")+ "=" expression | NAME (":" type)? "=" expression | target "," destructure_tail "=" expression | "(" target "," destructure_tail ")" "=" expression
destructure_tail := (target ("," target)* ","?)?
target := NAME | PRIMED_NAMEPRIMED_NAME := NAME "'" +Parsing is only the first layer. init, while, primed targets, return, nested definitions, and
pragma have placement rules described under Statements and
Commit Loops. In particular, a Nilakan while is always a commit
loop; there is no separate imperative while statement.
Expressions
Section titled “Expressions”From lowest to highest precedence:
expression := conditional ("catch" conditional)*conditional := or_expr ("if" or_expr "else" or_expr)*or_expr := and_expr ("or" and_expr)*and_expr := not_expr ("and" not_expr)*not_expr := "not"* equalityequality := comparison (("==" | "!=") comparison)*comparison := bit_or (("<" | "<=" | ">" | ">=" | "in" | "not" "in") bit_or)*bit_or := bit_xor ("|" bit_xor)*bit_xor := bit_and ("^" bit_and)*bit_and := sum ("&" sum)*sum := product (("+" | "-") product)*product := unary (("*" | "/" | "%") unary)*unary := ("try" | "-")* postfixpostfix := primary (("." NAME call) | subscript)*
primary := NUMBER | STRING | "True" | "False" | PRIMED_NAME | NAME call? | list_literal | brace_literal | parenthesizedcall := "(" (argument ("," argument)* ","?)? ")"argument := NAME "=" expression | expressionparenthesized := "(" (expression ("," expression)* ","?)? ")"The parser can recover a comparison-shaped token sequence containing multiple comparison operators,
but static AST construction rejects chained comparisons with NLK1005. Write
left < middle and middle < right.
Calls support positional and named arguments, with positional arguments first. A direct call suffix
is accepted only as part of a NAME primary; it is not a general postfix, so (str)(1) is invalid.
After a primary, the parser accepts only method calls and subscripts. Parenthesized expressions,
lists, sets, dicts, tuples, calls, and returns accept a trailing comma. Subscripts support indexes
and start:end slices; slice steps are unsupported.
Type Expressions
Section titled “Type Expressions”type := primary_type ("|" primary_type)*primary_type := NAME ("[" (type ("," type)* ","?)? "]")?The recognized scalar names are num, bool, str, and err. Container forms are list[T],
set[T], dict[K, V], and fixed tuples such as tuple[num, str]. See
Type Contracts for validation rules. The parser also accepts empty
type arguments such as list[]. An empty argument list is the same unconstrained container contract
as the bare form list.
Deliberately Unsupported Or Not Yet Implemented
Section titled “Deliberately Unsupported Or Not Yet Implemented”| Construct | Status and replacement |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| for, break, continue | Unsupported. Express iteration as commit-loop state. |
| class, import, modules | Unsupported. Nilakan programs are single files of functions and top-level code. |
| lambda, comprehensions, generators | Unsupported. Use named functions and explicit commit loops. |
| None, null values, bytes | Unsupported. Some Python defaults that require None are therefore unavailable. |
| try/except, raise | Unsupported spelling. Nilakan uses error values, prefix try, and infix catch. |
| chained comparisons | Rejected with NLK1005; join explicit comparisons with and. |
| augmented assignment (+=) | Unsupported. Write a normal assignment or primed assignment. |
| exponentiation (**) | Unsupported. |
| exponent/hex/octal/binary number literals | Unsupported; use decimal integers or fractions. |
| slice steps (a:b:c) | Rejected with NLK1005. |
| nested function definitions | Parsed for recovery but rejected statically. |
| branch-local return | Rejected; every function has one final return statement. |
| direct and mutual recursion | Allowed; non-terminating calls are stopped by the configured call-depth limit. |
| general mutation methods | Methods are pure and return a new value. Raw list/dict index assignment is available in limited statement positions. |
| effectful calls in expressions | Rejected. Call print and transitively effectful user functions as statements. |
“Unsupported” means programs must not rely on the construct. It is not a promise that the construct will be added or keep Python semantics if it is added later.
Example Convention
Section titled “Example Convention”An untitled nlk code fence anywhere in the documentation is a complete executable program and is
run by the documentation test suite. A fence whose title begins with Intentional failure states
and tests the expected diagnostic code written in its title. Fences titled Fragment or
Expression forms are syntax illustrations that explicitly require the surrounding context named in
the title. This convention prevents pseudo-code from being mistaken for a runnable lesson.