#ifndef PARSER_AUX
#define PARSER_AUX

#include "error.h"
#include "lexer.h"

struct control_vista {
   const token* ini;
   const token*& p_ref;

   control_vista(const token*& p)
   : ini(p), p_ref(p) {
   }

   explicit operator std::string_view( ) const {
      return { ini->vista.begin( ), size_t(ini == p_ref ? 0 : (p_ref - 1)->vista.end( ) - ini->vista.begin( )) };
   }
};

token espera(const token*& p, tipo_token t) {
   if (p->tipo == t) {
      return *p++;
   } else {
      throw error("Token inesperado", p->vista);
   }
}

// funciones que toman el tipo del token

int precedencia(tipo_token t) {
   switch (t) {
   case ASIGNACION:
   case MAS_ASIGNACION:
   case MENOS_ASIGNACION:
   case POR_ASIGNACION:
   case ENTRE_ASIGNACION:
   case MODULO_ASIGNACION:
      return 0;
   case OR:
      return 1;
   case AND:
      return 2;
   case MENOR:
   case MENOR_IGUAL:
   case MAYOR:
   case MAYOR_IGUAL:
   case IGUAL:
   case DIFERENTE:
      return 3;
   case MAS:
   case MENOS:
      return 4;
   case POR:
   case ENTRE:
   case MODULO:
      return 5;
   default:
      return -1;
   };
}

int asociatividad(tipo_token t) {
   return (precedencia(t) != 0);
}

bool es_termino(tipo_token t) {
   return (t == IDENTIFICADOR ||
           t == LITERAL_ENTERA || t == LITERAL_CADENA ||
           t == INT || t == CHAR || t == VOID ||
           t == PRINT || t == SCAN);
}

bool es_operador_prefijo(tipo_token t) {
   return (t == MAS || t == MENOS ||
           t == NOT || t == TAMANYO || t == DIRECCION);
}

bool es_operador_binario(tipo_token t) {
   return precedencia(t) != -1;
}

bool es_operador_posfijo(tipo_token t) {
   return (t == CORCHETE_IZQ || t == PARENTESIS_IZQ ||
           t == COMILLA);
}

bool es_inicio_expr(tipo_token t) {
   return (es_termino(t) || es_operador_prefijo(t) || t == PARENTESIS_IZQ || t == CORCHETE_IZQ);
}

// funciones que toman el apuntador

int precedencia(const token* p) {
   return precedencia(p->tipo);
}

int asociatividad(const token* p) {
   return asociatividad(p->tipo);
}

bool es_operador_prefijo(const token* p) {
   return es_operador_prefijo(p->tipo);
}

bool es_operador_binario(const token* p) {
   return es_operador_binario(p->tipo);
}

bool es_operador_posfijo(const token* p) {
   return es_operador_posfijo(p->tipo);
}

bool es_termino(const token* p) {
   return es_termino(p->tipo);
}

bool es_inicio_expr(const token* p) {
   return es_inicio_expr(p->tipo);
}

#endif
