typedef struct Visitor { Tokens tokens; size_t current; } Visitor; Token peek_token(const Visitor *visitor) { return visitor->tokens.buf[visitor->current]; } Token next_token(Visitor *visitor) { return visitor->tokens.buf[visitor->current++]; } bool has_next_token(const Visitor *visitor) { return visitor->current < visitor->tokens.size; } Object * parse_fixnum(Token tok) { ssize_t num = 0; int sign = 1; for (size_t i = 0; i < tok.value.n; i++) { char c = tok.value.start[i]; if (c == '-') { sign = -1; continue; } num = num * 10 + (c - '0'); } return make_fixnum(num * sign); } Object * parse_tree(Visitor *vs); Object * parse_list(Visitor *vs) { Token tok = peek_token(vs); if (tok.type == TOKEN_EOF) { return obj_err; } Object *next_obj = parse_tree(vs); if (next_obj == obj_err) { return obj_err; } Object *root = make_pair(next_obj, obj_nil); Object *list = root; while (has_next_token(vs)) { Token tok = peek_token(vs); if (tok.type == TOKEN_RPAREN) { next_token(vs); break; } if (tok.type == TOKEN_EOF) { free_objects(root); return obj_err; } next_obj = parse_tree(vs); if (next_obj == obj_err) { free_objects(root); return obj_err; } list->cdr = make_pair(next_obj, obj_nil); list = list->cdr; } return root; } Object * parse_tree(Visitor *vs) { Token tok = next_token(vs); switch (tok.type) { case TOKEN_FIXNUM: { return parse_fixnum(tok); } break; case TOKEN_TRUE: { return obj_true; } break; case TOKEN_FALSE: { return obj_false; } break; case TOKEN_RPAREN: { error_push((Error){ .type = ERR_TYPE_PARSER, .value = ERR_UNBALANCED_PAREN, .line = tok.line, .col = tok.column, }); return obj_err; } break; case TOKEN_QUOTE: { Object *quote_sym = make_symbol((StringView){"quote", 5}); Object *next_obj = parse_tree(vs); if (next_obj == obj_err) { free_objects(quote_sym); return obj_err; } return make_pair(quote_sym, make_pair(next_obj, obj_nil)); } break; case TOKEN_LPAREN: { Object *obj = parse_list(vs); if (obj == obj_err) { error_push((Error){ .type = ERR_TYPE_PARSER, .value = ERR_UNBALANCED_PAREN, .line = tok.line, .col = tok.column, }); } return obj; } break; case TOKEN_STRING: { Object *obj = make_string(); append_string(obj, tok.value); return obj; } break; case TOKEN_SYMBOL: { return make_symbol(tok.value); } break; case TOKEN_NIL: { return obj_nil; } break; default: { break; } break; } error_push((Error){ .type = ERR_TYPE_PARSER, .value = ERR_EOF_REACHED, .line = tok.line, .col = tok.column, }); return obj_err; }