packages feed

zeolite-lang-0.6.0.0: example/parser/parser.0rx

define ParseState {
  // This internal inheritance takes advantage of function merging.
  //
  // Notice that several functions (e.g., run, hasAnyError) appear to be
  // declared separately in ParseState and ParseContext in parser.0rp. Since the
  // function types are compatible, the compiler automatically merges them. This
  // allows ParseState to expose a subset of ParseContext without needing a
  // superfluous interface that both categories refine.
  refines ParseContext<#x>

  @value String             data
  @value Int                index
  @value Int                line
  @value Int                char
  @value ErrorOr<#x>        value
  @value optional Formatted error

  new (data) {
    return ParseState<any>{ data, 0, 0, 0, ErrorOr$$value<Void>(Void$void()), empty }
  }

  run (parser) {
    return parser.run(self)
  }

  runAndGet (parser) {
    ParseState<#y> context <- parser.run(self)
    return context, context.getValue()
  }

  convertError () {
    return ParseState<#y>{ data, index, line, char, ErrorOr$$error(getError()), error }
  }

  getValue () {
    if (present(error)) {
      return ErrorOr$$error(require(error))
    } else {
      return value
    }
  }

  setValue (value2) {
    if (hasBrokenInput()) {
      return convertError<#y>()
    } else {
      return ParseState<#y>{ data, index, line, char, value2, error }
    }
  }

  setBrokenInput (message) {
    return ParseState<all>{ data, index, line, char, ErrorOr$$error(message), message }
  }

  toState () {
    return self
  }

  getPosition () {
    return String$builder()
        .append("(")
        .append(line.formatted())
        .append(",")
        .append(char.formatted())
        .append(")")
        .build()
  }

  atEof () {
    return index >= data.readSize()
  }

  hasAnyError () {
    return present(error) || value.isError()
  }

  hasBrokenInput () {
    return present(error)
  }

  current () {
    \ sanityCheck()
    return data.readPosition(index)
  }

  advance () {
    \ sanityCheck()
    if (data.readPosition(index) == '\n') {
      return ParseState<#x>{ data, index+1, line+1, 0, value, error }
    } else {
      return ParseState<#x>{ data, index+1, line, char+1, value, error }
    }
  }

  getError () {
    if (present(error)) {
      return require(error)
    } else {
      return value.getError()
    }
  }

  @value sanityCheck () -> ()
  sanityCheck () {
    if (hasBrokenInput()) {
      \ LazyStream<Formatted>$new()
          .append("Error at ")
          .append(getPosition())
          .append(": ")
          .append(getError())
          .writeTo(SimpleOutput$error())
    }
    if (atEof()) {
      \ LazyStream<Formatted>$new()
          .append("Reached end of input at ")
          .append(getPosition())
          .writeTo(SimpleOutput$error())
    }
  }
}