Feature Parity (Interpreter vs Compiler)¶
This document tracks which Crespi language features are available in the interpreter and in the native compiler. It is intentionally short and practical, so it can guide gap-fixing work.
Legend: Yes = implemented, Partial = implemented but incomplete or missing checks, No = not supported.
Core Language Features¶
| Feature | Interpreter | Compiler | Notes |
|---|---|---|---|
| Variables and constants | Yes | Yes | var, let; let enforces immutability for collections |
| Control flow | Yes | Yes | if/else, while, for/in, break, continue, guard, when |
| Functions | Yes | Yes | Named, default params, single-expression syntax |
| Lambdas and closures | Yes | Yes | Capture works |
| Classes and constructors | Yes | Yes | Primary (with var/let modifiers) + secondary constructors |
| Inheritance | Yes | Yes | : syntax |
| Operator overloading | Yes | Yes | All operators in the reference |
| Extensions | Yes | Yes | Swift-style extensions |
| Extension trait conformance | Yes | Yes | Default methods applied; conflicts error |
| Generics (duck-typed) | Yes | Yes | fn [T] name() syntax for functions; Class[T] for classes |
Pattern matching (when) |
Yes | Yes | With default |
| Built-in functions (61) | Yes | Yes | Unified registry |
| Top-level code | Yes | Yes | Compiler synthesizes main() |
| Language packs (keywords/builtins) | Yes | Yes | Normalized in the lexer |
| Traits | Yes | Yes | Conformance checks + default methods applied in interpreter/compiler |
| Multi-file imports | Yes | Yes | Module loading + explicit symbol lists supported |
| Decorators | Yes | Yes | Applied at runtime; functions/classes only |
| Nested classes | Yes | Yes | nested for static, inner for outer instance (__outer; o.Inner() now lowers via runtime helper) |
| Assignment as expression | No | No | Statements only (by design) |
Syntax and Ergonomics¶
| Feature | Interpreter | Compiler | Notes |
|---|---|---|---|
| String interpolation | Yes | Yes | $name and ${expr} |
| Raw/triple-quoted strings | Yes | Yes | Multiline literals |
| Null coalescing | Yes | Yes | ?? |
| Ternary operator | Yes | Yes | cond ? a : b |
| Automatic semicolon insertion | Yes | Yes | Lexer inserts semicolons on line breaks |
| Visibility modifiers | Yes | Yes | public default; internal = same directory; private = same file; fileprivate = file-scoped |
| Type annotations (syntax) | Yes | Yes | Parsed on vars/params/returns |
| Type checker (optional) | Partial | Partial | Separate pass; opt-in via --check |
| Qualified imports | Yes | Yes | import, import Module { symbols }, import fn, import class |
Operators and Expressions¶
| Feature | Interpreter | Compiler | Notes |
|---|---|---|---|
| Arithmetic operators | Yes | Yes | +, -, *, /, % |
| Comparison operators | Yes | Yes | <, >, <=, >= |
| Equality operators | Yes | Yes | ==, != |
| Logical operators | Yes | Yes | && (AND), || (OR) |
| Bitwise operators | Yes | Yes | &, |, ^, <<, >>, ~ |
| Unary operators | Yes | Yes | -, !, ~ |
| Membership tests | Yes | Yes | value in collection |
| Compound assignment | Yes | Yes | +=, -=, *=, /=; also i++, i-- as statements |
| Indexing and assignment | Yes | Yes | obj[i], obj[i] = v |
| Property access | Yes | Yes | obj.field, obj.method() |
| Function calls | Yes | Yes | f(x) and operator invoke |
Data Types and Literals¶
| Feature | Interpreter | Compiler | Notes |
|---|---|---|---|
| Integers, floats, booleans, null | Yes | Yes | int, float, bool, null |
| Strings | Yes | Yes | UTF-8 text values |
| Lists | Yes | Yes | Literals, indexing, iteration |
| Dictionaries | Yes | Yes | Text-keyed maps |
| Tuples | Yes | Yes | Tuple literals (a, b) |
| Class instances | Yes | Yes | Constructed by calling the class |
| Pattern destructuring | Yes | Yes | Lists/dicts/classes inside when |
Functional and Runtime Behavior¶
| Feature | Interpreter | Compiler | Notes |
|---|---|---|---|
| Higher-order functions | Yes | Yes | Functions as values; extension function types (String.() -> Int) |
| Memoization | Yes | Yes | @memoize and memoize() |
| Tail-call optimization | Yes | Yes | Tail recursion optimized |
| String/list/collection helpers | Yes | Yes | Built-in functions (map/filter/etc.) |
Modules and Resolution¶
| Feature | Interpreter | Compiler | Notes |
|---|---|---|---|
| Module imports | Yes | Yes | import Foo.Bar with optional { symbols } |
| Symbol-specific imports | Yes | Yes | import fn, import class, import Module { symbols } |
| Module path resolution | Yes | Yes | Relative, root, and -I paths; snake_case → PascalCase |
| Module cycles | Yes | Yes | Tarjan SCC detection for init cycles |
Visibility Enforcement & LSP Integration¶
Crespi ensures that public, internal, and private declarations behave the same no matter whether code runs through the interpreter, the native compiler, or the language server.
- The interpreter now runs
MultiFileInterpreter::type_check_modulesduring module loading so visibility failures are reported before execution rather than at runtime.MultiFileInterpreterbuilds a per-module visibility map and resolves imports with the sameinternal/privaterules exposed to the static type checker, keeping the REPL and scripts consistent with the compiled path. - The compiler's module namespace builder mirrors the interpreter's visibility map; HIR lowering (
crespi-codegen::lowering) filters symbol exports using the sameVisibilityhelpers before emitting imports, and the LLVM backend/runtime enforces the resulting APIs during execution. - The external Language Server (crespi-ide-support) uses the same visibility rules to ensure that hover, completion, and go-to-definition only surface symbols that are visible from the import site.
- Tests cover interpreter and compiler layers:
lang/crates/crespi-core/tests/module_imports.rsvalidates interpreter visibility enforcement (public/internal/private imports), andlang/crates/crespi-codegenhas parity tests for compiler visibility errors.
Type System (Optional)¶
| Feature | Interpreter | Compiler | Notes |
|---|---|---|---|
| Type annotations | Yes | Yes | Variables, params, returns |
| Type inference | Partial | Partial | HM-style inference pass; optional, not default |
| Nullable types | Partial | Partial | T? sugar for T | Null in checker |
| Union types | Partial | Partial | T | U in checker |
| Type constraints | Partial | Partial | Numeric/Comparable/Equatable constraints |
| Inheritance-aware assignability | Partial | Partial | Subclass checks in type checker |
Tooling and Platform¶
| Feature | Interpreter | Compiler | Notes |
|---|---|---|---|
| CLI REPL | Yes | No | Interpreter-only REPL and file runner |
| VSCode extension | Yes | Yes | External (crespi-ide-support repo) |
| LSP diagnostics | Partial (visibility-aware) | Partial (visibility-aware) | External (crespi-ide-support repo). Supports diagnostics, hover, go-to-definition, and completions. |
| WASM execution (web) | Yes | No | External (crespi-wasm repo) |
| Language packs | Yes | Yes | Built-in Spanish pack; validator supports custom packs |
Notes and Known Gaps¶
- Type checking: optional; only run when explicitly requested (
--check). - Assignment expressions: not supported (statements only, by design).
Verification Checklist¶
These commands help validate the table above:
# Interpreter + compiler behavior parity for examples
./scripts/compare-outputs.sh
# Includes multi_file entrypoint examples.
# Core interpreter tests
cd lang
cargo test -p crespi-core
# Visibility enforcement and module imports (interpreter + compiler)
cargo test -p crespi-core module_imports
cargo test -p crespi-codegen --lib
# Language pack validation
cargo run -p crespi-langpack -- validate crates/crespi-i18n/packs/spanish.crespilang
Work Items (Current Gaps)¶
- Assignment expressions (by design)
Subsystem Coverage Matrix¶
Each layer—interpreter and compiler—now shares the same visibility predicate. This section maps the visibility story to the files/tests that keep the systems aligned.
Interpreter Pipeline¶
- Entry point:
lang/crates/crespi-core/src/interpreter/multi_file.rs(MultiFileInterpreter::type_check_modules,module_visibility_map, andis_visible) builds the per-module visibility map before execution. - The REPL and script runner use the map for symbol lookup, so private/internal symbols raise errors before runtime.
- Coverage:
cargo test -p crespi-core module_importsexercises public/internal/private imports and qualified access.
Compiler Pipeline¶
- The lowering phase (
lang/crates/crespi-codegen/src/lowering.rs) mirrors the interpreter visibility map when collecting namespace exports and resolving imports. - Compiler visibility tests in
lang/crates/crespi-codegen/src/lib.rsassert the same private/internal restrictions. - Coverage:
cargo test -p crespi-codegen --libruns visibility-focused and namespace-resolution tests, ensuring runtime/compile-time agreement.
Appendix: Full Feature Inventory¶
This appendix enumerates the full language surface to keep the parity table honest.
Syntax Summary¶
- Declarations:
var,let,fn,class,trait,extension,import, visibility modifiers (public,private,internal). - Statements:
return,break,continue,if/else,while,for/in,guard,when. - Expressions: literals, arithmetic/comparison/logical ops,
?:,??, calls, indexing, property access, lambdas (=>), assignment, class instantiation by call. - Patterns: list
[a, b], dictionary{"name": n}, class destructuringPerson { name: n }.
Keywords (Canonical + Spanish Alias)¶
| Category | English | Spanish Alias | Notes |
|---|---|---|---|
| Declaration | var |
variable |
Mutable variable |
| Declaration | let |
immutable |
Immutable constant |
| Declaration | public |
publico |
Visibility modifier |
| Declaration | private |
privado |
Visibility modifier |
| Declaration | internal |
interno |
Visibility modifier |
| Functions | fn |
bloque |
Function declaration |
| Functions | return |
resultado |
Return from function |
| Control | if |
si |
Conditional |
| Control | else |
o |
Conditional branch |
| Control | while |
mientras |
Loop |
| Control | for |
repetir |
For-each |
| Control | in |
en |
Membership / iteration |
| Control | break |
salir |
Exit loop |
| Control | continue |
continuar |
Next iteration |
| Control | guard |
asegura |
Guard clause |
| Control | when |
cuando |
Pattern matching |
| Control | is |
es |
when branch |
| Control | default |
defecto |
when fallback |
| OOP | class |
tipo |
Class declaration |
| OOP | nested |
anidado |
Nested class declaration |
| OOP | inner |
interno |
Inner class declaration |
| OOP | trait |
trait |
Trait declaration |
| OOP | extends |
extiende |
Reserved (use :) |
| OOP | implements |
implementa |
Reserved (use :) |
| OOP | this |
yo |
Current instance |
| OOP | super |
super |
Superclass |
| OOP | operator |
operador |
Operator overloads |
| Modules | import |
importar |
Imports |
| Modules | extension |
extension |
Type extensions |
| Literals | true |
verdadero |
Boolean literal |
| Literals | false |
falso |
Boolean literal |
| Literals | null / nil |
nada |
Null literal |
| Logical | and |
and |
Logical AND |
| Logical | or |
or |
Logical OR |
Operators and Text Aliases¶
| Operator | Description | Spanish Alias |
|---|---|---|
+ |
Add | mas |
- |
Subtract | menos |
* |
Multiply | por |
/ |
Divide | entre |
% |
Modulo | modulo |
< |
Less than | menorQue |
> |
Greater than | mayorQue |
<= |
Less or equal | menorOIgual |
>= |
Greater or equal | mayorOIgual |
== |
Equal | igualA |
!= |
Not equal | diferenteDe |
and / && |
Logical AND | and |
or / || |
Logical OR | or |
?? |
Null coalescing | (symbol only) |
?: |
Ternary | (symbol only) |
Operator Overloads (Class Level)¶
Supported overloads: +, -, *, /, %, ==, !, negate, compare, not, increment, decrement, get, set, contains, invoke.
Built-in Functions (60)¶
Aliases in parentheses refer to the Spanish language pack or English aliases.
I/O and type conversion
- print (mostrar)
- read (leer)
- typeof (tipo_de, alias type_of)
- str (texto, alias string)
- int (entero)
- float (decimal)
Collections (base)
- length (longitud, alias len)
- push (agregar, alias append)
- pop (quitar)
- keys (claves)
- values (valores)
- contains (contiene)
Memoization
- memoize (memorizar)
Strings
- split (dividir)
- trim (recortar)
- uppercase (mayusculas)
- lowercase (minusculas)
- substring (subcadena)
- replace (reemplazar)
- starts_with (empieza_con)
- ends_with (termina_con)
- index_of (indice_de)
- join (unir)
Collections (functional)
- map (mapear)
- filter (filtrar)
- reduce (reducir)
- sort (ordenar)
- reverse (invertir)
- slice (cortar)
- find (encontrar)
- every (cada)
- some (alguno)
- flatten (aplanar)
Math
- abs (absoluto)
- sign (signo)
- sqrt (raiz)
- cbrt (raiz_cubica)
- pow (potencia)
- round (redondear)
- floor (piso)
- ceil (techo)
- truncate (truncar)
- min (minimo)
- max (maximo)
- random (aleatorio)
- random_seed (semilla_aleatoria)
- sin (seno)
- cos (coseno)
- tan (tangente)
- asin (aseno)
- acos (acoseno)
- atan (atangente)
- atan2 (atangente2)
- exp (exponencial)
- ln (logaritmo_natural)
- log10 (logaritmo10)
- log2 (logaritmo2)
- hypot (hipotenusa)
- pi (pi, alias PI)
- e (e, alias E)
Notes:
- PI and E behave as constants in the interpreter. In compiled code, use pi() and e() calls.
Grammar Cheat Sheet (Canonical English)¶
Generated from docs/en/reference/grammar.md. Run ./scripts/update-feature-parity-grammar.sh to refresh.
// Generated from docs/en/reference/grammar.md (parser rules only)
grammar Crespi;
// ===== Parser rules =====
program
: statement* EOF
;
statement
: declaration
| ifStmt
| whenStmt
| whileStmt
| forStmt
| guardStmt
| returnStmt
| breakStmt
| continueStmt
| block
| exprStmt
;
declaration
: importDecl
| decorator* visibility? (varDecl | letDecl | functionDecl | extensionFunctionDecl | classDecl | traitDecl)
| extensionDecl
;
visibility
: 'public' | 'private' | 'internal' | 'fileprivate'
;
decorator
: '@' IDENTIFIER
;
varDecl
: 'var' IDENTIFIER typeAnn? ('=' expression)? semi
;
letDecl
: 'let' IDENTIFIER typeAnn? '=' expression semi
;
functionDecl
: 'fn' IDENTIFIER typeParams? '(' parameters? ')' returnType? (block | '=' expression semi)
;
extensionFunctionDecl
: 'fn' IDENTIFIER '.' IDENTIFIER typeParams? '(' parameters? ')' returnType? (block | '=' expression semi)
;
operatorDecl
: 'operator' operatorName '(' parameters? ')' returnType? (block | '=' expression semi)
;
constructorDecl
: 'constructor' '(' parameters? ')' (':' constructorDelegation)? block
;
constructorDelegation
: 'this' '(' arguments? ')'
| 'super' '(' arguments? ')'
;
classDecl
: 'class' IDENTIFIER typeParams? ('(' parameters? ')')? (':' parents)? classBody?
;
parents
: IDENTIFIER ('(' arguments? ')')? (',' IDENTIFIER)*
;
classBody
: '{' classMember* '}'
;
classMember
: functionDecl
| operatorDecl
| constructorDecl
| varDecl
| letDecl
| staticMember
;
staticMember
: 'static' functionDecl
| 'static' varDecl
| 'static' letDecl
| 'static' block
;
traitDecl
: 'trait' IDENTIFIER typeParams? (':' parents)? '{' traitMember* '}'
;
traitMember
: 'fn' IDENTIFIER '(' parameters? ')' returnType? block?
;
extensionDecl
: 'extension' IDENTIFIER (':' parents)? '{' extensionMember* '}'
;
extensionMember
: functionDecl
| operatorDecl
;
importDecl
: 'import' importKind? modulePath importAlias? importSymbols? semi
;
importKind
: 'fn' | 'class' | 'let' | 'var'
;
importAlias
: 'as' IDENTIFIER
;
importSymbols
: '{' importSymbol (',' importSymbol)* '}'
;
importSymbol
: IDENTIFIER importAlias?
;
modulePath
: IDENTIFIER ('.' IDENTIFIER)*
;
parameters
: parameter (',' parameter)*
;
parameter
: IDENTIFIER typeAnn? ('=' expression)?
;
typeParams
: '[' typeParam (',' typeParam)* ']'
;
typeParam
: IDENTIFIER (':' typeExpr)?
;
typeAnn
: ':' typeExpr
;
returnType
: '->' typeExpr
;
ifStmt
: 'if' expression block ('else' (ifStmt | block))?
;
guardStmt
: 'guard' (guardBind | expression) 'else' blockExpr semi?
;
guardBind
: 'var' IDENTIFIER '=' expression
;
whenStmt
: 'when' expression '{' whenCase* defaultCase? '}'
;
whenCase
: 'is' pattern '=>' block
;
defaultCase
: 'default' '=>' block
;
whileStmt
: 'while' expression block
;
forStmt
: 'for' IDENTIFIER 'in' expression block
;
returnStmt
: 'return' expression? semi
;
breakStmt
: 'break' semi
;
continueStmt
: 'continue' semi
;
exprStmt
: expression semi
;
block
: '{' statement* '}'
;
blockExpr
: '{' statement* blockExprTail? '}'
;
blockExprTail
: 'return' expression?
| expression
;
expression
: assignment
;
assignment
: conditional (assignmentOp assignment)?
;
assignmentOp
: '=' | '+=' | '-=' | '*=' | '/='
;
conditional
: ifExpr
| coalesce ('?' expression ':' expression)?
;
ifExpr
: 'if' expression blockExpr 'else' blockExpr
;
coalesce
: logicalOr ('??' logicalOr)*
;
logicalOr
: logicalAnd (('or' | '||') logicalAnd)*
;
logicalAnd
: bitwiseOr (('and' | '&&') bitwiseOr)*
;
bitwiseOr
: bitwiseXor ('|' bitwiseXor)*
;
bitwiseXor
: bitwiseAnd ('^' bitwiseAnd)*
;
bitwiseAnd
: equality ('&' bitwiseAnd)*
;
equality
: comparison (('==' | '!=') comparison)*
;
comparison
: shift (('<' | '<=' | '>' | '>=' | 'in') shift)*
;
shift
: term (('<<' | '>>') term)*
;
term
: factor (('+' | '-') factor)*
;
factor
: unary (('*' | '/' | '%') unary)*
;
unary
: ('!' | '-' | '~') unary
| call
;
call
: primary callSuffix*
;
callSuffix
: '(' arguments? ')'
| '.' IDENTIFIER
| '[' expression ']'
| '++'
| '--'
;
arguments
: expression (',' expression)*
;
primary
: literal
| IDENTIFIER
| 'this'
| 'super' '.' IDENTIFIER
| lambdaExpr
| tupleLiteral
| '(' expression ')'
| arrayLiteral
| dictLiteral
;
lambdaExpr
: IDENTIFIER '=>' lambdaBody
| '(' parameters? ')' returnType? '=>' lambdaBody
;
lambdaBody
: block
| expression
;
tupleLiteral
: '(' expression ',' (expression (',' expression)*)? ','? ')'
;
arrayLiteral
: '[' (expression (',' expression)*)? ']'
;
dictLiteral
: '{' (dictEntry (',' dictEntry)*)? '}'
;
dictEntry
: (IDENTIFIER | STRING) ':' expression
;
pattern
: '_'
| IDENTIFIER patternClass?
| literal
| listPattern
| dictPattern
;
patternClass
: '{' patternField (',' patternField)* '}'
;
patternField
: IDENTIFIER ':' pattern
;
listPattern
: '[' (pattern (',' pattern)*)? ']'
;
dictPattern
: '{' (patternEntry (',' patternEntry)*)? '}'
;
patternEntry
: (IDENTIFIER | STRING) ':' pattern
;
operatorName
: '+' | '-' | '*' | '/' | '%'
| '==' | '!' | '<' | '<=>'
| 'compare' | 'negate' | 'not'
| 'increment' | 'decrement'
| 'get' | 'set' | 'contains' | 'invoke'
;
typeExpr
: unionType
;
unionType
: nullableType ('|' nullableType)*
;
nullableType
: primaryType '?'?
;
primaryType
: arrayType
| dictType
| functionType
| tupleType
| namedType
;
namedType
: IDENTIFIER ('[' typeExpr (',' typeExpr)* ']')? ('.' '(' parameters? ')' '->' typeExpr)?
;
arrayType
: '[' typeExpr ']'
;
dictType
: '{' typeExpr ':' typeExpr '}'
;
functionType
: '(' typeExpr (',' typeExpr)* ')' '->' typeExpr
;
tupleType
: '(' typeExpr (',' typeExpr)+ ')'
;
semi
: ';'?
;