package ppxlib_jane

  1. Overview
  2. Docs

We expose the types within the specific Ast_builder.S modules because those modules are designed to be opened.

type mode =
  1. | Local
    (*

    local_ ty

    *)

The modes that can go on function arguments or return types

type arrow_argument = {
  1. arg_label : Ppxlib_ast.Asttypes.arg_label;
  2. arg_mode : mode option;
  3. arg_type : Ppxlib_ast.Parsetree.core_type;
}

Function arguments; a value of this type represents:

  • arg_mode arg_type -> ... when arg_label is Nolabel,
  • l:arg_mode arg_type -> ... when arg_label is Labelled, and
  • ?l:arg_mode arg_type -> ... when arg_label is Optional.
type arrow_result = {
  1. result_mode : mode option;
  2. result_type : Ppxlib_ast.Parsetree.core_type;
}

Function return types; a value of this type represents ... -> result_mode result_type.

type modality =
  1. | Global
    (*

    C of (..., global_ ty, ...) or { ...; global_ l : ty; ... }.

    *)

The modalities that can go on constructor fields

type function_param_desc = Jane_syntax.N_ary_functions.function_param_desc =
  1. | Pparam_val of Ppxlib_ast.Asttypes.arg_label * Ppxlib_ast.Parsetree.expression option * Ppxlib_ast.Parsetree.pattern
    (*

    In Pparam_val (lbl, def, pat):

    • lbl is the parameter label
    • def is the default argument for an optional parameter
    • pat is the pattern that is matched against the argument. See comment on Parsetree.expression_desc.Pexp_fun for more detail.
    *)

This type corresponds to Parsetree.function_param added in #12236; see the comment below introducing function arity.

type function_param = Jane_syntax.N_ary_functions.function_param = {
  1. pparam_desc : function_param_desc;
  2. pparam_loc : Astlib.Location.t;
}

Construct an arrow type with the provided argument and result, including the types, modes, and argument label (if any).

Construct a multi-argument arrow type with the provided arguments and result.

  • raises [Invalid_argument]

    if the input list is empty.

As tarrow, but will return the result if the input list is empty rather than erroring; this means the result type cannot have a mode annotation.

Splits a possibly-mode-annotated function argument or result into a pair of its mode and the unannotated type. If the resulting mode is None, then the type is returned unchanged.

Construct a Pcstr_tuple, a representation for the contents of a tupled variant constructor, that attaches the provided modalities to each field.

Construct a Pcstr_record, a representation for the contents of a variant constructor with an inlined record, that attaches the provided modalities to each label.

  • raises [Invalid_argument]

    if the input list is empty.

Construct a Ptype_record, a representation of a record type, that attaches the provided modalities to each label.

  • raises [Invalid_argument]

    if the input list is empty.

Splits a possibly-modality-annotated field of a tupled variant constructor into a pair of its modality and the unannotated field. If the resulting mode is None, then the field is returned unchanged.

Splits a possibly-modality-annotated label declaration into a pair of its modality and the unannotated label declaration. If the resulting modality is None, then the label declaration is returned unchanged.

Many comments below make reference to the Jane Street compiler's treatment of function arity. These comments refer to a parsetree change made to upstream OCaml in https://github.com/ocaml/ocaml/pull/12236, but that Jane Street has mirrored internally already.

The treatment of arity can be summarized as follows:

  • In a previous version of OCaml, a function's runtime arity was inferred at a late stage of the compiler, after typechecking, where it fuses together nested lambdas.
  • In the new version of OCaml (both upstream OCaml after #12236 and the internal Jane Street compiler), a function's runtime arity is purely a syntactic notion: it's the number of parameters in a fun x1 ... xn -> body construct, with some special allowances for function cases.

Why is arity important? In native code, application sites of a function to n syntactic arguments will trigger a fast path (where arguments are passed in registers) only if the function's runtime arity is n.

As a result, ppxes must take more care than before to generate functions of the correct arity. Now, a nested function like fun x -> fun y -> e has arity 1 (returning still another function of arity 1) instead of arity 2. All bindings below that construct functions are documented as to the arity of the returned function.

Some examples of arity:

  • 2-ary function: fun x y -> e
  • 1-ary function returning 1-ary function: fun x -> fun y -> e
  • 3-ary function: fun x y -> function P1 -> e1 | P2 -> e2
  • 2-ary function returning 1-ary function: fun x y -> (function P1 -> e1 | P2 -> e2)
  • 2-ary function returning 1-ary function: fun x -> function P1 -> function P2 -> e

Notably, unparenthesized function has a special meaning when used as a direct body of fun: the function becomes part of the arity of the outer fun. The same does not apply for multiple nested functions, even if they each have a single case; the nested functions are treated as unary. (See the last example.)

Create a function with unlabeled parameters and an expression body. Like Ppxlib.Ast_builder.eapply, but for constructing functions.

coalesce_fun_arity is relevant for the Jane Street compiler. By default, coalesce_fun_arity is true.

Suppose there is a call eabstract pats body ~coalesce_fun_arity

  • If colaesce_fun_arity is true, the arity of the returned function is the same as the arity of: add_fun_params (List.map params ~f:(Fun.param Nolabel)) body
  • If coalesce_fun_arity is false, then the arity of the returned function is the length of pats.

In other words, coalesce_fun_arity = true allows you to build up the arity of an already-constructed function rather than necessarily creating a new function.

unary_function cases is function <cases>. When used with the Jane Street compiler, the function's runtime arity is 1, so the fast path for function application happens only when application sites of the resulting function receive 1 argument. To create a function with multiple argument that pattern-matches on the last one, use add_param or add_params to add more parameters. Alternatively, use pexp_function to provide all parameters at once.

The attributes of the resulting expression will be the attrs argument together with any attributes added by the Jane Street compiler.

fun_param lbl pat is Pparam_val (lbl, None, pat). This gives a more self-documenting way of constructing the usual case: value parameters without optional argument defaults.

Say an expression is a "function" if it is a Pexp_fun or a Pexp_function. All functions have parameters and arity.

Suppose add_param lbl def pat e ==> e'. Then, letting param = Pparam_val (lbl, def, pat),

  • If e is a function with arity n, then e' is a function with arity n+1. param is added at the outermost layer. For example, if e = fun <params> -> <body>, then e' = fun <param :: params> -> body. The attributes on the resulting expression will be the attrs argument together with any attributes already present on e.
  • If e is not a function, then e' is a function with arity 1, namely: fun <param> -> <e>. The attributes of the resulting expression will be the attrs argument together with any attributes added by the Jane Street compiler.

add_params params e is List.fold_right params ~init:e ~f:add_param. Note the fold_right: if e is fun <params'> -> <body>, then add_params params e is fun <params @ params'> -> <body>.

This operation is a no-op, except as interpreted by the Jane Street compiler. If e is a function with arity n with an expression body that itself is a function with arity m, then coalesce_fun_arity e is a function of arity n + m.

You should usually call coalesce_fun_arity on metaquot fun expressions whose body may be a function, e.g.:

coalesce_fun_arity [%expr fun x y -> [%e possibly_function]]

OCaml

Innovation. Community. Security.