A lightweight functional language with a parser, REPL, and a rudimentary interpreter/runtime.
flt (pronounced "flight") is a single Rust crate that provides:
- a parser + AST (
flt::parser,flt::ast) - a REPL (
flt::repl) backed by a simple interpreter/runtime (flt::runtime)
The language has literals (including arrays and maps), let and const bindings, if expressions, operators, string interpolation, comments, type-checked function calls with keyword and variadic arguments, and an Elixir-style pipe operator. Types are first-class values, and a Rust host can add its own functions and types.
See the documentation, starting with the one-page language specification.
[dependencies]
flt = "0.3.0"use flt::runtime::Runtime;
use flt::runtime::SimpleRuntime;
fn main() {
let mut runtime = SimpleRuntime::default();
let value = runtime.eval("let x = 1 + 2; x * 2").expect("evaluation should succeed");
println!("{value}");
}A host works with a runtime only through the Runtime trait, and names SimpleRuntime, the reference implementation, only to create one. See The Runtime Trait, and Native Functions, Types and Values for extending flt from Rust.
- Integer:
42,+7,-2(arbitrary precision) - Number:
3.14,-0.5 - String:
"hello","path\\to\\file" - Boolean:
true,false - Symbol:
:name,:"display name" - None:
None - Array:
[1, 2, 3] - Map:
{ foo: 1, "spaced out": 2 }
Identifiers start with a letter, then can include letters, digits, _, or -.
- Valid:
foo,foo_1,foo-1,READ - Invalid:
_foo,-foo,123foo
Both forms are supported:
- Parenthesized:
add(1, 2) - Without parentheses:
add 1, 2
Keyword arguments follow positional ones: greet("Ada", greeting: "Hi"). Every call is checked against the function's declared types, which also pick the overload to call. See Functions and Pipe.
Interpolated strings support {expr} and compile into concatenation (<>) expressions.
"Hello, {name}!"
"Answer: {1 + 2}"Inside interpolated strings, \{ escapes a literal {.
# starts a comment that runs to end-of-line.
1 + 2 # inline comment
# full line commentUnary operators:
!(logical not)+(unary plus)-(unary minus)
Binary operators:
- Arithmetic:
+,-,*,/,//(integer floor division) - String concat:
<> - Logical:
&&,||,^^ - Bitwise:
&,|,^ - Comparison:
==,!=,<,>,<=,>= - Pipe:
|>(x |> f(a)evaluates asf(x, a))
|| → && → ^^ → ==/!= → </>/<=/>= → | → ^ → & → |> → +/-/<> → */////
Parentheses override precedence as expected. See Operators.
use flt::parser::parse_expr;
parse_expr("42");
parse_expr(r#""hello""#);
parse_expr(":id");
parse_expr("add(1, 2)");
parse_expr("add 1, 2");
parse_expr(r#""Hello, {who}!""#);
parse_expr(r#""foo" <> "bar""#);
parse_expr("1 + 2 * 3");
parse_expr("(1 + 2) * 3");
parse_expr("READ(\"input\") |> WRITE(\"output\")");
parse_expr("1 # comment\n+ 2");Run the REPL:
cargo runPrint version:
cargo run -- versionEvaluate a program, like ruby -e:
cargo run -- -e 'let x = 2; x * 3'See the Quickstart.
The runtime evaluates expressions and statements: literals (including maps and arrays), identifiers, field access, unary/binary operators, if expressions, let and const bindings, function calls, and pipes. Bitwise operators and standalone keyword expressions are parsed but not yet evaluated. See Runtime Behavior of the Reference Runtime.
flt::parser- Parses flt source text into statements and expressionsflt::ast- Defines the syntax tree types that the parser makesflt::repl- Provides the interactive prompt, which a host can embed as its own REPLflt::runtime- Provides theSimpleRuntimereference implementationflt::eval- Evaluates a parsed expression with a fresh runtime
cargo test
cargo clippy --all-targets --all-featuresDesign decisions are recorded as ADRs.
MIT