From: rexim Date: Sun, 26 Aug 2018 22:29:23 +0000 (+0700) Subject: (#301) Make parser support lists X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=7dc8140b5acdc719799f75cde699a1eab7fc0200;hp=7e94e70efcd425b374325ce86abae91d26c01d9c;p=nothing.git (#301) Make parser support lists --- diff --git a/src/script/expr.c b/src/script/expr.c index 90c156c8..68d98c2d 100644 --- a/src/script/expr.c +++ b/src/script/expr.c @@ -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; } } diff --git a/src/script/expr.h b/src/script/expr.h index 01dfa606..bf778299 100644 --- a/src/script/expr.h +++ b/src/script/expr.h @@ -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); diff --git a/src/script/parser.c b/src/script/parser.c index 785809b4..2645e47e 100644 --- a/src/script/parser.c +++ b/src/script/parser.c @@ -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: {}