Files
usagi/main.ml
2025-09-17 22:45:14 +01:00

68 lines
1.8 KiB
OCaml

open Periodic
open Parser
type element =
{ symbol : string
; count : int
}
type molecule =
{ elements : element list
}
let unary_symbol_p : string parser =
let* x = upper in
String.make 1 x |> return
let binary_symbol_p : string parser =
let* x = upper in
let* x' = lower in
String.make 1 x ^ String.make 1 x' |> return
let symbol_p : string parser =
let* xs = binary_symbol_p <++ unary_symbol_p in
match StringMap.find_opt xs periodic_table with
| Some _ -> return xs
| None -> match element_find_closest xs with
| [] -> fail "invalid atomic element"
| xs -> List.fold_left (fun acc x -> acc ^ Printf.sprintf "%s " x) "" xs
|> Printf.sprintf "invalid atomic element. Did you mean any of the following: %s"
|> fail
let element_count_p : int parser =
let* x = many1 digit in
List.to_seq x
|> String.of_seq
|> int_of_string
|> return
let element_p : element parser =
let* s = symbol_p in
let* n = element_count_p <++ return 1 in
{ symbol = s
; count = n
} |> return
let molecule_p : molecule parser =
let* xs = manyTill element_p eof in
return { elements = xs }
let parse_molecule s : (molecule, error list) result =
match make_input s |> molecule_p.run with
| Ok [] -> failwith "TODO: make method total; empty list"
| Ok ((x,_)::_) -> Ok x
| Error xs -> Error xs
let print_molecule (s: molecule) : unit =
List.iter (fun x -> Printf.printf "%s, %i\n" x.symbol x.count) s.elements
let print_error (xs: error list) (s: string) : unit =
List.iter (fun x -> Printf.printf "%s\n%*s\n%s\n\n" s x.column "^" x.content) xs
let molecule s : unit =
match parse_molecule s with
| Ok x -> print_molecule x
| Error xs -> print_error xs s
let () = molecule "C6Hi12O6"