#ifndef TOKEN_H
#define TOKEN_H

#include "./str.h"

enum token_type_enum {
	TT_EOF = -1,
	TT_ILLEGAL = 0,

	TT_IDENT,
	TT_INT_LIT,
	TT_STR_LIT,

	TT_ASSIGN,
	TT_PLUS,
	TT_BANG,
	TT_SLASH,
	
	TT_EQ,     /* '==' */
	TT_NOT_EQ, /* '!=' */

	TT_COMMA,
	TT_SEMICOLON,
	TT_ASTERISK,  /* '*' */
	TT_AMPERSAND, /* '&' */
	TT_DASH,      /* '-' */
	TT_DOT,       /* '.' */

	TT_LPAREN,
	TT_RPAREN,
	TT_LBRACE,
	TT_RBRACE,
	TT_LBRACKET,  /* '[' */
	TT_RBRACKET,  /* ']' */
	TT_LABRACKET, /* '<' */
	TT_RABRACKET, /* '>' */

	TT_FUNCION,
	TT_RETURN,
	TT_CONST,
	TT_STRUCT,
	TT_ENUM,
	TT_TYPE,
	TT_FOR,
	TT_WHILE,
	TT_DO,
	TT_CONTINUE,
	TT_IF,
	TT_ELSE,
	TT_SWITCH,
	TT_CASE,
	TT_BREAK,

	TT_COMMENT,

	TT_PP_INCLUDE,
	TT_PP_DEFINE,
	TT_PP_IFNDEF,
	TT_PP_IFDEF,
	TT_PP_IF,

	TT_SQUOTE,
	TT_DQUOTE,

	TT_TOTAL
};

struct token_type {
	enum token_type_enum code;
	const char *name;
};

struct token {
	struct token_type typ;
	struct str lit;
};

struct token TOKEN_ILLEGAL = {{TT_ILLEGAL, "TT_ILLEGAL"}, STR_EMPTY};

struct token token_create(enum token_type_enum tte, struct str lit);
struct token_type token_type_create(enum token_type_enum tte);
const char *token_type_enum_2_cstr(enum token_type_enum tte);

#if defined(IMP) | defined(TOKEN_IMP)


struct
token token_create(enum token_type_enum tte, struct str lit)
{
	struct token t = {0};
	t.typ = token_type_create(tte);
	t.lit = lit;
	return t;
}

struct token_type
token_type_create(enum token_type_enum tte)
{
	struct token_type tt = {0};

	tt.code = tte;
	tt.name = token_type_enum_2_cstr(tte);

	return tt;
}

const char *
token_type_enum_2_cstr(enum token_type_enum tte)
{
#define _TOKEN_CASE(it) case it: return #it; break;
	switch ( tte ) {
	_TOKEN_CASE(TT_EOF);
	_TOKEN_CASE(TT_ILLEGAL);

	_TOKEN_CASE(TT_IDENT);
	_TOKEN_CASE(TT_INT_LIT);
	_TOKEN_CASE(TT_STR_LIT);

	_TOKEN_CASE(TT_ASSIGN);
	_TOKEN_CASE(TT_PLUS);
	_TOKEN_CASE(TT_BANG);
	_TOKEN_CASE(TT_SLASH);

	_TOKEN_CASE(TT_EQ);
	_TOKEN_CASE(TT_NOT_EQ);

	_TOKEN_CASE(TT_COMMA);
	_TOKEN_CASE(TT_SEMICOLON);
	_TOKEN_CASE(TT_ASTERISK);
	_TOKEN_CASE(TT_AMPERSAND);
	_TOKEN_CASE(TT_DASH);
	_TOKEN_CASE(TT_DOT);

	_TOKEN_CASE(TT_LPAREN);
	_TOKEN_CASE(TT_RPAREN);
	_TOKEN_CASE(TT_LBRACE);
	_TOKEN_CASE(TT_RBRACE);
	_TOKEN_CASE(TT_LBRACKET);
	_TOKEN_CASE(TT_RBRACKET);
	_TOKEN_CASE(TT_LABRACKET);
	_TOKEN_CASE(TT_RABRACKET);

	_TOKEN_CASE(TT_FUNCION);
	_TOKEN_CASE(TT_RETURN);
	_TOKEN_CASE(TT_CONST);
	_TOKEN_CASE(TT_STRUCT);
	_TOKEN_CASE(TT_ENUM);
	_TOKEN_CASE(TT_TYPE);
	_TOKEN_CASE(TT_FOR);
	_TOKEN_CASE(TT_WHILE);
	_TOKEN_CASE(TT_DO);
	_TOKEN_CASE(TT_CONTINUE);
	_TOKEN_CASE(TT_IF);
	_TOKEN_CASE(TT_ELSE);
	_TOKEN_CASE(TT_SWITCH);
	_TOKEN_CASE(TT_CASE);
	_TOKEN_CASE(TT_BREAK);

	_TOKEN_CASE(TT_COMMENT);
	
	_TOKEN_CASE(TT_PP_INCLUDE);
	_TOKEN_CASE(TT_PP_DEFINE);
	_TOKEN_CASE(TT_PP_IFNDEF);
	_TOKEN_CASE(TT_PP_IFDEF);
	_TOKEN_CASE(TT_PP_IF);

	_TOKEN_CASE(TT_SQUOTE);
	_TOKEN_CASE(TT_DQUOTE);

	_TOKEN_CASE(TT_TOTAL);
	}
	return "UNKNOWN TOKEN";
#undef _TOKEN_CASE
}

#endif /* defined(IMP) | defined(TOKEN_IMP) */

#endif /* TOKEN_H */
