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 } }; } }