Module Melange_compiler_libs.Location

Source code locations (ranges of positions), used in parsetree.

Warning: this module is unstable and part of compiler-libs.

type t = Warnings.loc = {
  1. loc_start: Stdlib.Lexing.position,
  2. loc_end: Stdlib.Lexing.position,
  3. loc_ghost: bool,
};

Note on the use of Lexing.position in this module. If pos_fname = "", then use !input_name instead. If pos_lnum = -1, then pos_bol = 0. Use pos_cnum and re-parse the file to get the line and character numbers. Else all fields are correct.

let none: t;

An arbitrary value of type t; describes an empty ghost range.

let is_none: t => bool;

True for Location.none, false any other location

let in_file: string => t;

Return an empty ghost range located in a given file.

let init: Stdlib.Lexing.lexbuf => string => unit;

Set the file name and line number of the lexbuf to be the start of the named file.

let curr: Stdlib.Lexing.lexbuf => t;

Get the location of the current token from the lexbuf.

let symbol_rloc: unit => t;
let symbol_gloc: unit => t;
let rhs_loc: int => t;

rhs_loc n returns the location of the symbol at position n, starting at 1, in the current parser rule.

let rhs_interval: int => int => t;
let set_input_name: string => unit;
let get_pos_info: Stdlib.Lexing.position => (string, int, int);

file, line, char

type loc('a) = Melange_wrapper.Location.loc('a) = {
  1. txt: 'a,
  2. loc: t,
};
let mknoloc: 'a => loc('a);
let mkloc: 'a => t => loc('a);

Input info

let input_name: Stdlib.ref(string);
let input_lexbuf: Stdlib.ref(option(Stdlib.Lexing.lexbuf));
let input_phrase_buffer: Stdlib.ref(option(Stdlib.Buffer.t));

Toplevel-specific functions

let echo_eof: unit => unit;
let separate_new_message: Stdlib.Format.formatter => unit;
let reset: unit => unit;

Rewriting path

let rewrite_absolute_path: string => string;

rewrite_absolute_path path rewrites path to honor the BUILD_PATH_PREFIX_MAP variable if it is set. It does not check whether path is absolute or not. The result is as follows:

  • If BUILD_PATH_PREFIX_MAP is not set, just return path.
  • otherwise, rewrite using the mapping (and if there are no matching prefixes that will just return path).

See the BUILD_PATH_PREFIX_MAP spec

let rewrite_find_first_existing: string => option(string);

rewrite_find_first_existing path uses a BUILD_PATH_PREFIX_MAP mapping and tries to find a source in mapping that maps to a result that exists in the file system. There are the following return values:

  • None, means either

    • BUILD_PATH_PREFIX_MAP is not set and path does not exists, or
    • no source prefixes of path in the mapping were found,
  • Some target, means target exists and either

    • BUILD_PATH_PREFIX_MAP is not set and target = path, or
    • target is the first file (in priority order) that path mapped to that exists in the file system.
  • Not_found raised, means some source prefixes in the map were found that matched path, but none of them existed in the file system. The caller should catch this and issue an appropriate error message.

See the BUILD_PATH_PREFIX_MAP spec

let rewrite_find_all_existing_dirs: string => list(string);

rewrite_find_all_existing_dirs dir accumulates a list of existing directories, dirs, that are the result of mapping a potentially abstract directory, dir, over all the mapping pairs in the BUILD_PATH_PREFIX_MAP environment variable, if any. The list dirs will be in priority order (head as highest priority).

The possible results are:

  • [], means either

    • BUILD_PATH_PREFIX_MAP is not set and dir is not an existing directory, or
    • if set, then there were no matching prefixes of dir.
  • Some dirs, means dirs are the directories found. Either

    • BUILD_PATH_PREFIX_MAP is not set and dirs = [dir], or
    • it was set and dirs are the mapped existing directories.
  • Not_found raised, means some source prefixes in the map were found that matched dir, but none of mapping results were existing directories (possibly due to misconfiguration). The caller should catch this and issue an appropriate error message.

See the BUILD_PATH_PREFIX_MAP spec

let absolute_path: string => string;

absolute_path path first makes an absolute path, s from path, prepending the current working directory if path was relative. Then s is rewritten using rewrite_absolute_path. Finally the result is normalized by eliminating instances of '.' or '..'.

Printing locations

let show_filename: string => string;

In -absname mode, return the absolute path for this filename. Otherwise, returns the filename unchanged.

let print_filename: Stdlib.Format.formatter => string => unit;
let print_loc: Stdlib.Format.formatter => t => unit;
let print_locs: Stdlib.Format.formatter => list(t) => unit;

Toplevel-specific location highlighting

let highlight_terminfo: Stdlib.Lexing.lexbuf => Stdlib.Format.formatter => list(t) => unit;

Reporting errors and warnings

The type of reports and report printers

