···6161 in
6262 Printf.sprintf "parse error at %s%s: expected %s"
6363 pos_str context (String.concat " or " e.expected)
6464+6565+module Memo : sig
6666+ type 'a table
6767+ val create : unit -> 'a table
6868+ val find : 'a table -> string -> int -> 'a option
6969+ val add : 'a table -> string -> int -> 'a -> unit
7070+end = struct
7171+ type 'a table = (string * int, 'a) Hashtbl.t
7272+ let create () = Hashtbl.create 64
7373+ let find tbl name pos = Hashtbl.find_opt tbl (name, pos)
7474+ let add tbl name pos v = Hashtbl.replace tbl (name, pos) v
7575+end
7676+7777+type 'a memo_table = ('a * Char_input.t, error) result Memo.table
···379379 | Ok _ as r -> r
380380 | Error e -> Error { e with Combin.expected = [[%e estring ~loc label]] }]
381381382382+ | Memo { name; p; loc } ->
383383+ let p_code = compile ~loc env p in
384384+ let name_expr = estring ~loc name in
385385+ [%expr
386386+ let pos = I.position input in
387387+ match Combin.Memo.find _memo [%e name_expr] pos with
388388+ | Some r -> r
389389+ | None ->
390390+ let r = [%e p_code] in
391391+ Combin.Memo.add _memo [%e name_expr] pos r;
392392+ r]
393393+382394 | Fix { body; _ } ->
383395 [%expr
384396 let rec parser_fix = [%e body] in
385397 parser_fix input]
386398387399 | Var { name; loc } ->
388388- [%expr [%e evar ~loc name] (module I) input]
400400+ [%expr [%e evar ~loc name] (module I) _memo input]
389401390402and compile_committed_alt ~loc env p q p_first q_first =
391403 let p_code = compile ~loc env p in
···117117 Ir.Map { loc; f; p = expr_to_ir ~loc p }
118118 | Pexp_apply ({ pexp_desc = Pexp_ident { txt = Lident "<?>"; _ }; _ }, [(Nolabel, p); (Nolabel, { pexp_desc = Pexp_constant (Pconst_string (label, _, _)); _ })]) ->
119119 Ir.Label { loc; p = expr_to_ir ~loc p; label }
120120+ | Pexp_apply ({ pexp_desc = Pexp_ident { txt = Lident "memo"; _ }; _ }, [(Nolabel, { pexp_desc = Pexp_constant (Pconst_string (name, _, _)); _ }); (Nolabel, p)]) ->
121121+ Ir.Memo { loc; name; p = expr_to_ir ~loc p }
120122121123 | Pexp_apply ({ pexp_desc = Pexp_ident { txt = Lident "fix"; _ }; _ }, [(Nolabel, fn)]) ->
122124 let (pats, body) = extract_fun_params fn in
···157159 Location.raise_errorf ~loc:err_loc "%s" msg
158160 ) errors;
159161 let body = Codegen.compile ~loc [] ir in
160160- [%expr fun (type inp) (module I : Combin.INPUT with type t = inp and type token = char) (input : inp) -> [%e body]]
162162+ [%expr fun (type inp) (module I : Combin.INPUT with type t = inp and type token = char) (input : inp) ->
163163+ let _memo = Combin.Memo.create () in
164164+ [%e body]]
161165162166let parser_extension =
163167 Extension.V3.declare
···183187 let bindings = extract_let_bindings str_items in
184188 let compiled = List.map (fun (name, expr, binding_loc) ->
185189 let ir = expr_to_ir ~loc:binding_loc expr in
186186- let errors = Check.check_expr [] ir in
190190+ let memoized_ir = Ir.Memo { loc = binding_loc; name; p = ir } in
191191+ let errors = Check.check_expr [] memoized_ir in
187192 List.iter (fun e ->
188193 let err_loc = Check.error_loc e in
189194 let msg = Check.format_error e in
190195 Location.raise_errorf ~loc:err_loc "%s" msg
191196 ) errors;
192192- let body = Codegen.compile ~loc:binding_loc [] ir in
193193- let func = [%expr fun (type inp) (module I : Combin.INPUT with type t = inp and type token = char) (input : inp) -> [%e body]] in
197197+ let body = Codegen.compile ~loc:binding_loc [] memoized_ir in
198198+ let func = [%expr fun (type inp) (module I : Combin.INPUT with type t = inp and type token = char) _memo (input : inp) -> [%e body]] in
194199 Ast_builder.Default.value_binding ~loc:binding_loc
195200 ~pat:(Ast_builder.Default.pvar ~loc:binding_loc name)
196201 ~expr:func