Simpl is a small dynamic expression language implemented in MoonBit.
It is meant to be compact, readable, and easy to embed. The language has a few deliberately strong ideas:
- every program is an expression
- patterns work in bindings, function parameters, and conditional branches
- many values are callable, not only functions
- the syntax favors small composable forms over a large statement set
Module: amistozy/simpl
let greet(name; title = "friend") =
"Hello, "title" "name"!";
greet "Ada"
let score_label(result) =
if result is
| #Ok(score) and score >= 60 then "pass: "$score
| #Ok(score) then "retry: "$score
| #Err(message) then message
else "unknown";
score_label #Ok(72)
let rec qsort(xs) =
guard xs is [x; ..rest] else [];
let smaller = qsort rest.filter fn _ <= x;
let larger = qsort rest.filter fn _ > x;
[..smaller; x; ..larger];
qsort [4; 1; 5; 1; 3]
[1; 20; 3]
.map(fn: (_ + 1) * 2)
.filter(fn _ < 10)
- Dynamic values: integers, booleans, strings,
nil, lists, records, variants, references, closures, and built-ins. - Expression forms:
let,let and,let rec,do,guard,if,with, lambdas, calls, field access, and=>probes. - List literals support in-place spread with
..list. - Pattern forms: binders,
_, literals, variants, records, lists, list rests, alternatives, andaspatterns. - Call forms: positional and named arguments, default parameters, trailing
application,
fn expreta-expansion, and UFCS-style field fallback. - Callable data: strings concatenate or join, integers repeat, lists index or collect, and records produce updated copies from named arguments.
- Built-ins for references, printing, list transforms, length, reverse, min, max, and sum.
- Diagnostics: parse and runtime errors include source positions.
Install MoonBit.
Run the test suite:
moon testEvaluate inline source:
moon run cmd/main -- --eval "1 + 2 * 3"Parse without evaluating:
moon run cmd/main -- --parse --eval "let x = 1; x"Run a file:
moon run cmd/main -- program.simplThe CLI accepts multi-block input. A line containing at least three dashes, such
as ---, splits the file into independent parse or evaluation blocks.
Public entry points:
parse(String) -> SurfaceExpr raiseeval_source(String) -> Value raiseformat_error(Error, Int) -> Stringparse_error_text(String) -> String?eval_error_text(String) -> String?
Test helpers:
parse_is_okparse_is_erroreval_source_is_inteval_source_is_stringeval_source_is_booleval_source_is_error
Public types:
SurfaceExprValue
Read the language guide in this order:
- 01 - Language Tour
- 02 - Functions and Calls
- 03 - Control Flow and Patterns
- 04 - Data and Mutation
- 05 - Callable Composition
- 06 - CLI and Embedding
simpl.mbt: AST definitions, runtime values, evaluator, and public helperslexer.mbt: tokenization and source spansparser.mbt: surface parser and diagnosticsdesugar.mbt: surface-to-core loweringpattern.mbt: pattern matching, truthiness, and value summariesapply.mbt: call semantics and built-inspretty.mbt: pretty-printers for ASTs and valuescmd/main/main.mbt: command-line interpretersimpl_test.mbt: black-box testssimpl_wbtest.mbt: white-box tests
Recommended validation loop:
moon test
moon info
moon fmtIf an intentional behavior change affects snapshots, refresh them with:
moon test --updateApache-2.0. See LICENSE.