| 80 | } |
| 81 | |
| 82 | NumberResult scanDecimalNumber(const std::string& source, size_t len, size_t& i) |
| 83 | { |
| 84 | NumberResult result; |
| 85 | |
| 86 | // Integer part |
| 87 | while(i < len && isDigit(source[i])) |
| 88 | { |
| 89 | ++i; |
| 90 | } |
| 91 | // Fractional part |
| 92 | if(i < len && source[i] == '.') |
| 93 | { |
| 94 | // Distinguish from ".." (concat operator) |
| 95 | if(i + 1 < len && source[i + 1] == '.') |
| 96 | { |
| 97 | // Stop here: "65.." is Integer("65") + DotDot |
| 98 | } |
| 99 | else if(i + 1 < len && isDigit(source[i + 1])) |
| 100 | { |
| 101 | result.is_real = true; |
| 102 | ++i; // consume '.' |
| 103 | while(i < len && isDigit(source[i])) |
| 104 | { |
| 105 | ++i; |
| 106 | } |
| 107 | } |
| 108 | else |
| 109 | { |
| 110 | // "65." or "65.x" -- incomplete real |
| 111 | result.has_error = true; |
| 112 | ++i; // consume the dot |
| 113 | consumeTrailingGarbage(source, len, i); |
| 114 | } |
| 115 | } |
| 116 | // Exponent (only for decimal numbers) |
| 117 | if(!result.has_error && i < len && (source[i] == 'e' || source[i] == 'E')) |
| 118 | { |
| 119 | result.is_real = true; |
| 120 | ++i; // consume 'e'/'E' |
| 121 | if(i < len && (source[i] == '+' || source[i] == '-')) |
| 122 | { |
| 123 | ++i; // consume sign |
| 124 | } |
| 125 | if(i >= len || !isDigit(source[i])) |
| 126 | { |
| 127 | result.has_error = true; |
| 128 | } |
| 129 | else |
| 130 | { |
| 131 | while(i < len && isDigit(source[i])) |
| 132 | { |
| 133 | ++i; |
| 134 | } |
| 135 | } |
| 136 | } |
| 137 | // Trailing alpha (e.g. "3foo", "65.43foo") |
| 138 | if(!result.has_error && i < len && isIdentStart(source[i])) |
| 139 | { |
no test coverage detected