diff --git a/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/fsa/FSA.java b/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/fsa/FSA.java index 4ff443c94..77f7aab7f 100644 --- a/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/fsa/FSA.java +++ b/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/fsa/FSA.java @@ -23,7 +23,6 @@ import it.unive.lisa.util.numeric.IntInterval; import it.unive.lisa.util.numeric.MathNumber; import it.unive.lisa.util.numeric.MathNumberConversionException; - import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -421,11 +420,34 @@ public Satisfiability containsChar(char c) throws SemanticException { return Satisfiability.NOT_SATISFIED; } + /** + * Yields a new FSA where trailing and leading whitespaces have been removed + * from {@code this}. + * + * @return a new FSA where trailing and leading whitespaces have been + * removed from {@code this} + */ public FSA trim() { + if (isBottom() || isTop()) + return this; return new FSA(this.a.trim()); } - + + /** + * Yields a new FSA instance recognizing each string of {@code this} + * automaton repeated k-times, with k belonging to {@code intv}. + * + * @param i the interval + * + * @return a new FSA instance recognizing each string of {@code this} + * automaton repeated k-times, with k belonging to {@code intv} + * + * @throws MathNumberConversionException if {@code intv} is iterated but is + * not finite + */ public FSA repeat(Interval i) throws MathNumberConversionException { + if (isBottom() || isTop()) + return this; return new FSA(this.a.repeat(i)); } } diff --git a/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/fsa/SimpleAutomaton.java b/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/fsa/SimpleAutomaton.java index 507fbb3e8..29ca79951 100644 --- a/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/fsa/SimpleAutomaton.java +++ b/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/fsa/SimpleAutomaton.java @@ -187,6 +187,13 @@ public SimpleAutomaton replace(SimpleAutomaton toReplace, SimpleAutomaton str) t return result; } + /** + * Yields a new automaton where leading whitespaces have been removed from + * {@code this}. + * + * @return a new automaton where leading whitespaces have been removed from + * {@code this} + */ public SimpleAutomaton trimLeft() { SimpleAutomaton result = copy(); @@ -218,6 +225,13 @@ public SimpleAutomaton trimLeft() { return result; } + /** + * Yields a new automaton where trailing whitespaces have been removed from + * {@code this}. + * + * @return a new automaton where trailing whitespaces have been removed from + * {@code this} + */ public SimpleAutomaton trimRight() { SimpleAutomaton result = copy(); @@ -257,10 +271,29 @@ public SimpleAutomaton trimRight() { return result; } + /** + * Yields a new automaton where leading and trailing whitespaces have been + * removed from {@code this}. + * + * @return a new automaton where leading trailing whitespaces have been + * removed from {@code this} + */ public SimpleAutomaton trim() { - return trimLeft().trimRight(); + return this.toRegex().trimRight().simplify().trimLeft().simplify().toAutomaton(this); } + /** + * Yields a new automaton instance recognizing each string of {@code this} + * automaton repeated k-times, with k belonging to {@code intv}. + * + * @param i the interval + * + * @return a new automaton instance recognizing each string of {@code this} + * automaton repeated k-times, with k belonging to {@code intv} + * + * @throws MathNumberConversionException if {@code intv} is iterated but is + * not finite + */ public SimpleAutomaton repeat(Interval i) throws MathNumberConversionException { if (equals(emptyString())) return this; @@ -326,7 +359,7 @@ else if (hasCycle()) return emptyLanguage(); } - public SimpleAutomaton auxRepeat(IntInterval i, State currentState, SortedSet> delta, + private SimpleAutomaton auxRepeat(IntInterval i, State currentState, SortedSet> delta, SimpleAutomaton result) throws MathNumberConversionException { if (currentState.isFinal()) { @@ -367,7 +400,7 @@ public SimpleAutomaton auxRepeat(IntInterval i, State currentState, SortedSet connectOn, boolean b) { + private SimpleAutomaton connectAutomaton(SimpleAutomaton second, SortedSet connectOn, boolean b) { SortedSet> delta = new TreeSet<>(); SortedSet states = new TreeSet<>(); HashMap firstMapping = new HashMap<>(); @@ -423,9 +456,11 @@ public SimpleAutomaton connectAutomaton(SimpleAutomaton second, SortedSet secondMapping.remove(second.getInitialState()); for (Transition t : second.getTransitions()) { - if (t.getSource().equals(second.getInitialState()) || t.getDestination().equals(second.getInitialState()) || !secondMapping.containsKey(t.getSource()) || !secondMapping.containsKey(t.getDestination())) + if (t.getSource().equals(second.getInitialState()) + || t.getDestination().equals(second.getInitialState()) + || !secondMapping.containsKey(t.getSource()) || !secondMapping.containsKey(t.getDestination())) continue; - + if (!t.getSource().isInitial() && !t.getDestination().isInitial()) { delta.add(new Transition<>(secondMapping.get(t.getSource()), secondMapping.get(t.getDestination()), t.getSymbol())); @@ -445,9 +480,9 @@ public SimpleAutomaton connectAutomaton(SimpleAutomaton second, SortedSet delta.add(new Transition<>(firstMapping.get(s), secondMapping.get(t.getDestination()), t.getSymbol())); } - } + } } - + return new SimpleAutomaton(states, delta); } } \ No newline at end of file diff --git a/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/tarsis/StringReplacer.java b/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/tarsis/StringReplacer.java index 69f9ac7a0..2229c9873 100644 --- a/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/tarsis/StringReplacer.java +++ b/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/tarsis/StringReplacer.java @@ -133,7 +133,6 @@ private RegexAutomaton emptyStringReplace(RegexAutomaton str) { Map mapper = new HashMap<>(); origin.getStates().forEach(s -> mapper.put(s, new State(s.getId(), s.isInitial(), false))); states.addAll(mapper.values()); - Function maker = s -> new State(counter.getAndIncrement(), false, false); diff --git a/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/tarsis/Tarsis.java b/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/tarsis/Tarsis.java index ea2591e7a..723223a80 100644 --- a/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/tarsis/Tarsis.java +++ b/lisa/lisa-analyses/src/main/java/it/unive/lisa/analysis/string/tarsis/Tarsis.java @@ -356,7 +356,7 @@ public Tarsis concat(Tarsis other) { public Tarsis replace(Tarsis search, Tarsis repl) { if (isBottom() || search.isBottom() || repl.isBottom()) return bottom(); - + try { return new Tarsis(this.a.replace(search.a, repl.a)); } catch (CyclicAutomatonException e) { @@ -423,7 +423,9 @@ public Satisfiability containsChar(char c) throws SemanticException { * not finite */ public Tarsis repeat(Interval intv) throws MathNumberConversionException { - if (intv.isTop() || a.hasCycle()) + if (isBottom()) + return this; + else if (intv.isTop() || a.hasCycle()) return new Tarsis(a.star()); else if (intv.interval.isFinite()) { if (intv.interval.isSingleton()) @@ -447,6 +449,9 @@ else if (intv.interval.isFinite()) { * have been removed from {@code this} */ public Tarsis trim() { + if (isBottom() || isTop()) + return this; + return new Tarsis(this.a.trim()); } } diff --git a/lisa/lisa-sdk/src/main/java/it/unive/lisa/util/datastructures/regex/RegularExpression.java b/lisa/lisa-sdk/src/main/java/it/unive/lisa/util/datastructures/regex/RegularExpression.java index a876aef12..32194cfc0 100644 --- a/lisa/lisa-sdk/src/main/java/it/unive/lisa/util/datastructures/regex/RegularExpression.java +++ b/lisa/lisa-sdk/src/main/java/it/unive/lisa/util/datastructures/regex/RegularExpression.java @@ -452,6 +452,13 @@ public String toString() { */ public abstract RegularExpression[] explode(); + /** + * Checks whether this regular expression recognize a string made just of + * whitespaces. + * + * @return {@true} if this regular expression recognize a string made just + * of whitespaces, {@code false} otherwise. + */ protected abstract boolean readsWhiteSpaceString(); /**