All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.fge.grappa.matchers.join.JoinMatcher Maven / Gradle / Ivy

/*
 * Copyright (C) 2014 Francis Galiegue 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.fge.grappa.matchers.join;

import com.github.fge.grappa.exceptions.GrappaException;
import com.github.fge.grappa.matchers.MatcherType;
import com.github.fge.grappa.matchers.base.CustomDefaultLabelMatcher;
import com.github.fge.grappa.matchers.base.Matcher;
import com.github.fge.grappa.rules.Rule;
import com.github.fge.grappa.run.context.MatcherContext;

/**
 * A joining matcher
 *
 * 

Such a matcher has two submatchers: a "joined" matcher and a "joining" * matcher.

* *

This matcher will run cycles through both of these; the first will be a * run of the "joined" matcher, subsequent cycles will be ("joining", "joined"). *

* *

Therefore:

* *
    *
  • one cycle is {@code joined};
  • *
  • two cycles is {@code joined, joining, joined};
  • *
  • etc etc.
  • *
* *

This matcher will correctly reset the index to the last successful * match; for instance, if the match sequence is {@code joined, joining, joined, * joining} and two cycles are enough, it will reset the index to before the * last {@code joining} so that subsequent matchers can proceed from there.

* *

It is forbidden for the "joining" matcher to match an * empty sequence. Unfortunately, due to current limitations, this can only * be detected at runtime.

* *

This matcher is not built directly; its build is initiated by a {@link * JoinMatcherBootstrap}. Example:

* *
 *     Rule threeDigitsExactly()
 *     {
 *         return join(digit()).using('.').times(3);
 *     }
 * 
* * @see JoinMatcherBootstrap */ public abstract class JoinMatcher extends CustomDefaultLabelMatcher { private static final int JOINED_CHILD_INDEX = 0; private static final int JOINING_CHILD_INDEX = 1; protected final Matcher joined; protected final Matcher joining; protected JoinMatcher(final Rule joined, final Rule joining) { super(new Rule[] { joined, joining }, "join"); this.joined = getChildren().get(JOINED_CHILD_INDEX); this.joining = getChildren().get(JOINING_CHILD_INDEX); } @Override public final MatcherType getType() { return MatcherType.COMPOSITE; } /** * Tries a match on the given MatcherContext. * * @param context the MatcherContext * @return true if the match was successful */ @Override public final boolean match(final MatcherContext context) { /* * TODO! Check logic * * At this point, if we have enough cycles, we can't determined whether * our joining rule would match empty... Which is illegal. */ int cycles = 0; if (!joined.getSubContext(context).runMatcher()) return enoughCycles(cycles); cycles++; Object snapshot = context.getValueStack().takeSnapshot(); int beforeCycle = context.getCurrentIndex(); while (runAgain(cycles) && matchCycle(context, beforeCycle)) { beforeCycle = context.getCurrentIndex(); snapshot = context.getValueStack().takeSnapshot(); cycles++; } context.getValueStack().restoreSnapshot(snapshot); context.setCurrentIndex(beforeCycle); return enoughCycles(cycles); } protected abstract boolean runAgain(final int cycles); protected abstract boolean enoughCycles(final int cycles); protected final boolean matchCycle(final MatcherContext context, final int beforeCycle) { if (!joining.getSubContext(context).runMatcher()) return false; if (context.getCurrentIndex() == beforeCycle) throw new GrappaException("joining rule (" + joining + ") of a " + "JoinMatcher cannot match an empty character sequence!"); return joined.getSubContext(context).runMatcher(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy