parent
4698e522cc
commit
d579e68051
33
README.adoc
33
README.adoc
|
@ -25,8 +25,8 @@ The parser, however, does a bunch of transformations:
|
||||||
* `[a b c]` makes a call to `(list a b c)`;
|
* `[a b c]` makes a call to `(list a b c)`;
|
||||||
* `@var` is a shorthand for `(set var)`;
|
* `@var` is a shorthand for `(set var)`;
|
||||||
* `{ code }` is the most complex one. Each line within the curly braces is
|
* `{ code }` is the most complex one. Each line within the curly braces is
|
||||||
wrapped in parentheses, and the resulting list is quoted, so that it doesn't
|
wrapped in parentheses, and the resulting sequence is wrapped in a quoted
|
||||||
execute immediately.
|
list, so that it doesn't execute immediately.
|
||||||
|
|
||||||
As an example, consider the following snippet:
|
As an example, consider the following snippet:
|
||||||
|
|
||||||
|
@ -38,13 +38,13 @@ As an example, consider the following snippet:
|
||||||
|
|
||||||
which gets expanded to the following:
|
which gets expanded to the following:
|
||||||
|
|
||||||
((print (if (quote ((eq? (set var) foo)))
|
((print (if (block (eq? (set var) foo))
|
||||||
(quote ((values 'Hello world\n')))
|
(block (values 'Hello world\n'))
|
||||||
else
|
else
|
||||||
(quote ((values 'Error\n'))))))
|
(block (values 'Error\n')))))
|
||||||
|
|
||||||
Observe that the whole program is enclosed in an implicit pair of `{}` and that
|
Observe that the whole program is enclosed in an implicit pair of `{}` and that
|
||||||
`quote` is a very powerful special form which can replace many others if needed.
|
`block` is all that's left of special forms.
|
||||||
|
|
||||||
For a slightly more realistic example you can have a look at 'greet.ell'.
|
For a slightly more realistic example you can have a look at 'greet.ell'.
|
||||||
|
|
||||||
|
@ -55,20 +55,27 @@ of lists) are assigned to local variables named `1`, `2`, etc., and the full
|
||||||
list of them is stored in `args`.
|
list of them is stored in `args`.
|
||||||
|
|
||||||
When evaluating a command, the first argument is typically a string with its
|
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.
|
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.
|
The last expression in a block is the return value.
|
||||||
|
|
||||||
Special Forms
|
Special Forms
|
||||||
-------------
|
-------------
|
||||||
`quote [<arg>]...`
|
`block [<arg>]...`
|
||||||
|
|
||||||
Like `values` but returns the arguments without any evaluation.
|
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
|
Standard Library
|
||||||
----------------
|
----------------
|
||||||
The standard library interprets the empty list and the empty string as false
|
The standard library interprets the empty list and the empty string as false
|
||||||
values, everything else is taken as true.
|
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>]...`
|
`local <names> [<value>]...`
|
||||||
|
|
||||||
|
@ -89,7 +96,7 @@ Return an arbitrary number of values.
|
||||||
|
|
||||||
`if <cond> <body> [elif <cond> <body>]... [else <body>]`
|
`if <cond> <body> [elif <cond> <body>]... [else <body>]`
|
||||||
|
|
||||||
Conditional evaluation, strings evaluate to themselves.
|
Conditional evaluation.
|
||||||
|
|
||||||
`for <list> <body>`
|
`for <list> <body>`
|
||||||
|
|
||||||
|
@ -129,7 +136,7 @@ Execute the body and pass any error to the handler instead of propagating it.
|
||||||
|
|
||||||
`throw <message>`
|
`throw <message>`
|
||||||
|
|
||||||
Throw an error. Messages starting on an underscore don't generate backtraces
|
Throw an error. Messages starting on an underscore don't generate backtraces,
|
||||||
which can be used to catch them.
|
which can be used to catch them.
|
||||||
|
|
||||||
`not <value>`
|
`not <value>`
|
||||||
|
|
16
ell.c
16
ell.c
|
@ -383,12 +383,10 @@ print_string (struct item *s) {
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
print_block (struct item *list) {
|
print_block (struct item *list) {
|
||||||
if (!list->head || strcmp (list->head->value, "quote")
|
if (!list->head || strcmp (list->head->value, "block"))
|
||||||
|| !list->head->next || list->head->next->next
|
|
||||||
|| list->head->next->type != ITEM_LIST)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
list = list->head->next->head;
|
list = list->head->next;
|
||||||
for (struct item *line = list; line; line = line->next)
|
for (struct item *line = list; line; line = line->next)
|
||||||
if (line->type != ITEM_LIST)
|
if (line->type != ITEM_LIST)
|
||||||
return false;
|
return false;
|
||||||
|
@ -579,8 +577,7 @@ parse_item (struct parser *self, jmp_buf out) {
|
||||||
while ((*tail = parse_line (self, err)))
|
while ((*tail = parse_line (self, err)))
|
||||||
tail = &(*tail)->next;
|
tail = &(*tail)->next;
|
||||||
EXPECT (T_RBRACE);
|
EXPECT (T_RBRACE);
|
||||||
result = CHECK (new_list (result));
|
return CHECK (parse_prefix_list (result, "block"));
|
||||||
return CHECK (parse_prefix_list (result, "quote"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self->memory_failure = !(self->error = lexer_errorf (&self->lexer,
|
self->memory_failure = !(self->error = lexer_errorf (&self->lexer,
|
||||||
|
@ -843,8 +840,9 @@ execute_item (struct context *ctx, struct item *body, struct item **result) {
|
||||||
struct item *args = body->next;
|
struct item *args = body->next;
|
||||||
if (body->type == ITEM_STRING) {
|
if (body->type == ITEM_STRING) {
|
||||||
const char *name = body->value;
|
const char *name = body->value;
|
||||||
if (!strcmp (name, "quote"))
|
if (!strcmp (name, "block"))
|
||||||
return !args || check (ctx, (*result = new_clone_list (args)));
|
return (!args || check (ctx, (args = new_clone_list (args))))
|
||||||
|
&& check (ctx, (*result = new_list (args)));
|
||||||
if ((body = get (ctx, name)))
|
if ((body = get (ctx, name)))
|
||||||
return execute_resolved (ctx, body, args, result);
|
return execute_resolved (ctx, body, args, result);
|
||||||
return execute_native (ctx, name, args, result);
|
return execute_native (ctx, name, args, result);
|
||||||
|
@ -857,7 +855,7 @@ execute_item (struct context *ctx, struct item *body, struct item **result) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// It might a bit confusing that this doesn't evaluate arguments
|
// It might a bit confusing that this doesn't evaluate arguments
|
||||||
// but neither does "quote" and there's nothing to do here
|
// but neither does "block" and there's nothing to do here
|
||||||
if (!evaluated)
|
if (!evaluated)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue