#include "script/expr.h"
#include "script/gc.h"
-
-static char *string_duplicate(const char *str,
- const char *str_end)
-{
- if (str_end != NULL && str > str_end) {
- return NULL;
- }
-
- const size_t n = str_end == NULL ? strlen(str) : (size_t) (str_end - str);
- char *dup_str = malloc(sizeof(char) * (n + 1));
- if (dup_str == NULL) {
- return NULL;
- }
-
- memcpy(dup_str, str, n);
- dup_str[n] = '\0';
-
- return dup_str;
-}
+#include "str.h"
struct Expr atom_as_expr(struct Atom *atom)
{
void print_expr_as_sexpr(struct Expr expr)
{
- /* TODO(#296): print_expr_as_sexpr doesn't support lists */
switch (expr.type) {
case EXPR_ATOM:
print_atom_as_sexpr(expr.atom);
free(atom);
}
+
+static int atom_as_sexpr(struct Atom *atom, char *output, size_t n)
+{
+ assert(atom);
+ assert(output);
+
+ switch (atom->type) {
+ case ATOM_SYMBOL:
+ return snprintf(output, n, "%s", atom->sym);
+
+ case ATOM_NUMBER:
+ return snprintf(output, n, "%ld", atom->num);
+
+ case ATOM_STRING:
+ return snprintf(output, n, "\"%s\"", atom->str);
+
+ case ATOM_NATIVE:
+ return snprintf(output, n, "<native>");
+ }
+
+ return 0;
+}
+
+static int cons_as_sexpr(struct Cons *head, char *output, size_t n)
+{
+ assert(head);
+ assert(output);
+
+ /* TODO(#378): cons_as_sexpr does not handle encoding errors of snprintf */
+
+ struct Cons *cons = head;
+
+ int m = (int) n;
+
+ int c = snprintf(output, n, "(");
+ if (m - c <= c) {
+ return c;
+ }
+
+ c += expr_as_sexpr(cons->car, output + c, (size_t) (m - c));
+ if (m - c <= 0) {
+ return c;
+ }
+
+ while (cons->cdr.type == EXPR_CONS) {
+ cons = cons->cdr.cons;
+
+ c += snprintf(output + c, (size_t) (m - c), " ");
+ if (m - c <= 0) {
+ return c;
+ }
+
+ c += expr_as_sexpr(cons->car, output + c, (size_t) (m - c));
+ if (m - c <= 0) {
+ return c;
+ }
+ }
+
+ if (cons->cdr.atom->type != ATOM_SYMBOL ||
+ strcmp("nil", cons->cdr.atom->sym) != 0) {
+
+ c += snprintf(output + c, (size_t) (m - c), " . ");
+ if (m - c <= 0) {
+ return c;
+ }
+
+ c += expr_as_sexpr(cons->cdr, output + c, (size_t) (m - c));
+ if (m - c <= 0) {
+ return c;
+ }
+ }
+
+ c += snprintf(output + c, (size_t) (m - c), ")");
+ if (m - c <= 0) {
+ return c;
+ }
+
+ return c;
+}
+
+int expr_as_sexpr(struct Expr expr, char *output, size_t n)
+{
+ switch(expr.type) {
+ case EXPR_ATOM:
+ return atom_as_sexpr(expr.atom, output, n);
+
+ case EXPR_CONS:
+ return cons_as_sexpr(expr.cons, output, n);
+
+ case EXPR_VOID:
+ return 0;
+ }
+
+ return 0;
+}