moonrockz/krueger/parser does not have a README file

    AttributeGroup

    pub(all) struct AttributeGroup {
    target : AttributeTarget
    attributes : ArrayView[DocAttribute]
    } 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.

    AttributeTarget

    pub(all) enum AttributeTarget {
    Module
    Declaration(name~ : String, range~ :
    Range
    )
    } 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.

    DocAttribute

    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.

    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")
    ),
    )
    }

    ParseResult

    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.

    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")
    }

    encode_attributes

    fn encode_attributes(groups : Array[AttributeGroup]) -> Json

    Attribute groups as JSON, for tools.

    Each group is {"target": ..., "attributes": [...]}. The target is "module" or {"declaration": name, "range": [...]}. An attribute is {"name": ..., "arguments": [...], "range": [...]}, with names and arguments as elm-syntax nodes; @docs is {"docs": [...], "range":[...]}. Ranges are elm-syntax ranges: [startRow, startColumn, endRow,endColumn]. Int arguments are written as elm-syntax writes them (see encode_attributes_with).

    test {
    let text =
    #|module Main exposing (x)
    #|
    #|{-| Answers.
    #|
    #|@since 2
    #|-}
    #|x = 42
    #|
    let source = @scanner.SourceText::new(text)
    let result = @parser.parse_module(source, @scanner.DefaultScanner::new())
    // The first doc comment documents the module.
    let json = @parser.encode_attributes(result.attributes)
    inspect(
    json.stringify(),
    content=(
    #|[{"target":"module","attributes":[{"name":{"range":[5,2,5,7],"value":"since"},"arguments":[{"range":[5,8,5,9],"value":{"type":"integer","integer":2}}],"range":[5,1,5,9]}]}]
    ),
    )
    }

    encode_attributes_with

    fn encode_attributes_with(groups : Array[AttributeGroup], exact_ints~ : Bool) -> Json

    Attribute groups as JSON. With exact_ints, Int arguments are written with their exact digits (see @ast.encode_file_with). Without it, an Int above 2^53 is written as the nearest Double, as elm-syntax does.

    test {
    let text =
    #|module Main exposing (x)
    #|
    #|{-| Ids.
    #|
    #|@id 9007199254740993
    #|-}
    #|x = 1
    #|
    let source = @scanner.SourceText::new(text)
    let groups = @parser.parse_module(source, @scanner.DefaultScanner::new()).attributes
    let exact = @parser.encode_attributes_with(groups, exact_ints=true).stringify()
    inspect(exact.contains("9007199254740993"), content="true")
    let nearest = @parser.encode_attributes(groups).stringify()
    inspect(nearest.contains("9007199254740993"), content="false")
    }

    parse_module

    Tokenize source with scanner and parse it in dialect (default: Elm 0.19.1). The caller builds scanner for the same dialect.

    When the source does not scan, the result has no AST and no CST, and its diagnostics are the scanner's. The root package's parse_module builds the default scanner for you.

    test {
    let dialect = @dialect.Dialect::elm_syntax_7_3_9()
    let scanner = @scanner.DefaultScanner::new(dialect~)
    let ok = @parser.parse_module(
    @scanner.SourceText::new("module Main exposing (..)\n\nx = 1\n"),
    scanner,
    dialect~,
    )
    inspect(ok.diagnostics.length(), content="0")
    let bad = @parser.parse_module(
    @scanner.SourceText::new("module Main exposing (..)\n\n{- open\n"),
    scanner,
    dialect~,
    )
    inspect(bad.ast is None && bad.cst is None, content="true")
    inspect(bad.diagnostics[0].code, content="KR-SCAN-001")
    }

    parse_tokens

    Parse a token stream into an elm-syntax AST, a CST and diagnostics, following stil4m/elm-syntax 7.3.9.

    Get the tokens from a scanner built for the same dialect (default: Elm 0.19.1). The dialect's rules decide what is an error, and its operator table decides how operators group.

    test {
    let dialect = @dialect.Dialect::elm_0_19_1()
    let source = @scanner.SourceText::new(
    "module Main exposing (..)\n\nx =\n 1 + 2 * 3\n",
    )
    guard @scanner.DefaultScanner::new(dialect~).tokenize(source) is Ok(tokens) else {
    fail("scan error")
    }
    let result = @parser.parse_tokens(tokens, dialect~)
    inspect(result.diagnostics.length(), content="0")
    guard result.ast is Some(file) else { fail("no AST") }
    guard file.declarations[0].value is FunctionDeclaration(f) else {
    fail("not a function")
    }
    // `*` binds tighter than `+`, so `+` is the root.
    guard f.declaration.value.expression.value is OperatorApplication(op, _, _, _) else {
    fail("not an operator application")
    }
    inspect(op, content="+")
    }

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io