define MatchState { @value Int enum @value String name @category MatchState matchFailVal <- MatchState{ 0, "matchFail" } @category MatchState matchCompleteVal <- MatchState{ 1, "matchComplete" } @category MatchState matchContinueVal <- MatchState{ 2, "matchContinue" } formatted () { return "MatchState$" + name + "()" } equals (x,y) { return x.getEnum() == y.getEnum() } lessThan (x,y) { return x.getEnum() < y.getEnum() } matchFail () { return matchFailVal } matchComplete () { return matchCompleteVal } matchContinue () { return matchContinueVal } @value getEnum () -> (Int) getEnum () { return enum } } define MatchSingle { @value #c match create (match) { return MatchSingle<#c>{ match } } matchesEmpty () { return false } newMatcher () { return MatchSingleMatcher<#c>$create(match) } } concrete MatchSingleMatcher<#c> { #c defines Equals<#c> refines Matcher<#c> @type create (#c) -> (MatchSingleMatcher<#c>) } define MatchSingleMatcher { @value #c match @value MatchState state create (match) { return MatchSingleMatcher<#c>{ match, MatchState$matchContinue() } } matchSatisfied () { return state `MatchState$equals` MatchState$matchComplete() } tryNextMatch (data) { if (!(state `MatchState$equals` MatchState$matchContinue())) { return (state <- MatchState$matchFail()) } if (data `#c$equals` match) { return (state <- MatchState$matchComplete()) } else { return (state <- MatchState$matchFail()) } } } define MatchRange { @value #c minMatch @value #c maxMatch create (minMatch,maxMatch) { return MatchRange<#c>{ minMatch, maxMatch } } matchesEmpty () { return false } newMatcher () { return MatchRangeMatcher<#c>$create(minMatch,maxMatch) } } concrete MatchRangeMatcher<#c> { #c defines LessThan<#c> refines Matcher<#c> @type create (#c,#c) -> (MatchRangeMatcher<#c>) } define MatchRangeMatcher { @value #c minMatch @value #c maxMatch @value MatchState state create (minMatch,maxMatch) { return MatchRangeMatcher<#c>{ minMatch, maxMatch, MatchState$matchContinue() } } matchSatisfied () { return state `MatchState$equals` MatchState$matchComplete() } tryNextMatch (data) { if (!(state `MatchState$equals` MatchState$matchContinue())) { return (state <- MatchState$matchFail()) } if (!(data `#c$lessThan` minMatch) && !(maxMatch `#c$lessThan` data)) { return (state <- MatchState$matchComplete()) } else { return (state <- MatchState$matchFail()) } } } define MatchAny { create () { return MatchAny{ } } matchesEmpty () { return false } newMatcher () { return MatchAnyMatcher$create() } } concrete MatchAnyMatcher { refines Matcher @type create () -> (MatchAnyMatcher) } define MatchAnyMatcher { @value MatchState state create () { return MatchAnyMatcher{ MatchState$matchContinue() } } matchSatisfied () { return state `MatchState$equals` MatchState$matchComplete() } tryNextMatch (data) { if (!(state `MatchState$equals` MatchState$matchContinue())) { return (state <- MatchState$matchFail()) } return (state <- MatchState$matchComplete()) } } define MatchEmpty { create () { return MatchEmpty{ } } matchesEmpty () { return true } newMatcher () { return MatchEmptyMatcher$create() } } concrete MatchEmptyMatcher { refines Matcher @type create () -> (MatchEmptyMatcher) } define MatchEmptyMatcher { @value Bool failed create () { return MatchEmptyMatcher{ false } } matchSatisfied () { return !failed } tryNextMatch (data) { failed <- true return MatchState$matchFail() } } define MatchRepeat { @value MatcherTemplate<#c> template @value Int minCount @value Int maxCount createZeroPlus (template) { return createRange(0,0,template) } createOnePlus (template) { return createRange(1,0,template) } createRange (minCount,maxCount,template) { return MatchRepeat<#c>{ template, minCount, maxCount } } matchesEmpty () { return minCount <= 0 || template.matchesEmpty() } newMatcher () { return MatchRepeatMatcher<#c>$create(minCount,maxCount,template) } } concrete MatchRepeatMatcher<#c> { refines Matcher<#c> @type create (Int,Int,MatcherTemplate<#c>) -> (MatchRepeatMatcher<#c>) } define MatchRepeatMatcher { @value MatcherTemplate<#c> template @value Matcher<#c> matcher @value Int minCount @value Int maxCount // 0 means unlimited. @value Int repetitionCount @value MatchState lastState create (minCount,maxCount,template) { return MatchRepeatMatcher<#c>{ template, template.newMatcher(), minCount, maxCount, 0, MatchState$matchComplete() } } matchSatisfied () { if (lastState `MatchState$equals` MatchState$matchFail()) { return false } if (lastState `MatchState$equals` MatchState$matchContinue() && (repetitionCount+1 >= minCount || template.matchesEmpty()) && matcher.matchSatisfied()) { // The rest of the current repetition can be ignored. return true } if (lastState `MatchState$equals` MatchState$matchComplete() && (repetitionCount >= minCount || template.matchesEmpty())) { return true } return false } tryNextMatch (data) (state) { if (atMax() || lastState `MatchState$equals` MatchState$matchFail()) { return MatchState$matchFail() } Bool canSkip <- matcher.matchSatisfied() state <- matcher.tryNextMatch(data) if (state `MatchState$equals` MatchState$matchFail() && lastState `MatchState$equals` MatchState$matchContinue() && canSkip) { // Handle the case where an optional end to the pattern can be skipped. ~ incrementMatch() ~ startRepeat() state <- matcher.tryNextMatch(data) } lastState <- state if (state `MatchState$equals` MatchState$matchComplete()) { ~ incrementMatch() ~ startRepeat() if (atMax()) { state <- MatchState$matchComplete() } else { state <- MatchState$matchContinue() } } } @value incrementMatch () -> () incrementMatch () { repetitionCount <- repetitionCount+1 } @value atMax () -> (Bool) atMax () { return maxCount > 0 && repetitionCount >= maxCount } @value startRepeat () -> () startRepeat () { matcher <- template.newMatcher() } } define MatchChoices { @value optional ReadSequence> choices create (choices) { return MatchChoices<#c>{ choices } } matchesEmpty () { scoped { optional ReadSequence> current <- choices } in while (present(current)) { if (require(current).value().matchesEmpty()) { return true } } update { current <- require(current).next() } return false } newMatcher () { return MatchChoicesMatcher<#c>$create(recursiveNewMatcher(choices)) } @type recursiveNewMatcher (optional ReadSequence>) -> (optional ReadSequence>) recursiveNewMatcher (choices) { if (!present(choices)) { return empty } return LinkedNode>$create(require(choices).value().newMatcher(), recursiveNewMatcher(require(choices).next())) } } concrete MatchChoicesMatcher<#c> { refines Matcher<#c> @type create (optional ReadSequence>) -> (MatchChoicesMatcher<#c>) } define MatchChoicesMatcher { @value optional ReadSequence> choices create (choices) { return MatchChoicesMatcher<#c>{ choices } } matchSatisfied () { scoped { optional ReadSequence> current <- choices } in while (present(current)) { if (require(current).value().matchSatisfied()) { return true } } update { current <- require(current).next() } return false } tryNextMatch (data) (state) { state <- MatchState$matchFail() scoped { optional ReadSequence> current <- choices } in while (present(current)) { // NOTE: Failing matchers are left in for simplicity, under the assumption // that they will keep failing. MatchState state2 <- require(current).value().tryNextMatch(data) if (state `MatchState$lessThan` state2) { state <- state2 } } update { current <- require(current).next() } } } define MatchBranches { @value MatchBrancherTemplate<#c> template create (template) { return MatchBranches<#c>{ template } } matchesEmpty () { return template.matchesEmpty() } newMatcher () { return MatchBranchesMatcher<#c>$create(template.newBrancher()) } } concrete MatchBranchesMatcher<#c> { refines Matcher<#c> @type create (MatchBrancher<#c>) -> (MatchBranchesMatcher<#c>) } define MatchBranchesMatcher { @value optional ReadSequence> branches @value Bool complete create (brancher) { return MatchBranchesMatcher<#c>{ LinkedNode>$create(brancher,empty), false } } matchSatisfied () { if (complete) { return true } scoped { optional ReadSequence> current <- branches } in while (present(current)) { if (require(current).value().matchSatisfied()) { return true } } update { current <- require(current).next() } return false } tryNextMatch (data) (state) { state <- MatchState$matchFail() optional ReadSequence> current <- branches branches <- empty complete <- false scoped { } in while(present(current)) { { MatchState state2, optional ReadSequence> branches2 } <- require(current).value().tryBranches(data) if (state2 `MatchState$equals` MatchState$matchComplete()) { complete <- true } if (state `MatchState$lessThan` state2) { state <- state2 } branches <- LinkedNode>$concatSequences(branches2,branches) } update { current <- require(current).next() } } } concrete BranchRepeatMatcher<#c> { refines MatchBrancher<#c> @type create (Int,Int,MatcherTemplate<#c>) -> (BranchRepeatMatcher<#c>) @value tryBranches (#c) -> (MatchState,optional ReadSequence>) } define BranchRepeatMatcher { @value MatcherTemplate<#c> template @value Matcher<#c> matcher @value Int minCount @value Int maxCount // 0 means unlimited. @value Int repetitionCount @value MatchState lastState create (minCount,maxCount,template) { return BranchRepeatMatcher<#c>{ template, template.newMatcher(), minCount, maxCount, 0, MatchState$matchComplete() } } matchSatisfied () { if (lastState `MatchState$equals` MatchState$matchFail()) { return false } if (lastState `MatchState$equals` MatchState$matchContinue() && (repetitionCount+1 >= minCount || template.matchesEmpty()) && matcher.matchSatisfied()) { // The rest of the current repetition can be ignored. return true } if (lastState `MatchState$equals` MatchState$matchComplete() && (repetitionCount >= minCount || template.matchesEmpty())) { return true } return false } tryBranches (data) (state,branch) { state <- MatchState$matchFail() branch <- empty if (atMax() || lastState `MatchState$equals` MatchState$matchFail()) { return _ } if (lastState `MatchState$equals` MatchState$matchContinue()) { // Handle a possible single branch. Bool canSkip <- matcher.matchSatisfied() state <- matcher.tryNextMatch(data) if (canSkip) { if (state `MatchState$equals` MatchState$matchContinue()) { // Add a branch for the optional suffix. branch <- LinkedNode>$create( BranchRepeatMatcher<#c>{ template, matcher, minCount, maxCount, repetitionCount, MatchState$matchContinue() },empty) } // Continue, skipping over the optional suffix. ~ incrementMatch() ~ startRepeat() if (atMax()) { // Skipping the branch puts us at the max. return _ } state <- matcher.tryNextMatch(data) } } else { // Branching is not possible. state <- matcher.tryNextMatch(data) } lastState <- state if (state `MatchState$equals` MatchState$matchComplete()) { ~ incrementMatch() ~ startRepeat() if (!atMax()) { branch <- LinkedNode>$create(self,branch) } } elif (state `MatchState$equals` MatchState$matchContinue()) { branch <- LinkedNode>$create(self,branch) } if (present(branch)) { state <- MatchState$matchContinue() } } @value incrementMatch () -> () incrementMatch () { repetitionCount <- repetitionCount+1 } @value atMax () -> (Bool) atMax () { return maxCount > 0 && repetitionCount >= maxCount } @value startRepeat () -> () startRepeat () { matcher <- template.newMatcher() } } define BranchSequence { @value optional ReadSequence> sequence create (sequence) { return BranchSequence<#c>{ sequence } } matchesEmpty () { scoped { optional ReadSequence> current <- sequence } in while (present(current)) { if (!require(current).value().matchesEmpty()) { return false } } update { current <- require(current).next() } return true } newBrancher () { return BranchSequenceMatcher<#c>$create(sequence) } } concrete BranchSequenceMatcher<#c> { refines MatchBrancher<#c> @type create (optional ReadSequence>) -> (BranchSequenceMatcher<#c>) @value tryBranches (#c) -> (MatchState,optional ReadSequence>) } define BranchSequenceMatcher { @value optional Matcher<#c> continued @value optional ReadSequence> sequence @value Bool consumed create (sequence) { return BranchSequenceMatcher<#c>{ empty, sequence, false } } matchSatisfied () { if (consumed) { return false } if (present(continued) && !require(continued).matchSatisfied()) { return false } scoped { optional ReadSequence> current <- sequence } in while (present(current)) { if (!require(current).value().matchesEmpty()) { return false } } update { current <- require(current).next() } return true } tryBranches (data) { if (consumed) { return { MatchState$matchFail(), empty } } consumed <- true return recursiveBranch(data,continued,sequence) } @type recursiveBranch (#c,optional Matcher<#c>,optional ReadSequence>) -> (MatchState,optional ReadSequence>) recursiveBranch (data,continued,sequence) (state,branch) { state <- MatchState$matchFail() branch <- empty if (!present(continued) && !present(sequence)) { return _ } optional Matcher<#c> continued2 <- continued optional ReadSequence> sequence2 <- sequence if (!present(continued2)) { continued2 <- require(sequence2).value().newMatcher() sequence2 <- require(sequence2).next() } if (require(continued2).matchSatisfied()) { { MatchState state2, branch } <- recursiveBranch(data,empty,sequence2) if (state `MatchState$lessThan` state2) { state <- state2 } } MatchState state2 <- require(continued2).tryNextMatch(data) if (state `MatchState$lessThan` state2) { state <- state2 } if (state2 `MatchState$equals` MatchState$matchComplete()) { if (present(sequence2)) { // Add a branch to continue this sequence. branch <- LinkedNode>$create( BranchSequenceMatcher<#c>{ empty, sequence2, false },branch) state <- MatchState$matchContinue() } else { // Add a branch to serve as a record of completeness. It will fail to // match anything, but matchSatisfied() will return true. branch <- LinkedNode>$create( BranchSequenceMatcher<#c>{ empty, empty, false },branch) } } elif (state `MatchState$equals` MatchState$matchContinue()) { // Add a branch to continue this sequence. branch <- LinkedNode>$create( BranchSequenceMatcher<#c>{ continued2, sequence2, false },branch) } } } define BranchRepeat { @value MatcherTemplate<#c> template @value Int minCount @value Int maxCount createZeroPlus (template) { return createRange(0,0,template) } createOnePlus (template) { return createRange(1,0,template) } createRange (minCount,maxCount,template) { return BranchRepeat<#c>{ template, minCount, maxCount } } matchesEmpty () { return minCount <= 0 || template.matchesEmpty() } newBrancher () { return BranchRepeatMatcher<#c>$create(minCount,maxCount,template) } } define LinkedNode { @value optional ReadSequence<#x> nextNode @value #x data create (data,nextNode) { return LinkedNode<#x>{ nextNode, data } } concatSequences (head1,head2) { if (!present(head2)) { return head1 } elif (present(head1)) { return LinkedNode<#x>$create(require(head1).value(), concatSequences(require(head1).next(),head2)) } else { return head2 } } value () { return data } next () { return nextNode } }