A reactive programming language for small devices (and maybe more)
  • Rust 96.7%
  • HTML 1.3%
  • JavaScript 0.7%
  • C 0.5%
  • Shell 0.4%
  • Other 0.3%
Find a file
David Pollak 15a53c2f9b
Fixed gaps
Signed-off-by: David Pollak <feeder.of.the.bears@gmail.com>
2026-03-01 21:55:08 -05:00
crates Fixed gaps 2026-03-01 21:55:08 -05:00
docker TLA+ initial support 2026-02-28 23:00:06 -05:00
docs Fixed gaps 2026-03-01 21:55:08 -05:00
editors/helix New language features 2026-02-20 08:06:49 -05:00
examples chat 2026-03-01 20:18:00 -05:00
firmware New language features 2026-02-20 08:06:49 -05:00
tree-sitter-meowscript New language features 2026-02-20 08:06:49 -05:00
.editorconfig Updated documentation 2026-02-08 17:51:30 -05:00
.gitignore Somewhat working against an ESP32-C6 2026-02-14 20:41:15 -05:00
ARCHITECTURE.md Fixed gaps 2026-03-01 21:55:08 -05:00
BOARDS.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
Cargo.toml chat 2026-03-01 20:18:00 -05:00
CHANGELOG.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
CONCEPTS.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
CONTRIBUTING.md WIP 2026-02-10 20:03:33 -05:00
DIMENSIONS_FOR_IOT.md New language features 2026-02-20 08:06:49 -05:00
DIMENSIONS_GUIDE.md New language features 2026-02-20 08:06:49 -05:00
EDITOR_SETUP.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
FROM_ARDUINO.md WIP 2026-02-10 20:03:33 -05:00
GAP_ANALYSIS.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
GETTING_STARTED.md WIP 2026-02-10 20:03:33 -05:00
HARDWARE_QUICKSTART.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
LANGUAGE_EVOLUTION.md New language features 2026-02-20 08:06:49 -05:00
LANGUAGE_REFERENCE.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
LICENSE-APACHE Updated documentation 2026-02-08 17:51:30 -05:00
LICENSE-MIT Updated documentation 2026-02-08 17:51:30 -05:00
logo.png WIP language bringup 2026-02-08 17:04:18 -05:00
meowscript_tla.md WIP 2026-02-10 20:03:33 -05:00
NOTE_REACTIVITY_COARSENESS.md Some work to prepare MeowScript for Automerge integration 2026-03-01 19:20:55 -05:00
patterns-communication.md New language features 2026-02-20 08:06:49 -05:00
patterns-control.md New language features 2026-02-20 08:06:49 -05:00
patterns-sensors.md New language features 2026-02-20 08:06:49 -05:00
patterns-system.md New language features 2026-02-20 08:06:49 -05:00
patterns.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
README.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
SECURITY.md Updated documentation 2026-02-08 17:51:30 -05:00
SERVICES.md chat 2026-03-01 20:18:00 -05:00
SIMULATOR.md Runs on various ESP32s 2026-02-16 16:38:32 -05:00
syntax.md New language features 2026-02-20 08:06:49 -05:00
thoughts.md New language features 2026-02-20 08:06:49 -05:00
WHY_DIMENSIONS_MATTER.md New language features 2026-02-20 08:06:49 -05:00

MeowScript logo

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 -- test blocks, mock service!, advance_time right in your modules
  • Pattern matching -- tagged unions, exhaustiveness checking, match expressions
  • Box semantics -- Box<T> unifies error handling with Full, Empty, and Failure states
  • Actions and triggers -- action! for effects, on changed for reactive event handlers, one-shot service! 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_std core -- 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

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.