- Rust 96.7%
- HTML 1.3%
- JavaScript 0.7%
- C 0.5%
- Shell 0.4%
- Other 0.3%
|
|
||
|---|---|---|
| crates | ||
| docker | ||
| docs | ||
| editors/helix | ||
| examples | ||
| firmware | ||
| tree-sitter-meowscript | ||
| .editorconfig | ||
| .gitignore | ||
| ARCHITECTURE.md | ||
| BOARDS.md | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| CONCEPTS.md | ||
| CONTRIBUTING.md | ||
| DIMENSIONS_FOR_IOT.md | ||
| DIMENSIONS_GUIDE.md | ||
| EDITOR_SETUP.md | ||
| FROM_ARDUINO.md | ||
| GAP_ANALYSIS.md | ||
| GETTING_STARTED.md | ||
| HARDWARE_QUICKSTART.md | ||
| LANGUAGE_EVOLUTION.md | ||
| LANGUAGE_REFERENCE.md | ||
| LICENSE-APACHE | ||
| LICENSE-MIT | ||
| logo.png | ||
| meowscript_tla.md | ||
| NOTE_REACTIVITY_COARSENESS.md | ||
| patterns-communication.md | ||
| patterns-control.md | ||
| patterns-sensors.md | ||
| patterns-system.md | ||
| patterns.md | ||
| README.md | ||
| SECURITY.md | ||
| SERVICES.md | ||
| SIMULATOR.md | ||
| syntax.md | ||
| thoughts.md | ||
| WHY_DIMENSIONS_MATTER.md | ||
MeowScript
A reactive, module-based programming language with spreadsheet semantics, designed for the Meows microkernel OS.
Why MeowScript?
Here's a thermostat in Arduino C++:
#include <DHT.h>
DHT dht(4, DHT22);
float temp_c = 0;
float setpoint = 22.0;
float hysteresis = 2.0;
bool heating = false;
bool cooling = false;
const char* label = "IDLE";
unsigned long last_read = 0;
void setup() {
Serial.begin(9600);
dht.begin();
pinMode(7, OUTPUT);
}
void loop() {
if (millis() - last_read >= 2000) {
last_read = millis();
float reading = dht.readTemperature();
if (!isnan(reading)) {
temp_c = reading;
}
}
if (temp_c < setpoint - hysteresis) {
heating = true; cooling = false; label = "HEATING";
} else if (temp_c > setpoint + hysteresis) {
heating = false; cooling = true; label = "COOLING";
} else {
heating = false; cooling = false; label = "IDLE";
}
digitalWrite(7, heating ? HIGH : LOW);
}
Seven globals. Manual state tracking. Timing arithmetic. No way to test without a DHT22 and a serial monitor.
Here's the same thing in MeowScript:
module Thermostat:
input temp_c: Float
input setpoint_c: Float = 22.0
temperature = temp_c.degC
setpoint = setpoint_c.degC
too_cold = temperature < setpoint - 2.0.degC
too_hot = temperature > setpoint + 2.0.degC
label = if too_hot: "COOLING" else: if too_cold: "HEATING" else: "IDLE"
test "heating kicks in when cold":
bind setpoint_c to 22.0
bind temp_c to 18.0
assert too_cold
assert_eq(label, "HEATING")
test "cooling kicks in when hot":
bind setpoint_c to 22.0
bind temp_c to 26.0
assert too_hot
assert_eq(label, "COOLING")
No globals. No loop(). No manual updates -- change temp_c and everything
downstream recomputes automatically. And those tests run right now, on your
laptop, without hardware:
$ meow test thermostat.meow
PASS heating kicks in when cold
PASS cooling kicks in when hot
test result: 2 passed, 0 failed (2 total)
That's the idea. Describe what your system does, not how to update every variable. Let the compiler catch your unit errors. Test without uploading.
For the longer version of this argument, read MeowScript for Arduino Developers.
Features
- Reactive by default -- computed fields update automatically when dependencies change
- First-class measurements --
22.5.degC,100.km, with dimension checking and unit conversion - URL type -- structured URL construction with
url(), path building with/, query params, percent-encoding - Bit operations --
&,|,^,<<,>>on integers, plus hex (0xFF) and binary (0b1010) literals - Built-in testing --
testblocks,mock service!,advance_timeright in your modules - Pattern matching -- tagged unions, exhaustiveness checking, match expressions
- Box semantics --
Box<T>unifies error handling withFull,Empty, andFailurestates - Actions and triggers --
action!for effects,on changedfor reactive event handlers, one-shotservice!calls - Timer service --
Timer.every(500.ms)for clock-driven reactive triggers - ESP32 + simulator -- develop with a full web dashboard simulator (with LCD display), deploy to real ESP32 hardware
no_stdcore -- parser, type checker, and runtime run without an allocator (suitable for embedded)
Quick Look
module ReactiveCounter:
input signal: Bool = false
input counter: Int = 0
doubled = counter * 2
action! on signal changed to true:
set counter = counter + 1
action! reset():
set counter = 0
test "counter increments on signal":
bind signal to true
assert_eq(counter, 1)
bind signal to false
bind signal to true
assert_eq(counter, 2)
assert_eq(doubled, 4)
module SensorHub:
service! temp = DHTSensor.read(ReadTemp {}) with {
when: { every: 2.seconds },
}
has_data = temp is Full
status = if has_data: "receiving" else: "waiting"
test "mock sensor responses":
mock service! temp with [Full(25.0), Full(26.0), Failure("timeout")]
assert temp is Empty
advance_time(2.seconds)
assert temp is Full
advance_time(2.seconds)
assert temp is Full
advance_time(2.seconds)
assert temp is Failure
Getting Started
See the Getting Started Guide for a hands-on tutorial.
Want to simulate ESP32 hardware with a web dashboard? See Simulator Guide.
Coming from Arduino/embedded C++? Start with MeowScript for Arduino Developers instead.
Building
Requires Rust (edition 2021).
git clone https://codeberg.org/dpp/meowscript.git
cd meowscript
cargo build --release
The meow binary will be at target/release/meow.
Usage
# Type-check a module
meow check examples/thermostat.meow
# Evaluate a module and print field values
meow run examples/hello.meow
# Run tests defined in a module
meow test examples/thermostat.meow
# Upload to ESP32 hardware via serial (hot-reload)
meow push examples/neopixel_blink.meow --port /dev/ttyUSB0
# Start the Language Server Protocol server
meow lsp
# Interactive REPL
meow repl
Running Tests
cargo test
This runs all 481 tests across the workspace -- parser, type checker, graph, runtime, test harness, HAL, ESP32 platform, simulator, bytecode compiler, LSP, and integration tests.
Project Structure
crates/
meowscript-syntax/ # AST types, Span (no_std)
meowscript-parser/ # Hand-written lexer + Pratt parser (no_std)
meowscript-types/ # Type system, dimensions, unit registry (no_std)
meowscript-checker/ # Name resolution, type inference, diagnostics
meowscript-graph/ # Reactive dependency graph, topological sort
meowscript-runtime/ # Tree-walking evaluator, reactive propagation, multi-module system
meowscript-ipc/ # Service IPC types (transport deferred)
meowscript-test-harness/ # In-language test runner
meowscript-cli/ # `meow` binary (check, run, test, push)
meowscript-hal/ # Hardware abstraction layer traits, board definitions
meowscript-esp/ # ESP32 platform (GPIO, I2C, SPI, UART, PWM, WiFi, BLE, sensors)
meowscript-sim/ # Simulator with REST API, WebSocket, and web dashboard
meowscript-bytecode/ # Bytecode compiler and VM (no_std)
meowscript-lsp/ # Language server (diagnostics, hover, completion, goto-def, etc.)
examples/ # Example .meow files
docker/ # Dockerfiles for dev environment and simulator
editors/ # Editor configurations (Helix)
For a deeper look at the implementation, see ARCHITECTURE.md.
Docker
Development Environment
cd docker
docker compose build
docker compose run meow-dev meow test /workspace/examples/thermostat.meow
Simulator
cd docker
docker compose -f docker-compose.sim.yml build
docker compose -f docker-compose.sim.yml up
This starts the simulator on http://localhost:3000 with a web dashboard for
real-time visualization of GPIO, I2C, SPI, WiFi, Neopixels, and more. Place
.meow files in the workspace/ directory and they'll be loaded and
hot-reloaded automatically.
See SIMULATOR.md for the full simulator guide.
Documentation
- GETTING_STARTED.md -- hands-on language tutorial
- CONCEPTS.md -- reactive model, dependency graph, Box, module lifecycle
- LANGUAGE_REFERENCE.md -- types, operators, built-in functions, methods
- SERVICES.md -- service handler reference and
withblock options - BOARDS.md -- supported board definitions and
board.*properties - SIMULATOR.md -- simulator and web dashboard guide
- HARDWARE_QUICKSTART.md -- build, flash, and deploy to ESP32
- EDITOR_SETUP.md -- LSP server, Helix, tree-sitter grammar
- FROM_ARDUINO.md -- migration guide for Arduino developers
- ARCHITECTURE.md -- compiler and runtime internals
- examples/README.md -- example program index
Hardware Examples
- NeoPixel Blink -- cycle an RGB LED through colors (ESP32-C6-DevKit, CYD)
- Box Buttons -- count button presses on LCD with hardware buttons or touch screen (ESP32-S3-BOX-Lite, CYD)
Design Documents
- thoughts.md -- design philosophy, module model, type system
- syntax.md -- concrete syntax reference (22 sections)
- patterns.md -- IoT pattern catalog (24 patterns across 4 documents)
License
Licensed under either of
at your option.
Contributing
See CONTRIBUTING.md for guidelines.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.