Properly report undefined sub-functions in replacement patterns

This commit is contained in:
Riccardo Azzolini 2019-01-30 20:11:43 +01:00
parent 3a5ccdfc13
commit f930242ee8
2 changed files with 48 additions and 13 deletions

View File

@ -5,10 +5,7 @@ import it.cavallium.warppi.math.rules.dsl.frontend.Lexer;
import it.cavallium.warppi.math.rules.dsl.frontend.Parser; import it.cavallium.warppi.math.rules.dsl.frontend.Parser;
import it.cavallium.warppi.math.rules.dsl.patterns.SubFunctionPattern; import it.cavallium.warppi.math.rules.dsl.patterns.SubFunctionPattern;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class RulesDsl { public class RulesDsl {
private RulesDsl() {} private RulesDsl() {}
@ -21,7 +18,10 @@ public class RulesDsl {
final List<PatternRule> rules = parser.parse(); final List<PatternRule> rules = parser.parse();
for (final PatternRule rule : rules) { for (final PatternRule rule : rules) {
checkSubFunctionsDefined(rule); undefinedSubFunctions(rule).stream()
.flatMap(subFunc -> parser.getSubFunctionIdentifiers(rule.getRuleName(), subFunc).stream())
.map(UndefinedSubFunctionException::new)
.forEach(errors::add);
} }
if (!errors.isEmpty()) { if (!errors.isEmpty()) {
@ -32,18 +32,21 @@ public class RulesDsl {
} }
/** /**
* Verifies that all sub-functions in the replacement patterns of a <code>PatternRule</code> * Finds any sub-functions that are used in the replacement patterns of a <code>PatternRule</code>
* are defined (captured) in the target pattern. * without being defined (captured) in the target pattern.
* *
* @param rule The rule to check. * @param rule The rule to analyze.
* @throws RuntimeException if any replacement pattern uses undefined sub-functions. * @return The (possibly empty) set of undefined sub-functions.
*/ */
private static void checkSubFunctionsDefined(final PatternRule rule) { private static Set<SubFunctionPattern> undefinedSubFunctions(final PatternRule rule) {
final Set<SubFunctionPattern> defined = rule.getTarget().getSubFunctions(); final Set<SubFunctionPattern> defined = rule.getTarget().getSubFunctions();
final Set<SubFunctionPattern> undefined = new HashSet<>();
for (final Pattern replacement : rule.getReplacements()) { for (final Pattern replacement : rule.getReplacements()) {
if (!defined.containsAll(replacement.getSubFunctions())) { undefined.addAll(replacement.getSubFunctions());
throw new RuntimeException("Undefined sub-function(s) in replacements for " + rule.getRuleName());
}
} }
undefined.removeAll(defined);
return undefined;
} }
} }

View File

@ -0,0 +1,32 @@
package it.cavallium.warppi.math.rules.dsl;
import it.cavallium.warppi.math.rules.dsl.frontend.Token;
/**
* Thrown when a sub-function is used in one of the replacement pattern of a <code>PatternRule</code>,
* but not defined (captured) in the target pattern.
*/
public class UndefinedSubFunctionException extends DslException {
private final Token identifier;
public UndefinedSubFunctionException(final Token identifier) {
this.identifier = identifier;
}
@Override
public int getPosition() {
return identifier.position;
}
@Override
public int getLength() {
return identifier.lexeme.length();
}
/**
* @return The name of the undefined sub-function.
*/
public String getName() {
return identifier.lexeme;
}
}