コード例 #1
0
ファイル: ErlangNumberToken.cs プロジェクト: ixmilia/erlang
        public static ErlangNumberToken Lex(TextBuffer buffer)
        {
            var sb = new StringBuilder();

            sb.Append(buffer.Peek());
            buffer.Advance();
            bool seenHash    = false;
            bool seenE       = false;
            bool seenDecimal = false;
            var  last        = default(char);

            while (buffer.TextRemains())
            {
                var c = buffer.Peek();
                if (c == '#')
                {
                    if (!seenHash && !seenDecimal)
                    {
                        seenHash = true;
                        buffer.Advance();
                        sb.Append(c);
                    }
                    else
                    {
                        // premature end of number
                        break;
                    }
                }
                else if (c == '.')
                {
                    if (!seenDecimal && !seenHash)
                    {
                        seenDecimal = true;
                        buffer.Advance();
                        sb.Append(c);
                    }
                    else
                    {
                        // premature end of number
                        break;
                    }
                }
                else if ((c == 'e' || c == 'E') && !seenHash)
                {
                    if (!seenE)
                    {
                        seenE = true;
                        buffer.Advance();
                        sb.Append(c);
                    }
                    else
                    {
                        // premature end of number
                        break;
                    }
                }
                else if (c == '+' || c == '-')
                {
                    if (seenE && (last == 'e' || last == 'E'))
                    {
                        buffer.Advance();
                        sb.Append(c);
                    }
                    else
                    {
                        // possibly already saw sign
                        break;
                    }
                }
                else if (IsNumberContinue(c))
                {
                    buffer.Advance();
                    sb.Append(c);
                }
                else
                {
                    break;
                }

                last = c;
            }

            Debug.Assert(!(seenDecimal && seenHash)); // should not have seen both
            Debug.Assert(!(seenE && seenHash));       // should not have seen both
            if (last == '.')
            {
                // numbers can't end in a decimal point
                buffer.Retreat();
                sb.Remove(sb.Length - 1, 1);
                seenDecimal = false;
            }

            var        text        = sb.ToString();
            double     doubleValue = default(double);
            BigInteger bigValue    = default(BigInteger);
            string     error       = null;

            if (!seenHash)
            {
                // simple parsing
                if (seenDecimal || seenE)
                {
                    doubleValue = Convert.ToDouble(text);
                }
                else
                {
                    bigValue = BigInteger.Parse(text);
                }
            }
            else
            {
                // complex hash parsing
                var parts = text.Split("#".ToCharArray(), 2);
                int @base = Convert.ToInt32(parts[0]);
                if (@base >= 2 && @base <= 36)
                {
                    int val = 0;
                    for (int i = 0; i < parts[1].Length; i++)
                    {
                        int digitValue = 0;
                        var l          = parts[1][i];
                        if (l >= '0' && l <= '9')
                        {
                            digitValue = l - '0';
                        }
                        else
                        {
                            digitValue = char.ToUpperInvariant(l) - 'A' + 10;
                        }

                        if (digitValue < 0 || digitValue >= @base)
                        {
                            error = string.Format("Digit '{0}' not valid for base '{1}'", l, @base);
                            return(new ErlangNumberToken(text)
                            {
                                Error = error
                            });
                        }

                        val = (val * @base) + digitValue;
                    }

                    bigValue = val;
                }
                else
                {
                    error = "Base must be between 2 and 36 inclusive.";
                }
            }

            if (seenDecimal)
            {
                return new ErlangNumberToken(text, doubleValue)
                       {
                           Error = error
                       }
            }
            ;
            else
            {
                return new ErlangNumberToken(text, bigValue)
                       {
                           Error = error
                       }
            };
        }
    }