type error = { line : int; column : int; message : string } let position lexbuf = let p = lexbuf.Lexing.lex_curr_p in (p.Lexing.pos_lnum, p.Lexing.pos_cnum - p.Lexing.pos_bol) let parse source = let lexbuf = Lexing.from_string source in match Parser.program Lexer.token lexbuf with | statements -> Ok statements | exception Lexer.Error message -> let line, column = position lexbuf in Error { line; column; message } | exception Parser.Error -> let line, column = position lexbuf in Error { line; column; message = Printf.sprintf "syntax error before %S" (Lexing.lexeme lexbuf); } let parse_string source = match parse source with | Ok statements -> Ok statements | Error { line; message; _ } -> Error (Printf.sprintf "line %d: %s" line message)