package MlFront_Core

  1. Overview
  2. Docs

Module MlFront_Core.PackageIdSource

Package identifiers.

Package identifiers are what developers type into ".ml" source code to refer to other fully-qualified units of code in MlFront that adhere to MlFront naming conventions. For example, unlike conventional OCaml a developer accesses the Int module through the Tr1Stdlib_V414Base.Int package identifier. And unlike conventional OCaml, MlFront makes it easy to open Tr1Stdlib_V414Base once in a library (inside "open__.ml") to save typing.

SIDE BAR: Developers can also type in conventional OCaml module names that are built into the MlFront runtime libraries (ex. "Cmdliner"). However, in future versions of MlFront every module will have a package identifier.

In contrast to package identifiers, a ModuleId identifies the module file which a developer can place source code (sometimes called a compilation unit).

MlFront packages are very similar to packages in Java:

  • A LibraryId.t is-a package id. See LibraryId.t for its naming conventions.
  • A package id is-a parent to zero or more sub package ids. That is, the package ids form a hierarchy.

Venn Diagram

Special modules cannot be referenced in code (ex. "open__.ml"); special module ids are not package ids. Library package modules (ex. "DkHello_Std.ml") are automatically generated by MlFront and cannot be written by a developer; library package ids are not module ids.

Unit ids are modules that can appear in the filesystem, whether or not a developer wrote the module or MlFront generated the module. As such, all modules ids and all package ids are unit ids.

In the Venn diagram below, the intersection of the MODULE ID and the PACKAGE ID are standard module ids.

  ┌──────────────| UNIT ID |───────────────┐
  │                                        │
  |                                        │
  |  ┌──────| MODULE ID |───────────┐      |
  |  │                              │      |
  |  │  DkEx_Std/open__.ml          │      |
  |  │     library_id: DkEx_Std     │      |
  |  │     state: Special LibOpen   │      |
  |  │                              │      |
  |  │  ┌───────────────────────────┼──┐   |
  |  │  │                           │  │   |
  |  │  │  DkEx_Std/One.ml          │  │   |
  |  |  │     library_id: DkEx_Std  |  │   |
  |  │  |     state: Standard       │  |   |
  |  |  │     namespace: [One]      |  │   |
  |  │  │                           │  │   |
  |  │  │  DkEx_Std/Sub/Two.ml      │  │   |
  |  |  │     library_id: DkEx_Std  |  │   |
  |  │  |     state: Standard       │  |   |
  |  |  │     namespace: [Sub,Two]  |  │   |
  |  │  │                           │  │   |
  |  └──┼───────────────────────────┘  │   |
  |     │                              │   |
  |     │    DkEx_Std.ml               │   |
  |     │       library_id: DkEx_Std   │   |
  |     │       namespace: []          │   |
  |     │                              │   |
  |     └─────| PACKAGE ID |───────────┘   |
  |                                        |
  └────────────────────────────────────────┘

Rules:

  • Use unit ids as inputs to the codept solver
  • Use module ids when scanning files ("compilation units") on disk
  • Use package ids when maintaining dependencies between source code

Fixed Length Representation

There is a compressed "fixed length" representation of a package identifier.

