зеркало из https://github.com/mozilla/smarthome.git
colors. Correct locale dependent lower-casing. Signed-off-by: Tilman Kamp <tilmankamp@posteo.de>
This commit is contained in:
Родитель
586e2cf3cc
Коммит
355c8ccd45
|
@ -9,6 +9,7 @@ package org.eclipse.smarthome.io.voice.internal.text;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.smarthome.core.library.types.HSBType;
|
||||
import org.eclipse.smarthome.core.library.types.IncreaseDecreaseType;
|
||||
import org.eclipse.smarthome.core.library.types.NextPreviousType;
|
||||
import org.eclipse.smarthome.core.library.types.OnOffType;
|
||||
|
@ -37,7 +38,18 @@ public class StandardInterpreter extends AbstractRuleBasedInterpreter {
|
|||
Expression onOff = alt(cmd("on", OnOffType.ON), cmd("off", OnOffType.OFF));
|
||||
Expression turn = alt("turn", "switch");
|
||||
Expression put = alt("put", "bring");
|
||||
Expression of = opt("of");
|
||||
Expression the = opt("the");
|
||||
Expression to = opt("to");
|
||||
Expression color = alt(
|
||||
cmd("white", HSBType.WHITE),
|
||||
cmd("pink", HSBType.fromRGB(255, 96, 208)),
|
||||
cmd("yellow", HSBType.fromRGB(255, 224, 32)),
|
||||
cmd("orange", HSBType.fromRGB(255, 160, 16)),
|
||||
cmd("purple", HSBType.fromRGB(128, 0, 128)),
|
||||
cmd("red", HSBType.RED),
|
||||
cmd("green", HSBType.GREEN),
|
||||
cmd("blue", HSBType.BLUE));
|
||||
|
||||
addRules(
|
||||
Locale.ENGLISH,
|
||||
|
@ -62,6 +74,10 @@ public class StandardInterpreter extends AbstractRuleBasedInterpreter {
|
|||
itemRule(seq(cmd(alt("brighten", "increase", "harden", "enhance"),
|
||||
IncreaseDecreaseType.INCREASE), the) /* item */),
|
||||
|
||||
/* ColorType */
|
||||
|
||||
itemRule(seq(opt("set"), the, opt("color"), of, the), /* item */ seq(to, color)),
|
||||
|
||||
/* UpDownType */
|
||||
|
||||
itemRule(seq(put, the), /* item */ cmd("up", UpDownType.UP)),
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.Set;
|
|||
|
||||
import org.eclipse.smarthome.core.common.registry.RegistryChangeListener;
|
||||
import org.eclipse.smarthome.core.events.EventPublisher;
|
||||
import org.eclipse.smarthome.core.items.GroupItem;
|
||||
import org.eclipse.smarthome.core.items.Item;
|
||||
import org.eclipse.smarthome.core.items.ItemRegistry;
|
||||
import org.eclipse.smarthome.core.items.events.ItemEventFactory;
|
||||
|
@ -46,12 +47,12 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
private static final String LANGUAGE_SUPPORT = "LanguageSupport";
|
||||
|
||||
private HashMap<Locale, ArrayList<Rule>> languageRules;
|
||||
private HashMap<Locale, HashSet<String>> allItemTokens = null;
|
||||
private HashMap<Locale, HashMap<Item, ArrayList<HashSet<String>>>> itemTokens = null;
|
||||
|
||||
private ItemRegistry itemRegistry;
|
||||
private EventPublisher eventPublisher;
|
||||
|
||||
private HashSet<String> identifierTokens = null;
|
||||
|
||||
private RegistryChangeListener<Item> registryChangeListener = new RegistryChangeListener<Item>() {
|
||||
@Override
|
||||
public void added(Item element) {
|
||||
|
@ -82,7 +83,7 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
throw new InterpretationException(
|
||||
locale.getDisplayLanguage(Locale.ENGLISH) + " is not supported at the moment.");
|
||||
}
|
||||
TokenList tokens = new TokenList(tokenize(text));
|
||||
TokenList tokens = new TokenList(tokenize(locale, text));
|
||||
if (tokens.eof()) {
|
||||
throw new InterpretationException(language.getString(SORRY));
|
||||
}
|
||||
|
@ -106,23 +107,92 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
}
|
||||
|
||||
private void invalidate() {
|
||||
identifierTokens = null;
|
||||
allItemTokens = null;
|
||||
itemTokens = null;
|
||||
languageRules = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* All the tokens (name parts) of the names of all the items in the {@link ItemRegistry}.
|
||||
*
|
||||
* @param locale The locale that is to be used for preparing the tokens.
|
||||
* @return the identifier tokens
|
||||
*/
|
||||
HashSet<String> getIdentifierTokens() {
|
||||
if (identifierTokens == null) {
|
||||
identifierTokens = new HashSet<String>();
|
||||
HashSet<String> getAllItemTokens(Locale locale) {
|
||||
if (allItemTokens == null) {
|
||||
allItemTokens = new HashMap<Locale, HashSet<String>>();
|
||||
}
|
||||
HashSet<String> localeTokens = allItemTokens.get(locale);
|
||||
if (localeTokens == null) {
|
||||
allItemTokens.put(locale, localeTokens = new HashSet<String>());
|
||||
for (Item item : itemRegistry.getAll()) {
|
||||
identifierTokens.addAll(splitName(item.getLabel(), true));
|
||||
localeTokens.addAll(tokenize(locale, item.getLabel()));
|
||||
}
|
||||
}
|
||||
return identifierTokens;
|
||||
return localeTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of identifier token sets per item currently contained in the {@link ItemRegistry}.
|
||||
* Each item entry in the resulting hash map will feature a list of different token sets. Each token set
|
||||
* represents one possible way "through" a chain of parent groups, where each groups tokenized name is
|
||||
* part of the set.
|
||||
*
|
||||
* @param locale The locale that is to be used for preparing the tokens.
|
||||
* @return the list of identifier token sets per item
|
||||
*/
|
||||
HashMap<Item, ArrayList<HashSet<String>>> getItemTokens(Locale locale) {
|
||||
if (itemTokens == null) {
|
||||
itemTokens = new HashMap<Locale, HashMap<Item, ArrayList<HashSet<String>>>>();
|
||||
}
|
||||
HashMap<Item, ArrayList<HashSet<String>>> localeTokens = itemTokens.get(locale);
|
||||
if (localeTokens == null) {
|
||||
itemTokens.put(locale, localeTokens = new HashMap<Item, ArrayList<HashSet<String>>>());
|
||||
for (Item item : itemRegistry.getItems()) {
|
||||
if (item.getGroupNames().isEmpty()) {
|
||||
addItem(locale, localeTokens, new HashSet<String>(), item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return localeTokens;
|
||||
}
|
||||
|
||||
private void addItem(Locale locale, HashMap<Item, ArrayList<HashSet<String>>> target, HashSet<String> tokens,
|
||||
Item item) {
|
||||
HashSet<String> nt = new HashSet<String>(tokens);
|
||||
nt.addAll(tokenize(locale, item.getLabel()));
|
||||
ArrayList<HashSet<String>> list = target.get(item);
|
||||
if (list == null) {
|
||||
target.put(item, list = new ArrayList<HashSet<String>>());
|
||||
}
|
||||
list.add(nt);
|
||||
if (item instanceof GroupItem) {
|
||||
for (Item member : ((GroupItem) item).getMembers()) {
|
||||
addItem(locale, target, nt, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String printItemDB(HashMap<Item, ArrayList<HashSet<String>>> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Item item : map.keySet()) {
|
||||
String name = item.getName();
|
||||
sb.append(name);
|
||||
sb.append("\n");
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
sb.append("=");
|
||||
}
|
||||
sb.append("\n\n");
|
||||
for (HashSet<String> parts : map.get(item)) {
|
||||
for (String token : parts) {
|
||||
sb.append(token);
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append("\n\n\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,11 +211,11 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
* all possible stop tokens as excludes.
|
||||
* It's safer to use {@link thingRule} instead.
|
||||
*
|
||||
* @param excludes Stop tokens that will stop this expression from consuming further tokens.
|
||||
* @param stopper Stop expression that, if matching, will stop this expression from consuming further tokens.
|
||||
* @return Expression that represents a name of an item.
|
||||
*/
|
||||
protected Expression name(HashSet<String> excludes) {
|
||||
return tag(NAME, star(new ExpressionIdentifier(this, excludes)));
|
||||
protected Expression name(Expression stopper) {
|
||||
return tag(NAME, star(new ExpressionIdentifier(this, stopper)));
|
||||
}
|
||||
|
||||
private HashMap<Locale, ArrayList<Rule>> getLanguageRules() {
|
||||
|
@ -228,7 +298,7 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
protected Rule itemRule(Object headExpression, Object tailExpression) {
|
||||
Expression tail = exp(tailExpression);
|
||||
Expression expression = tail == null ? seq(headExpression, name())
|
||||
: seq(headExpression, name(tail.getFirsts()), tail);
|
||||
: seq(headExpression, name(tail), tail);
|
||||
return new Rule(expression) {
|
||||
@Override
|
||||
public InterpretationResult interpretAST(ResourceBundle language, ASTNode node) {
|
||||
|
@ -410,16 +480,16 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
* Fails, if there is more than on item.
|
||||
*
|
||||
* @param language resource bundle used for producing localized response texts
|
||||
* @param nameFragments name fragments that are used to match an item's name.
|
||||
* For a positive match, the item's name has to contain every fragment - independently of their order.
|
||||
* @param labelFragments label fragments that are used to match an item's label.
|
||||
* For a positive match, the item's label has to contain every fragment - independently of their order.
|
||||
* They are treated case insensitive.
|
||||
* @param command command that should be executed
|
||||
* @return response text
|
||||
* @throws InterpretationException in case that there is no or more than on item matching the fragments
|
||||
*/
|
||||
protected String executeSingle(ResourceBundle language, String[] nameFragments, Command command)
|
||||
protected String executeSingle(ResourceBundle language, String[] labelFragments, Command command)
|
||||
throws InterpretationException {
|
||||
ArrayList<Item> items = getMatchingItems(nameFragments, command.getClass());
|
||||
ArrayList<Item> items = getMatchingItems(language, labelFragments, command.getClass());
|
||||
if (items.size() < 1) {
|
||||
throw new InterpretationException(language.getString("no_objects"));
|
||||
} else if (items.size() > 1) {
|
||||
|
@ -446,28 +516,60 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
|
||||
/**
|
||||
* Filters the item registry by matching each item's name with the provided name fragments.
|
||||
* For this the item's name is at first tokenized by {@link splitName}.
|
||||
* The resulting fragments are now looked up by each and every provided fragment.
|
||||
* For the item to get included into the result list, every provided fragment has to be found among the item's ones.
|
||||
* The item's label and its parent group's labels are tokenizend {@link tokenize} and then altogether looked up
|
||||
* by each and every provided fragment.
|
||||
* For the item to get included into the result list, every provided fragment has to be found among the label
|
||||
* tokens.
|
||||
* If a command type is provided, the item also has to support it.
|
||||
* In case of channels and their owners being ambiguous due to sharing most of the label sequence, only the top
|
||||
* most item with support for the
|
||||
* given command type is kept.
|
||||
*
|
||||
* @param nameFragments name fragments that are used to match an item's name.
|
||||
* For a positive match, the item's name has to contain every fragment - independently of their order.
|
||||
* @param language Language information that is used for matching
|
||||
* @param labelFragments label fragments that are used to match an item's label.
|
||||
* For a positive match, the item's label has to contain every fragment - independently of their order.
|
||||
* They are treated case insensitive.
|
||||
* @param commandType optional command type that all items have to support.
|
||||
* Provide {null} if there is no need for a certain command to be supported.
|
||||
* @return All matching items from the item registry.
|
||||
*/
|
||||
protected ArrayList<Item> getMatchingItems(String[] nameFragments, Class<?> commandType) {
|
||||
protected ArrayList<Item> getMatchingItems(ResourceBundle language, String[] labelFragments, Class<?> commandType) {
|
||||
ArrayList<Item> items = new ArrayList<Item>();
|
||||
for (Item item : itemRegistry.getAll()) {
|
||||
HashSet<String> parts = new HashSet<String>(splitName(item.getLabel(), true));
|
||||
boolean allMatch = true;
|
||||
for (String fragment : nameFragments) {
|
||||
allMatch = allMatch && parts.contains(fragment.toLowerCase());
|
||||
}
|
||||
if (allMatch && (commandType == null || item.getAcceptedCommandTypes().contains(commandType))) {
|
||||
items.add(item);
|
||||
HashMap<Item, ArrayList<HashSet<String>>> map = getItemTokens(language.getLocale());
|
||||
String pto;
|
||||
if (labelFragments.length > 0 && labelFragments[0].equals("dududu")) {
|
||||
pto = printItemDB(map);
|
||||
}
|
||||
for (Item item : map.keySet()) {
|
||||
for (HashSet<String> parts : map.get(item)) {
|
||||
boolean allMatch = true;
|
||||
for (String fragment : labelFragments) {
|
||||
if (!parts.contains(fragment.toLowerCase(language.getLocale()))) {
|
||||
allMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allMatch) {
|
||||
if (commandType == null || item.getAcceptedCommandTypes().contains(commandType)) {
|
||||
String name = item.getName();
|
||||
boolean insert = true;
|
||||
for (Item si : items) {
|
||||
if (name.startsWith(si.getName())) {
|
||||
insert = false;
|
||||
}
|
||||
}
|
||||
if (insert) {
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
Item si = items.get(i);
|
||||
if (si.getName().startsWith(name)) {
|
||||
items.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
|
@ -476,12 +578,16 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
/**
|
||||
* Tokenizes text. Filters out all unsupported punctuation. Tokens will be lower case.
|
||||
*
|
||||
* @param locale the locale that should be used for lower casing
|
||||
* @param text the text that should be tokenized
|
||||
* @return resulting tokens
|
||||
*/
|
||||
protected ArrayList<String> tokenize(String text) {
|
||||
protected ArrayList<String> tokenize(Locale locale, String text) {
|
||||
ArrayList<String> parts = new ArrayList<String>();
|
||||
String[] split = text.toLowerCase().replaceAll("[^\\w\\s]", " ").split("\\s");
|
||||
if (text == null) {
|
||||
return parts;
|
||||
}
|
||||
String[] split = text.toLowerCase(locale).replaceAll("[\\']", "").replaceAll("[^\\w\\s]", " ").split("\\s");
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
String part = split[i].trim();
|
||||
if (part.length() > 0) {
|
||||
|
@ -491,31 +597,6 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
return parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits an item's name into single words. It splits whitespace, Pascal, Camel and Snake-casing.
|
||||
*
|
||||
* @param name the name that's to be split
|
||||
* @param toLowerCase if {true}, all resulting fragments will be made lower case
|
||||
* @return resulting fragments of the name
|
||||
*/
|
||||
protected ArrayList<String> splitName(String name, boolean toLowerCase) {
|
||||
ArrayList<String> parts = new ArrayList<String>();
|
||||
if (name == null) {
|
||||
return parts;
|
||||
}
|
||||
String[] split = name.replaceAll("\\.", "").split("(?<!^)(?=[A-Z])|_|\\s+");
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
String part = split[i].trim();
|
||||
if (part.length() > 1) {
|
||||
if (toLowerCase) {
|
||||
part = part.toLowerCase();
|
||||
}
|
||||
parts.add(part);
|
||||
}
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Locale> getSupportedLocales() {
|
||||
return Collections.unmodifiableSet(getLanguageRules().keySet());
|
||||
|
@ -534,7 +615,7 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
*/
|
||||
private class JSGFGenerator {
|
||||
|
||||
private Locale locale;
|
||||
private ResourceBundle language;
|
||||
|
||||
private HashMap<Expression, Integer> ids = new HashMap<Expression, Integer>();
|
||||
private HashSet<Expression> exported = new HashSet<Expression>();
|
||||
|
@ -546,8 +627,8 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
|
||||
private StringBuilder builder = new StringBuilder();
|
||||
|
||||
JSGFGenerator(Locale locale) {
|
||||
this.locale = locale;
|
||||
JSGFGenerator(ResourceBundle language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
private void addChildren(Expression exp) {
|
||||
|
@ -661,7 +742,8 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
|
||||
private void emitItemIdentifierExpression(ExpressionIdentifier expression) {
|
||||
HashSet<String> remainder = new HashSet<String>(identifierExcludes);
|
||||
HashSet<String> excludes = expression.getExcludes();
|
||||
Expression stopper = expression.getStopper();
|
||||
HashSet<String> excludes = stopper == null ? new HashSet<String>() : stopper.getFirsts(language);
|
||||
if (excludes.size() > 0) {
|
||||
remainder.removeAll(excludes);
|
||||
if (remainder.size() > 0) {
|
||||
|
@ -709,15 +791,18 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
}
|
||||
|
||||
String getGrammar() {
|
||||
Rule[] rules = getRules(locale);
|
||||
identifiers.addAll(getIdentifierTokens());
|
||||
Rule[] rules = getRules(language.getLocale());
|
||||
identifiers.addAll(getAllItemTokens(language.getLocale()));
|
||||
for (Rule rule : rules) {
|
||||
Expression e = rule.getExpression();
|
||||
addExportedExpression(e);
|
||||
}
|
||||
for (Expression e : ids.keySet()) {
|
||||
if (e instanceof ExpressionIdentifier) {
|
||||
identifierExcludes.addAll(((ExpressionIdentifier) e).getExcludes());
|
||||
Expression stopper = ((ExpressionIdentifier) e).getStopper();
|
||||
if (stopper != null) {
|
||||
identifierExcludes.addAll(stopper.getFirsts(language));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -751,7 +836,7 @@ public abstract class AbstractRuleBasedInterpreter implements HumanLanguageInter
|
|||
if (format != JSGF) {
|
||||
return null;
|
||||
}
|
||||
JSGFGenerator generator = new JSGFGenerator(locale);
|
||||
JSGFGenerator generator = new JSGFGenerator(ResourceBundle.getBundle(LANGUAGE_SUPPORT, locale));
|
||||
return generator.getGrammar();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ package org.eclipse.smarthome.io.voice.text;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Base class for all expressions.
|
||||
|
@ -21,7 +22,7 @@ public abstract class Expression {
|
|||
Expression() {
|
||||
}
|
||||
|
||||
abstract ASTNode parse(TokenList list);
|
||||
abstract ASTNode parse(ResourceBundle language, TokenList list);
|
||||
|
||||
void generateValue(ASTNode node) {
|
||||
}
|
||||
|
@ -30,11 +31,11 @@ public abstract class Expression {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
abstract boolean collectFirsts(HashSet<String> firsts);
|
||||
abstract boolean collectFirsts(ResourceBundle language, HashSet<String> firsts);
|
||||
|
||||
HashSet<String> getFirsts() {
|
||||
HashSet<String> getFirsts(ResourceBundle language) {
|
||||
HashSet<String> firsts = new HashSet<String>();
|
||||
collectFirsts(firsts);
|
||||
collectFirsts(language, firsts);
|
||||
return firsts;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Expression that successfully parses, if one of the given alternative expressions matches. This class is immutable.
|
||||
|
@ -33,10 +34,10 @@ final class ExpressionAlternatives extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
ASTNode parse(TokenList list) {
|
||||
ASTNode parse(ResourceBundle language, TokenList list) {
|
||||
ASTNode node = new ASTNode(), cr;
|
||||
for (int i = 0; i < subExpressions.size(); i++) {
|
||||
cr = subExpressions.get(i).parse(list);
|
||||
cr = subExpressions.get(i).parse(language, list);
|
||||
if (cr.isSuccess()) {
|
||||
node.setChildren(new ASTNode[] {
|
||||
cr
|
||||
|
@ -57,10 +58,10 @@ final class ExpressionAlternatives extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean collectFirsts(HashSet<String> firsts) {
|
||||
boolean collectFirsts(ResourceBundle language, HashSet<String> firsts) {
|
||||
boolean blocking = true;
|
||||
for (Expression e : subExpressions) {
|
||||
blocking = blocking && e.collectFirsts(firsts);
|
||||
blocking = blocking && e.collectFirsts(language, firsts);
|
||||
}
|
||||
return blocking;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Expression that successfully parses, if a given expression occurs or repeats with a specified cardinality. This class
|
||||
|
@ -39,11 +40,11 @@ public final class ExpressionCardinality extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
ASTNode parse(TokenList list) {
|
||||
ASTNode parse(ResourceBundle language, TokenList list) {
|
||||
ASTNode node = new ASTNode(), cr;
|
||||
ArrayList<ASTNode> nodes = new ArrayList<ASTNode>();
|
||||
ArrayList<Object> values = new ArrayList<Object>();
|
||||
while ((cr = subExpression.parse(list)).isSuccess()) {
|
||||
while ((cr = subExpression.parse(language, list)).isSuccess()) {
|
||||
nodes.add(cr);
|
||||
values.add(cr.getValue());
|
||||
list = cr.getRemainingTokens();
|
||||
|
@ -67,8 +68,8 @@ public final class ExpressionCardinality extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean collectFirsts(HashSet<String> firsts) {
|
||||
return subExpression.collectFirsts(firsts) || atLeastOne;
|
||||
boolean collectFirsts(ResourceBundle language, HashSet<String> firsts) {
|
||||
return subExpression.collectFirsts(language, firsts) || atLeastOne;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
package org.eclipse.smarthome.io.voice.text;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Expression that successfully parses, if a thing identifier token is found. This class is immutable.
|
||||
|
@ -17,7 +18,7 @@ import java.util.HashSet;
|
|||
*/
|
||||
public final class ExpressionIdentifier extends Expression {
|
||||
private AbstractRuleBasedInterpreter interpreter;
|
||||
private HashSet<String> excludes;
|
||||
private Expression stopper;
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
|
@ -32,23 +33,21 @@ public final class ExpressionIdentifier extends Expression {
|
|||
* Constructs a new instance.
|
||||
*
|
||||
* @param interpreter the interpreter it belongs to. Used for dynamically fetching item name tokens
|
||||
* @param excludes tokens that should not occur for this expression to match
|
||||
* @param stopper Expression that should not match, if the current token should be accepted as identifier
|
||||
*/
|
||||
public ExpressionIdentifier(AbstractRuleBasedInterpreter interpreter, HashSet<String> excludes) {
|
||||
public ExpressionIdentifier(AbstractRuleBasedInterpreter interpreter, Expression stopper) {
|
||||
super();
|
||||
this.interpreter = interpreter;
|
||||
this.excludes = excludes == null ? new HashSet<String>() : new HashSet<String>(excludes);
|
||||
this.stopper = stopper;
|
||||
}
|
||||
|
||||
@Override
|
||||
ASTNode parse(TokenList list) {
|
||||
ASTNode parse(ResourceBundle language, TokenList list) {
|
||||
ASTNode node = new ASTNode();
|
||||
HashSet<String> tokens = interpreter.getIdentifierTokens();
|
||||
String head = list.head();
|
||||
node.setSuccess(head != null /* && tokens.contains(head) */ && !excludes.contains(head));
|
||||
node.setSuccess(list.size() > 0 && (stopper == null || !stopper.parse(language, list).isSuccess()));
|
||||
if (node.isSuccess()) {
|
||||
node.setRemainingTokens(list.skipHead());
|
||||
node.setValue(head);
|
||||
node.setValue(list.head());
|
||||
node.setChildren(new ASTNode[0]);
|
||||
generateValue(node);
|
||||
}
|
||||
|
@ -56,16 +55,18 @@ public final class ExpressionIdentifier extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean collectFirsts(HashSet<String> firsts) {
|
||||
HashSet<String> f = new HashSet<String>(interpreter.getIdentifierTokens());
|
||||
f.removeAll(excludes);
|
||||
boolean collectFirsts(ResourceBundle language, HashSet<String> firsts) {
|
||||
HashSet<String> f = new HashSet<String>(interpreter.getAllItemTokens(language.getLocale()));
|
||||
if (stopper != null) {
|
||||
f.removeAll(stopper.getFirsts(language));
|
||||
}
|
||||
firsts.addAll(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "identifier(stop=\"" + excludes + "\")";
|
||||
return "identifier(stop=" + stopper + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,9 +77,9 @@ public final class ExpressionIdentifier extends Expression {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the excludes
|
||||
* @return the stopper expression
|
||||
*/
|
||||
public HashSet<String> getExcludes() {
|
||||
return new HashSet<String>(excludes);
|
||||
public Expression getStopper() {
|
||||
return stopper;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Expression that decorates the resulting (proxied) AST node of a given expression by a name, value and tag.
|
||||
|
@ -69,8 +70,8 @@ public final class ExpressionLet extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
ASTNode parse(TokenList list) {
|
||||
ASTNode node = subExpression.parse(list);
|
||||
ASTNode parse(ResourceBundle language, TokenList list) {
|
||||
ASTNode node = subExpression.parse(language, list);
|
||||
if (node.isSuccess()) {
|
||||
node.setName(name);
|
||||
if (value != null) {
|
||||
|
@ -89,8 +90,8 @@ public final class ExpressionLet extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean collectFirsts(HashSet<String> firsts) {
|
||||
return subExpression.collectFirsts(firsts);
|
||||
boolean collectFirsts(ResourceBundle language, HashSet<String> firsts) {
|
||||
return subExpression.collectFirsts(language, firsts);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
package org.eclipse.smarthome.io.voice.text;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Expression that successfully parses, if a given string constant is found. This class is immutable.
|
||||
|
@ -29,7 +30,7 @@ public final class ExpressionMatch extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
ASTNode parse(TokenList list) {
|
||||
ASTNode parse(ResourceBundle language, TokenList list) {
|
||||
ASTNode node = new ASTNode();
|
||||
node.setSuccess(list.checkHead(pattern));
|
||||
if (node.isSuccess()) {
|
||||
|
@ -42,7 +43,7 @@ public final class ExpressionMatch extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean collectFirsts(HashSet<String> firsts) {
|
||||
boolean collectFirsts(ResourceBundle language, HashSet<String> firsts) {
|
||||
firsts.add(pattern);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Expression that successfully parses, if a sequence of given expressions is matching. This class is immutable.
|
||||
|
@ -33,13 +34,13 @@ public final class ExpressionSequence extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
ASTNode parse(TokenList list) {
|
||||
ASTNode parse(ResourceBundle language, TokenList list) {
|
||||
int l = subExpressions.size();
|
||||
ASTNode node = new ASTNode(), cr;
|
||||
ASTNode[] children = new ASTNode[l];
|
||||
Object[] values = new Object[l];
|
||||
for (int i = 0; i < l; i++) {
|
||||
cr = children[i] = subExpressions.get(i).parse(list);
|
||||
cr = children[i] = subExpressions.get(i).parse(language, list);
|
||||
if (!cr.isSuccess()) {
|
||||
return node;
|
||||
}
|
||||
|
@ -60,10 +61,10 @@ public final class ExpressionSequence extends Expression {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean collectFirsts(HashSet<String> firsts) {
|
||||
boolean collectFirsts(ResourceBundle language, HashSet<String> firsts) {
|
||||
boolean blocking = false;
|
||||
for (Expression e : subExpressions) {
|
||||
if ((blocking = e.collectFirsts(firsts)) == true) {
|
||||
if ((blocking = e.collectFirsts(language, firsts)) == true) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public abstract class Rule {
|
|||
public abstract InterpretationResult interpretAST(ResourceBundle language, ASTNode node);
|
||||
|
||||
InterpretationResult execute(ResourceBundle language, TokenList list) {
|
||||
ASTNode node = expression.parse(list);
|
||||
ASTNode node = expression.parse(language, list);
|
||||
if (node.isSuccess() && node.getRemainingTokens().eof()) {
|
||||
return interpretAST(language, node);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче