packages feed

zeolite-lang-0.24.0.0: example/parser/parse-text.0rx

define StringParser {
  refines Parser<String>

  @value String match

  run (contextOld) {
    if (contextOld.hasAnyError()) {
      return contextOld.convertError()
    }
    String message <- "Failed to match \"" + match + "\" at " + contextOld.getPosition()
    ParseContext<any> context <- contextOld
    traverse (Counter.zeroIndexed(match.size()) -> Int index) {
      $ReadOnly[index]$
      if (context.atEof() || context.current() != match.readAt(index)) {
        if (index > 0) {
          // Partial match => set error context.
          return context.setBrokenInput(message)
        } else {
          return context.setValue(ErrorOr:error(message))
        }
      }
      context <- context.advance()
    }
    return context.setValue(ErrorOr:value(match))
  }

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

define SequenceOfParser {
  refines Parser<String>

  @value String matches
  @value Int    min
  @value Int    max

  run (contextOld) {
    if (contextOld.hasAnyError()) {
      return contextOld.convertError()
    }
    String message <- "Failed to match [" + matches + "]{" +
                      min.formatted() + "," + max.formatted() + "} at " +
                      contextOld.getPosition()
    ParseContext<any> context <- contextOld
    [Append<Formatted> & Build<String>] builder <- String.builder()

    optional Order<Int> counter <- defer
    if (max == 0) {
      counter <- Counter.unlimited()
    } else {
      counter <- Counter.zeroIndexed(max)
    }

    Int count <- 0
    traverse (counter -> count) {
      $Hidden[count, counter]$
      if (context.atEof()) {
        break
      }
      Bool found <- false
      traverse (Counter.zeroIndexed(matches.size()) -> Int index) {
        $ReadOnly[context, index]$
        if (context.current() == matches.readAt(index)) {
          \ builder.append(matches.readAt(index))
          found <- true
          break
        }
      }
      if (!found) {
        break
      }
      context <- context.advance()
    }
    if (count >= min) {
      return context.setValue(ErrorOr:value(builder.build()))
    } elif (count > 0) {
      // Partial match => set error context.
      return context.setBrokenInput(message)
    } else {
      return context.setValue(ErrorOr:error(message))
    }
  }

  create (matches, min, max) {
    return delegate -> #self
  }
}

define CharParser {
  refines Parser<Char>

  @value Char match

  run (contextOld) {
    if (contextOld.hasAnyError()) {
      return contextOld.convertError()
    }
    if (contextOld.atEof() || contextOld.current() != match) {
      String message <- "Failed to match '" + match.formatted() + "' at " + contextOld.getPosition()
      return contextOld.setValue(ErrorOr:error(message))
    } else {
      return contextOld.advance().setValue(ErrorOr:value(match))
    }
  }

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

concrete ConstParser<#x> {
  #x immutable

  @type create (#x) -> (Parser<#x>)
}

define ConstParser {
  refines Parser<#x>

  @value #x value

  run (contextOld) {
    return contextOld.setValue(ErrorOr:value(value))
  }

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

concrete ErrorParser {
  @type create (Formatted) -> (Parser<all>)
}

define ErrorParser {
  refines Parser<all>

  @value String message

  run (contextOld) {
    return contextOld.setValue(ErrorOr:error(message))
  }

  create (message) {
    return ErrorParser{ message.formatted() }
  }
}

concrete TryParser<#x> {
  @type create (Parser<#x>) -> (Parser<#x>)
}

define TryParser {
  refines Parser<#x>

  @value Parser<#x> parser

  run (contextOld) {
    if (contextOld.hasAnyError()) {
      return contextOld.convertError()
    }
    ParseContext<#x> context <- contextOld.run<#x>(parser)
    if (context.hasAnyError()) {
      return contextOld.setValue(context.getValue().convertError())
    } else {
      return context.toState()
    }
  }

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

concrete OrParser<#x> {
  @type create (Parser<#x>, Parser<#x>) -> (Parser<#x>)
}

define OrParser {
  refines Parser<#x>

  @value Parser<#x> parser1
  @value Parser<#x> parser2

  run (contextOld) {
    if (contextOld.hasAnyError()) {
      return contextOld.convertError()
    }
    ParseContext<#x> context <- contextOld.run<#x>(parser1)
    if (context.hasAnyError() && !context.hasBrokenInput()) {
      return contextOld.run<#x>(parser2).toState()
    } else {
      return context.toState()
    }
  }

  create (parser1, parser2) {
    return delegate -> #self
  }
}

concrete LeftParser<#x> {

  @type create (Parser<#x>, Parser<any>) -> (Parser<#x>)
}

define LeftParser {
  refines Parser<#x>

  @value Parser<#x>  parser1
  @value Parser<any> parser2

  run (contextOld) {
    if (contextOld.hasAnyError()) {
      return contextOld.convertError()
    }
    ParseContext<#x> context <- contextOld.run<#x>(parser1)
    if (context.hasAnyError()) {
      return context.toState()
    } else {
      ParseContext<any> context2 <- context.run(parser2)
      if (context2.hasAnyError()) {
        return context2.convertError()
      } else {
        return context2.setValue(context.getValue())
      }
    }
  }

  create (parser1, parser2) {
    return delegate -> #self
  }
}

concrete RightParser<#x> {
  @type create (Parser<any>, Parser<#x>) -> (Parser<#x>)
}

define RightParser {
  refines Parser<#x>

  @value Parser<any> parser1
  @value Parser<#x>  parser2

  run (contextOld) {
    if (contextOld.hasAnyError()) {
      return contextOld.convertError()
    }
    ParseContext<any> context <- contextOld.run(parser1)
    if (context.hasAnyError()) {
      return context.convertError()
    } else {
      return context.run<#x>(parser2).toState()
    }
  }

  create (parser1, parser2) {
    return delegate -> #self
  }
}

define Parse {
  error (message) {
    return delegate -> `ErrorParser.create`
  }

  const (value) {
    return delegate -> `ConstParser<#x>.create`
  }

  try (parser) {
    return delegate -> `TryParser<#x>.create`
  }

  or (parser1, parser2) {
    return delegate -> `OrParser<#x>.create`
  }

  left (parser1, parser2) {
    return delegate -> `LeftParser<#x>.create`
  }

  right (parser1, parser2) {
    return delegate -> `RightParser<#x>.create`
  }
}