Skip to content
Matthew Trost edited this page Dec 19, 2015 · 1 revision

Runiq runs atop JavaScript. If you want to run Runiq on your system, the only prerequisite is that you have Node.js installed. (Runiq also runs fine in browsers if you want to bundle it via Browserify or Webpack, although for UI thread performance I would recommend only running Runiq inside a Web Worker.)

For maximum flexibility, the Runiq implementation is split into three main components that you can use together, or a-la-carte:

  • Parser
  • Interpreter
  • Libraries

Parser

Parsing has two phases. First, the lexer produces a collection of token objects. Then the parser consumes the tokens and produces a AST. To use the parser, first load the parser object:

var RuniqParser = require('runiq/parser');

Get a collection of token objects:

var tokens = RuniqParser.lex('(my (source-code 3.14159 "hello world"))')

The tokens array will look something (roughly) like this:

[{type:"open"},{type:"identifier",string:"my"},...]

Then pass the tokens to the parser:

var ast = RuniqParser.parse(tokens);

And get a full AST object back:

["my",["source-code",3.14159,"hello world"]

Interpreter

You can pass any valid Runiq AST to an instance of the Runiq interpreter, and then execute the program either stepwise or in its entirety. First create an instance of the interpreter:

var RuniqInterpreter = require('runiq/interpreter');
var interpreter = new RuniqInterpreter(myLibraryInstance, options);

Then run the program:

var program = ["+",1,["-",5,10]];
interpreter.run(program, [], null, function(err, result) {
    // result will be -4
});
Stepwise

Or you can step the program. Stepping executes one computation of the given program, then returns a complete new AST representing the next step of the program.

var program = ["+",1,["-",5,10]];
interpreter.step(program, [], null, function(err, ast) {
    // ast will be ["+",1,-5]
});

Both .step and .run take four arguments: The program AST, an argv array, an event object (or null), and a Node-style callback function. We'll ignore the argv array and the event object for now.

Interpreter options

The interpreter constructor accepts an options object for overriding the following defaults:

debug: false // T/F print debug messages on every step
timeout: Infinity // Exit with error if program takes longer than this (ms)

Libraries

The interpreter doesn't automatically load any standard libraries, as you may have inferred from the examples above. It really only defines these four basic operations:

  • Function invocation: ["fn",1,2,3]
  • Nested functions: ["fn2",["fn1",["fn0"]]]
  • Parallel functions: [["fn0"],["fn1"],["fn2"]]
  • Quoted functions: ["quote",["fn",1,2,3]] i.e. [{"'":["fn",1,2,3]}]

To use the interpreter a-la-carte style, you must pass in the desired library functions to the interpreter's constructor. A minimal core library is provided as part of the Runiq package:

var RuniqLib = require('runiq/lib'); // Note: This returns a function
var RuniqInterpreter = require('runiq/interpreter');
var interpreter = new RuniqInterpreter(RuniqLib());
Clone this wiki locally