Limits And Errors
Diagnostics include source locations when source text is available.
Only failures registered by an operation contract are recoverable as err values. Fatal diagnostics
are never implicitly converted. See Error Handling for safe
access, try, catch, matching, and runtime rejection.
Syntax Nesting Limit
Section titled “Syntax Nesting Limit”The current TypeScript implementation rejects more than 64 nested syntax levels in a structural path
so malformed or machine-generated input cannot overflow the host JavaScript stack. This covers
indentation blocks; parentheses, brackets, and braces; and nested expression forms such as unary
operators, conditional expressions, catch, and chained operators. Nilakan reports NLK1006 and
suggests splitting the code into functions or intermediate assignments.
This is an implementation resource limit, not a claim that deeper programs are meaningless or a permanent part of the language grammar. The value may change as the implementation evolves.
Runtime limits can be configured through the CLI:
nilakan --max-rounds 100000 program.nlknilakan --max-call-depth 100 program.nlknilakan --max-loop-depth 100 program.nlknilakan --max-prime-depth 5 program.nlkRuntime Limits
Section titled “Runtime Limits”The interpreter tracks:
- attempted commit-loop body rounds across the whole run, default
100000 - function call depth, default
100 - loop depth, default
100 - source prime depth, default
5 - runtime values, limited to 256 container levels and 1,000,000 visited nodes
- repetition results, limited to 1,000,000 collection slots or JavaScript UTF-16 string units
The default source prime-depth limit is 5. Function calls start again at prime depth zero. Runtime
loop depth is different: it counts dynamically active commit loops across function-call boundaries.
Execution tracing has separate capture budgets: by default 5,000 events, 100,000 value nodes, and
2,000,000 UTF-16 text units across the run. Nested speculative trace events consume these budgets
before publication. When a budget is exhausted, tracing stops and the program continues normally;
the playground marks the retained trace as truncated. API callers can configure maxTraceEvents,
maxTraceNodes, and maxTraceCharacters, and receive onTraceTruncated once. These budgets do not
apply when no trace callback is supplied.
One round is charged immediately before each commit-loop body execution. Ordinary assignments, expressions, top-level statements, and function calls do not independently consume rounds. A current-state guard that is initially false consumes no round. A guard that reads primed state speculatively executes the body first, so every speculative round—including the final discarded round—counts. A round that later fails also counts. Nested loops and recursive function calls share the same run-wide counter.
Runtime value and repetition limits are fixed safety bounds rather than CLI-configurable limits. A container is itself one visited node, so a list with 1,000,000 scalar items exceeds the node limit even though its item count alone is within the repetition-slot limit. Process large values in smaller pieces when NLK5006 is reported.
Error Categories
Section titled “Error Categories”| Category | Example |
| ------------- | ------------------------------------------------------------------------ |
| syntax/parse | malformed literal, tab indentation, unsupported slice assignment |
| static | undefined variable, invalid statement placement, duplicate function name |
| type | value does not satisfy a type contract |
| value | registered list.index(x) absence; invalid ord/chr domain |
| key | registered safe dictionary or set operation misses |
| index | registered sequence get, pop, or set misses |
| panic | runtime rejection of an error through an unknown shape |
| round limit | maxRounds exceeded |
| call depth | maxCallDepth exceeded |
| loop depth | maxLoopDepth exceeded |
| prime depth | maxPrimeDepth exceeded |
| runtime value | repetition size, value size, or value nesting exceeds NLK5006 limits |
Static Restrictions
Section titled “Static Restrictions”Major static restrictions include:
- top-level
whileandinitare not supported - top-level
returnis illegal - top-level primed reads are illegal
- primed assignment is legal only inside commit loops
- constant commit-loop guards are rejected
- functions must end with a final
return - non-terminating direct or mutual recursion is stopped by the call-depth limit
- reserved built-in names cannot be rebound
- unknown methods are rejected
Only failures registered by a specific operation are recoverable. The current registered failures are selected value, key, and index errors. Type errors—including invalid operation argument types—and known arity errors remain fatal, as do static, syntax, panic, and resource-limit errors.