packages feed

zeolite-lang-0.7.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
    scoped {
      Int index <- 0
    } in while (index < match.readSize()) {
      if (context.atEof() || context.current() != match.readPosition(index)) {
        if (index > 0) {
          // Partial match => set error context.
          return context.setBrokenInput(message)
        } else {
          return context.setValue<?>(ErrorOr$$error(message))
        }
      }
    } update {
      index <- index+1
      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
    Builder<String> builder <- String$builder()
    Int count <- 0
    while (!context.atEof() && (max == 0 || count < max)) {
      Bool found <- false
      scoped {
        Int index <- 0
      } in while (index < matches.readSize()) {
        if (context.current() == matches.readPosition(index)) {
          \ builder.append(matches.readPosition(index).formatted())
          found <- true
          break
        }
      } update {
        index <- index+1
      }
      if (!found) {
        break
      }
    } update {
      count <- count+1
      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> {
  @type create (#x) -> (Parser<#x>)
}

define ConstParser {
  refines Parser<#x>

  @value #x value

  run (contextOld) {
    return contextOld.setValue<?>(ErrorOr$$value<?>(value))
  }

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

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

define ErrorParser {
  refines Parser<all>

  @value Formatted message

  run (contextOld) {
    return contextOld.setValue<?>(ErrorOr$$error(message))
  }

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

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 TryParser<#x>{ 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 OrParser<#x>{ 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<any>(parser2)
      if (context2.hasAnyError()) {
        return context2.convertError()
      } else {
        return context2.setValue<?>(context.getValue())
      }
    }
  }

  create (parser1,parser2) {
    return LeftParser<#x>{ 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<any>(parser1)
    if (context.hasAnyError()) {
      return context.convertError()
    } else {
      return context.run<#x>(parser2).toState()
    }
  }

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

define Parse {
  const (value) {
    return ConstParser<#x>$create(value)
  }

  error (message) {
    return ErrorParser$create(message)
  }

  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)
  }
}