This is an interpreter for the Runway specification language, which was created to model distributed and concurrent systems. The interpreter is typically used as part of runway-browser, which provides a web-based UI in which you can run interactive visualizations based on the models.
(We expect this repo to become a compiler over time, which is why it's called runway-compiler and not runway-interpreter.)
First make sure you have node
and npm
(node package manager) installed.
Clone this repository and run npm install
within it to get started.
Syntax highlighting for the Vim text editor is available
using the syntax file vim/runway.vim. Copy it into
~/.vim/syntax/
and set your filetype to runway
in ~/.vimrc
:
autocmd BufRead,BufNewFile *.model set filetype=runway
Syntax highlighting for the Atom text editor can be found in a separate language-runway repo.
Use the REPL to try out statements and expressions in your console:
$ node bin/main.js
> 3 * 4
12
> type Pair : record { first: 0..9, second: 10..99 };
> var p : Pair;
> p
Pair { first: 0, second: 10 }
> p.first = 20
ModelingBoundsError: Cannot assign value of 20 to range undefined: 0..9;
> p.first = 3
> p
Pair { first: 3, second: 10 }
> type Maybe : either { Nothing, Something { it: 3..5 } }
> var m : Maybe
> m
Nothing
> m = Something { it: 4 }
> m
Something { it: 4 }
> match m { Something as s => { print s.it; }, Nothing => { print False; } }
4
> m = Nothing
> match m { Something as s => { print s.it; }, Nothing => { print False; } }
False
>
You can also load Runway models into the REPL, such as the Too Many Bananas model.
$ node main.js ~/runway-model-toomanybananas/toomanybananas.model
bananas = 0
notePresent = False
roommates = [1: Happy, 2: Happy, 3: Happy, 4: Happy, 5: Happy]
Executing step
bananas = 0
notePresent = False
roommates = [1: Hungry, 2: Happy, 3: Happy, 4: Happy, 5: Happy]
> .fire step 3
bananas = 0
notePresent = False
roommates = [1: Hungry, 2: Happy, 3: Hungry, 4: Happy, 5: Happy]
> .fire step 3
bananas = 0
notePresent = True
roommates = [1: Hungry, 2: Happy, 3: GoingToStore, 4: Happy, 5: Happy]
> bananas = 7
> .fire step 3
bananas = 7
notePresent = True
roommates = [1: Hungry, 2: Happy, 3: ReturningFromStore { carrying: 3 }, 4: Happy, 5: Happy]
> .fire step 3
bananas = 10
notePresent = False
roommates = [1: Hungry, 2: Happy, 3: Hungry, 4: Happy, 5: Happy]
Note that invariants are not automatically checked in the REPL (issue #1).
You're encouraged to look at existing examples to begin with, such as runway-model-toomanybananas and runway-model-elevators. The specification language is documented in doc/LANGUAGE-GUIDE.md, and the most important thing to note is that most things are pass-by-value (copy semantics), but for loops are by reference.
The lexer+parser (lib/parser.js) is written using the Parsimmon library. It outputs a really big basically JSON parse tree like what you find in test-scripts/parser/output-2.json. Every object in the parse tree has a "kind" field specifying its type and a "source" field specifying where it comes from in the input file (for error messages).
After parsing completes, the entire structure is converting into an AST (abstract syntax tree). There's mostly a one-to-one mapping between a node in the parse tree and a node in the AST, but the AST is actual JavaScript objects. There are two kinds of nodes in the AST: statements and expressions. These refer to types and values (value classes are defined next to the corresponding type).
After the AST is set up, typecheck()
is called on it, which is invoked
through the entire tree (children before parents). Then execute()
calls the
top-level initialization statements, if any.
Run npm test
.
Unit tests use the Mocha library. To add a new test
file, place it in the test/
directory.
The parser is tested by feeding it a couple of files
(test-scripts/parser/input*.model
) and automatically checking their parser output
(against test-scripts/parser/output*.json
). Eventually we'll want more targeted tests
for the parser, but this has worked pretty well so far at making sure there
aren't any regressions.