From 5ae69c1cfcc05f3dce30a60fcfe38ce6de7a799d Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Thu, 25 May 2017 18:57:01 +0200
Subject: Finish implementation of printing
Now readds all syntax sugar and quotes strings properly.
Removed automatic line breaking and indenting since it is complicated.
Removed #ifndef since it stopped making any sense.
---
ell.c | 131 ++++++++++++++++++++++++++++++++++++++++++++--------------
interpreter.c | 5 ---
repl.c | 2 +-
3 files changed, 100 insertions(+), 38 deletions(-)
diff --git a/ell.c b/ell.c
index 2d35d4f..1b66f72 100644
--- a/ell.c
+++ b/ell.c
@@ -343,43 +343,111 @@ lexer_errorf (struct lexer *self, const char *fmt, ...) {
return e;
}
-// --- Parsing -----------------------------------------------------------------
+// --- Printing ----------------------------------------------------------------
+
+static void print_item_list (struct item *item);
+
+static bool
+print_string_needs_quoting (struct item *s) {
+ for (size_t i = 0; i < s->len; i++) {
+ unsigned char c = s->value[i];
+ if (lexer_is_whitespace (c) || lexer_tokens[c]
+ || c == LEXER_ESCAPE || c < 32)
+ return true;
+ }
+ return s->len == 0;
+}
+
+static bool
+print_string (struct item *s) {
+ if (s->type != ITEM_STRING)
+ return false;
+ if (!print_string_needs_quoting (s)) {
+ printf ("%s", s->value);
+ return true;
+ }
+
+ putchar (LEXER_STRING_QUOTE);
+ for (size_t i = 0; i < s->len; i++) {
+ unsigned char c = s->value[i];
+ if (c < 32)
+ printf ("\\x%02x", c);
+ else if (c == LEXER_ESCAPE || c == LEXER_STRING_QUOTE)
+ printf ("\\%c", c);
+ else
+ putchar (c);
+ }
+ putchar (LEXER_STRING_QUOTE);
+ return true;
+}
+
+static bool
+print_block (struct item *list) {
+ if (!list->head || strcmp (list->head->value, "quote")
+ || !list->head->next || list->head->next->next
+ || list->head->next->type != ITEM_LIST)
+ return false;
+
+ list = list->head->next->head;
+ for (struct item *line = list; line; line = line->next)
+ if (line->type != ITEM_LIST)
+ return false;
+
+ putchar ('{');
+ for (struct item *line = list; line; line = line->next) {
+ putchar (' ');
+ print_item_list (line->head);
+ putchar (line->next ? ';' : ' ');
+ }
+ putchar ('}');
+ return true;
+}
+
+static bool
+print_set (struct item *list) {
+ if (!list->head || strcmp (list->head->value, "set")
+ || !list->head->next || list->head->next->next)
+ return false;
+
+ putchar ('@');
+ print_item_list (list->head->next);
+ return true;
+}
+
+static bool
+print_list (struct item *list) {
+ if (!list->head || strcmp (list->head->value, "list"))
+ return false;
+
+ putchar ('[');
+ print_item_list (list->head->next);
+ putchar (']');
+ return true;
+}
static void
-print_string (const char *s) {
- putc ('\'', stdout);
- for (; *s; s++)
- if (*s == '\n') printf ("\\n");
- else if (*s == '\\') putc ('\\', stdout);
- else putc (*s, stdout);
- putc ('\'', stdout);
+print_item (struct item *item) {
+ if (print_string (item)
+ || print_block (item)
+ || print_set (item)
+ || print_list (item))
+ return;
+
+ putchar ('(');
+ print_item_list (item->head);
+ putchar (')');
}
static void
-print_tree (struct item *tree, int level) {
- // TODO: also re-add syntax sugar
- for (struct item *iter = tree; iter; iter = iter->next) {
- if (iter != tree)
- printf ("%*s", level, "");
- if (iter->type == ITEM_STRING) {
- print_string (iter->value);
- } else if (iter->head
- && iter->head->type == ITEM_STRING
- && !strcmp (iter->head->value, "list")) {
- printf ("[");
- print_tree (iter->head->next, level + 1);
- printf ("]");
- } else {
- printf ("(");
- print_tree (iter->head, level + 1);
- printf (")");
- }
- if (iter->next)
- printf ("\n");
+print_item_list (struct item *item) {
+ for (; item; item = item->next) {
+ print_item (item);
+ if (item->next)
+ putchar (' ');
}
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// --- Parsing -----------------------------------------------------------------
struct parser {
struct lexer lexer; ///< Tokenizer
@@ -965,9 +1033,8 @@ defn (fn_print) {
(void) result;
for (; args; args = args->next) {
if (args->type != ITEM_STRING)
- // TODO: print lists as their parsable representation
- return set_error (ctx, "cannot print lists");
- if (fwrite (args->value, 1, args->len, stdout) != args->len)
+ print_item (args);
+ else if (fwrite (args->value, 1, args->len, stdout) != args->len)
return set_error (ctx, "write failed: %s", strerror (errno));
}
return true;
diff --git a/interpreter.c b/interpreter.c
index 4159e08..3743c4a 100644
--- a/interpreter.c
+++ b/interpreter.c
@@ -38,11 +38,6 @@ main (int argc, char *argv[]) {
parser_init (&parser, buf.s, buf.len - 1);
const char *e = NULL;
struct item *program = parser_run (&parser, &e);
-#ifndef NDEBUG
- printf ("\x1b[1m%s\x1b[0m\n", buf.s);
- print_tree (program, 0);
- printf ("\n\n");
-#endif
free (buf.s);
if (e) {
printf ("%s: %s\n", "parse error", e);
diff --git a/repl.c b/repl.c
index f14e24f..d374d13 100644
--- a/repl.c
+++ b/repl.c
@@ -36,7 +36,7 @@ run (struct context *ctx, struct item *program) {
ctx->error = NULL;
ctx->memory_failure = false;
} else {
- print_tree (result, 0);
+ print_item_list (result);
putchar ('\n');
item_free_list (result);
}
--
cgit v1.2.3-70-g09d2