aboutsummaryrefslogtreecommitdiff
path: root/README.adoc
blob: 0cb914c5911e58c268e2d4a9d788e5a4f13e7602 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
ell
===
:compact-option:

'ell' is a middle ground between Scheme and Tcl.  The goal was to conceive
a programming language implementable with as little code as possible while
still being reasonably comfortable to use.

This package is an implementation of said language, meant to be self-contained,
portable and reusable.  Performance is specifically not an intent.

The project is currently in a "proof of concept" stage with many useful data
operations missing but I believe it won't be a problem to implement them as
needed for anyone interested.

Syntax
------
Owing to its heritage, 'ell' is homoiconic, that is a program can be directly
expressed using the language's data types.  There are only two of those:
the list and the string.  Any numerical conversions are made on an as-needed
basis.  Similarly, strings act like atoms/symbols when executed.

The parser, however, does a bunch of transformations:

 * `[a b c]` makes a call to `(list a b c)`;
 * `@var` is a shorthand for `(set var)`;
 * `{ code }` is the most complex one.  Each line within the curly braces is
   wrapped in parentheses, and the resulting sequence is wrapped in a quoted
   list, so that it doesn't execute immediately.

As an example, consider the following snippet:

 print (if { eq? @var foo } {
     values 'Hello world\n'
 } else {
     values 'Error\n'
 })

which gets expanded to the following:

 ((print (if (block (eq? (set var) foo))
             (block (values 'Hello world\n'))
             else
             (block (values 'Error\n')))))

Observe that the whole program is enclosed in an implicit pair of `{}` and that
`block` is all that's left of special forms.

For a slightly more realistic example you can have a look at 'greet.ell'.

Runtime
-------
Variables use per-block dynamic scoping.  Arguments to a block (which is a list
of lists) are assigned to local variables named `1`, `2`, etc., and the full
list of them is stored in `args`.

When evaluating a command, the first argument is typically a string with its
name and it is resolved as if `set` was called on it.  Lists are left for
execution as they are.

The last expression in a block is the return value.

Special Forms
-------------
`block [<arg>]...`

Like `list` but doesn't evaluate arguments.  A more appropriate name might be
`quoted-list`, which is not as descriptive in terms of syntax.  If simple
quoting is desired, the list can be unpacked by an ordinary command.

Standard Library
----------------
The standard library interprets the empty list and the empty string as false
values, everything else is considered true.  Numbers are floating point with
double precision, trailing zeroes are truncated.

Where a `<body>` is expected, strings retain their value, and block evaluation
is postponed as necessary.

`local <names> [<value>]...`

Create local variables in the current block.  Names for which there are no
values left default to `()`.

`set <name> [<value>]`

Retrieve or set a named variable.  The syntax sugar for retrieval is `@`.

`list [<item>]...`

Return a list made of given arguments.  The syntax sugar for lists is `[]`.

`values [<item>]...`

Return an arbitrary number of values.

`if <cond> <body> [elif <cond> <body>]... [else <body>]`

Conditional evaluation.

`for <list> <body>`

Run the body for each element.

`break`

Abort the running loop.

`map <list> <body>`

Transform each element with the given function into any number of values.

`filter <list> <body>`

Return a new list consisting of matching elements only.

`.. [<string>]...`

Concatenate strings.

`print [<item>]...`

Print all items in sequence--strings directly, lists as source code.

`system <command>`

Run a system command and return its return value.

`parse <program>`

Parse a program into a list of lists.

`try <body> <handler>`

Execute the body and pass any error to the handler instead of propagating it.

`throw <message>`

Throw an error.  Messages starting on an underscore don't generate backtraces,
which can be used to catch them.

`not <value>`

Return a boolean with the opposite truthiness.

`and [<body>]...`, `or [<body>]...`

Short-circuit evaluation, trying to return whatever the bodies result in.

`+`, `-`, `*`, `/`

Arithmetic operations on floating point numbers.

`=`, `<>`, `<`, `>`, `<=`, `>=`

Arithmetic comparisons on floating point numbers.

`eq?`, `ne?`, `lt?`, `gt?`, `le?`, `ge?`

Simple string comparisons.

Building and Running
--------------------
By default, running `make' will only build the interpreter:

 $ make
 $ ./interpreter greet.ell

Install development packages for GNU Readline to get a REPL for toying around:

 $ make repl
 $ ./repl

Possible Ways of Complicating
-----------------------------
 * `local [_a _b _rest] @args` would elegantly solve the problem of varargs,
   that is, unpack a list when names are list, and make the last element a list
   when there are more arguments than names
 * reference counting: currently all values are always copied as needed, which
   is good enough for all imaginable use cases, simpler and less error-prone

Contributing and Support
------------------------
Use this project's GitHub to report any bugs, request features, or submit pull
requests.  If you want to discuss this project, or maybe just hang out with
the developer, feel free to join me at irc://irc.janouch.name, channel #dev.

Bitcoin donations: 12r5uEWEgcHC46xd64tt3hHt9EUvYYDHe9

License
-------
'ell' is written by Přemysl Janouch <p.janouch@gmail.com>.

You may use the software under the terms of the ISC license, the text of which
is included within the package, or, at your option, you may relicense the work
under the MIT or the Modified BSD License, as listed at the following site:

http://www.gnu.org/licenses/license-list.html