Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/main/java/ca/l5/expandingdev/jsgf/Grammar.java
Original file line number Diff line number Diff line change
Expand Up @@ -737,8 +737,12 @@ public static Grammar parseGrammarFromString(String s) {
ruleName = ruleName.trim();
Expansion exp = Grammar.parseExpansionsFromString(parts[1]);
grammar.addRule(new Rule(ruleName, false, exp));
} else if (statement.startsWith("import <")) {
statement = statement.replaceFirst("import ", "");
statement = statement.replaceAll("<|>", "");
String importName = statement.trim();
grammar.addImport(importName);
}

}
} catch (Exception e) {
e.printStackTrace();
Expand Down
256 changes: 256 additions & 0 deletions src/main/java/ca/l5/expandingdev/jsgf/GrammarGroup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
package ca.l5.expandingdev.jsgf;

import java.util.*;

public class GrammarGroup {
private Map<String, Grammar> grammarMap;

public GrammarGroup() {
grammarMap = new HashMap<>();
}

public void addGrammar(Grammar grammar) {
grammarMap.put(grammar.name, grammar);
}

public boolean matchesRule(Grammar grammar, String ruleName, String test) {
try {
Rule rule = grammar.getRule(ruleName); // Try to get the rule
return this.matchesRule(grammar, rule, test);
}
catch (RuntimeException exception) {
return false;
}
}

public boolean matchesRule(Grammar grammar, Rule rule, String test) {
String[] words = test.split(" ");
List<MatchInfo> m1 = this.getMatchingExpansions(grammar, rule.getChildExpansion(), words, 0);
int matchCount = 0;
for (MatchInfo mi2 : m1) {
if (!mi2.getMatchingStringSection().equals("")) {
matchCount++;
}
}
return matchCount == words.length; // Must match all the words!
}

private List<MatchInfo> getMatchingExpansions(
Grammar grammar, Expansion expansion, String[] words, int wordPosition) {
List<MatchInfo> matchList = new ArrayList<>();
if (expansion instanceof Token) {
Token token = (Token) expansion;
if (token.getText().equals(words[wordPosition])) {
String matchedPart = words[wordPosition];
matchList.add(new MatchInfo(token, words[wordPosition]));
}
} else if (expansion instanceof RuleReference) {
RuleReference ref = (RuleReference) expansion;
try {
// Try to get the rule
Rule rule = this.getRule(grammar, ref.getRuleName());
Grammar grammarReference = grammar;
if (rule == null) {
// rule reference may be import rule
Grammar importGrammar = findImportGrammarByRule(grammar, ref.getRuleName());
if (importGrammar != null) {
rule = this.getRule(importGrammar, ref.getRuleName());
grammarReference = importGrammar;
}
}
if (rule == null) {
throw new RuntimeException("Could not find rule by name: " + ref.getRuleName());
}
List<MatchInfo> matchingExpansions = this.getMatchingExpansions(
grammarReference, rule.getChildExpansion(), words, wordPosition);
if (matchingExpansions.size() != 0) {
// Need to mark that the rule was matched!
matchList.add(new MatchInfo(expansion, ""));
matchList.addAll(matchingExpansions);
}
} catch (RuntimeException exception) {
// Rule couldnt be found
}
} else if (expansion instanceof OptionalGrouping) {
OptionalGrouping optionalGrouping = (OptionalGrouping) expansion;
List<MatchInfo> matchingExpansions = this.getMatchingExpansions(
grammar, optionalGrouping.getChildExpansion(), words, wordPosition);
if (matchingExpansions.size() == 0) {
// Optional, so it can match. Used for sequences
// matchList.add(new MatchInfo(e, ""));
} else {
//Matches
matchList.add(new MatchInfo(expansion, ""));
matchList.addAll(this.getMatchingExpansions(
grammar, optionalGrouping.getChildExpansion(), words, wordPosition));
}
} else if (expansion instanceof RequiredGrouping) {
RequiredGrouping requiredGrouping = (RequiredGrouping) expansion;
List<MatchInfo> matchingExpansions = (this.getMatchingExpansions(grammar, requiredGrouping.getChildExpansion(), words, wordPosition));

if (matchingExpansions.size() != 0) {
matchList.add(new MatchInfo(expansion, ""));
matchList.addAll(matchingExpansions);
}
} else if (expansion instanceof Tag) {
Tag tag = (Tag) expansion;
List<MatchInfo> matchingExpansions = this.getMatchingExpansions(
grammar, tag.getChildExpansion(), words, wordPosition);
if (matchingExpansions.size() != 0) {
matchList.add(new MatchInfo(expansion,""));
matchList.addAll(matchingExpansions); // Found a match! Add it to the list
}
} else if (expansion instanceof AlternativeSet) {
AlternativeSet as = (AlternativeSet) expansion;
for (Expansion expansionTmp : as.getChildExpansions()) {
List<MatchInfo> matchingExpansions = this.getMatchingExpansions(
grammar, expansionTmp, words, wordPosition);

if ((expansionTmp instanceof KleeneStar || expansionTmp instanceof OptionalGrouping) &&
matchingExpansions.size() == 0) { // Stupid OptionalGrouping
continue;
}

if (matchingExpansions.size() != 0) {
matchList.add(new MatchInfo(expansion,""));
matchList.addAll(matchingExpansions); // Found a match! Add it to the list
break;
}
}
} else if (expansion instanceof Sequence) {
Sequence seq = (Sequence) expansion;
List<MatchInfo> localMatchList = new ArrayList<>();
int matchedCount = 0;
for (Object object : seq) {
Expansion expansionTemp = (Expansion) object;
List<MatchInfo> m1 = this.getMatchingExpansions(grammar, expansionTemp, words, wordPosition);
if (m1.size() == 0 && (expansionTemp instanceof KleeneStar || expansionTemp instanceof OptionalGrouping)) {
matchedCount++; // Still counts a match
continue;
}

if (m1.size() != 0) {
matchedCount++;
for (MatchInfo localMatch : m1) {
if(!localMatch.getMatchingStringSection().equals("")) {
wordPosition += localMatch.getMatchingStringSection().split(" ").length;
}
}
localMatchList.addAll(m1); // Found a match! Add it to the list
}
else { // Doesn't match! Sequence aborted.
localMatchList.clear();
break;
}

if (wordPosition > words.length - 1) { // Sequence is longer than provided words! Abort!
break;
}
}

if (matchedCount != seq.size()) { // Not all of the required matches were met!
localMatchList.clear();
}

if (localMatchList.size() != 0) {
matchList.add(new MatchInfo(expansion, ""));
matchList.addAll(localMatchList);
}
} else if (expansion instanceof KleeneStar) {
KleeneStar kleeneStar = (KleeneStar) expansion;
boolean done = false;
List<MatchInfo> matchInfoList;
matchList.add(new MatchInfo(expansion, ""));
while(!done) {
if (wordPosition > words.length - 1) {
break;
}
matchInfoList = this.getMatchingExpansions(grammar, kleeneStar.getChildExpansion(), words, wordPosition);
if (matchInfoList.size() == 0) {
// No matches
done = true;
} else {
//Matches
for (MatchInfo mi2 : matchInfoList) {
if(!mi2.getMatchingStringSection().equals("")) {
wordPosition += mi2.getMatchingStringSection().split(" ").length;
}
}
matchList.addAll(matchInfoList);
matchList.add(new MatchInfo(expansion, ""));
}
}
} else if (expansion instanceof PlusOperator) {
PlusOperator plusOperator = (PlusOperator) expansion;
boolean done = false;
List<MatchInfo> matchInfoList;
while(!done) {
if (wordPosition > words.length-1) {
break;
}
matchInfoList = this.getMatchingExpansions(grammar, plusOperator.getChildExpansion(), words, wordPosition);
if (matchInfoList.size() == 0) {
// No matches
done = true;
} else {
//Matches
matchList.add(new MatchInfo(expansion, ""));
for (MatchInfo matchInfo : matchInfoList) {
if(!matchInfo.getMatchingStringSection().equals("")) {
wordPosition += matchInfo.getMatchingStringSection().split(" ").length;
}
}
matchList.addAll(matchInfoList);
}
}
}

return matchList;
}

private Rule getRule(Grammar grammar, String ruleName) {
for (Rule rule : grammar.getRules()) {
if (rule.name.equals(ruleName)) {
return rule;
}
}
// Can find rule in grammar, may be in import rule.
return null;
}

private Grammar findImportGrammarByRule(Grammar grammar, String ruleName) {
for (Import importRule : grammar.getImports()) {
String[] items = importRule.getImportName().split("\\.");
if (items.length == 0) {
continue;
}
String importRuleName = items[items.length-1].trim();
if (importRuleName.equals(ruleName) || importRuleName.equals("*")) {
StringJoiner stringJoiner = new StringJoiner(".");
for (int i = 0; i < items.length-1; ++i) {
stringJoiner.add(items[i]);
}
String grammarName = stringJoiner.toString();
Grammar importGrammar = grammarMap.get(grammarName);
if (importGrammar == null) {
continue;
}
// import * need find match rule
if (importRuleName.equals("*")) {
for (Rule rule : importGrammar.getRules()) {
if (rule.isvisible && rule.name.equals(ruleName)) {
return importGrammar;
}
}
} else {
// import real rule name
Rule rule = importGrammar.getRule(importRuleName);
if (rule != null && rule.isvisible) {
return importGrammar;
}
}
}
}
return null;
}
}
4 changes: 4 additions & 0 deletions src/main/java/ca/l5/expandingdev/jsgf/Import.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ public Import(String name) {
public String getString() {
return "import <" + importName + ">;";
}

public String getImportName() {
return importName;
}
}
38 changes: 38 additions & 0 deletions src/main/test/GrammarCompileTest.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ca.l5.expandingdev.jsgf.*;
import org.junit.Assert;
import org.junit.Test;

import java.rmi.UnexpectedException;
Expand Down Expand Up @@ -26,4 +27,41 @@ public void test() throws UnexpectedException {
System.out.println(g.getMatchingRule(testString).name);
}
}

