blob: baab5c8f99e5eb7082530d9aec06451127852867 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 The University of York.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Dimitrios Kolovos - initial API and implementation
******************************************************************************/
package org.eclipse.epsilon.ecl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.Lexer;
import org.antlr.runtime.TokenStream;
import org.eclipse.epsilon.common.module.IModule;
import org.eclipse.epsilon.common.module.ModuleElement;
import org.eclipse.epsilon.common.parse.AST;
import org.eclipse.epsilon.common.parse.EpsilonParser;
import org.eclipse.epsilon.common.util.AstUtil;
import org.eclipse.epsilon.ecl.dom.MatchRule;
import org.eclipse.epsilon.ecl.execute.EclOperationFactory;
import org.eclipse.epsilon.ecl.execute.context.EclContext;
import org.eclipse.epsilon.ecl.execute.context.IEclContext;
import org.eclipse.epsilon.ecl.parse.EclLexer;
import org.eclipse.epsilon.ecl.parse.EclParser;
import org.eclipse.epsilon.ecl.trace.Match;
import org.eclipse.epsilon.ecl.trace.MatchTrace;
import org.eclipse.epsilon.eol.dom.ExecutableBlock;
import org.eclipse.epsilon.eol.dom.Import;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.execute.context.IEolContext;
import org.eclipse.epsilon.eol.execute.context.Variable;
import org.eclipse.epsilon.erl.ErlModule;
import org.eclipse.epsilon.erl.dom.NamedRuleList;
public class EclModule extends ErlModule implements IEclModule {
protected NamedRuleList<MatchRule> matchRules;
protected final NamedRuleList<MatchRule> declaredMatchRules = new NamedRuleList<>();
public EclModule() {
setContext(new EclContext());
}
@Override
protected Lexer createLexer(ANTLRInputStream inputStream) {
return new EclLexer(inputStream);
}
@Override
public EpsilonParser createParser(TokenStream tokenStream) {
return new EclParser(tokenStream);
}
@Override
public String getMainRule() {
return "eclModule";
}
@Override
public void build(AST cst, IModule module) {
super.build(cst, module);
// Parse the match rules
Collection<AST> matchChildren = AstUtil.getChildren(cst, EclParser.MATCH);
declaredMatchRules.ensureCapacity(matchChildren.size());
for (AST matchRuleAst : matchChildren) {
declaredMatchRules.add((MatchRule) module.createAst(matchRuleAst, this));
}
getParseProblems().addAll(calculateSuperRules(getMatchRules()));
}
@Override
public ModuleElement adapt(AST cst, ModuleElement parentAst) {
switch (cst.getType()) {
case EclParser.MATCH: return new MatchRule();
case EclParser.GUARD:
case EclParser.COMPARE:
return new ExecutableBlock<Boolean>(Boolean.class);
case EclParser.DO: return new ExecutableBlock<Void>(Void.class);
}
return super.adapt(cst, parentAst);
}
@Override
public HashMap<String, Class<?>> getImportConfiguration() {
HashMap<String, Class<?>> importConfiguration = super.getImportConfiguration();
importConfiguration.put("ecl", EclModule.class);
return importConfiguration;
}
@Override
public List<MatchRule> getMatchRules() {
if (matchRules == null) {
matchRules = new NamedRuleList<>();
for (Import import_ : imports) {
if (import_.isLoaded() && (import_.getModule() instanceof IEclModule)) {
IEclModule module = (IEclModule) import_.getModule();
matchRules.addAll(module.getMatchRules());
}
}
matchRules.addAll(declaredMatchRules);
}
return matchRules;
}
@Override
protected void prepareContext() {
super.prepareContext();
IEclContext context = getContext();
context.setOperationFactory(new EclOperationFactory());
context.getFrameStack().put(
Variable.createReadOnlyVariable("matchTrace", context.getMatchTrace()),
Variable.createReadOnlyVariable("context", context),
Variable.createReadOnlyVariable("self", this)
);
}
@Override
public final MatchTrace execute() throws EolRuntimeException {
return (MatchTrace) super.execute();
}
@Override
public MatchTrace executeImpl() throws EolRuntimeException {
prepareExecution();
matchModels();
postExecution();
return getContext().getMatchTrace();
}
@Override
public void matchModels() throws EolRuntimeException {
matchAllRules(false);
matchAllRules(true);
}
protected void matchAllRules(boolean greedy) throws EolRuntimeException {
boolean ofTypeOnly = !greedy;
IEclContext context = getContext();
for (MatchRule matchRule : getMatchRules()) {
if (!matchRule.isAbstract() && !matchRule.isLazy(context) && (!greedy || matchRule.isGreedy())) {
for (Object left : matchRule.getLeftInstances(context, ofTypeOnly)) {
for (Object right : matchRule.getRightInstances(context, ofTypeOnly)) {
matchRule.matchPair(context, ofTypeOnly, left, right);
}
}
}
}
}
@Override
public Match match(Object left, Object right, boolean forcedMatch) throws EolRuntimeException {
IEclContext context = getContext();
Match traceMatch = context.getMatchTrace().getMatch(left, right);
if (traceMatch != null) return traceMatch;
List<MatchRule> matchRules = getRulesFor(left, right, context, true);
if (!matchRules.isEmpty()) {
MatchRule matchRule = (MatchRule) matchRules.iterator().next();
return matchRule.match(left, right, context, false, null, forcedMatch);
}
else {
matchRules = getRulesFor(left, right, context, false);
boolean matchRulesNotEmpty = !matchRules.isEmpty();
Match match = new Match(left, right, matchRulesNotEmpty, null);
if (matchRulesNotEmpty) {
for (MatchRule matchRule : matchRules) {
if (matchRule.isGreedy()) {
Match tempMatch = matchRule.match(left, right, context, true, match.getInfo(), forcedMatch);
match.setMatching(match.isMatching() && tempMatch.isMatching());
match.setRule(matchRule);
}
}
}
context.getMatchTrace().getMatches().add(match);
return match;
}
}
@Override
public IEclContext getContext() {
return (IEclContext) super.getContext();
}
@Override
public List<MatchRule> getDeclaredMatchRules() {
return declaredMatchRules;
}
@Override
protected int getPostBlockTokenType() {
return EclParser.POST;
}
@Override
protected int getPreBlockTokenType() {
return EclParser.PRE;
}
@Override
public void setContext(IEolContext context) {
if (context instanceof IEclContext) {
super.setContext(context);
}
}
public List<MatchRule> getRulesFor(Object obj1, Object obj2, IEclContext context, boolean ofClassOnly) throws EolRuntimeException {
List<MatchRule> rules = new ArrayList<>();
for (MatchRule matchRule : getMatchRules()) {
if (!matchRule.isAbstract() && matchRule.appliesTo(obj1, obj2, context, ofClassOnly)) {
rules.add(matchRule);
}
}
return rules;
}
}