001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util.parse.metapattern.parsers;
018
019import java.util.regex.Matcher;
020
021import org.apache.wicket.util.parse.metapattern.MetaPattern;
022
023
024/**
025 * Base class for various MetaPattern based parsers.
026 * 
027 * @author Jonathan Locke
028 */
029public abstract class MetaPatternParser
030{
031        /** The input to parse */
032        private final CharSequence input;
033
034        /** The length of the input; no. of characters */
035        private final int length;
036
037        /**
038         * The position (index) behind the last pattern group matched while advancing from one pattern
039         * group to the next one.
040         */
041        private int pos;
042
043        /** The object maintaining all the regex match details */
044        private Matcher matcher;
045
046        /**
047         * Construct the parser. You must call
048         * 
049         * @see #advance(MetaPattern) to initialize the matcher with the pattern.
050         * @param input
051         *            to parse
052         */
053        public MetaPatternParser(final CharSequence input)
054        {
055                this.input = input;
056                length = input.length();
057        }
058
059        /**
060         * Construct the parser and initialize the matcher with the pattern given.
061         * 
062         * @param pattern
063         *            Meta pattern
064         * @param input
065         *            Input to parse
066         */
067        public MetaPatternParser(final MetaPattern pattern, final CharSequence input)
068        {
069                this(input);
070                setPattern(pattern);
071        }
072
073        /**
074         * @param pattern
075         *            Pattern
076         */
077        public void setPattern(final MetaPattern pattern)
078        {
079                matcher = pattern.matcher(input);
080        }
081
082        /**
083         * Advance parsing to the next element. The internal cursor will be moved to end of the string
084         * matched.
085         * 
086         * @param pattern
087         *            Meta pattern
088         * @return True if found, false otherwise
089         */
090        protected final boolean advance(final MetaPattern pattern)
091        {
092                // get the remaining part of the input
093                final CharSequence s = input.subSequence(pos, length);
094
095                // does the pattern match?
096                matcher = pattern.matcher(s);
097                if (matcher.lookingAt())
098                {
099                        // Yes, it does. Move the cursor to the end of the
100                        // char sequence matched.
101                        pos += matcher.end();
102
103                        // Found the pattern
104                        return true;
105                }
106
107                // Did not find the pattern.
108                return false;
109        }
110
111        /**
112         * Whether the matcher matches the pattern.
113         * 
114         * @return whether the matcher matches
115         */
116        public boolean matches()
117        {
118                return matcher.matches();
119        }
120
121        /**
122         * Gets the matcher.
123         * 
124         * @return the matcher
125         */
126        public final Matcher matcher()
127        {
128                return matcher;
129        }
130
131        /**
132         * Whether the internal cursor has advanced to the end of the input.
133         * 
134         * @return whether the input is parsed
135         */
136        public final boolean atEnd()
137        {
138                return pos == length;
139        }
140}