Skip to content

Commit

Permalink
FSM.Matched
Browse files Browse the repository at this point in the history
  • Loading branch information
Pastor committed Dec 23, 2024
1 parent 0b312bf commit 18b6b51
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ static Input of(String text) {

Input copy();

boolean hasNext();

record Marker(int pos) {
}

final class StringInput implements Input {
private final char[] chars;
private int it;

private StringInput(String text) {
public StringInput(String text) {
this.chars = text.toCharArray();
}

Expand Down Expand Up @@ -63,5 +65,10 @@ public void next() {
public Input copy() {
return new StringInput(chars, it);
}

@Override
public boolean hasNext() {
return it < chars.length;
}
}
}
30 changes: 30 additions & 0 deletions vol8/src/main/java/ru/mifi/practice/vol8/regexp/machine/Match.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ru.mifi.practice.vol8.regexp.machine;

import ru.mifi.practice.vol8.regexp.tree.Tree;

public interface Match {
boolean match(String text);

final class Machine implements Match {
private final State state;

public Machine(Tree tree) {
MachineGenerator generator = new MachineGenerator();
tree.visit(generator);
this.state = generator.getState();
}

@Override
public boolean match(String text) {
Input input = new Input.StringInput(text);
return match(state, input);
}

private static boolean match(State state, Input input) {
if (state.accept(input)) {
return state.match(input);
}
return false;
}
}
}
163 changes: 163 additions & 0 deletions vol8/src/main/java/ru/mifi/practice/vol8/regexp/machine/State.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ protected void setNext(State next) {
this.next = next;
}

public boolean accept(Input input) {
return false;
}

@Override
public String toString() {
if (next != null) {
Expand All @@ -31,6 +35,10 @@ public String toString() {
return "";
}

public boolean match(Input input) {
return false;
}

public static final class Symbol extends State {
final char symbol;

Expand All @@ -39,6 +47,23 @@ private Symbol(Manager manager, int index, Character symbol) {
this.symbol = symbol;
}

@Override
public boolean accept(Input input) {
return input.peek().map(c -> c == symbol).orElse(false);
}

@Override
public boolean match(Input input) {
if (accept(input)) {
input.next();
if (next != null && next.accept(input)) {
return next.match(input);
}
return true;
}
return input.hasNext();
}

@Override
public void visit(Visitor visitor) {
visitor.visit(this, next);
Expand Down Expand Up @@ -72,6 +97,23 @@ private Sequence(Manager manager, int index) {
super(manager, index);
}

@Override
public boolean accept(Input input) {
return start.accept(input);
}

@Override
public boolean match(Input input) {
if (accept(input)) {
boolean matched = start.match(input);
if (matched && next != null && next.accept(input)) {
return next.match(input);
}
return matched;
}
return false;
}

@Override
public void visit(Visitor visitor) {
visitor.visit(this, start);
Expand All @@ -86,6 +128,7 @@ void add(State state) {
if (start == null) {
start = state;
} else {
state.parent = last;
last.setNext(state);
}
last = state;
Expand All @@ -101,6 +144,11 @@ public static final class Epsilon extends Parallel {
private Epsilon(Manager manager, int index) {
super(manager, index);
}

@Override
public boolean accept(Input input) {
return true;
}
}

public static class Parallel extends State {
Expand All @@ -110,6 +158,36 @@ private Parallel(Manager manager, int index) {
super(manager, index);
}

@Override
public boolean accept(Input input) {
List<State> accepted = getAccepted(input);
return !accepted.isEmpty();
}

@Override
public boolean match(Input input) {
if (accept(input)) {
List<State> accepted = getAccepted(input);
for (State next : accepted) {
Input copy = input.copy();
boolean accept = next.match(copy);
//TODO: Реализовать для всех оставшихся путей
if (accept) {
if (this.next != null && next.accept(copy)) {
return next.match(copy);
}
return true;
}
}
return false;
}
return super.match(input);
}

private List<State> getAccepted(Input input) {
return states.stream().filter(c -> c.accept(input)).toList();
}

@Override
public void visit(Visitor visitor) {
for (State state : states) {
Expand Down Expand Up @@ -152,6 +230,30 @@ private NoneOrOne(Manager manager, int index, State state) {
super(manager, index, state);
}

//FIXME: Проверить правильность
@Override
public boolean accept(Input input) {
return true;
}

@Override
public boolean match(Input input) {
if (accept(input)) {
Input copy = input.copy();
if (state.accept(copy)) {
boolean matched = state.match(copy);
if (matched && next != null && next.accept(copy)) {
return next.match(input);
}
return matched;
} else if (next != null && next.accept(copy)) {
return next.match(input);
}
return input.hasNext();
}
return false;
}

@Override
public void visit(Visitor visitor) {
visitor.visit(this, state);
Expand All @@ -173,6 +275,39 @@ private NoneOrMore(Manager manager, int index, State state) {
super(manager, index, state);
}

@Override
public boolean accept(Input input) {
return true;
}

@Override
public boolean match(Input input) {
if (accept(input)) {
Input copy = input.copy();
if (state.accept(copy)) {
boolean matched = state.match(copy);
if (matched) {
Input prev = copy;
while (matched) {
prev = copy.copy();
matched = state.match(copy);
}
copy = prev;
if (next != null && next.accept(copy)) {
return next.match(copy);
}
}
if (next != null && next.accept(copy)) {
return next.match(copy);
}
} else if (next != null && next.accept(copy)) {
return next.match(copy);
}
return input.hasNext();
}
return false;
}

@Override
public void visit(Visitor visitor) {
visitor.visit(this, state);
Expand All @@ -194,6 +329,34 @@ private OneOrMore(Manager manager, int index, State state) {
super(manager, index, state);
}

@Override
public boolean accept(Input input) {
return state.accept(input);
}

@Override
public boolean match(Input input) {
if (accept(input)) {
Input copy = input.copy();
boolean matched = state.match(copy);
if (matched) {
Input prev = copy;
while (matched) {
prev = copy.copy();
matched = state.match(copy);
}
copy = prev;
if (next != null && next.accept(copy)) {
return next.match(copy);
}
}
if (next != null && next.accept(copy)) {
return next.match(copy);
}
}
return false;
}

@Override
public void visit(Visitor visitor) {
visitor.visit(this, state);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ru.mifi.practice.vol8.regexp.machine;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import ru.mifi.practice.vol8.regexp.tree.Tree;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

@DisplayName("Match")
class MatchTest {

protected static Stream<Arguments> patternMatching() {
return Stream.of(
Arguments.of(true, "a", "(a|b*(c?d)+|e)|(of|pt)"),
Arguments.of(true, "e", "(a|b*(c?d)+|e)|(of|pt)"),
Arguments.of(true, "of", "(a|b*(c?d)+|e)|(of|pt)"),
Arguments.of(true, "pt", "(a|b*(c?d)+|e)|(of|pt)"),
Arguments.of(true, "bddd", "(a|b*(c?d)+|e)|(of|pt)"),
Arguments.of(true, "bbbbbd", "(a|b*(c?d)+|e)|(of|pt)"),
Arguments.of(false, "hello", "(a|b*(c?d)+|e)|(of|pt)"),
Arguments.of(false, "bbcdddo", "(a|b*(c?d)+|e)|(of|pt)")
);
}

@Disabled
@ParameterizedTest
@MethodSource("patternMatching")
void match(boolean isMatch, String input, String pattern) {
Tree tree = new Tree.Default(pattern);
Match match = new Match.Machine(tree);
if (isMatch) {
assertTrue(match.match(input));
} else {
assertFalse(match.match(input));
}
}
}

0 comments on commit 18b6b51

Please sign in to comment.