Status: Authoritative Specification Version: 2.0.0 Last Updated: 2026-07-26 Related Documents: 05 AST Design · 09 Runtime Design · 11 Interpreter Design · 14 Error Codes
The semantic analyzer processes the AST, validating scopes, resolving identifiers, constructing the symbol table, and issuing deprecation warnings. It runs in two passes: Pass 1 hoists top-level declarations; Pass 2 validates all statements.
A lexical Scope Frame contains symbol references. Name resolution maps every identifier node to its matching declaration. Hoisting in Pass 1 pre-registers:
- Top-level
dofunction declarations - Top-level
classdefinitions - Top-level
constdeclarations
This allows forward references to functions declared later in the file.
The following 10 rules are frozen and authoritative for TechScript 2.0:
The first assignment to an identifier in a scope declares it. No make, let,
or var keyword is required or allowed in canonical 2.0 code.
name = "Alice" # declares 'name' in current scope
age = 30 # declares 'age'
Use of
make/let/varemits TSW1001 and is stripped at compile time.
Identifiers declared with const cannot be reassigned. Attempting to do so is a
compile-time hard error (TSE0302).
const MAX = 100
MAX = 200 # TSE0302: Cannot reassign `const`
A declaration in an inner scope may shadow an outer scope identifier. This is allowed but emits TSW2002 (Variable shadows outer scope).
x = 10
do example()
x = 99 # TSW2002: 'x' shadows outer scope
end
Functions capture the value of outer scope variables at the time of the function call (copy semantics for primitives; reference semantics for objects). Lambda expressions capture the enclosing scope lexically.
Variables introduced inside a for/loop/repeat block are scoped to the
loop body. They are not accessible after the loop ends.
for item in list
total += item
end
say total # ok — total was declared outside
say item # TSE0300: Undefined variable 'item'
The error variable in a catch block is scoped exclusively to that block:
try
throw "problem"
catch err
say err # ok
end
say err # TSE0300: Undefined variable 'err'
Class fields without an explicit initializer are automatically set to null.
No separate constructor initialisation is required.
class Point
x = 0 # explicit default
label # implicitly null (TSW2001 if never assigned before use)
end
Using send (or the deprecated return/give) outside a do function body is
a compile-time hard error (TSE0312).
send 42 # TSE0312: `send` outside function body
Integer division by the literal 0 is detected at compile time when the
divisor is a constant expression. At runtime it raises TSE1010.
Reading a variable that has not yet been assigned in the current scope is a
compile-time error (TSE0300). Variables are not auto-created on read.
say missing_var # TSE0300: Undefined variable 'missing_var'
The semantic pass issues TSW warnings for all deprecated syntax patterns that
the parser preserves (to support backward compatibility). Key triggers:
| Trigger | Code | Canonical replacement |
|---|---|---|
build/fun/function keyword |
TSW1002 |
do |
make/let/var keyword |
TSW1001 |
plain assignment |
return |
TSW1003 |
send |
model keyword |
TSW1013 |
class |
if/elif keyword |
TSW1007 |
when/else when |
while keyword |
TSW1008 |
repeat |
import/from keyword |
TSW1009 |
use |
each keyword |
TSW1010 |
for |
attempt keyword |
TSW1004 |
try |
give keyword |
TSW1005 |
send |
none literal |
TSW1011 |
null |
f"..." string |
TSW1012 |
$"..." |
std.io.println(x) |
TSW1014 |
say x |
| Unused variable | TSW2001 |
(remove or use) |
| Variable shadows outer scope | TSW2002 |
(rename or intentional) |
When errors or warnings are found, they are gathered in the diagnostics vector.
- For name typos, Levenshtein distance generates suggestions ("Did you mean X?").
- Deprecation warnings never set
has_errors = true— they are non-blocking. - TSE errors set
has_errors = true— compilation halts before code generation.
- Deprecated Keyword Parsing: The semantic analyzer processes deprecated keywords
(e.g.
build,if,model) via their lowered canonical equivalents. No behavioural difference exists between canonical and deprecated forms at runtime. - TSW Warnings Are Non-Blocking: All
TSWcodes produce warnings but do not prevent program execution. This preserves backward compatibility for the 2.x series.
Run tsc migrate . to auto-convert TSW1001–TSW1013 patterns. Remaining warnings
can be found with tsc lint .. examples/compat/ files are intentionally exempt.
- v2.2: Optional type annotations — the semantic analyzer will validate annotated parameter types against call-site argument types.
- v3.0: Optimizations will leverage type analysis records to emit optimized native instruction sequences.