Sign in

    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. fuel (default @dialect.DEFAULT_FUEL, 1200) bounds the nesting the parser accepts before it refuses with KR-PARSE-010.

    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. fuel (default @dialect.DEFAULT_FUEL, 1200) bounds the nesting the parser accepts before it refuses with KR-PARSE-010; more fuel needs more stack.

    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