packages feed

zeolite-lang-0.24.0.0: example/parser/test-data.0rx

$TestsOnly$

define TestData {
  @value String name
  @value String description
  @value Bool   boolean

  create (name, description, boolean) {
    return TestData{ name, description, boolean }
  }

  name () {
    return name
  }

  description () {
    return description
  }

  boolean () {
    return boolean
  }

  // From TestCompare<TestData>.
  testCompare (actual, report) {
    \ MultiChecker.new(report)
        .tryCheck(
            title: "name",
            actual.name(),
            CheckValue:equals(name))
        .tryCheck(
            title: "description",
            actual.description(),
            CheckValue:equals(description))
        .tryCheck(
            title: "boolean",
            actual.boolean(),
            CheckValue:equals(boolean))
  }
}

define TestDataParser {
  // Mark @category members as read-only, to avoid accidental assignment.
  $ReadOnlyExcept[]$

  // Mark @category members as hidden, since they should not be used directly.
  $Hidden[whitespace,
          sentenceChars,
          sentence,
          quote,
          quotedSentence,
          token,
          acronym,
          aardvark]$

  refines Parser<TestData>

  @category Parser<any> whitespace <- SequenceOfParser.create(" \n\t", min: 1, max: 0) `Parse.or` Parse.error("Expected whitespace")

  @category String sentenceChars <- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                                    "abcdefghijklmnopqrstuvwxyz" +
                                    "., !?-"
  @category Parser<String> sentence <- SequenceOfParser.create(sentenceChars, min: 0, max: 0)
  @category Parser<any>    quote    <- CharParser.create('"')

  @category Parser<String> quotedSentence  <- quote `Parse.right` sentence `Parse.left` quote
  @category Parser<String> token           <- SequenceOfParser.create("ABCDEFGHIJKLMNOPQRSTUVWXYZ_", min: 1, max: 0)
  @category Parser<String> sentenceOrToken <- quotedSentence `Parse.or` token `Parse.left` whitespace

  @category Parser<Bool> acronym           <- StringParser.create("acronym")  `Parse.right` Parse.const(true)
  @category Parser<Bool> aardvark          <- StringParser.create("aardvark") `Parse.right` Parse.const(false)
  @category Parser<Bool> acronymOrAardvark <- Parse.try(acronym) `Parse.or` aardvark `Parse.left` whitespace

  @category Parser<any> fileStart      <- StringParser.create("file_start")   `Parse.left` whitespace
  @category Parser<any> fileEnd        <- StringParser.create("file_end")     `Parse.left` whitespace
  @category Parser<any> nameTag        <- StringParser.create("name:")        `Parse.left` whitespace
  @category Parser<any> descriptionTag <- StringParser.create("description:") `Parse.left` whitespace
  @category Parser<any> aWordTag       <- StringParser.create("a_word:")      `Parse.left` whitespace

  run (contextOld) {
    ParseContext<any> context <- contextOld
    context                              <- context.run(fileStart)
    context                              <- context.run(nameTag)
    context, ErrorOr<String> name        <- context.runAndGet(sentenceOrToken)
    context                              <- context.run(descriptionTag)
    context, ErrorOr<String> description <- context.runAndGet(sentenceOrToken)
    context                              <- context.run(aWordTag)
    context, ErrorOr<Bool> boolean       <- context.runAndGet(acronymOrAardvark)
    context                              <- context.run(fileEnd)

    if (context.hasAnyError()) {
      return context.convertError()
    } else {
      return context.setValue(
        // Since TestData.create specifies labels, we _must_ use them here.
        ErrorOr:value(TestData.create(
            name:        name.getValue(),
            description: description.getValue(),
            boolean:     boolean.getValue())))
    }
  }

  create ()  {
    return delegate -> #self
  }
}