Ratslang is a compact configuration language, delivered as a Rust library.
It was born out of frustration with the lack of proper types for time and length in configuration files. When we configure physical systems like robots, even a single zero more or less can have massive consequences. Sometimes, we don't even realize there's a problem until it's too late. The famous Loss of the Mars Climate Orbiter is a prime example of this issue.
The core motivations behind Ratslang are:
- Solving units: The language should inherently handle units when configuring physical systems.
- Combining configs: It should be easier to combine existing configuration files rather than copying them.
- Simple and extensible: The implementation should be small, simple, and easy to extend.
Let's take a look at how it works:
# a comment
variable = true
time = 1s
time_is_running = 1ms..2mins # ranges convert automatically
len = 1cm..1m
# _ signals a variable the interpreter is looking for.
_internal = time_is_running
my.super.long.prefix.var = 0..100 # ranges on namespaced variable "var"
# nested
my.super {
long.prefix {
next_var = "UTF-🎱 Strings"
}
something_else = -99.018
}
mat = [ [ 6, 1, 9 ],
[ 3, 1, 8 ] ]
Currently, Ratslang doesn't support expressions like arithmetic, loops, or conditional statements. This is a deliberate choice, and it's still undecided if it will ever include such features. Some keywords are already reserved for potential future use.
Variables
- Dynamic types
- Mutable
- Copy-on-assignment
- C-style naming
Types
- Boolean:
true,false - Integer: Example:
42,-100 - Floating-point: Example:
69.42,-3.14 - String: Quotes can be omitted if the string doesn't conflict with a previously defined variable. Example:
"my string",another_string_without_quotes - Path: Example:
./somewhere/relative.dat,/or/absolute,./../backneed/dotfirst.launch.py - Array/Matrix: Newlines after commas are also supported for readability.
[ <Type>, <Type>, ... ],[ 42, World, [ "nested" ] ],[ [ 1, 2, 3 ], [ 4, 5, 6 ] ] - Time:
- Hour:
hour,hours(sis optional). Example:2hours,1.5hour - Minute:
min,mins(sis optional). Example:30min,5mins - Second:
s. Example:10s,0.5s - Millisecond:
ms. Example:200ms,1ms
- Hour:
- Length:
- Meter:
m. Example:10m,0.5m - Centimeter:
cm. Example:50cm,2.5cm - Millimeter:
mm. Example:100mm,1mm
- Meter:
- Range: Including unbound variants and empty
...- Time: Example:
1ms..5.3hours,6s.. - Length: Example:
1mm..100m,..4m - Numbers: Example:
-4..l,6.00001..6.0001
- Time: Example:
Includes
In Ratslang, including is done by assigning a path to the current namespace. All variables will then get the respective prefix.
= ./path_relative_to_current_file.rl
strangefile {
= ./../namespacing_contents.rl
}
Library Usage
Add this to your Cargo.toml.
= { = "0.1.0-alpha.3", = "https://github.com/stelzo/ratslang", = "main" }
First, you compile a Ratslang file to get a cleaned Abstract Syntax Tree (AST) with all variables resolved.
let file = new;
let ast = compile_file.unwrap;
Then, you can safely read the variables you need — either with the provided helper macros for concise code, or manually using Rust's powerful pattern matching.
Using helper macros (recommended):
use ;
// Local configs combining user vars and optional defaults
let file = new;
let ast = compile_file.unwrap;
let configs = Configs ;
// Simple values
let name: String = resolve_string!?;
let enabled: bool = resolve_bool!?;
let k: i64 = resolve_int!?;
let ratio: f64 = resolve_float!?;
// Paths
let path: String = resolve_path!?; // e.g., `_file = /abs/or/relative`
// Ranges (with sensible defaults used when bounds are missing)
let = resolve_length_range_meters_float!?; // meters as f64
let = resolve_time_range_seconds_float!?; // seconds as f64
let = resolve_int_range!?;
Manual resolution:
use anyhow;
use ;
// Local configs combining user vars and optional defaults
let file = new;
let ast = compile_file.unwrap;
let vars = ast.vars.filter_ns;
// Resolve a variable and pattern-match its type manually
let value = vars
.resolve?
.map_or?;
// Or use the generic resolve_var! macro
use resolve_var;
let configs = Configs ;
let k_neighbors: usize = resolve_var!?;
- Ratslang files typically use the
.rlextension. - Syntax highlighting is available with this tree-sitter grammar or this VS Code extension. For Markdown files, you can use the
awklanguage for syntax highlighting. It is not perfect but works reasonably well. - Compile errors are beautifully rendered thanks to Ariadne ❤️.
Ratslang: More a slang, less a lang.
Future Plans
The following features and improvements are planned:
- Expanded Units and Scales: Integrate more diverse units and scales with centralized conversion, ranging from astronomy to quantum physics, powered by the
uomcrate. - Opt-in Language Versioning: Implement an opt-in versioning system for
.rlfiles.