package jscl.text; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; import jscl.NumeralBase; import jscl.math.Generic; import jscl.math.NumericWrapper; import jscl.math.numeric.Real; import jscl.text.msg.Messages; public class DoubleParser implements Parser<NumericWrapper> { public static final Parser<NumericWrapper> parser = new DoubleParser(); private static final List<Parser<Double>> parsers = Arrays.asList( Singularity.parser, FloatingPointLiteral.parser); private DoubleParser() { } @Nonnull public NumericWrapper parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { final Parser<Double> multiTryParser = new MultiTryParser<Double>(new ArrayList<Parser<? extends Double>>(parsers)); return new NumericWrapper(Real.valueOf(multiTryParser.parse(p, previousSumElement))); } } class Singularity implements Parser<Double> { public static final Parser<Double> parser = new Singularity(); private Singularity() { } @Nonnull public Double parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { int pos0 = p.position.intValue(); double result = 0d; String s = Identifier.parser.parse(p, previousSumElement); if (s.equals("NaN")) { result = Double.NaN; } else if (s.equals("Infinity") || s.equals("∞")) { result = Double.POSITIVE_INFINITY; } else { ParserUtils.throwParseException(p, pos0, Messages.msg_10, "NaN", "∞"); } return result; } } class FloatingPointLiteral implements Parser<Double> { public static final Parser<Double> parser = new FloatingPointLiteral(); private FloatingPointLiteral() { } public Double parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { int pos0 = p.position.intValue(); final NumeralBase nb = NumeralBaseParser.parser.parse(p, previousSumElement); boolean digits = false; boolean point = false; boolean exponent = false; final Digits digitsParser = new Digits(nb); final StringBuilder result = new StringBuilder(); try { result.append(digitsParser.parse(p, previousSumElement)); digits = true; } catch (ParseException e) { p.exceptionsPool.release(e); } try { DecimalPoint.parser.parse(p, previousSumElement); result.append("."); point = true; } catch (ParseException e) { if (!digits) { p.position.setValue(pos0); throw e; } else { p.exceptionsPool.release(e); } } if (point && nb != NumeralBase.dec) { ParserUtils.throwParseException(p, pos0, Messages.msg_15); } try { result.append(digitsParser.parse(p, previousSumElement)); } catch (ParseException e) { if (!digits) { p.position.setValue(pos0); throw e; } else { p.exceptionsPool.release(e); } } try { result.append(ExponentPart.parser.parse(p, previousSumElement)); exponent = true; } catch (ParseException e) { if (!point) { p.position.setValue(pos0); throw e; } else { p.exceptionsPool.release(e); } } if (exponent && nb != NumeralBase.dec) { ParserUtils.throwParseException(p, pos0, Messages.msg_15); } final String doubleString = result.toString(); try { return nb.toDouble(doubleString); } catch (NumberFormatException e) { throw p.exceptionsPool.obtain(p.position.intValue(), p.expression, Messages.msg_8, Collections.singletonList(doubleString)); } } } class DecimalPoint implements Parser<Void> { public static final Parser<Void> parser = new DecimalPoint(); private DecimalPoint() { } @Nullable public Void parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { int pos0 = p.position.intValue(); ParserUtils.skipWhitespaces(p); ParserUtils.tryToParse(p, pos0, '.'); return null; } } class ExponentPart implements Parser<String> { public static final Parser<String> parser = new ExponentPart(); private ExponentPart() { } @Nonnull public String parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { int pos0 = p.position.intValue(); ParserUtils.skipWhitespaces(p); final StringBuilder result; if (p.position.intValue() < p.expression.length() && (p.expression.charAt(p.position.intValue()) == 'e' || p.expression.charAt(p.position.intValue()) == 'E')) { result = new StringBuilder(); result.append(p.expression.charAt(p.position.intValue())); p.position.increment(); } else { throw ParserUtils.makeParseException(p, pos0, Messages.msg_10, 'e', 'E'); } try { result.append(SignedInteger.parser.parse(p, previousSumElement)); } catch (ParseException e) { p.position.setValue(pos0); throw e; } return result.toString(); } } class SignedInteger implements Parser<String> { public static final Parser<String> parser = new SignedInteger(); private SignedInteger() { } @Nonnull public String parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException { final int pos0 = p.position.intValue(); ParserUtils.skipWhitespaces(p); final StringBuilder result = new StringBuilder(); final int pos1 = p.position.intValue(); if (pos1 < p.expression.length() && (p.expression.charAt(pos1) == '+' || MinusParser.isMinus(p.expression.charAt(pos1)))) { final char c = p.expression.charAt(pos1); p.position.increment(); result.append(c); } try { result.append(IntegerParser.parser.parse(p, previousSumElement).intValue()); } catch (ParseException e) { p.position.setValue(pos0); throw e; } return result.toString(); } }