type code_pos = { line : int; col : int } type lexer_error = { pos : code_pos; msg : string } module LexerError = struct type t = lexer_error let make (pos : code_pos) (msg : string) : lexer_error = { pos; msg } let print (e : lexer_error) = Printf.printf "LexerError at line %d, column %d: %s\n" e.pos.line e.pos.col e.msg end type parser_error = { pos : code_pos; msg : string } module ParserError = struct type t = parser_error let make (pos : code_pos) (msg : string) : parser_error = { pos; msg } let print (e : parser_error) = Printf.printf "ParserError at line %d, column %d: %s\n" e.pos.line e.pos.col e.msg end type runtime_error = { pos : code_pos; msg : string; is_break : bool } module RuntimeError = struct type t = parser_error let make (pos : code_pos) (msg : string) : runtime_error = { pos; msg; is_break = false } let break () : runtime_error = let pos = { line = -1; col = -1 } in let msg = "" in { pos; msg; is_break = true } let print (e : runtime_error) = Printf.printf "RuntimeError at line %d, column %d: %s\n" e.pos.line e.pos.col e.msg end type lox_error = | LexerError of lexer_error list | ParserError of parser_error list | RuntimeError of runtime_error let print_error (e : lox_error) = match e with | LexerError es -> let num_errors = List.length es in assert (num_errors <> 0); Printf.printf "found %d %s:\n" num_errors (if num_errors = 1 then "LexerError" else "LexerErrors"); List.iter LexerError.print es | ParserError es -> let num_errors = List.length es in assert (num_errors <> 0); Printf.printf "found %d %s:\n" num_errors (if num_errors = 1 then "ParserError" else "ParserErrors"); List.iter ParserError.print es | RuntimeError e -> RuntimeError.print e let of_lexer_error e = Result.map_error (fun e -> LexerError e) e let of_parser_error e = Result.map_error (fun e -> ParserError e) e let of_runtimer_error e = Result.map_error (fun e -> RuntimeError e) e