Compare commits

..

No commits in common. "71056896ac6c963f8590795e1d41b2dd679025b9" and "13b4b8a5f5670d38eae095749ddbba734ac2df89" have entirely different histories.

6 changed files with 49 additions and 76 deletions

View File

@ -1,15 +0,0 @@
BasedOnStyle: GNU
ColumnLimit: 80
IndentWidth: 4
TabWidth: 4
UseTab: ForContinuationAndIndentation
BreakBeforeBraces: Attach
BreakBeforeBinaryOperators: None
SpaceAfterCStyleCast: true
AlignAfterOpenBracket: DontAlign
AlignEscapedNewlines: DontAlign
AlignOperands: DontAlign
AlignConsecutiveMacros: Consecutive
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
IndentGotoLabels: false

2
.gitignore vendored
View File

@ -9,5 +9,3 @@
/ell.files /ell.files
/ell.creator* /ell.creator*
/ell.includes /ell.includes
/ell.cflags
/ell.cxxflags

101
ell.c
View File

@ -16,14 +16,14 @@
* *
*/ */
#include <ctype.h>
#include <errno.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <setjmp.h>
#if defined __GNUC__ #if defined __GNUC__
#define ELL_ATTRIBUTE_PRINTF(x, y) __attribute__ ((format (printf, x, y))) #define ELL_ATTRIBUTE_PRINTF(x, y) __attribute__ ((format (printf, x, y)))
@ -188,18 +188,9 @@ ell_list (struct ell_v *head) {
// --- Lexer ------------------------------------------------------------------- // --- Lexer -------------------------------------------------------------------
enum ell_token { enum ell_token { ELLT_ABORT, ELLT_LPAREN, ELLT_RPAREN,
ELLT_ABORT, ELLT_LBRACKET, ELLT_RBRACKET, ELLT_LBRACE, ELLT_RBRACE,
ELLT_LPAREN, ELLT_STRING, ELLT_NEWLINE, ELLT_AT };
ELLT_RPAREN,
ELLT_LBRACKET,
ELLT_RBRACKET,
ELLT_LBRACE,
ELLT_RBRACE,
ELLT_STRING,
ELLT_NEWLINE,
ELLT_AT
};
static const char *ell_token_names[] = { static const char *ell_token_names[] = {
[ELLT_ABORT] = "end of input", [ELLT_ABORT] = "end of input",
@ -249,8 +240,8 @@ ell_lexer_advance (struct ell_lexer *self) {
static bool static bool
ell_lexer_hexa_escape (struct ell_lexer *self, struct ell_buffer *output) { ell_lexer_hexa_escape (struct ell_lexer *self, struct ell_buffer *output) {
const char *abc = "0123456789abcdef", *h, *l; const char *abc = "0123456789abcdef", *h, *l;
if (!self->len || !(h = strchr (abc, tolower (ell_lexer_advance (self)))) || if (!self->len || !(h = strchr (abc, tolower (ell_lexer_advance (self))))
!self->len || !(l = strchr (abc, tolower (ell_lexer_advance (self))))) || !self->len || !(l = strchr (abc, tolower (ell_lexer_advance (self)))))
return false; return false;
ell_buffer_append_c (output, (h - abc) << 4 | (l - abc)); ell_buffer_append_c (output, (h - abc) << 4 | (l - abc));
@ -263,8 +254,7 @@ enum {
ELL_LEXER_COMMENT = '#' ELL_LEXER_COMMENT = '#'
}; };
static bool static bool ell_lexer_is_whitespace (int c) {
ell_lexer_is_whitespace (int c) {
return !c || c == ' ' || c == '\t' || c == '\r'; return !c || c == ' ' || c == '\t' || c == '\r';
} }
@ -336,12 +326,13 @@ ell_lexer_next (struct ell_lexer *self, const char **e) {
enum ell_token token = ell_lexer_tokens[c]; enum ell_token token = ell_lexer_tokens[c];
if (!token) { if (!token) {
ell_buffer_append_c (&self->string, c); ell_buffer_append_c (&self->string, c);
while (self->len && !ell_lexer_is_whitespace (*self->p) && while (self->len && !ell_lexer_is_whitespace (*self->p)
!ell_lexer_tokens[*self->p]) && !ell_lexer_tokens[*self->p])
ell_buffer_append_c (&self->string, ell_lexer_advance (self)); ell_buffer_append_c (&self->string, ell_lexer_advance (self));
return ELLT_STRING; return ELLT_STRING;
} }
if (token == ELLT_STRING && (*e = ell_lexer_string (self, &self->string))) if (token == ELLT_STRING
&& (*e = ell_lexer_string (self, &self->string)))
return ELLT_ABORT; return ELLT_ABORT;
return token; return token;
} }
@ -378,8 +369,8 @@ static bool
ell_print_string_needs_quoting (struct ell_v *s) { ell_print_string_needs_quoting (struct ell_v *s) {
for (size_t i = 0; i < s->len; i++) { for (size_t i = 0; i < s->len; i++) {
unsigned char c = s->string[i]; unsigned char c = s->string[i];
if (ell_lexer_is_whitespace (c) || ell_lexer_tokens[c] || if (ell_lexer_is_whitespace (c) || ell_lexer_tokens[c]
c == ELL_LEXER_ESCAPE || c < 32) || c == ELL_LEXER_ESCAPE || c < 32)
return true; return true;
} }
return s->len == 0; return s->len == 0;
@ -435,8 +426,8 @@ ell_print_block (struct ell_printer *printer, struct ell_v *list) {
static bool static bool
ell_print_set (struct ell_printer *printer, struct ell_v *list) { ell_print_set (struct ell_printer *printer, struct ell_v *list) {
if (!list->head || strcmp (list->head->string, "set") || if (!list->head || strcmp (list->head->string, "set")
!list->head->next || list->head->next->next) || !list->head->next || list->head->next->next)
return false; return false;
printer->putchar (printer, '@'); printer->putchar (printer, '@');
@ -457,10 +448,10 @@ ell_print_list (struct ell_printer *printer, struct ell_v *list) {
static void static void
ell_print_v (struct ell_printer *printer, struct ell_v *v) { ell_print_v (struct ell_printer *printer, struct ell_v *v) {
if (ell_print_string (printer, v) || if (ell_print_string (printer, v)
ell_print_block (printer, v) || || ell_print_block (printer, v)
ell_print_set (printer, v) || || ell_print_set (printer, v)
ell_print_list (printer, v)) || ell_print_list (printer, v))
return; return;
printer->putchar (printer, '('); printer->putchar (printer, '(');
@ -572,7 +563,7 @@ ell_parse_prefix_list (struct ell_v *seq, const char *name) {
return ell_list (prefix); return ell_list (prefix);
} }
static struct ell_v *ell_parse_line (struct ell_parser *p, jmp_buf out); static struct ell_v * ell_parse_line (struct ell_parser *p, jmp_buf out);
static struct ell_v * static struct ell_v *
ell_parse_v (struct ell_parser *p, jmp_buf out) { ell_parse_v (struct ell_parser *p, jmp_buf out) {
@ -585,7 +576,8 @@ ell_parse_v (struct ell_parser *p, jmp_buf out) {
SKIP_NL (); SKIP_NL ();
if (ACCEPT (ELLT_STRING)) if (ACCEPT (ELLT_STRING))
return CHECK (ell_string (p->lexer.string.s, p->lexer.string.len)); return CHECK (ell_string
(p->lexer.string.s, p->lexer.string.len));
if (ACCEPT (ELLT_AT)) { if (ACCEPT (ELLT_AT)) {
result = ell_parse_v (p, out); result = ell_parse_v (p, out);
return CHECK (ell_parse_prefix_list (result, "set")); return CHECK (ell_parse_prefix_list (result, "set"));
@ -714,8 +706,8 @@ static bool
ell_scope_prepend (struct ell *ell, struct ell_v **scope, const char *name, ell_scope_prepend (struct ell *ell, struct ell_v **scope, const char *name,
struct ell_v *v) { struct ell_v *v) {
struct ell_v *key, *pair; struct ell_v *key, *pair;
if (!ell_check (ell, (key = ell_string (name, strlen (name)))) || if (!ell_check (ell, (key = ell_string (name, strlen (name))))
!ell_check (ell, (pair = ell_list (key)))) { || !ell_check (ell, (pair = ell_list (key)))) {
ell_free_seq (v); ell_free_seq (v);
return false; return false;
} }
@ -814,8 +806,8 @@ ell_eval_args (struct ell *ell,
for (; args; args = args->next) { for (; args; args = args->next) {
struct ell_v *evaluated = NULL; struct ell_v *evaluated = NULL;
// Arguments should not evaporate, default to a nil value // Arguments should not evaporate, default to a nil value
if (!ell_eval_statement (ell, args, &evaluated) || if (!ell_eval_statement (ell, args, &evaluated)
(!evaluated && !ell_check (ell, (evaluated = ell_list (NULL))))) || (!evaluated && !ell_check (ell, (evaluated = ell_list (NULL)))))
goto error; goto error;
ell_free_seq (evaluated->next); ell_free_seq (evaluated->next);
evaluated->next = NULL; evaluated->next = NULL;
@ -897,14 +889,15 @@ ell_eval_value (struct ell *ell, const struct ell_v *body,
} }
static bool static bool
ell_eval_statement (struct ell *ell, const struct ell_v *statement, ell_eval_statement
struct ell_v **result) { (struct ell *ell, const struct ell_v *statement, struct ell_v **result) {
if (statement->type == ELL_STRING) if (statement->type == ELL_STRING)
return ell_check (ell, (*result = ell_clone (statement))); return ell_check (ell, (*result = ell_clone (statement)));
// Executing a nil value results in no value. It's not very different from // Executing a nil value results in no value. It's not very different from
// calling a block that returns no value--it's for our callers to resolve. // calling a block that returns no value--it's for our callers to resolve.
if (!statement->head || ell_eval_value (ell, statement->head, result)) if (!statement->head
|| ell_eval_value (ell, statement->head, result))
return true; return true;
ell_free_seq (*result); ell_free_seq (*result);
@ -925,8 +918,8 @@ ell_eval_statement (struct ell *ell, const struct ell_v *statement,
static bool static bool
args_to_scope (struct ell *ell, struct ell_v *args, struct ell_v **scope) { args_to_scope (struct ell *ell, struct ell_v *args, struct ell_v **scope) {
if (!ell_check (ell, (args = ell_list (args))) || if (!ell_check (ell, (args = ell_list (args)))
!ell_scope_prepend (ell, scope, "args", args)) || !ell_scope_prepend (ell, scope, "args", args))
return false; return false;
size_t i = 0; size_t i = 0;
@ -934,8 +927,8 @@ args_to_scope (struct ell *ell, struct ell_v *args, struct ell_v **scope) {
char buf[16] = ""; char buf[16] = "";
(void) snprintf (buf, sizeof buf, "%zu", ++i); (void) snprintf (buf, sizeof buf, "%zu", ++i);
struct ell_v *copy = NULL; struct ell_v *copy = NULL;
if ((args && !ell_check (ell, (copy = ell_clone (args)))) || if ((args && !ell_check (ell, (copy = ell_clone (args))))
!ell_scope_prepend (ell, scope, buf, copy)) || !ell_scope_prepend (ell, scope, buf, copy))
return false; return false;
} }
return ell_check (ell, (*scope = ell_list (*scope))); return ell_check (ell, (*scope = ell_list (*scope)));
@ -1038,8 +1031,8 @@ ell_defn (ell_fn_local) {
struct ell_v *values = names->next; struct ell_v *values = names->next;
for (names = names->head; names; names = names->next) { for (names = names->head; names; names = names->next) {
struct ell_v *value = NULL; struct ell_v *value = NULL;
if ((values && !ell_check (ell, (value = ell_clone (values)))) || if ((values && !ell_check (ell, (value = ell_clone (values))))
!ell_scope_prepend (ell, scope, names->string, value)) || !ell_scope_prepend (ell, scope, names->string, value))
return false; return false;
if (values) if (values)
values = values->next; values = values->next;
@ -1054,9 +1047,9 @@ ell_defn (ell_fn_set) {
struct ell_v *v; struct ell_v *v;
if ((v = name->next)) if ((v = name->next))
return ell_check (ell, (v = ell_clone (v))) && return ell_check (ell, (v = ell_clone (v)))
ell_check (ell, (*result = ell_clone (v))) && && ell_check (ell, (*result = ell_clone (v)))
ell_set (ell, name->string, v); && ell_set (ell, name->string, v);
// We return an empty list for a nil value // We return an empty list for a nil value
if (!(v = ell_get (ell, name->string))) if (!(v = ell_get (ell, name->string)))
@ -1146,8 +1139,8 @@ ell_defn (ell_fn_cat) {
else else
ell_buffer_append (&buf, args->string, args->len); ell_buffer_append (&buf, args->string, args->len);
} }
bool ok = !(ell->memory_failure |= buf.memory_failure) && bool ok = !(ell->memory_failure |= buf.memory_failure)
ell_check (ell, (*result = ell_string (buf.s, buf.len))); && ell_check (ell, (*result = ell_string (buf.s, buf.len)));
free (buf.s); free (buf.s);
return ok; return ok;
} }
@ -1185,8 +1178,8 @@ ell_defn (ell_fn_try) {
return true; return true;
struct ell_v *msg; struct ell_v *msg;
if (ell->memory_failure || if (ell->memory_failure
!ell_check (ell, (msg = ell_string (ell->error, strlen (ell->error))))) || !ell_check (ell, (msg = ell_string (ell->error, strlen (ell->error)))))
return false; return false;
free (ell->error); ell->error = NULL; free (ell->error); ell->error = NULL;

4
go.mod
View File

@ -1,7 +1,3 @@
module janouch.name/ell module janouch.name/ell
go 1.17
require github.com/peterh/liner v1.1.0 require github.com/peterh/liner v1.1.0
require github.com/mattn/go-runewidth v0.0.3 // indirect

View File

@ -65,3 +65,4 @@ main (int argc, char *argv[]) {
ell_free (&ell); ell_free (&ell);
return 0; return 0;
} }

2
repl.c
View File

@ -17,8 +17,8 @@
*/ */
#include "ell.c" #include "ell.c"
#include <readline/history.h>
#include <readline/readline.h> #include <readline/readline.h>
#include <readline/history.h>
static void static void
run (struct ell *ell, struct ell_v *program) { run (struct ell *ell, struct ell_v *program) {