/** * This file Copyright (c) 2005-2008 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain other free and open source software ("FOSS") code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.lexer.matcher; /** * @author Kevin Sawicki */ public class NumberMatcher extends AndMatcher { private boolean _matchNegative; private boolean _matchPositive; private boolean _matchIntegerPart; private boolean _matchFractionPart; private boolean _matchSciNotation; /** * NumberMatcher */ public NumberMatcher() { this(true, true, true, true, false); } /** * NumberMatcher * @param hasNegative * @param hasPositive * @param hasIntegerPart * @param hasFractionPart * @param hasScientificNotation * */ public NumberMatcher(boolean hasNegative, boolean hasPositive, boolean hasIntegerPart, boolean hasFractionPart, boolean hasScientificNotation) { this._matchNegative = hasNegative; this._matchPositive = hasPositive; this._matchIntegerPart = hasIntegerPart; this._matchFractionPart = hasFractionPart; this._matchSciNotation = hasScientificNotation; } /** * @see com.aptana.ide.lexer.matcher.AbstractTextMatcher#addFirstCharacters(com.aptana.ide.lexer.matcher.MatcherMap, com.aptana.ide.lexer.matcher.ITextMatcher) */ public void addFirstCharacters(MatcherMap map, ITextMatcher target) { if (this._matchPositive) { map.addCharacterMatcher('+', target); } if (this._matchNegative) { map.addCharacterMatcher('-', target); } if (this._matchFractionPart) { map.addCharacterMatcher('.', target); } map.addDigitMatcher(target); } /** * buildMatcher */ private void buildMatcher() { this.addPlusOrMinus(); this.addIntegerPart(); this.addFractionPart(); this.addScientificNotation(); } /** * addFractionPart */ private void addFractionPart() { if (this._matchFractionPart) { // match '.' CharacterMatcher dot = new CharacterMatcher('.'); // match \d+ OneOrMoreMatcher digits = new OneOrMoreMatcher(); digits.appendChild(new DigitMatcher()); // \s WhitespaceMatcher whitespace = new WhitespaceMatcher(); // $ EndOfFileMatcher eof = new EndOfFileMatcher(); // \s | $ OrMatcher whitespaceOrEOF = new OrMatcher(); whitespaceOrEOF.appendChild(whitespace); whitespaceOrEOF.appendChild(eof); // (?> \s | $) LookaheadMatcher lookahead = new LookaheadMatcher(); lookahead.appendChild(whitespaceOrEOF); // \d+ | (?>\s|$) OrMatcher or = new OrMatcher(); or.appendChild(digits); or.appendChild(lookahead); // require both in sequence AndMatcher and = new AndMatcher(); and.appendChild(dot); and.appendChild(or); // make the whole thing optional OptionalMatcher option = new OptionalMatcher(); option.appendChild(and); // add to list this.appendChild(option); } } /** * addIntegerPart */ private void addIntegerPart() { if (this._matchIntegerPart) { // match \d+ //OneOrMoreMatcher repetition = new OneOrMoreMatcher(); ZeroOrMoreMatcher repetition = new ZeroOrMoreMatcher(); repetition.appendChild(new DigitMatcher()); // add to list this.appendChild(repetition); } } /** * addScientificNotation */ private void addScientificNotation() { if (this._matchSciNotation) { // [eE] CharacterClassMatcher exp = new CharacterClassMatcher("eE"); //$NON-NLS-1$ // [-+]? OptionalMatcher plusOrMinus = new OptionalMatcher(); plusOrMinus.appendChild(new CharacterClassMatcher("-+")); //$NON-NLS-1$ // \d+ OneOrMoreMatcher digits = new OneOrMoreMatcher(); digits.appendChild(new DigitMatcher()); // combine AndMatcher group = new AndMatcher(); group.appendChild(exp); group.appendChild(plusOrMinus); group.appendChild(digits); // make optional OptionalMatcher optional = new OptionalMatcher(); optional.appendChild(group); // add to list this.appendChild(optional); } } /** * addPlusOrMinus */ private void addPlusOrMinus() { if (this._matchPositive || this._matchNegative) { OptionalMatcher option = new OptionalMatcher(); if (this._matchPositive && this._matchNegative) { option.appendChild(new CharacterClassMatcher("-+")); //$NON-NLS-1$ } else if (this._matchPositive) { option.appendChild(new CharacterMatcher('+')); } else { option.appendChild(new CharacterMatcher('-')); } this.appendChild(option); } } /** * @see com.aptana.ide.lexer.matcher.AndMatcher#match(char[], int, int) */ public int match(char[] source, int offset, int eofset) { if (this.getChildCount() == 0) { this.buildMatcher(); } int result = super.match(source, offset, eofset); // make sure we advanced, if we matched if (result == offset) { result = -1; } else if (result - 1 == offset) { char c = source[result - 1]; switch (c) { case '-': case '+': case '.': result = -1; break; default: break; } } return result; } /** * getMatchFractionPart * * @return boolean */ public boolean getMatchFractionPart() { return this._matchFractionPart; } /** * setMatchFractionPart * * @param matchFractionPart */ public void setMatchFractionPart(boolean matchFractionPart) { this._matchFractionPart = matchFractionPart; } /** * getMatchIntegerPart * * @return boolean */ public boolean getMatchIntegerPart() { return this._matchIntegerPart; } /** * setMatchIntegerPart * * @param matchIntegerPart */ public void setMatchIntegerPart(boolean matchIntegerPart) { this._matchIntegerPart = matchIntegerPart; } /** * getMatchNegative * * @return boolean */ public boolean getMatchNegative() { return this._matchNegative; } /** * setMatchNegative * * @param matchNegative */ public void setMatchNegative(boolean matchNegative) { this._matchNegative = matchNegative; } /** * getMatchPositive * * @return boolean */ public boolean getMatchPositive() { return this._matchPositive; } /** * setMatchPositive * * @param matchPositive */ public void setMatchPositive(boolean matchPositive) { this._matchPositive = matchPositive; } /** * getMatchSciNotation * * @return boolean */ public boolean getMatchSciNotation() { return this._matchSciNotation; } /** * setMatchSciNotation * * @param matchSciNotation */ public void setMatchSciNotation(boolean matchSciNotation) { this._matchSciNotation = matchSciNotation; } /** * @see com.aptana.ide.lexer.matcher.AndMatcher#toString() */ public String toString() { return "Number"; //$NON-NLS-1$ } }