All Mason programs must use the msl (Mason Standard Library) package.
The examples can be run on the site, but you may want to install mason too.
syntax
Character sequences are valid names if they have no special characters
(() [
{} # % ^ & _ | \ : ; ' " , .] or whitespace),
do not start with a digit or ~
, and are not keywords.
Blocks of code are written as indented blocks of text. Tabs by default, but there is a compiler option for spaces.
Spaces within a line are significant too, so don't go adding spaces anywhere the examples don't.
a. b
, a.b
, and a .b
all mean different things!
You don't need semicolons, commas, or curly braces, and parentheses are rare.
Mason generally uses prefix syntax as in + 1 2
instead of infix 1 + 2
in JavaScript.
The few infix operators such as a = 1
are statements — meaning they only occur once per line, and can't appear as subexpressions —
so operator precedence is not necessary.
||
is an ignored line comment. For other comments, see doc.
block
In addition to normal blocks, blocks of code can also build objects, arrays, and maps.
object
Objects are written as indented blocks of key. value
pairs.
x. 1 y. 2
Object keys are local variables, so you can use them as if you had used =
.
If an object key is a local variable from elsewhere, just write foo.
.
one. 1 uno. one ein = uno ein.
array
Arrays are also written in indented blocks.
Each line beginning with .
, followed by a space, writes a new entry to it.
...
adds many elements.
. 1 . 2 ... [3 4]
map
Maps follow the same pattern.
Each line with a ->
writes an entry to the map.
1 -> 2 3 -> 4
building
Why are these called builders?
It's because they build their result incrementally, making them more advanced than just literals.
. 1 if false . 2 if true . 3
short forms
You can also do it all on one line.
obj = {a. 1 b. 2} arr = [1 2] || When a value is just accessing the variable with the key name, you don't have to type it. . {foo. 1 arr.} || When all values are just local accesses, you don't need `.`. . {obj arr}
value blocks
If a block appears in a value position, either it is a builder it returns its last line.
return
keyword.two = 2 two
Yes, you can use a block anywhere a value is expected!
a. || `x` is scoped to this block. x = 1 x b. . 1 . || `. ` expects a value, which can of course be a block! . 2 . 3
literals
Constants and numbers work as in JavaScript.
. true . false . null . undefined . 0 . -1.1 . 0b10 . 0o10 . 0x10
strings
Text surrounded in "
makes a string.
Interpolate values with #()
. For a local name use #foo
without parentheses.
\
escapes special characters as in JavaScript.
Multi-line strings go in indented text.
#equation
is indented.
For short strings, use '
followed by an identifier.
This is useful for the names of events, CSS classes, methods, etc.
wise-man = 'Confucius equation = "1 + 1 = #(+ 1 1)" " #wise-man say: #equation but I don't know if I believe it...
regexps
RegExps look just like strings but use `
instead of "
.
You can include any of the flags g i m y
after the closing `
.
y
flag isn't available on your system, you won't be able to compile it yet.When interpolated values are RegExps, their .source is interpolated, so regexps can compose. But flags on interpolated regexps are ignored.
hex-digit = `[0-9a-f]` hex-number = `0x#(hex-digit)+`i . hex-number || We used the `i` flag, so capital letters are OK. . hex-number.test "0xDEADBEEF"
operators
Operators are written in prefix notation.
They can take any number of arguments. Unlike function calls, they don't require parentheses.
The operators are:
and or
+ - * / ** %
=? ==? <? <=? >? >=?
**
is equivalent to Math.pow
.
==?
tests identity while =?
is overridable via binary=?.
|| Operators ending in `?` test their arguments in pairs. || This is equivalent to `and <? 1 2 <? 2 3`. . <? 1 2 3 || Other operators run left to right. || This is equivalent to `- (- 3 2) 1`. . - 3 2 1 || Operators don't require parentheses. || This is equivalent to `=? 9 (* 3 (+ 2 1))`. . =? 9 * 3 + 2 1
Since operators take any number of arguments, you will still occasionally need parentheses to distinguish these:
|| + 1 (* 2 3 (- 4 5)) . + 1 * 2 3 - 4 5 || + 1 (* 2 3) (- 4 5) . + 1 (* 2 3) - 4 5
There are also two unary operators, neg
and not
.
These take only one argument no matter what, so
neg a b
is parsed as neg (a b)
.
. neg 1 . not true || Equivalent to `neg (identity 1)` . neg identity 1
Mason does not implement these javascript operators:
<< >> >>> & ^ | ~ ++ -- in
or the unary +
operator.
If you need these, they are available as functions such as js<<.
functions
Functions are written with \
followed by arguments.
The body of a function is a block meaning it can be a builder.
Calling a function doesn't usually require parentheses, except for arguments that are theirselves function calls.
id = \a a two-of = \a . a . a . id 1 . two-of 1 || Parentheses are only needed when a subexpression is itself a function call. . id (id 1)
If you want to put a block inside parentheses, just don't include the closing parenthesis.
two-of = \a . a . a two-of (two-of . 1 . 2 || No closing parenthesis!
For functions with no return value, use !\
.
If you don't need to do anything in a block, use pass
.
A function with no arguments is called like fun()
.
do-nothing! = !\ pass do-nothing!()
this-functions
Normal functions compile to JavaScript's arrow functions.
For function() { }
, which has a freshly bound this
variable, use .\
and .!\
.
In inner functions, it's safe to use this
.
You usually won't need these, because Mason has class syntax.
f = .\ || In here `this` has a different value than outside. \ || In here `this` has the same value as in `f`. this (f.call 3)()
new
Calling a constructor looks like a function call with new
in front.
new
is parsed like an operator, as are all other expression keywords. So foo new Bar
is foo (new Bar)
.new Array 4
modules
Mason is planned to compile to JavaScript native modules.
A module is written as an object block.
The default export is an entry with the same name as the file name.
|| my-module.ms || default export my-module. 1 || named export a. 2
If your module does not have any named exports, it is treated as a block and its value is assigned to the default export.
pass
.So, the code for a module whose default export is zero is:
0
Module imports go at the top of a script and use a special syntax.
import || Uses the globally available module `fs`. fs || File "brother.ms" (or ".js") in the same directory. .brother || ./brother-dir/nephew.ms .brother-dir.nephew || ../aunt.ms ..aunt || ../../aunt/cousin.ms ...aunt.cousin || Creates a local `a` equal to the module's default export. a || Imports named exports `b` and `c` as locals. a b c || Both combined. The default export is still called `a`, not `_`. a _ b c
Mason doesn't normally allow global variables (except for builtin globals), but you can declare them using the fake global
module.
import global alert alert 'hi
Some values from msl such as identity are builtins — you don't have to explitly import them. The necessary imports will be added for you.
The list of builtins is currently only available here.
Putting these together, global variables such as Object
are really builtins from the global module. Common JS globals (not including web-specific ones) are builtins.