Make the printer generic

Now you can concatenate lists like strings.
This commit is contained in:
Přemysl Eric Janouch 2017-06-01 10:39:29 +02:00
parent 863ea189eb
commit 0ae4a42335
Signed by: p
GPG Key ID: B715679E3A361BE6
2 changed files with 73 additions and 42 deletions

111
ell.c
View File

@ -356,7 +356,12 @@ ell_lexer_errorf (struct ell_lexer *self, const char *fmt, ...) {
// --- Printing ---------------------------------------------------------------- // --- Printing ----------------------------------------------------------------
static void ell_print_seq (struct ell_v *v); // This can be wrapped inside a larger structure, and errors simply accumulated
struct ell_printer {
void (*putchar) (struct ell_printer *self, unsigned char c);
};
static void ell_print_seq (struct ell_printer *printer, struct ell_v *v);
static bool static bool
ell_print_string_needs_quoting (struct ell_v *s) { ell_print_string_needs_quoting (struct ell_v *s) {
@ -370,30 +375,35 @@ ell_print_string_needs_quoting (struct ell_v *s) {
} }
static bool static bool
ell_print_string (struct ell_v *s) { ell_print_string (struct ell_printer *printer, struct ell_v *s) {
if (s->type != ELL_STRING) if (s->type != ELL_STRING)
return false; return false;
if (!ell_print_string_needs_quoting (s)) { if (!ell_print_string_needs_quoting (s)) {
printf ("%s", s->string); for (size_t i = 0; i < s->len; i++)
printer->putchar (printer, s->string[i]);
return true; return true;
} }
putchar (ELL_LEXER_STRING_QUOTE); printer->putchar (printer, ELL_LEXER_STRING_QUOTE);
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 (c < 32) if (c < 32) {
printf ("\\x%02x", c); printer->putchar (printer, '\\');
else if (c == ELL_LEXER_ESCAPE || c == ELL_LEXER_STRING_QUOTE) printer->putchar (printer, 'x');
printf ("\\%c", c); printer->putchar (printer, "0123456789abcdef"[c >> 4]);
else printer->putchar (printer, "0123456789abcdef"[c & 15]);
putchar (c); } else if (c == ELL_LEXER_ESCAPE || c == ELL_LEXER_STRING_QUOTE) {
printer->putchar (printer, '\\');
printer->putchar (printer, c);
} else
printer->putchar (printer, c);
} }
putchar (ELL_LEXER_STRING_QUOTE); printer->putchar (printer, ELL_LEXER_STRING_QUOTE);
return true; return true;
} }
static bool static bool
ell_print_block (struct ell_v *list) { ell_print_block (struct ell_printer *printer, struct ell_v *list) {
if (!list->head || strcmp (list->head->string, "block")) if (!list->head || strcmp (list->head->string, "block"))
return false; return false;
@ -402,57 +412,57 @@ ell_print_block (struct ell_v *list) {
if (line->type != ELL_LIST) if (line->type != ELL_LIST)
return false; return false;
putchar ('{'); printer->putchar (printer, '{');
for (struct ell_v *line = list; line; line = line->next) { for (struct ell_v *line = list; line; line = line->next) {
putchar (' '); printer->putchar (printer, ' ');
ell_print_seq (line->head); ell_print_seq (printer, line->head);
putchar (line->next ? ';' : ' '); printer->putchar (printer, line->next ? ';' : ' ');
} }
putchar ('}'); printer->putchar (printer, '}');
return true; return true;
} }
static bool static bool
ell_print_set (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;
putchar ('@'); printer->putchar (printer, '@');
ell_print_seq (list->head->next); ell_print_seq (printer, list->head->next);
return true; return true;
} }
static bool static bool
ell_print_list (struct ell_v *list) { ell_print_list (struct ell_printer *printer, struct ell_v *list) {
if (!list->head || strcmp (list->head->string, "list")) if (!list->head || strcmp (list->head->string, "list"))
return false; return false;
putchar ('['); printer->putchar (printer, '[');
ell_print_seq (list->head->next); ell_print_seq (printer, list->head->next);
putchar (']'); printer->putchar (printer, ']');
return true; return true;
} }
static void static void
ell_print_v (struct ell_v *v) { ell_print_v (struct ell_printer *printer, struct ell_v *v) {
if (ell_print_string (v) if (ell_print_string (printer, v)
|| ell_print_block (v) || ell_print_block (printer, v)
|| ell_print_set (v) || ell_print_set (printer, v)
|| ell_print_list (v)) || ell_print_list (printer, v))
return; return;
putchar ('('); printer->putchar (printer, '(');
ell_print_seq (v->head); ell_print_seq (printer, v->head);
putchar (')'); printer->putchar (printer, ')');
} }
static void static void
ell_print_seq (struct ell_v *v) { ell_print_seq (struct ell_printer *printer, struct ell_v *v) {
for (; v; v = v->next) { for (; v; v = v->next) {
ell_print_v (v); ell_print_v (printer, v);
if (v->next) if (v->next)
putchar (' '); printer->putchar (printer, ' ');
} }
} }
@ -984,6 +994,27 @@ static struct ell_v * ell_boolean (bool b) { return ell_string ("1", b); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
ell_stdout_printer_putchar (struct ell_printer *self, unsigned char c) {
(void) self;
(void) putchar (c);
}
static struct ell_printer ell_stdout_printer = { ell_stdout_printer_putchar };
struct ell_buffer_printer {
struct ell_printer super; ///< Superclass
struct ell_buffer *output; ///< Where to append the result to
};
static void
ell_buffer_printer_putchar (struct ell_printer *printer, unsigned char c) {
struct ell_buffer_printer *self = (struct ell_buffer_printer *) printer;
ell_buffer_append_c (self->output, c);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ell_defn (ell_fn_local) { ell_defn (ell_fn_local) {
struct ell_v *names = args; struct ell_v *names = args;
if (!names || names->type != ELL_LIST) if (!names || names->type != ELL_LIST)
@ -1088,7 +1119,7 @@ ell_defn (ell_fn_print) {
(void) result; (void) result;
for (; args; args = args->next) { for (; args; args = args->next) {
if (args->type != ELL_STRING) if (args->type != ELL_STRING)
ell_print_v (args); ell_print_v (&ell_stdout_printer, args);
else if (fwrite (args->string, 1, args->len, stdout) != args->len) else if (fwrite (args->string, 1, args->len, stdout) != args->len)
return ell_error (ell, "write failed: %s", strerror (errno)); return ell_error (ell, "write failed: %s", strerror (errno));
} }
@ -1097,11 +1128,11 @@ ell_defn (ell_fn_print) {
ell_defn (ell_fn_cat) { ell_defn (ell_fn_cat) {
struct ell_buffer buf = ELL_BUFFER_INITIALIZER; struct ell_buffer buf = ELL_BUFFER_INITIALIZER;
struct ell_buffer_printer bp = { { ell_buffer_printer_putchar }, &buf };
for (; args; args = args->next) { for (; args; args = args->next) {
if (args->type != ELL_STRING) { if (args->type != ELL_STRING)
free (buf.s); ell_print_v (&bp.super, args);
return ell_error (ell, "cannot concatenate lists"); 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)

2
repl.c
View File

@ -36,7 +36,7 @@ run (struct ell *ell, struct ell_v *program) {
ell->error = NULL; ell->error = NULL;
ell->memory_failure = false; ell->memory_failure = false;
} else { } else {
ell_print_seq (result); ell_print_seq (&ell_stdout_printer, result);
putchar ('\n'); putchar ('\n');
ell_free_seq (result); ell_free_seq (result);
} }