/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.grammars.parsers;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.whole.lang.factories.GenericEntityFactory;
import org.whole.lang.grammars.codebase.GrammarsRegistry;
import org.whole.lang.grammars.model.CompiledPattern;
import org.whole.lang.grammars.model.Grammar;
import org.whole.lang.grammars.model.LiteralTerminal;
import org.whole.lang.grammars.model.Production;
import org.whole.lang.grammars.model.Rule;
import org.whole.lang.grammars.util.GrammarsUtils;
import org.whole.lang.model.IEntity;
import org.whole.lang.operations.NormalizerOperation;
import org.whole.lang.parsers.Lexer;
import org.whole.lang.parsers.Lexer.Memento;
import org.whole.lang.parsers.ParseException;
import org.whole.lang.reflect.EntityDescriptor;
import org.whole.lang.reflect.EntityDescriptorEnum;
import org.whole.lang.reflect.FeatureDescriptor;
import org.whole.lang.reflect.FeatureDescriptorEnum;
import org.whole.lang.reflect.ILanguageKit;
import org.whole.lang.reflect.ReflectionFactory;
import org.whole.lang.util.DataTypeUtils;
import org.whole.lang.util.EntityUtils;
/**
* @author Enrico Persiani
*/
public abstract class AbstractPredictiveParser {
private ILanguageKit languageKit;
private EntityDescriptorEnum edEnum;
private FeatureDescriptorEnum fdEnum;
protected Lexer lexer;
protected Grammar grammar;
public AbstractPredictiveParser(Lexer lexer, String grammarUri) {
this.lexer = lexer;
this.grammar = GrammarsRegistry.instance().getGrammar(grammarUri);
this.languageKit = ReflectionFactory.getLanguageKit(GrammarsUtils.getLanguageURI(grammar), false, null);
this.edEnum = languageKit.getEntityDescriptorEnum();
this.fdEnum = languageKit.getFeatureDescriptorEnum();
LiteralTerminal delimiter = this.grammar.getDelimiter();
if (EntityUtils.isNotResolver(delimiter)) {
CompiledPattern pattern = (CompiledPattern) delimiter.getPattern();
lexer.withDelimiter(pattern.getValue());
}
}
protected Grammar normalize(Grammar grammar) {
grammar = EntityUtils.clone(grammar);
NormalizerOperation.normalize(grammar);
return grammar;
}
protected final IEntity create(String edName) {
return create(ed(edName));
}
protected final IEntity create(EntityDescriptor<?> ed) {
return GenericEntityFactory.instance.create(ed);
}
protected final void setValue(IEntity entity, String token) {
DataTypeUtils.setFromPersistenceString(entity, token);
}
protected EntityDescriptor<?> ed(String name) {
return edEnum.valueOf(name);
}
protected FeatureDescriptor fd(String name) {
return fdEnum.valueOf(name);
}
protected ParseException createParseError(String errorMessage) throws ParseException {
return new ParseException(lexer, errorMessage);
}
protected String nextToken(String regExp) {
return nextToken(java.util.regex.Pattern.compile(regExp));
}
protected String nextToken(java.util.regex.Pattern compiledPattern) {
lexer.withPattern(compiledPattern);
if (lexer.hasNext())
return lexer.next();
throw createParseError("missing terminal");
}
protected static final int NO_MATCH = Integer.MIN_VALUE;
protected static final int NON_CONSUMING_MATCH = -1;
protected static final boolean isMatch(int predictResult) {
return predictResult != NO_MATCH;
}
protected static final boolean isConsumingMatch(int predictResult) {
return predictResult >= 0;
}
protected static final int nonConsumingMatch(int predictResult) {
return -predictResult -1;
}
protected static final int indexOfMatch(int predictResult) {
return predictResult >= 0 ? predictResult : nonConsumingMatch(predictResult);
}
protected int wPredict(String location) {
return wPredict((Rule) EntityUtils.getEntity(grammar, location));
}
protected int wPredict(Rule rule) {
int prediction = NO_MATCH;
Lexer.Memento memento = mark();
try {
prediction = wMatch(rule);
if (isSame(memento))
prediction = nonConsumingMatch(prediction);
} catch (Exception e) {
}
reset(memento);
return prediction;
}
protected int wMatch(Rule rule) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
String lookaheadMethodName = "match"+((Production) rule).getName().getValue();
Method method = getClass().getMethod(lookaheadMethodName, new Class<?>[0]);
return (Integer) method.invoke(this, new Object[0]);
}
public void wParse() {
wParseStartSymbol();
if (!lexer.hitEnd())
throw createParseError("end of input expected");
}
public abstract void wParseStartSymbol();
/* Lexer delegate methods */
protected boolean isSame(Memento memento) {
return lexer.isSame(memento);
}
protected Lexer.Memento mark() {
return lexer.mark();
}
protected void reset(Lexer.Memento memento) {
lexer.reset(memento);
}
protected boolean hitEnd() {
return lexer.hitEnd();
}
protected int getHorizonPosition() {
return lexer.getHorizonPosition();
}
protected int setHorizonPosition(int position, boolean force) {
return lexer.setHorizonPosition(position, force);
}
protected int setHorizonBySize(int length) {
try {
return lexer.setHorizonBySize(length);
} catch (IndexOutOfBoundsException e) {
throw createParseError(e.getLocalizedMessage());
}
}
protected int moveHorizonByDelimiter(String regExp, int endPosition) {
return moveHorizonByDelimiter(java.util.regex.Pattern.compile(regExp), endPosition);
}
protected int moveHorizonByDelimiter(java.util.regex.Pattern compiledPattern, int endPosition) {
try {
return lexer.moveHorizonByDelimiter(compiledPattern, endPosition);
} catch (IndexOutOfBoundsException e) {
throw createParseError(e.getLocalizedMessage());
}
}
protected int setHorizonByDelimiter(String regExp) {
return setHorizonByDelimiter(java.util.regex.Pattern.compile(regExp));
}
protected int setHorizonByDelimiter(java.util.regex.Pattern compiledPattern) {
try {
return lexer.setHorizonByDelimiter(compiledPattern);
} catch (IndexOutOfBoundsException e) {
throw createParseError(e.getLocalizedMessage());
}
}
protected int setHorizonByLines(int lines) {
try {
return lexer.setHorizonByLines(lines);
} catch (IndexOutOfBoundsException e) {
throw createParseError(e.getLocalizedMessage());
}
}
}