Symbolic expressions are the fundamental building blocks of the Pigeon Core language. An s-expression is simply a list, where each entry in the list is either a constant value, the name of a variable, or another list. The rules for evaluating an s-expression program are very simple:
S-expression programs are written using parentheses:
(print 'hello') (print '1 + 1 = ' (add: 1 1)) (print (sqrt -1))
Because the function is always the first entry in the list, arithmetic calculations must be written in a prefix format. For instance the calculation (a+b)*(c+d) would be written as:
(mul: (add: a b) (add: c d))
Parentheses indicate the list structure of the program. There tend to be lots of them. If your text editor doesn't have a brace matching function, find a better one now. You will need it!
Identifiers consist of one of the characters a-z, A-Z, or an underscore, followed by any number of the characters a-z, A-Z, 0-9, or an underscore, followed by an optional trailing colon.
Anything inside 'single quotes' is a constant string. Backslash escapes work as in the regular syntax. Integer constants look like 23 or -42, and floating point constants like 3.14 or -1.2e3.
Comments start with # or // and continue to the end of the line.
Whitespace is ignored.
The symbols true, false, nil, and undef are special constants, not variable names.
Anything other than the above is a single character identifier, unless it is two adjacent asterisks, in which case ** forms a single identifier, for bootstrapping reasons which are too ugly to explain just now.
You may think this all seems a bit minimal compared to the regular Pigeon syntax. And you'd be right. What about "double quoted strings", or 0xDEADBEEF or 0b101010 constants, or /* C style comments */, for instance? Those are all implemented by the higher level syntax parser.
An s-expression is stored as a recursive list of Pigeon list objects. Each list element must be one of three types: