ocaml
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Warn when encountering unresolved identifier

Previously we would always fall back to interpreting as a TeX control
sequence. Now we only do this when in math mode. I have added a bunch of
built-in things that automatically resolve to TeX control sequences no
matter the mode, because currently there is no way to control what mode
macro arguments are evaluated in (except making them lazy, which is
probably going to annoy users of forester if we impose it). So this is a
best effort thing.

+246 -237
+28 -6
lib/compiler/Eval.ml
··· 79 79 module Emitted_trees = Algaeff.State.Make(struct type t = T.content T.article list end) 80 80 module Jobs = Algaeff.State.Make(struct type t = Job.job Range.located list end) 81 81 module Frontmatter = Algaeff.State.Make(struct type t = T.content T.frontmatter end) 82 + module Mode_env = Algaeff.Reader.Make(struct type t = eval_mode end) 82 83 83 84 let get_current_uri ~loc = 84 85 match (Frontmatter.get ()).uri with ··· 224 225 emit_content_node ~loc @@ Link {href; content} 225 226 | Math (mode, body) -> 226 227 let content = 228 + let@ () = Mode_env.run ~env: TeX_mode in 227 229 {node with value = eval_tape body} |> extract_content 228 230 in 229 231 emit_content_node ~loc @@ KaTeX (mode, content) ··· 238 240 emit_content_node ~loc @@ T.Xml_elt {name; attrs = process attrs; content} 239 241 | TeX_cs cs -> 240 242 emit_content_node ~loc @@ T.Text (Format.asprintf "%a" pp_tex_cs cs) 243 + | Unresolved_ident (visible, path) -> 244 + let tex_cs_opt = 245 + match path with 246 + | [name] -> TeX_cs.parse name 247 + | _ -> None 248 + in 249 + begin 250 + match Mode_env.read (), tex_cs_opt with 251 + | TeX_mode, Some (cs, rest) -> 252 + emit_content_node ~loc @@ T.Text (Format.asprintf "%a%s" pp_tex_cs cs rest) 253 + | _, _ -> 254 + let extra_remarks = Suggestions.create_suggestions ~visible path in 255 + Reporter.emit ?loc ~extra_remarks (Unresolved_identifier (visible, path)); 256 + emit_content_node ~loc @@ T.Text (Format.asprintf "\\%a" Resolver.Scope.pp_path path) 257 + end 241 258 | Transclude -> 242 259 let flags = get_transclusion_flags ~loc in 243 260 let href_arg = eval_pop_arg ~loc in ··· 300 317 process_tape () 301 318 | Embed_tex -> 302 319 let config = Config_env.read () in 303 - let preamble = pop_content_arg ~loc |> TeX_like.string_of_content in 304 - let body = pop_content_arg ~loc |> TeX_like.string_of_content in 320 + let preamble, body = 321 + let@ () = Mode_env.run ~env: TeX_mode in 322 + let preamble = pop_content_arg ~loc |> TeX_like.string_of_content in 323 + let body = pop_content_arg ~loc |> TeX_like.string_of_content in 324 + preamble, body 325 + in 305 326 let source = LaTeX_template.to_string ~preamble ~body in 306 327 let hash = Digest.to_hex @@ Digest.string source in 307 328 let job = Job.{hash; source} in ··· 416 437 | None -> 417 438 Reporter.fatal 418 439 ?loc: node.loc 419 - (Resolution_error (k, env)) 440 + (Unbound_fluid_symbol (k, env)) 420 441 | Some v -> focus ?loc: node.loc v 421 442 end 422 443 | Verbatim str -> ··· 544 565 | None -> 545 566 Reporter.fatal 546 567 ?loc 547 - (Resolution_error (x, env)) 568 + (Unbound_lexical_symbol (x, env)) 548 569 549 570 and focus ?loc = function 550 571 | Clo (rho, xs, body) -> ··· 572 593 focus ?loc @@ 573 594 let@ () = Lex_env.run ~env: rho in 574 595 eval_tape body 575 - | (strategy, y) :: ys -> 596 + | (info, y) :: ys -> 576 597 match Tape.pop_arg_opt () with 577 598 | Some arg -> 578 599 let yval = 579 - match strategy with 600 + match info with 580 601 | Strict -> eval_tape arg.value 581 602 | Lazy -> Clo (Lex_env.read (), [(Strict, Symbol.fresh ())], arg.value) 582 603 in ··· 637 658 ~emit: push 638 659 @@ fun () -> 639 660 let fm = T.default_frontmatter ~uri ?source_path () in 661 + let@ () = Mode_env.run ~env: Text_mode in 640 662 let@ () = Frontmatter.run ~init: fm in 641 663 let@ () = Emitted_trees.run ~init: [] in 642 664 let@ () = Jobs.run ~init: [] in
+71 -146
lib/compiler/Expand.ml
··· 15 15 module Sc = R.Scope 16 16 end 17 17 18 - (* TODO: remove this in favor of https://github.com/ocaml/ocaml/pull/13760 *) 19 - let edit_distance ~cutoff x y = 20 - let len_x, len_y = String.length x, String.length y in 21 - let grid = Array.make_matrix (len_x + 1) (len_y + 1) 0 in 22 - for i = 1 to len_x do 23 - grid.(i).(0) <- i; 24 - done; 25 - for j = 1 to len_y do 26 - grid.(0).(j) <- j; 27 - done; 28 - for j = 1 to len_y do 29 - for i = 1 to len_x do 30 - let cost = if x.[i - 1] = y.[j - 1] then 0 else 1 in 31 - let k = Int.min (grid.(i - 1).(j) + 1) (grid.(i).(j - 1) + 1) in 32 - grid.(i).(j) <- Int.min k (grid.(i - 1).(j - 1) + cost) 33 - done; 34 - done; 35 - let result = grid.(len_x).(len_y) in 36 - if result > cutoff then None 37 - else 38 - Some result 39 - 40 - let suggestions 41 - ?prefix 42 - ~(cutoff : int) 43 - (p : Trie.bwd_path) 44 - : ('data, 'tag) Trie.t -> ('data, int) Trie.t 45 - = 46 - let compare p d = 47 - edit_distance ~cutoff (String.concat "" (Bwd.to_list p)) (String.concat "" (Bwd.to_list d)) 48 - in 49 - Trie.filter_map 50 - ?prefix 51 - (fun q (data, _) -> 52 - match compare p q with 53 - | Some i -> 54 - if i > cutoff then 55 - None 56 - else 57 - (Some (data, i)) 58 - | None -> None 59 - ) 60 - 61 - let suggestions path visible = 62 - suggestions ~cutoff: 2 (Bwd.of_list path) visible 63 - |> Trie.to_seq 64 - |> Seq.map (fun (path, (data, distance)) -> (path, data, distance)) 65 - |> List.of_seq 66 - |> List.sort (fun (_, _, a) (_, _, b) -> Int.compare a b) 67 - 68 - let create_suggestions path = 69 - let visible = Sc.get_visible () in 70 - let suggestions = suggestions path visible in 71 - let extra_remarks = 72 - if List.length suggestions > 0 then 73 - let (path, data, _) = List.hd suggestions in 74 - let location_hint = 75 - match data with 76 - | R.P.Term ({loc = Some loc; _} :: _) -> 77 - begin 78 - match Range.view loc with 79 - | `End_of_file {source; _} 80 - | `Range ({source; _}, _) -> 81 - match Range.title source with 82 - | Some string -> 83 - [Asai.Diagnostic.loctextf "defined in %s" string] 84 - | _ -> [] 85 - end 86 - | _ -> [] 87 - in 88 - [Asai.Diagnostic.loctextf "Did you mean %a?" Sc.pp_path path] @ location_hint 89 - else [] 90 - in 91 - extra_remarks 92 - 93 18 module Builtins = struct 94 19 95 20 let create_sym path = ··· 103 28 Sc.include_subtree [] @@ 104 29 Yuujinchou.Trie.of_seq @@ 105 30 let@ path, node = Seq.map @~ List.to_seq builtins in 106 - path, (R.P.Term [Range.locate_opt None node], None) 31 + path, (Syn.Term [Range.locate_opt None node], None) 107 32 108 33 module Transclude = struct 109 34 let expanded_sym, alloc_expanded = create_sym ["transclude"; "expanded"] ··· 253 178 let var = Range.{value = Syn.Var sym; loc = node.loc} in (* TODO: correct the location *) 254 179 begin 255 180 let@ self = Option.iter @~ self in 256 - Sc.import_singleton self @@ (R.P.Term [var], node.loc) (* TODO: correct the location*) 181 + Sc.import_singleton self @@ (Term [var], node.loc) (* TODO: correct the location*) 257 182 end; 258 183 sym, List.map (expand_method ~forest) methods 259 184 in ··· 313 238 | rest -> None, rest 314 239 315 240 and expand_ident loc path = 316 - match Sc.resolve path, path with 317 - | None, [name] -> 318 - begin 319 - match TeX_cs.parse name with 320 - | None -> 321 - let extra_remarks = create_suggestions path in 322 - let visible = Sc.get_visible () in 323 - Reporter.fatal 324 - ?loc 325 - ~extra_remarks 326 - (Expansion_error (`Resolution_error (visible, path))) 327 - | Some (cs, rest) -> 328 - let rest = match rest with "" -> [] | _ -> [Range.{value = Syn.Text rest; loc}] in 329 - Range.{value = Syn.TeX_cs cs; loc} :: rest 330 - end 331 - | None, _ -> 332 - let extra_remarks = create_suggestions path in 241 + match Sc.resolve path with 242 + | None -> 333 243 let visible = Sc.get_visible () in 334 - Reporter.fatal ?loc ~extra_remarks (Expansion_error (`Resolution_error (visible, path))) 335 - | Some (Term x, _), _ -> 244 + [Range.{value = Syn.Unresolved_ident (visible, path); loc}] 245 + | Some (Term x, _) -> 336 246 let relocate Range.{value; _} = Range.{value; loc} in 337 247 List.map relocate x 338 - | Some (Xmlns {xmlns; prefix}, _), _ -> 248 + | Some (Xmlns {xmlns; prefix}, _) -> 339 249 let visible = Sc.get_visible () in 340 250 Reporter.fatal 341 251 ?loc ··· 347 257 xmlns 348 258 prefix 349 259 ] 350 - (Expansion_error (`Resolution_error (visible, path))) 260 + (Unresolved_identifier (visible, path)) (* TODO: This should be perhaps a different error *) 351 261 352 262 and expand_xml_ident loc (prefix, uname) : Types.xml_qname = 353 263 match prefix with ··· 359 269 | _ -> 360 270 Reporter.fatal 361 271 ?loc 362 - (Expansion_error `Xmlns_error) 272 + (Unresolved_xmlns prefix) 363 273 ~extra_remarks: [ 364 274 Asai.Diagnostic.loctextf 365 275 "expected path `%s` to resolve to xmlns" ··· 398 308 let expand ~forest (xs : Code.t) : Syn.t = 399 309 ignore_entered_range (expand_eff ~forest) xs 400 310 401 - let builtins = [ 402 - ["p"], Syn.Prim `P; 403 - ["em"], Syn.Prim `Em; 404 - ["strong"], Syn.Prim `Strong; 405 - ["li"], Syn.Prim `Li; 406 - ["ol"], Syn.Prim `Ol; 407 - ["ul"], Syn.Prim `Ul; 408 - ["code"], Syn.Prim `Code; 409 - ["blockquote"], Syn.Prim `Blockquote; 410 - ["pre"], Syn.Prim `Pre; 411 - ["figure"], Syn.Prim `Figure; 412 - ["figcaption"], Syn.Prim `Figcaption; 413 - ["transclude"], Syn.Transclude; 414 - ["tex"], Syn.Embed_tex; 415 - ["ref"], Syn.Ref; 416 - ["title"], Syn.Title; 417 - ["taxon"], Syn.Taxon; 418 - ["date"], Syn.Date; 419 - ["meta"], Syn.Meta; 420 - ["author"], Syn.Attribution (Author, `Uri); 421 - ["author"; "literal"], Syn.Attribution (Author, `Content); 422 - ["contributor"], Syn.Attribution (Contributor, `Uri); 423 - ["contributor"; "literal"], Syn.Attribution (Contributor, `Content); 424 - ["parent"], Syn.Parent; 425 - ["number"], Syn.Number; 426 - ["tag"], Syn.Tag `Content; 427 - ["query"], Syn.Results_of_query; 428 - ["rel"; "has-tag"], Syn.Text Builtin_relation.has_tag; 429 - ["rel"; "has-taxon"], Syn.Text Builtin_relation.has_taxon; 430 - ["rel"; "has-author"], Syn.Text Builtin_relation.has_author; 431 - ["rel"; "has-direct-contributor"], Syn.Text Builtin_relation.has_direct_contributor; 432 - ["rel"; "transcludes"], Syn.Text Builtin_relation.transcludes; 433 - ["rel"; "transcludes"; "transitive-closure"], Syn.Text Builtin_relation.transcludes_tc; 434 - ["rel"; "transcludes"; "reflexive-transitive-closure"], Syn.Text Builtin_relation.transcludes_rtc; 435 - ["rel"; "links-to"], Syn.Text Builtin_relation.links_to; 436 - ["rel"; "is-reference"], Syn.Text Builtin_relation.is_reference; 437 - ["rel"; "is-person"], Syn.Text Builtin_relation.is_person; 438 - ["rel"; "is-node"], Syn.Text Builtin_relation.is_node; 439 - ["rel"; "is-article"], Syn.Text Builtin_relation.is_article; 440 - ["rel"; "is-asset"], Syn.Text Builtin_relation.is_asset; 441 - ["rel"; "in-host"], Syn.Text Builtin_relation.in_host; 442 - ["execute"], Syn.Dx_execute; 443 - ["route-asset"], Syn.Route_asset; 444 - ["syndicate-query-as-json-blob"], Syn.Syndicate_query_as_json_blob; 445 - ["syndicate-current-tree-as-atom-feed"], Syn.Syndicate_current_tree_as_atom_feed; 446 - ["current-tree"], Syn.Current_tree; 447 - ] 311 + (* Feel free to extend this *) 312 + let tex_builtin_words = ["left"; "right"; "big"; "bigr"; "Big"; "Bigr"; "bigg"; "biggr"; "Bigg"; "Biggr"; "bigl"; "Bigl"; "biggl"; "Biggl"; "mathrlap"; "mathllap"; "mathclap"; "rlap"; "llap"; "ulap"; "dlap"; "infty"; "infinity"; "lbrace"; "rbrace"; "llbracket"; "rrbracket"; "lvert"; "lVert"; "rvert"; "rVert"; "vert"; "Vert"; "setminus"; "backslash"; "smallsetminus"; "sslash"; "lfloor"; "lceil"; "lmoustache"; "lang"; "langle"; "llangle"; "rfloor"; "rceil"; "rmoustache"; "rang"; "rangle"; "rrangle"; "uparrow"; "downarrow"; "updownarrow"; "prime"; "alpha"; "beta"; "gamma"; "delta"; "zeta"; "eta"; "theta"; "iota"; "kappa"; "lambda"; "mu"; "nu"; "xi"; "pi"; "rho"; "sigma"; "tau"; "upsilon"; "chi"; "psi"; "omega"; "backepsilon"; "varkappa"; "varpi"; "varrho"; "varsigma"; "vartheta"; "varepsilon"; "phi"; "varphi"; "arccos"; "arcsin"; "arctan"; "arg"; "cos"; "cosh"; "cot"; "coth"; "csc"; "deg"; "dim"; "exp"; "hom"; "ker"; "lg"; "ln"; "log"; "sec"; "sin"; "sinh"; "tan"; "tanh"; "det"; "gcd"; "inf"; "lim"; "liminf"; "limsup"; "max"; "min"; "Pr"; "sup"; "omicron"; "epsilon"; "cdot"; "Alpha"; "Beta"; "Delta"; "Gamma"; "digamma"; "Lambda"; "Pi"; "Phi"; "Psi"; "Sigma"; "Theta"; "Xi"; "Zeta"; "Eta"; "Iota"; "Kappa"; "Mu"; "Nu"; "Rho"; "Tau"; "mho"; "Omega"; "Upsilon"; "Upsi"; "iff"; "Longleftrightarrow"; "Leftrightarrow"; "impliedby"; "Leftarrow"; "implies"; "Rightarrow"; "hookleftarrow"; "embedsin"; "hookrightarrow"; "longleftarrow"; "longrightarrow"; "leftarrow"; "to"; "rightarrow"; "leftrightarrow"; "mapsto"; "map"; "nearrow"; "nearr"; "nwarrow"; "nwarr"; "searrow"; "searr"; "swarrow"; "swarr"; "neArrow"; "neArr"; "nwArrow"; "nwArr"; "seArrow"; "seArr"; "swArrow"; "swArr"; "darr"; "Downarrow"; "uparr"; "Uparrow"; "downuparrow"; "duparr"; "updarr"; "Updownarrow"; "leftsquigarrow"; "rightsquigarrow"; "dashleftarrow"; "dashrightarrow"; "curvearrowbotright"; "righttoleftarrow"; "lefttorightarrow"; "leftrightsquigarrow"; "upuparrows"; "rightleftarrows"; "rightrightarrows"; "curvearrowleft"; "curvearrowright"; "downdownarrows"; "leftarrowtail"; "rightarrowtail"; "leftleftarrows"; "leftrightarrows"; "Lleftarrow"; "Rrightarrow"; "looparrowleft"; "looparrowright"; "Lsh"; "Rsh"; "circlearrowleft"; "circlearrowright"; "twoheadleftarrow"; "twoheadrightarrow"; "nLeftarrow"; "nleftarrow"; "nLeftrightarrow"; "nleftrightarrow"; "nRightarrow"; "nrightarrow"; "rightharpoonup"; "rightharpoondown"; "leftharpoonup"; "leftharpoondown"; "downharpoonleft"; "downharpoonright"; "leftrightharpoons"; "rightleftharpoons"; "upharpoonleft"; "upharpoonright"; "xrightarrow"; "xleftarrow"; "xleftrightarrow"; "xLeftarrow"; "xRightarrow"; "xLeftrightarrow"; "xleftrightharpoons"; "xrightleftharpoons"; "xhookleftarrow"; "xhookrightarrow"; "xmapsto"; "dots"; "ldots"; "cdots"; "ddots"; "udots"; "vdots"; "colon"; "cup"; "union"; "bigcup"; "Union"; "&Union;"; "cap"; "intersection"; "bigcap"; "Intersection"; "in"; "coloneqq"; "Coloneqq"; "coloneq"; "Coloneq"; "eqqcolon"; "Eqqcolon"; "eqcolon"; "Eqcolon"; "colonapprox"; "Colonapprox"; "colonsim"; "Colonsim"; "dblcolon"; "ast"; "Cap"; "Cup"; "circledast"; "circledcirc"; "curlyvee"; "curlywedge"; "divideontimes"; "dotplus"; "leftthreetimes"; "rightthreetimes"; "veebar"; "gt"; "lt"; "approxeq"; "backsim"; "backsimeq"; "barwedge"; "doublebarwedge"; "subset"; "subseteq"; "subseteqq"; "subsetneq"; "subsetneqq"; "varsubsetneq"; "varsubsetneqq"; "prec"; "parallel"; "nparallel"; "shortparallel"; "nshortparallel"; "perp"; "eqslantgtr"; "eqslantless"; "gg"; "ggg"; "geq"; "geqq"; "geqslant"; "gneq"; "gneqq"; "gnapprox"; "gnsim"; "gtrapprox"; "ge"; "le"; "leq"; "leqq"; "leqslant"; "lessapprox"; "lessdot"; "lesseqgtr"; "lesseqqgtr"; "lessgtr"; "lneq"; "lneqq"; "lnsim"; "lvertneqq"; "gtrsim"; "gtrdot"; "gtreqless"; "gtreqqless"; "gtrless"; "gvertneqq"; "lesssim"; "lnapprox"; "nsubset"; "nsubseteq"; "nsubseteqq"; "notin"; "ni"; "notni"; "nmid"; "nshortmid"; "preceq"; "npreceq"; "ll"; "ngeq"; "ngeqq"; "ngeqslant"; "nleq"; "nleqq"; "nleqslant"; "nless"; "supset"; "supseteq"; "supseteqq"; "supsetneq"; "supsetneqq"; "varsupsetneq"; "varsupsetneqq"; "approx"; "asymp"; "bowtie"; "dashv"; "Vdash"; "vDash"; "VDash"; "vdash"; "Vvdash"; "models"; "sim"; "simeq"; "nsim"; "smile"; "triangle"; "triangledown"; "triangleleft"; "cong"; "succ"; "nsucc"; "ngtr"; "nsupset"; "nsupseteq"; "propto"; "equiv"; "nequiv"; "frown"; "triangleright"; "ncong"; "succeq"; "succapprox"; "succnapprox"; "succcurlyeq"; "succsim"; "succnsim"; "nsucceq"; "nvDash"; "nvdash"; "nVDash"; "amalg"; "pm"; "mp"; "bigcirc"; "wr"; "odot"; "uplus"; "clubsuit"; "spadesuit"; "Diamond"; "diamond"; "sqcup"; "sqcap"; "sqsubset"; "sqsubseteq"; "sqsupset"; "sqsupseteq"; "Subset"; "Supset"; "ltimes"; "div"; "rtimes"; "bot"; "therefore"; "thickapprox"; "thicksim"; "varpropto"; "varnothing"; "flat"; "vee"; "because"; "between"; "Bumpeq"; "bumpeq"; "circeq"; "curlyeqprec"; "curlyeqsucc"; "doteq"; "doteqdot"; "eqcirc"; "fallingdotseq"; "multimap"; "pitchfork"; "precapprox"; "precnapprox"; "preccurlyeq"; "precsim"; "precnsim"; "risingdotseq"; "sharp"; "bullet"; "nexists"; "dagger"; "ddagger"; "not"; "top"; "natural"; "angle"; "measuredangle"; "backprime"; "bigstar"; "blacklozenge"; "lozenge"; "blacksquare"; "blacktriangle"; "blacktriangleleft"; "blacktriangleright"; "blacktriangledown"; "ntriangleleft"; "ntriangleright"; "ntrianglelefteq"; "ntrianglerighteq"; "trianglelefteq"; "trianglerighteq"; "triangleq"; "vartriangleleft"; "vartriangleright"; "forall"; "bigtriangleup"; "bigtriangledown"; "nprec"; "aleph"; "beth"; "eth"; "ell"; "hbar"; "Im"; "imath"; "jmath"; "wp"; "Re"; "Perp"; "Vbar"; "boxdot"; "Box"; "square"; "emptyset"; "empty"; "exists"; "circ"; "rhd"; "lhd"; "lll"; "unrhd"; "unlhd"; "Del"; "nabla"; "sphericalangle"; "heartsuit"; "diamondsuit"; "partial"; "qed"; "mod"; "pmod"; "bottom"; "neg"; "neq"; "ne"; "shortmid"; "mid"; "int"; "integral"; "iint"; "doubleintegral"; "iiint"; "tripleintegral"; "iiiint"; "quadrupleintegral"; "oint"; "conint"; "contourintegral"; "times"; "star"; "circleddash"; "odash"; "intercal"; "smallfrown"; "smallsmile"; "boxminus"; "minusb"; "boxplus"; "plusb"; "boxtimes"; "timesb"; "sum"; "prod"; "product"; "coprod"; "coproduct"; "otimes"; "Otimes"; "bigotimes"; "ominus"; "oslash"; "oplus"; "Oplus"; "bigoplus"; "bigodot"; "bigsqcup"; "bigsqcap"; "biginterleave"; "biguplus"; "wedge"; "Wedge"; "bigwedge"; "Vee"; "bigvee"; "invamp"; "parr"; "frac"; "tfrac"; "binom"; "tbinom"; "tensor"; "multiscripts"; "overbrace"; "underbrace"; "underline"; "bar"; "overline"; "closure"; "widebar"; "vec"; "widevec"; "overrightarrow"; "overleftarrow"; "overleftrightarrow"; "underrightarrow"; "underleftarrow"; "underleftrightarrow"; "dot"; "ddot"; "dddot"; "ddddot"; "tilde"; "widetilde"; "check"; "widecheck"; "hat"; "widehat"; "underset"; "stackrel"; "overset"; "over"; "atop"; "underoverset"; "sqrt"; "root"; "space"; "text"; "statusline"; "tooltip"; "toggle"; "begintoggle"; "endtoggle"; "mathraisebox"; "fghilight"; "fghighlight"; "bghilight"; "bghighlight"; "color"; "bgcolor"; "displaystyle"; "textstyle"; "textsize"; "scriptsize"; "scriptscriptsize"; "mathit"; "mathsf"; "mathtt"; "boldsymbol"; "mathbf"; "mathrm"; "mathbb"; "mathfrak"; "mathfr"; "slash"; "boxed"; "mathcal"; "mathscr"; "begin"; "end"; "substack"; "array"; "arrayopts"; "colalign"; "collayout"; "rowalign"; "align"; "equalrows"; "equalcols"; "rowlines"; "collines"; "frame"; "padding"; "rowopts"; "cellopts"; "rowspan"; "colspan"; "thinspace"; "medspace"; "thickspace"; "quad"; "qquad"; "negspace"; "negthinspace"; "negmedspace"; "negthickspace"; "phantom"; "operatorname"; "mathop"; "mathbin"; "mathrel"; "includegraphics"; "lparen"; "rparen"; "land"; "lor"; "middle"; "mathpunct"; "mathord"] 313 + 314 + (* Feel free to extend this *) 315 + let tex_builtin_symbols = ['_'; ','; ';'] 316 + 317 + let builtins = 318 + [ 319 + ["p"], Syn.Prim `P; 320 + ["em"], Syn.Prim `Em; 321 + ["strong"], Syn.Prim `Strong; 322 + ["li"], Syn.Prim `Li; 323 + ["ol"], Syn.Prim `Ol; 324 + ["ul"], Syn.Prim `Ul; 325 + ["code"], Syn.Prim `Code; 326 + ["blockquote"], Syn.Prim `Blockquote; 327 + ["pre"], Syn.Prim `Pre; 328 + ["figure"], Syn.Prim `Figure; 329 + ["figcaption"], Syn.Prim `Figcaption; 330 + ["transclude"], Syn.Transclude; 331 + ["tex"], Syn.Embed_tex; 332 + ["ref"], Syn.Ref; 333 + ["title"], Syn.Title; 334 + ["taxon"], Syn.Taxon; 335 + ["date"], Syn.Date; 336 + ["meta"], Syn.Meta; 337 + ["author"], Syn.Attribution (Author, `Uri); 338 + ["author"; "literal"], Syn.Attribution (Author, `Content); 339 + ["contributor"], Syn.Attribution (Contributor, `Uri); 340 + ["contributor"; "literal"], Syn.Attribution (Contributor, `Content); 341 + ["parent"], Syn.Parent; 342 + ["number"], Syn.Number; 343 + ["tag"], Syn.Tag `Content; 344 + ["query"], Syn.Results_of_query; 345 + ["rel"; "has-tag"], Syn.Text Builtin_relation.has_tag; 346 + ["rel"; "has-taxon"], Syn.Text Builtin_relation.has_taxon; 347 + ["rel"; "has-author"], Syn.Text Builtin_relation.has_author; 348 + ["rel"; "has-direct-contributor"], Syn.Text Builtin_relation.has_direct_contributor; 349 + ["rel"; "transcludes"], Syn.Text Builtin_relation.transcludes; 350 + ["rel"; "transcludes"; "transitive-closure"], Syn.Text Builtin_relation.transcludes_tc; 351 + ["rel"; "transcludes"; "reflexive-transitive-closure"], Syn.Text Builtin_relation.transcludes_rtc; 352 + ["rel"; "links-to"], Syn.Text Builtin_relation.links_to; 353 + ["rel"; "is-reference"], Syn.Text Builtin_relation.is_reference; 354 + ["rel"; "is-person"], Syn.Text Builtin_relation.is_person; 355 + ["rel"; "is-node"], Syn.Text Builtin_relation.is_node; 356 + ["rel"; "is-article"], Syn.Text Builtin_relation.is_article; 357 + ["rel"; "is-asset"], Syn.Text Builtin_relation.is_asset; 358 + ["rel"; "in-host"], Syn.Text Builtin_relation.in_host; 359 + ["execute"], Syn.Dx_execute; 360 + ["route-asset"], Syn.Route_asset; 361 + ["syndicate-query-as-json-blob"], Syn.Syndicate_query_as_json_blob; 362 + ["syndicate-current-tree-as-atom-feed"], Syn.Syndicate_current_tree_as_atom_feed; 363 + ["current-tree"], Syn.Current_tree; 364 + ] @ 365 + begin 366 + let@ word = List.map @~ tex_builtin_words in 367 + [word], Syn.TeX_cs (TeX_cs.Word word) 368 + end @ 369 + begin 370 + let@ sym = List.map @~ tex_builtin_symbols in 371 + [String_util.implode [sym]], Syn.TeX_cs (TeX_cs.Symbol sym) 372 + end 448 373 449 374 let expand_tree_inner ~forest (code : Tree.code) : Tree.syn = 450 375 let trace k =
-2
lib/compiler/Expand.mli
··· 23 23 end 24 24 end 25 25 26 - val suggestions : string list -> ('a, 'b) Trie.t -> (Trie.path * 'a * int) list 27 - 28 26 val expand : forest: State.t -> Code.t -> Syn.t 29 27 val expand_tree : forest: State.t -> Tree.code -> Tree.syn * Reporter.Message.t Asai.Diagnostic.t list 30 28
+4 -2
lib/compiler/LaTeX_pipeline.ml
··· 39 39 Reporter.fatal 40 40 External_error 41 41 ~extra_remarks: [ 42 - Asai.Diagnostic.loctextf ?loc 42 + Asai.Diagnostic.loctextf 43 + ?loc 43 44 "Encountered fatal LaTeX error: @.@.%s@.@. while running `%s` in directory `%s`." 44 45 formatted_output 45 46 (String.concat " " cmd) ··· 61 62 Reporter.fatal 62 63 External_error 63 64 ~extra_remarks: [ 64 - Asai.Diagnostic.loctextf ?loc 65 + Asai.Diagnostic.loctextf 66 + ?loc 65 67 "Encountered fatal error running `dvisvgm`: %s" 66 68 (Buffer.contents err_buf) 67 69 ]
+76
lib/compiler/Suggestions.ml
··· 1 + open Forester_core 2 + open Bwd 3 + 4 + (* TODO: remove this in favor of https://github.com/ocaml/ocaml/pull/13760 *) 5 + let edit_distance ~cutoff x y = 6 + let len_x, len_y = String.length x, String.length y in 7 + let grid = Array.make_matrix (len_x + 1) (len_y + 1) 0 in 8 + for i = 1 to len_x do 9 + grid.(i).(0) <- i; 10 + done; 11 + for j = 1 to len_y do 12 + grid.(0).(j) <- j; 13 + done; 14 + for j = 1 to len_y do 15 + for i = 1 to len_x do 16 + let cost = if x.[i - 1] = y.[j - 1] then 0 else 1 in 17 + let k = Int.min (grid.(i - 1).(j) + 1) (grid.(i).(j - 1) + 1) in 18 + grid.(i).(j) <- Int.min k (grid.(i - 1).(j - 1) + cost) 19 + done; 20 + done; 21 + let result = grid.(len_x).(len_y) in 22 + if result > cutoff then None 23 + else 24 + Some result 25 + 26 + let suggestions 27 + ?prefix 28 + ~(cutoff : int) 29 + (p : Trie.bwd_path) 30 + : ('data, 'tag) Trie.t -> ('data, int) Trie.t 31 + = 32 + let compare p d = 33 + edit_distance ~cutoff (String.concat "" (Bwd.to_list p)) (String.concat "" (Bwd.to_list d)) 34 + in 35 + Trie.filter_map 36 + ?prefix 37 + (fun q (data, _) -> 38 + match compare p q with 39 + | Some i -> 40 + if i > cutoff then 41 + None 42 + else 43 + (Some (data, i)) 44 + | None -> None 45 + ) 46 + 47 + let suggestions ~visible path = 48 + suggestions ~cutoff: 2 (Bwd.of_list path) visible 49 + |> Trie.to_seq 50 + |> Seq.map (fun (path, (data, distance)) -> (path, data, distance)) 51 + |> List.of_seq 52 + |> List.sort (fun (_, _, a) (_, _, b) -> Int.compare a b) 53 + 54 + let create_suggestions ~visible path = 55 + let suggestions = suggestions ~visible path in 56 + let extra_remarks = 57 + if List.length suggestions > 0 then 58 + let (path, data, _) = List.hd suggestions in 59 + let location_hint = 60 + match data with 61 + | Syn.Term ({loc = Some loc; _} :: _) -> 62 + begin 63 + match Range.view loc with 64 + | `End_of_file {source; _} 65 + | `Range ({source; _}, _) -> 66 + match Range.title source with 67 + | Some string -> 68 + [Asai.Diagnostic.loctextf "defined in %s" string] 69 + | _ -> [] 70 + end 71 + | _ -> [] 72 + in 73 + [Asai.Diagnostic.loctextf "Did you mean %a?" Trie.pp_path path] @ location_hint 74 + else [] 75 + in 76 + extra_remarks
+1 -1
lib/compiler/test/Test_expansion.ml
··· 18 18 module S = Resolver.Scope 19 19 module P = Resolver.P 20 20 let config = Config.default () 21 - let _data = Alcotest.testable P.pp_data (=) 21 + let _data = Alcotest.testable Syn.pp_resolver_data (=) 22 22 end 23 23 24 24 open State.Syntax
+13 -6
lib/core/Base.ml
··· 4 4 * SPDX-License-Identifier: GPL-3.0-or-later 5 5 *) 6 6 7 - type delim = 8 - Braces | Squares | Parens 7 + type eval_mode = 8 + | Text_mode 9 + | TeX_mode 10 + [@@deriving show, repr] 11 + 12 + type binding_info = 13 + | Strict 14 + | Lazy 9 15 [@@deriving show, repr] 10 16 11 - type binding_strategy = 12 - Lazy | Strict 17 + type 'a binding = binding_info * 'a 13 18 [@@deriving show, repr] 14 19 15 - type 'a binding = binding_strategy * 'a 20 + type delim = 21 + Braces | Squares | Parens 16 22 [@@deriving show, repr] 17 23 18 24 let delim_to_strings = function ··· 21 27 | Parens -> "(", ")" 22 28 23 29 type math_mode = 24 - Inline | Display 30 + | Inline 31 + | Display 25 32 [@@deriving show, repr] 26 33 27 34 type visibility =
+12 -19
lib/core/Base.mli
··· 6 6 7 7 (** {1 Base} *) 8 8 9 + type eval_mode = 10 + | Text_mode 11 + | TeX_mode 12 + [@@deriving show, repr] 13 + 14 + type binding_info = 15 + | Strict 16 + | Lazy 17 + [@@deriving show, repr] 18 + 9 19 (** {2 Delimiters} *) 10 20 11 21 type delim = Braces | Squares | Parens ··· 16 26 val delim_to_strings : delim -> string * string 17 27 18 28 (** {2 Variable binding} *) 19 - 20 - type binding_strategy = Lazy | Strict 21 - val pp_binding_strategy : 22 - Format.formatter -> 23 - binding_strategy -> 24 - unit 25 - val show_binding_strategy : binding_strategy -> string 26 - val binding_strategy_t : binding_strategy Repr.t 27 - type 'a binding = binding_strategy * 'a 28 - val pp_binding : 29 - (Format.formatter -> 'a -> unit) -> 30 - Format.formatter -> 31 - 'a binding -> 32 - unit 33 - val show_binding : 34 - (Format.formatter -> 'a -> unit) -> 35 - 'a binding -> 36 - string 37 - val binding_t : 'a Repr.t -> (binding_strategy * 'a) Repr.t 29 + type 'a binding = binding_info * 'a 30 + [@@deriving show, repr] 38 31 39 32 (** {2 Math modes} *) 40 33
+18 -25
lib/core/Reporter.ml
··· 41 41 got: Value.t option; 42 42 expected: expected_value list 43 43 } 44 - | Resolution_error of (Symbol.t * Value.t Value.Env.t) 45 - | Expansion_error of 46 - [ 47 - | `Resolution_error of 48 - (((Sc.data, R.P.tag) Trie.t [@opaque]) 49 - * (Yuujinchou.Trie.Untagged.path [@printer Format.(pp_print_list pp_print_string)])) 50 - | `Xmlns_error 51 - ] 52 - | Resolution_warning 44 + | Unbound_fluid_symbol of (Symbol.t * Value.t Value.Env.t) 45 + | Unbound_lexical_symbol of (Symbol.t * Value.t Value.Env.t) 46 + | Unresolved_identifier of ((Sc.data, R.P.tag) Trie.t [@opaque]) * Trie.path 47 + | Unresolved_xmlns of string 53 48 | Reference_error of URI.t 54 49 | Unhandled_case 55 50 | Transclusion_loop ··· 71 66 72 67 let default_severity : t -> Asai.Diagnostic.severity = function 73 68 | Import_not_found _ -> Error 74 - | Expansion_error _ -> Error 69 + | Unresolved_identifier _ -> Warning 70 + | Unresolved_xmlns _ -> Error 75 71 | Invalid_URI -> Error 76 72 | Unbound_method _ -> Error 77 73 | Asset_has_no_content_address _ -> Error ··· 82 78 | Parse_error -> Error 83 79 | Type_error _ -> Error 84 80 | Type_warning -> Warning 85 - | Resolution_error _ -> Error 86 - | Resolution_warning -> Warning 81 + | Unbound_fluid_symbol _ -> Error 82 + | Unbound_lexical_symbol _ -> Error 87 83 | Unhandled_case -> Bug 88 84 | Transclusion_loop -> Error 89 85 | Internal_error -> Bug ··· 112 108 | Unbound_method _ -> "unbound_method" 113 109 | Type_warning -> "type_warning" 114 110 | Type_error _ -> "type_error" 115 - | Resolution_error _ -> "resolution_error" 116 - | Expansion_error _ -> "expansion_error" 117 - | Resolution_warning -> "resolution_warning" 111 + | Unbound_fluid_symbol _ -> "unbound_fluid_symbol" 112 + | Unbound_lexical_symbol _ -> "unbound_lexical_symbol" 113 + | Unresolved_xmlns _ -> "unresolved_xmlns" 114 + | Unresolved_identifier _ -> "unresolved_identifier" 118 115 | Reference_error _ -> "reference_error" 119 116 | Unhandled_case -> "unhandled_case" 120 117 | Transclusion_loop -> "transclusion_loop" ··· 160 157 161 158 let default_text : t -> Asai.Diagnostic.text = function 162 159 | Import_not_found uri -> Asai.Diagnostic.textf "%a not found" URI.pp uri 163 - | Expansion_error err -> 164 - begin 165 - match err with 166 - | `Xmlns_error -> 167 - Asai.Diagnostic.textf "" 168 - | `Resolution_error (_, p) -> 169 - Asai.Diagnostic.textf "Unknown binding %a" Trie.pp_path p 170 - end 160 + | Unresolved_xmlns prefix -> 161 + Asai.Diagnostic.textf "Could not resolve prefix `%s` to XML namespace" prefix 162 + | Unresolved_identifier (_, p) -> 163 + Asai.Diagnostic.textf "Unknown binding \\%a. To interpret as a TeX control sequence, explicitly enter TeX mode using #{...}." Trie.pp_path p 171 164 | Type_error {got; expected} -> 172 165 begin 173 166 let expected_msg = ··· 256 249 | Reference_error _ 257 250 | Parse_error 258 251 | Type_warning 259 - | Resolution_error _ 260 - | Resolution_warning 252 + | Unbound_fluid_symbol _ 253 + | Unbound_lexical_symbol _ 261 254 | Unhandled_case 262 255 | Transclusion_loop 263 256 | Internal_error
+4 -8
lib/core/Reporter.mli
··· 36 36 got: Value.t option; 37 37 expected: expected_value list 38 38 } 39 - | Resolution_error of (Symbol.t * Value.t Value.Env.t) 40 - | Expansion_error of 41 - [ 42 - | `Resolution_error of 43 - (Resolver.Scope.data, Resolver.P.tag) Trie.t * Trie.Untagged.path 44 - | `Xmlns_error 45 - ] 46 - | Resolution_warning 39 + | Unbound_fluid_symbol of (Symbol.t * Value.t Value.Env.t) 40 + | Unbound_lexical_symbol of (Symbol.t * Value.t Value.Env.t) 41 + | Unresolved_identifier of ((Resolver.Scope.data, Resolver.P.tag) Trie.t) * Trie.path 42 + | Unresolved_xmlns of string 47 43 | Reference_error of URI.t 48 44 | Unhandled_case 49 45 | Transclusion_loop
+2 -5
lib/core/Resolver.ml
··· 5 5 *) 6 6 7 7 module P = struct 8 - type data = 9 - | Term of Syn.t 10 - | Xmlns of {xmlns: string; prefix: string} 11 - [@@deriving show] 8 + type data = Syn.resolver_data 12 9 13 10 type tag = Asai.Range.t option 14 11 ··· 47 44 ( 48 45 pp_print_pair 49 46 Trie.pp_path 50 - (pp_print_pair P.pp_data (pp_print_option Asai.Range.dump)) 47 + (pp_print_pair Syn.pp_resolver_data (pp_print_option Asai.Range.dump)) 51 48 ) 52 49 ) 53 50 end
+10 -12
lib/core/Syn.ml
··· 22 22 | Get of t 23 23 | Xml_tag of xml_qname * (xml_qname * t) list * t 24 24 | TeX_cs of TeX_cs.t 25 + | Unresolved_ident of ((resolver_data, Range.t option) Trie.t [@opaque]) * Trie.path 25 26 | Prim of Prim.t 26 27 | Object of {self: Symbol.t; methods: (string * t) list} 27 28 | Patch of {obj: t; self: Symbol.t; super: Symbol.t; methods: (string * t) list} ··· 53 54 and t = node Range.located list 54 55 [@@deriving show] 55 56 57 + and resolver_data = 58 + | Term of t 59 + | Xmlns of {xmlns: string; prefix: string} 60 + [@@deriving show] 61 + 56 62 let map f node = 57 63 match node with 58 64 | Group (d, t) -> Group (d, f @@ t) ··· 66 72 | Xml_tag (q, qs, t) -> Xml_tag (q, List.map (fun (q, t) -> q, f t) qs, f t) 67 73 | Call (t, s) -> Call (f t, s) 68 74 | Object {self; methods} -> 69 - Object 70 - { 71 - self; 72 - methods = List.map (fun (str, t) -> str, f t) methods 73 - } 75 + Object {self; methods = List.map (fun (str, t) -> str, f t) methods} 74 76 | Patch {obj; self; super; methods} -> 75 - Patch 76 - { 77 - obj = f obj; 78 - self; 79 - super; 80 - methods = List.map (fun (str, t) -> str, f t) methods 81 - } 77 + Patch {obj = f obj; self; super; methods = List.map (fun (str, t) -> str, f t) methods} 82 78 | Dx_sequent (t, ts) -> Dx_sequent (f t, List.map f ts) 83 79 | Dx_query (s, ps, ns) -> Dx_query (s, List.map f ps, List.map f ns) 84 80 | Dx_const (s, n) -> Dx_const (s, f n) ··· 88 84 | Var _ 89 85 | Sym _ 90 86 | TeX_cs _ 87 + | Unresolved_ident _ 91 88 | Prim _ 92 89 | Results_of_query 93 90 | Transclude ··· 135 132 | Var _ 136 133 | Sym _ 137 134 | TeX_cs _ 135 + | Unresolved_ident _ 138 136 | Prim _ 139 137 | Results_of_query 140 138 | Transclude
+3 -2
lib/language_server/Completion.ml
··· 193 193 | Get _ 194 194 | Xml_tag (_, _, _) 195 195 | TeX_cs _ 196 + | Unresolved_ident _ 196 197 | Object _ 197 198 | Patch _ 198 199 | Call (_, _) ··· 242 243 243 244 let make (path, (data, _): Yuujinchou.Trie.path * (Resolver.P.data * Asai.Range.t option)) = 244 245 match data with 245 - | Resolver.P.Term syn -> 246 + | Term syn -> 246 247 (* NOTE: Eventually we want to analyse the syntax so that, for example, 247 248 you can tab through the snippet for a function of arity n*) 248 249 let kind = kind (List.hd syn).value in ··· 255 256 ~label: (String.concat "/" path) 256 257 () 257 258 ) 258 - | Resolver.P.Xmlns _ -> 259 + | Xmlns _ -> 259 260 assert false 260 261 261 262 (* These are useful completion items that are handled during parsing, not during expansion and are thus not "builtins"*)
+3 -2
lib/language_server/Workspace_symbols.ml
··· 31 31 let@ path, (data, range) = List.filter_map @~ List.of_seq @@ Trie.to_seq exports in 32 32 let@ location = Option.map @~ location_of_range range in 33 33 match data with 34 - | Resolver.P.Xmlns _ -> 34 + | Xmlns _ -> 35 35 L.SymbolInformation.create 36 36 ~kind: Namespace 37 37 ~location 38 38 ~name: (Format.asprintf "%a" Resolver.Scope.pp_path path) 39 39 () 40 - | Resolver.P.Term syn -> 40 + | Term syn -> 41 41 let kind = 42 42 match (List.hd syn).value with 43 43 | Syn.Text _ -> L.SymbolKind.String ··· 55 55 | Syn.Get _ 56 56 | Syn.Xml_tag (_, _, _) 57 57 | Syn.TeX_cs _ 58 + | Syn.Unresolved_ident _ 58 59 | Syn.Prim _ 59 60 | Syn.Patch _ 60 61 | Syn.Call (_, _)
+1 -1
test/Testables.ml
··· 45 45 let syn = testable Syn.pp (=) 46 46 let eval_result = testable Eval.pp_result (=) 47 47 let path = testable Trie.pp_path (=) 48 - let data = testable Resolver.P.pp_data (=) 48 + let data = testable Syn.pp_resolver_data (=) 49 49 let diagnostic = 50 50 let pp = pp_diagnostic Reporter.Message.pp in 51 51 testable pp (=)