type msg = loc((Stdlib.Format.formatter => unit));
let msg: ?loc:t => Stdlib.format4('a, Stdlib.Format.formatter, unit, msg) => 'a;
type report_kind = Melange_wrapper.Location.report_kind =
  1. | Report_error
  2. | Report_warning(string)
  3. | Report_warning_as_error(string)
  4. | Report_alert(string)
  5. | Report_alert_as_error(string)
;
type report = Melange_wrapper.Location.report = {
  1. kind: report_kind,
  2. main: msg,
  3. sub: list(msg),
};
type report_printer = Melange_wrapper.Location.report_printer = {
  1. pp: report_printer => Stdlib.Format.formatter => report => unit,
  2. pp_report_kind: report_printer => report => Stdlib.Format.formatter => report_kind => unit,
  3. pp_main_loc: report_printer => report => Stdlib.Format.formatter => t => unit,
  4. pp_main_txt: report_printer => report => Stdlib.Format.formatter => (Stdlib.Format.formatter => unit) => unit,
  5. pp_submsgs: report_printer => report => Stdlib.Format.formatter => list(msg) => unit,
  6. pp_submsg: report_printer => report => Stdlib.Format.formatter => msg => unit,
  7. pp_submsg_loc: report_printer => report => Stdlib.Format.formatter => t => unit,
  8. pp_submsg_txt: report_printer => report => Stdlib.Format.formatter => (Stdlib.Format.formatter => unit) => unit,
};

A printer for reports, defined using open-recursion. The goal is to make it easy to define new printers by re-using code from existing ones.

Report printers used in the compiler

let batch_mode_printer: report_printer;
let terminfo_toplevel_printer: Stdlib.Lexing.lexbuf => report_printer;
let best_toplevel_printer: unit => report_printer;

Detects the terminal capabilities and selects an adequate printer

Printing a report

let print_report: Stdlib.Format.formatter => report => unit;

Display an error or warning report.

let report_printer: Stdlib.ref((unit => report_printer));

Hook for redefining the printer of reports.

The hook is a unit -> report_printer and not simply a report_printer: this is useful so that it can detect the type of the output (a file, a terminal, ...) and select a printer accordingly.

let default_report_printer: unit => report_printer;

Original report printer for use in hooks.

Reporting warnings

Converting a Warnings.t into a report

let report_warning: t => Warnings.t => option(report);

report_warning loc w produces a report for the given warning w, or None if the warning is not to be printed.

let warning_reporter: Stdlib.ref((t => Warnings.t => option(report)));

Hook for intercepting warnings.

let default_warning_reporter: t => Warnings.t => option(report);

Original warning reporter for use in hooks.

Printing warnings

let formatter_for_warnings: Stdlib.ref(Stdlib.Format.formatter);
let print_warning: t => Stdlib.Format.formatter => Warnings.t => unit;

Prints a warning. This is simply the composition of report_warning and print_report.

let prerr_warning: t => Warnings.t => unit;

Same as print_warning, but uses !formatter_for_warnings as output formatter.

Reporting alerts

Converting an Alert.t into a report

let report_alert: t => Warnings.alert => option(report);

report_alert loc w produces a report for the given alert w, or None if the alert is not to be printed.

let alert_reporter: Stdlib.ref((t => Warnings.alert => option(report)));

Hook for intercepting alerts.

let default_alert_reporter: t => Warnings.alert => option(report);

Original alert reporter for use in hooks.

Printing alerts

let print_alert: t => Stdlib.Format.formatter => Warnings.alert => unit;

Prints an alert. This is simply the composition of report_alert and print_report.

let prerr_alert: t => Warnings.alert => unit;

Same as print_alert, but uses !formatter_for_warnings as output formatter.

let deprecated: ?def:t => ?use:t => t => string => unit;

Prints a deprecation alert.

let alert: ?def:t => ?use:t => kind:string => t => string => unit;

Prints an arbitrary alert.

let auto_include_alert: string => unit;

Prints an alert that -I +lib has been automatically added to the load path

let deprecated_script_alert: string => unit;

deprecated_script_alert command prints an alert that command foo has been deprecated in favour of command ./foo

Reporting errors

type error = report;

An error is a report which report_kind must be Report_error.

let error: ?loc:t => ?sub:list(msg) => string => error;
let errorf: ?loc:t => ?sub:list(msg) => Stdlib.format4('a, Stdlib.Format.formatter, unit, error) => 'a;
let error_of_printer: ?loc:t => ?sub:list(msg) => (Stdlib.Format.formatter => 'a => unit) => 'a => error;
let error_of_printer_file: (Stdlib.Format.formatter => 'a => unit) => 'a => error;

Automatically reporting errors for raised exceptions

let register_error_of_exn: (exn => option(error)) => unit;

Each compiler module which defines a custom type of exception which can surface as a user-visible error should register a "printer" for this exception using register_error_of_exn. The result of the printer is an error value containing a location, a message, and optionally sub-messages (each of them being located as well).

let error_of_exn: exn => option([ `Ok(error) | `Already_displayed ]);
exception Error(error);

Raising Error e signals an error e; the exception will be caught and the error will be printed.

exception Already_displayed_error;

Raising Already_displayed_error signals an error which has already been printed. The exception will be caught, but nothing will be printed

let raise_errorf: ?loc:t => ?sub:list(msg) => Stdlib.format4('a, Stdlib.Format.formatter, unit, 'b) => 'a;
let report_exception: Stdlib.Format.formatter => exn => unit;

Reraise the exception if it is unknown.