Skip to content

Repository files navigation

Creature

CI License: MIT

Creature is a small, statically-checked-where-possible, dynamically-typed programming language with a hand-written lexer, parser, semantic analyzer, and tree-walking interpreter — implemented from scratch in TypeScript, with no parser generator or runtime framework.

Its object model is built around organisms (isolated, actor-like instances with private state) and signals (typed, asynchronously delivered messages), coordinated by a deterministic cooperative scheduler. Every run of a Creature program produces the same output, the same signal ordering, and the same errors, regardless of host machine or timing.

The language's vocabulary is drawn from real animal behavior — territories, alarm calls, migration — sourced and documented in docs/ECOLOGICAL_BASIS.md. It is a genuine design constraint, not just naming: functions are behaviors, objects are organisms, modules are habitats, messages are signals.

Why this project

This is a compiler/interpreter project, not a wrapper around an existing toolchain:

  • Full pipeline, hand-written: lexer → recursive-descent parser → semantic analyzer → tree-walking interpreter, each a separate, independently testable stage with source-span-aware diagnostics.
  • Actor-style concurrency without nondeterminism: organisms have private memory and communicate only through signals; a FIFO scheduler with snapshot-at-emission semantics keeps every run reproducible.
  • A real type story for a dynamic language: optional annotations get best-effort static checking during semantic analysis, and full validation at runtime — no silent coercion.
  • Structured, actionable diagnostics: every error has a stable code (CR1xxxCR5xxx), a source location with a caret, and recovery guidance (see docs/DIAGNOSTICS.md).
  • Tested like production infrastructure: 225 tests across 32 files, 93%+ statement coverage, plus deterministic fuzz tests on the lexer and parser that assert "never throws, never produces an invalid span" over arbitrary UTF-8 input.

Quick example

import { print } from "habitat.io"

signal Alarm {
  location: Text
}

organism Sentinel {
  behavior watch(place: Text) {
    emit Alarm(location: place)
  }
}

organism Forager {
  listen Alarm as warning {
    print("Retreat from " + warning.location)
  }
}

begin {
  mark sentinel = Sentinel()
  mark forager = Forager()
  awaken sentinel
  awaken forager
  sentinel.watch("north ridge")
}

Running it prints Retreat from north ridge — the Forager's memory is completely private to it, and the alarm is delivered deterministically because Forager was awakened before the signal was emitted. See examples/ for eleven more, covering conditionals, collections, error handling, modules, and stateful organism lifecycles.

Language at a glance

Creature Conventional equivalent
mark / memory immutable / mutable binding
behavior function
organism class instance with private state (actor)
environment shared singleton state
signal / emit / listen typed message / send / subscribe
habitat.* standard library module
stage / transform state-machine state / transition
observe pattern matching (switch)

Full semantics are normative in docs/LANGUAGE_SPEC.md; syntax is normative in docs/GRAMMAR.md.

Getting started

Requires Node.js 22 (LTS) and npm.

git clone https://github.com/GuerraXe/creature-lang.git
cd creature-lang
npm ci
npm run build
node dist/cli/main.js run examples/01_hello.grr

Run every command from inside the creature-lang directory — npm ci needs its package.json, and node dist/cli/main.js is a relative path resolved from wherever your shell currently is (Cannot find module '...dist/cli/main.js' almost always means you're one cd away from the project root).

Installed as a package, the CLI is available as creature instead of node dist/cli/main.js:

creature run den.grr              # execute a program
creature check den.grr            # validate without running
creature format-check den.grr     # check source formatting
creature version

run accepts --debug (show host stack traces) and --max-steps N (override the evaluator's step budget, default 1,000,000). Exit codes: 0 success, 1 source/runtime error, 2 CLI usage error.

Creature source files use the .grr extension. Windows users who want Explorer to show the project's claw icon for .grr files can run the optional, reversible tools/register-windows-file-association.ps1 script (see its -Remove flag to undo).

Writing your own program

Create any file ending in .grr — there's no scaffolding command, it's a plain text file:

// hello.grr
import { print } from "habitat.io"

begin {
  mark greeting = "hello, creature"
  print(greeting)
}

Then run it the same way as any example, using the path to your file:

node dist/cli/main.js run hello.grr

Every program needs exactly one begin { ... } block — that's the entry point. See examples/ for more complete programs (organisms, signals, stages, error handling, files), and docs/LANGUAGE_SPEC.md / docs/GRAMMAR.md for the full syntax.

Verification

npm run format:check   # prettier
npm run lint           # eslint
npm run typecheck      # tsc --noEmit
npm test               # vitest (225 tests)
npm run test:coverage  # vitest with coverage (93%+ statements)
npm run examples       # builds the CLI and runs all 12 examples end to end

All of the above run in CI on every push and pull request (see .github/workflows/ci.yml).

Documentation

Known limitations

Native group/colony/swarm syntax and a rewrite-mode formatter are deferred; format-check validates LF endings, space indentation, no trailing whitespace, and a final newline, but does not rewrite files. Filesystem access is not sandboxed by default — an embedding must supply a sandbox root for untrusted input (see docs/STANDARD_LIBRARY.md).

License

MIT — see LICENSE.

About

A hand-written interpreted programming language with an organism/signal actor model and a deterministic scheduler, built from scratch in TypeScript.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages