type token_type = 
  | Eof
  | Identifier of string
  | Digit of string
  | Add
  | Sub
  | Mul
  | Div
  | Mod
  | Pow
  | LParen
  | RParen
  | Equal
  | Arrow
  | Colon
  | Let 
  | In
  | If
  | Then
  | Else
  | Fun
  | Comment of string
  | Fail of string

let op = [
  Add, "+";
  Sub, "-";
  Mul, "*";
  Div, "/";
  Mod, "%";
  Pow, "^";
] |> List.to_seq |> Hashtbl.of_seq

let op2str op = Hashtbl.find op

let symbol = [
  LParen, "(";
  RParen, ")";
  Equal, "=";
  Arrow, "->";
  Colon, ":";
] |> List.to_seq |> Hashtbl.of_seq


let keywordTable = [
  Let, "let";
  In, "in";
  If, "if";
  Then, "then";
  Else, "else";
  Fun, "fun";
] |> List.to_seq |> Hashtbl.of_seq

let str2keywordTable = keywordTable 
  |> Hashtbl.to_seq 
  |> Seq.map (fun (x, y) -> (y, x)) 
  |> Hashtbl.of_seq

let keyword2str keyword = Hashtbl.find keywordTable keyword
let str2keyword str = Hashtbl.find_opt str2keywordTable str

type t = {
  (* token type *)
  token_type: token_type;
  (* start position *)
  pos: int;
}