@Test
public void testWithImport() throws UnexpectedException {
String grammarText = "grammar ca.l5.expandingdev.test;" +
"import <ca.l5.expandingdev.common.*>;" +
"public <weather> = (What is the weather in <city>);" +
"<weather2> = (What is the weather in <other_city>);";
Grammar grammar = Grammar.parseGrammarFromString(grammarText);

String grammarText2 = "grammar ca.l5.expandingdev.common;" +
"public <city> = (Beijing|<other_city>);" +
"<other_city> = (Shanghai|Hangzhou);";
Grammar grammar2 = Grammar.parseGrammarFromString(grammarText2);

GrammarGroup grammarGroup = new GrammarGroup();
grammarGroup.addGrammar(grammar);
grammarGroup.addGrammar(grammar2);

System.out.println(grammar.toString());
System.out.println(grammar2.toString());

{
String testString = "What is the weather in Beijing";
System.out.println("Test String:" + testString);
Assert.assertTrue(grammarGroup.matchesRule(grammar, "weather", testString));
Assert.assertFalse(grammarGroup.matchesRule(grammar, "weather2", testString));
Assert.assertFalse(grammarGroup.matchesRule(grammar, "weather_invalid", testString));
}

{
String testString = "What is the weather in Shanghai";
System.out.println("Test String:" + testString);
Assert.assertTrue(grammarGroup.matchesRule(grammar, "weather", testString));
Assert.assertFalse(grammarGroup.matchesRule(grammar, "weather2", testString));
Assert.assertFalse(grammarGroup.matchesRule(grammar, "weather_invalid", testString));
}
}
}