Keep track of identifiers separately for each SubFunctionPattern object

This commit is contained in:
Riccardo Azzolini 2019-08-11 21:36:06 +02:00
parent c8656d1b30
commit eb8fcaafb9
27 changed files with 132 additions and 151 deletions

View File

@ -7,7 +7,7 @@ import it.cavallium.warppi.math.rules.dsl.patterns.SubFunctionPattern;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Recognizes and generates functions of some specific shape. * Recognizes and generates functions of some specific shape.
@ -51,8 +51,10 @@ public interface Pattern {
Function replace(MathContext mathContext, Map<String, Function> subFunctions); Function replace(MathContext mathContext, Map<String, Function> subFunctions);
/** /**
* @return The (possibly empty) <code>Set</code> of all sub-function patterns * @return A (possibly empty) <code>Stream</code> of all sub-function patterns
* found within this pattern and its children. * found within this pattern and its children.
* If there are multiple sub-function patterns with the same name, the stream still contains all of them.
* The order of the patterns within the stream is unspecified.
*/ */
Set<SubFunctionPattern> getSubFunctions(); Stream<SubFunctionPattern> getSubFunctions();
} }

View File

@ -52,11 +52,11 @@ public class PatternRule implements Rule {
return ruleType; return ruleType;
} }
Pattern getTarget() { public Pattern getTarget() {
return target; return target;
} }
List<Pattern> getReplacements() { public List<Pattern> getReplacements() {
return replacements; return replacements;
} }

View File

@ -1,26 +0,0 @@
package it.cavallium.warppi.math.rules.dsl;
import it.cavallium.warppi.math.rules.dsl.patterns.SubFunctionPattern;
import java.util.*;
import java.util.stream.Collectors;
/**
* Contains helper methods which are useful for writing patterns.
*/
public class PatternUtils {
private PatternUtils() {}
/**
* Gathers all sub-function patterns from multiple patterns.
*
* @param patterns The patterns from which sub-functions are gathered.
* @return The union of the return values of {@link Pattern#getSubFunctions()} for each pattern.
*/
public static Set<SubFunctionPattern> getSubFunctionsFrom(final Pattern... patterns) {
return Arrays.stream(patterns)
.map(Pattern::getSubFunctions)
.flatMap(Set::stream)
.collect(Collectors.toSet());
}
}

View File

@ -6,6 +6,8 @@ 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.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* Implements a domain-specific language (DSL) for the definition of {@link Rule}s. * Implements a domain-specific language (DSL) for the definition of {@link Rule}s.
@ -28,9 +30,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) {
undefinedSubFunctions(rule).stream() undefinedSubFunctions(rule)
.flatMap(subFunc -> parser.getSubFunctionIdentifiers(rule, subFunc).stream()) .map(subFunc -> new UndefinedSubFunction(
.map(UndefinedSubFunction::new) parser.getSubFunctionIdentifier(subFunc)
))
.forEach(errors::add); .forEach(errors::add);
} }
@ -46,15 +49,12 @@ public class RulesDsl {
* without being defined (captured) in the target pattern. * without being defined (captured) in the target pattern.
* *
* @param rule The rule to analyze. * @param rule The rule to analyze.
* @return The (possibly empty) set of undefined sub-functions. * @return A (possibly empty) <code>Stream</code> of undefined sub-functions.
*/ */
private static Set<SubFunctionPattern> undefinedSubFunctions(final PatternRule rule) { private static Stream<SubFunctionPattern> undefinedSubFunctions(final PatternRule rule) {
final Set<SubFunctionPattern> defined = rule.getTarget().getSubFunctions(); final Set<SubFunctionPattern> defined = rule.getTarget().getSubFunctions().collect(Collectors.toSet());
final Set<SubFunctionPattern> undefined = new HashSet<>(); return rule.getReplacements().stream()
for (final Pattern replacement : rule.getReplacements()) { .flatMap(Pattern::getSubFunctions)
undefined.addAll(replacement.getSubFunctions()); .filter(subFunc -> !defined.contains(subFunc));
}
undefined.removeAll(defined);
return undefined;
} }
} }

View File

@ -32,10 +32,8 @@ public class Parser {
private int currentIndex = 0; private int currentIndex = 0;
// For error reporting // For error reporting
private Map<SubFunctionPattern, List<Token>> ruleSubFunctionIdentifiers; // An IdentityHashMap is used to distinguish SubFunctionPatterns even if they're identical (equal)
// An IdentityHashMap is used to distinguish rules even if they're identical (equal) private final IdentityHashMap<SubFunctionPattern, Token> subFunctionIdentifiers = new IdentityHashMap<>();
private final IdentityHashMap<PatternRule, Map<SubFunctionPattern, List<Token>>> subFunctionIdentifiers =
new IdentityHashMap<>();
/** /**
* Constructs a <code>Parser</code> that will produce a list of {@link PatternRule}s from the the given list of {@link Token}s. * Constructs a <code>Parser</code> that will produce a list of {@link PatternRule}s from the the given list of {@link Token}s.
@ -64,8 +62,21 @@ public class Parser {
return rules(); return rules();
} }
public List<Token> getSubFunctionIdentifiers(final PatternRule rule, final SubFunctionPattern subFunction) { /**
return subFunctionIdentifiers.get(rule).get(subFunction); * Retrieves the <code>IDENTIFIER</code> token which corresponds to the given <code>SubFunctionPattern</code>.
* <p>
* The information returned by this method can be used to point out the location of sub-function related errors
* within the DSL source code.
*
* @param subFunction a <code>SubFunctionsPattern</code> from one of the rules returned by this <code>Parser</code>
* instance. While <code>SubFunctionPattern</code>s with the same name are considered equal,
* this method can distinguish between them, in order to return the exact identifier which led
* to the creation of the specified <code>SubFunctionPattern</code> object.
* @return the <code>Token</code> (of type <code>IDENTIFIER</code>) which corresponds to the given
* <code>SubFunctionPattern</code>.
*/
public Token getSubFunctionIdentifier(final SubFunctionPattern subFunction) {
return subFunctionIdentifiers.get(subFunction);
} }
// rules = { rule } , EOF ; // rules = { rule } , EOF ;
@ -88,14 +99,11 @@ public class Parser {
private PatternRule rule() throws SyntaxException { private PatternRule rule() throws SyntaxException {
final RuleType type = ruleType(); final RuleType type = ruleType();
final String name = matchOrFail(IDENTIFIER).lexeme; final String name = matchOrFail(IDENTIFIER).lexeme;
ruleSubFunctionIdentifiers = new HashMap<>(); // Must be initialized before calling pattern() and replacements()
matchOrFail(COLON); matchOrFail(COLON);
final Pattern target = pattern(); final Pattern target = pattern();
matchOrFail(ARROW); matchOrFail(ARROW);
final List<Pattern> replacements = replacements(); final List<Pattern> replacements = replacements();
final PatternRule rule = new PatternRule(name, type, target, replacements); return new PatternRule(name, type, target, replacements);
subFunctionIdentifiers.put(rule, ruleSubFunctionIdentifiers);
return rule;
} }
// rule type = REDUCTION | EXPANSION | CALCULATION | EXISTENCE ; // rule type = REDUCTION | EXPANSION | CALCULATION | EXISTENCE ;
@ -247,7 +255,7 @@ public class Parser {
return new NumberPattern(new BigDecimal(curToken.lexeme)); return new NumberPattern(new BigDecimal(curToken.lexeme));
case IDENTIFIER: case IDENTIFIER:
final SubFunctionPattern subFunction = new SubFunctionPattern(curToken.lexeme); final SubFunctionPattern subFunction = new SubFunctionPattern(curToken.lexeme);
saveSubFunctionIdentifier(subFunction, curToken); subFunctionIdentifiers.put(subFunction, curToken);
return subFunction; return subFunction;
case LEFT_PAREN: case LEFT_PAREN:
final Pattern grouped = sum(); final Pattern grouped = sum();
@ -257,14 +265,6 @@ public class Parser {
throw new SyntaxException(new UnexpectedToken(curToken)); throw new SyntaxException(new UnexpectedToken(curToken));
} }
private void saveSubFunctionIdentifier(final SubFunctionPattern subFunction, final Token curToken) {
final List<Token> subFunctionList = ruleSubFunctionIdentifiers.computeIfAbsent(
subFunction,
key -> new ArrayList<>()
);
subFunctionList.add(curToken);
}
private Pattern matchLeftAssoc( private Pattern matchLeftAssoc(
final PatternParser operandParser, final PatternParser operandParser,
final Map<TokenType, BiFunction<Pattern, Pattern, Pattern>> operators final Map<TokenType, BiFunction<Pattern, Pattern, Pattern>> operators

View File

@ -8,7 +8,7 @@ import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates the arccosine of another pattern. * Matches and generates the arccosine of another pattern.
@ -34,7 +34,7 @@ public class ArcCosinePattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return argument.getSubFunctions(); return argument.getSubFunctions();
} }

View File

@ -8,7 +8,7 @@ import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates the arcsine of another pattern. * Matches and generates the arcsine of another pattern.
@ -34,7 +34,7 @@ public class ArcSinePattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return argument.getSubFunctions(); return argument.getSubFunctions();
} }

View File

@ -8,7 +8,7 @@ import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates the arctangent of another pattern. * Matches and generates the arctangent of another pattern.
@ -34,7 +34,7 @@ public class ArcTangentPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return argument.getSubFunctions(); return argument.getSubFunctions();
} }

View File

@ -5,10 +5,9 @@ import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Variable; import it.cavallium.warppi.math.functions.Variable;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a specific symbolic constant. * Matches and generates a specific symbolic constant.
@ -32,8 +31,8 @@ public class ConstantPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return Collections.emptySet(); return Stream.empty();
} }
@Override @Override

View File

@ -8,7 +8,7 @@ import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates the cosine of another pattern. * Matches and generates the cosine of another pattern.
@ -34,7 +34,7 @@ public class CosinePattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return argument.getSubFunctions(); return argument.getSubFunctions();
} }

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Division; import it.cavallium.warppi.math.functions.Division;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a division of two other patterns. * Matches and generates a division of two other patterns.
@ -39,8 +38,9 @@ public class DivisionPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(dividend, divisor); return Stream.of(dividend, divisor)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.equations.Equation; import it.cavallium.warppi.math.functions.equations.Equation;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates an equation of two other patterns. * Matches and generates an equation of two other patterns.
@ -39,8 +38,9 @@ public class EquationPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(left, right); return Stream.of(left, right)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.equations.EquationsSystem; import it.cavallium.warppi.math.functions.equations.EquationsSystem;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a system of equations of multiple other patterns. * Matches and generates a system of equations of multiple other patterns.
@ -47,8 +46,9 @@ public class EquationsSystemPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(patterns); return Stream.of(patterns)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Logarithm; import it.cavallium.warppi.math.functions.Logarithm;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a logarithm of base and argument patterns. * Matches and generates a logarithm of base and argument patterns.
@ -39,8 +38,9 @@ public class LogarithmPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(base, argument); return Stream.of(base, argument)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Multiplication; import it.cavallium.warppi.math.functions.Multiplication;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a multiplication of two other patterns. * Matches and generates a multiplication of two other patterns.
@ -39,8 +38,9 @@ public class MultiplicationPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(left, right); return Stream.of(left, right)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -10,7 +10,7 @@ import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates the negative of another pattern. * Matches and generates the negative of another pattern.
@ -52,7 +52,7 @@ public class NegativePattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return inner.getSubFunctions(); return inner.getSubFunctions();
} }

View File

@ -6,10 +6,9 @@ import it.cavallium.warppi.math.functions.Number;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a specific number. * Matches and generates a specific number.
@ -32,8 +31,8 @@ public class NumberPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return Collections.emptySet(); return Stream.empty();
} }
@Override @Override

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Power; import it.cavallium.warppi.math.functions.Power;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a power (exponentiation) of base and exponent patterns. * Matches and generates a power (exponentiation) of base and exponent patterns.
@ -39,8 +38,9 @@ public class PowerPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(base, exponent); return Stream.of(base, exponent)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -6,13 +6,12 @@ import it.cavallium.warppi.math.functions.Number;
import it.cavallium.warppi.math.functions.Root; import it.cavallium.warppi.math.functions.Root;
import it.cavallium.warppi.math.functions.RootSquare; import it.cavallium.warppi.math.functions.RootSquare;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a root of degree and radicand patterns. * Matches and generates a root of degree and radicand patterns.
@ -54,8 +53,9 @@ public class RootPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(degree, radicand); return Stream.of(degree, radicand)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -8,7 +8,7 @@ import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates the sine of another pattern. * Matches and generates the sine of another pattern.
@ -34,7 +34,7 @@ public class SinePattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return argument.getSubFunctions(); return argument.getSubFunctions();
} }

View File

@ -4,10 +4,9 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates any function as a named sub-function. * Matches and generates any function as a named sub-function.
@ -31,8 +30,8 @@ public class SubFunctionPattern implements Pattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return Collections.singleton(this); return Stream.of(this);
} }
@Override @Override

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Subtraction; import it.cavallium.warppi.math.functions.Subtraction;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a subtraction of two other patterns. * Matches and generates a subtraction of two other patterns.
@ -39,8 +38,9 @@ public class SubtractionPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(left, right); return Stream.of(left, right)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Sum; import it.cavallium.warppi.math.functions.Sum;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a sum of two other patterns. * Matches and generates a sum of two other patterns.
@ -39,8 +38,9 @@ public class SumPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(left, right); return Stream.of(left, right)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -4,12 +4,11 @@ import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.SumSubtraction; import it.cavallium.warppi.math.functions.SumSubtraction;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternUtils;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates a sum/subtraction (±) of two other patterns. * Matches and generates a sum/subtraction (±) of two other patterns.
@ -39,8 +38,9 @@ public class SumSubtractionPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return PatternUtils.getSubFunctionsFrom(left, right); return Stream.of(left, right)
.flatMap(Pattern::getSubFunctions);
} }
@Override @Override

View File

@ -8,7 +8,7 @@ import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates the tangent of another pattern. * Matches and generates the tangent of another pattern.
@ -34,7 +34,7 @@ public class TangentPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return argument.getSubFunctions(); return argument.getSubFunctions();
} }

View File

@ -5,9 +5,8 @@ import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.functions.Undefined; import it.cavallium.warppi.math.functions.Undefined;
import it.cavallium.warppi.math.rules.dsl.VisitorPattern; import it.cavallium.warppi.math.rules.dsl.VisitorPattern;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.stream.Stream;
/** /**
* Matches and generates <code>Undefined</code>. * Matches and generates <code>Undefined</code>.
@ -24,8 +23,8 @@ public class UndefinedPattern extends VisitorPattern {
} }
@Override @Override
public Set<SubFunctionPattern> getSubFunctions() { public Stream<SubFunctionPattern> getSubFunctions() {
return Collections.emptySet(); return Stream.empty();
} }
@Override @Override

View File

@ -6,6 +6,7 @@ import it.cavallium.warppi.math.rules.dsl.DslError;
import it.cavallium.warppi.math.rules.dsl.Pattern; import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternRule; import it.cavallium.warppi.math.rules.dsl.PatternRule;
import it.cavallium.warppi.math.rules.dsl.patterns.*; import it.cavallium.warppi.math.rules.dsl.patterns.*;
import org.apache.commons.lang3.ObjectUtils;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -15,6 +16,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static it.cavallium.warppi.math.rules.dsl.frontend.TokenType.*; import static it.cavallium.warppi.math.rules.dsl.frontend.TokenType.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -344,21 +346,11 @@ public class ParserTest {
final Parser parser = new Parser(tokens, errors::add); final Parser parser = new Parser(tokens, errors::add);
final List<PatternRule> rules = parser.parse(); final List<PatternRule> rules = parser.parse();
assertEquals(rule0x, toReferenceEquality( assertEquals(rule0x, getSubFunctionIdentifiers(parser, rules.get(0), "x"));
parser.getSubFunctionIdentifiers(rules.get(0), new SubFunctionPattern("x")) assertEquals(rule1x, getSubFunctionIdentifiers(parser, rules.get(1), "x"));
)); assertEquals(rule1y, getSubFunctionIdentifiers(parser, rules.get(1), "y"));
assertEquals(rule1x, toReferenceEquality( assertEquals(rule2x, getSubFunctionIdentifiers(parser, rules.get(2), "x"));
parser.getSubFunctionIdentifiers(rules.get(1), new SubFunctionPattern("x")) assertEquals(rule3x, getSubFunctionIdentifiers(parser, rules.get(3), "x"));
));
assertEquals(rule1y, toReferenceEquality(
parser.getSubFunctionIdentifiers(rules.get(1), new SubFunctionPattern("y"))
));
assertEquals(rule2x, toReferenceEquality(
parser.getSubFunctionIdentifiers(rules.get(2), new SubFunctionPattern("x"))
));
assertEquals(rule3x, toReferenceEquality(
parser.getSubFunctionIdentifiers(rules.get(3), new SubFunctionPattern("x"))
));
} }
private static Token addIdentifierToken(final List<ReferenceEqualityToken> list, final String identifier) { private static Token addIdentifierToken(final List<ReferenceEqualityToken> list, final String identifier) {
@ -367,10 +359,22 @@ public class ParserTest {
return token; return token;
} }
private static List<ReferenceEqualityToken> toReferenceEquality(final List<Token> tokens) { private static List<ReferenceEqualityToken> getSubFunctionIdentifiers(
return tokens.stream() final Parser parser,
.map(ReferenceEqualityToken::new) final PatternRule rule,
.collect(Collectors.toList()); final String subFunctionName
) {
final SubFunctionPattern exampleSubFunction = new SubFunctionPattern(subFunctionName);
final Stream<SubFunctionPattern> allSubFunctions = Stream.concat(
rule.getTarget().getSubFunctions(),
rule.getReplacements().stream().flatMap(Pattern::getSubFunctions)
);
return allSubFunctions
.filter(subFunc -> subFunc.equals(exampleSubFunction)) // Match the name without having access to it directly
.map(subFunc -> new ReferenceEqualityToken(
parser.getSubFunctionIdentifier(subFunc)
))
.collect(Collectors.toList());
} }
private static class ReferenceEqualityToken { private static class ReferenceEqualityToken {
@ -387,6 +391,11 @@ public class ParserTest {
} }
return this.token == ((ReferenceEqualityToken) o).token; return this.token == ((ReferenceEqualityToken) o).token;
} }
@Override
public String toString() {
return "ReferenceEqualityToken{" + ObjectUtils.identityToString(token) + '}';
}
} }
// The EOF token is inserted by the lexer, therefore it can only be missing // The EOF token is inserted by the lexer, therefore it can only be missing