All Downloads are FREE. Search and download functionalities are using the official Maven repository.

parsley.token.numeric.UnsignedCombined.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2020 Parsley Contributors 
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
package parsley.token.numeric

import parsley.Parsley, Parsley.atomic
import parsley.token.descriptions.numeric.NumericDesc
import parsley.token.errors.ErrorConfig

import org.typelevel.scalaccompat.annotation.unused

private [token] final class UnsignedCombined(@unused desc: NumericDesc, integer: IntegerParsers, rational: RealParsers, err: ErrorConfig)
    extends CombinedParsers(err) {
    override lazy val decimal: Parsley[Either[BigInt, BigDecimal]] = (atomic(rational.decimal) <+> integer.decimal).map(_.swap)
    override lazy val hexadecimal: Parsley[Either[BigInt, BigDecimal]] = (atomic(rational.hexadecimal) <+> integer.hexadecimal).map(_.swap)
    override lazy val octal: Parsley[Either[BigInt, BigDecimal]] = (atomic(rational.octal) <+> integer.octal).map(_.swap)
    override lazy val binary: Parsley[Either[BigInt, BigDecimal]] = (atomic(rational.binary) <+> integer.binary).map(_.swap)
    override lazy val number: Parsley[Either[BigInt, BigDecimal]] = (atomic(rational.number) <+> integer.number).map(_.swap)

    // FIXME: gross :( we should restructure this to be more reusable friendly
    // FIXME: This doesn't respect the number requirements on hex oct bin for both integer and rational
    // FIXME: It also doesn't account for the trailing and leading dot
    // FIXME: It also doesn't respect exponent descriptions
        /*{
        val decFractional = '.' *> digit.foldRight1[BigDecimal](0)((d, x) => x/10 + d.asDigit)
        // TODO: This integer needs to have the description altered to account for the sign presence
        val decExponent = oneOf('e', 'E') *> integer.decimal32
        val zeroPoint = (decFractional, decExponent <|> pure(0)).zipped[Either[BigInt, BigDecimal]] {
            case (f, e) => Right(f / 10 * BigDecimal(10).pow(e))
        } <|> decExponent.as(Right(BigDecimal(0)))
        val zeroLead = '0' *> (noZeroHexadecimal <|> noZeroOctal <|> noZeroBinary <|> zeroPoint <|> decimal <|> pure(Left(BigInt(0))))
        atomic(zeroLead <|> decimal)
    }*/

    // TODO: Using choice here will generate a jump table, which will be nicer for `number` (this requires enhancements to the jumptable optimisation)
    // TODO: Leave these as defs so they get inlined into number for the jumptable optimisation
    //private val noZeroHexadecimal = oneOf(desc.hexadecimalLeads) *> ofRadix(16, 2, hexDigit, oneOf('p', 'P'))
    //private val noZeroOctal = oneOf(desc.octalLeads) *> ofRadix(8, 8, octDigit, oneOf('p', 'P'))
    //private val noZeroBinary = oneOf(desc.binaryLeads) *> ofRadix(2, 2, oneOf('0', '1'), oneOf('p', 'P'))

    override protected [numeric] def bounded[T](number: Parsley[Either[BigInt, BigDecimal]], bits: Bits, radix: Int)
                                               (implicit ev: CanHold[bits.self,T]): Parsley[Either[T, BigDecimal]] = {
        err.filterIntegerOutOfBounds(min = 0, bits.upperUnsigned, radix).injectLeft.collect(number) {
            case Left(x) if x <= bits.upperUnsigned => Left(ev.fromBigInt(x))
            case Right(x) => Right(x)
        }
    }

    // This isn't quite accurate: for non decimal floats the exponent is required, but for wholes it is not
    /*private def ofRadix(radix: Int, base: Int, digit: Parsley[Char], exp: Parsley[Char]) = {
        // could allow for foldLeft and foldRight here!
        // this reuses components of natural numbers, which will prevent duplication in a larger parser
        val whole = radix match {
            case 10 => integer.plainDecimal
            case 16 => integer.plainHexadecimal
            case 8 => integer.plainOctal
            case 2 => integer.plainBinary
        }
        val fractional = '.' *> digit.foldRight1[BigDecimal](0)((d, x) => x/radix + d.asDigit)
        val exponent = exp *> integer.decimal32
        //(whole, (fractional <~> exponent) <+> fractional
        if (radix == 10) {
            (whole, option(fractional), option(exponent)).zipped[Either[BigInt, BigDecimal]] {
                case (w, None, None)       => Left(w)
                case (w, Some(f), None)    => Right(BigDecimal(w) + f / radix)
                case (w, None, Some(e))    => Right(BigDecimal(w) * BigDecimal(base).pow(e))
                case (w, Some(f), Some(e)) => Right((BigDecimal(w) + f / radix) * BigDecimal(base).pow(e))
            }
        }
        else {
            (whole, option((fractional <~> exponent) <+> exponent)).zipped[Either[BigInt, BigDecimal]] {
                case (w, None)               => Left(w)
                case (w, Some(Left((f, e)))) => Right((BigDecimal(w) + f / radix) * BigDecimal(base).pow(e))
                case (w, Some(Right(e)))     => Right(BigDecimal(w) * BigDecimal(base).pow(e))
            }
        }
    }*/
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy