Commit da98f424 authored by Sarah Grebing's avatar Sarah Grebing

bugfix matcher

parent 2b65453d
group = 'org.dockfx'
description = 'DockFX'
// apply plugin: 'io.franzbecker.gradle-lombok'
//apply plugin: 'java'
//apply plugin: 'java-library'
//apply plugin: 'idea'
/*sourceCompatibility = 1.8
targetCompatibility = 1.8
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
repositories {
mavenLocal()
maven { url "http://repo.maven.apache.org/maven2" }
maven { url "http://dl.bintray.com/jerady/maven" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}
dependencies {
compile group: 'commons-cli', name: 'commons-cli', version: '1.4'
compile group: 'com.google.guava', name: 'guava', version: '25.0-jre'
compile group: 'commons-io', name: 'commons-io', version: '2.6'
compile group: 'commons-lang', name: 'commons-lang', version: '2.6'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
testCompile group: 'junit', name: 'junit', version: '4.12'
//compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.16.20'
compileOnly files("$rootDir/lombok-edge.jar")
}*/
......@@ -41,7 +41,7 @@ import lombok.Data;
public class MatchExpression extends Expression<ScriptLanguageParser.MatchPatternContext> {
//private Signature signature = new Signature();
private Expression pattern;
private boolean isDerivable;
private boolean isDerivable = false;
@Deprecated
private Expression derivableTerm;
......
grammar MatchPattern;
/* Examples for testing
f(x)
f(x,y,g(y))
X
?Y
_
...
f(... ?X ...)
f(..., ?X)
f(..., ...?X...)
f(..., ... g(x) ...)
f(_, x, _, y, ... y ...)
*/
sequentPattern : antec=semiSeqPattern? ARROW succ=semiSeqPattern? #sequentArrow
| anywhere=semiSeqPattern #sequentAnywhere
;
semiSeqPattern : termPattern (',' termPattern)*;
termPattern :
'(' quantifier=(EXISTS|FORALL) boundVars+=(SID|ID|DONTCARE)+ skope=termPattern ')' bindClause? #quantForm
| termPattern MUL termPattern #mult
| <assoc=right> termPattern op=(DIV|MOD) termPattern #divMod
| termPattern op=(PLUS|MINUS) termPattern #plusMinus
| termPattern op=(LE|GE|LEQ|GEQ) termPattern #comparison
| termPattern op=(NEQ|EQ) termPattern #equality
| termPattern AND termPattern #and
| termPattern OR termPattern #or
| termPattern IMP termPattern #impl
| termPattern XOR termPattern #xor
| termPattern EQUIV termPattern #equivalence
| MINUS termPattern #exprNegate
| NOT termPattern #exprNot
| '(' termPattern ')' bindClause? #exprParen
| func=ID ( '(' termPattern (',' termPattern)* ')')? bindClause? #function
| DONTCARE bindClause? #dontCare
//| STARDONTCARE #starDontCare
| SID #schemaVar
| STARDONTCARE termPattern STARDONTCARE #anywhere
| DIGITS #number
// not working because of ambigue | left=termPattern op=(PLUS|MINUS|MUL|LE|GE|LEQ|GEQ|NEQ|EQ| AND|OR|IMP) right=termPattern #binaryOperation
;
/*
f(x), f(x,y,g(y)), X, ?Y, _, ..., f(... ?X ...), f(..., ?X), f(..., ...?X...), f(..., ... g(x) ...), f(_, x, _, y, ... y ...)
*/
bindClause : ('\\as' | ':') SID;
DONTCARE: '?' | '_' | '█';
DIGITS : DIGIT+ ;
fragment DIGIT : [0-9] ;
ARROW : '⇒' | '==>';
STARDONTCARE: '...' | '…';
PLUS : '+' ;
MINUS : '-' ;
MUL : '*' ;
DIV : '/' ;
EQ : '=' ;
NEQ : '!=' ;
GEQ : '>=' ;
LEQ : '<=' ;
EQUIV : '<->';
GE : '>' ;
LE : '<' ;
AND : '&' ;
OR: '|' ;
IMP: '->';
MOD:'%';
XOR:'^';
NOT :'!';
FORALL: '\\forall' | '∀';
EXISTS: '\\exists';
SID: '?' [_a-zA-Z0-9\\]+ ;
ID : [a-zA-Z\\_] ([_a-zA-Z0-9\\])*
| 'update-application'
| 'parallel-upd'
| 'elem-update'
;
COMMENT: '//' ~[\n\r]* -> channel(HIDDEN);
WS: [\n\f\r\t ] -> channel(HIDDEN);
package edu.kit.iti.formal.psdbg.termmatcher;
import org.antlr.v4.runtime.ParserRuleContext;
import java.util.Stack;
public abstract class MatchPatternDualVisitor<T, S> extends MatchPatternBaseVisitor<T> {
private Stack<S> stack = new Stack<>();
public final T accept(ParserRuleContext ctx, S arg) {
stack.push(arg);
T t = ctx.accept(this);
stack.pop();
return t;
}
@Override
public T visitSequentAnywhere(MatchPatternParser.SequentAnywhereContext ctx) {
return visitSequentAnywhere(ctx, stack.peek());
}
public abstract T visitSequentAnywhere(MatchPatternParser.SequentAnywhereContext ctx, S peek);
@Override
public T visitSequentArrow(MatchPatternParser.SequentArrowContext ctx) {
return visitSequentArrow(ctx, stack.peek());
}
public abstract T visitSequentArrow(MatchPatternParser.SequentArrowContext ctx, S peek);
@Override
public T visitQuantForm(MatchPatternParser.QuantFormContext ctx) {
return visitQuantForm(ctx, stack.peek());
}
public abstract T visitQuantForm(MatchPatternParser.QuantFormContext ctx, S peek);
@Override
public final T visitSemiSeqPattern(MatchPatternParser.SemiSeqPatternContext ctx) {
return visitSemiSeqPattern(ctx, stack.peek());
}
protected abstract T visitSemiSeqPattern(MatchPatternParser.SemiSeqPatternContext ctx, S peek);
@Override
public T visitNumber(MatchPatternParser.NumberContext ctx) {
return visitNumber(ctx, stack.peek());
}
@Override
public final T visitDontCare(MatchPatternParser.DontCareContext ctx) {
return visitDontCare(ctx, stack.peek());
}
public abstract T visitDontCare(MatchPatternParser.DontCareContext ctx, S peek);
/*@Override
public final T visitStartDontCare(MatchPatternParser.StarDontCareContext ctx) {
return visitStartDontCare(ctx, stack.peek());
}
protected abstract T visitStartDontCare(MatchPatternParser.StartDontCareContext ctx, S peek);
*/
@Override
public final T visitSchemaVar(MatchPatternParser.SchemaVarContext ctx) {
return visitSchemaVar(ctx, stack.peek());
}
protected abstract T visitSchemaVar(MatchPatternParser.SchemaVarContext ctx, S peek);
@Override
public final T visitFunction(MatchPatternParser.FunctionContext ctx) {
return visitFunction(ctx, stack.peek());
}
@Override
public final T visitAnywhere(MatchPatternParser.AnywhereContext ctx) {
return visitAnywhere(ctx, stack.peek());
}
protected abstract T visitAnywhere(MatchPatternParser.AnywhereContext ctx, S peek);
protected abstract T visitFunction(MatchPatternParser.FunctionContext ctx, S peek);
protected abstract T visitNumber(MatchPatternParser.NumberContext ctx, S peek);
@Override
public T visitPlusMinus(MatchPatternParser.PlusMinusContext ctx) {
return visitPlusMinus(ctx, stack.peek());
}
protected abstract T visitPlusMinus(MatchPatternParser.PlusMinusContext ctx, S peek);
@Override
public T visitMult(MatchPatternParser.MultContext ctx) {
return visitMult(ctx, stack.peek());
}
protected abstract T visitMult(MatchPatternParser.MultContext ctx, S peek);
@Override
public T visitComparison(MatchPatternParser.ComparisonContext ctx) {
return visitComparison(ctx, stack.peek());
}
protected abstract T visitComparison(MatchPatternParser.ComparisonContext ctx, S peek);
@Override
public T visitOr(MatchPatternParser.OrContext ctx) {
return visitOr(ctx, stack.peek());
}
protected abstract T visitOr(MatchPatternParser.OrContext ctx, S peek);
@Override
public T visitExprNot(MatchPatternParser.ExprNotContext ctx) {
return visitExprNot(ctx, stack.peek());
}
public abstract T visitExprNot(MatchPatternParser.ExprNotContext ctx, S peek);
@Override
public T visitExprNegate(MatchPatternParser.ExprNegateContext ctx) {
return visitExprNegate(ctx, stack.peek());
}
public abstract T visitExprNegate(MatchPatternParser.ExprNegateContext ctx, S peek);
@Override
public T visitExprParen(MatchPatternParser.ExprParenContext ctx) {
return visitExprParen(ctx, stack.peek());
}
public abstract T visitExprParen(MatchPatternParser.ExprParenContext ctx, S peek);
@Override
public T visitImpl(MatchPatternParser.ImplContext ctx) {
return visitImpl(ctx, stack.peek());
}
protected abstract T visitImpl(MatchPatternParser.ImplContext ctx, S peek);
@Override
public T visitDivMod(MatchPatternParser.DivModContext ctx) {
return visitDivMod(ctx, stack.peek());
}
protected abstract T visitDivMod(MatchPatternParser.DivModContext ctx, S peek);
@Override
public T visitAnd(MatchPatternParser.AndContext ctx) {
return visitAnd(ctx, stack.peek());
}
protected abstract T visitAnd(MatchPatternParser.AndContext ctx, S peek);
@Override
public T visitXor(MatchPatternParser.XorContext ctx) {
return visitXor(ctx, stack.peek());
}
protected abstract T visitXor(MatchPatternParser.XorContext ctx, S peek);
@Override
public T visitEquality(MatchPatternParser.EqualityContext ctx) {
return visitEquality(ctx, stack.peek());
}
protected abstract T visitEquality(MatchPatternParser.EqualityContext ctx, S peek);
@Override
public T visitEquivalence(MatchPatternParser.EquivalenceContext ctx) {
return visitEquivalence(ctx, stack.peek());
}
protected abstract T visitEquivalence(MatchPatternParser.EquivalenceContext ctx, S peek);
}
package edu.kit.iti.formal.psdbg.termmatcher;
import de.uka.ilkd.key.java.Services;
import de.uka.ilkd.key.logic.Semisequent;
import de.uka.ilkd.key.logic.Sequent;
import de.uka.ilkd.key.logic.Term;
import de.uka.ilkd.key.parser.DefaultTermParser;
import de.uka.ilkd.key.parser.ParserException;
import edu.kit.iti.formal.psdbg.termmatcher.MatchPatternLexer;
import edu.kit.iti.formal.psdbg.termmatcher.MatchPatternParser;
import edu.kit.iti.formal.psdbg.termmatcher.mp.MatchPathFacade;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.StringReader;
/**
* A facade for capturing everything we want to do with matchers.
*
* @author Alexander Weigl
* @author S.Grebing
*/
public class MatcherFacade {
private static Logger logger = LogManager.getLogger(MatcherFacade.class);
public static Matchings matches(String pattern, Term keyTerm, Services services) {
MatcherImpl matcher = new MatcherImpl(services);
matcher.setCatchAll(false);
MatchPatternParser mpp = getParser(pattern);
MatchPatternParser.TermPatternContext ctx = mpp.termPattern();
return matcher.accept(ctx, MatchPathFacade.createRoot(keyTerm));
}
/**
* Returns a {@link MatchPatternParser} for the given input pattern.
*
* @param pattern
* @return
*/
public static MatchPatternParser getParser(String pattern) {
return getParser(CharStreams.fromString(pattern));
}
public static MatchPatternParser getParser(CharStream stream) {
return new MatchPatternParser(new CommonTokenStream(new MatchPatternLexer(stream)));
}
/**
* Match a semisequent against a sequent
*
* @param pattern Semisequent pattern e.g. f(x), f(x)
* @param semiSeq Concrete KeY Semisequent
* @param catchAll
* @param services
* @return Matchings
*/
public static Matchings matches(String pattern, Semisequent semiSeq, boolean catchAll, Services services) {
MatchPatternParser mpp = getParser(pattern);
MatchPatternParser.SemiSeqPatternContext ctx = mpp.semiSeqPattern();
MatcherImpl matcher = new MatcherImpl(services);
matcher.setCatchAll(catchAll);
Matchings m = matcher.accept(ctx, MatchPathFacade.createRoot(semiSeq));
return m;
}
/**
* Match a sequent pattern against a concrete sequent
*
* @param pattern e.g., f(x) ==> f(y)
* @param sequent
* @param services
* @return
*/
public static Matchings matches(String pattern, Sequent sequent, boolean catchAll, Services services) {
MatchPatternParser mpp = getParser(pattern);
MatchPatternParser.SequentPatternContext ctx = mpp.sequentPattern();
logger.info("Matching \n" + pattern + "\n" + sequent.toString());
if (mpp.getNumberOfSyntaxErrors() != 0) {
logger.info("Invalid pattern syntax '{}' no matches returned.", pattern);
return new Matchings();
}
MatcherImpl matcher = new MatcherImpl(services);
matcher.setCatchAll(catchAll);
Matchings m = matcher.accept(ctx, MatchPathFacade.create(sequent));
return m;
}
/**
* Like {@link #matches(String, Sequent, Services)} but allows to use
* MatcherImpl#isCatchAll.
*
* @param pattern
* @param sequent
* @param services
* @return
*/
public static Matchings matches(String pattern, Sequent sequent, Services services) {
return matches(pattern, sequent, true, services);
}
}
package edu.kit.iti.formal.psdbg.termmatcher;
import com.google.common.collect.Sets;
import de.uka.ilkd.key.java.Services;
import de.uka.ilkd.key.logic.*;
import de.uka.ilkd.key.logic.op.QuantifiableVariable;
import edu.kit.iti.formal.psdbg.termmatcher.MatchPatternLexer;
import edu.kit.iti.formal.psdbg.termmatcher.MatchPatternParser;
import edu.kit.iti.formal.psdbg.termmatcher.mp.MatchPath;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Token;
import org.key_project.util.collection.ImmutableArray;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static edu.kit.iti.formal.psdbg.termmatcher.mp.MatchPathFacade.*;
/**
* Matchpattern visitor visits the matchpatterns of case-statements
*
* @author Alexander Weigl
* @author S. Grebing
*/
@RequiredArgsConstructor
class MatcherImpl extends MatchPatternDualVisitor<Matchings, MatchPath> {
static final Matchings NO_MATCH = new Matchings();
static final Matchings EMPTY_MATCH = Matchings.singleton("EMPTY_MATCH", null);
static final Map<String, MatchPath> EMPTY_VARIABLE_ASSIGNMENT = EMPTY_MATCH.first();
@Getter
private final Services services;
Random random = new Random(42L);
/*
* Reduce two matchinfos
*
* @param m1
* @param m2
* @return
*
protected static List<MatchInfo> reduceConform(List<MatchInfo> m1, List<MatchInfo> m2) {
if (m1 == null || m2 == null) return null; //"null" is equivalent to NO_MATCH
List<MatchInfo> res = new ArrayList<>();
boolean oneMatch = false;
for (MatchInfo minfo1 : m1) {
for (MatchInfo minfo2 : m2) {
Set<SequentFormula> intersection = new HashSet<>(minfo1.matchedForms);
intersection.retainAll(minfo2.matchedForms);
if (!intersection.isEmpty()) continue;
HashMap<String, MatchPath> h3 = reduceConform(minfo1.matching, minfo2.matching);
if (h3 != null) {
Set<SequentFormula> union = new HashSet<>(minfo1.matchedForms);
union.addAll(minfo2.matchedForms);
res.add(new MatchInfo(h3, union));
oneMatch = true;
}
}
}
return oneMatch ? res : null;
}
*/
private List<Integer> currentPosition = new ArrayList<>();
/**
* If true, we assume every term in the pattern has a binder.
* The binding names are generated.
*
* @see #handleBindClause(MatchPatternParser.BindClauseContext, MatchPath, Matchings)
*/
@Getter
@Setter
private boolean catchAll = false;
private static HashMap<String, MatchPath> reduceConform(Map<String, MatchPath> h1, Map<String, MatchPath> h2) {
HashMap<String, MatchPath> listOfElementsofH1 = new HashMap<>(h1);
for (String s1 : listOfElementsofH1.keySet()) {
if (!s1.equals("EMPTY_MATCH") && h2.containsKey(s1)) {
if (h2.get(s1) instanceof MatchPath.MPQuantifiableVariable &&
!((QuantifiableVariable) h2.get(s1).getUnit()).name().toString().equals(h1.get(s1).toString())) {
return null;
}
if (h1.get(s1) instanceof MatchPath.MPQuantifiableVariable &&
!((QuantifiableVariable) h1.get(s1).getUnit()).name().toString().equals(h2.get(s1).toString())) {
return null;
}
if (!h2.get(s1).equals(h1.get(s1))) {
return null;
}
}
}
listOfElementsofH1.putAll(h2);
return listOfElementsofH1;
}
/**
* Reduce the matchings by eliminating non-compatible matchings.
* For example:
* m1: <X, f(y)>, <Y,g> and m2: <X, g> <Y, f(x)>
*
* @param m1
* @param m2
* @return
*/
protected static Matchings reduceConform(Matchings m1, Matchings m2) {
//shortcuts
if (m1 == NO_MATCH || m2 == NO_MATCH) return NO_MATCH;
if (m1 == EMPTY_MATCH) return m2;
if (m2 == EMPTY_MATCH) return m1;
Matchings m3 = new Matchings();
boolean oneMatch = false;
for (Map<String, MatchPath> h1 : m1) {
for (Map<String, MatchPath> h2 : m2) {
Map<String, MatchPath> h3 = reduceConform(h1, h2);
if (h3 != null) {
//m3.add(h3);
if (!m3.contains(h3)) m3.add(h3);
oneMatch = true;
}
}
}
return oneMatch ? m3 : NO_MATCH;
}
/**
* Transform a number term into an int value.
* <p>
* i.e. Z(1(2(3(#)))) ==> 123
*
* @param zTerm
* @return
*/
public static int transformToNumber(Term zTerm) {
List<Integer> integ = MatcherImpl.transformHelper(new ArrayList<>(), zTerm);
int dec = 10;
int output = integ.get(0);
for (int i = 1; i < integ.size(); i++) {
Integer integer = integ.get(i);
output += integer * dec;
dec = dec * 10;
}
return output;
}
private static List<Integer> transformHelper(List<Integer> l, Term sub) {
if (sub.op().name().toString().equals("#")) {
return l;
} else {
l.add(Integer.parseUnsignedInt(sub.op().name().toString()));
return transformHelper(l, sub.sub(0));
}
}
/**
* Visit '_'
*
* @param ctx