Skip to content

Commit

Permalink
#36. Generate Not Matching String
Browse files Browse the repository at this point in the history
Implementation of Choice and other final steps.
  • Loading branch information
curious-odd-man committed Aug 25, 2020
1 parent 2211ea1 commit a641a16
Show file tree
Hide file tree
Showing 21 changed files with 574 additions and 180 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@

import java.util.Arrays;

public class Choice implements Node {
public class Choice extends Node {

private final Node[] aNodes;

public Choice(Node... nodes) {
public Choice(String pattern, Node... nodes) {
super(pattern);
aNodes = nodes;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@

import com.github.curiousoddman.rgxgen.generator.visitors.NodeVisitor;

public class FinalSymbol implements Node {
public class FinalSymbol extends Node {
private final String aValue;

public FinalSymbol(String value) {
super(value);
aValue = value;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@

import com.github.curiousoddman.rgxgen.generator.visitors.NodeVisitor;

public class Group implements Node {
public class Group extends Node {
private final Node aNode;
private final int aGroupIndex;

public Group(int index, Node node) {
public Group(String pattern, int index, Node node) {
super(pattern);
aNode = node;
aGroupIndex = index;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@

import com.github.curiousoddman.rgxgen.generator.visitors.NodeVisitor;

public class GroupRef implements Node {
public class GroupRef extends Node {
private final int aIndex;

public GroupRef(int index) {
public GroupRef(String pattern, int index) {
super(pattern);
aIndex = index;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@

import com.github.curiousoddman.rgxgen.generator.visitors.NodeVisitor;

public interface Node {
void visit(NodeVisitor visitor);
public abstract class Node {
private final String aPattern;

protected Node(String pattern) {
aPattern = pattern;
}

public abstract void visit(NodeVisitor visitor);

public String getPattern() {
return aPattern;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@

import java.util.regex.Pattern;

public class NotSymbol implements Node {
public class NotSymbol extends Node {
private final Pattern aSubPattern;

// TODO: Parse this pattern always!!
public NotSymbol(String pattern) {
super(pattern);
aSubPattern = Pattern.compile(pattern);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@

import com.github.curiousoddman.rgxgen.generator.visitors.NodeVisitor;

public class Repeat implements Node {
public class Repeat extends Node {
private final Node aNode;
private final int aMin;
private final int aMax;

public static Repeat minimum(Node node, int times) {
return new Repeat(node, times, -1);
public static Repeat minimum(String pattern, Node node, int times) {
return new Repeat(pattern, node, times, -1);
}

public Repeat(Node node, int times) {
this(node, times, times);
public Repeat(String pattern, Node node, int times) {
this(pattern, node, times, times);
}

public Repeat(Node node, int min, int max) {
public Repeat(String pattern, Node node, int min, int max) {
super(pattern);
aNode = node;
aMin = min;
aMax = max;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@

import java.util.Arrays;

public class Sequence implements Node {
public class Sequence extends Node {
private final Node[] aNodes;

public Sequence(Node... nodes) {
public Sequence(String pattern, Node... nodes) {
super(pattern);
aNodes = nodes;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
/**
* Generate Any printable character.
*/
public class SymbolSet implements Node {
public class SymbolSet extends Node {
private static final String[] ALL_SYMBOLS = new String[127 - 32];

public static String[] getAllSymbols() {
Expand All @@ -37,9 +37,11 @@ public static String[] getAllSymbols() {
private static final int DEL_ASCII_CODE = 127; // Bound for printable characters in ASCII table

static {
StringBuilder sb = new StringBuilder("[");
for (int i = SPACE_ASCII_CODE; i < DEL_ASCII_CODE; ++i) {
ALL_SYMBOLS[i - SPACE_ASCII_CODE] = Character.valueOf((char) i)
.toString();
Character character = (char) i;
ALL_SYMBOLS[i - SPACE_ASCII_CODE] = character.toString();
sb.append(character);
}
}

Expand Down Expand Up @@ -98,15 +100,15 @@ public String toString() {
* Symbol set containing all symbols
*/
public SymbolSet() {
this(ALL_SYMBOLS.clone(), TYPE.POSITIVE);
this(".", ALL_SYMBOLS.clone(), TYPE.POSITIVE);
}

public SymbolSet(String[] symbols, TYPE type) {
this(Collections.emptyList(), symbols, type);
public SymbolSet(String pattern, String[] symbols, TYPE type) {
this(pattern, Collections.emptyList(), symbols, type);
}

public SymbolSet(Collection<SymbolRange> symbolRanges, TYPE type) {
this(symbolRanges, Util.ZERO_LENGTH_STRING_ARRAY, type);
public SymbolSet(String pattern, Collection<SymbolRange> symbolRanges, TYPE type) {
this(pattern, symbolRanges, Util.ZERO_LENGTH_STRING_ARRAY, type);
}

/**
Expand All @@ -116,7 +118,8 @@ public SymbolSet(Collection<SymbolRange> symbolRanges, TYPE type) {
* @param symbols symbols to include/exclude
* @param type POSITIVE - include, NEGATIVE - exclude
*/
public SymbolSet(Collection<SymbolRange> symbolRanges, String[] symbols, TYPE type) {
public SymbolSet(String pattern, Collection<SymbolRange> symbolRanges, String[] symbols, TYPE type) {
super(pattern);
List<String> initial = type == TYPE.NEGATIVE
? new ArrayList<>(Arrays.asList(ALL_SYMBOLS)) // First we need to add all, later we remove unnecessary
: new ArrayList<>(ALL_SYMBOLS.length); // Most probably it will be enough.
Expand Down Expand Up @@ -159,4 +162,8 @@ public String[] getSymbols() {
public String toString() {
return "SymbolSet{" + Arrays.toString(aSymbols) + '}';
}

public boolean isAnyChar() {
return Arrays.deepEquals(aSymbols, ALL_SYMBOLS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public interface NodeVisitor {

void visit(Sequence node);

void visit(NotSymbol notSymbol);
void visit(NotSymbol node);

void visit(GroupRef groupRef);
void visit(GroupRef node);

void visit(Group group);
void visit(Group node);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.github.curiousoddman.rgxgen.parsing.dflt.DefaultTreeBuilder;

import java.util.Random;
import java.util.regex.Pattern;

public class NotMatchingGenerationVisitor extends GenerationVisitor {
private static final String[] allSymbols = SymbolSet.getAllSymbols();
Expand All @@ -34,26 +35,65 @@ public NotMatchingGenerationVisitor(Random random) {

@Override
public void visit(SymbolSet node) {
super.visit(new SymbolSet(node.getSymbols(), SymbolSet.TYPE.NEGATIVE));
// There is only one way to generate not matching for any character - is to not generate anything
if (!node.isAnyChar()) {
String pattern = node.getPattern();
super.visit(new SymbolSet("[^" + pattern.substring(1), node.getSymbols(), SymbolSet.TYPE.NEGATIVE));
}
}

@Override
public void visit(Choice node) {
throw new RuntimeException("not implemented");
Node[] nodes = node.getNodes();
int pos = aStringBuilder.length();
// We need to add existing group values, so that we could later use it in matching pattern
StringBuilder groupsBuilder = new StringBuilder();
StringBuilder valuePrefixBuilder = new StringBuilder();
for (int i = 0; i < aGroupValues.size(); i++) {
String s = aGroupValues.get(i);
groupsBuilder.append('(')
.append(s)
.append(')');
valuePrefixBuilder.append(s);
}

// Add groups values to pattern - in case there are group refs used inside the node.getPattern()
Pattern pattern = Pattern.compile(groupsBuilder + node.getPattern());

do {
aStringBuilder.delete(pos, Integer.MAX_VALUE);
int i = aRandom.nextInt(nodes.length);
nodes[i].visit(this);
// To match group values along with generated values - we need to prepend groups values before the generated
} while (pattern.matcher(valuePrefixBuilder + aStringBuilder.substring(pos))
.matches());
}

@Override
public void visit(FinalSymbol node) {
String nodeValue = node.getValue();
StringBuilder builder = new StringBuilder(nodeValue.length());
if (nodeValue.isEmpty()) {
aStringBuilder.append(allSymbols[aRandom.nextInt(allSymbols.length)].charAt(0));
} else {
StringBuilder builder = new StringBuilder(nodeValue.length());
do {
builder.delete(0, Integer.MAX_VALUE);
nodeValue.chars()
.map(c -> allSymbols[aRandom.nextInt(allSymbols.length)].charAt(0))
.forEachOrdered(c -> builder.append((char) c));
} while (nodeValue.equals(builder.toString()));
aStringBuilder.append(builder);
}
}

do {
builder.delete(0, builder.length());
nodeValue.chars()
.map(c -> allSymbols[aRandom.nextInt(allSymbols.length)].charAt(0))
.forEachOrdered(c -> builder.append((char) c));
} while (nodeValue.equals(builder.toString()));
aStringBuilder.append(builder);
@Override
public void visit(Repeat node) {
// Zero length repeat will match pattern despite what node is repeated.
if (node.getMin() == 0) {
super.visit(new Repeat(node.getPattern(), node.getNode(), 1, node.getMax()));
} else {
super.visit(node);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,8 @@ public void setBound(int offset) {
public int pos() {
return aCurrentIndex - 1;
}

public String substringToCurrPos(int pos) {
return aValue.substring(pos, aCurrentIndex);
}
}
Loading

0 comments on commit a641a16

Please sign in to comment.