Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion moon.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "moonbitlang/parser"

version = "0.3.14"
version = "0.3.15"

import {
"moonbitlang/x@0.4.39",
Expand Down
7 changes: 4 additions & 3 deletions untyped_cst/README.mbt.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ syntax tree that preserves tokens, comments, delimiters, separators, and source
spans. It is intended for tooling that needs source-faithful structure before
or alongside the existing typed syntax AST.

Use `parse_structure(source, name?)` for a MoonBit source file and
`parse_expression(source, name?)` for a standalone expression. Both return a
`ParseResult`.
Use `parse_structure(source, name?, enable_metavar?)` for a MoonBit source file
and `parse_expression(source, name?, enable_metavar?)` for a standalone
expression. Both return a `ParseResult`. Metavariable syntax is disabled by
default; pass `enable_metavar=true` to enable it.

- `parse_structure` returns a root whose kind is `Impls`.
- `parse_expression` returns a root whose kind is `Expression`.
Expand Down
30 changes: 25 additions & 5 deletions untyped_cst/api.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,47 @@ fn parse_with_state(
fn parse_source(
source : String,
name : String,
enable_metavar : Bool,
parse_root : (ParserState) -> CstNode,
) -> ParseResult {
let lex = @lexer.tokens_from_string(source, name~, comment=true)
let lex = @lexer.tokens_from_string(
source,
name~,
enable_metavar~,
comment=true,
)
let diagnostics = reports_from_lex_errors(lex.errors)
parse_with_state(lex.tokens, source, diagnostics, lex.docstrings, parse_root)
}

///|
/// Parses a MoonBit source file into a concrete syntax tree.
///
/// Metavariable syntax is disabled by default. Set `enable_metavar=true` to
/// enable it.
///
/// The returned root node has kind `Impls`. Its source spans use UTF-16
/// code-unit offsets suitable for slicing the original `source` string.
pub fn parse_structure(source : String, name? : String = "") -> ParseResult {
parse_source(source, name, parse_source_file)
pub fn parse_structure(
source : String,
name? : String = "",
enable_metavar? : Bool = false,
) -> ParseResult {
parse_source(source, name, enable_metavar, parse_source_file)
}

///|
/// Parses a MoonBit expression into a concrete syntax tree.
///
/// Metavariable syntax is disabled by default. Set `enable_metavar=true` to
/// enable it.
///
/// The returned root node has kind `Expression`. Its source spans use
/// UTF-16 code-unit offsets suitable for slicing the original `source` string.
pub fn parse_expression(source : String, name? : String = "") -> ParseResult {
parse_source(source, name, parse_expr_fragment)
pub fn parse_expression(
source : String,
name? : String = "",
enable_metavar? : Bool = false,
) -> ParseResult {
parse_source(source, name, enable_metavar, parse_expr_fragment)
}
43 changes: 43 additions & 0 deletions untyped_cst/api_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,49 @@ test "parse entry points expose distinct roots and propagate names" {
@test.assert_eq(expression.root().loc.end.fname, "expression.mbt")
}

///|
test "parse entry points gate metavariable syntax" {
let expression_source = "$(value:exp)"
@test.assert_eq(
@untyped_cst.parse_expression(expression_source)
.diagnostics_view()
.is_empty(),
false,
)
let expression = @untyped_cst.parse_expression(
expression_source,
enable_metavar=true,
)
@test.assert_eq(expression.diagnostics_view().is_empty(), true)
@test.assert_eq(
api_has_string_value(
expression.root(),
fn(kind) { kind is Syntax_Identifier },
expression_source,
),
true,
)

let structure_source = "let $(value:pat) = 1"
@test.assert_eq(
@untyped_cst.parse_structure(structure_source).diagnostics_view().is_empty(),
false,
)
let structure = @untyped_cst.parse_structure(
structure_source,
enable_metavar=true,
)
@test.assert_eq(structure.diagnostics_view().is_empty(), true)
@test.assert_eq(
api_has_string_value(
structure.root(),
fn(kind) { kind is Syntax_Identifier },
"$(value:pat)",
),
true,
)
}

///|
test "constant kinds and normalized payloads are parser semantics" {
let cases : Array[(String, String, String)] = [
Expand Down
4 changes: 2 additions & 2 deletions untyped_cst/pkg.generated.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
}

// Values
pub fn parse_expression(String, name? : String) -> ParseResult
pub fn parse_expression(String, name? : String, enable_metavar? : Bool) -> ParseResult

pub fn parse_structure(String, name? : String) -> ParseResult
pub fn parse_structure(String, name? : String, enable_metavar? : Bool) -> ParseResult

// Errors

Expand Down
Loading