///|
/// Result of parsing one Elm module.
///
/// The parser does not stop at the first error. A declaration that does not
/// parse is left out of `ast` and `cst`, and a diagnostic reports it. Check
/// `diagnostics` for an entry with severity `Error` before you use the AST
/// as a full copy of the source.
///
/// ```mbt check
/// test {
/// let source = @scanner.SourceText::new(
/// "module Main exposing (x)\n\n{-| The answer. -}\nx = 42\n",
/// )
/// let result = @parser.parse_module(source, @scanner.DefaultScanner::new())
/// inspect(result.diagnostics.length(), content="0")
/// guard result.ast is Some(file) else { fail("no AST") }
/// inspect(file.declarations.length(), content="1")
/// guard result.cst is Some(cst) else { fail("no CST") }
/// inspect(cst.declarations.length(), content="1")
/// inspect(result.attributes.length(), content="0")
/// }
/// ```
pub(all) struct ParseResult {
/// The elm-syntax 7.3.9 AST. It is `None` when the module header is
/// missing or malformed (`KR-PARSE-001`, `KR-PARSE-006`) or when the
/// source does not scan.
ast : @ast.File?
/// The concrete syntax tree: every token, with its trivia, and every
/// declaration that parses. It is `None` only when the source does not
/// scan; without a valid module header its `header` is `None`.
cst : @cst.ModuleCst?
/// Scanner and parser problems, in source order. Each has a code
/// (`KR-SCAN-*`, `KR-PARSE-*`, `KR-ATTR-*`), a severity, a message, a span,
/// the `elm make` title and a long report.
diagnostics : Array[@scanner.Diagnostic]
/// Attributes from doc comments (see `DocAttribute`), in source order. It
/// is empty when the dialect turns attributes off.
attributes : Array[AttributeGroup]
} derive(Eq, Debug)
///|
/// What a group of doc-comment attributes belongs to: the module (its
/// documentation comment) or one top-level declaration, by name and range.
pub(all) enum AttributeTarget {
Module
Declaration(name~ : String, range~ : @ast.Range)
} derive(Eq, Debug)
///|
/// One attribute line in a doc comment: `@name value...`, or the built-in
/// `@docs a, b` list.
///
/// `Attribute` holds the name and the values as elm-syntax expressions.
/// Values are Elm data: literals, lists, records, tuples, names and
/// constructor applications. `range` covers the attribute in the file. A
/// malformed attribute is warning `KR-ATTR-001` and is not in the list.
///
/// ```mbt check
/// test {
/// let text =
/// #|module Main exposing (price)
/// #|
/// #|{-| Prices.
/// #|
/// #|@docs price
/// #|-}
/// #|
/// #|{-| A price.
/// #|
/// #|@unit "EUR"
/// #|-}
/// #|price : Float
/// #|price =
/// #| 9.5
/// #|
/// let source = @scanner.SourceText::new(text)
/// let result = @parser.parse_module(source, @scanner.DefaultScanner::new())
/// inspect(result.diagnostics.length(), content="0")
/// // The first doc comment documents the module.
/// debug_inspect(result.attributes[0].target, content="Module")
/// guard result.attributes[0].attributes[0] is Docs(names~, ..) else {
/// fail("not @docs")
/// }
/// inspect(names[0].value, content="price")
/// // A later doc comment documents the declaration after it.
/// let group = result.attributes[1]
/// guard group.target is Declaration(name~, ..) else {
/// fail("not a declaration")
/// }
/// inspect(name, content="price")
/// guard group.attributes[0] is Attribute(name~, arguments~, ..) else {
/// fail("not an attribute")
/// }
/// inspect(name.value, content="unit")
/// debug_inspect(
/// arguments[0].value,
/// content=(
/// #|Literal("EUR")
/// ),
/// )
/// }
/// ```
pub(all) enum DocAttribute {
Attribute(
name~ : @ast.Node[String],
arguments~ : ArrayView[@ast.Node[@ast.Expression]],
range~ : @ast.Range
)
Docs(names~ : ArrayView[@ast.Node[String]], range~ : @ast.Range)
} derive(Eq, Debug)
///|
/// The attributes of the module or of one declaration, in source order. Only
/// a target with at least one attribute has a group.
pub(all) struct AttributeGroup {
target : AttributeTarget
attributes : ArrayView[DocAttribute]
} derive(Eq, Debug)