#ifndef LEX_H_
#define LEX_H_

#include <stdint.h>

#include "file.h"

enum tokentype {
	TOK_NUM,
	TOK_IDEN,
	TOK_KEYWORD,
	TOK_OP,
	TOK_SEMICOLON = ';',
	TOK_COMMA = ',',
	TOK_LBRACKET = '[',
	TOK_RBRACKET = ']',
	TOK_LPAREN = '(',
	TOK_RPAREN = ')',
	TOK_LBRACE = '{',
	TOK_RBRACE = '}',
};

enum keyword {
	KEY_VOID,
	KEY_U8,
	KEY_I8,
	KEY_U16,
	KEY_I16,
	KEY_U32,
	KEY_I32,
	KEY_U64,
	KEY_I64,
	KEY_IF,
	KEY_ELSE,
	KEY_WHILE,
	KEY_FOR,
};

static const char* keywords[] = {
	"void",
	"u8",
	"i8",
	"u16",
	"i16",
	"u32",
	"i32",
	"u64",
	"i64",
	"if",
	"else",
	"while",
	"for"
};

static const char* ops[] = {
	"==",
	"=",
	"!=",
	"!",
	"+=",
	"+",
	"-=",
	"-",
	"*=",
	"*",
	"/=",
	"/",
	"%=",
	"%",
	"<<=",
	"<<",
	">>=",
	">>",
	"<=",
	">=",
	"<",
	">",
	"~",
	"&&",
	"&=",
	"&",
	"||",
	"|=",
	"|",
	"^=",
	"^"
};

enum op {
	OP_EQ,
	OP_ASSGN,
	OP_NOTEQ,
	OP_LNOT,
	OP_ADDASSGN,
	OP_ADD,
	OP_SUBASSGN,
	OP_MINUS,
	OP_MULASSGN,
	OP_STAR,
	OP_DIVASSGN,
	OP_DIV,
	OP_MODASSGN,
	OP_MOD,
	OP_LSHIFTASSGN,
	OP_LSHIFT,
	OP_RSHIFTASSGN,
	OP_RSHIFT,
	OP_LESSEQ,
	OP_MOREEQ,
	OP_LESS,
	OP_MORE,
	OP_BNOT,
	OP_LAND,
	OP_BANDASSGN,
	OP_BAND,
	OP_LOR,
	OP_BORASSGN,
	OP_BOR,
	OP_XORASSGN,
	OP_XOR
};

/* base token type */
struct token {
	struct token* next;
	/* location information */
	int row;
	int col;
	size_t len;
	struct file* file;
	/* token type and union */
	enum tokentype type;
	union {
		int64_t num;
		size_t iden;
		enum op op;
		enum keyword keyword;
	};
};

int lex(struct file* state);

#endif
