Avoid using methods which are not available on TeaVM

This commit is contained in:
Riccardo Azzolini 2019-08-08 14:35:30 +02:00
parent d4b91c4d4f
commit fef30042ce
5 changed files with 100 additions and 45 deletions

View File

@ -181,11 +181,11 @@ public class LineMap {
@Override
public String toString() {
return new StringJoiner(", ", "Line{", "}")
.add("number=" + number)
.add("startPosition=" + startPosition)
.add("text='" + text + "'")
.toString();
return "Line{" +
"number=" + number +
", startPosition=" + startPosition +
", text='" + text + '\'' +
'}';
}
}
}

View File

@ -2,14 +2,9 @@ package it.cavallium.warppi.math.rules.dsl.frontend;
import it.cavallium.warppi.math.rules.dsl.DslError;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static it.cavallium.warppi.math.rules.dsl.frontend.TokenType.*;
@ -17,14 +12,19 @@ import static it.cavallium.warppi.math.rules.dsl.frontend.TokenType.*;
* Converts the source string to a list of tokens.
*/
public class Lexer {
private static final Map<String, TokenType> keywords = Stream.of(
private static final Map<String, TokenType> KEYWORDS;
static {
TokenType[] keywordTokenTypes = {
REDUCTION, EXPANSION, CALCULATION, EXISTENCE,
ARCCOS, ARCSIN, ARCTAN, COS, SIN, TAN, ROOT, SQRT, LOG,
UNDEFINED, PI, E
).collect(Collectors.toMap(
tokenType -> tokenType.name().toLowerCase(),
Function.identity()
));
};
Map<String, TokenType> map = new HashMap<>();
for (TokenType type : keywordTokenTypes) {
map.put(type.name().toLowerCase(), type);
}
KEYWORDS = Collections.unmodifiableMap(map);
}
private final String source;
private final Consumer<? super DslError> errorReporter;
@ -160,7 +160,7 @@ public class Lexer {
private void keywordOrIdentifier() {
matchWhile(Character::isJavaIdentifierPart);
TokenType type = keywords.getOrDefault(currentLexeme(), IDENTIFIER);
TokenType type = KEYWORDS.getOrDefault(currentLexeme(), IDENTIFIER);
emitToken(type);
}

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.PatternRule;
import it.cavallium.warppi.math.rules.dsl.patterns.*;
import it.cavallium.warppi.util.MapFactory;
import java.math.BigDecimal;
import java.util.*;
@ -19,11 +20,11 @@ import static it.cavallium.warppi.math.rules.dsl.frontend.TokenType.*;
* Converts a list of tokens to a list of <code>PatternRule</code>s.
*/
public class Parser {
private static final Map<TokenType, RuleType> ruleTypes = Map.ofEntries(
Map.entry(REDUCTION, RuleType.REDUCTION),
Map.entry(EXPANSION, RuleType.EXPANSION),
Map.entry(CALCULATION, RuleType.CALCULATION),
Map.entry(EXISTENCE, RuleType.EXISTENCE)
private static final Map<TokenType, RuleType> RULE_TYPES = MapFactory.fromEntries(
MapFactory.entry(REDUCTION, RuleType.REDUCTION),
MapFactory.entry(EXPANSION, RuleType.EXPANSION),
MapFactory.entry(CALCULATION, RuleType.CALCULATION),
MapFactory.entry(EXISTENCE, RuleType.EXISTENCE)
);
private final List<Token> tokens;
@ -57,7 +58,7 @@ public class Parser {
rules.add(rule());
} catch (final SyntaxException e) {
errorReporter.accept(e.getError());
synchronizeTo(ruleTypes.keySet()); // Skip to the next rule to minimize "false" errors
synchronizeTo(RULE_TYPES.keySet()); // Skip to the next rule to minimize "false" errors
}
}
return rules;
@ -82,12 +83,12 @@ public class Parser {
// rule type = REDUCTION | EXPANSION | CALCULATION | EXISTENCE ;
private RuleType ruleType() throws SyntaxException {
final Token curToken = pop();
if (!ruleTypes.containsKey(curToken.type)) {
if (!RULE_TYPES.containsKey(curToken.type)) {
throw new SyntaxException(
new UnexpectedToken(curToken, ruleTypes.keySet())
new UnexpectedToken(curToken, RULE_TYPES.keySet())
);
}
return ruleTypes.get(curToken.type);
return RULE_TYPES.get(curToken.type);
}
// pattern = equation ;
@ -126,18 +127,18 @@ public class Parser {
// sum = product , { ( PLUS | MINUS | PLUS_MINUS ) product } ;
private Pattern sum() throws SyntaxException {
return matchLeftAssoc(this::product, Map.ofEntries(
Map.entry(PLUS, SumPattern::new),
Map.entry(MINUS, SubtractionPattern::new),
Map.entry(PLUS_MINUS, SumSubtractionPattern::new)
return matchLeftAssoc(this::product, MapFactory.fromEntries(
MapFactory.entry(PLUS, SumPattern::new),
MapFactory.entry(MINUS, SubtractionPattern::new),
MapFactory.entry(PLUS_MINUS, SumSubtractionPattern::new)
));
}
// product = unary , { ( TIMES | DIVIDE ) unary } ;
private Pattern product() throws SyntaxException {
return matchLeftAssoc(this::unary, Map.ofEntries(
Map.entry(TIMES, MultiplicationPattern::new),
Map.entry(DIVIDE, DivisionPattern::new)
return matchLeftAssoc(this::unary, MapFactory.fromEntries(
MapFactory.entry(TIMES, MultiplicationPattern::new),
MapFactory.entry(DIVIDE, DivisionPattern::new)
));
}
@ -170,18 +171,18 @@ public class Parser {
// function = ( ARCCOS | ARCSIN | ARCTAN | COS | SIN | SQRT | TAN ) , LEFT_PAREN , sum , RIGHT_PAREN
// | ( LOG | ROOT ) LEFT_PAREN , sum , COMMA , sum , RIGHT_PAREN ;
private Pattern tryFunction() throws SyntaxException {
final Map<TokenType, Function<Pattern, Pattern>> oneArg = Map.ofEntries(
Map.entry(ARCCOS, ArcCosinePattern::new),
Map.entry(ARCSIN, ArcSinePattern::new),
Map.entry(ARCTAN, ArcTangentPattern::new),
Map.entry(COS, CosinePattern::new),
Map.entry(SIN, SinePattern::new),
Map.entry(SQRT, arg -> new RootPattern(new NumberPattern(new BigDecimal(2)), arg)),
Map.entry(TAN, TangentPattern::new)
final Map<TokenType, Function<Pattern, Pattern>> oneArg = MapFactory.fromEntries(
MapFactory.entry(ARCCOS, ArcCosinePattern::new),
MapFactory.entry(ARCSIN, ArcSinePattern::new),
MapFactory.entry(ARCTAN, ArcTangentPattern::new),
MapFactory.entry(COS, CosinePattern::new),
MapFactory.entry(SIN, SinePattern::new),
MapFactory.entry(SQRT, arg -> new RootPattern(new NumberPattern(new BigDecimal(2)), arg)),
MapFactory.entry(TAN, TangentPattern::new)
);
final Map<TokenType, BiFunction<Pattern, Pattern, Pattern>> twoArg = Map.ofEntries(
Map.entry(LOG, LogarithmPattern::new),
Map.entry(ROOT, RootPattern::new)
final Map<TokenType, BiFunction<Pattern, Pattern, Pattern>> twoArg = MapFactory.fromEntries(
MapFactory.entry(LOG, LogarithmPattern::new),
MapFactory.entry(ROOT, RootPattern::new)
);
final TokenType curType = peek().type;

View File

@ -2,6 +2,8 @@ package it.cavallium.warppi.math.rules.dsl.frontend;
import it.cavallium.warppi.math.rules.dsl.DslError;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@ -19,7 +21,7 @@ public class UnexpectedToken implements DslError {
public UnexpectedToken(final Token unexpected, final TokenType... suggested) {
this.unexpected = unexpected;
this.suggested = Set.of(suggested);
this.suggested = new HashSet<>(Arrays.asList(suggested)); // TeaVM doesn't support Set.of
}
@Override

View File

@ -0,0 +1,52 @@
package it.cavallium.warppi.util;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Reimplements map creation methods which are not available on TeaVM.
*/
public class MapFactory {
private MapFactory() {}
/**
* Returns an unmodifiable map containing keys and values extracted from the given entries.
* <p>
* This method is equivalent to {@link Map#ofEntries(Map.Entry...)}.
*
* @param entries <code>Map.Entry</code>s containing the keys and values from which the map is populated
* @param <K> the <code>Map</code>'s key type
* @param <V> the <code>Map</code>'s value type
* @return a Map containing the specified mappings
* @see MapFactory#entry(K, V)
*/
@SafeVarargs
public static <K, V> Map<K, V> fromEntries(Map.Entry<? extends K, ? extends V>... entries) {
HashMap<K, V> map = new HashMap<>();
for (Map.Entry<? extends K, ? extends V> entry : entries) {
map.put(entry.getKey(), entry.getValue());
}
return Collections.unmodifiableMap(map);
}
/**
* Returns an unmodifiable <code>Map.Entry</code> containing the given key and value.
* These entries are suitable for populating Map instances using the {@link MapFactory#fromEntries(Map.Entry...)}
* or {@link Map#ofEntries(Map.Entry...)} methods.
* <p>
* This method can be used as a replacement for {@link Map#entry(K, V)}, if the latter is not available (for example,
* when compiling for TeaVM). However, unlike <code>Map.entry</code>, <code>null</code> keys and values are allowed,
* and the returned <code>Entry</code> is serializable.
*
* @param key the key
* @param value the value
* @param <K> the key's type
* @param <V> the value's type
* @return an <code>Entry</code> containing the specified key and value
*/
public static <K, V> Map.Entry<K, V> entry(K key, V value) {
return new AbstractMap.SimpleImmutableEntry<>(key, value);
}
}