// Parser descendente recursivo: una función por cada regla de la gramática.
//
//   expr    → compare
//   compare → sum [ ("<" | "<=" | ">" | ">=" | "==" | "!=") sum ]
//   sum     → term (("+" | "-") term)*
//   term    → unary (("*" | "/") unary)*
//   unary   → "-" unary | primary
//   primary → NUMBER | NAME | "(" expr ")"
//
// Cada parse_* mira p->current, consume lo que le toca y devuelve un árbol del que quien
// llama es owner. Si falla, deja el error llenado, libera lo suyo y devuelve NULL.
#include "parser.h"

#include <stdio.h>
#include <stdlib.h>

#include "lexer.h"

typedef struct {
    Lexer *lexer;
    Token current;      // el token que toca mirar, todavía sin consumir
    ParseError *error;
} Parser;

static Expr *parse_expr(Parser *p);

// Pasa al token siguiente.
static void advance(Parser *p) {
    p->current = lexer_next(p->lexer);
}

// Por escribir (parte 3): anota el error en p->error, con la línea y la columna de token.
// Si token es un TOKEN_ERROR, el mensaje es token.text: el analizador léxico ya lo explicó.
// Si no, es message. Copien con snprintf.
static void syntax_error(Parser *p, Token token, const char *message) {
    (void) p;
    (void) token;
    (void) message;
}

// Por escribir (parte 2): NUMBER | NAME | "(" expr ")"
// Cualquier otro token es un error, y aquí se reporta con syntax_error.
static Expr *parse_primary(Parser *p) {
    syntax_error(p, p->current, "se esperaba un número, un nombre o '('");
    return NULL;
}

// Por escribir (parte 2): "-" unary | primary
// -x se construye como 0 - x: no hay una variante nueva en Expr.
static Expr *parse_unary(Parser *p) {
    return parse_primary(p);
}

// Por escribir (parte 2): unary (("*" | "/") unary)*
static Expr *parse_term(Parser *p) {
    return parse_unary(p);
}

// Por escribir (parte 2): term (("+" | "-") term)*
static Expr *parse_sum(Parser *p) {
    return parse_term(p);
}

// Por escribir (parte 2): sum [ ("<" | "<=" | ">" | ">=" | "==" | "!=") sum ]
// Hay un comparador como máximo. Sin ciclo: 1 < 2 < 3 es un error.
static Expr *parse_compare(Parser *p) {
    return parse_sum(p);
}

// Ya está hecha. La próxima semana, aquí entra if.
static Expr *parse_expr(Parser *p) {
    return parse_compare(p);
}

// Ya está hecha.
Expr *parse_expression(const char *source, ParseError *error) {
    error->line = 0;
    error->column = 0;
    error->message[0] = '\0';

    Parser parser = {.lexer = lexer_new(source), .error = error};
    if (parser.lexer == NULL) {
        snprintf(error->message, sizeof error->message, "no hay memoria");
        return NULL;
    }
    advance(&parser);

    Expr *tree = parse_expr(&parser);
    if (tree != NULL && parser.current.kind != TOKEN_END) {
        syntax_error(&parser, parser.current, "sobra texto después de la expresión");
        expr_free(tree);
        tree = NULL;
    }
    lexer_free(parser.lexer);
    return tree;
}
