Avoid using methods which are not available on TeaVM
This commit is contained in:
parent
d4b91c4d4f
commit
fef30042ce
@ -181,11 +181,11 @@ public class LineMap {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new StringJoiner(", ", "Line{", "}")
|
return "Line{" +
|
||||||
.add("number=" + number)
|
"number=" + number +
|
||||||
.add("startPosition=" + startPosition)
|
", startPosition=" + startPosition +
|
||||||
.add("text='" + text + "'")
|
", text='" + text + '\'' +
|
||||||
.toString();
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,9 @@ package it.cavallium.warppi.math.rules.dsl.frontend;
|
|||||||
|
|
||||||
import it.cavallium.warppi.math.rules.dsl.DslError;
|
import it.cavallium.warppi.math.rules.dsl.DslError;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
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.*;
|
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.
|
* Converts the source string to a list of tokens.
|
||||||
*/
|
*/
|
||||||
public class Lexer {
|
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,
|
REDUCTION, EXPANSION, CALCULATION, EXISTENCE,
|
||||||
ARCCOS, ARCSIN, ARCTAN, COS, SIN, TAN, ROOT, SQRT, LOG,
|
ARCCOS, ARCSIN, ARCTAN, COS, SIN, TAN, ROOT, SQRT, LOG,
|
||||||
UNDEFINED, PI, E
|
UNDEFINED, PI, E
|
||||||
).collect(Collectors.toMap(
|
};
|
||||||
tokenType -> tokenType.name().toLowerCase(),
|
Map<String, TokenType> map = new HashMap<>();
|
||||||
Function.identity()
|
for (TokenType type : keywordTokenTypes) {
|
||||||
));
|
map.put(type.name().toLowerCase(), type);
|
||||||
|
}
|
||||||
|
KEYWORDS = Collections.unmodifiableMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
private final String source;
|
private final String source;
|
||||||
private final Consumer<? super DslError> errorReporter;
|
private final Consumer<? super DslError> errorReporter;
|
||||||
@ -160,7 +160,7 @@ public class Lexer {
|
|||||||
|
|
||||||
private void keywordOrIdentifier() {
|
private void keywordOrIdentifier() {
|
||||||
matchWhile(Character::isJavaIdentifierPart);
|
matchWhile(Character::isJavaIdentifierPart);
|
||||||
TokenType type = keywords.getOrDefault(currentLexeme(), IDENTIFIER);
|
TokenType type = KEYWORDS.getOrDefault(currentLexeme(), IDENTIFIER);
|
||||||
emitToken(type);
|
emitToken(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 it.cavallium.warppi.util.MapFactory;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
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.
|
* Converts a list of tokens to a list of <code>PatternRule</code>s.
|
||||||
*/
|
*/
|
||||||
public class Parser {
|
public class Parser {
|
||||||
private static final Map<TokenType, RuleType> ruleTypes = Map.ofEntries(
|
private static final Map<TokenType, RuleType> RULE_TYPES = MapFactory.fromEntries(
|
||||||
Map.entry(REDUCTION, RuleType.REDUCTION),
|
MapFactory.entry(REDUCTION, RuleType.REDUCTION),
|
||||||
Map.entry(EXPANSION, RuleType.EXPANSION),
|
MapFactory.entry(EXPANSION, RuleType.EXPANSION),
|
||||||
Map.entry(CALCULATION, RuleType.CALCULATION),
|
MapFactory.entry(CALCULATION, RuleType.CALCULATION),
|
||||||
Map.entry(EXISTENCE, RuleType.EXISTENCE)
|
MapFactory.entry(EXISTENCE, RuleType.EXISTENCE)
|
||||||
);
|
);
|
||||||
|
|
||||||
private final List<Token> tokens;
|
private final List<Token> tokens;
|
||||||
@ -57,7 +58,7 @@ public class Parser {
|
|||||||
rules.add(rule());
|
rules.add(rule());
|
||||||
} catch (final SyntaxException e) {
|
} catch (final SyntaxException e) {
|
||||||
errorReporter.accept(e.getError());
|
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;
|
return rules;
|
||||||
@ -82,12 +83,12 @@ public class Parser {
|
|||||||
// rule type = REDUCTION | EXPANSION | CALCULATION | EXISTENCE ;
|
// rule type = REDUCTION | EXPANSION | CALCULATION | EXISTENCE ;
|
||||||
private RuleType ruleType() throws SyntaxException {
|
private RuleType ruleType() throws SyntaxException {
|
||||||
final Token curToken = pop();
|
final Token curToken = pop();
|
||||||
if (!ruleTypes.containsKey(curToken.type)) {
|
if (!RULE_TYPES.containsKey(curToken.type)) {
|
||||||
throw new SyntaxException(
|
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 ;
|
// pattern = equation ;
|
||||||
@ -126,18 +127,18 @@ public class Parser {
|
|||||||
|
|
||||||
// sum = product , { ( PLUS | MINUS | PLUS_MINUS ) product } ;
|
// sum = product , { ( PLUS | MINUS | PLUS_MINUS ) product } ;
|
||||||
private Pattern sum() throws SyntaxException {
|
private Pattern sum() throws SyntaxException {
|
||||||
return matchLeftAssoc(this::product, Map.ofEntries(
|
return matchLeftAssoc(this::product, MapFactory.fromEntries(
|
||||||
Map.entry(PLUS, SumPattern::new),
|
MapFactory.entry(PLUS, SumPattern::new),
|
||||||
Map.entry(MINUS, SubtractionPattern::new),
|
MapFactory.entry(MINUS, SubtractionPattern::new),
|
||||||
Map.entry(PLUS_MINUS, SumSubtractionPattern::new)
|
MapFactory.entry(PLUS_MINUS, SumSubtractionPattern::new)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// product = unary , { ( TIMES | DIVIDE ) unary } ;
|
// product = unary , { ( TIMES | DIVIDE ) unary } ;
|
||||||
private Pattern product() throws SyntaxException {
|
private Pattern product() throws SyntaxException {
|
||||||
return matchLeftAssoc(this::unary, Map.ofEntries(
|
return matchLeftAssoc(this::unary, MapFactory.fromEntries(
|
||||||
Map.entry(TIMES, MultiplicationPattern::new),
|
MapFactory.entry(TIMES, MultiplicationPattern::new),
|
||||||
Map.entry(DIVIDE, DivisionPattern::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
|
// function = ( ARCCOS | ARCSIN | ARCTAN | COS | SIN | SQRT | TAN ) , LEFT_PAREN , sum , RIGHT_PAREN
|
||||||
// | ( LOG | ROOT ) LEFT_PAREN , sum , COMMA , sum , RIGHT_PAREN ;
|
// | ( LOG | ROOT ) LEFT_PAREN , sum , COMMA , sum , RIGHT_PAREN ;
|
||||||
private Pattern tryFunction() throws SyntaxException {
|
private Pattern tryFunction() throws SyntaxException {
|
||||||
final Map<TokenType, Function<Pattern, Pattern>> oneArg = Map.ofEntries(
|
final Map<TokenType, Function<Pattern, Pattern>> oneArg = MapFactory.fromEntries(
|
||||||
Map.entry(ARCCOS, ArcCosinePattern::new),
|
MapFactory.entry(ARCCOS, ArcCosinePattern::new),
|
||||||
Map.entry(ARCSIN, ArcSinePattern::new),
|
MapFactory.entry(ARCSIN, ArcSinePattern::new),
|
||||||
Map.entry(ARCTAN, ArcTangentPattern::new),
|
MapFactory.entry(ARCTAN, ArcTangentPattern::new),
|
||||||
Map.entry(COS, CosinePattern::new),
|
MapFactory.entry(COS, CosinePattern::new),
|
||||||
Map.entry(SIN, SinePattern::new),
|
MapFactory.entry(SIN, SinePattern::new),
|
||||||
Map.entry(SQRT, arg -> new RootPattern(new NumberPattern(new BigDecimal(2)), arg)),
|
MapFactory.entry(SQRT, arg -> new RootPattern(new NumberPattern(new BigDecimal(2)), arg)),
|
||||||
Map.entry(TAN, TangentPattern::new)
|
MapFactory.entry(TAN, TangentPattern::new)
|
||||||
);
|
);
|
||||||
final Map<TokenType, BiFunction<Pattern, Pattern, Pattern>> twoArg = Map.ofEntries(
|
final Map<TokenType, BiFunction<Pattern, Pattern, Pattern>> twoArg = MapFactory.fromEntries(
|
||||||
Map.entry(LOG, LogarithmPattern::new),
|
MapFactory.entry(LOG, LogarithmPattern::new),
|
||||||
Map.entry(ROOT, RootPattern::new)
|
MapFactory.entry(ROOT, RootPattern::new)
|
||||||
);
|
);
|
||||||
|
|
||||||
final TokenType curType = peek().type;
|
final TokenType curType = peek().type;
|
||||||
|
@ -2,6 +2,8 @@ package it.cavallium.warppi.math.rules.dsl.frontend;
|
|||||||
|
|
||||||
import it.cavallium.warppi.math.rules.dsl.DslError;
|
import it.cavallium.warppi.math.rules.dsl.DslError;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ public class UnexpectedToken implements DslError {
|
|||||||
|
|
||||||
public UnexpectedToken(final Token unexpected, final TokenType... suggested) {
|
public UnexpectedToken(final Token unexpected, final TokenType... suggested) {
|
||||||
this.unexpected = unexpected;
|
this.unexpected = unexpected;
|
||||||
this.suggested = Set.of(suggested);
|
this.suggested = new HashSet<>(Arrays.asList(suggested)); // TeaVM doesn't support Set.of
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
52
core/src/main/java/it/cavallium/warppi/util/MapFactory.java
Normal file
52
core/src/main/java/it/cavallium/warppi/util/MapFactory.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user