Quick reference derived from the current parser/interpreter (chumsky-based).
// line comment
/* block
comment */
var x = 10;
var name = "hi";
x = x + 1; // assignment to an *already declared* var
- Assigning to an undeclared name is an error (
UndeclaredAssign). varre-declares/shadows in the current scope (each{ }block gets a childEnvironment).
| Type | Literal | Notes |
|---|---|---|
Num |
10, 3.14 |
f64 under the hood, digits + optional .digits |
Str |
"text" |
no escape sequences supported yet |
Bool |
(no literal syntax) | only produced by comparisons/logic — no true/false keyword in the grammar |
Fn |
via fn decl |
closures capture their defining Environment |
Truthiness (is_truthy):
Bool→ itselfNum→falseonly if0.0Str→falseonly if emptyFn→ alwaystrue
+ - * / // arithmetic (Div by zero is an error)
== != < > <= >= // comparison
&& || // logical (short-circuit)
!expr // logical not
-expr // unary negation (desugars to 0 - expr)
+also does string concatenation: if either side is aStr, the result is aStr(numbers getDisplay-formatted in).- No
%modulo, no bitwise ops, no+=/-=etc.
print "hello";
print 1 + 2;
if (cond) {
...
} elif (cond) {
...
} else {
...
}
while (cond) {
...
}
for (var i = 0; i < 10; i = i + 1) {
...
}
for's init/cond/post are all optional (for (;;) { ... }is valid).elifdesugars to a nestedifin theelsebranch.
fn add(a, b) {
return a + b;
}
add(1, 2);
return;andreturn expr;both valid; a function that falls off the end (or does barereturn;) yieldsNum(0.0)as its call-expression value.- Functions are first-class
Value::Fn— stored in variables, called vianame(args). Arg count mismatches error out (ArgCountMismatch). - Closures capture the environment they were declared in (
Rc<RefCell<Environment>>), so nested/returned functions retain access to outer scope.
import <math>;
import <string>;
import <mvis>;
- Importing pulls that module's native functions into the flat
ctx.functionscall namespace (nomod.fn()syntax — justfn()after import, even though the names are prefixedmath_/str_). - Unknown import name →
EvalError::UnknownImport. - Known gap:
KNOWN_MODULES(interpreter side) currently only contains"mvis".mathandstringare registered viaregister_stdlib/register_module_fnbutimport <math>;/import <string>;will fail withUnknownImportuntilKNOWN_MODULESis updated (or the check is changed to look atctx.stdlib.contains_keyinstead of the hard-coded list) — this is presumably whatPATCH_NOTES.mdrefers to as still-pending interpreter-side work.
| Function | Signature | Notes |
|---|---|---|
math_abs(x) |
num → num | |
math_sqrt(x) |
num → num | errors if x < 0 |
math_pow(base, exp) |
num, num → num | |
math_floor(x) / math_ceil(x) / math_round(x) / math_trunc(x) |
num → num | |
math_min(a, b) / math_max(a, b) |
num, num → num | 2-arg only, no varargs |
math_pi() |
→ num | takes no args, still called as math_pi() |
math_log(x) |
num → num | natural log; errors if x <= 0 |
math_log2(x) / math_log10(x) |
num → num | errors if x <= 0 |
math_exp(x) |
num → num | |
math_sin(x) / math_cos(x) / math_tan(x) |
num → num | radians |
math_asin(x) / math_acos(x) |
num → num | errors if x outside [-1, 1] |
math_atan(x) |
num → num | |
math_atan2(y, x) |
num, num → num | |
math_sign(x) |
num → num | 1, -1, or 0 |
math_clamp(x, min, max) |
num, num, num → num | errors if min > max |
math_random() |
→ num | in [0, 1); simple xorshift seeded off system time — not cryptographically random |
| Function | Signature | Notes |
|---|---|---|
str_len(s) |
str → num | char count, not bytes |
str_upper(s) / str_lower(s) |
str → str | |
str_trim(s) |
str → str | |
str_contains(s, sub) |
str, str → bool | |
str_replace(s, from, to) |
str, str, str → str | replaces all occurrences |
str_index_of(s, sub) |
str, str → num | char index, -1 if not found (converts from byte index internally) |
str_substr(s, start, len) |
str, num, num → str | char-based; errors if start/len negative |
str_to_num(s) |
str → num | errors if not parseable as f64 |
str_from_num(x) |
num → str |
All stdlib errors surface as EvalError::Native(String) with a "fn_name: message" format, and arity mismatches use the same ArgCountMismatch as user-defined functions.
let mut interp = Interpreter::new();
interp.set_var("x", Value::Num(5.0));
interp.register_fn("double", |args| { /* ... */ Ok(Value::Num(args[0].as_num()? * 2.0)) });
interp.register_module_fn("mvis", "snapshot", |args| { /* ... */ });
interp.eval_str("print double(x);")?;
// or
interp.eval_file("script.finch")?;- No
true/false/nilliterals in the grammar — only reachable as values through comparisons or return defaults. - No string escaping (
\",\n, etc.) —none_of('"')reads until the next literal". - No arrays/lists/objects yet.
- No
%or compound assignment operators. - Step/recursion limits exist in
EvalError(StepLimitExceeded) but aren't wired into the eval loop shown here yet.