diff --git a/lib/compiler/Asset_router.ml b/lib/compiler/Asset_router.ml index 15445e9..228dcc2 100644 --- a/lib/compiler/Asset_router.ml +++ b/lib/compiler/Asset_router.ml @@ -11,14 +11,14 @@ let router : (string, URI.t) Hashtbl.t = Hashtbl.create 100 module Error = struct type error = Not_found of string | No_content_address | Failed_to_hash [@@deriving show] - type t = {range: Range.t option; error: error} - let failed_to_hash = error {range = None; error = Failed_to_hash} + type t = {range: Range.t; error: error} + let failed_to_hash ~range = error {range; error = Failed_to_hash} let no_content_address ~range = error {range; error = No_content_address} end open Error -let normalize ?range source_path = +let normalize ~range source_path = try Ok (Unix.realpath source_path) with Unix.Unix_error (e, _, m) -> error @@ -27,16 +27,16 @@ let normalize ?range source_path = error = Not_found (Format.asprintf "%s: %s" (Unix.error_message e) m); } -let install ~(config : Config.t) ~source_path ~content = +let install ~(config : Config.t) ~range ~source_path ~content = let open Result.Syntax in - let* normalized = normalize source_path in + let* normalized = normalize ~range source_path in match Hashtbl.find_opt router normalized with | Some uri -> Ok uri | None -> ( match Multihash_digestif.of_cstruct `Sha3_256 (Cstruct.of_string content) with - | Error _ -> failed_to_hash + | Error _ -> failed_to_hash ~range | Ok hash -> let cid = Cid.v ~version:`Cidv1 ~codec:`Raw ~base:`Base32 ~hash in let cid_str = Cid.to_string cid in @@ -45,9 +45,9 @@ let install ~(config : Config.t) ~source_path ~content = Hashtbl.add router normalized uri; ok uri) -let uri_of_asset ?range ~source_path () = +let uri_of_asset ~range ~source_path () = let open Result.Syntax in - let* normalized = normalize ?range source_path in + let* normalized = normalize ~range source_path in match Hashtbl.find_opt router normalized with | Some uri -> ok uri | None -> no_content_address ~range diff --git a/lib/compiler/Error.ml b/lib/compiler/Error.ml index 99c46ee..23a8a5e 100644 --- a/lib/compiler/Error.ml +++ b/lib/compiler/Error.ml @@ -20,7 +20,7 @@ type t = | Failed_to_load_foreign_blob of string | Failed_to_parse_foreign_blob of string | Failed_to_add_edge of Vertex.t * Vertex.t - | Failed_to_add_vertex of Range.t option * URI.t + | Failed_to_add_vertex of Range.t * URI.t | Unknown_error of string and latex_error = {range: Grace.Range.t; msg: string} @@ -87,32 +87,24 @@ let render_type_error ~range Eval_error.{got; expected} = | Value.Obj _ -> "an object" in let labels = - range - |> Option.fold ~none:[] ~some:(fun range -> - match got with - | Some (Clo _) -> - [ - Label.createf ~range ~priority:Primary - "This is a function. Did you forget to provide some arguments?"; - ] - | Some (Obj _) -> - [ - Label.createf ~range ~priority:Primary - "This is an object. Did you forget to bind this object to an \ - identifier?"; - ] - | Some got -> - [Label.createf ~range ~priority:Primary "this is %s" (show_value got)] - | None -> []) - in - let got_note = - match range with - | None -> - Option.fold got - ~some:(fun got -> [Message.createf "this is %s" (show_value got)]) - ~none:[] - | Some _ -> [] + match got with + | Some (Clo _) -> + [ + Label.createf ~range ~priority:Primary + "This is a function. Did you forget to provide some arguments?"; + ] + | Some (Obj _) -> + [ + Label.createf ~range ~priority:Primary + "This is an object. Did you forget to bind this object to an \ + identifier?"; + ] + | Some got -> + [Label.createf ~range ~priority:Primary "this is %s" (show_value got)] + | None -> [] in + (*let got_note = [Message.createf "this is %s" (show_value got)] in*) + let got_note = [] in let notes = match expected with | [] -> [] @@ -136,9 +128,7 @@ let render_type_error ~range Eval_error.{got; expected} = *) let render_eval_error Eval_error.{error; range} = - let default_labels = - Option.fold ~none:[] ~some:(fun range -> [empty_label ~range]) range - in + let default_labels = [empty_label ~range] in match error with | Type_error err -> render_type_error ~range err | Invalid_URI _ -> Diagnostic.createf Error ~labels:[] ~notes:[] "" @@ -158,8 +148,7 @@ let render_eval_error Eval_error.{error; range} = Diagnostic.createf ~labels:default_labels Error "asset error" | Unresolved_identifier {suggestions; path} -> Diagnostic.createf Error - ~labels: - (Option.fold ~none:[] ~some:(fun range -> [empty_label ~range]) range) + ~labels:[empty_label ~range] ~notes:suggestions "unresolved identifier %a" Trie.pp_path path let render_parse_error Parse.{range; msg} = @@ -238,9 +227,9 @@ let render = | Broken_link link -> render_broken_link link | Broken_transclusion t -> render_broken_transclusion t | Unlinked_attribution_warning w -> render_unlinked_attribution_warning w - | Failed_to_load_foreign_blob _ -> + | Failed_to_load_foreign_blob s -> let labels = [] in - createf ~labels Error "" + createf ~labels Error "Failed to load foreign blob: %s" s | Failed_to_parse_foreign_blob s -> let labels = [] in createf ~labels Error "Failed to parse foreign blob: %s" s @@ -248,7 +237,10 @@ let render = | Failed_to_add_vertex (range, uri) -> let name = Option.get @@ URI.(name uri) in let labels = - fold_range ~range Message.(createf "No file %s.tree found." name) + [ + Label.create ~range ~priority:Primary + Message.(createf "No file %s.tree found." name); + ] in createf ~labels Error "Unresolved import" | Unknown_error _ -> failwith "unknown error" diff --git a/lib/compiler/Error.mli b/lib/compiler/Error.mli index ed5f516..533a43c 100644 --- a/lib/compiler/Error.mli +++ b/lib/compiler/Error.mli @@ -30,7 +30,7 @@ val duplicate_tree : uri:URI.t -> t val of_tex_error : latex_error -> t val failed_to_add_edge : Vertex.t -> Vertex.t -> t -val failed_to_add_vertex : range:Grace.Range.t option -> URI.t -> t +val failed_to_add_vertex : range:Grace.Range.t -> URI.t -> t val collect : (unit -> unit) -> t Seq.t val yield : t -> unit diff --git a/lib/compiler/Eval.ml b/lib/compiler/Eval.ml index ba9ab0f..db21cf9 100644 --- a/lib/compiler/Eval.ml +++ b/lib/compiler/Eval.ml @@ -167,7 +167,7 @@ let get_current_uri ~env ~range = let get_transclusion_flags ~env ~range = let get_bool key = let@ value = Option.bind @@ Symbol_map.find_opt key env.dyn_env in - Result.to_option @@ extract_bool @@ Range.locate_opt range value + Result.to_option @@ extract_bool @@ Range.locate range value in let module S = Expand.Builtins.Transclude in let open Option_util in @@ -269,7 +269,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = in emit_content_node ~env ~range @@ T.prim p @@ T.Content content | Fun (xs, body) -> - focus_clo ~env ?range env.lex_env + focus_clo ~env ~range env.lex_env (List.map (fun (info, x) -> (info, Some x)) xs) body | Ref -> begin @@ -278,12 +278,12 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = let content = T.Content [ - T.Transclude {href; target = T.Taxon; range}; + T.Transclude {href; target = T.Taxon; range = Some range}; T.Text " "; T.Contextual_number href; ] in - emit_content_node ~env ~range @@ Link {href; content; range} + emit_content_node ~env ~range @@ Link {href; content; range = Some range} | Error _ -> let got = None in let expected = [URI] in @@ -300,21 +300,17 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = @@ T.Content [ T.Transclude - {href; target = T.Title {empty_when_untitled = false}; range}; + { + href; + target = T.Title {empty_when_untitled = false}; + range = Some range; + }; ] | Some title -> let* value = eval_tape ~env title in {node with value} |> extract_content in - emit_content_node ~env ~range - @@ Link - { - href; - content; - range = - (assert (Option.is_some range); - range); - } + emit_content_node ~env ~range @@ Link {href; content; range = Some range} | Math (mode, body) -> let* content = let* value = eval_tape ~env:{env with mode = TeX_mode} body in @@ -367,7 +363,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = let* href_arg = eval_pop_arg ~env ~range in let* {value = href; range} = extract_uri ~env href_arg in emit_content_node ~env ~range - @@ T.Transclude {href; target = Full flags; range} + @@ T.Transclude {href; target = Full flags; range = Some range} | Subtree (addr_opt, nodes) -> let flags = get_transclusion_flags ~env ~range in let uri = @@ -387,7 +383,9 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = begin match uri with | Some uri -> Stack.push subtree env.emitted_trees; - let transclusion = T.{href = uri; target = Full flags; range} in + let transclusion = + T.{href = uri; target = Full flags; range = Some range} + in emit_content_node ~env ~range @@ Transclude transclusion | None -> emit_content_node ~env ~range @@ -411,8 +409,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = | Dx_query query -> let job = Job.Syndicate (Json_blob {blob_uri; query}) in (* TODO: *) - let range = Some (Option.get range) in - Stack.push (Range.locate_opt range job) env.jobs; + Stack.push (Range.locate range job) env.jobs; process_tape ~env | other -> let expected = [Dx_query] in @@ -423,7 +420,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = let* source_uri = get_current_uri ~env ~range:node.range in let feed_uri = URI.append_path_component source_uri "atom.xml" in let job = Job.Syndicate (Atom_feed {source_uri; feed_uri}) in - Stack.push (Range.locate_opt range job) env.jobs; + Stack.push (Range.locate range job) env.jobs; process_tape ~env | Embed_tex -> let* preamble, body = @@ -469,13 +466,13 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = ] in let artefact = T.{hash; content; sources} in - Stack.push (Range.locate_opt range (Job.LaTeX_to_svg job)) env.jobs; + Stack.push (Range.locate range (Job.LaTeX_to_svg job)) env.jobs; emit_content_node ~env ~range @@ T.Artefact artefact | Route_asset -> let* Range.{value = source_path; range = path_range} = pop_text_arg_loc ~env ~range in - begin match Asset_router.uri_of_asset ?range:path_range ~source_path () with + begin match Asset_router.uri_of_asset ~range:path_range ~source_path () with | Ok uri -> emit_content_nodes ~env ~range @@ [T.Route_of_uri uri] | Error e -> of_asset_error e end @@ -489,7 +486,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = in let sym = Symbol.named ["obj"] in Symbol_table.replace env.heap sym Value.{prototype = None; methods = table}; - focus ~env ?range:node.range @@ Value.Obj sym + focus ~env ~range:node.range @@ Value.Obj sym | Patch {obj; self; super; methods} -> let* obj_ptr = let* value = eval_tape ~env obj in @@ -504,7 +501,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = let sym = Symbol.named ["obj"] in Symbol_table.replace env.heap sym Value.{prototype = Some obj_ptr; methods = table}; - focus ~env ?range:node.range @@ Value.Obj sym + focus ~env ~range:node.range @@ Value.Obj sym | Group (d, body) -> let l, r = delim_to_strings d in let* content = @@ -512,7 +509,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = let* body = extract_content {node with value} in ok @@ T.Content ((T.Text l :: T.extract_content body) @ [T.Text r]) in - focus ~env ?range:node.range @@ Value.Content (T.compress_content content) + focus ~env ~range:node.range @@ Value.Content (T.compress_content content) | Call (obj, method_name) -> let* sym = let* value = eval_tape ~env obj in @@ -544,7 +541,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = unbound_method ~range method_name) in let* result = call_method ~env @@ Symbol_table.find env.heap sym in - focus ~env ?range:node.range result + focus ~env ~range:node.range result | Put (k, v, body) -> let* value = eval_tape ~env k in let* k = extract_sym {node with value} in @@ -554,7 +551,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = ~env:{env with dyn_env = Symbol_map.add k symbol env.dyn_env} body in - focus ~env ?range:node.range body + focus ~env ~range:node.range body | Default (k, v, body) -> let* k = let* value = (eval_tape ~env) k in @@ -570,7 +567,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = let* dyn_env = upd env.dyn_env in eval_tape ~env:{env with dyn_env} body in - focus ~env ?range:node.range body + focus ~env ~range:node.range body | Get k -> let* k = let* value = eval_tape ~env k in @@ -578,7 +575,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = in begin match Symbol_map.find_opt k env.dyn_env with | None -> unbound_fluid_symbol ~range k - | Some v -> focus ~env ?range:node.range v + | Some v -> focus ~env ~range:node.range v end | Verbatim str -> emit_content_node ~env ~range @@ CDATA str | Title -> @@ -609,7 +606,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = (* The URI parser is "too resilient", extracting vertices can't fail*) assert false in - let attribution = T.{role; vertex; range = arg.range} in + let attribution = T.{role; vertex; range = Some arg.range} in env.frontmatter := { env.frontmatter.contents with @@ -646,7 +643,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = let* taxon = pop_content_arg ~env ~range in env.frontmatter := {env.frontmatter.contents with taxon = Some taxon}; process_tape ~env - | Sym sym -> focus ~env ?range:node.range @@ Value.Sym sym + | Sym sym -> focus ~env ~range:node.range @@ Value.Sym sym | Dx_prop (rel, args) -> let* value = eval_tape ~env rel in let* {value = rel; range = _} = extract_text {node with value} in @@ -656,7 +653,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = extract_dx_term {node with value} in List.iter Error.yield_eval_error errors; - focus ~env ?range:node.range @@ Dx_prop {rel; args} + focus ~env ~range:node.range @@ Dx_prop {rel; args} | Dx_sequent (conclusion, premises) -> let* conclusion = let* value = eval_tape ~env conclusion in @@ -668,7 +665,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = extract_dx_prop {node with value} in List.iter Error.yield_eval_error errors; - focus ~env ?range:node.range @@ Dx_sequent {conclusion; premises} + focus ~env ~range:node.range @@ Dx_sequent {conclusion; premises} | Dx_query (var, positives, negatives) -> let errors, positives = let@ premise = List_util.error_partition @~ positives in @@ -682,8 +679,8 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = extract_dx_prop {node with value} in List.iter Error.yield_eval_error errors; - focus ~env ?range:node.range @@ Dx_query {var; positives; negatives} - | Dx_var name -> focus ~env ?range:node.range @@ Dx_var name + focus ~env ~range:node.range @@ Dx_query {var; positives; negatives} + | Dx_var name -> focus ~env ~range:node.range @@ Dx_var name | Dx_const (type_, arg) -> let* value = eval_tape ~env arg in let arg = {node with value} in @@ -697,7 +694,7 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = ok @@ T.Uri_vertex uri end in - focus ~env ?range:node.range @@ Dx_const const + focus ~env ~range:node.range @@ Dx_const const | Dx_execute -> let* script = eval_pop_arg ~env ~range:node.range |> Result.bind @~ extract_dx_sequent @@ -709,11 +706,11 @@ and eval_node ~env ({value; range} as node) : (Value.t, Eval_error.t) result = and eval_var ~env ~range (x : string) = match String_map.find_opt x env.lex_env with - | Some v -> focus ~env ?range v + | Some v -> focus ~env ~range v | None -> unbound_variable ~range x -and focus ~env ?range = function - | Clo (rho, xs, body) -> focus_clo ~env ?range rho xs body +and focus ~env ~range = function + | Clo (rho, xs, body) -> focus_clo ~env ~range rho xs body | Content content -> begin let* v = process_tape ~env in match v with @@ -732,12 +729,12 @@ and focus ~env ?range = function type_error ~got ~expected ~range end -and focus_clo ~env ?range rho (xs : string option binding list) body = +and focus_clo ~env ~range rho (xs : string option binding list) body = match xs with | [] -> Result.bind (eval_tape ~env:{env with lex_env = rho} body) - (focus ~env ?range) + (focus ~env ~range) | (info, y) :: ys -> begin match pop_arg_opt ~env with | Some arg -> @@ -749,7 +746,7 @@ and focus_clo ~env ?range rho (xs : string option binding list) body = let rhoy = match y with Some y -> String_map.add y yval rho | None -> rho in - focus_clo ~env ?range rhoy ys body + focus_clo ~env ~range rhoy ys body | None -> begin let* c = process_tape ~env in match c with @@ -760,7 +757,7 @@ and focus_clo ~env ?range rho (xs : string option binding list) body = end and emit_content_nodes ~env ~range content = - focus ~env ?range @@ Content (T.Content (T.compress_nodes content)) + focus ~env ~range @@ Content (T.Content (T.compress_nodes content)) and emit_content_node ~env ~range content = emit_content_nodes ~env ~range [content] @@ -805,9 +802,7 @@ let eval_tree : let source = Tree.Expanded.source tree in let nodes = Tree.Expanded.nodes tree in let range = - Option.map - Range.(fun source -> total ~source) - (source :> Grace.Source.t option) + Range.(fun source -> total ~source) (source :> Grace.Source.t) in match eval_tree_inner ~range ~env ~uri nodes with | Error error -> Error.yield_eval_error error diff --git a/lib/compiler/Eval_error.ml b/lib/compiler/Eval_error.ml index 0783f9d..a55a841 100644 --- a/lib/compiler/Eval_error.ml +++ b/lib/compiler/Eval_error.ml @@ -49,7 +49,7 @@ type error = and type_error = {got: Value.t option; expected: expected_value list} [@@deriving show] -type t = {error: error; range: Range.t option} [@@deriving show] +type t = {error: error; range: Range.t} [@@deriving show] let of_asset_error : Asset_router.Error.t -> ('a, t) result = function | {error; range} -> Result.error {error = Asset_error error; range} diff --git a/lib/compiler/Expand.ml b/lib/compiler/Expand.ml index f0e9ccd..f82bcb3 100644 --- a/lib/compiler/Expand.ml +++ b/lib/compiler/Expand.ml @@ -31,9 +31,9 @@ let rec expand_method_calls (base : Syn.t) : Code.t -> Syn.t * Code.t = function expand_method_calls base rest | rest -> (base, rest) -type 'a Effect.t += Entered_range : Range.t option -> unit Effect.t +type 'a Effect.t += Entered_range : Range.t -> unit Effect.t -let entered_range (range : Range.t option) : unit = +let entered_range (range : Range.t) : unit = Effect.perform @@ Entered_range range let rec expand_eff ~(forest : State.t) : Code.t -> Syn.t = function @@ -71,7 +71,7 @@ let rec expand_eff ~(forest : State.t) : Code.t -> Syn.t = function (* Done? *) { value = Link {dest = y; title = Some x}; - range = Range.merge_opt node.range yrange; + range = Range.merge node.range yrange; } :: expand_eff ~forest rest | _ -> {node with value = Group (Squares, x)} :: expand_eff ~forest rest @@ -110,7 +110,7 @@ let rec expand_eff ~(forest : State.t) : Code.t -> Syn.t = function | Alloc x -> let symbol = Symbol.named x in Sc.include_singleton x - (Term [Range.locate_opt node.range (Syn.Sym symbol)], node.range); + (Term [Range.locate node.range (Syn.Sym symbol)], Some node.range); expand_eff ~forest rest | Put (k, v) -> let k = expand_ident node.range k in @@ -156,15 +156,15 @@ let rec expand_eff ~(forest : State.t) : Code.t -> Syn.t = function | Let (x, ys, def) -> let lam = expand_lambda ~forest node.range (ys, def) in let@ () = Sc.section [] in - Sc.import_singleton x (Term [lam], node.range); + Sc.import_singleton x (Term [lam], Some node.range); expand_eff ~forest rest | Def (x, ys, def) -> let lam = expand_lambda ~forest node.range (ys, def) in - Sc.include_singleton x (Term [lam], node.range); + Sc.include_singleton x (Term [lam], Some node.range); expand_eff ~forest rest | Decl_xmlns (prefix, xmlns) -> let path = ["xmlns"; prefix] in - Sc.include_singleton path (Xmlns {prefix; xmlns}, node.range); + Sc.include_singleton path (Xmlns {prefix; xmlns}, Some node.range); expand_eff ~forest rest | Object {self; methods} -> let methods = @@ -173,7 +173,7 @@ let rec expand_eff ~(forest : State.t) : Code.t -> Syn.t = function let@ self = Option.iter @~ self in let var = Range.{value = Syn.Var self; range = node.range} in (* TODO: correct the location *) - Sc.import_singleton [self] (Term [var], node.range) + Sc.import_singleton [self] (Term [var], Some node.range) (* TODO: correct the location*) end; List.map (expand_method ~forest) methods @@ -185,11 +185,13 @@ let rec expand_eff ~(forest : State.t) : Code.t -> Syn.t = function let@ () = Sc.section [] in begin let@ self = Option.iter @~ self in - let self_var = Range.locate_opt None @@ Syn.Var self in - Sc.import_singleton [self] (Term [self_var], node.range); + (* TODO: Don't use builtin range*) + let self_var = Range.(locate builtin_range) @@ Syn.Var self in + Sc.import_singleton [self] (Term [self_var], Some node.range); let@ super = Option.iter @~ super in - let super_var = Range.locate_opt None @@ Syn.Var super in - Sc.import_singleton [super] (Term [super_var], node.range) + (* TODO: Don't use builtin range*) + let super_var = Range.(locate builtin_range) @@ Syn.Var super in + Sc.import_singleton [super] (Term [super_var], Some node.range) end; List.map (expand_method ~forest) methods in @@ -270,8 +272,8 @@ and expand_lambda ~forest range (xs, body) = let@ () = Sc.section [] in let xs = let@ strategy, x = List.map @~ xs in - let var = Range.locate_opt None @@ Syn.Var x in - Sc.import_singleton [x] (Term [var], range); + let var = Range.locate range @@ Syn.Var x in + Sc.import_singleton [x] (Term [var], Some range); (strategy, x) in Range.{value = Syn.Fun (xs, expand_eff ~forest body); range} @@ -318,8 +320,7 @@ let builtins = show_metadata_sym; ] |> Seq.map @@ fun sym -> - ( Symbol.name sym, - (Syn.Term [Range.locate_opt None (Syn.Sym sym)], None) ) + (Symbol.name sym, (Syn.Term [Range.builtin (Syn.Sym sym)], None)) end; begin List.to_seq @@ -377,7 +378,7 @@ let builtins = (["current-tree"], Syn.Current_tree); ] |> Seq.map @@ fun (path, node) -> - (path, (Syn.Term [Range.locate_opt None node], None)) + (path, (Syn.Term [Range.builtin node], None)) end; ] @@ -391,7 +392,7 @@ let expand_tree_inner ~forest (code : Tree.(parsed tree)) : Tree.(expanded tree) let units = Sc.get_export () in let tree : Tree.expanded = {nodes; code = Tree.Parsed.nodes code; units} in let source = Tree.Parsed.source code in - Tree.Expanded.create ?source tree + Tree.Expanded.create ~source tree let expand_tree ~(forest : State.t) (code : Tree.(parsed tree)) : Tree.(expanded tree) * Error.t list = diff --git a/lib/compiler/Expand.mli b/lib/compiler/Expand.mli index 1a38d1c..50db06f 100644 --- a/lib/compiler/Expand.mli +++ b/lib/compiler/Expand.mli @@ -24,6 +24,6 @@ val expand : forest:State.t -> Code.t -> Syn.t val expand_tree : forest:State.t -> Tree.(parsed tree) -> Tree.(expanded tree) * Error.t list -type 'a Effect.t += Entered_range : Range.t option -> unit Effect.t +type 'a Effect.t += Entered_range : Range.t -> unit Effect.t val expand_eff : forest:State.t -> Code.t -> Syn.t diff --git a/lib/compiler/Expand_error.ml b/lib/compiler/Expand_error.ml index 47af482..6f180e8 100644 --- a/lib/compiler/Expand_error.ml +++ b/lib/compiler/Expand_error.ml @@ -6,7 +6,7 @@ type error = | Unresolved_xmlns of string [@@deriving show] -type t = {range: Range.t option; error: error} [@@deriving show] +type t = {range: Range.t; error: error} [@@deriving show] let import_not_found ~range uri = {range; error = Import_not_found uri} let unresolved_identifier ~range = {range; error = Unresolved_identifier} @@ -23,11 +23,7 @@ let render_unresolved_xmlns ~range prefix = "You may fix this by defining an XML namespace:@.\\xmlns:%s{...}" prefix; ] in - let labels = - Option.fold ~none:[] - ~some:(fun range -> [Label.createf ~range ~priority:Primary ""]) - range - in + let labels = [Label.createf ~range ~priority:Primary ""] in Diagnostic.createf Error ~labels ~notes "Unresolved XML namespace" let render {range; error} = diff --git a/lib/compiler/Imports.ml b/lib/compiler/Imports.ml index 968c149..cc9ebd3 100644 --- a/lib/compiler/Imports.ml +++ b/lib/compiler/Imports.ml @@ -149,9 +149,7 @@ let build forest = let env = {forest; follow = false; graph = Forest_graph.create (); errors = []} in - let code = State.get_all_code ~forest:env.forest in - Logs.debug (fun m -> m "imports: got %i parsed trees" List.(length code)); - code + State.get_all_code ~forest:env.forest |> List.iter (fun (uri, code) -> analyse_tree ~uri:(Some uri) ~env Tree.Parsed.(nodes code)); (env.errors, env.graph) diff --git a/lib/compiler/Phases.ml b/lib/compiler/Phases.ml index 8f27592..c0a4af2 100644 --- a/lib/compiler/Phases.ml +++ b/lib/compiler/Phases.ml @@ -101,9 +101,8 @@ let reparse (doc : Lsp.Text_document.t) (forest : State.t) = | Error d -> forest.?{uri} <- [Error.parse_error d] end -let build_import_graph ~(forest : State.t) : Error.t list * _ = - let errors, graph = Imports.build forest in - (errors, graph) +let build_import_graph ~(forest : State.t) : Error.t list * Forest_graph.t = + Imports.build forest let expand (forest : State.t) = Expand.expand_tree ~forest @@ -139,12 +138,11 @@ let run_jobs (forest : State.t) jobs = export. *) let resources_to_plant = let@ Range.{value; range} = Eio.Fiber.List.map ~max_fibers:20 @~ jobs in - let range = Option.get range in match value with | Job.LaTeX_to_svg job -> let* svg = Build_latex.latex_to_svg ~env:forest.env ~range job.source in let uri = Job.uri_for_latex_to_svg_job ~base:forest.config.url job in - ok (T.Asset {uri; content = svg}) + ok (T.Asset {uri; content = svg; source = job.source}) | Job.Syndicate syndication -> ok (T.Syndication syndication) in begin @@ -176,13 +174,11 @@ let eval (forest : State.t) = let config = State.config forest in let (articles, jobs), errors = let expanded = State.get_all_expanded ~forest in - Logs.debug (fun m -> - m "eval: got %i expanded trees " List.(length expanded)); organize @@ let@ uri, tree = List.map @~ expanded in let source_path = - if State.dev forest then Option.bind forest.={uri} Tree.path else None + if State.dev forest then Option.map Tree.path forest.={uri} else None in Eval.(eval_tree ~config ~source_path ~uri tree) in @@ -201,7 +197,7 @@ let eval_only (uri : URI.t) (forest : State.t) = | Loaded | Parsed | Evaluated -> assert false | Expanded -> begin let source_path = - if State.dev forest then Option.bind forest.={uri} Tree.path else None + if State.dev forest then Option.map Tree.path forest.={uri} else None in let result, errors = Eval.eval_tree ~config ~source_path ~uri t in forest.?{uri} <- errors; @@ -230,11 +226,14 @@ let plant_assets ~(forest : State.t) = let@ path = Eio.Fiber.List.iter ~max_fibers:20 @~ List.of_seq paths in let content = EP.load path in let source_path = EP.native_exn path in - match Asset_router.install ~config:forest.config ~source_path ~content with + let range = Range.total ~source:(`File source_path) in + match + Asset_router.install ~config:forest.config ~source_path ~content ~range + with | Error _ -> failwith "handle asset router install failure" | Ok uri -> Logs.debug (fun m -> m "Installed %s at %a" source_path URI.pp uri); - State.plant_resource ~forest (T.Asset {uri; content}) + State.plant_resource ~forest (T.Asset {uri; content; source = source_path}) let implant ~(forest : State.t) (foreign : Config.foreign) = let* path = diff --git a/lib/compiler/State.ml b/lib/compiler/State.ml index ff30085..a205c42 100644 --- a/lib/compiler/State.ml +++ b/lib/compiler/State.ml @@ -1,4 +1,5 @@ -(* * SPDX-FileCopyrightText: 2024 The Forester Project Contributors +(* + * SPDX-FileCopyrightText: 2024 The Forester Project Contributors * * SPDX-License-Identifier: GPL-3.0-or-later *) @@ -27,15 +28,6 @@ type t = { suggestions: URI.t URI.Tbl.t; } -let summarize : t -> unit = function - | {index; diagnostics; import_graph; _} -> - Logs.debug @@ fun m -> - m "Trees in index: %i" (Forest.length index); - Logs.debug @@ fun m -> - m "Total diagnostics: %i" (Forest.length diagnostics); - Logs.debug @@ fun m -> - m "Graph vertices: %d" (Forest_graph.nb_vertex import_graph) - let dev forest = forest.dev let config forest = forest.config let env forest = forest.env @@ -81,7 +73,7 @@ module Syntax = struct | None -> URI.Tbl.replace state.index uri tree | Some existing -> if - (Option.compare compare) (Tree.source tree) (Tree.source existing) = 0 + compare (Tree.source tree) (Tree.source existing) = 0 && Tree.(equal_phases tree existing) then let () = state.?{uri} <- [Error.duplicate_tree ~uri] in @@ -114,7 +106,7 @@ let filter ~forest f = |> List.of_seq let get_all_uris ~forest = forest.index |> URI.Tbl.to_seq_keys |> List.of_seq -let get_all_paths = get_all Tree.path +let get_all_paths = get_all (Tree.path >>> Option.some) let get_all_unparsed = get_all Tree.document let get_all_code = get_all Tree.code let get_all_expanded = get_all Tree.syn @@ -263,12 +255,18 @@ let plant_resource : ~some:begin fun tree -> let expanded = Tree.syn tree in let source = Tree.source tree in - Tree.Evaluated.create ?source ~route_locally ~include_in_manifest + Tree.Evaluated.create ~source ~route_locally ~include_in_manifest ?expanded resource end ~none:begin - let source = (* TODO: *) None in - Tree.Evaluated.create ?source ~route_locally ~include_in_manifest + let source = + match resource with + | T.Article _ -> `File "" + | T.Asset {source; _} -> `File source + | T.Syndication (T.Json_blob _) -> `File "todo" + | T.Syndication (T.Atom_feed _) -> `File "todo" + in + Tree.Evaluated.create ~source ~route_locally ~include_in_manifest resource end in diff --git a/lib/compiler/Suggestions.ml b/lib/compiler/Suggestions.ml index 6f942aa..e717180 100644 --- a/lib/compiler/Suggestions.ml +++ b/lib/compiler/Suggestions.ml @@ -32,7 +32,7 @@ let create_suggestions ~visible path : Diagnostic.Message.t list = let path, data, _ = List.hd suggestions in let location_hint = match data with - | Syn.Term ({range = Some range; _} :: _) -> begin + | Syn.Term ({range; _} :: _) -> begin match Range.source range with | `File name | `Reader {name = Some name; _} -> [Diagnostic.Message.createf "defined in %s" name] diff --git a/lib/compiler/Tex_builtins.ml b/lib/compiler/Tex_builtins.ml index 4b7e9af..5850731 100644 --- a/lib/compiler/Tex_builtins.ml +++ b/lib/compiler/Tex_builtins.ml @@ -694,7 +694,7 @@ let words = |> Seq.map @@ fun word -> let path = [word] in let node = Syn.TeX_cs (TeX_cs.Word word) in - (path, (Syn.Term [Range.locate_opt None node], None)) + (path, (Syn.Term [Range.builtin node], None)) (* Feel free to extend this *) let symbols = @@ -702,7 +702,7 @@ let symbols = |> Seq.map @@ fun c -> let path = [String_util.implode [c]] in let node = Syn.TeX_cs (TeX_cs.Symbol c) in - (path, (Syn.Term [Range.locate_opt None node], None)) + (path, (Syn.Term [Range.builtin node], None)) let builtin_xml_namespaces = List.to_seq diff --git a/lib/compiler/test/Test_expansion.ml b/lib/compiler/test/Test_expansion.ml deleted file mode 100644 index 69fce86..0000000 --- a/lib/compiler/test/Test_expansion.ml +++ /dev/null @@ -1,125 +0,0 @@ -(* - * SPDX-FileCopyrightText: 2024 The Forester Project Contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - *) - -open Forester_core -open Forester_compiler -open Forester_test -open Forester_lsp -open Forester_frontend -open Testables - -open struct - module T = Types -end - -open struct - module S = Resolver.Scope - module P = Resolver.P - - let config = Config.default () - let _data = Alcotest.testable Syn.pp_resolver_data ( = ) -end - -open State.Syntax - -let expand ~forest src = - Result.map_error (Fun.const ()) - @@ - let@ code = Result.map @~ parse_string_no_loc src in - S.run ~init_visible:Expand.initial_visible_trie @@ fun () -> - let nodes = Expand.expand ~forest code in - ({tree = {nodes; code; units = Trie.empty}; phase = Expanded; source = None} - : Tree.(expanded tree)) - -let render ~forest expanded = - let result, _ = - Eval.eval_tree ~config:(Config.default ()) - ~uri:(URI.of_string_exn "http://localhost/test") - ~source_path:None expanded - in - match result with - | None -> error () - | Some {articles; _} -> - let () = - List.iter - (fun article -> - let@ uri = Option.iter @~ T.(article.frontmatter.uri) in - forest.={uri} <- - Tree - { - phase = Evaluated; - source = None; - tree = - { - resource = Article article; - expanded = None; - route_locally = true; - include_in_manifest = true; - }; - }) - articles - in - let rendered = - List.map - (fun article -> - Plain_text_client.string_of_content ~forest T.(article.mainmatter)) - articles - in - ok @@ String.concat "" rendered - -let test_subtree ~env () = - let forest = State.make ~env ~config ~dev:false () in - let expanded = - expand ~forest - {| - \subtree[foo]{ - \title{Hello} - \taxon{Example} - } - |} - in - let evaluated = Result.bind expanded (render ~forest) in - Alcotest.(check @@ result string unit) - "" (Ok {||}) evaluated - -let test_visible ~env () = - let forest = State.make ~env ~config ~dev:false () in - let code = - Result.get_ok - @@ parse_string {| -\def\greet[name]{Hello, \name!} -\p{\greet{Jon}} - |} - in - (*let tree : Tree.code = Tree. {nodes = code; identity = Anonymous; origin = Undefined; timestamp = None} in*) - (*Format.printf "%a@." Code.pp code;*) - (*let syn, _ = Expand.expand_tree ~forest tree in*) - (*Format.printf "%a@." Tree.pp_syn syn;*) - let result = - Trie.to_seq - @@ Analysis.get_visible ~forest ~position:{line = 2; character = 5} code - in - let greet = - let@ path, _ = - Option.map @~ Seq.find (fun (p, _) -> p = ["greet"]) result - in - path - in - Alcotest.(check (option path)) "greet is visible" (Some ["greet"]) greet - -let () = - Logs.set_level (Some Debug); - Logs.set_reporter (Logs.format_reporter ()); - let open Alcotest in - let@ env = Eio_main.run in - run "Test_expansion" - [ - ( "", - [ - test_case "subtree" `Quick (test_subtree ~env); - test_case "get_visible" `Quick (test_visible ~env); - ] ); - ] diff --git a/lib/compiler/test/dune b/lib/compiler/test/dune index 9c0e924..82c0638 100644 --- a/lib/compiler/test/dune +++ b/lib/compiler/test/dune @@ -4,7 +4,6 @@ (tests (names - Test_expansion Test_diagnostic_store Test_graph_database Test_import_graph diff --git a/lib/core/Code.ml b/lib/core/Code.ml index f2251bb..9f2109a 100644 --- a/lib/core/Code.ml +++ b/lib/core/Code.ml @@ -138,88 +138,3 @@ let children (node : node Range.located) = | Decl_xmlns (_, _) | Alloc _ | Dx_var _ | Comment _ | Error _ -> [] - -module DSL = struct - open Range - let import_private = import_private >>> unloc - let import_public = import_public >>> unloc - let inline_math = inline_math >>> unloc - let display_math = display_math >>> unloc - let parens = parens >>> unloc - let squares = squares >>> unloc - let braces = braces >>> unloc - let ident i = unloc @@ Ident i - let hash_ident str = unloc @@ Hash_ident str - let p content = [ident ["p"]; braces content] - let ul content = [ident ["ul"]; braces content] - let li content = [ident ["li"]; braces content] - let text str = unloc @@ Text str - let verbatim str = unloc @@ Verbatim str - let math mode nodes = unloc @@ Math (mode, nodes) - let ident path = unloc @@ Ident path - let scope nodes = unloc @@ Scope nodes - let open_ path = unloc @@ Open path - let group delim nodes = unloc @@ Group (delim, nodes) - let def p b t = unloc @@ Def (p, b, t) - let object_ t = unloc @@ Object t -end - -(* Not all nodes need to be documented, such as `Group` *) -let nodes = - [ - Text ""; - Verbatim ""; - Math (Inline, []); - Ident []; - Hash_ident ""; - Xml_ident (None, ""); - Subtree (None, []); - Let ([], [], []); - Open []; - Scope []; - Put ([], []); - Default ([], []); - Get []; - Fun ([], []); - Object {self = None; methods = []}; - Patch {obj = []; self = None; super = None; methods = []}; - Call ([], ""); - Import (Private, ""); - Import (Public, ""); - Def ([], [], []); - Decl_xmlns ("", ""); - Alloc []; - Namespace ([], []); - Comment ""; - ] - -let doc = - let open DSL in - List.map - (function - | Text _ -> p [text ""] - | Verbatim _ - | Group (_, _) - | Math (_, _) - | Ident _ | Hash_ident _ - | Xml_ident (_, _) - | Subtree (_, _) - | Let (_, _, _) - | Open _ | Scope _ - | Put (_, _) - | Default (_, _) - | Get _ - | Fun (_, _) - | Object _ | Patch _ - | Call (_, _) - | Import (_, _) - | Def (_, _, _) - | Decl_xmlns (_, _) - | Alloc _ - | Namespace (_, _) - | Dx_sequent (_, _) - | Dx_query (_, _, _) - | Dx_prop (_, _) - | Dx_var _ | Dx_const_content _ | Dx_const_uri _ | Comment _ | Error _ -> - []) - nodes diff --git a/lib/core/Code.mli b/lib/core/Code.mli index 244117b..962369d 100644 --- a/lib/core/Code.mli +++ b/lib/core/Code.mli @@ -71,28 +71,3 @@ val inline_math : t -> node val display_math : t -> node val map : (t -> t) -> node -> node val children : node Range.located -> t - -module DSL : sig - val import_private : string -> node Range.located - val import_public : string -> node Range.located - val inline_math : t -> node Range.located - val display_math : t -> node Range.located - val parens : t -> node Range.located - val squares : t -> node Range.located - val braces : t -> node Range.located - val hash_ident : string -> node Range.located - val p : t -> node Range.located list - val ul : t -> node Range.located list - val li : t -> node Range.located list - val text : string -> node Range.located - val verbatim : string -> node Range.located - val math : Base.math_mode -> t -> node Range.located - val ident : Trie.path -> node Range.located - val scope : t -> node Range.located - val open_ : Trie.path -> node Range.located - val group : Base.delim -> t -> node Range.located - - val def : Trie.path -> string Base.binding list -> t -> node Range.located - - val object_ : t _object -> node Range.located -end diff --git a/lib/core/Range.ml b/lib/core/Range.ml index c3972fb..aa98068 100644 --- a/lib/core/Range.ml +++ b/lib/core/Range.ml @@ -57,25 +57,29 @@ let t = end in T.repr -type 'a really_located = {value: 'a; range: t} -type 'a located = {value: 'a; range: t option} [@@deriving show] +type 'a located_opt = {value: 'a; range: t option} [@@deriving show] +let get_value {value; _} = value + +type 'a located = {value: 'a; range: t} [@@deriving repr, show] -let builtin = +let builtin_range = initial (`Reader {id = 0; length = 0; name = None; unsafe_get = (fun _ -> ' ')}) -let unloc a = {value = a; range = None} -let get_value {value; _} = value +let builtin value = {range = builtin_range; value} + +let unloc a : 'a located_opt = {value = a; range = None} (*let pp_located pp_arg fmt (x : 'a located) = pp_arg fmt x.value*) let map : type a b. (a -> b) -> a located -> b located = fun f node -> {node with value = f node.value} -let located_t a = Repr.map a unloc get_value -let locate_lex ?source (start, end_) a = - {range = Some (of_lex ?source (start, end_)); value = a} +let located_opt_t a = Repr.map a unloc get_value +let locate_lex ?source (start, end_) a : 'a located = + {range = of_lex ?source (start, end_); value = a} -let locate_opt range value = {range; value} +let locate_opt range value : _ located_opt = {range; value} +let locate range value : _ located = {range; value} let merge_opt r s = match (r, s) with diff --git a/lib/core/Tree.ml b/lib/core/Tree.ml index 11b6fdd..bba3637 100644 --- a/lib/core/Tree.ml +++ b/lib/core/Tree.ml @@ -32,28 +32,28 @@ type 'a tag = | Expanded : expanded tag | Evaluated : evaluated tag -type 'a tree = {phase: 'a tag; tree: 'a; source: source option} +type 'a tree = {phase: 'a tag; tree: 'a; source: source} module Loaded = struct type t = loaded tree - let create : ?source:source -> loaded -> t = - fun ?source tree -> {tree; phase = Loaded; source} + let create : source:source -> loaded -> t = + fun ~source tree -> {tree; phase = Loaded; source} let source {source; _} = source let uri {tree; _} = Lsp.Text_document.documentUri tree end module Parsed = struct type t = parsed tree - let create : ?source:source -> parsed -> t = - fun ?source tree -> {tree; phase = Parsed; source} + let create : source:source -> parsed -> t = + fun ~source tree -> {tree; phase = Parsed; source} let source {source; _} = source let nodes ({tree; _} : t) = tree end module Expanded = struct type t = expanded tree - let create : ?source:source -> expanded -> t = - fun ?source tree -> {tree; phase = Expanded; source} + let create : source:source -> expanded -> t = + fun ~source tree -> {tree; phase = Expanded; source} let source {source; _} = source let nodes {tree = {nodes; _}; _} = nodes end @@ -61,7 +61,7 @@ end module Evaluated = struct type t = evaluated tree let create ?(route_locally = true) ?(include_in_manifest = true) ?expanded - ?source (resource : _ T.resource) = + ~source (resource : _ T.resource) = let tree = let expanded = match expanded with Some expanded -> Some expanded.tree | None -> None @@ -77,14 +77,9 @@ type t = Tree : 'a tree -> t type phase = Phase : 'a tag -> phase -let source : t -> _ option = function - | Tree {source; _} -> begin - match source with Some s -> Some s | _ -> None - end +let source : t -> _ = function Tree {source; _} -> source -let path t = - let@ (`File p) = Option.map @~ source t in - p +let path = function Tree {source = `File path; _} -> path let phase : type a. a tree -> phase = function | {phase; _} -> begin @@ -104,14 +99,12 @@ let equal_phases = | Evaluated, Evaluated -> true | _ -> false -let lsp_uri : t -> Lsp.Uri.t option = function +let lsp_uri : t -> Lsp.Uri.t = function | Tree {tree; phase; source} -> begin match phase with - | Loaded -> Some (Lsp.Text_document.documentUri tree) + | Loaded -> Lsp.Text_document.documentUri tree | Parsed | Expanded | Evaluated -> begin - match source with - | None -> None - | Some (`File string) -> Some (Lsp.Uri.of_string string) + match source with `File string -> Lsp.Uri.of_string string end end @@ -121,14 +114,13 @@ let document : t -> loaded option = function end let of_code : path:string -> Code.t -> t = - fun ~path nodes -> - Tree {phase = Parsed; tree = nodes; source = Some (`File path)} + fun ~path nodes -> Tree {phase = Parsed; tree = nodes; source = `File path} let of_doc : Lsp.Text_document.t -> t = fun doc -> let uri = Lsp.Text_document.documentUri doc in let path = Lsp.Uri.to_path uri in - Tree {phase = Loaded; tree = doc; source = Some (`File path)} + Tree {phase = Loaded; tree = doc; source = `File path} let of_syn ~source syn = Tree {phase = Expanded; tree = syn; source} diff --git a/lib/core/Types.ml b/lib/core/Types.ml index 5e0cc80..77c6e08 100644 --- a/lib/core/Types.ml +++ b/lib/core/Types.ml @@ -90,7 +90,8 @@ type 'content article = { } [@@deriving show, repr] -type asset = {uri: URI.t; content: string} [@@deriving show, repr] +type asset = {uri: URI.t; content: string; source: string} +[@@deriving show, repr] type 'a json_blob_syndication = { blob_uri: URI.t; @@ -213,19 +214,9 @@ let trim_whitespace xs = and trim_back xs = List.rev @@ trim_front @@ List.rev xs in trim_back @@ trim_front xs -let default_frontmatter - ?uri - ?source_path - ?designated_parent - ?(dates = []) - ?(attributions = []) - ?taxon - ?number - ?(metas = []) - ?(tags = []) - ?title - ?last_changed - () = +let default_frontmatter ?uri ?source_path ?designated_parent ?(dates = []) + ?(attributions = []) ?taxon ?number ?(metas = []) ?(tags = []) ?title + ?last_changed () = { uri; source_path; @@ -240,9 +231,7 @@ let default_frontmatter last_changed; } -let article_to_section - ?(flags = default_section_flags) - ?range +let article_to_section ?(flags = default_section_flags) ?range (article : 'a article) = let mainmatter = match article.frontmatter.uri with diff --git a/lib/frontend/test/Test_transclusion.ml b/lib/frontend/test/Test_transclusion.ml deleted file mode 100644 index dda3d01..0000000 --- a/lib/frontend/test/Test_transclusion.ml +++ /dev/null @@ -1,80 +0,0 @@ -(* - * SPDX-FileCopyrightText: 2024 The Forester Project Contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - *) - -(* TODO: should just use cram tests for this instead. *) - -open Forester_core -open Forester_compiler -open Forester_frontend - -open struct - module T = Types - module HTML = Pure_html.HTML -end - -let config = {(Config.default ()) with trees = ["transclude"]} -let href = URI.named_uri ~base:config.url "transcludee" - -module Transclusions = struct - (* It would be cool to use quickcheck here, but no good way to test the result*) - open T - - let full_default = {href; target = Full default_section_flags; range = None} - let metadata_shown = {default_section_flags with metadata_shown = Some true} -end - -let () = - let@ env = Eio_main.run in - Logs.set_level (Some Debug); - let uri = URI.named_uri ~base:config.url "transcludee" in - let index = URI.Tbl.create 10 in - URI.Tbl.add index uri - @@ Tree.Tree - { - phase = Evaluated; - source = None; - tree = - { - resource = - T.Article - { - frontmatter = - T.default_frontmatter - ~uri:(URI.of_string_exn "forest://test/transcludee") - ~title:(T.Content [Text "I am being transcluded"]) (); - mainmatter = Content [Text "Hello"]; - backmatter = Content []; - }; - expanded = None; - route_locally = true; - include_in_manifest = true; - }; - }; - let forest = {(State.make ~env ~config ~dev:false ()) with index} in - let print_transclusion : T.transclusion -> unit = - fun t -> - let content = Option.get @@ State.get_content_of_transclusion ~forest t in - Format.printf "%a" - (Legacy_xml_client.pp_xml ~forest ?stylesheet:None) - T. - { - frontmatter = default_frontmatter ~uri:href (); - mainmatter = content; - backmatter = Content []; - } - in - let test_full_default () = print_transclusion Transclusions.full_default in - let test_title_default () = - print_transclusion - {href = uri; target = Title {empty_when_untitled = false}; range = None} - in - let test_full_metadata () = - print_transclusion - {href = uri; target = Full Transclusions.metadata_shown; range = None} - in - List.iter - (fun f -> f ()) - [test_full_default; test_title_default; test_full_metadata] diff --git a/lib/frontend/test/dune b/lib/frontend/test/dune index cd312a5..c5ea70c 100644 --- a/lib/frontend/test/dune +++ b/lib/frontend/test/dune @@ -26,18 +26,6 @@ forester.frontend forester.test)) -(executable - (name Test_transclusion) - (public_name transclude) - (libraries - forester.core - forester.prelude - forester.compiler - forester.frontend - pure-html - eio_main - logs)) - (executable (name Test_config_parser) (public_name parse_forester_config) diff --git a/lib/language_server/Analysis.ml b/lib/language_server/Analysis.ml index 91bf030..03c7a41 100644 --- a/lib/language_server/Analysis.ml +++ b/lib/language_server/Analysis.ml @@ -78,10 +78,7 @@ let analyse_syntax nodes = let@ () = S.run in List.iter analyse nodes -let contains ~(position : L.Position.t) (loc : Range.t option) = - Option.value ~default:false - @@ - let@ loc = Option.map @~ loc in +let contains ~(position : L.Position.t) (loc : Range.t) = let offset = Grace.Byte_index.of_int position.character in let index = Grace.Byte_index.(add (of_int position.line) (diff offset initial)) @@ -98,10 +95,11 @@ let rec node_at : type a. List.find_opt (fun Range.{range; _} -> contains ~position range) code with | None -> None - | Some n -> ( + | Some n -> begin match (node_at ~position ~children) (children n) with | Some inner -> Some inner - | None -> Some n) + | None -> Some n + end let get_enclosing_code_group ~position tree = let rec go ~position nodes = @@ -111,11 +109,11 @@ let get_enclosing_code_group ~position tree = | None -> None | Some ({value; range} as node) -> ( match value with - | Code.Group (delim, t) -> - begin match go ~position t with + | Code.Group (delim, t) -> begin + match go ~position t with | None -> Some Range.{value = (delim, t); range} | Some t -> Some t - end + end | _ -> (go ~position) (Code.children node)) in match Tree.code tree with @@ -130,11 +128,11 @@ let get_enclosing_syn_group ~position tree = | None -> None | Some ({value; range} as node) -> ( match value with - | Syn.Group (delim, children) -> - begin match go ~position children with + | Syn.Group (delim, children) -> begin + match go ~position children with | None -> Some Range.{value = (delim, children); range} | Some t -> Some t - end + end | _ -> go ~position (Syn.children node)) in match Tree.syn tree with @@ -146,8 +144,8 @@ let enclosing_group_start ~position position:L.Position.t -> Tree.t -> (delim * 'a) Range.located option) (tree : Tree.t) = match enclosing_group ~position tree with - | None -> Some position - | Some {range; value = _} -> Option.map Lsp_shims.lsp_pos_of_range range + | None -> position + | Some {range; value = _} -> Lsp_shims.lsp_pos_of_range range let find_with_prev ~position = let rec go prev = function @@ -172,13 +170,13 @@ let parent_or_prev_at : type a. let go ~position ~children nodes = match find_with_prev ~position nodes with | None -> None - | Some (None, node) -> - begin match (node_at ~position ~children) (children node) with + | Some (None, node) -> begin + match (node_at ~position ~children) (children node) with | Some inner -> (* go ~position ~children (children inner) *) Some (Context.Top inner) | None -> Some (Top node) - end + end | Some (Some prev, node) -> ( match (node_at ~position ~children) (children node) with | None -> Some (Prev (prev, node)) diff --git a/lib/language_server/Completion.ml b/lib/language_server/Completion.ml index 1a4be78..f5167e5 100644 --- a/lib/language_server/Completion.ml +++ b/lib/language_server/Completion.ml @@ -133,16 +133,16 @@ let completion_types (t : Tree.t) ~position = m "Text_context: %a" Format.(pp_print_option pp_print_string) text_context); let code_context = let enclosing_group = Analysis.get_enclosing_code_group in - let@ position = - Option.bind @@ Analysis.enclosing_group_start ~enclosing_group ~position t + let position = + Analysis.enclosing_group_start ~enclosing_group ~position t in let@ code = Option.bind code_opt in Analysis.parent_or_prev_at_code ~position @@ Tree.Parsed.nodes code in let syn_context = let enclosing_group = Analysis.get_enclosing_syn_group in - let@ position = - Option.bind @@ Analysis.enclosing_group_start ~enclosing_group ~position t + let position = + Analysis.enclosing_group_start ~enclosing_group ~position t in let@ syn = Option.bind syn_opt in Analysis.parent_or_prev_at_syn ~position syn.tree.nodes diff --git a/lib/language_server/Definitions.ml b/lib/language_server/Definitions.ml index f1e4e6b..f49a48f 100644 --- a/lib/language_server/Definitions.ml +++ b/lib/language_server/Definitions.ml @@ -24,7 +24,7 @@ let compute (params : L.DefinitionParams.t) = Option.bind @@ Analysis.addr_at ~position:params.position nodes in let uri = URI.named_uri ~base str in - let@ lsp_uri = Option.map @~ Option.bind forest.={uri} Tree.lsp_uri in + let@ lsp_uri = Option.map @~ Option.map Tree.lsp_uri forest.={uri} in let range = L.Range.create ~start:{character = 1; line = 0} ~end_:{character = 1; line = 0} diff --git a/lib/language_server/Did_change.ml b/lib/language_server/Did_change.ml index d530762..bca87e7 100644 --- a/lib/language_server/Did_change.ml +++ b/lib/language_server/Did_change.ml @@ -23,7 +23,9 @@ let compute (params : L.DidChangeTextDocumentParams.t) = | None -> assert false | Some doc -> let updated = - Tree.Loaded.create + let path = Lsp.Uri.to_path lsp_uri in + let source = `File path in + Tree.Loaded.create ~source @@ Lsp.Text_document.apply_content_changes doc params.contentChanges in forest.={uri} <- Tree updated; diff --git a/lib/language_server/Did_open.ml b/lib/language_server/Did_open.ml index 56d7fbc..93f27d9 100644 --- a/lib/language_server/Did_open.ml +++ b/lib/language_server/Did_open.ml @@ -19,8 +19,7 @@ let compute (params : L.DidOpenTextDocumentParams.t) = let Lsp_state.{forest; _} = Lsp_state.get () in let document = Lsp.Text_document.make ~position_encoding:`UTF16 params in let uri = URI.of_lsp_uri ~base:forest.config.url lsp_uri in - forest.={uri} <- - Tree {tree = document; source = Some (`File path); phase = Loaded}; + forest.={uri} <- Tree {tree = document; source = `File path; phase = Loaded}; Lsp_state.modify (fun ({forest; _} as lsp_state) -> let new_forest = Driver.run_until_done (Action.Parse lsp_uri) forest in {lsp_state with forest = new_forest}); diff --git a/lib/language_server/Document_link.ml b/lib/language_server/Document_link.ml index d1313ee..95ef5db 100644 --- a/lib/language_server/Document_link.ml +++ b/lib/language_server/Document_link.ml @@ -34,10 +34,9 @@ let compute (params : L.DocumentLinkParams.t) = | Code.Group (Parens, [{value = Text addr; _}]) | Code.Group (Braces, [{value = Text addr; _}]) -> (* TODO: Need to analyse syn *) - let* range = range in let range = Lsp_shims.lsp_range_of_range range in let target_uri = URI.named_uri ~base:config.url addr in - let* target = Option.bind forest.={target_uri} Tree.lsp_uri in + let* target = Option.map Tree.lsp_uri forest.={target_uri} in let* {frontmatter; _} = State.get_article ~forest uri in let* tooltip = Option.map (fun c -> render c) frontmatter.title in let link = L.DocumentLink.create ~range ~target ~tooltip () in diff --git a/lib/language_server/Document_symbols.ml b/lib/language_server/Document_symbols.ml index 769f262..d6dd489 100644 --- a/lib/language_server/Document_symbols.ml +++ b/lib/language_server/Document_symbols.ml @@ -25,7 +25,7 @@ let compute ({textDocument = {uri; _}; _} : L.DocumentSymbolParams.t) : let symbols : L.DocumentSymbol.t list = let@ {range; value} = List.filter_map @~ tree in let open Code in - let* range = Option.map Lsp_shims.lsp_range_of_range range in + let range = Lsp_shims.lsp_range_of_range range in let selectionRange = range in match value with | Subtree (addr, _) -> diff --git a/lib/language_server/Highlight.ml b/lib/language_server/Highlight.ml index 8c86f3a..4765b35 100644 --- a/lib/language_server/Highlight.ml +++ b/lib/language_server/Highlight.ml @@ -18,7 +18,6 @@ let compute (params : L.DocumentHighlightParams.t) = let uri = URI.of_lsp_uri ~base:forest.config.url params.textDocument.uri in let@ tree = Option.map @~ State.get_code ~forest uri in let@ Range.{range; value} = List.filter_map @~ Tree.Parsed.nodes tree in - let@ range = Option.map @~ range in let range = Lsp_shims.lsp_range_of_range range in let kind = match value with @@ -48,4 +47,4 @@ let compute (params : L.DocumentHighlightParams.t) = | Code.Comment _ | Code.Error _ -> None in - L.DocumentHighlight.create ~range ?kind () + Some (L.DocumentHighlight.create ~range ?kind ()) diff --git a/lib/language_server/Inlay_hint.ml b/lib/language_server/Inlay_hint.ml index 269937a..8edac5e 100644 --- a/lib/language_server/Inlay_hint.ml +++ b/lib/language_server/Inlay_hint.ml @@ -24,14 +24,14 @@ let consume_addr_for_inlay ~(config : Config.t) ~(forest : State.t) | _ -> (None, Syn.children node) let inlay_hint_for_addr ~(config : Config.t) ~(forest : State.t) - ~(pos : Range.t) (addr : string) : L.InlayHint.t option = + ~(range : Range.t) (addr : string) : L.InlayHint.t option = let uri = URI.named_uri ~base:config.url addr in let@ {frontmatter; _} = Option.bind @@ State.get_article ~forest uri in let@ title = Option.bind frontmatter.title in let content = " " ^ Plain_text_client.string_of_content ~forest title in Option.some @@ L.InlayHint.create - ~position:(Lsp_shims.lsp_pos_of_range pos) + ~position:(Lsp_shims.lsp_pos_of_range range) ~label:(`String content) () let rec extract_inlayable_hints ~(config : Config.t) ~(forest : State.t) @@ -40,8 +40,7 @@ let rec extract_inlayable_hints ~(config : Config.t) ~(forest : State.t) let addr_opt, rest = consume_addr_for_inlay ~config ~forest node in let hint_opt = let@ addr = Option.bind addr_opt in - let@ pos = Option.bind @@ node.range in - inlay_hint_for_addr ~config ~forest ~pos addr + inlay_hint_for_addr ~config ~forest ~range:node.range addr in let hints = extract_inlayable_hints ~config ~forest rest in list_of_option hint_opt @ hints diff --git a/lib/language_server/Semantic_tokens.ml b/lib/language_server/Semantic_tokens.ml index ed8d446..4ddf028 100644 --- a/lib/language_server/Semantic_tokens.ml +++ b/lib/language_server/Semantic_tokens.ml @@ -167,48 +167,45 @@ let builtin ~(start : L.Position.t) str tks = let tokens (nodes : Code.t) : token list = let@ Range.{range; value} = List.concat_map @~ nodes in - let range = Option.map Lsp_shims.lsp_range_of_range range in - match range with - | None -> [] - | Some L.Range.{start; end_} -> ( - if - (* Multiline tokens not supported*) - start.line <> end_.line - then [] - else - match value with - | Code.Ident path -> tokenize_path ~start path - | Code.Text _ -> [] - | Code.Put (_path, _t) -> [] - (* -> *) - (* builtin *) - (* ~start *) - (* "put" @@ *) - (* tokenize_path ~start path @ tokens t *) - | Code.Math (_, _) - | Code.Verbatim _ - | Code.Import (_, _) - | Code.Let (_, _, _) - | Code.Def (_, _, _) - | Code.Group (_, _) - | Code.Hash_ident _ - | Code.Xml_ident (_, _) - | Code.Subtree (_, _) - | Code.Open _ | Code.Scope _ - | Code.Default (_, _) - | Code.Get _ - | Code.Fun (_, _) - | Code.Object _ | Code.Patch _ - | Code.Call (_, _) - | Code.Decl_xmlns (_, _) - | Code.Alloc _ - | Code.Dx_sequent (_, _) - | Code.Dx_query (_, _, _) - | Code.Dx_prop (_, _) - | Code.Dx_var _ | Code.Dx_const_content _ | Code.Dx_const_uri _ - | Code.Error _ | Code.Comment _ - | Code.Namespace (_, _) -> - []) + let L.Range.{start; end_} = Lsp_shims.lsp_range_of_range range in + if + (* Multiline tokens not supported*) + start.line <> end_.line + then [] + else + match value with + | Code.Ident path -> tokenize_path ~start path + | Code.Text _ -> [] + | Code.Put (_path, _t) -> [] + (* -> *) + (* builtin *) + (* ~start *) + (* "put" @@ *) + (* tokenize_path ~start path @ tokens t *) + | Code.Math (_, _) + | Code.Verbatim _ + | Code.Import (_, _) + | Code.Let (_, _, _) + | Code.Def (_, _, _) + | Code.Group (_, _) + | Code.Hash_ident _ + | Code.Xml_ident (_, _) + | Code.Subtree (_, _) + | Code.Open _ | Code.Scope _ + | Code.Default (_, _) + | Code.Get _ + | Code.Fun (_, _) + | Code.Object _ | Code.Patch _ + | Code.Call (_, _) + | Code.Decl_xmlns (_, _) + | Code.Alloc _ + | Code.Dx_sequent (_, _) + | Code.Dx_query (_, _, _) + | Code.Dx_prop (_, _) + | Code.Dx_var _ | Code.Dx_const_content _ | Code.Dx_const_uri _ + | Code.Error _ | Code.Comment _ + | Code.Namespace (_, _) -> + [] let process_line_delta (index_of_last_line : int option) (tokens : token list) : int * delta_token list = diff --git a/lib/language_server/Workspace_symbols.ml b/lib/language_server/Workspace_symbols.ml index f6ae1e3..4458ab7 100644 --- a/lib/language_server/Workspace_symbols.ml +++ b/lib/language_server/Workspace_symbols.ml @@ -111,7 +111,7 @@ let compute (params : L.WorkspaceSymbolParams.t) : _ = let@ file_symbol = List.concat_map @~ Option.to_list @@ - let@ source_path = Option.map @~ Option.bind forest.={uri} Tree.path in + let@ source_path = Option.map @~ Option.map Tree.path forest.={uri} in let lsp_uri = Lsp.Uri.of_string source_path in let location = L.Location. diff --git a/lib/parser/test/Test_parser.ml b/lib/parser/test/Test_parser.ml deleted file mode 100644 index 6d3bc72..0000000 --- a/lib/parser/test/Test_parser.ml +++ /dev/null @@ -1,109 +0,0 @@ -(* - * SPDX-FileCopyrightText: 2024 The Forester Project Contributors - * - * SPDX-License-Identifier: GPL-3.0-or-later - *) - -open Forester_test -open Forester_core -open Testables -open Code.DSL - -let test_prim () = - Alcotest.(check @@ result code unit) - "same nodes" - (Ok - [ - ident ["p"]; - braces [ident ["ul"]; braces [ident ["li"]; braces [text "foo"]]]; - ]) - (parse_string_no_loc {|\p{\ul{\li{foo}}}|}) - -let test_open () = - Alcotest.(check @@ result code unit) - "same nodes" - (Ok [open_ ["foo"]]) - (parse_string_no_loc {|\open\foo|}); - Alcotest.(check @@ result code unit) - "same nodes" - (Ok [open_ ["foo"; "bar"; "baz"]]) - (parse_string_no_loc {|\open\foo/bar/baz|}) - -let test_scope () = - Alcotest.(check @@ result code unit) - "same nodes" - (Ok [scope [ident ["p"]; braces []]]) - (parse_string_no_loc {|\scope{\p{}}|}) - -let test_verbatim () = - Alcotest.(check @@ result code unit) - "same nodes" - (Ok [verbatim "asdf"]) - (parse_string_no_loc {|\verb<<|asdf<<|}) - -let test_math () = - Alcotest.(check @@ result code unit) - "same nodes" - (Ok - [ - math Inline - [ - text "a^2"; - text " "; - text "+"; - text " "; - text "b^2"; - text " "; - text "="; - text " "; - text "c^2"; - ]; - ]) - (parse_string_no_loc {|#{a^2 + b^2 = c^2}|}); - Alcotest.(check @@ result code unit) - "same nodes" - (Ok - [ - math Display - [ - text "a^2"; - text " "; - text "+"; - text " "; - text "b^2"; - text " "; - text "="; - text " "; - text "c^2"; - ]; - ]) - (parse_string_no_loc {|##{a^2 + b^2 = c^2}|}) - -let test_hashtag () = - Alcotest.(check @@ result code unit) - "same nodes" - (Ok [hash_ident "abc"]) - (parse_string_no_loc {|#abc|}) - -let test_object () = - Alcotest.(check @@ result code unit) - "same nodes" - (Ok [object_ {self = Some "self"; methods = [("foo", [])]}]) - (parse_string_no_loc - {| - \object[self]{ - [foo]{} - }|}) - -let () = - let open Alcotest in - run "Parser" - [ - ("nodes", [test_case "open" `Quick test_open]); - ("scope", [test_case "scope" `Quick test_scope]); - ("text", [test_case "text" `Quick test_prim]); - ("verbatim", [test_case "verbatim" `Quick test_verbatim]); - ("math", [test_case "math" `Quick test_math]); - ("hashtag", [test_case "hashtag" `Quick test_hashtag]); - ("object", [test_case "object" `Quick test_object]); - ] diff --git a/lib/parser/test/dune b/lib/parser/test/dune deleted file mode 100644 index c7ae7f8..0000000 --- a/lib/parser/test/dune +++ /dev/null @@ -1,14 +0,0 @@ -;;; SPDX-FileCopyrightText: 2024 The Forester Project Contributors -;;; -;;; SPDX-License-Identifier: GPL-3.0-or-later - -(test - (name Test_parser) - (libraries - alcotest - forester.test - forester.prelude - forester.compiler - forester.core - forester.parser - forester.frontend)) diff --git a/test/Prelude.ml b/test/Prelude.ml index b21fffa..2e7511c 100644 --- a/test/Prelude.ml +++ b/test/Prelude.ml @@ -11,24 +11,12 @@ open Forester_compiler open struct module L = Lsp.Types end - -let rec strip_syn (syn : Syn.t) : Syn.t = - let@ {value; _} = List.map @~ syn in - Range.{value = Syn.map strip_syn value; range = None} - -let rec strip_code (code : Code.t) : Code.t = - let@ Range.{value; _} = List.map @~ code in - Range.{value = Code.map strip_code value; range = None} - type raw_tree = {path: string; content: string} let parse_string str = let lexbuf = Lexing.from_string str in Parse.parse (`String {content = str; name = None}) lexbuf -let parse_string_no_loc str = - Result.map_error (Fun.const ()) @@ Result.map strip_code @@ parse_string str - let with_open_tmp_dir ~env kont = let open Eio in let cwd = Eio.Stdenv.cwd env in