| open Source | |
| type annot = annot' Source.phrase | |
| and annot' = {name : Ast.name; items : item list} | |
| and item = item' Source.phrase | |
| and item' = | |
| | Atom of string | |
| | Var of string | |
| | String of string | |
| | Nat of string | |
| | Int of string | |
| | Float of string | |
| | Parens of item list | |
| | Annot of annot | |
| (* Stateful recorder for annotations *) | |
| (* I wish this could be encapsulated in the parser somehow *) | |
| module NameMap = Map.Make(struct type t = Ast.name let compare = compare end) | |
| type map = annot list NameMap.t | |
| let current : map ref = ref NameMap.empty | |
| let current_source : Buffer.t = Buffer.create 512 | |
| let reset () = | |
| current := NameMap.empty; | |
| Buffer.clear current_source | |
| let get_source () = | |
| Buffer.contents current_source | |
| let extend_source s = | |
| Buffer.add_string current_source s | |
| let record annot = | |
| let old = Option.value (NameMap.find_opt annot.it.name !current) ~default:[] in | |
| current := NameMap.add annot.it.name (annot::old) !current | |
| let is_contained r1 r2 = r1.left >= r2.left && r1.right <= r2.right | |
| let get_all () = | |
| let all = !current in | |
| current := NameMap.empty; | |
| all | |
| let filter f map = | |
| NameMap.filter (fun _ annots -> annots <> []) | |
| (NameMap.map (List.filter f) map) | |
| let get r = | |
| let sub = filter (fun annot -> is_contained annot.at r) !current in | |
| let map' = filter (fun annot -> not (is_contained annot.at r)) !current in | |
| current := map'; | |
| sub |