-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merlin files no longer get generated (ocaml/dune#3554); It's quite nice actually, but I think it's also valuable to keep a simple and lightweight way of extracting basic info about the project structure, such as what library a module belongs to, or what modules are open at compilation time. This usually follows from directory structures, but that's not a requirement. So, following the "simplest approximation" policy this project adheres to, this patch adds trivial parsing of `dune` files, just to infer what library a module belongs to. This in turn enables the search engine to know about the corresponding open module, and helps get proper cross-module references.
- Loading branch information
Showing
6 changed files
with
171 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
(**************************************************************************) | ||
(* *) | ||
(* Copyright 2021 OCamlPro *) | ||
(* *) | ||
(* All rights reserved. This file is distributed under the terms of *) | ||
(* the Lesser GNU Public License version 3.0. *) | ||
(* *) | ||
(* This software is distributed in the hope that it will be useful, *) | ||
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) | ||
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) | ||
(* Lesser GNU General Public License for more details. *) | ||
(* *) | ||
(**************************************************************************) | ||
|
||
type sexp = A of string | T of sexp list | ||
|
||
let atom str i = | ||
let rec escaped j = | ||
if j >= String.length str then j | ||
else match str.[j] with | ||
| '"' -> j+1 | ||
| '\\' -> escaped (j+2) | ||
| _ -> escaped (j+1) | ||
in | ||
let rec unescaped j = | ||
if j >= String.length str then j | ||
else match str.[j] with | ||
| ' ' | '\n' | '\t' | '\r' | '(' | ')' -> j | ||
| '\\' -> unescaped (j+2) | ||
| _ -> unescaped (j+1) | ||
in | ||
let j = match str.[i] with | ||
| '"' -> escaped (i+1) | ||
| _ -> unescaped (i+1) | ||
in | ||
j, String.sub str i (j - i) | ||
|
||
let rec sexp_parse str i = | ||
if i >= String.length str then i, [] | ||
else | ||
match str.[i] with | ||
| ' ' | '\n' | '\t' | '\r' -> sexp_parse str (i+1) | ||
| '(' -> | ||
let i, t1 = sexp_parse str (i+1) in | ||
let i, t = sexp_parse str i in | ||
i, T t1 :: t | ||
| ')' -> i+1, [] | ||
| ';' -> | ||
let i = | ||
try String.index_from str (i+1) '\n' + 1 | ||
with Not_found -> String.length str | ||
in | ||
sexp_parse str i | ||
| _ -> | ||
let i, a = atom str i in | ||
let i, t = sexp_parse str i in | ||
i, A a :: t | ||
|
||
let rec cut_list a acc = function | ||
| x :: r -> if x = a then acc, r else cut_list a (x::acc) r | ||
| [] -> acc, [] | ||
|
||
let module_eq name = function | ||
| A n -> IndexMisc.capitalize n = name | ||
| _ -> false | ||
|
||
let rec get_lib_name modname = function | ||
| T (A "library" :: t) :: r -> | ||
if List.mem (T [A "wrapped"; A "false"]) t then get_lib_name modname r | ||
else | ||
let libname = | ||
match | ||
List.find_opt (function T (A "name" :: _) -> true | _ -> false) t | ||
with | ||
| Some (T [_; A name]) -> name | ||
| _ -> "" | ||
in | ||
(match | ||
List.find_opt (function T ( A "modules" :: _) -> true | _ -> false) t | ||
with | ||
| None -> Some libname | ||
| Some (T (_ :: ms)) -> | ||
let inc, exc = cut_list (A "\\") [] ms in | ||
if not (List.exists (module_eq modname) exc) && | ||
List.exists (fun n -> module_eq modname n || n = A ":standard") | ||
inc | ||
then Some libname | ||
else | ||
get_lib_name modname r | ||
| Some _ -> assert false) | ||
| _ :: r -> get_lib_name modname r | ||
| [] -> None | ||
|
||
let string_of_channel ic = | ||
let n = 4096 in | ||
let s = Bytes.create n in | ||
let b = Buffer.create 1024 in | ||
let rec iter ic b s = | ||
let nread = | ||
try input ic s 0 n | ||
with End_of_file -> 0 in | ||
if nread > 0 then ( | ||
Buffer.add_subbytes b s 0 nread; | ||
iter ic b s | ||
) in | ||
iter ic b s; | ||
Buffer.contents b | ||
|
||
let read_dune dir = | ||
try | ||
let ic = open_in (Filename.concat dir "dune") in | ||
let s = string_of_channel ic in | ||
let r = sexp_parse s 0 in | ||
close_in ic; | ||
Some r | ||
with Sys_error _ -> None | ||
|
||
let get_libname file = | ||
let modname = | ||
IndexMisc.capitalize (Filename.(basename (remove_extension file))) | ||
in | ||
match read_dune (Filename.dirname file) with | ||
| Some (_, sexp) -> get_lib_name modname sexp | ||
| None -> None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
(**************************************************************************) | ||
(* *) | ||
(* Copyright 2021 OCamlPro *) | ||
(* *) | ||
(* All rights reserved. This file is distributed under the terms of *) | ||
(* the Lesser GNU Public License version 3.0. *) | ||
(* *) | ||
(* This software is distributed in the hope that it will be useful, *) | ||
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) | ||
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) | ||
(* Lesser GNU General Public License for more details. *) | ||
(* *) | ||
(**************************************************************************) | ||
|
||
(** Looks up a 'dune' file in the dirname of the given file, and attempts to | ||
extract the name of the (wrapped) library the module belongs to. *) | ||
val get_libname: string -> string option |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters