Make the printer generic
Now you can concatenate lists like strings.
This commit is contained in:
parent
863ea189eb
commit
0ae4a42335
111
ell.c
111
ell.c
|
@ -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
2
repl.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue