packages feed

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

define ParseState {
  refines ParseContext<#x>

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

  consumeAll (parser,data) {
    ParseContext<#y> context <- parser.run(new(data))
    if (context.hasAnyError()) {
      return context.getValue()
    } elif (!context.atEof()) {
      return ErrorOr$$error("Parsing did not consume all of the data " + context.getPosition())
    } else {
      return context.getValue()
    }
  }

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

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

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

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

  setValue (value2) {
    if (hasBrokenInput()) {
      return convertError()
    } 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("[line: ")
        .append(line.formatted())
        .append(", char: ")
        .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, 1, value, error }
    } else {
      return ParseState<#x>{ data, index+1, line, char+1, value, error }
    }
  }

  @category new (String) -> (ParseState<any>)
  new (data) {
    return ParseState<any>{ data, 0, 1, 1, ErrorOr$$value<?>(Void$void()), empty }
  }

  @value getError () -> (Formatted)
  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())
    }
  }
}