diff --git a/jscl/src/main/java/jscl/math/Expression.java b/jscl/src/main/java/jscl/math/Expression.java index 6a8be1d0..53c4224e 100644 --- a/jscl/src/main/java/jscl/math/Expression.java +++ b/jscl/src/main/java/jscl/math/Expression.java @@ -123,7 +123,7 @@ public class Expression extends Generic { int index = position.intValue(); if (index < expression.length()) { - throw new ParseException(Messages.msg_1, index, expression, index + 1); + throw new ParseException(index, expression, Messages.msg_1, index + 1); } return new Expression().init(generic); diff --git a/jscl/src/main/java/jscl/text/CompoundIdentifier.java b/jscl/src/main/java/jscl/text/CompoundIdentifier.java index b52665fe..94145d51 100644 --- a/jscl/src/main/java/jscl/text/CompoundIdentifier.java +++ b/jscl/src/main/java/jscl/text/CompoundIdentifier.java @@ -33,6 +33,7 @@ public class CompoundIdentifier implements Parser { // NOTE: '.' must be appended after parsing result.append(".").append(dotAndId); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } diff --git a/jscl/src/main/java/jscl/text/ConstantParser.java b/jscl/src/main/java/jscl/text/ConstantParser.java index 4aa0f1a9..58eddb11 100644 --- a/jscl/src/main/java/jscl/text/ConstantParser.java +++ b/jscl/src/main/java/jscl/text/ConstantParser.java @@ -25,6 +25,7 @@ public class ConstantParser implements Parser { try { l.add(Subscript.parser.parse(p, previousSumElement)); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } @@ -33,6 +34,7 @@ public class ConstantParser implements Parser { try { prime = Prime.parser.parse(p, previousSumElement); } catch (ParseException e) { + p.exceptionsPool.release(e); } return new Constant(name, prime, ArrayUtils.toArray(l, new Generic[l.size()])); diff --git a/jscl/src/main/java/jscl/text/DoubleParser.java b/jscl/src/main/java/jscl/text/DoubleParser.java index a5edcf0e..bbe9eb23 100644 --- a/jscl/src/main/java/jscl/text/DoubleParser.java +++ b/jscl/src/main/java/jscl/text/DoubleParser.java @@ -10,6 +10,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; public class DoubleParser implements Parser { @@ -80,6 +81,7 @@ class FloatingPointLiteral implements Parser { result.append(digitsParser.parse(p, previousSumElement)); digits = true; } catch (ParseException e) { + p.exceptionsPool.release(e); } try { @@ -90,6 +92,8 @@ class FloatingPointLiteral implements Parser { if (!digits) { p.position.setValue(pos0); throw e; + } else { + p.exceptionsPool.release(e); } } @@ -103,6 +107,8 @@ class FloatingPointLiteral implements Parser { if (!digits) { p.position.setValue(pos0); throw e; + } else { + p.exceptionsPool.release(e); } } @@ -113,6 +119,8 @@ class FloatingPointLiteral implements Parser { if (!point) { p.position.setValue(pos0); throw e; + } else { + p.exceptionsPool.release(e); } } @@ -124,7 +132,7 @@ class FloatingPointLiteral implements Parser { try { return nb.toDouble(doubleString); } catch (NumberFormatException e) { - throw new ParseException(Messages.msg_8, p.position.intValue(), p.expression, doubleString); + throw p.exceptionsPool.obtain(p.position.intValue(), p.expression, Messages.msg_8, Collections.singletonList(doubleString)); } } } diff --git a/jscl/src/main/java/jscl/text/ExceptionsPool.java b/jscl/src/main/java/jscl/text/ExceptionsPool.java new file mode 100644 index 00000000..a0089778 --- /dev/null +++ b/jscl/src/main/java/jscl/text/ExceptionsPool.java @@ -0,0 +1,28 @@ +package jscl.text; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ExceptionsPool { + + @Nonnull + private final List list = new ArrayList<>(); + + @Nonnull + public ParseException obtain(int position, @Nonnull String expression, @Nonnull String messageCode) { + return obtain(position, expression, messageCode, Collections.emptyList()); + } + + @Nonnull + public ParseException obtain(int position, @Nonnull String expression, @Nonnull String messageCode, @Nonnull List messagesArgs) { + final ParseException exception = !list.isEmpty() ? list.remove(list.size() - 1) : new ParseException(); + exception.set(position, expression, messageCode, messagesArgs); + return exception; + } + + public void release(@Nonnull ParseException e) { + list.add(e); + } +} diff --git a/jscl/src/main/java/jscl/text/ExpressionParser.java b/jscl/src/main/java/jscl/text/ExpressionParser.java index 40f85e67..b406fb12 100644 --- a/jscl/src/main/java/jscl/text/ExpressionParser.java +++ b/jscl/src/main/java/jscl/text/ExpressionParser.java @@ -25,6 +25,7 @@ public class ExpressionParser implements Parser { try { result = result.add(PlusOrMinusTerm.parser.parse(p, result)); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } diff --git a/jscl/src/main/java/jscl/text/ImplicitFunctionParser.java b/jscl/src/main/java/jscl/text/ImplicitFunctionParser.java index b24868ed..e220f731 100644 --- a/jscl/src/main/java/jscl/text/ImplicitFunctionParser.java +++ b/jscl/src/main/java/jscl/text/ImplicitFunctionParser.java @@ -10,6 +10,7 @@ import jscl.util.ArrayUtils; import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class ImplicitFunctionParser implements Parser { @@ -25,7 +26,7 @@ public class ImplicitFunctionParser implements Parser { final String name = ParserUtils.parseWithRollback(CompoundIdentifier.parser, pos0, previousSumElement, p); if (FunctionsRegistry.getInstance().getNames().contains(name) || OperatorsRegistry.getInstance().getNames().contains(name)) { p.position.setValue(pos0); - throw new ParseException(Messages.msg_6, p.position.intValue(), p.expression, name); + throw p.exceptionsPool.obtain(p.position.intValue(), p.expression, Messages.msg_6, Collections.singletonList(name)); } final List subscripts = new ArrayList(); @@ -33,6 +34,7 @@ public class ImplicitFunctionParser implements Parser { try { subscripts.add(Subscript.parser.parse(p, previousSumElement)); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } @@ -41,6 +43,7 @@ public class ImplicitFunctionParser implements Parser { try { b = Derivation.parser.parse(p, previousSumElement); } catch (ParseException e) { + p.exceptionsPool.release(e); b = new int[0]; } try { @@ -67,15 +70,12 @@ class Derivation implements Parser { } public int[] parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { - - int result[]; try { - result = new int[]{PrimeCharacters.parser.parse(p, previousSumElement)}; + return new int[]{PrimeCharacters.parser.parse(p, previousSumElement)}; } catch (ParseException e) { - result = SuperscriptList.parser.parse(p, previousSumElement); + p.exceptionsPool.release(e); } - - return result; + return SuperscriptList.parser.parse(p, previousSumElement); } } @@ -103,6 +103,7 @@ class SuperscriptList implements Parser { try { result.add(CommaAndInteger.parser.parse(p, previousSumElement)); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } diff --git a/jscl/src/main/java/jscl/text/IntegerParser.java b/jscl/src/main/java/jscl/text/IntegerParser.java index 83622339..0c1de355 100644 --- a/jscl/src/main/java/jscl/text/IntegerParser.java +++ b/jscl/src/main/java/jscl/text/IntegerParser.java @@ -6,6 +6,7 @@ import jscl.text.msg.Messages; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Collections; public class IntegerParser implements Parser { @@ -46,7 +47,7 @@ public class IntegerParser implements Parser { result.append(c); } else { p.position.setValue(pos0); - throw new ParseException(Messages.msg_7, p.position.intValue(), p.expression); + throw p.exceptionsPool.obtain(p.position.intValue(), p.expression, Messages.msg_7); } while (p.position.intValue() < p.expression.length() && nb.getAcceptableCharacters().contains(p.expression.charAt(p.position.intValue()))) { @@ -59,7 +60,7 @@ public class IntegerParser implements Parser { try { return nb.toInteger(number); } catch (NumberFormatException e) { - throw new ParseException(Messages.msg_8, p.position.intValue(), p.expression, number); + throw p.exceptionsPool.obtain(p.position.intValue(), p.expression, Messages.msg_8, Collections.singletonList(number)); } } } diff --git a/jscl/src/main/java/jscl/text/JsclIntegerParser.java b/jscl/src/main/java/jscl/text/JsclIntegerParser.java index 690aad17..f82f89aa 100644 --- a/jscl/src/main/java/jscl/text/JsclIntegerParser.java +++ b/jscl/src/main/java/jscl/text/JsclIntegerParser.java @@ -7,6 +7,7 @@ import jscl.text.msg.Messages; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Collections; public class JsclIntegerParser implements Parser { @@ -33,7 +34,7 @@ public class JsclIntegerParser implements Parser { try { return nb.toJsclInteger(number); } catch (NumberFormatException e) { - throw new ParseException(Messages.msg_8, p.position.intValue(), p.expression, number); + throw p.exceptionsPool.obtain(p.position.intValue(), p.expression, Messages.msg_8, Collections.singletonList(number)); } } } diff --git a/jscl/src/main/java/jscl/text/MatrixParser.java b/jscl/src/main/java/jscl/text/MatrixParser.java index 33671142..e37fe181 100644 --- a/jscl/src/main/java/jscl/text/MatrixParser.java +++ b/jscl/src/main/java/jscl/text/MatrixParser.java @@ -34,6 +34,7 @@ public class MatrixParser implements Parser { try { vectors.add(CommaAndVector.parser.parse(p, previousSumElement)); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } diff --git a/jscl/src/main/java/jscl/text/MatrixVariableParser.java b/jscl/src/main/java/jscl/text/MatrixVariableParser.java index c8e233da..be905278 100644 --- a/jscl/src/main/java/jscl/text/MatrixVariableParser.java +++ b/jscl/src/main/java/jscl/text/MatrixVariableParser.java @@ -1,7 +1,6 @@ package jscl.text; import jscl.math.Generic; -import jscl.math.Matrix; import jscl.math.MatrixVariable; import jscl.math.Variable; @@ -14,12 +13,6 @@ class MatrixVariableParser implements Parser { } public Variable parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { - Matrix m; - try { - m = (Matrix) MatrixParser.parser.parse(p, previousSumElement); - } catch (ParseException e) { - throw e; - } - return new MatrixVariable(m); + return new MatrixVariable(MatrixParser.parser.parse(p, previousSumElement)); } } diff --git a/jscl/src/main/java/jscl/text/NumeralBaseParser.java b/jscl/src/main/java/jscl/text/NumeralBaseParser.java index ba2b4feb..a8a38e86 100644 --- a/jscl/src/main/java/jscl/text/NumeralBaseParser.java +++ b/jscl/src/main/java/jscl/text/NumeralBaseParser.java @@ -27,6 +27,7 @@ public class NumeralBaseParser implements Parser { result = numeralBase; break; } catch (ParseException e) { + p.exceptionsPool.release(e); } } diff --git a/jscl/src/main/java/jscl/text/ParameterListParser.java b/jscl/src/main/java/jscl/text/ParameterListParser.java index c92db0bb..095283f7 100644 --- a/jscl/src/main/java/jscl/text/ParameterListParser.java +++ b/jscl/src/main/java/jscl/text/ParameterListParser.java @@ -34,6 +34,8 @@ public class ParameterListParser implements Parser { if (minNumberOfParameters > 0) { p.position.setValue(pos0); throw e; + } else { + p.exceptionsPool.release(e); } } @@ -41,6 +43,7 @@ public class ParameterListParser implements Parser { try { result.add(CommaAndExpression.parser.parse(p, previousSumElement)); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } diff --git a/jscl/src/main/java/jscl/text/ParseException.java b/jscl/src/main/java/jscl/text/ParseException.java index 4b3dba8e..d99fe2d2 100644 --- a/jscl/src/main/java/jscl/text/ParseException.java +++ b/jscl/src/main/java/jscl/text/ParseException.java @@ -1,56 +1,61 @@ package jscl.text; -import jscl.text.msg.JsclMessage; +import org.solovyev.common.collections.Collections; import org.solovyev.common.msg.Message; import org.solovyev.common.msg.MessageLevel; import org.solovyev.common.msg.MessageType; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.List; import java.util.Locale; +import java.util.ResourceBundle; public class ParseException extends Exception implements Message { + private int position; @Nonnull - private final Message message; - - private final int position; - + private String expression; @Nonnull - private final String expression; + private String messageCode; + @Nonnull + private List parameters; - public ParseException(@Nonnull String messageCode, int position, @Nonnull String expression, Object... parameters) { - this.message = new JsclMessage(messageCode, MessageType.error, parameters); - this.position = position; - this.expression = expression; + ParseException() { } - public ParseException(@Nonnull Message message, int position, @Nonnull String expression) { - this.message = message; + public ParseException(int position, @Nonnull String expression, @Nonnull String messageCode, @Nullable Object... parameters) { + set(position, expression, messageCode, Collections.asList(parameters)); + } + + void set(int position, @Nonnull String expression, @Nonnull String messageCode, @Nonnull List parameters) { this.position = position; this.expression = expression; + this.messageCode = messageCode; + this.parameters = parameters; } @Nonnull public String getMessageCode() { - return this.message.getMessageCode(); + return messageCode; } @Nonnull public List getParameters() { - return this.message.getParameters(); + return (List) parameters; } @Nonnull @Override public MessageLevel getMessageLevel() { - return this.message.getMessageLevel(); + return MessageType.error; } @Nonnull @Override public String getLocalizedMessage(@Nonnull Locale locale) { - return this.message.getLocalizedMessage(locale); + final ResourceBundle rb = ResourceBundle.getBundle("jscl/text/msg/messages", locale); + return rb.getString(getMessageCode()); } public int getPosition() { @@ -67,20 +72,21 @@ public class ParseException extends Exception implements Message { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - ParseException that = (ParseException) o; + ParseException exception = (ParseException) o; - if (position != that.position) return false; - if (!expression.equals(that.expression)) return false; - if (!message.equals(that.message)) return false; + if (position != exception.position) return false; + if (!expression.equals(exception.expression)) return false; + if (!messageCode.equals(exception.messageCode)) return false; + return parameters.equals(exception.parameters); - return true; } @Override public int hashCode() { - int result = message.hashCode(); - result = 31 * result + position; + int result = position; result = 31 * result + expression.hashCode(); + result = 31 * result + messageCode.hashCode(); + result = 31 * result + parameters.hashCode(); return result; } } diff --git a/jscl/src/main/java/jscl/text/Parser.java b/jscl/src/main/java/jscl/text/Parser.java index 0b7525ce..813fb328 100644 --- a/jscl/src/main/java/jscl/text/Parser.java +++ b/jscl/src/main/java/jscl/text/Parser.java @@ -39,6 +39,9 @@ public interface Parser { @Nonnull public final MathContext context; + @Nonnull + public final ExceptionsPool exceptionsPool = new ExceptionsPool(); + /** * @param expression expression to be parsed * @param position current position of expression. Side effect: if parsing is successful this parameter should be increased on the number of parsed letters (incl whitespaces etc) diff --git a/jscl/src/main/java/jscl/text/ParserUtils.java b/jscl/src/main/java/jscl/text/ParserUtils.java index dc9baab5..01168b43 100644 --- a/jscl/src/main/java/jscl/text/ParserUtils.java +++ b/jscl/src/main/java/jscl/text/ParserUtils.java @@ -2,6 +2,7 @@ package jscl.text; import jscl.math.Generic; import jscl.text.msg.Messages; +import org.solovyev.common.collections.Collections; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -67,7 +68,7 @@ public class ParserUtils { @Nonnull String messageId, Object... parameters) throws ParseException { final MutableInt position = p.position; - final ParseException parseException = new ParseException(messageId, position.intValue(), p.expression, parameters); + final ParseException parseException = p.exceptionsPool.obtain(position.intValue(), p.expression, messageId, Collections.asList(parameters)); position.setValue(pos0); throw parseException; } diff --git a/jscl/src/main/java/jscl/text/PostfixFunctionsParser.java b/jscl/src/main/java/jscl/text/PostfixFunctionsParser.java index 32a70d7c..2f8ec3ee 100644 --- a/jscl/src/main/java/jscl/text/PostfixFunctionsParser.java +++ b/jscl/src/main/java/jscl/text/PostfixFunctionsParser.java @@ -9,6 +9,7 @@ import jscl.text.msg.Messages; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -28,11 +29,11 @@ public class PostfixFunctionsParser implements Parser { private static Generic parsePostfix(@Nonnull List parsers, Generic content, @Nullable final Generic previousSumElement, - @Nonnull final Parameters parseParameters) throws ParseException { + @Nonnull final Parameters p) throws ParseException { Generic result = content; for (PostfixFunctionParser parser : parsers) { - final PostfixFunctionParser.Result postfixResult = parser.parse(parseParameters, previousSumElement); + final PostfixFunctionParser.Result postfixResult = parser.parse(p, previousSumElement); if (postfixResult.isPostfixFunction()) { final Operator postfixFunction; @@ -44,13 +45,13 @@ public class PostfixFunctionsParser implements Parser { if (postfixFunction == null) { if (TripleFactorial.NAME.equals(postfixResult.getPostfixFunctionName())) { - throw new ParseException(Messages.msg_18, parseParameters.position.intValue(), parseParameters.expression); + throw p.exceptionsPool.obtain(p.position.intValue(), p.expression, Messages.msg_18); } else { - throw new ParseException(Messages.msg_4, parseParameters.position.intValue(), parseParameters.expression, postfixResult.getPostfixFunctionName()); + throw p.exceptionsPool.obtain(p.position.intValue(), p.expression, Messages.msg_4, Collections.singletonList(postfixResult.getPostfixFunctionName())); } } - result = parsePostfix(parsers, postfixFunction.expressionValue(), previousSumElement, parseParameters); + result = parsePostfix(parsers, postfixFunction.expressionValue(), previousSumElement, p); } } diff --git a/jscl/src/main/java/jscl/text/TermParser.java b/jscl/src/main/java/jscl/text/TermParser.java index 438640b2..35749273 100644 --- a/jscl/src/main/java/jscl/text/TermParser.java +++ b/jscl/src/main/java/jscl/text/TermParser.java @@ -31,6 +31,7 @@ class TermParser implements Parser { result = result.multiply(s); s = b; } catch (ParseException e) { + p.exceptionsPool.release(e); try { Generic b = DivideFactor.parser.parse(p, null); if (s.compareTo(JsclInteger.valueOf(1)) == 0) @@ -38,6 +39,7 @@ class TermParser implements Parser { else s = new Fraction(GenericVariable.content(s, true), GenericVariable.content(b, true)).expressionValue(); } catch (ParseException e2) { + p.exceptionsPool.release(e2); break; } } diff --git a/jscl/src/main/java/jscl/text/UnsignedFactor.java b/jscl/src/main/java/jscl/text/UnsignedFactor.java index 46cfb0f7..acb10840 100644 --- a/jscl/src/main/java/jscl/text/UnsignedFactor.java +++ b/jscl/src/main/java/jscl/text/UnsignedFactor.java @@ -33,6 +33,7 @@ class UnsignedFactor implements Parser { try { list.add(PowerExponentParser.parser.parse(p, null)); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } diff --git a/jscl/src/main/java/jscl/text/VectorParser.java b/jscl/src/main/java/jscl/text/VectorParser.java index ad98ba50..12173c96 100644 --- a/jscl/src/main/java/jscl/text/VectorParser.java +++ b/jscl/src/main/java/jscl/text/VectorParser.java @@ -34,6 +34,7 @@ public class VectorParser implements Parser { try { result.add(CommaAndExpression.parser.parse(p, previousSumElement)); } catch (ParseException e) { + p.exceptionsPool.release(e); break; } } diff --git a/jscl/src/main/java/jscl/text/VectorVariableParser.java b/jscl/src/main/java/jscl/text/VectorVariableParser.java index 93a696b3..0f342543 100644 --- a/jscl/src/main/java/jscl/text/VectorVariableParser.java +++ b/jscl/src/main/java/jscl/text/VectorVariableParser.java @@ -1,7 +1,6 @@ package jscl.text; import jscl.math.Generic; -import jscl.math.JsclVector; import jscl.math.Variable; import jscl.math.VectorVariable; @@ -14,12 +13,6 @@ public class VectorVariableParser implements Parser { } public Variable parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { - JsclVector result; - try { - result = VectorParser.parser.parse(p, previousSumElement); - } catch (ParseException e) { - throw e; - } - return new VectorVariable(result); + return new VectorVariable(VectorParser.parser.parse(p, previousSumElement)); } }