codept a whole project dependency analyzer for ocaml
play

Codept, a whole-project dependency analyzer for OCaml Florian - PowerPoint PPT Presentation

Codept, a whole-project dependency analyzer for OCaml Florian octachron Angeletti INRIA ICFP 2019, OCaml workshop, 23 August 2019 Discovering dependencies $ ls a.ml b.ml c.ml d.ml e.ml f.ml atlas.ml Discovering dependencies $ ls


  1. Codept, a whole-project dependency analyzer for OCaml Florian “octachron” Angeletti INRIA ICFP 2019, OCaml workshop, 23 August 2019

  2. Discovering dependencies $ ls a.ml b.ml c.ml d.ml e.ml f.ml atlas.ml

  3. Discovering dependencies $ ls a.ml b.ml ◮ Discovering project structure c.ml d.ml e.ml f.ml atlas.ml

  4. Discovering dependencies $ ls a.ml b.ml ◮ Discovering project structure c.ml ◮ Building project d.ml e.ml f.ml atlas.ml

  5. Let’s call ocamldep

  6. Let’s call ocamldep B D C Atlas A F E

  7. Let’s call ocamldep The End

  8. Let’s call ocamldep wait . . . a flower?

  9. A . . . flower ? B D C Atlas A F E

  10. A . . . flower ? B (* Atlas.ml *) module X = A D C module Y = B module Z = C Atlas module W = D A F module R = E module S = F E

  11. $ ocamldep -map atlas.ml a.ml b.ml c.ml d.ml e.ml f.ml

  12. And submodule collisions? (* a.ml *) open B B open A A (* b.ml *) module A = struct end

  13. Don’t forget first class modules (* a.ml *) module type S = sig module A : sig end end let f () = let module M = struct module A = struct end A end in ( module M : S ) let () = let module M = ( val f ()) in let open M in let open A in ()

  14. Abstract module types? (* a.ml *) module type S = sig module type T module M : T end module F ( X : S )= struct module M = X . M end module X = struct A module type T = sig module A : sig end end module M = struct module A = struct end end end open F ( X ) open M open A

  15. Modules and compilation units Compilation units A concrete file or pair of files mapped to a module ◮ All compilation units are mapped to a module ◮ All modules do not come from compilation units

  16. Context matters ... open A

  17. Context matters module A = struct ... end open A

  18. Context matters (* start of the file *) open A

  19. Context matters open B (* Does B define a submodule A *) open A

  20. Dependency tracking in OCaml Recognizing compilation units from submodules.

  21. Naive dependencies ◮ All actual direct dependencies are recorded ◮ So many false positives ◮ Aliases are not tracked

  22. OCamldep’s way: local analysis Local analysis module Sub = struct ... end include Sub ◮ Every modules that is not of the current compilation unit submodules is a compilation unit ◮ Nearly an over-approximation ◮ False positive: post-processing phase ◮ Alias: manual map tracking with -map option

  23. OCamldep’s way: local analysis Local analysis module Sub = struct ... end include Sub ◮ Every modules that is not of the current compilation unit submodules is a compilation unit ◮ Nearly an over-approximation ◮ False positive: post-processing phase ◮ Alias: manual map tracking with -map option

  24. Going further: whole-project analysis How to get precise dependencies for a file A? What do you need for precise dependencies ◮ A signature for the universe

  25. Going further: whole-project analysis How to get precise dependencies for a file A? What do you need for precise dependencies ◮ A signature for the universe ◮ How to deal with first-class modules?

  26. Going further: whole-project analysis How to get precise dependencies for a file A? What do you need for precise dependencies ◮ A signature for the universe ◮ How to deal with first-class modules? ◮ A signature for all compilation units

  27. Going further: whole-project analysis How to get precise dependencies for a file A? What do you need for precise dependencies ◮ A signature for the universe ◮ How to deal with first-class modules? ◮ A signature for all compilation units ◮ A signature for all dependencies Codept core idea ◮ A dependency and signature analyzer ◮ ...than can stop on a missing signature and resume later

  28. Codept specification ◮ No warning, exact dependencies ◮ At worst, an over-approximation of dependencies ◮ All analysis results are serializable in machine readable formats Secondary goal ◮ Full compatibility with ocamldep

  29. 3 layers ◮ AST simplification ◮ Interruptible interpreter ◮ Dependency orchestration

  30. Simplified M2l Ast ◮ expressions ◮ classes ◮ patterns ◮ modules ◮ types ◮ module types type expression = | Open of module_expr | Include of module_expr | SigInclude of module_type | Bind of module_expr bind | Bind_sig of module_type bind | Bind_rec of module_expr bind list | Minor of annotation | Extension_node of extension and ... Full OCaml Parsetree: 960 LOC Simplified (M2l) AST : 80 LOC

  31. [ module M = module M = struct [ module X = [] (l2.2-l3.5)] module X = struct (l1.0-l4.3) end open [ M ](l5.0-6) end open [ X ](l5.7-13) open M open X open [ B ](l6.0-6) open B module C = [](l7.0-21) module C = struct end ]

  32. Interruptible interpreter ◮ How to represent partial evaluation result partial result, � , partial AST

  33. Interruptible interpreter ◮ How to represent partial evaluation result partial result, � , partial AST ◮ � : a still unknown module name

  34. Interruptible interpreter ◮ How to represent partial evaluation result partial result, � , partial AST ◮ � : a still unknown module name Zipper ◮ Add holes to the AST data type ◮ Holes are to be filled by the environment

  35. [ module M = [ module X = [] (l2.2-l3.5)] (l1.0-l4.3) Computation halted at: open [ M ](l5.0-6) ... open B ? open [ X ](l5.7-13) [ module C = [] (l7.0-21)] open [ B ](l6.0-6) module C = [](l7.0-21) ]

  36. Zipper example type ' hole me = ... | Ident : and module_expr = path_in_context me | Ident of | Apply_left : Paths . Simple .t M2l .module_expr | Apply of -> M2l .module_expr me { f: module_expr | Apply_right : ; x:module_expr module_expr } -> M2l .module_expr me ... | ...

  37. Evaluation ◮ Try to fill all holes ◮ Fail if there is a hole that the environment doesn’t know how to fill ◮ Return the signature and dependencies otherwise

  38. Orchestration ◮ Different strategies to compute whole-project signature and dependencies ◮ What to do with cycles?

  39. Cycles ◮ Report them? ◮ Try to remove them and go on with the rest of the computation? C D B A H E G F

  40. Codept in the real world How well does codept fare against its specification?

  41. Alias tracking E (* Atlas.ml *) D module X = A module Y = B F Atlas module Z = C module W = D C A module R = E B module S = F

  42. And submodule collisions? (* a.ml *) open B A open A B (* b.ml *) module A = struct end

  43. Don’t forget first class modules (* a.ml *) ... let () = A let module M = ( val f ()) in let open M in let open A in () [ Warning ]: a.ml:l7.6-12, first- class module M was opened while its signature was unknown. Local solution: (* a.ml *) ... let module M : S = ( val f ()) in ...

  44. Abstract module types? Work-in-progress.

  45. Performances Slower than ocamldep Not the right question:

  46. Library core, ocamldep compatible executable ◮ Codept executable, fully compatible with ocamldep

  47. Library core, ocamldep compatible executable ◮ Codept executable, fully compatible with ocamldep ◮ Core library, to be published on version 1.0

  48. Library core, ocamldep compatible executable ◮ Codept executable, fully compatible with ocamldep ◮ Core library, to be published on version 1.0 ◮ Too many options, a lighter executable planned

  49. Machine readable output ◮ JSON and sexp format available ◮ for signature and dependencies ◮ for the M2l AST

  50. { "version" : [0, 10, 3], "dependencies" : [{ "file" : "a.ml", "deps" : [["C"], ["B"], ["Atlas"]] }, { "file" : "atlas.ml" }, { "file" : "b.ml", "deps" : [["C" { "file" : "c.ml", "deps" : [["Atlas"]] }, { "file" : "d.ml", "deps" : [["Atlas"]] }, { "file" : "e.ml", "deps" : [["Atlas"]] }, { "file" : "f.ml", "deps" : [["Atlas"]] }], "local" : [{ "module" : ["A"], "ml" : "a.ml" }, { "module" : ["Atlas"], "ml" : "atlas.ml" }, { "module" : ["B"], "ml" : "b.ml" }, { "module" : ["C"], "ml" { "module" : ["D"], "ml" : "d.ml" }, { "module" : ["E"], "ml" { "module" : ["F"], "ml" : "f.ml" }] } Support incremental compilation

  51. Perspectives ◮ Library publication ◮ Lightweight executable ◮ Multi-zipper ◮ Dune integration Dune integration ◮ Not that straightforward: a full new layer of dependency computation ◮ But more opportunities for caching Past features from the future ◮ Full support for decoupling module names from filenames ◮ Full support for nested namespaces with -nested

  52. Thanks!

  53. Nearly an over-approximation (* a.ml *) module Sub = struct module SubSub = struct end (* b.ml *) end module Sub = struct end open B open Sub open SubSub

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend