Exemple #1
0
 public void Parse_HexTest(ulong expected, string input)
 {
     Assert.True(ParsingCommon.Parse_Hex(input.AsMemory(), out ulong actual));
     Assert.Equal(expected, actual);
 }
Exemple #2
0
 public void Digits_To_Base10_UnsignedTest(ulong expected, string input)
 {
     Assert.Equal(expected, ParsingCommon.Digits_To_Base10_Unsigned(input));
 }
Exemple #3
0
        public static string Consume_HTTP_Quoted_String(DataConsumer <char> Stream, bool bExtract_Value_Flag = false)
        {/* Docs: https://fetch.spec.whatwg.org/#collect-an-http-quoted-string */
            var positionStart = Stream.LongPosition;
            var sb            = bExtract_Value_Flag ? new StringBuilder() : null;

            /* 3) Assert: the code point at position within input is U+0022 ("). */
            if (Stream.Next != CHAR_QUOTATION_MARK)
            {
                throw new DOM.Exceptions.DomSyntaxError($"Expected quotation mark @\"{ParsingCommon.Get_Location(Stream)}");
            }

            Stream.Consume();
            while (true)
            {
                /* 1) Append the result of collecting a sequence of code points that are not U+0022 (") or U+005C (\) from input, given position, to value. */
                Stream.Consume_While(c => c != CHAR_EQUALS && c != CHAR_REVERSE_SOLIDUS, out ReadOnlyMemory <char> outConsumed);
                if (sb != null)
                {
                    sb.Append(outConsumed.ToString());
                }

                if (Stream.atEnd)
                {
                    break;
                }

                var quoteOrBackslash = Stream.Next;
                Stream.Consume();
                if (quoteOrBackslash == CHAR_REVERSE_SOLIDUS)
                {
                    if (Stream.atEnd)
                    {
                        if (sb != null)
                        {
                            sb.Append(CHAR_REVERSE_SOLIDUS);
                        }
                        break;
                    }

                    if (sb != null)
                    {
                        sb.Append(Stream.Next);
                    }
                    Stream.Consume();
                }
                else
                {
                    /* 1) Assert: quoteOrBackslash is U+0022 ("). */
                    if (quoteOrBackslash != CHAR_QUOTATION_MARK)
                    {
                        throw new DOM.Exceptions.DomSyntaxError($"Expected quotation mark @\"{ParsingCommon.Get_Location(Stream)}");
                    }

                    break;
                }
            }

            if (bExtract_Value_Flag)
            {
                return(sb.ToString());
            }

            /* 7) Return the code points from positionStart to position, inclusive, within input. */
            return(Stream.AsMemory().Slice((int)positionStart, (int)(Stream.LongPosition - positionStart)).ToString());
        }
Exemple #4
0
 public void Digits_To_Base10Test(long expected, string input)
 {
     Assert.Equal(expected, ParsingCommon.Digits_To_Base10(input));
 }
Exemple #5
0
        public static bool Try_Parse_FloatingPoint(DataConsumer <char> Stream, out double outValue)
        {/* Docs: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-floating-point-number-values */
            if (Stream is null)
            {
                throw new ArgumentNullException(nameof(Stream));
            }
            Contract.EndContractBlock();

            double value    = 1;
            double divisor  = 1;
            double exponent = 1;

            /* Skip ASCII whitespace */
            Stream.Consume_While(Is_Ascii_Whitespace);

            if (Stream.atEnd)
            {
                outValue = double.NaN;
                return(false);
            }

            switch (Stream.Next)
            {
            case CHAR_HYPHEN_MINUS:
            {
                value = divisor = -1;
                Stream.Consume();
            }
            break;

            case CHAR_PLUS_SIGN:
            {
                Stream.Consume();
            }
            break;
            }

            if (Stream.atEnd)
            {
                outValue = double.NaN;
                return(false);
            }

            /* 9) If the character indicated by position is a U+002E FULL STOP (.),
             * and that is not the last character in input,
             * and the character after the character indicated by position is an ASCII digit,
             * then set value to zero and jump to the step labeled fraction. */
            if (Stream.Remaining > 1 && Stream.Next == CHAR_FULL_STOP && Is_Ascii_Digit(Stream.NextNext))
            {
                value = 0;
            }
            else if (!Is_Ascii_Digit(Stream.Next))
            {
                outValue = double.NaN;
                return(false);
            }
            else
            {
                /* 11) Collect a sequence of code points that are ASCII digits from input given position, and interpret the resulting sequence as a base-ten integer. Multiply value by that integer. */
                Stream.Consume_While(Is_Ascii_Digit, out ReadOnlySpan <char> outDigits);
                value *= ParsingCommon.Digits_To_Base10(outDigits);
            }

            /* 12) If position is past the end of input, jump to the step labeled conversion. */
            if (!Stream.atEnd)
            {
                /* 13) Fraction: If the character indicated by position is a U+002E FULL STOP (.), run these substeps: */
                if (Stream.Next == CHAR_FULL_STOP)
                {
                    Stream.Consume();
                    /* 2) If position is past the end of input, or if the character indicated by position is not an ASCII digit, U+0065 LATIN SMALL LETTER E (e), or U+0045 LATIN CAPITAL LETTER E (E), then jump to the step labeled conversion. */
                    if (!Stream.atEnd && (Is_Ascii_Digit(Stream.Next) || Stream.Next == CHAR_E_LOWER || Stream.Next == CHAR_E_UPPER))
                    {
                        /* 3) If the character indicated by position is a U+0065 LATIN SMALL LETTER E character (e) or a U+0045 LATIN CAPITAL LETTER E character (E), skip the remainder of these substeps. */
                        if (Is_Ascii_Digit(Stream.Next))
                        {
                            while (Is_Ascii_Digit(Stream.Next))
                            {
                                /* 4) Fraction loop: Multiply divisor by ten. */
                                divisor *= 10;
                                /* 5) Add the value of the character indicated by position, interpreted as a base-ten digit (0..9) and divided by divisor, to value. */
                                double n = Ascii_Digit_To_Value(Stream.Next) / divisor;
                                value += n;
                                /* 6) Advance position to the next character. */
                                Stream.Consume();
                                /* 7) If position is past the end of input, then jump to the step labeled conversion. */

                                if (Stream.atEnd)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                /* 14) If the character indicated by position is U+0065 (e) or a U+0045 (E), then: */
                if (Stream.Next == CHAR_E_LOWER || Stream.Next == CHAR_E_UPPER)
                {
                    Stream.Consume();
                    /* 2) If position is past the end of input, then jump to the step labeled conversion. */
                    /* 3) If the character indicated by position is a U+002D HYPHEN-MINUS character (-): */
                    if (Stream.Next == CHAR_HYPHEN_MINUS)
                    {
                        exponent = -1;
                        Stream.Consume();
                    }
                    else if (Stream.Next == CHAR_PLUS_SIGN)
                    {
                        Stream.Consume();
                    }

                    /* 4) If the character indicated by position is not an ASCII digit, then jump to the step labeled conversion. */
                    if (Is_Ascii_Digit(Stream.Next))
                    {
                        /* 5) Collect a sequence of code points that are ASCII digits from input given position, and interpret the resulting sequence as a base-ten integer. Multiply exponent by that integer. */
                        Stream.Consume_While(Is_Ascii_Digit, out ReadOnlySpan <char> outDigits);
                        exponent *= ParsingCommon.Digits_To_Base10(outDigits);
                        /* 6) Multiply value by ten raised to the exponentth power. */
                        value *= Math.Pow(10, exponent);
                    }
                }
            }

            /* 15) Conversion: Let S be the set of finite IEEE 754 double-precision floating-point values except −0, but with two special values added: 21024 and −21024. */

            /* 16) Let rounded-value be the number in S that is closest to value,
             * selecting the number with an even significand if there are two equally close values.
             * (The two special values 21024 and −21024 are considered to have even significands for this purpose.) */
            var roundedValue = Math.Round(value, MidpointRounding.ToEven);

            /* 17) If rounded-value is 21024 or −21024, return an error. */
            if ((roundedValue == double.MinValue) || (roundedValue == double.MaxValue))
            {
                outValue = double.NaN;
                return(false);
            }

            outValue = roundedValue;
            return(true);
        }