packages feed

zeolite-lang-0.3.0.0: example/regex/char-regex.0rx

define CharRegex {
  parse (pattern) (matcher) {
    ReadIterator<Char> p <- ReadIterator$$fromReadPosition<Char>(pattern)
    // TODO: Needs error handling.
    _, matcher <- parseExpression(p)
  }

  match (template,data) {
    ReadIterator<Char> p <- ReadIterator$$fromReadPosition<Char>(data)
    Matcher<Char> matcher <- template.newMatcher()
    while (!p.pastForwardEnd()) {
      MatchState state <- matcher.tryNextMatch(p.readCurrent())
      if (state `MatchState$equals` MatchState$matchFail()) {
        break
      }
      p <- p.forward()
      if (state `MatchState$equals` MatchState$matchComplete()) {
        break
      }
    }
    return p.pastForwardEnd() && matcher.matchSatisfied()
  }

  @type parseSequence (ReadIterator<Char>) ->
                      (ReadIterator<Char>,optional ReadSequence<MatcherTemplate<Char>>)
  parseSequence (p) {
    if (p.pastForwardEnd()) {
      return p, empty
    }
    ReadIterator<Char> p2, optional MatcherTemplate<Char> matcher <- parseNonSequence(p)
    if (!p2.pastForwardEnd() && (p2.readCurrent() == '|' || p2.readCurrent() == ')')) {
      // Requires choice matching or the end of a subexpression.
      if (present(matcher)) {
        return p2, LinkedNode<MatcherTemplate<Char>>$create(require(matcher),empty)
      } else {
        // TODO: Disregards errors from parseNonSequence.
        return p2, LinkedNode<MatcherTemplate<Char>>$create(MatchEmpty$create(),empty)
      }
    } if (!present(matcher)) {
      return p2, empty
    } else {
      p2, optional ReadSequence<MatcherTemplate<Char>> sequence <- parseSequence(p2)
      return p2, LinkedNode<MatcherTemplate<Char>>$create(require(matcher),sequence)
    }
  }

  @type parseNonSequence (ReadIterator<Char>) ->
                         (ReadIterator<Char>,optional MatcherTemplate<Char>)
  parseNonSequence (p) (p2,matcher) {
    p2 <- p
    matcher <- empty
    while (!p2.pastForwardEnd()) {
      Char c <- p2.readCurrent()
      if (c == '|' || c == ')') {
        // Requires choice matching or the end of a subexpression.
        return _
      } elif (c == '*') {
        // TODO: Needs error handling.
        return p2.forward(),
               MatchBranches<Char>$create(BranchRepeat<Char>$createZeroPlus(require(matcher)))
      } elif (c == '+') {
        // TODO: Needs error handling.
        return p2.forward(),
               MatchBranches<Char>$create(BranchRepeat<Char>$createOnePlus(require(matcher)))
      } elif (c == '{') {
        p2, Int min, Int max <- parseRange(p2.forward())
        if (p2.pastForwardEnd() || p2.readCurrent() != '}') {
          // TODO: Needs error handling.
          fail("missing }")
        }
        return p2.forward(),
               MatchBranches<Char>$create(BranchRepeat<Char>$createRange(min,max,require(matcher)))
      } elif (present(matcher)) {
        return _
      } elif (c == '[') {
        p2, matcher <- parseCharChoices(p2.forward())
        if (p2.pastForwardEnd() || p2.readCurrent() != ']') {
          // TODO: Needs error handling.
          fail("missing ]")
        }
        p2 <- p2.forward()
      } elif (c == '(') {
        p2, matcher <- parseExpression(p2.forward())
        if (p2.pastForwardEnd() || p2.readCurrent() != ')') {
          // TODO: Needs error handling.
          fail("missing )")
        }
        p2 <- p2.forward()
      } else {
        p2, matcher <- parseSingleChar(p2)
      }
    }
  }

  @type parseRange (ReadIterator<Char>) -> (ReadIterator<Char>,Int,Int)
  parseRange (p) (p2,min,max) {
    max <- 0
    p2, min <- parseCount(p)
    if (p2.pastForwardEnd() || p2.readCurrent() != ',') {
      max <- min
    } else {
      p2, max <- parseCount(p2.forward())
    }
  }

  @type parseCount (ReadIterator<Char>) -> (ReadIterator<Char>,Int)
  parseCount (p) (p2,count) {
    // TODO: Needs error handling.
    count <- 0
    p2 <- p
    while (!p2.pastForwardEnd()) {
      Char c <- p2.readCurrent()
      if (c >= '0' && c <= '9') {
        count <- 10*count + (c - '0')
      } else {
        break
      }
    } update {
      p2 <- p2.forward()
    }
  }

  @type parseExpression (ReadIterator<Char>) ->
                        (ReadIterator<Char>,optional MatcherTemplate<Char>)
  parseExpression (p) (p2,matcher) {
    optional ReadSequence<MatcherTemplate<Char>> choices <- empty
    p2 <- p
    while (!p2.pastForwardEnd()) {
      p2, optional ReadSequence<MatcherTemplate<Char>> sequence <- parseSequence(p2)
      if (!present(sequence)) {
        break
      }
      choices <- LinkedNode<MatcherTemplate<Char>>$create(
          MatchBranches<Char>$create(BranchSequence<Char>$create(sequence)),choices)
      if (p2.pastForwardEnd() || p2.readCurrent() != '|') {
        break
      }
      p2 <- p2.forward()
    }
    if (!present(choices)) {
      matcher <- MatchEmpty$create()
    } else {
      matcher <- MatchChoices<Char>$create(choices)
    }
  }

  @type parseSingleChar (ReadIterator<Char>) ->
                        (ReadIterator<Char>,optional MatcherTemplate<Char>)
  parseSingleChar (p) (p2,matcher) {
    // TODO: Needs error handling.
    Char c <- p.readCurrent()
    p2 <- p.forward()
    if (c == '\\') {
      matcher <- MatchSingle<Char>$create(p2.readCurrent())
      p2 <- p.forward()
    } elif (c == '.') {
      matcher <- MatchAny$create()
    } else {
      matcher <- MatchSingle<Char>$create(c)
    }
  }

  @type parseCharChoices (ReadIterator<Char>) ->
                         (ReadIterator<Char>,optional MatcherTemplate<Char>)
  parseCharChoices (p) (p2,matcher) {
    p2 <- p
    matcher <- empty
    optional Char previous <- empty
    Bool doRange <- false
    optional ReadSequence<MatcherTemplate<Char>> choices <- empty
    while (!p2.pastForwardEnd()) {
      Char c <- p2.readCurrent()
      if (c == '\\') {
        p2 <- p2.forward()
        c <- p2.readCurrent()
      }
      if (c == ']') {
        break
      } elif (c == '-' && present(previous) && !doRange) {
        doRange <- true
      } elif (doRange) {
        choices <- LinkedNode<MatcherTemplate<Char>>$create(MatchRange<Char>$create(require(previous),c),choices)
        previous <- empty
        doRange <- false
      } elif (present(previous)) {
        choices <- LinkedNode<MatcherTemplate<Char>>$create(MatchSingle<Char>$create(require(previous)),choices)
        previous <- c
      } else {
        previous <- c
      }
    } update {
      p2 <- p2.forward()
    }
    if (present(previous)) {
      choices <- LinkedNode<MatcherTemplate<Char>>$create(MatchSingle<Char>$create(require(previous)),choices)
    }
    matcher <- MatchChoices<Char>$create(choices)
  }
}