sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Partial fix of exponent parsing in expression like (m.s)-1.
Date Mon, 06 Aug 2018 12:02:11 GMT
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 <martin.desruisseaux@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");


Mime
View raw message