Scripting - sid-code/nmoo GitHub Wiki

The scripting language is designed to be simple. It uses S-expressions to represent lists (and code) and borrows many concepts from Lisps. I am not a Lisp programmer and this guide is written for non-Lisp programmers.

An atom is defined as the following:

  • 123, 1e9, 1.456 etc. (numbers - note that these are bound by the rules of parseInt and parseFloat)
  • "some characters" (" and \\ are the only currently valid escapes)
  • 'symbol-name (apostrophe is optional!)
  • #345 (the number is an object ID)
  • E_ERRORNAME
  • nil (actually a symbol, but is bound to the nil value)

A list is defined as the following:

  • ( atom atom ... atom )

Together, the kinds of atoms and list make up the eight fundamental data types: int, float, string, symbol, object, error, list, nil

Because lists are a data type and lists are also code, code is data.

Scripts can call builtins: (builtin-name arg1 arg2 ...)

There are two kinds of builtins. Runtime builtins are simple argument/return value + optional side-effect operations and compiler specials are special forms that are transformed by the compiler. These are usually control-flow constructs such as let, try, if, among many others. These are documented along with builtins as they are almost exactly the same. The only difference is that a compiler special can NOT be called using the call builtin because the compiler needs to know what's being called at compile-time. You can generate documentation for builtins and compiler specials alike by running nake docs in the project root directory.

The data types are pretty straightforward with some exceptions. Symbols are identifiers that may or may not be bound to a value. Here, "bound" means "interchangable with". For example, if a symbol a was bound to the value 3.6, whenever you refer to a, the compiler will instead look up the symbol and insert instructions to access whatever was at a. Using unbound symbols will result in an error (see page on errors) unless it's quoted. quote is a compiler special that takes one argument and returns just that argument but with the guarantee that nothing inside it will be evaluated. If you bind a symbol dog and try to access it from within a quote, you'll still get the symbol dog, and not whatever it was bound to. There is a construct called quasiquote which behaves exactly like quote but within a quasiquote you can insert unquotes anywhere inside it which will evaluate their arguments (and insert more quasiquotes or do whatever you want). More information on quote and friends is found on the builtin page.

Binding symbols is achieved through the compiler special let. Here is how:

(let ((bound-symbol 5))
  (echo (+ bound-symbol 50)))

let takes 2 arguments. The first is a list of (symbol value) pairs which binds each symbol to value but only while executing the second argument.

There is one more data type, but it is a sneaky one. It's called a lambda or anonymous function but it masquerades a list. Information on lambda can be found on the builtin page and information about its internal representation can be found on the lambda page.