Originally the feature was intended to help on Windows. Long paths often break OCaml on Windows, but more importantly the MlFront standards (https://diskuv.com/dksdk/coder/2024-intro-scripting/) give a module path limit of 240 characters to support FAT32 paths.

Clearly if the user is constrained by a module path limit, the build system paths must also be constrained. For this reason each package identifier had a fixed-length representation that can be used in build system paths.

The fixed length representation is also in the design for versioned modules, with each version of a module having a different fixed length representation.

Sourcetype t = private {
  1. full_name : string;
  2. fixlen_name : string;
  3. library_id : LibraryId.t;
  4. namespace : string list;
}
Sourceval pp : Format.formatter -> t -> unit
Sourceval compare : t -> t -> int
Sourceval hash : t -> int
Sourceval create : library_id:LibraryId.t -> namespace:string list -> t

create ~library_id ~namespace creates a package from a library id library_id and the namespace namespace.

The namespace is everything after the library id but before the last name. For example, the module DkTest_A.B.C.D has the namespace "B.C".

The namespace may be empty which is equivalent to of_library_id.

Sourceval create_child : t -> string -> t

create_child package_id name creates a child package of the package id package_id.

Sourceval of_library_id : LibraryId.t -> t

of_library_id library_id creates the package corresponding to the library id library_id.

Sourceval library_id : t -> LibraryId.t
Sourceval full_name : t -> string
Sourceval fixlen_name : t -> string
Sourceval show_double_underscore : t -> string

show_underscore package_id returns a string with the library followed by a double underscore and then the namespace seperated by double underscores.

Sourceval pp_dot : Format.formatter -> t -> unit

pp_dot ppf package_id prints on the pretty printer ppf a string with the library followed by a dot and then the namespace seperated by dots.

Sourceval pp_fixlen_name : Format.formatter -> t -> unit
Sourceval json : t -> [> `String of string ]

json package_id returns the canonical JSON representation of the package id package_id.

The representation is compatible with Ezjsonm.

Sourceval namespace_tail : t -> string option

namespace_tail package_id is the last term of the package namespace. If the package namespace is empty (ie. a library id), then None is returned.

Sourceval namespace : t -> string list

namespace package_id are the terms of the package namespace. If the package id is a library id then the empty list is returned.

Sourceval parent : t -> t option

parent t is the parent package of the package t.

Example: "DkHello_Std.A.B" returns Some "DkHello_Std.A".

Example: "DkHello_Std.A" returns Some "DkHello_Std".

Example: "DkHello_Std" returns None.

Sourceval ancestors : t -> t list

ancestors are the parent package and the parent of the parent package, and so on, until the library package is reached.

The closest ancestors are returned first.

Example: "DkHello_Std.A.B" returns "DkHello_Std.A"; "DkHello_Std"

Sourceval is_strict_subpackage : parent:t -> child:t -> bool

is_strict_subpackage ~parent ~child is true if and only if child is a strict subpackage of parent.

Sourceval parse : ?allow_reserved:unit -> string -> t option

parse ~allow_reserved name will convert the dot-qualified name name to a package if it is a valid MlFront package name. Otherwise None.

The library "ZzZz_Zz" is reserved for internal dk and MlFront use. Any package belonging to that library will return None, unless the ~allow_reserved:() flag is used.

Sourceval parse_exn : ?allow_reserved:unit -> string -> t

parse_exn ~allow_reserved package creates the package identifier for the dot-qualified package named package.

Raises Invalid_argument when the package is not a valid MlFront package name.

The library "ZzZz_Zz" is reserved for internal dk and MlFront use. Any package belonging to that library will raise Invalid_argument, unless the ~allow_reserved:() flag is used.

Sourcetype abspath_parse_success = {
  1. parsed_package : t;
  2. parsed_extra_you_dir : string;
  3. parsed_you_abs_path : string;
}

abspath_parse_success is the result of parsing an absolute path into a package identifier, an extra you directory, and a you absolute path.

Sourcetype abspath_parse_error =
  1. | Tail_is_root_volume
    (*

    Tail_is_root_volume is an error that occurs when the absolute path is a root volume. Examples of root volumes are "/", "C:\\", "\\\\Server2\\", "\\\\.\\C:\\" and "\\\\?\\C:\\".

    *)
  2. | Tail_is_not_namespace_term of {
    1. capitalized_base : string;
    }
    (*

    Tail_is_not_namespace_term is an error that occurs when the capitalization of the last component of the absolute path (available in capitalized_base) is not a valid MlFront namespace term. For example, when the last component is "Editor~saved.ml".

    *)
  3. | Not_a_module of {
    1. basename : string;
    }
    (*

    Not_a_module { basename } is an error that occurs when the last component of the absolute path is not a valid MlFront module name.

    *)
  4. | No_library
    (*

    No_library is an error that occurs when the absolute path or one of its ancestor directories is not a valid MlFront library.

    *)
  5. | Invalid_path of {
    1. reason : string;
    }
Sourceval parse_path : ?allow_reserved:unit -> string -> (abspath_parse_success, abspath_parse_error) result

parse_path ~allow_reserved path parses the path path into a package identifier.

The path may be a Unix path, a traditional DOS path, a UNC path or a DOS device path.

The segments of the path path are consulted until an ancestor of path is a LibraryId.t; the real file system is not consulted. It is recommended by not required that the path be an absolute path. Alternatively, you may use a relative path as long as one of its segments is a LibraryId.t.

The parsing of path is pure and OS-agnostic: the parsing does not consider whether the host operating system is Windows or Unix.

The last segment of the path must be a valid MlFront namespace term. The parent segments of the last component must also be valid MlFront namespace terms until the ancestor segment whose name is a LibraryId.t is reached.

The path extension is ignored. For example, the paths "/path/to/DkHello_Std/A/B/C/" and "/path/to/DkHello_Std/A/B/C.ml" and "/path/to/DkHello_Std/A/B/C.values.json" will all be parsed as the package "DkHello_Std.A.B.C", whether or not any of those files or directories exist.

If the package is reserved (ie. belongs to "ZzZz_Zz") then None is returned unless the ~allow_reserved:() flag is used.

Casting

Sourceval cast_as_unit_id : t -> [> `PackageId of t ]

cast_as_unit_id package_id is the package package_id upcast to a UnitId.t.

Sourceval downcast_as_library_id : t -> LibraryId.t option

downcast_as_library_id package_id tries to convert the package identifier package_id to a library id.

If the package identifier has a non-empty namespace the downcasting will fail (ie. return None).