A simple language & interpreter. Might be a Lisp.
In BNF notation:
<program> ::= <expression> <program> | <expression>
<expression> ::= <optional-whitespace> "(" <optional-whitespace> <expression> <whitespace> <optional-parameter-list> <optional-whitespace> ")" <optional-whitespace> | <optional-whitespace> <literal> <optional-whitespace> | <optional-whitespace> <identifier> <optional-whitespace>
<optional-parameter-list> ::= <parameter-list> | ""
<parameter-list> ::= <expression> <whitespace> <parameter-list> | <expression>
<literal> ::= <number> | <string>
<number> ::= <float> | <integer>
<integer> ::= <digit> <integer> | <digit>
<float> ::= <integer> "." <integer> | <integer> "."
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<optional-whitespace> ::= <whitespace> | ""
<whitespace> ::= " " <whitespace> |
"\t" <whitespace> |
"\n" <whitespace> |
"\r" <whitespace> |
" " |
"\t" |
"\n" |
"\r"
Identifiers can be any permutation of one or more non-whitespace characters, not starting with a number or '
, and excluding (
and )
.
Strings can be any permutation of characters surrounded by '
, excluding '
unless escaped as \'
.
See the unit tests for some examples of simple programs/expressions.
boolean
represents a single bit (0 or 1).
byte
represents an unsigned, 8-bit integer.
cons
represents a recursive structure: a car
and cdr
. Each can be any type.
floatingPoint
represents a 64-bit IEEE-754 floating point number.
function
represents a function.
integer
represents a signed, 64-bit integer.
nil
represents a lack of something; nothing. Usually the sentinel value at the end of a list.
All type names (listed above) are reserved words, even if currently unused in the language.
endl
is an "end of line" character (\n
).
lambda
creates a function, taking named (identifier) arguments and an expression that can use those arguments.
let
creates a named identifier in the current scope, and assigns it the result of an expression.
cons
constructs a pair of (x,y).car
retrieves the first element of such a pair.cdr
retrieves the second element of such a pair.list
constructs a list of pairs like (x, (y, (z, etc.)))len
returns the size of alist
, as aninteger
.- Singly linked lists (as constructed via
list
) are represented as follows:
((list) = (cons nil nil))
((list a) = (cons a nil))
((list a b) = (cons a b))
((list a b c) = (cons a (cons b c)))
((list a b c d ) = (cons a (cons b (cons c d))))
And so on.
Strings (including those created with string literals) are represented as singly-linked lists of bytes.
Mathematical operators and equality operator.
sequence
runs multiple expressions in sequence. Returns the result of the last expression and discards the results of prior expressions.
- If
condition
evaluates totrue
, evaluatesexpr1
and returns the result. - If
condition
evaluates tofalse
, evaluatesexpr2
and returns the result. - If
condition
evaluates to a non-Boolean value, errors. Notably (and distinctly from non-conditionals), only the returned expression is evaluated.
May be used with any number of parameters.
Each pair of two parameters (condition and expression), starting from cond1 expr1
, gives the following behavior:
- If the condition evaluates to
true
, evaluates the expression and returns the result. - If the condition evaluates to
false
, does not evaluate the expression, and moves on to the next pair (if any). - If the condition evaluates to a non-Boolean value, errors. If no conditional expression evaluates to true, errors.
Converts x to a string representation.
print
prints variadic arguments to standard output.
read
reads a single byte from standard input, and returns:
- If standard input is closed (end of stream),
nil
. - If standard input yielded one byte, returns the read byte.
import
imports the specified file as a module, into the current scope.
parallel
runs multiple expressions in parallel (returning when the last-running expression returns).