You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2018/08/06 12:02:11 UTC
[sis] branch geoapi-4.0 updated: Partial fix of exponent parsing in
expression like (m.s)-1.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new c028527 Partial fix of exponent parsing in expression like (m.s)-1.
c028527 is described below
commit c0285273453128352190ca5c584181a4d8a987eb
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Mon Aug 6 10:53:37 2018 +0200
Partial fix of exponent parsing in expression like (m.s)-1.
---
.../java/org/apache/sis/measure/UnitFormat.java | 61 +++++++++++++++++-----
.../org/apache/sis/measure/UnitFormatTest.java | 4 +-
2 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
index ee7cc59..cdf6332 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
@@ -1080,7 +1080,7 @@ public class UnitFormat extends Format implements javax.measure.format.UnitForma
*
* The 'start' variable is the index of the first character of the next unit term to parse.
*/
- final Operation operation = new Operation(); // Enumeration value: NOOP, IMPLICIT, MULTIPLY, DIVIDE.
+ final Operation operation = new Operation(symbols); // Enumeration value: NOOP, IMPLICIT, MULTIPLY, DIVIDE.
Unit<?> unit = null;
boolean hasSpaces = false;
int i = start;
@@ -1090,6 +1090,19 @@ scan: for (int n; i < end; i += n) {
final int next;
switch (c) {
/*
+ * The minus sign can be both part of a number or part of a symbol. If the minus sign if followed
+ * by a digit, then handle it as part of a number, in which case the action is only "continue".
+ * Otherwise handle as part of a symbol, in which case the action is in the default case below.
+ * The intent is to prevent the replacement of Operation.IMPLICIT by Operation.MULTIPLY in symbol
+ * like "(m²⋅s)-1" because we want the "-1" part to be handled as Operation.EXPONENT instead.
+ */
+ case '-': {
+ if (i + n < end && Character.isDigit(Character.codePointAt(symbols, i + n))) {
+ continue;
+ }
+ // else fall through.
+ }
+ /*
* For any character that are is not an operator or parenthesis, either continue the scanning of
* characters or stop it, depending on whether the character is valid for a unit symbol or not.
* In the later case, we consider that we reached the end of a unit symbol.
@@ -1126,8 +1139,8 @@ scan: for (int n; i < end; i += n) {
}
case Style.EXPONENT: {
if (operation.code == Operation.IMPLICIT) {
- // Support of exponentiation after parenthesis is not yet supported.
- break scan;
+ next = Operation.EXPONENT;
+ break;
}
continue;
}
@@ -1150,14 +1163,15 @@ scan: for (int n; i < end; i += n) {
* find that closing parenthesis, this will be considered an error.
*/
case Style.OPEN: {
- final ParsePosition sub = new ParsePosition(i + Character.charCount(c));
+ final int pos = i + Character.charCount(c);
+ final ParsePosition sub = new ParsePosition(pos);
final Unit<?> term = parse(symbols, sub);
i = CharSequences.skipLeadingWhitespaces(symbols, sub.getIndex(), end);
if (i >= end || Character.codePointAt(symbols, i) != Style.CLOSE) {
throw new ParserException(Errors.format(Errors.Keys.NonEquilibratedParenthesis_2,
symbols.subSequence(start, i), Style.CLOSE), symbols, start);
}
- unit = operation.apply(unit, term);
+ unit = operation.apply(unit, term, pos);
operation.code = Operation.IMPLICIT; // Default operation if there is no × or / symbols after parenthesis.
start = i + (n = 1); // Skip the number of characters in the '(' Unicode code point.
continue;
@@ -1182,7 +1196,7 @@ scan: for (int n; i < end; i += n) {
* the above 'switch' statement all cases that end with 'break', not 'break scan' or 'continue').
*/
if (operation.code != Operation.IMPLICIT) {
- unit = operation.apply(unit, parseTerm(symbols, start, i, operation));
+ unit = operation.apply(unit, parseTerm(symbols, start, i, operation), start);
}
hasSpaces = false;
operation.code = next;
@@ -1230,7 +1244,7 @@ search: while ((i = CharSequences.skipTrailingWhitespaces(symbols, start, i)
if (component == null) {
component = parseTerm(symbols, start, i, operation);
}
- unit = operation.apply(unit, component);
+ unit = operation.apply(unit, component, start);
position.setIndex(endOfURI >= 0 ? endOfURI : i);
return unit;
}
@@ -1245,7 +1259,7 @@ search: while ((i = CharSequences.skipTrailingWhitespaces(symbols, start, i)
* The {@code IMPLICIT} case is a multiplication without symbol, which can be
* overridden by an explicit × or / symbol.
*/
- static final int NOOP = 0, IMPLICIT = 1, MULTIPLY = 2, DIVIDE = 3;
+ static final int NOOP = 0, IMPLICIT = 1, MULTIPLY = 2, DIVIDE = 3, EXPONENT = 4;
/**
* The operation as one of the {@link #NOOP}, {@link #IMPLICIT}, {@link #MULTIPLY}
@@ -1254,23 +1268,43 @@ search: while ((i = CharSequences.skipTrailingWhitespaces(symbols, start, i)
int code;
/**
+ * The symbols being parsed. Used only for formatting error message if needed.
+ */
+ private final CharSequence symbols;
+
+ /**
* Creates an operation initialized to {@link #NOOP}.
*/
- Operation() {
+ Operation(final CharSequence symbols) {
+ this.symbols = symbols;
}
/**
* Applies a multiplication or division operation between the given units.
*
- * @param unit the left operand, which is the unit parsed so far.
- * @param term the right operation, which is the newly parsed unit.
+ * @param unit the left operand, which is the unit parsed so far.
+ * @param term the right operation, which is the newly parsed unit.
+ * @param position the parse position to report if parsing fail.
*/
- Unit<?> apply(final Unit<?> unit, final Unit<?> term) {
+ Unit<?> apply(final Unit<?> unit, final Unit<?> term, final int position) {
switch (code) {
case NOOP: return term;
case IMPLICIT:
case MULTIPLY: return unit.multiply(term);
case DIVIDE: return unit.divide(term);
+ case EXPONENT: {
+ if (UnitDimension.isDimensionless(term.getDimension())) {
+ final String symbol = term.getSymbol();
+ if (symbol == null || symbol.isEmpty()) {
+ final double scale = Units.toStandardUnit(term);
+ final int power = (int) scale;
+ if (power == scale) {
+ return unit.pow(power);
+ }
+ }
+ }
+ throw new ParserException(Errors.format(Errors.Keys.NotAnInteger_1, term), symbols, position);
+ }
default: throw new AssertionError(code);
}
}
@@ -1350,6 +1384,9 @@ search: while ((i = CharSequences.skipTrailingWhitespaces(symbols, start, i)
throw (ParserException) new ParserException(Errors.format(
Errors.Keys.UnknownUnit_1, uom), symbols, lower).initCause(e);
}
+ if (operation.code == Operation.IMPLICIT) {
+ operation.code = Operation.EXPONENT;
+ }
return Units.UNITY.multiply(multiplier);
}
}
diff --git a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
index ae55366..e32ef1a 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
@@ -620,6 +620,8 @@ public final strictfp class UnitFormatTest extends TestCase {
roundtrip(f, "kg.m-3.s-1", "kg∕(m³⋅s)");
roundtrip(f, "m.rad-1", "m∕rad");
roundtrip(f, "rad.s-1", "rad∕s");
+ roundtrip(f, "(m2.s)^-1", "1∕(m²⋅s)");
+ roundtrip(f, "(m2.s)-1", "1∕(m²⋅s)");
}
/**
@@ -635,7 +637,7 @@ public final strictfp class UnitFormatTest extends TestCase {
public void needForImprovements() {
final UnitFormat f = new UnitFormat(Locale.UK);
roundtrip(f, "kg.kg-1.m.s-1", "m∕s");
- roundtrip(f, "(m2.s.sr)-1", "-1⋅m²⋅s"); // TODO: this one is a bug.
+ roundtrip(f, "(m2.s.sr)-1", "1∕(m²⋅s)");
roundtrip(f, "cm/day", "1.1574074074074074E-7⋅m∕s");
roundtrip(f, "m-2.s.rad-1", "s∕m²");
roundtrip(f, "kg.kg-1.s-1", "Hz");