trivet 3.1.0

The trivet Parser Library
Documentation
# Parsing Numbers

**Trivet** provides convenience methods to parse three kinds of numbers.

- Unsigned integers as `u128`
- Signed integers as `i128`
- Floating point numbers as `f64`

To parse a number, you can just use one of the number parsing methods available in `trivet::Parser`.

| Method                                 | Use                                                                     |
| -------------------------------------- | ----------------------------------------------------------------------- |
| `parse_i128() -> ParseResult<i128>`    | Parse a signed integer.                                                 |
| `parse_i128_ws() -> ParseResult<i128>` | Parse a signed integer and then consume any trailing whitespace.        |
| `parse_u128() -> ParseResult<u128>`    | Parse an unsigned integer.                                              |
| `parse_u128_ws() -> ParseResult<u128>` | Parse an unsigned integer and then consume any trailing whitespace.     |
| `parse_f64() -> ParseResult<f64>`      | Parse a floating point number.                                          |
| `parse_f64_ws() -> ParseResult<f64>`   | Parse a floating point number and then consume any trailing whitespace. |

All of these can fail for various reasons, so they return a `ParseResult`.

Here is a very short example that parses floating point numbers from the standard input and then writes them to the standard output.

```rust,ignore
{{#include ../../examples/book_numbers_float.rs}}
```

## Number Representation

Numbers can be represented in any of the following radices.

- Decimal
- Hexadecimal
- Octal
- Binary

Radices other than decimal are indicated by a prefix.

| Prefix | Radix       |
| ------ | ----------- |
| `0b`   | Binary      |
| `0o`   | Octal       |
| none   | Decimal     |
| `0x`   | Hexadecimal |

By default, underscores can be present in numbers. This can be disabled if not desired. The following are some examples of signed and unsigned integers.

- `0x1011_1010` = 186
- `0o272` = 186
- `-0xba` = -186

Floating point numbers can be given in different radices, too. For instance, the following are a few ways to write a floating point value equivalent[^float] to 1/2.

| Radix       | Representation    |
| ----------- | ----------------- |
| Binary      | `0b0.1`, `0b1e-1` |
| Octal       | `0o0.4`, `0o4e-1` |
| Decimal     | `0.5`, `5e-1`     |
| Hexadecimal | `0x0.8`, `0x8p-1` |

Note in the last example above that `p` is used for exponents in hexadecimal to avoid ambiguity. You can use `p` for any base, but cannot use `e` for hexadecimal for obvious reasons.

The general form for floating point numbers is as follows.

```text
Float  ::= '-'? ( 'inf' | 'infinity' | 'nan' | Number )
Number ::= ( Digit+ |
             Digit+ '.' Digit* |
             Digit* '.' Digit+ ) Exp?
Exp    ::= ('e'|'p') ('-'|'+') Digit+
Digit  ::= [0-9]
```

## Configuring Number Parsing

Number parsing is performed by the struct `trivet::numbers::NumberParser`. A number parser is already installed in each instance of `trivet::Parser`, and you can obtain mutable access to it to configure it using `borrow_number_parser() -> &mut NumberParser`.

| Method                                        | Use                                                       |
| --------------------------------------------- | --------------------------------------------------------- |
| `borrow_number_parser() -> &mut NumberParser` | Obtain a mutable reference to the internal number parser. |

You can enable and disable support for different radices and can even change the prefix indicator used to detect radices. Disabling radices you don't want to support can increase performance a bit since **Trivet** does not need to check for the related prefixes.

## A Note About Parsing Numbers

We've seen some examples of parsing numbers already, but this can be trickier than you might think. A naive signed integer parsing method might look as follows.

```rust,ignore
// Bad Example
let negative = parser.peek_and_consume('-');
let digits = parser.take_while(|ch| ch.is_ascii_digit());
let number = match result.parse::<i64>() {
        Ok(number) => number,
        Err(err) => return Err(trivet::errors::error(parser.loc(), err)),
};
if negative { -number } else { number }
```

This seems really good, but it breaks for the maximum negative value. Because the absolute value of the most negative `i64` is higher than the absolute value of the most positive `i64` value, we _can't_ parse the most negative value with this method. The implementation in **Trivet** handles this case correctly.

[^float]: See [What Every Computer Scientist Should Know About Floating-Point Arithmetic]https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html