cucumber-expressions

    Cucumber Expressions parser and matcher for MoonBit

    cucumber
    expressions
    bdd
    testing
    gherkin
    Download zip
    Author
    Version
    0.6.0
    License
    Apache-2.0
    Last updated
    yesterday
    Downloads
    1K

    Dependencies

    #moonrockz/cucumber-expressions

    A Cucumber Expressions parser and matcher for MoonBit. The simpler alternative to regular expressions used in BDD step definitions.

    #Installation

    moon add moonrockz/cucumber-expressions

    #Quick Start

    let expr = @cucumber-expressions.Expression::parse!("I have {int} cucumber(s) in my {word}")
    let m = expr.match_("I have 42 cucumbers in my basket").unwrap()
    // m.params[0].value => IntVal(42), m.params[0].raw => "42"
    // m.params[1].value => WordVal("basket"), m.params[1].raw => "basket"

    Each Param has value, type_, raw and group. group is the capture Group of the parameter, with start and end (UTF-16 offsets). match_ raises the error of a transformer. Expression::regexp() gives the compiled regex.

    #Built-in Parameter Types

    All 11 types from the Cucumber Expressions specification:

    ParameterDescriptionExample matchValue type
    {int}Integers, optionally negative42, -1IntVal(Int)
    {float}Decimal and scientific notation3.14, -1.5e10FloatVal(Double)
    {double}Same as float3.14, 1.5e10DoubleVal(Double)
    {long}64-bit integers9223372036854775807LongVal(Int64)
    {byte}Integers from -128 to 127127, -128ByteVal(Byte) (two's complement)
    {short}Integers from -32768 to 327678080ShortVal(Int)
    {bigdecimal}Arbitrary-precision decimals99.99BigDecimalVal(Decimal)
    {biginteger}Arbitrary-precision integers12345678901234567890BigIntegerVal(BigInt)
    {string}Single- or double-quoted strings"hello", 'hi'StringVal(String)
    {word}A single word (no whitespace)bananaWordVal(String)
    {}Anonymous — matches anythingwhatever you wantAnonymousVal(String)

    let expr = @cucumber-expressions.Expression::parse!("{word} costs {float} dollars")
    let m = expr.match_("coffee costs 4.50 dollars").unwrap()
    // m.params[0].value => WordVal("coffee"), m.params[0].raw => "coffee"
    // m.params[1].value => FloatVal(4.5), m.params[1].raw => "4.50"

    #Optional Text

    Parentheses mark text as optional. This is useful for plurals:

    let expr = @cucumber-expressions.Expression::parse!("I have {int} cucumber(s)")
    expr.match_("I have 1 cucumber") // matches
    expr.match_("I have 5 cucumbers") // matches

    #Alternation

    Use / to match one of several alternatives:

    let expr = @cucumber-expressions.Expression::parse!("I have a cat/dog")
    expr.match_("I have a cat") // matches
    expr.match_("I have a dog") // matches

    #Custom Parameter Types

    Register your own named parameter types with ParamTypeRegistry. An optional transformer converts matched text into a typed value. The transformer gets the values of the capture groups of the regexp, or the whole match when the regexp has no capture groups. Without a transformer, the value is StringVal of the first of these values.

    register raises ParameterTypeError when the name is already registered, when the name has one of {, }, (, ), \ or /, or when there are no regexps:

    let registry = @cucumber-expressions.ParamTypeRegistry::default()
    registry.register(
    "color",
    @cucumber-expressions.ParamType::Custom("color"),
    [@cucumber-expressions.RegexPattern("red|green|blue")],
    transformer=@cucumber-expressions.Transformer::new(fn(groups) {
    @cucumber-expressions.ParamValue::StringVal(groups[0].to_upper())
    }),
    )
    let expr = @cucumber-expressions.Expression::parse_with_registry!(
    "the {color} ball",
    registry,
    )
    let m = expr.match_("the red ball").unwrap()
    // m.params[0].value => StringVal("RED"), m.params[0].raw => "red"

    #Typed Parameter Types

    A typed parameter type gives values of your own type, with no casts. Registration returns a ParameterType[T] handle; use it to read the value. Registration also checks the number of capture groups: a transformer with n arguments needs n top-level capture groups (added over all regexps), and a transformer with 1 argument also accepts a regexp with no groups (it then gets the whole match).

    #define1 to define8

    let registry = @cucumber-expressions.ParamTypeRegistry::default()
    let color = registry.define1("color", [@cucumber-expressions.RegexPattern("red|green|blue")], Color::new)
    let coord = registry.define2("coord", [@cucumber-expressions.RegexPattern("(\\d+),(\\d+)")], (x, y) => {
    Coord::new(@string.parse_int(x), @string.parse_int(y))
    })
    let expr = @cucumber-expressions.Expression::parse_with_registry("a {color} ball at {coord}", registry)
    let m = expr.match_("a red ball at 3,4").unwrap()
    let c : Color = color.get(m.params[0]) // raises if params[0] is not a {color}
    let p : Coord = m.get(coord) // the only {coord} of the match
    let all : Array[Color] = m.get_all(color)

    #Captures: typed parts with zip and map

    Captures decodes each capture group with a typed part (string(), int(), long(), float(), double(), custom(f), optional(part)). zip joins parts into a flat tuple, and map makes one value. Register it with define_with:

    let seat = registry.define_with(
    "seat",
    [@cucumber-expressions.RegexPattern("(\\d+)-(\\w+)-(\\d+)")],
    @cucumber-expressions.Captures::int()
    .zip(@cucumber-expressions.Captures::string())
    .zip(@cucumber-expressions.Captures::int())
    .map((row, block, number) => Seat::new(row, block, number)),
    )

    A group that did not match raises GroupDidNotMatch, unless its part is wrapped in Captures::optional, which gives None.

    map returns a decoder that can be zipped again, so large types are built from named parts:

    let person = @cucumber-expressions.Captures::string().zip(@cucumber-expressions.Captures::string()).map((first, last) => Person::new(first, last))
    let customer = person.zip(address).zip(contact).map((p, a, c) => Customer::new(p, a, c))

    After 8 values, zip folds the 8 values into one tuple and continues, so there is no hard limit.

    #Traits: ParameterTypeDef and FromGroups1 to FromGroups8

    impl @cucumber-expressions.ParameterTypeDef for Color with name() { "color" }
    impl @cucumber-expressions.ParameterTypeDef for Color with regexps() {
    [@cucumber-expressions.RegexPattern("red|green|blue")]
    }
    impl @cucumber-expressions.FromGroups1 for Color with from_groups(name) { Color::new(name) }

    let color : @cucumber-expressions.ParameterType[Color] = registry.define_type1()

    use_for_snippets (default true) and prefer_for_regexp_match (default false) can be overridden in the ParameterTypeDef implementation.

    #Match Result

    Expression::match_ returns a Match?. A successful match contains an array of Param values in order. Each Param has:

    • value — typed ParamValue (pattern-matchable enum)
    • type_ — which ParamType matched
    • raw — original matched text as String

    let expr = @cucumber-expressions.Expression::parse!("{word} is {int}")
    match expr.match_("MoonBit is 1") {
    Some(m) => {
    let name = m.params[0] // { value: WordVal("MoonBit"), type_: Word, raw: "MoonBit" }
    let num = m.params[1] // { value: IntVal(1), type_: Int, raw: "1" }
    }
    None => println("no match")
    }

    #Regular Expressions

    RegularExpression matches a step with a regex. Each top-level capture group gives one parameter. The registry finds the type of a group from its regexp, so (\d+) gives {int}. A group with no registered type gives AnonymousVal, and an optional group that did not match gives NullVal.

    let expr = @cucumber-expressions.RegularExpression::new("^I have (\\d+) cukes? in my (.+)$")
    let m = expr.match_("I have 3 cukes in my belly").unwrap()
    // m.params[0].value => IntVal(3), m.params[1].value => AnonymousVal("belly")

    When more than one parameter type has the regexp of a group, match_ raises AmbiguousParameterTypeError. Give one of the types prefer_for_regexp_match=true in register to fix this. The built-in {int}, {double} and {} are preferential, so (\d+) gives {int} and a group with the float regexp gives {double}, the same as the Java implementation.

    ExpressionFactory makes a StepExpression from a string. A string that starts with ^ or ends with $, or that starts and ends with /, is a regular expression. All other strings are Cucumber Expressions.

    let factory = @cucumber-expressions.ExpressionFactory::new(registry)
    let expr = factory.create_expression("^I have (\\d+) cukes$") // Regular(...)
    let expr = factory.create_expression("I have {int} cukes") // Cucumber(...)

    #Snippet Generation

    CucumberExpressionGenerator makes Cucumber Expressions from step text, for example for the snippet of an undefined step. It uses only the parameter types with use_for_snippets=true (the default for custom types; for the built-in types, only {int}, {float} and {string}).

    let generator = @cucumber-expressions.CucumberExpressionGenerator::new(registry)
    let generated = generator.generate_expressions("I have 2 cucumbers and 1.5 tomato")
    // generated[0].source() => "I have {int} cucumbers and {float} tomato"
    // generated[0].parameter_names() => ["int", "float"]

    #Error Handling

    tokenize, parse_expression, compile_expression and Expression::parse raise ExpressionError, a suberror with these variants:

    VariantCause
    UnmatchedBraceMissing closing }
    UnmatchedParenMissing closing )
    CannotEscapeInvalid escape sequence
    UnexpectedEscapeEndBackslash at end of expression
    ValidationErrorStructural errors (empty alternation, nested optionals, etc.)
    UnknownParameterTypeUnregistered {name} in expression

    Each error has position() (the code point offset of the problem) and message(). One error has no column: when the compiled regex does not compile, the position is 0 and the message gives the regex error. The message uses the same format as the reference implementation, for example:

    This Cucumber Expression has a problem at column 3: (a(b)) ^-^ An optional may not contain an other optional. If you did not mean to use an optional type you can use '\(' to escape the '('. For more complicated expressions consider using a regular expression instead.

    try {
    let _ = @cucumber-expressions.Expression::parse!("{unknown}")
    } catch {
    @cucumber-expressions.ExpressionError::UnknownParameterType(name~, ..) =>
    println("Unknown parameter: " + name)
    }

    #License

    Apache-2.0

    FromGroups1

    pub(open) trait FromGroups1 {
    fn from_groups(String) -> Self raise
    }

    Make a value from 1 capture group value.

    FromGroups2

    pub(open) trait FromGroups2 {
    fn from_groups(String, String) -> Self raise
    }

    Make a value from 2 capture group values.

    FromGroups3

    pub(open) trait FromGroups3 {
    fn from_groups(String, String, String) -> Self raise
    }

    Make a value from 3 capture group values.

    FromGroups4

    pub(open) trait FromGroups4 {
    fn from_groups(String, String, String, String) -> Self raise
    }

    Make a value from 4 capture group values.

    FromGroups5

    pub(open) trait FromGroups5 {
    fn from_groups(String, String, String, String, String) -> Self raise
    }

    Make a value from 5 capture group values.

    FromGroups6

    pub(open) trait FromGroups6 {
    fn from_groups(String, String, String, String, String, String) -> Self raise
    }

    Make a value from 6 capture group values.

    FromGroups7

    pub(open) trait FromGroups7 {
    fn from_groups(String, String, String, String, String, String, String) -> Self raise
    }

    Make a value from 7 capture group values.

    FromGroups8

    pub(open) trait FromGroups8 {
    fn from_groups(String, String, String, String, String, String, String, String) -> Self raise
    }

    Make a value from 8 capture group values.

    ParameterTypeDef

    pub(open) trait ParameterTypeDef {
    fn name() -> String
    fn regexps() -> Array[RegexPattern]
    fn use_for_snippets() -> Bool = _
    fn prefer_for_regexp_match() -> Bool = _
    }

    A typed parameter type defined by the type itself. Implement it and one of FromGroups1 to FromGroups8, then register the type with define_type1 to define_type8.

    AmbiguousParameterTypeError

    pub suberror AmbiguousParameterTypeError {
    AmbiguousParameterType(regexp~ : String, expression_regexp~ : String, names~ : Array[String], generated~ : Array[String])
    } derive(
    Debug
    )

    A capture group of a regular expression matches more than one parameter type, and none of them is preferential.

    AmbiguousParameterTypeError::message

    The error message, in the same format as the reference implementation.

    AmbiguousParameterTypeError::output

    fn AmbiguousParameterTypeError::output(self : AmbiguousParameterTypeError, logger : &Logger) -> Unit

    AmbiguousParameterTypeError::to_repr

    #deprecated("`AmbiguousParameterTypeError::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn AmbiguousParameterTypeError::to_repr(AmbiguousParameterTypeError) ->
    Repr

    AmbiguousParameterTypeError::to_string

    ExpressionError

    pub suberror ExpressionError {
    UnmatchedBrace(position~ : Int, message~ : String)
    UnmatchedParen(position~ : Int, message~ : String)
    CannotEscape(position~ : Int, character~ : Char, message~ : String)
    UnexpectedEscapeEnd(position~ : Int, message~ : String)
    ValidationError(position~ : Int, message~ : String)
    UnknownParameterType(name~ : String, position~ : Int, message~ : String)
    } derive(
    Debug
    )

    Errors that can occur when a cucumber expression is parsed or compiled.

    position is the code point offset of the problem in the expression. message is the full message, in the same format as the reference implementation.

    ExpressionError::message

    fn ExpressionError::message(self : ExpressionError) -> String

    The full error message.

    ExpressionError::output

    fn ExpressionError::output(self : ExpressionError, logger : &Logger) -> Unit

    ExpressionError::position

    fn ExpressionError::position(self : ExpressionError) -> Int

    The code point offset of the problem in the expression.

    ExpressionError::to_repr

    #deprecated("`ExpressionError::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn ExpressionError::to_repr(ExpressionError) ->
    Repr

    ExpressionError::to_string

    fn ExpressionError::to_string(self : ExpressionError) -> String

    ParameterTypeError

    pub suberror ParameterTypeError {
    DuplicateParameterType(name~ : String)
    IllegalParameterName(name~ : String)
    NoRegexps(name~ : String)
    DuplicatePreferentialParameterType(regexp~ : String, first~ : String, second~ : String)
    WrongParameterType(expected~ : String, actual~ : String)
    MissingParameter(name~ : String)
    AmbiguousParameter(name~ : String, count~ : Int)
    GroupDidNotMatch(name~ : String, index~ : Int)
    ArityMismatch(name~ : String, expected~ : Int, groups~ : Int)
    InvalidRegexp(name~ : String, regexp~ : String)
    WrongGroupCount(name~ : String, expected~ : Int, actual~ : Int)
    } derive(
    Debug
    )

    Errors that can occur when a parameter type is registered.

    ParameterTypeError::message

    fn ParameterTypeError::message(self : ParameterTypeError) -> String

    The error message.

    ParameterTypeError::output

    fn ParameterTypeError::output(self : ParameterTypeError, logger : &Logger) -> Unit

    ParameterTypeError::to_repr

    #deprecated("`ParameterTypeError::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn ParameterTypeError::to_repr(ParameterTypeError) ->
    Repr

    ParameterTypeError::to_string

    fn ParameterTypeError::to_string(self : ParameterTypeError) -> String

    Captures

    pub enum Captures {
    }

    Makes the parts of a Captures decoder. Each part decodes one capture group. Join parts with zip and make a value with map:

    Captures::int().zip(Captures::string()).map((n, s) => Item::new(n, s))

    Captures::custom

    fn[T] Captures::custom(f : (String) -> T raise) -> Captures1[T]

    The capture group, converted by f.

    Captures::double

    fn Captures::double() -> Captures1[Double]

    The capture group as a Double.

    Captures::float

    fn Captures::float() -> Captures1[Double]

    The capture group as a Double.

    Captures::int

    fn Captures::int() -> Captures1[Int]

    The capture group as an Int.

    Captures::long

    fn Captures::long() -> Captures1[Int64]

    The capture group as an Int64.

    Captures::optional

    fn[T] Captures::optional(part : Captures1[T]) -> Captures1[T?]

    None when none of the groups of part matched. Otherwise part decodes as usual, so a group that did not match raises GroupDidNotMatch.

    Captures::string

    fn Captures::string() -> Captures1[String]

    The text of the capture group.

    Captures1

    pub struct Captures1[T] {
    // private fields
    }

    A decoder of capture group values into one value of type T.

    count is the number of capture groups it decodes. decode gets the values of those groups and the 1-based index of the first one.

    Captures1::map

    fn[A, T] Captures1::map(self : Captures1[A], f : (A) -> T raise) -> Captures1[T]

    Change the value with f. The result decodes the same capture groups.

    Captures1::zip

    fn[A, B] Captures1::zip(self : Captures1[A], next : Captures1[B]) -> Captures2[A, B]

    Add the next part. The result decodes both values.

    Captures2

    pub struct Captures2[A, B] {
    // private fields
    }

    A decoder of 2 values. Add a value with zip, or make one value with map.

    Captures2::map

    fn[A, B, T] Captures2::map(self : Captures2[A, B], f : (A, B) -> T raise) -> Captures1[T]

    Make one value from the 2 values with f. The result decodes the same capture groups, so it can be zipped into a bigger decoder.

    Captures2::zip

    fn[A, B, C] Captures2::zip(self : Captures2[A, B], next : Captures1[C]) -> Captures3[A, B, C]

    Add the next part. The result decodes 3 values.

    Captures3

    pub struct Captures3[A, B, C] {
    // private fields
    }

    A decoder of 3 values. Add a value with zip, or make one value with map.

    Captures3::map

    fn[A, B, C, T] Captures3::map(self : Captures3[A, B, C], f : (A, B, C) -> T raise) -> Captures1[T]

    Make one value from the 3 values with f. The result decodes the same capture groups, so it can be zipped into a bigger decoder.

    Captures3::zip

    fn[A, B, C, D] Captures3::zip(self : Captures3[A, B, C], next : Captures1[D]) -> Captures4[A, B, C, D]

    Add the next part. The result decodes 4 values.

    Captures4

    pub struct Captures4[A, B, C, D] {
    // private fields
    }

    A decoder of 4 values. Add a value with zip, or make one value with map.

    Captures4::map

    fn[A, B, C, D, T] Captures4::map(self : Captures4[A, B, C, D], f : (A, B, C, D) -> T raise) -> Captures1[T]

    Make one value from the 4 values with f. The result decodes the same capture groups, so it can be zipped into a bigger decoder.

    Captures4::zip

    fn[A, B, C, D, E] Captures4::zip(self : Captures4[A, B, C, D], next : Captures1[E]) -> Captures5[A, B, C, D, E]

    Add the next part. The result decodes 5 values.

    Captures5

    pub struct Captures5[A, B, C, D, E] {
    // private fields
    }

    A decoder of 5 values. Add a value with zip, or make one value with map.

    Captures5::map

    fn[A, B, C, D, E, T] Captures5::map(self : Captures5[A, B, C, D, E], f : (A, B, C, D, E) -> T raise) -> Captures1[T]

    Make one value from the 5 values with f. The result decodes the same capture groups, so it can be zipped into a bigger decoder.

    Captures5::zip

    fn[A, B, C, D, E, F] Captures5::zip(self : Captures5[A, B, C, D, E], next : Captures1[F]) -> Captures6[A, B, C, D, E, F]

    Add the next part. The result decodes 6 values.

    Captures6

    pub struct Captures6[A, B, C, D, E, F] {
    // private fields
    }

    A decoder of 6 values. Add a value with zip, or make one value with map.

    Captures6::map

    fn[A, B, C, D, E, F, T] Captures6::map(self : Captures6[A, B, C, D, E, F], f : (A, B, C, D, E, F) -> T raise) -> Captures1[T]

    Make one value from the 6 values with f. The result decodes the same capture groups, so it can be zipped into a bigger decoder.

    Captures6::zip

    fn[A, B, C, D, E, F, G] Captures6::zip(self : Captures6[A, B, C, D, E, F], next : Captures1[G]) -> Captures7[A, B, C, D, E, F, G]

    Add the next part. The result decodes 7 values.

    Captures7

    pub struct Captures7[A, B, C, D, E, F, G] {
    // private fields
    }

    A decoder of 7 values. Add a value with zip, or make one value with map.

    Captures7::map

    fn[A, B, C, D, E, F, G, T] Captures7::map(self : Captures7[A, B, C, D, E, F, G], f : (A, B, C, D, E, F, G) -> T raise) -> Captures1[T]

    Make one value from the 7 values with f. The result decodes the same capture groups, so it can be zipped into a bigger decoder.

    Captures7::zip

    fn[A, B, C, D, E, F, G, H] Captures7::zip(self : Captures7[A, B, C, D, E, F, G], next : Captures1[H]) -> Captures8[A, B, C, D, E, F, G, H]

    Add the next part. The result decodes 8 values.

    Captures8

    pub struct Captures8[A, B, C, D, E, F, G, H] {
    // private fields
    }

    A decoder of 8 values. Add a value with zip, or make one value with map.

    Captures8::map

    fn[A, B, C, D, E, F, G, H, T] Captures8::map(self : Captures8[A, B, C, D, E, F, G, H], f : (A, B, C, D, E, F, G, H) -> T raise) -> Captures1[T]

    Make one value from the 8 values with f. The result decodes the same capture groups, so it can be zipped into a bigger decoder.

    Captures8::zip

    fn[A, B, C, D, E, F, G, H, X] Captures8::zip(self : Captures8[A, B, C, D, E, F, G, H], next : Captures1[X]) -> Captures2[(A, B, C, D, E, F, G, H), X]

    Add the next part after 8 values. The 8 values fold into one tuple, so the result is a Captures2 of that tuple and the next value. Zipping can continue with no limit.

    CucumberExpressionGenerator

    pub(all) struct CucumberExpressionGenerator {
    // private fields
    }

    Makes Cucumber Expressions from step text, for example for the snippet of an undefined step. It uses the parameter types with use_for_snippets.

    CucumberExpressionGenerator::generate_expressions

    fn CucumberExpressionGenerator::generate_expressions(self : CucumberExpressionGenerator, text : String) -> Array[GeneratedExpression]

    Make the possible expressions for the text. The best expression is first.

    CucumberExpressionGenerator::new

    Expression

    pub(all) struct Expression {
    // private fields
    }

    A parsed and compiled cucumber expression, ready for matching.

    Expression::match_

    fn Expression::match_(self : Expression, text : String) -> Match? raise

    Match this expression against a text string.

    Returns None if the text does not match. Each transformer gets the values of the capture groups of its parameter, or the whole match of the parameter when its regexps have no capture groups. A group that did not match gives an empty string. An error from a transformer goes to the caller.

    Expression::parse

    fn Expression::parse(expression : String) -> Expression raise ExpressionError

    Parse a cucumber expression with the default parameter type registry.

    Expression::parse_with_registry

    fn Expression::parse_with_registry(expression : String, registry : ParamTypeRegistry) -> Expression raise ExpressionError

    Parse a cucumber expression with a custom parameter type registry.

    Expression::regexp

    fn Expression::regexp(self : Expression) -> String

    Get the regex that this expression compiles to.

    Expression::source

    fn Expression::source(self : Expression) -> String

    Get the original expression source string.

    ExpressionFactory

    pub(all) struct ExpressionFactory {
    // private fields
    }

    Makes a Cucumber Expression or a regular expression from a string, with the same rules as the reference Java implementation:

    • A string that starts with ^ or ends with $ is a regular expression.
    • A string that starts and ends with / is a regular expression without the slashes.
    • All other strings are Cucumber Expressions.

    ExpressionFactory::create_expression

    fn ExpressionFactory::create_expression(self : ExpressionFactory, expression : String) -> StepExpression raise ExpressionError

    Make an expression from a string.

    ExpressionFactory::new

    GeneratedExpression

    pub(all) struct GeneratedExpression {
    parameter_types : Array[ParamTypeEntry]
    // private fields
    }

    A Cucumber Expression made by CucumberExpressionGenerator.

    GeneratedExpression::parameter_infos

    The name, type and count of each parameter.

    GeneratedExpression::parameter_names

    fn GeneratedExpression::parameter_names(self : GeneratedExpression) -> Array[String]

    Parameter names for a generated function signature, for example ["int", "int2"].

    GeneratedExpression::source

    fn GeneratedExpression::source(self : GeneratedExpression) -> String

    The text of the generated expression.

    Group

    pub(all) struct Group {
    value : String?
    start : Int?
    end : Int?
    children : Array[Group]
    } derive(Eq,
    Debug
    )

    A capture group of a match, with the capture groups inside it.

    value, start and end are None when the group did not match. start and end are UTF-16 offsets into the matched text.

    Group::equal

    #deprecated("`Group::equal` is deprecated, use `Eq::equal` instead.")
    fn Group::equal(Group, Group) -> Bool

    Group::not_equal

    #deprecated("`Group::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Group::not_equal(x : Group, y : Group) -> Bool

    Group::to_repr

    #deprecated("`Group::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Group::to_repr(Group) ->
    Repr

    Group::values

    fn Group::values(self : Group) -> Array[String?]

    The values that a transformer gets: the values of the child groups, or the value of this group when it has no children.

    Match

    pub(all) struct Match {
    params : Array[Param]
    } derive(Eq,
    Debug
    )

    A successful match result with extracted parameters.

    Match::equal

    #deprecated("`Match::equal` is deprecated, use `Eq::equal` instead.")
    fn Match::equal(Match, Match) -> Bool

    Match::get

    fn[T] Match::get(self : Match, handle : ParameterType[T]) -> T raise ParameterTypeError

    The value of the only parameter of the match that came from handle. Raises MissingParameter when there is none, and AmbiguousParameter when there is more than one.

    Match::get_all

    fn[T] Match::get_all(self : Match, handle : ParameterType[T]) -> Array[T]

    The values of all parameters of the match that came from handle, in order.

    Match::not_equal

    #deprecated("`Match::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Match::not_equal(x : Match, y : Match) -> Bool

    Match::to_repr

    #deprecated("`Match::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Match::to_repr(Match) ->
    Repr

    Node

    pub(all) struct Node {
    type_ : NodeType
    nodes : Array[Node]
    token : String
    start : Int
    end : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A node in a cucumber expression AST.

    start and end are code point offsets into the expression. A TextNode has a token and no nodes. All other nodes have nodes and an empty token.

    Node::equal

    #deprecated("`Node::equal` is deprecated, use `Eq::equal` instead.")
    fn Node::equal(Node, Node) -> Bool

    Node::not_equal

    #deprecated("`Node::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Node::not_equal(x : Node, y : Node) -> Bool

    Node::text

    fn Node::text(self : Node) -> String

    The text of this node: the token of a text node, or the joined text of the child nodes.

    Node::to_json

    fn Node::to_json(Node) -> Json

    Node::to_repr

    #deprecated("`Node::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Node::to_repr(Node) ->
    Repr

    NodeType

    pub(all) enum NodeType {
    TextNode
    OptionalNode
    AlternationNode
    AlternativeNode
    ParameterNode
    ExpressionNode
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    The kind of a node in a cucumber expression AST.

    NodeType::equal

    #deprecated("`NodeType::equal` is deprecated, use `Eq::equal` instead.")
    fn NodeType::equal(NodeType, NodeType) -> Bool

    NodeType::not_equal

    #deprecated("`NodeType::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn NodeType::not_equal(x : NodeType, y : NodeType) -> Bool

    NodeType::to_json

    fn NodeType::to_json(NodeType) -> Json

    NodeType::to_repr

    #deprecated("`NodeType::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn NodeType::to_repr(NodeType) ->
    Repr

    Param

    pub(all) struct Param {
    value : ParamValue
    type_ : ParamType
    raw : String
    group : Group
    } derive(Eq,
    Debug
    )

    An extracted parameter value.

    raw is the matched text. For {string} it is the text between the quotes, before the escaped quotes are changed. group is the capture group of the parameter, with its position and the groups inside it.

    Param::equal

    #deprecated("`Param::equal` is deprecated, use `Eq::equal` instead.")
    fn Param::equal(Param, Param) -> Bool

    Param::not_equal

    #deprecated("`Param::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Param::not_equal(x : Param, y : Param) -> Bool

    Param::to_repr

    #deprecated("`Param::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Param::to_repr(Param) ->
    Repr

    ParamType

    pub(all) enum ParamType {
    Int
    Float
    String_
    Word
    Anonymous
    Double_
    Long
    Byte
    Short
    BigDecimal
    BigInteger
    Custom(String)
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Parameter types supported by cucumber expressions.

    ParamType::equal

    #deprecated("`ParamType::equal` is deprecated, use `Eq::equal` instead.")
    fn ParamType::equal(ParamType, ParamType) -> Bool

    ParamType::not_equal

    #deprecated("`ParamType::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn ParamType::not_equal(x : ParamType, y : ParamType) -> Bool

    ParamType::to_json

    fn ParamType::to_json(ParamType) -> Json

    ParamType::to_repr

    #deprecated("`ParamType::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn ParamType::to_repr(ParamType) ->
    Repr

    ParamTypeEntry

    pub(all) struct ParamTypeEntry {
    name : String
    type_ : ParamType
    patterns : Array[RegexPattern]
    transformer : Transformer
    use_for_snippets : Bool
    prefer_for_regexp_match : Bool
    } derive(
    Debug
    )

    A registered parameter type entry with name, type, regex patterns, and transformer.

    use_for_snippets is true when CucumberExpressionGenerator can use the type. prefer_for_regexp_match is true when a RegularExpression uses this type before other types with the same regexp.

    ParamTypeEntry::equal

    #deprecated("`ParamTypeEntry::equal` is deprecated, use `Eq::equal` instead.")
    fn ParamTypeEntry::equal(self : ParamTypeEntry, other : ParamTypeEntry) -> Bool

    ParamTypeEntry::not_equal

    #deprecated("`ParamTypeEntry::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn ParamTypeEntry::not_equal(x : ParamTypeEntry, y : ParamTypeEntry) -> Bool

    ParamTypeEntry::to_repr

    #deprecated("`ParamTypeEntry::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn ParamTypeEntry::to_repr(ParamTypeEntry) ->
    Repr

    ParamTypeRegistry

    pub(all) struct ParamTypeRegistry {
    // private fields
    }

    Registry mapping parameter type names to their regex patterns.

    ParamTypeRegistry::default

    Create a registry with the 11 built-in parameter types pre-registered.

    ParamTypeRegistry::define1

    fn[T] ParamTypeRegistry::define1(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], transformer : (String) -> T raise, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type whose transformer takes 1 capture group value. See define_with for the rules.

    ParamTypeRegistry::define2

    fn[T] ParamTypeRegistry::define2(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], transformer : (String, String) -> T raise, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type whose transformer takes 2 capture group values. See define_with for the rules.

    ParamTypeRegistry::define3

    fn[T] ParamTypeRegistry::define3(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], transformer : (String, String, String) -> T raise, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type whose transformer takes 3 capture group values. See define_with for the rules.

    ParamTypeRegistry::define4

    fn[T] ParamTypeRegistry::define4(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], transformer : (String, String, String, String) -> T raise, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type whose transformer takes 4 capture group values. See define_with for the rules.

    ParamTypeRegistry::define5

    fn[T] ParamTypeRegistry::define5(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], transformer : (String, String, String, String, String) -> T raise, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type whose transformer takes 5 capture group values. See define_with for the rules.

    ParamTypeRegistry::define6

    fn[T] ParamTypeRegistry::define6(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], transformer : (String, String, String, String, String, String) -> T raise, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type whose transformer takes 6 capture group values. See define_with for the rules.

    ParamTypeRegistry::define7

    fn[T] ParamTypeRegistry::define7(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], transformer : (String, String, String, String, String, String, String) -> T raise, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type whose transformer takes 7 capture group values. See define_with for the rules.

    ParamTypeRegistry::define8

    fn[T] ParamTypeRegistry::define8(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], transformer : (String, String, String, String, String, String, String, String) -> T raise, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type whose transformer takes 8 capture group values. See define_with for the rules.

    ParamTypeRegistry::define_type1

    Register the typed parameter type T, which takes 1 capture group value. Select T with a type annotation, for example let color : ParameterType[Color] = registry.define_type1().

    ParamTypeRegistry::define_type2

    Register the typed parameter type T, which takes 2 capture group values. Select T with a type annotation, for example let color : ParameterType[Color] = registry.define_type2().

    ParamTypeRegistry::define_type3

    Register the typed parameter type T, which takes 3 capture group values. Select T with a type annotation, for example let color : ParameterType[Color] = registry.define_type3().

    ParamTypeRegistry::define_type4

    Register the typed parameter type T, which takes 4 capture group values. Select T with a type annotation, for example let color : ParameterType[Color] = registry.define_type4().

    ParamTypeRegistry::define_type5

    Register the typed parameter type T, which takes 5 capture group values. Select T with a type annotation, for example let color : ParameterType[Color] = registry.define_type5().

    ParamTypeRegistry::define_type6

    Register the typed parameter type T, which takes 6 capture group values. Select T with a type annotation, for example let color : ParameterType[Color] = registry.define_type6().

    ParamTypeRegistry::define_type7

    Register the typed parameter type T, which takes 7 capture group values. Select T with a type annotation, for example let color : ParameterType[Color] = registry.define_type7().

    ParamTypeRegistry::define_type8

    Register the typed parameter type T, which takes 8 capture group values. Select T with a type annotation, for example let color : ParameterType[Color] = registry.define_type8().

    ParamTypeRegistry::define_with

    fn[T] ParamTypeRegistry::define_with(self : ParamTypeRegistry, name : String, regexps : Array[RegexPattern], captures : Captures1[T], use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> ParameterType[T] raise ParameterTypeError

    Register a typed parameter type that decodes its capture groups with captures, and return its handle.

    captures must decode as many values as the regexps have top-level capture groups, added over all regexps. A decoder of one value also accepts regexps with no groups; it then gets the whole match. Otherwise ArityMismatch is raised. The checks of register also apply, before the arity check.

    Groups are counted over all regexps. So with the regexps (a)b and c, a decoder of one value is accepted, but a match of c raises GroupDidNotMatch, because the group of the first regexp did not match. Wrap the part in Captures::optional, or give each regexp the same groups.

    ParamTypeRegistry::entries_view

    Read-only view of all registered parameter type entries.

    ParamTypeRegistry::get

    fn ParamTypeRegistry::get(self : ParamTypeRegistry, name : String) -> ParamTypeEntry?

    ParamTypeRegistry::lookup_by_regexp

    fn ParamTypeRegistry::lookup_by_regexp(self : ParamTypeRegistry, regexp : String, expression_regexp : String, text : String) -> ParamTypeEntry? raise AmbiguousParameterTypeError

    Find the parameter type for a capture group of a regular expression.

    regexp is the source of the capture group. expression_regexp and text are used for the error message. Returns None when no type has the regexp. Raises an error when more than one type has the regexp and none of them is preferential.

    ParamTypeRegistry::new

    ParamTypeRegistry::register

    fn ParamTypeRegistry::register(self : ParamTypeRegistry, name : String, type_ : ParamType, patterns : Array[RegexPattern], transformer? : Transformer, use_for_snippets? : Bool, prefer_for_regexp_match? : Bool) -> Unit raise ParameterTypeError

    Register a parameter type.

    Raises an error when the name is already registered, when the name has one of the characters {, }, (, ), \ or /, when there are no regexps, or when a preferential type already has one of the regexps.

    use_for_snippets (default true) lets CucumberExpressionGenerator use the type. prefer_for_regexp_match (default false) makes a RegularExpression use this type before other types with the same regexp.

    Without a transformer, the value is StringVal of the first value: the first capture group, or the whole match when there are no groups.

    ParamValue

    pub(all) enum ParamValue {
    IntVal(Int)
    FloatVal(Double)
    DoubleVal(Double)
    LongVal(Int64)
    ByteVal(Byte)
    ShortVal(Int)
    StringVal(String)
    WordVal(String)
    AnonymousVal(String)
    BigDecimalVal(
    Decimal
    )
    BigIntegerVal(
    BigInt
    )
    NullVal
    TypedVal(TypedValue)
    }

    A typed value produced by a transformer function. Built-in types have concrete variants for compile-time pattern matching.
    impl Eq for ParamValue
    impl Show for ParamValue

    ParamValue::equal

    #deprecated("`ParamValue::equal` is deprecated, use `Eq::equal` instead.")
    fn ParamValue::equal(self : ParamValue, other : ParamValue) -> Bool

    ParamValue::not_equal

    #deprecated("`ParamValue::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn ParamValue::not_equal(x : ParamValue, y : ParamValue) -> Bool

    ParamValue::output

    fn ParamValue::output(self : ParamValue, logger : &Logger) -> Unit

    ParamValue::to_repr

    #deprecated("`ParamValue::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn ParamValue::to_repr(self : ParamValue) ->
    Repr

    ParamValue::to_string

    fn ParamValue::to_string(self : ParamValue) -> String

    ParameterInfo

    pub(all) struct ParameterInfo {
    type_ : ParamType
    name : String
    count : Int
    } derive(Eq,
    Debug
    )

    The name and type of a parameter of a generated expression. count is the number of times that the name is used up to and including this parameter.

    ParameterInfo::equal

    #deprecated("`ParameterInfo::equal` is deprecated, use `Eq::equal` instead.")
    fn ParameterInfo::equal(ParameterInfo, ParameterInfo) -> Bool

    ParameterInfo::not_equal

    #deprecated("`ParameterInfo::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn ParameterInfo::not_equal(x : ParameterInfo, y : ParameterInfo) -> Bool

    ParameterInfo::to_repr

    #deprecated("`ParameterInfo::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn ParameterInfo::to_repr(ParameterInfo) ->
    Repr

    ParameterType

    pub struct ParameterType[T] {
    // private fields
    }

    A typed parameter type. define1 to define8, define_with and define_type1 to define_type8 return it. Use it to read the value of a parameter of this type, with its type.

    ParameterType::get

    fn[T] ParameterType::get(self : ParameterType[T], param : Param) -> T raise ParameterTypeError

    The value of param. Raises WrongParameterType when param did not come from this handle, including a type with the same name in another registry.

    ParameterType::name

    fn[T] ParameterType::name(self : ParameterType[T]) -> String

    The name of the parameter type, as used in expressions.

    RegexPattern

    pub(all) struct RegexPattern {
    // private fields
    } derive(Eq,
    Debug
    )

    A regex pattern used for matching parameter types in cucumber expressions.

    RegexPattern::RegexPattern

    fn RegexPattern::RegexPattern(value : String) -> RegexPattern

    RegexPattern::equal

    #deprecated("`RegexPattern::equal` is deprecated, use `Eq::equal` instead.")
    fn RegexPattern::equal(RegexPattern, RegexPattern) -> Bool

    RegexPattern::not_equal

    #deprecated("`RegexPattern::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn RegexPattern::not_equal(x : RegexPattern, y : RegexPattern) -> Bool

    RegexPattern::to_repr

    #deprecated("`RegexPattern::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn RegexPattern::to_repr(RegexPattern) ->
    Repr

    RegexPattern::to_string

    fn RegexPattern::to_string(self : RegexPattern) -> String

    RegularExpression

    pub(all) struct RegularExpression {
    // private fields
    }

    A step pattern written as a regular expression, for example ^I have (\d+) cukes$.

    Each top-level capture group gives one parameter. The registry finds the parameter type from the source of the group, for example \d+ gives {int}. A group with no registered type gives an AnonymousVal, and a group that did not match gives NullVal.

    RegularExpression::match_

    fn RegularExpression::match_(self : RegularExpression, text : String) -> Match? raise

    Match the regular expression against a text.

    Returns None if the text does not match. Raises an AmbiguousParameterTypeError when a group matches more than one parameter type and none of them is preferential, and the error of a transformer.

    RegularExpression::new

    fn RegularExpression::new(regexp : String, registry? : ParamTypeRegistry) -> RegularExpression raise ExpressionError

    Compile a regular expression. Raises an error when the regex is not valid.

    RegularExpression::regexp

    fn RegularExpression::regexp(self : RegularExpression) -> String

    The regex. This is the same as source.

    RegularExpression::source

    fn RegularExpression::source(self : RegularExpression) -> String

    The source of the regular expression.

    StepExpression

    pub(all) enum StepExpression {
    Cucumber(Expression)
    Regular(RegularExpression)
    }

    A step pattern: a Cucumber Expression or a regular expression.

    StepExpression::match_

    fn StepExpression::match_(self : StepExpression, text : String) -> Match? raise

    Match the expression against a text.

    StepExpression::source

    fn StepExpression::source(self : StepExpression) -> String

    The source of the expression.

    Token

    pub(all) struct Token {
    type_ : TokenType
    text : String
    start : Int
    end : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A token of a cucumber expression.

    start and end are code point offsets into the expression. For a text token, the range includes the escape characters, but text does not.

    Token::equal

    #deprecated("`Token::equal` is deprecated, use `Eq::equal` instead.")
    fn Token::equal(Token, Token) -> Bool

    Token::not_equal

    #deprecated("`Token::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn Token::not_equal(x : Token, y : Token) -> Bool

    Token::to_json

    fn Token::to_json(Token) -> Json

    Token::to_repr

    #deprecated("`Token::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Token::to_repr(Token) ->
    Repr

    TokenType

    pub(all) enum TokenType {
    StartOfLine
    EndOfLine
    WhiteSpace
    BeginOptional
    EndOptional
    BeginParameter
    EndParameter
    Alternation
    Text
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    The kind of a token in a cucumber expression.

    TokenType::equal

    #deprecated("`TokenType::equal` is deprecated, use `Eq::equal` instead.")
    fn TokenType::equal(TokenType, TokenType) -> Bool

    TokenType::not_equal

    #deprecated("`TokenType::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn TokenType::not_equal(x : TokenType, y : TokenType) -> Bool

    TokenType::to_json

    fn TokenType::to_json(TokenType) -> Json

    TokenType::to_repr

    #deprecated("`TokenType::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn TokenType::to_repr(TokenType) ->
    Repr

    Transformer

    pub(all) struct Transformer {
    // private fields
    }

    A transformer function that converts captured regex group strings into a typed ParamValue. Receives an array of captured group strings (arity matches capture groups in the regex).

    Transformer::call

    fn Transformer::call(self : Transformer, groups : Array[String]) -> ParamValue raise

    Transformer::new

    fn Transformer::new(f : (Array[String]) -> ParamValue raise) -> Transformer

    Transformer::to_repr

    #deprecated("`Transformer::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn Transformer::to_repr(_self : Transformer) ->
    Repr

    TypedValue

    pub struct TypedValue {
    // private fields
    }

    The value of a typed parameter type.

    The value is kept in a closure. The closure writes the value into the slot of the ParameterType[T] handle that made it, so reading the value back needs no casts and works on every target. token is the token of that handle, so another handle does not run put.

    TypedValue::type_name

    fn TypedValue::type_name(self : TypedValue) -> String

    The name of the parameter type that made the value.

    compile_expression

    fn compile_expression(expression : String, registry? : ParamTypeRegistry) -> String raise ExpressionError

    Parse a cucumber expression and compile it to a regex pattern string.

    parse_expression

    fn parse_expression(expression : String) -> Node raise ExpressionError

    Parse a cucumber expression into an AST.

    This checks only the syntax. compile_expression and Expression::parse also check the structure, for example that an optional is not empty.

    tokenize

    fn tokenize(expression : String) -> Array[Token] raise ExpressionError

    Tokenize a cucumber expression.

    The result starts with a StartOfLine token and ends with an EndOfLine token. Adjacent text and adjacent white space join into one token. Only a space is white space.

    version

    fn version() -> String

    Cucumber Expressions for MoonBit.

    A parser and matcher for Cucumber Expressions, the simpler alternative to regular expressions used in BDD step definitions.