packages feed

zeolite-lang-0.20.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 StringParser{ match }
  }
}

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 SequenceOfParser{ matches, min, max }
  }
}

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 CharParser{ match }
  }
}

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 #self{ value }
  }
}

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 #self{ parser }
  }
}

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 #self{ parser1, parser2 }
  }
}

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 #self{ parser1, parser2 }
  }
}

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 #self{ parser1, parser2 }
  }
}

define Parse {
  error (message) {
    return ErrorParser.create(message)
  }

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

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

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

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

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