]> git.lizzy.rs Git - nothing.git/commitdiff
(#301) Make parser support lists
authorrexim <reximkut@gmail.com>
Sun, 26 Aug 2018 22:29:23 +0000 (05:29 +0700)
committerrexim <reximkut@gmail.com>
Sun, 26 Aug 2018 22:29:23 +0000 (05:29 +0700)
src/script/expr.c
src/script/expr.h
src/script/parser.c

index 90c156c8f8202f582611d813e38112f5b485d9e3..68d98c2def80699f2b0e29db089901ad8e624ab4 100644 (file)
@@ -44,6 +44,15 @@ struct Expr cons_as_expr(struct Cons *cons)
     return expr;
 }
 
+struct Expr void_expr(void)
+{
+    struct Expr expr = {
+        .type = EXPR_VOID
+    };
+
+    return expr;
+}
+
 void print_atom_as_sexpr(struct Atom *atom)
 {
     assert(atom);
@@ -98,6 +107,9 @@ void print_expr_as_sexpr(struct Expr expr)
     case EXPR_CONS:
         print_cons_as_sexpr(expr.cons);
         break;
+
+    case EXPR_VOID:
+        break;
     }
 }
 
@@ -111,6 +123,9 @@ void destroy_expr(struct Expr expr)
     case EXPR_CONS:
         destroy_cons(expr.cons);
         break;
+
+    case EXPR_VOID:
+        break;
     }
 }
 
index 01dfa6064321995a394e25b6518b27dca7765255..bf77829988f25a85e9c57a9d86eab6cee3cc4f9e 100644 (file)
@@ -9,7 +9,8 @@ struct Atom;
 enum ExprType
 {
     EXPR_ATOM = 0,
-    EXPR_CONS
+    EXPR_CONS,
+    EXPR_VOID
 };
 
 // TODO(#285): there is no way to execute struct Expr
@@ -22,10 +23,9 @@ struct Expr
     };
 };
 
-
-
 struct Expr atom_as_expr(struct Atom *atom);
 struct Expr cons_as_expr(struct Cons *cons);
+struct Expr void_expr(void);
 
 void destroy_expr(struct Expr expr);
 void print_expr_as_sexpr(struct Expr expr);
index 785809b48e8875bb4acc18cc73c3f948d6a96b70..2645e47e78400ce49bed0cf23bcc25844f97b7c6 100644 (file)
@@ -25,7 +25,17 @@ static struct ParseResult parse_cdr(struct Token current_token)
     return parse_success(cdr.expr, current_token.end);
 }
 
-static struct ParseResult parse_cons(struct Token current_token)
+static struct ParseResult parse_list_end(struct Token current_token)
+{
+    if (*current_token.begin != ')') {
+        return parse_failure("Expected )", current_token.begin);
+    }
+
+    return parse_success(atom_as_expr(create_symbol_atom("nil", NULL)),
+                         current_token.end);
+}
+
+static struct ParseResult parse_list(struct Token current_token)
 {
     if (*current_token.begin != '(') {
         return parse_failure("Expected (", current_token.begin);
@@ -34,7 +44,7 @@ static struct ParseResult parse_cons(struct Token current_token)
     current_token = next_token(current_token.end);
 
     if (*current_token.begin == ')') {
-        return parse_success(atom_as_expr(create_symbol_atom("nil", NULL)), current_token.end);
+        return parse_list_end(current_token);
     }
 
     struct ParseResult car = parse_expr(current_token);
@@ -42,13 +52,37 @@ static struct ParseResult parse_cons(struct Token current_token)
         return car;
     }
 
-    struct ParseResult cdr = parse_cdr(next_token(car.end));
+    struct Cons *list = create_cons(car.expr, void_expr());
+    struct Cons *cons = list;
+    current_token = next_token(car.end);
+
+    while (*current_token.begin != '.' &&
+           *current_token.begin != ')' &&
+           *current_token.begin != 0) {
+        car = parse_expr(current_token);
+        if (car.is_error) {
+            destroy_cons(list);
+            return car;
+        }
+
+        cons->cdr = cons_as_expr(create_cons(car.expr, void_expr()));
+        cons = cons->cdr.cons;
+
+        current_token = next_token(car.end);
+    }
+
+    struct ParseResult cdr = *current_token.begin == '.'
+        ? parse_cdr(current_token)
+        : parse_list_end(current_token);
+
     if (cdr.is_error) {
-        destroy_expr(car.expr);
+        destroy_cons(list);
         return cdr;
     }
 
-    return parse_success(cons_as_expr(create_cons(car.expr, cdr.expr)), cdr.end);
+    cons->cdr = cdr.expr;
+
+    return parse_success(cons_as_expr(list), cdr.end);
 }
 
 static struct ParseResult parse_string(struct Token current_token)
@@ -103,10 +137,8 @@ struct ParseResult parse_expr(struct Token current_token)
         return parse_failure("EOF", current_token.begin);
     }
 
-    /* TODO(#301): parse_expr doesn't parse lists */
-
     switch (*current_token.begin) {
-    case '(': return parse_cons(current_token);
+    case '(': return parse_list(current_token);
     /* TODO(#292): parser does not support escaped string characters */
     case '"': return parse_string(current_token);
     default: {}