Parser

Struct Parser 

Source
pub struct Parser {
    pub parse_comments: bool,
    /* private fields */
}
Expand description

Provide methods to implement a recursive descent parser.

This struct wraps a stream (an instance of Read) and provides two primitives.

  • You can “peek” at upcoming characters in the stream.
  • You can “consume” characters from the stream.

These primitives are used to construct a series of more complex methods, but essentially all you can do is look at what is coming up in the stream, and then consume and discard characters from the stream.

§Whitespace

Aside from methods specifically to consume whitespace, there are special versions of some “consume” methods that consume whitespace following a match. These methods end with _ws and consume any trailing whitespace following a successful match.

Whitespace includes only those characters that satisfy the char::is_whitespace() predicate. This includes Unicode whitespace characters. See Self::consume_ws_only for details.

§Comments

This is able to parse comments, using an embedded CommentParser instance. The default comment parser handles C and C++-style comments.

If you want to configure the comment parser, you can borrow a mutable reference to it using Self::borrow_comment_parser().

use trivet::parsers::comments::CommentParser;
use trivet::Parser;
use trivet::parse_from_string;

let mut parser = parse_from_string("# This is a comment.");
let mut compar = parser.borrow_comment_parser();
compar.enable_c = false;
compar.enable_cpp = false;
compar.enable_python = true;
parser.consume_ws();
assert!(parser.is_at_eof());

If your language does not support comments, you can disable them completely and possibly gain a bit of performance by setting the Self::parse_comments flag to false.

§Parsing Strings

String parsing is provided by a StringParser instance. This instance can be obtained and configured using Self::borrow_string_parser.

Strings are parsed on-demand by the Self::parse_string method. This takes an optional terminator character.

use trivet::Parser;
use trivet::errors::ParseResult;
use trivet::parse_from_string;

// We will use «..» quotes here.
let mut parser = parse_from_string(r#"«This is\b\bwas\u{a}\x09some text»"#);
// Consume the opening quote mark.
parser.consume();
// Now consume until the closing mark.
let text = parser.parse_string_until_delimiter('\u{BB}')?;
assert_eq!(text, "This is\x08\x08was\n\tsome text");

§Parsing Numbers

Number parsing is provided by a NumberParser instance. This instance can be obtained and configured using Self::borrow_number_parser.

Numbers are parsed on-demand by the Self::parse_i128, Self::parse_u128, and Self::parse_f64 methods and their _ws counterparts.

§Parsing Keywords

Keyword parsing is provided by a KeywordParser instance. This instance can be obtained and configured using Self::borrow_keyword_parser.

Keywords are parsed on-demand by the Self::parse_keyword method and its _ws counterpart.

§Method Names

There are many methods. Most method names have the following form:

[peek/consume][type][whitespace]

[peek/consume]

  • The peek methods look ahead at the character source. Their return is either the characters themselves or a Boolean indicating a match or failure to match.
  • The consume methods discard characters from the character source. Their return is either nothing (for unconditional consumes) or a Boolean if something was conditionally consumed.
  • The peek_and_consume method both match a string and consume that string when it is matched, and only when it is matched.

[type]

  • Methods that work with a single character have no additional specification.
  • Methods that work with a specific number of characters are suffixed with _n. These do not test characters, but return or consume them unconditionally.
  • Methods that work with a vector of chars have _chars in the name.
  • Methods that work with a string have _str in the name. These methods are absent from ParserCore.

[whitespace]

  • Methods that consume trailing whitespace (possibly including comments) are suffixed with _ws. These methods are absent from ParserCore.

Some method name combinations do not make sense, and are not present. For instance, peek_ws. The following is a quick reference to the implemented methods. Methods indicated with an * are in Parser, but not in ParserCore.

MethodInputReturnOnly in Parser
Self::peekchar
Self::peek_nusizeString
Self::peek_n_vecusizeVec<char>
Self::peek_offsetusizechar
Self::peek_charsVec<char>bool
Self::peek_chars_greedy (see below)Vec<char>bool*
Self::peek_str&strbool*
Self::peek_str_greedy (see below)&strbool*
Self::consume
Self::consume_nusize
Self::consume_wsbool*
Self::peek_and_consumecharbool
Self::peek_and_consume_wscharbool*
Self::peek_and_consume_charsVec<char>bool
Self::peek_and_consume_chars_wsVec<char>bool*
Self::peek_and_consume_str&strbool*
Self::peek_and_consume_str_ws&strbool*
Self::take_whileclosureString
Self::take_while_unlessclosureString
Self::take_untilStringString
Self::take_until_greedy (see below)StringString*
Self::consume_whileclosurebool
Self::consume_untilStringbool

The additional method Self::consume_ws_only consumes whitespace and is present in ParserCore, but does not consume comments even if there is a comment parser installed.

The special _greedy methods exist to handle a special case. Suppose the input stream contains """"""" and you want to match on three consecutive quotation marks. The Self::peek_str method will match on the first three quotation marks. The Self::peek_str_greedy method will match on the last three quotation marks. These methods are not in ParserCore.

§Example

To use this, make an instance with Self::new(), giving a stream and a name for the stream. The name given will be used when constructing Loc instances. If the name is the empty string, then Console locations are created; otherwise File locations are created.

The following shows how to create a parser around the standard input.

use std::io;
use trivet::Parser;
use trivet::parse_from_stdin;

// Make a new parser around the standard input.
let mut parser = parse_from_stdin();
// Invoke methods to parse...

Use Self::peek() to peek at the next character in the stream, and use Self::consume() to discard that character. Note that Self::peek() returns a result, and may be Ok(None) if at the end of stream. The following uses these two methods to ignore whitespace (though there actually is a method just for that).

use trivet::Parser;
use trivet::parse_from_string;

// Make a new parser around the standard input.
let mut parser = parse_from_string("\t\tx");

// While the next character is whitespace, consume it.
while parser.peek().is_whitespace() {
    parser.consume();
}

// The stream should now be pointing to the first
// non-whitespace character.
assert_eq!(parser.peek(), 'x');

This would be a very tedious way to parse anything, so there are other methods to help. In particular, Self::consume_ws() will do the job just outlined above.

More interestingly you can look to see if the next thing in the stream is a given string with Self::peek_str() and Self::peek_str_greedy(). Usually once you match an upcoming string, you probably want to consume it. To both check for the string and consume it if you find it, use Self::peek_and_consume() (for single characters) or Self::peek_and_consume_str() (for strings).

You may also want to consume a sequence of characters, such as all the digits or letters in a stream. The method Self::take_while() will do that. It takes a predicate on characters (usually a lambda) and consumes characters while the predicate is true. All the characters are then returned. The following uses this to obtain the next decimal integer from the stream.

use std::io;
use trivet::Parser;
use trivet::parse_from_string;

// Make a new parser around the standard input.
let mut parser = parse_from_string("-14x");

// Look for a minus sign.
let minus = parser.peek_and_consume('-');

// Read the next integer from the stream.
let digits = parser.take_while(|ch| ch.is_ascii_digit());
let number: i64 = (if minus { -1 } else { 1 })
    * digits.parse().unwrap_or(0);
assert_eq!(number, -14i64);

// The stream now points to the first non-digit character.
assert_eq!(parser.peek(), 'x');

Fields§

§parse_comments: bool

If true (default) then the Self::consume_ws method and other _ws methods look for and consume comments. If false, then they consume whitespace only.

Implementations§

Source§

impl Parser

Source

pub fn new(name: &str, decoder: Decode) -> Self

Create a new parser using the given decoder as the source of characters. A name is given that will be used when creating Loc instances.

Source

pub fn borrow_core(&mut self) -> &mut ParserCore

Borrow the parser core. This returns a mutable borrow of the internal parser core. This is probably only needed if you want to run or test an external comment parser.

Examples found in repository?
examples/numbers.rs (line 26)
7pub fn main() {
8    println!("Enter a number to see how Trivet parses it.  Enter a blank line to stop.");
9    let numpar = NumberParser::new();
10    print!("> ");
11    let _ = stdout().flush();
12    for line in stdin().lock().lines() {
13        if line.is_err() {
14            break;
15        }
16        let line = line.unwrap();
17
18        // Consume any whitespace.
19        let mut parser = parse_from_string(&line);
20        parser.consume_ws();
21        if parser.is_at_eof() {
22            break;
23        }
24
25        // Try to read a number as pieces.
26        let parts = numpar.get_parts(parser.borrow_core());
27        println!("{:?}", parts);
28        if parts.is_apparent_float() {
29            let value: f64 = parts.into();
30            println!("f64: {}", value);
31        } else {
32            let value: i128 = parts.into();
33            println!("i128: {}", value);
34        }
35
36        // Go around again.
37        print!("> ");
38        let _ = stdout().flush();
39    }
40}
More examples
Hide additional examples
examples/book_json_parser.rs (line 138)
122pub fn main() {
123    let mut parser = trivet::parse_from_stdin();
124    parser.parse_comments = false;
125    let numpar = parser.borrow_number_parser();
126    numpar.settings.permit_binary = false;
127    numpar.settings.permit_hexadecimal = false;
128    numpar.settings.permit_octal = false;
129    numpar.settings.permit_underscores = false;
130    numpar.settings.decimal_only_floats = true;
131    numpar.settings.permit_plus = false;
132    numpar.settings.permit_leading_zero = false;
133    numpar.settings.permit_empty_whole = false;
134    numpar.settings.permit_empty_fraction = false;
135    let strpar = parser.borrow_string_parser();
136    strpar.set(trivet::strings::StringStandard::JSON);
137    let _ = parser
138        .borrow_core()
139        .replace_whitespace_test(Box::new(|ch| [' ', '\n', '\r', '\t'].contains(&ch)));
140    parser.consume_ws();
141    let result = parse_value_ws(&mut parser);
142    match result {
143        Err(error) => {
144            println!("ERROR: {}", error);
145            std::process::exit(1);
146        }
147        Ok(json) => {
148            // If there is any trailing stuff that is not whitespace, then this is not a valid
149            // JSON file.
150            if parser.is_at_eof() {
151                // Print the JSON value.
152                println!("{:?}", json);
153                std::process::exit(0)
154            } else {
155                println!("Found unexpected trailing characters after JSON value.");
156                std::process::exit(1);
157            }
158        }
159    }
160}
Source

pub fn borrow_comment_parser(&mut self) -> &mut CommentParser

Borrow the comment parser. This returns a mutable borrow of the internal comment parser that will allow you to configure the parser.

Examples found in repository?
examples/book_primitives_lua.rs (line 11)
1fn main() {
2    // Text to parse.  Note that the comment ends on line 5 at column 12, with
3    // the first non-comment position at column 13.
4    let mut parser = trivet::parse_from_string(
5        r#"
6        --[[
7            I am a long form
8            Lua comment.
9        --]]"#,
10    );
11    parser.borrow_comment_parser().enable_c = false;
12    parser.borrow_comment_parser().enable_cpp = false;
13    parser.borrow_comment_parser().custom = Box::new(|parser: &mut trivet::ParserCore| -> bool {
14        if parser.peek_and_consume_chars(&['-', '-', '[', '[']) {
15            parser.take_until("--]]");
16            true
17        } else if parser.peek_and_consume_chars(&['-', '-']) {
18            parser.take_while(|ch| ch != '\n');
19            true
20        } else {
21            false
22        }
23    });
24    parser.borrow_comment_parser().enable_custom = true;
25    parser.consume_ws();
26    assert_eq!(parser.loc().to_string(), "<string>:5:13");
27    assert!(parser.is_at_eof());
28}
Source

pub fn replace_comment_parser(&mut self, compar: CommentParser) -> CommentParser

Replace the internal comment parser with the given instance of a comment parser. The prior comment parser is returned.

Source

pub fn borrow_number_parser(&mut self) -> &mut NumberParser

Borrow the number parser. This returns a mutable borrow of the internal number parser that will allow you to configure the parser.

Examples found in repository?
examples/book_json_parser.rs (line 125)
122pub fn main() {
123    let mut parser = trivet::parse_from_stdin();
124    parser.parse_comments = false;
125    let numpar = parser.borrow_number_parser();
126    numpar.settings.permit_binary = false;
127    numpar.settings.permit_hexadecimal = false;
128    numpar.settings.permit_octal = false;
129    numpar.settings.permit_underscores = false;
130    numpar.settings.decimal_only_floats = true;
131    numpar.settings.permit_plus = false;
132    numpar.settings.permit_leading_zero = false;
133    numpar.settings.permit_empty_whole = false;
134    numpar.settings.permit_empty_fraction = false;
135    let strpar = parser.borrow_string_parser();
136    strpar.set(trivet::strings::StringStandard::JSON);
137    let _ = parser
138        .borrow_core()
139        .replace_whitespace_test(Box::new(|ch| [' ', '\n', '\r', '\t'].contains(&ch)));
140    parser.consume_ws();
141    let result = parse_value_ws(&mut parser);
142    match result {
143        Err(error) => {
144            println!("ERROR: {}", error);
145            std::process::exit(1);
146        }
147        Ok(json) => {
148            // If there is any trailing stuff that is not whitespace, then this is not a valid
149            // JSON file.
150            if parser.is_at_eof() {
151                // Print the JSON value.
152                println!("{:?}", json);
153                std::process::exit(0)
154            } else {
155                println!("Found unexpected trailing characters after JSON value.");
156                std::process::exit(1);
157            }
158        }
159    }
160}
Source

pub fn replace_number_parser(&mut self, numpar: NumberParser) -> NumberParser

Replace the internal string parser with the given instance of a string parser. The prior string parser is returned.

Source

pub fn borrow_string_parser(&mut self) -> &mut StringParser

Borrow the string parser. This returns a mutable borrow of the internal string parser that will allow you to configure the parser.

Examples found in repository?
examples/book_json_parser.rs (line 135)
122pub fn main() {
123    let mut parser = trivet::parse_from_stdin();
124    parser.parse_comments = false;
125    let numpar = parser.borrow_number_parser();
126    numpar.settings.permit_binary = false;
127    numpar.settings.permit_hexadecimal = false;
128    numpar.settings.permit_octal = false;
129    numpar.settings.permit_underscores = false;
130    numpar.settings.decimal_only_floats = true;
131    numpar.settings.permit_plus = false;
132    numpar.settings.permit_leading_zero = false;
133    numpar.settings.permit_empty_whole = false;
134    numpar.settings.permit_empty_fraction = false;
135    let strpar = parser.borrow_string_parser();
136    strpar.set(trivet::strings::StringStandard::JSON);
137    let _ = parser
138        .borrow_core()
139        .replace_whitespace_test(Box::new(|ch| [' ', '\n', '\r', '\t'].contains(&ch)));
140    parser.consume_ws();
141    let result = parse_value_ws(&mut parser);
142    match result {
143        Err(error) => {
144            println!("ERROR: {}", error);
145            std::process::exit(1);
146        }
147        Ok(json) => {
148            // If there is any trailing stuff that is not whitespace, then this is not a valid
149            // JSON file.
150            if parser.is_at_eof() {
151                // Print the JSON value.
152                println!("{:?}", json);
153                std::process::exit(0)
154            } else {
155                println!("Found unexpected trailing characters after JSON value.");
156                std::process::exit(1);
157            }
158        }
159    }
160}
Source

pub fn replace_string_parser(&mut self, strpar: StringParser) -> StringParser

Replace the internal string parser with the given instance of a string parser. The prior string parser is returned.

Source

pub fn borrow_keyword_parser(&mut self) -> &mut KeywordParser

Borrow the keyword parser. This returns a mutable borrow of the internal keyword parser that will allow you to configure the parser.

Examples found in repository?
examples/book_keywords_permit.rs (line 18)
16fn main() {
17    let mut parser = trivet::parse_from_stdin();
18    parser.borrow_keyword_parser().use_permit = true;
19    parser.borrow_keyword_parser().permit = Box::new(keyword);
20    while !parser.is_at_eof() {
21        match parser.parse_keyword_ws() {
22            Err(err) => {
23                println!("ERROR: {}", err);
24                // Consume until whitespace, then resume trying.
25                parser.take_while(|ch| !ch.is_whitespace());
26                parser.consume_ws();
27            }
28            Ok(value) => {
29                println!("  {}", value);
30            }
31        }
32    }
33}
More examples
Hide additional examples
examples/book_keywords_transform.rs (line 3)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    parser.borrow_keyword_parser().use_transform = true;
4    parser.borrow_keyword_parser().transform =
5        Box::new(|ch| if [':', '.'].contains(&ch) { '_' } else { ch });
6    while !parser.is_at_eof() {
7        match parser.parse_keyword_ws() {
8            Err(err) => {
9                println!("ERROR: {}", err);
10                // Consume until whitespace, then resume trying.
11                parser.take_while(|ch| !ch.is_whitespace());
12                parser.consume_ws();
13            }
14            Ok(value) => {
15                println!("  {}", value);
16            }
17        }
18    }
19}
Source

pub fn replace_keyword_parser(&mut self, strpar: KeywordParser) -> KeywordParser

Replace the internal keyword parser with the given instance of a keyword parser. The prior keyword parser is returned.

Source

pub fn parse_string_match_delimiter(&mut self) -> ParseResult<String>

Parse the next string. The parse is assumed to be pointing to the opening delimiter, and the string is terminated by the next occurrence of the delimiter.

Source

pub fn parse_string_until_delimiter( &mut self, delimiter: char, ) -> ParseResult<String>

Parse the next string. The opening delimiter, if any, should have already been consumed. Provide the closing delimiter to look for.

Source

pub fn parse_string_match_delimiter_ws(&mut self) -> ParseResult<String>

Parse the next string. The parse is assumed to be pointing to the opening delimiter, and the string is terminated by the next occurrence of the delimiter. Consume any whitespace after the closing delimiter.

Examples found in repository?
examples/book_string_simple.rs (line 9)
1fn main() -> trivet::errors::ParseResult<()> {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        // Save the location for later use in error messages.
5        let loc = parser.loc();
6        // Parse strings only for the supported delimiters.
7        let string = match parser.peek() {
8            // The initial and final delimiters match.
9            '"' | '\'' => parser.parse_string_match_delimiter_ws()?,
10            // Here the initial and final delimiters do not match.
11            '«' => {
12                parser.consume();
13                parser.parse_string_until_delimiter_ws('»')?
14            }
15            // This is not a legal opening delimiter.
16            ch => {
17                return Err(trivet::errors::syntax_error(
18                    loc,
19                    &format!("Invalid delimiter: '{}'", ch),
20                ));
21            }
22        };
23        println!("  --> {:?}", string);
24    }
25    Ok(())
26}
More examples
Hide additional examples
examples/book_json_parser.rs (line 25)
16pub fn parse_value_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
17    match parser.peek() {
18        // Check for an object.
19        '{' => parse_object_ws(parser),
20
21        // Check for an array.
22        '[' => parse_array_ws(parser),
23
24        // Check for a string.
25        '"' => Ok(JSON::String(parser.parse_string_match_delimiter_ws()?)),
26
27        // Check for a number.
28        ch if ch == '-' || ch.is_ascii_digit() => Ok(JSON::Number(parser.parse_f64_decimal_ws()?)),
29
30        // Check for Boolean true.
31        't' if parser.peek_and_consume_str_ws("true") => Ok(JSON::Boolean(true)),
32
33        // Check for Boolean false.
34        'f' if parser.peek_and_consume_str_ws("false") => Ok(JSON::Boolean(false)),
35
36        // Check for null.
37        'n' if parser.peek_and_consume_str_ws("null") => Ok(JSON::Null),
38
39        // Error.
40        ch => Err(trivet::errors::unexpected_text_error(
41            parser.loc(),
42            "the start of a JSON value",
43            &ch.to_string(),
44        )),
45    }
46}
47
48/// Parse a JSON object.  On entry the parser is assumed to be pointing to the first
49/// character of the object (a curly brace `{`).  Trailing whitespace is consumed.
50fn parse_object_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
51    parser.consume(); // Consume opening brace.
52    parser.consume_ws();
53    let mut first = true;
54    let mut map = HashMap::new();
55    while !parser.peek_and_consume_ws('}') {
56        // If not the first element, then we expect to have a comma here.  JSON requires
57        // a comma between members of an object.
58        if first {
59            first = false;
60        } else if !parser.peek_and_consume_ws(',') {
61            return Err(trivet::errors::syntax_error(
62                parser.loc(),
63                "There must be a comma (,) between members of an object.",
64            ));
65        }
66
67        // Look for the quotation mark for a string.
68        if parser.peek() != '"' {
69            return Err(trivet::errors::syntax_error(
70                parser.loc(),
71                "Names in a JSON object must be quoted strings.",
72            ));
73        }
74        let name = parser.parse_string_match_delimiter_ws()?;
75
76        // Look for the colon.
77        if !parser.peek_and_consume_ws(':') {
78            return Err(trivet::errors::syntax_error(
79                parser.loc(),
80                "Names in a JSON object must be followed by a colon (:).",
81            ));
82        }
83
84        // Get the value.
85        let value = parse_value_ws(parser)?;
86
87        // Add the name, value pair to the map.
88        map.insert(name, value);
89    }
90    Ok(JSON::Object(map))
91}
examples/book_cookbook_things.rs (line 18)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    loop {
9        parser.consume_ws();
10        if parser.is_at_eof() {
11            break;
12        }
13        if parser.peek_and_consume_str_ws("string") {
14            parser.expect(':')?;
15            parser.consume_ws();
16            let ch = parser.peek();
17            if ch == '"' || ch == '\'' {
18                let string = parser.parse_string_match_delimiter_ws()?;
19                println!("Got string: {}", StringEncoder::new().encode(&string));
20            }
21        } else if parser.peek_and_consume_str_ws("integer") {
22            parser.expect(':')?;
23            parser.consume_ws();
24            let number = parser.parse_u128_ws()?;
25            println!("Got integer: {}", number);
26        } else if parser.peek_and_consume_str_ws("float") {
27            parser.expect(':')?;
28            parser.consume_ws();
29            let number = parser.parse_f64_ws()?;
30            println!("Got float: {}", number);
31        } else if parser.peek_and_consume_str_ws("json") {
32            parser.expect(':')?;
33            parser.consume_ws();
34            let json = JSONParser::new().parse_value_unstandard_ws(&mut parser)?;
35            println!("Got JSON:\n{}", json);
36        } else {
37            return Err(syntax_error(
38                parser.loc(),
39                "Unexpected element found in stream",
40            ));
41        }
42    }
43    Ok(())
44}
Source

pub fn parse_string(&self, string: &str) -> ParseResult<String>

Use the embedded string parse to parse the provided string. This reads from the provided string; nothing is consumed during this process. The primary use case for this is matching a more complex string environment and then using the embedded string parser to decode the result of the match.

Source

pub fn parse_string_until_delimiter_ws( &mut self, terminator: char, ) -> ParseResult<String>

Parse the next string. The opening delimiter, if any, should have already been consumed. Provide the closing delimiter to look for. Consume any trailing whitespace after the closing delimiter.

Examples found in repository?
examples/book_string_simple.rs (line 13)
1fn main() -> trivet::errors::ParseResult<()> {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        // Save the location for later use in error messages.
5        let loc = parser.loc();
6        // Parse strings only for the supported delimiters.
7        let string = match parser.peek() {
8            // The initial and final delimiters match.
9            '"' | '\'' => parser.parse_string_match_delimiter_ws()?,
10            // Here the initial and final delimiters do not match.
11            '«' => {
12                parser.consume();
13                parser.parse_string_until_delimiter_ws('»')?
14            }
15            // This is not a legal opening delimiter.
16            ch => {
17                return Err(trivet::errors::syntax_error(
18                    loc,
19                    &format!("Invalid delimiter: '{}'", ch),
20                ));
21            }
22        };
23        println!("  --> {:?}", string);
24    }
25    Ok(())
26}
Source

pub fn parse_u128(&mut self) -> ParseResult<u128>

Parse an integer. The parser should be on the first character of the integer.

Source

pub fn parse_i128(&mut self) -> ParseResult<i128>

Parse an integer. The parser should be on the first character of the integer.

Source

pub fn parse_u64(&mut self) -> ParseResult<u64>

Parse an integer. The parser should be on the first character of the integer.

Source

pub fn parse_i64(&mut self) -> ParseResult<i64>

Parse an integer. The parser should be on the first character of the integer.

Source

pub fn parse_f64(&mut self) -> ParseResult<f64>

Parse a floating point number. The parser should be on the first character of the number. Radix specifiers are honored, if configured.

Source

pub fn parse_f64_decimal(&mut self) -> ParseResult<f64>

Parse a floating point number. The parser should be on the first character of the number. Radix specifiers are not allowed; the number is assumed to be decimal.

Source

pub fn parse_u128_ws(&mut self) -> ParseResult<u128>

Parse an integer. The parser should be on the first character of the integer. Any trailing whitespace (and possibly comments) is consumed.

Examples found in repository?
examples/book_cookbook_things.rs (line 24)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    loop {
9        parser.consume_ws();
10        if parser.is_at_eof() {
11            break;
12        }
13        if parser.peek_and_consume_str_ws("string") {
14            parser.expect(':')?;
15            parser.consume_ws();
16            let ch = parser.peek();
17            if ch == '"' || ch == '\'' {
18                let string = parser.parse_string_match_delimiter_ws()?;
19                println!("Got string: {}", StringEncoder::new().encode(&string));
20            }
21        } else if parser.peek_and_consume_str_ws("integer") {
22            parser.expect(':')?;
23            parser.consume_ws();
24            let number = parser.parse_u128_ws()?;
25            println!("Got integer: {}", number);
26        } else if parser.peek_and_consume_str_ws("float") {
27            parser.expect(':')?;
28            parser.consume_ws();
29            let number = parser.parse_f64_ws()?;
30            println!("Got float: {}", number);
31        } else if parser.peek_and_consume_str_ws("json") {
32            parser.expect(':')?;
33            parser.consume_ws();
34            let json = JSONParser::new().parse_value_unstandard_ws(&mut parser)?;
35            println!("Got JSON:\n{}", json);
36        } else {
37            return Err(syntax_error(
38                parser.loc(),
39                "Unexpected element found in stream",
40            ));
41        }
42    }
43    Ok(())
44}
Source

pub fn parse_i128_ws(&mut self) -> ParseResult<i128>

Parse an integer. The parser should be on the first character of the integer. Any trailing whitespace (and possibly comments) is consumed.

Source

pub fn parse_u64_ws(&mut self) -> ParseResult<u64>

Parse an integer. The parser should be on the first character of the integer. Any trailing whitespace (and possibly comments) is consumed.

Source

pub fn parse_i64_ws(&mut self) -> ParseResult<i64>

Parse an integer. The parser should be on the first character of the integer. Any trailing whitespace (and possibly comments) is consumed.

Source

pub fn parse_f64_ws(&mut self) -> ParseResult<f64>

Parse a floating point number. The parser should be on the first character of the number. Radix specifiers are honored, if configured. Trailing whitespace is consumed.

Examples found in repository?
examples/book_math_parser.rs (line 17)
16pub fn parse_number_ws(parser: &mut Parser) -> ParseResult<f64> {
17    parser.parse_f64_ws()
18}
More examples
Hide additional examples
examples/book_numbers_float.rs (line 4)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        match parser.parse_f64_ws() {
5            Err(err) => {
6                println!("ERROR: {}", err);
7            }
8            Ok(value) => {
9                println!("  {}", value);
10            }
11        }
12    }
13}
examples/book_cookbook_things.rs (line 29)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    loop {
9        parser.consume_ws();
10        if parser.is_at_eof() {
11            break;
12        }
13        if parser.peek_and_consume_str_ws("string") {
14            parser.expect(':')?;
15            parser.consume_ws();
16            let ch = parser.peek();
17            if ch == '"' || ch == '\'' {
18                let string = parser.parse_string_match_delimiter_ws()?;
19                println!("Got string: {}", StringEncoder::new().encode(&string));
20            }
21        } else if parser.peek_and_consume_str_ws("integer") {
22            parser.expect(':')?;
23            parser.consume_ws();
24            let number = parser.parse_u128_ws()?;
25            println!("Got integer: {}", number);
26        } else if parser.peek_and_consume_str_ws("float") {
27            parser.expect(':')?;
28            parser.consume_ws();
29            let number = parser.parse_f64_ws()?;
30            println!("Got float: {}", number);
31        } else if parser.peek_and_consume_str_ws("json") {
32            parser.expect(':')?;
33            parser.consume_ws();
34            let json = JSONParser::new().parse_value_unstandard_ws(&mut parser)?;
35            println!("Got JSON:\n{}", json);
36        } else {
37            return Err(syntax_error(
38                parser.loc(),
39                "Unexpected element found in stream",
40            ));
41        }
42    }
43    Ok(())
44}
Source

pub fn parse_f64_decimal_ws(&mut self) -> ParseResult<f64>

Parse a floating point number. The parser should be on the first character of the number. Radix specifiers are not allowed; the number is assumed to be decimal. Trailing whitespace is consumed.

Examples found in repository?
examples/book_json_parser.rs (line 28)
16pub fn parse_value_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
17    match parser.peek() {
18        // Check for an object.
19        '{' => parse_object_ws(parser),
20
21        // Check for an array.
22        '[' => parse_array_ws(parser),
23
24        // Check for a string.
25        '"' => Ok(JSON::String(parser.parse_string_match_delimiter_ws()?)),
26
27        // Check for a number.
28        ch if ch == '-' || ch.is_ascii_digit() => Ok(JSON::Number(parser.parse_f64_decimal_ws()?)),
29
30        // Check for Boolean true.
31        't' if parser.peek_and_consume_str_ws("true") => Ok(JSON::Boolean(true)),
32
33        // Check for Boolean false.
34        'f' if parser.peek_and_consume_str_ws("false") => Ok(JSON::Boolean(false)),
35
36        // Check for null.
37        'n' if parser.peek_and_consume_str_ws("null") => Ok(JSON::Null),
38
39        // Error.
40        ch => Err(trivet::errors::unexpected_text_error(
41            parser.loc(),
42            "the start of a JSON value",
43            &ch.to_string(),
44        )),
45    }
46}
Source

pub fn parse_keyword(&mut self) -> ParseResult<String>

Parse a keyword from the stream using the keyword parser. The parser should be on the first character of the keyword.

Source

pub fn parse_keyword_ws(&mut self) -> ParseResult<String>

Parse a keyword from the stream using the keyword parser. The parser should be on the first character of the keyword. Trailing whitespace is consumed.

Examples found in repository?
examples/book_keywords.rs (line 4)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        match parser.parse_keyword_ws() {
5            Err(err) => {
6                println!("ERROR: {}", err);
7                // Consume until whitespace, then resume trying.
8                parser.take_while(|ch| !ch.is_whitespace());
9                parser.consume_ws();
10            }
11            Ok(value) => {
12                println!("  {}", value);
13            }
14        }
15    }
16}
More examples
Hide additional examples
examples/book_keywords_permit.rs (line 21)
16fn main() {
17    let mut parser = trivet::parse_from_stdin();
18    parser.borrow_keyword_parser().use_permit = true;
19    parser.borrow_keyword_parser().permit = Box::new(keyword);
20    while !parser.is_at_eof() {
21        match parser.parse_keyword_ws() {
22            Err(err) => {
23                println!("ERROR: {}", err);
24                // Consume until whitespace, then resume trying.
25                parser.take_while(|ch| !ch.is_whitespace());
26                parser.consume_ws();
27            }
28            Ok(value) => {
29                println!("  {}", value);
30            }
31        }
32    }
33}
examples/book_keywords_transform.rs (line 7)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    parser.borrow_keyword_parser().use_transform = true;
4    parser.borrow_keyword_parser().transform =
5        Box::new(|ch| if [':', '.'].contains(&ch) { '_' } else { ch });
6    while !parser.is_at_eof() {
7        match parser.parse_keyword_ws() {
8            Err(err) => {
9                println!("ERROR: {}", err);
10                // Consume until whitespace, then resume trying.
11                parser.take_while(|ch| !ch.is_whitespace());
12                parser.consume_ws();
13            }
14            Ok(value) => {
15                println!("  {}", value);
16            }
17        }
18    }
19}
Source

pub fn loc(&self) -> Loc

Get the current location in the parse. This will return either a console (if the name is the empty string) or a file location (if the name was not the empty string).

Examples found in repository?
examples/integers.rs (line 8)
4fn parse_unsigned_integer(parser: &mut trivet::Parser) -> ParseResult<u64> {
5    let result = parser.take_while(|ch| ch.is_ascii_digit());
6    match result.parse::<u64>() {
7        Ok(number) => Ok(number),
8        Err(err) => Err(error(parser.loc(), err)),
9    }
10}
More examples
Hide additional examples
examples/book_building_parse_integer_2.rs (line 5)
1fn parse_unsigned_integer(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<u64> {
2    let result = parser.take_while(|ch| ch.is_ascii_digit());
3    match result.parse::<u64>() {
4        Ok(number) => Ok(number),
5        Err(err) => Err(trivet::errors::error(parser.loc(), err)),
6    }
7}
examples/book_building_sequence.rs (line 5)
1fn parse_unsigned_integer(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<u64> {
2    let result = parser.take_while(|ch| ch.is_ascii_digit());
3    match result.parse::<u64>() {
4        Ok(number) => Ok(number),
5        Err(err) => Err(trivet::errors::error(parser.loc(), err)),
6    }
7}
8
9fn parse_identifier(parser: &mut trivet::Parser) -> String {
10    let mut result = parser.take_while(|ch| ch.is_alphabetic());
11    result += parser.take_while(|ch| ch.is_alphanumeric()).as_str();
12    result
13}
14
15#[derive(Debug)]
16enum Thing {
17    Number(trivet::Loc, u64),
18    Id(trivet::Loc, String),
19}
20
21fn parse_sequence_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<Vec<Thing>> {
22    let mut things = Vec::new();
23    let _ = parser.consume_ws();
24    while !parser.is_at_eof() {
25        match parser.peek() {
26            ch if ch.is_ascii_digit() => {
27                things.push(Thing::Number(parser.loc(), parse_unsigned_integer(parser)?));
28            }
29            ch if ch.is_alphabetic() => {
30                things.push(Thing::Id(parser.loc(), parse_identifier(parser)));
31            }
32            ch => {
33                return Err(trivet::errors::unexpected_text_error(
34                    parser.loc(),
35                    "number or identifier",
36                    &ch.to_string(),
37                ));
38            }
39        }
40        let _ = parser.consume_ws();
41    }
42    Ok(things)
43}
examples/book_building_parse_integer_1.rs (line 9)
1fn parse_unsigned_integer(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<u64> {
2    let mut result = String::new();
3    while parser.peek().is_ascii_digit() {
4        result.push(parser.peek());
5        parser.consume();
6    }
7    match result.parse::<u64>() {
8        Ok(number) => Ok(number),
9        Err(err) => Err(trivet::errors::error(parser.loc(), err)),
10    }
11}
examples/book_math_parser.rs (line 34)
25pub fn parse_primitive_ws(parser: &mut Parser) -> ParseResult<f64> {
26    // Look for leading minus sign.
27    let is_neg = parser.peek_and_consume('-');
28
29    // Look for a parenthesized expression.  Here is where our bottom-up approach
30    // otherwise breaks.
31    let value = if parser.peek_and_consume('(') {
32        let value = parse_top_expr_ws(parser)?;
33        if !parser.peek_and_consume_ws(')') {
34            return Err(syntax_error(parser.loc(), "Missing closing parenthesis."));
35        }
36        value
37    } else {
38        // Note that we have already parsed the negative sign from the number above, so
39        // we wil get back a nonnegative value here.  That's fine, since we will fix it
40        // at the end.
41        parse_number_ws(parser)?
42    };
43    Ok(if is_neg { -value } else { value })
44}
examples/book_string_simple.rs (line 5)
1fn main() -> trivet::errors::ParseResult<()> {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        // Save the location for later use in error messages.
5        let loc = parser.loc();
6        // Parse strings only for the supported delimiters.
7        let string = match parser.peek() {
8            // The initial and final delimiters match.
9            '"' | '\'' => parser.parse_string_match_delimiter_ws()?,
10            // Here the initial and final delimiters do not match.
11            '«' => {
12                parser.consume();
13                parser.parse_string_until_delimiter_ws('»')?
14            }
15            // This is not a legal opening delimiter.
16            ch => {
17                return Err(trivet::errors::syntax_error(
18                    loc,
19                    &format!("Invalid delimiter: '{}'", ch),
20                ));
21            }
22        };
23        println!("  --> {:?}", string);
24    }
25    Ok(())
26}
Source

pub fn is_at_eof(&self) -> bool

Determine if the parser has reached the end of the stream. If this is true, then no further characters are available from this parser.

Examples found in repository?
examples/book_math_parser.rs (line 108)
105pub fn main() -> ParseResult<()> {
106    let mut parser = parse_from_stdin();
107    parser.consume_ws();
108    while !parser.is_at_eof() {
109        let number = parse_top_expr_ws(&mut parser)?;
110        println!("  {}", number);
111    }
112    Ok(())
113}
More examples
Hide additional examples
examples/book_numbers_float.rs (line 3)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        match parser.parse_f64_ws() {
5            Err(err) => {
6                println!("ERROR: {}", err);
7            }
8            Ok(value) => {
9                println!("  {}", value);
10            }
11        }
12    }
13}
examples/passthrough.rs (line 8)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    while !parser.is_at_eof() {
9        // Read some bytes and then write them out.
10        let value = parser.peek_n(57);
11        // We can't use value.len() because that is in bytes, not characters.
12        for _ in value.chars() {
13            parser.consume();
14        }
15        print!("{}", value);
16    }
17    Ok(())
18}
examples/book_keywords.rs (line 3)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        match parser.parse_keyword_ws() {
5            Err(err) => {
6                println!("ERROR: {}", err);
7                // Consume until whitespace, then resume trying.
8                parser.take_while(|ch| !ch.is_whitespace());
9                parser.consume_ws();
10            }
11            Ok(value) => {
12                println!("  {}", value);
13            }
14        }
15    }
16}
examples/book_keywords_permit.rs (line 20)
16fn main() {
17    let mut parser = trivet::parse_from_stdin();
18    parser.borrow_keyword_parser().use_permit = true;
19    parser.borrow_keyword_parser().permit = Box::new(keyword);
20    while !parser.is_at_eof() {
21        match parser.parse_keyword_ws() {
22            Err(err) => {
23                println!("ERROR: {}", err);
24                // Consume until whitespace, then resume trying.
25                parser.take_while(|ch| !ch.is_whitespace());
26                parser.consume_ws();
27            }
28            Ok(value) => {
29                println!("  {}", value);
30            }
31        }
32    }
33}
examples/book_keywords_transform.rs (line 6)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    parser.borrow_keyword_parser().use_transform = true;
4    parser.borrow_keyword_parser().transform =
5        Box::new(|ch| if [':', '.'].contains(&ch) { '_' } else { ch });
6    while !parser.is_at_eof() {
7        match parser.parse_keyword_ws() {
8            Err(err) => {
9                println!("ERROR: {}", err);
10                // Consume until whitespace, then resume trying.
11                parser.take_while(|ch| !ch.is_whitespace());
12                parser.consume_ws();
13            }
14            Ok(value) => {
15                println!("  {}", value);
16            }
17        }
18    }
19}
Source

pub fn peek(&mut self) -> char

Peek at the next character in the stream. In order to be as fast as is reasonable, no stream checking is done. If the stream is at the end, then you should get null characters, but you should not rely on that, since the null is also a valid character in a file. Instead, be sure to check Parser::is_at_eof.

If this method is invoked too many times without any characters being consumed, then it will panic to indicate that parsing has stalled. See PEEK_LIMIT.

Examples found in repository?
examples/book_building_parse_integer_1.rs (line 3)
1fn parse_unsigned_integer(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<u64> {
2    let mut result = String::new();
3    while parser.peek().is_ascii_digit() {
4        result.push(parser.peek());
5        parser.consume();
6    }
7    match result.parse::<u64>() {
8        Ok(number) => Ok(number),
9        Err(err) => Err(trivet::errors::error(parser.loc(), err)),
10    }
11}
More examples
Hide additional examples
examples/book_building_sequence.rs (line 25)
21fn parse_sequence_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<Vec<Thing>> {
22    let mut things = Vec::new();
23    let _ = parser.consume_ws();
24    while !parser.is_at_eof() {
25        match parser.peek() {
26            ch if ch.is_ascii_digit() => {
27                things.push(Thing::Number(parser.loc(), parse_unsigned_integer(parser)?));
28            }
29            ch if ch.is_alphabetic() => {
30                things.push(Thing::Id(parser.loc(), parse_identifier(parser)));
31            }
32            ch => {
33                return Err(trivet::errors::unexpected_text_error(
34                    parser.loc(),
35                    "number or identifier",
36                    &ch.to_string(),
37                ));
38            }
39        }
40        let _ = parser.consume_ws();
41    }
42    Ok(things)
43}
examples/book_string_simple.rs (line 7)
1fn main() -> trivet::errors::ParseResult<()> {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        // Save the location for later use in error messages.
5        let loc = parser.loc();
6        // Parse strings only for the supported delimiters.
7        let string = match parser.peek() {
8            // The initial and final delimiters match.
9            '"' | '\'' => parser.parse_string_match_delimiter_ws()?,
10            // Here the initial and final delimiters do not match.
11            '«' => {
12                parser.consume();
13                parser.parse_string_until_delimiter_ws('»')?
14            }
15            // This is not a legal opening delimiter.
16            ch => {
17                return Err(trivet::errors::syntax_error(
18                    loc,
19                    &format!("Invalid delimiter: '{}'", ch),
20                ));
21            }
22        };
23        println!("  --> {:?}", string);
24    }
25    Ok(())
26}
examples/book_json_parser.rs (line 17)
16pub fn parse_value_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
17    match parser.peek() {
18        // Check for an object.
19        '{' => parse_object_ws(parser),
20
21        // Check for an array.
22        '[' => parse_array_ws(parser),
23
24        // Check for a string.
25        '"' => Ok(JSON::String(parser.parse_string_match_delimiter_ws()?)),
26
27        // Check for a number.
28        ch if ch == '-' || ch.is_ascii_digit() => Ok(JSON::Number(parser.parse_f64_decimal_ws()?)),
29
30        // Check for Boolean true.
31        't' if parser.peek_and_consume_str_ws("true") => Ok(JSON::Boolean(true)),
32
33        // Check for Boolean false.
34        'f' if parser.peek_and_consume_str_ws("false") => Ok(JSON::Boolean(false)),
35
36        // Check for null.
37        'n' if parser.peek_and_consume_str_ws("null") => Ok(JSON::Null),
38
39        // Error.
40        ch => Err(trivet::errors::unexpected_text_error(
41            parser.loc(),
42            "the start of a JSON value",
43            &ch.to_string(),
44        )),
45    }
46}
47
48/// Parse a JSON object.  On entry the parser is assumed to be pointing to the first
49/// character of the object (a curly brace `{`).  Trailing whitespace is consumed.
50fn parse_object_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
51    parser.consume(); // Consume opening brace.
52    parser.consume_ws();
53    let mut first = true;
54    let mut map = HashMap::new();
55    while !parser.peek_and_consume_ws('}') {
56        // If not the first element, then we expect to have a comma here.  JSON requires
57        // a comma between members of an object.
58        if first {
59            first = false;
60        } else if !parser.peek_and_consume_ws(',') {
61            return Err(trivet::errors::syntax_error(
62                parser.loc(),
63                "There must be a comma (,) between members of an object.",
64            ));
65        }
66
67        // Look for the quotation mark for a string.
68        if parser.peek() != '"' {
69            return Err(trivet::errors::syntax_error(
70                parser.loc(),
71                "Names in a JSON object must be quoted strings.",
72            ));
73        }
74        let name = parser.parse_string_match_delimiter_ws()?;
75
76        // Look for the colon.
77        if !parser.peek_and_consume_ws(':') {
78            return Err(trivet::errors::syntax_error(
79                parser.loc(),
80                "Names in a JSON object must be followed by a colon (:).",
81            ));
82        }
83
84        // Get the value.
85        let value = parse_value_ws(parser)?;
86
87        // Add the name, value pair to the map.
88        map.insert(name, value);
89    }
90    Ok(JSON::Object(map))
91}
examples/book_cookbook_things.rs (line 16)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    loop {
9        parser.consume_ws();
10        if parser.is_at_eof() {
11            break;
12        }
13        if parser.peek_and_consume_str_ws("string") {
14            parser.expect(':')?;
15            parser.consume_ws();
16            let ch = parser.peek();
17            if ch == '"' || ch == '\'' {
18                let string = parser.parse_string_match_delimiter_ws()?;
19                println!("Got string: {}", StringEncoder::new().encode(&string));
20            }
21        } else if parser.peek_and_consume_str_ws("integer") {
22            parser.expect(':')?;
23            parser.consume_ws();
24            let number = parser.parse_u128_ws()?;
25            println!("Got integer: {}", number);
26        } else if parser.peek_and_consume_str_ws("float") {
27            parser.expect(':')?;
28            parser.consume_ws();
29            let number = parser.parse_f64_ws()?;
30            println!("Got float: {}", number);
31        } else if parser.peek_and_consume_str_ws("json") {
32            parser.expect(':')?;
33            parser.consume_ws();
34            let json = JSONParser::new().parse_value_unstandard_ws(&mut parser)?;
35            println!("Got JSON:\n{}", json);
36        } else {
37            return Err(syntax_error(
38                parser.loc(),
39                "Unexpected element found in stream",
40            ));
41        }
42    }
43    Ok(())
44}
Source

pub fn consume(&mut self)

Consume the next character from the stream, if there is one. If not, then do nothing.

If this method is invoked too many times after reaching the end of file, then it will panic to indicate that parsing has stalled. See EOF_LIMIT.

Examples found in repository?
examples/book_building_parse_integer_1.rs (line 5)
1fn parse_unsigned_integer(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<u64> {
2    let mut result = String::new();
3    while parser.peek().is_ascii_digit() {
4        result.push(parser.peek());
5        parser.consume();
6    }
7    match result.parse::<u64>() {
8        Ok(number) => Ok(number),
9        Err(err) => Err(trivet::errors::error(parser.loc(), err)),
10    }
11}
More examples
Hide additional examples
examples/passthrough.rs (line 13)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    while !parser.is_at_eof() {
9        // Read some bytes and then write them out.
10        let value = parser.peek_n(57);
11        // We can't use value.len() because that is in bytes, not characters.
12        for _ in value.chars() {
13            parser.consume();
14        }
15        print!("{}", value);
16    }
17    Ok(())
18}
examples/book_string_simple.rs (line 12)
1fn main() -> trivet::errors::ParseResult<()> {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        // Save the location for later use in error messages.
5        let loc = parser.loc();
6        // Parse strings only for the supported delimiters.
7        let string = match parser.peek() {
8            // The initial and final delimiters match.
9            '"' | '\'' => parser.parse_string_match_delimiter_ws()?,
10            // Here the initial and final delimiters do not match.
11            '«' => {
12                parser.consume();
13                parser.parse_string_until_delimiter_ws('»')?
14            }
15            // This is not a legal opening delimiter.
16            ch => {
17                return Err(trivet::errors::syntax_error(
18                    loc,
19                    &format!("Invalid delimiter: '{}'", ch),
20                ));
21            }
22        };
23        println!("  --> {:?}", string);
24    }
25    Ok(())
26}
examples/book_json_parser.rs (line 51)
50fn parse_object_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
51    parser.consume(); // Consume opening brace.
52    parser.consume_ws();
53    let mut first = true;
54    let mut map = HashMap::new();
55    while !parser.peek_and_consume_ws('}') {
56        // If not the first element, then we expect to have a comma here.  JSON requires
57        // a comma between members of an object.
58        if first {
59            first = false;
60        } else if !parser.peek_and_consume_ws(',') {
61            return Err(trivet::errors::syntax_error(
62                parser.loc(),
63                "There must be a comma (,) between members of an object.",
64            ));
65        }
66
67        // Look for the quotation mark for a string.
68        if parser.peek() != '"' {
69            return Err(trivet::errors::syntax_error(
70                parser.loc(),
71                "Names in a JSON object must be quoted strings.",
72            ));
73        }
74        let name = parser.parse_string_match_delimiter_ws()?;
75
76        // Look for the colon.
77        if !parser.peek_and_consume_ws(':') {
78            return Err(trivet::errors::syntax_error(
79                parser.loc(),
80                "Names in a JSON object must be followed by a colon (:).",
81            ));
82        }
83
84        // Get the value.
85        let value = parse_value_ws(parser)?;
86
87        // Add the name, value pair to the map.
88        map.insert(name, value);
89    }
90    Ok(JSON::Object(map))
91}
92
93/// Parse a JSON array.  On entry the parser is assumed to be pointing to the first
94/// character of the array (a square bracket `[`).  Trailing whitespace is consumed.
95fn parse_array_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
96    parser.consume(); // Consume opening bracket.
97    parser.consume_ws_only();
98    let mut first = true;
99    let mut array = vec![];
100    while !parser.peek_and_consume_ws(']') {
101        // If not the first element, then we expect to have a comma here.  JSON requires
102        // a comma between members of an array.
103        if first {
104            first = false;
105        } else if !parser.peek_and_consume_ws(',') {
106            return Err(trivet::errors::syntax_error(
107                parser.loc(),
108                "There must be a comma (,) between members of an array.",
109            ));
110        }
111
112        // Get the value.
113        let value = parse_value_ws(parser)?;
114
115        // Add the value to the array.
116        array.push(value);
117    }
118    Ok(JSON::Array(array))
119}
Source

pub fn peek_offset(&mut self, n: usize) -> char

Peek at an offset in the stream. That is, peek at a character at a given position. The position index is zero-based, with the next character to read (the result of a simple Self::peek) being at index zero.

If there are not enough characters in the stream, then null (\0) is returned. The distance is limited by the maximum lookahead; attempts to look past it will also return a null.

Note the distinction between this method and Self::peek_n; peek_n(1) method will return the character at position zero, so it is equivalent to peek() and to peek_offset(0).

Source

pub fn peek_n(&mut self, n: usize) -> String

Peek at characters in the stream. If there are fewer than n characters in the stream, then fewer are returned. If the stream is exhausted, an empty string is returned.

If this method is invoked too many times without any characters being consumed, then it will panic to indicate that parsing has stalled. See PEEK_LIMIT.

Examples found in repository?
examples/passthrough.rs (line 10)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    while !parser.is_at_eof() {
9        // Read some bytes and then write them out.
10        let value = parser.peek_n(57);
11        // We can't use value.len() because that is in bytes, not characters.
12        for _ in value.chars() {
13            parser.consume();
14        }
15        print!("{}", value);
16    }
17    Ok(())
18}
Source

pub fn peek_n_vec(&mut self, n: usize) -> Vec<char>

Peek at characters in the stream. If there are fewer than n characters in the stream, then fewer are returned. If the stream is exhausted, an empty vector is returned.

If this method is invoked too many times without any characters being consumed, then it will panic to indicate that parsing has stalled. See PEEK_LIMIT.

This method is similar to Self::peek_n, but does not construct a string for the result, which can be better in some cases.

Source

pub fn consume_n(&mut self, n: usize)

Consume a given number of characters from the stream. The end of file is not checked during this. If there are no characters to consume, nothing is done.

If this method is invoked too many times after reaching the end of file, it will panic to indicate that parsing has stalled. See EOF_LIMIT.

Source

pub fn peek_chars(&mut self, chars: &[char]) -> bool

Check the next characters in the stream. If the next characters exactly match those given in the vector, then true is returned. Otherwise false is returned. Nothing is consumed.

Source

pub fn peek_and_consume_chars(&mut self, chars: &[char]) -> bool

Check the next characters in the stream and, if the match, consume them and return true. Otherwise return false.

Source

pub fn take_until(&mut self, token: &str) -> String

Consume characters until an end token is found. The characters consumed are returned without the end token.

Source

pub fn take_while<T: Fn(char) -> bool>(&mut self, include: T) -> String

Consume characters so long as the test is true. Return the characters that satisfy the first test.

Examples found in repository?
examples/integers.rs (line 5)
4fn parse_unsigned_integer(parser: &mut trivet::Parser) -> ParseResult<u64> {
5    let result = parser.take_while(|ch| ch.is_ascii_digit());
6    match result.parse::<u64>() {
7        Ok(number) => Ok(number),
8        Err(err) => Err(error(parser.loc(), err)),
9    }
10}
More examples
Hide additional examples
examples/book_building_parse_integer_2.rs (line 2)
1fn parse_unsigned_integer(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<u64> {
2    let result = parser.take_while(|ch| ch.is_ascii_digit());
3    match result.parse::<u64>() {
4        Ok(number) => Ok(number),
5        Err(err) => Err(trivet::errors::error(parser.loc(), err)),
6    }
7}
examples/book_building_sequence.rs (line 2)
1fn parse_unsigned_integer(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<u64> {
2    let result = parser.take_while(|ch| ch.is_ascii_digit());
3    match result.parse::<u64>() {
4        Ok(number) => Ok(number),
5        Err(err) => Err(trivet::errors::error(parser.loc(), err)),
6    }
7}
8
9fn parse_identifier(parser: &mut trivet::Parser) -> String {
10    let mut result = parser.take_while(|ch| ch.is_alphabetic());
11    result += parser.take_while(|ch| ch.is_alphanumeric()).as_str();
12    result
13}
examples/book_keywords.rs (line 8)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        match parser.parse_keyword_ws() {
5            Err(err) => {
6                println!("ERROR: {}", err);
7                // Consume until whitespace, then resume trying.
8                parser.take_while(|ch| !ch.is_whitespace());
9                parser.consume_ws();
10            }
11            Ok(value) => {
12                println!("  {}", value);
13            }
14        }
15    }
16}
examples/book_keywords_permit.rs (line 25)
16fn main() {
17    let mut parser = trivet::parse_from_stdin();
18    parser.borrow_keyword_parser().use_permit = true;
19    parser.borrow_keyword_parser().permit = Box::new(keyword);
20    while !parser.is_at_eof() {
21        match parser.parse_keyword_ws() {
22            Err(err) => {
23                println!("ERROR: {}", err);
24                // Consume until whitespace, then resume trying.
25                parser.take_while(|ch| !ch.is_whitespace());
26                parser.consume_ws();
27            }
28            Ok(value) => {
29                println!("  {}", value);
30            }
31        }
32    }
33}
examples/book_keywords_transform.rs (line 11)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    parser.borrow_keyword_parser().use_transform = true;
4    parser.borrow_keyword_parser().transform =
5        Box::new(|ch| if [':', '.'].contains(&ch) { '_' } else { ch });
6    while !parser.is_at_eof() {
7        match parser.parse_keyword_ws() {
8            Err(err) => {
9                println!("ERROR: {}", err);
10                // Consume until whitespace, then resume trying.
11                parser.take_while(|ch| !ch.is_whitespace());
12                parser.consume_ws();
13            }
14            Ok(value) => {
15                println!("  {}", value);
16            }
17        }
18    }
19}
Source

pub fn take_while_unless<T: Fn(char) -> bool, U: Fn(char) -> bool>( &mut self, include: T, exclude: U, ) -> String

Consume characters so long as either test is true. Return only those characters that satisfy the first test. The exclude predicate is checked first.

Source

pub fn take<S, K>(&mut self, skip: S, stop: K) -> (Vec<char>, Option<char>)
where S: Fn(char) -> bool, K: Fn(char) -> bool,

Consume and return characters. This works as follows.

If the current character satisfies stop, then the parse is stopped and the result is returned, regardless of whether any other predicates match.

If the current character satisfies skip, then the character is skipped.

Other characters (those that do not match skip or stop) are collected and returned.

The returned pair contains all matched characters and the character that caused the stop, or None if parsing stopped because the end of stream was reached. Because the stopping character is returned, it is also consumed.

Source

pub fn consume_while<T: Fn(char) -> bool>(&mut self, include: T) -> bool

Consume characters so long as the test is true. Returns true if any characters are consumed.

Source

pub fn consume_until(&mut self, token: &str) -> bool

Consume characters until the given end token is found. Returns true if any characters are consumed. The end token is also consumed.

Source

pub fn consume_ws_only(&mut self) -> bool

Consume all whitespace starting at the current position. The definition of whitespace used here is the same as the Unicode standard.

At the time of writing, the following is the definition of whitespace used.

0009..000D    ; White_Space # Cc   [5] <control-0009>..<control-000D>
0020          ; White_Space # Zs       SPACE
0085          ; White_Space # Cc       <control-0085>
00A0          ; White_Space # Zs       NO-BREAK SPACE
1680          ; White_Space # Zs       OGHAM SPACE MARK
2000..200A    ; White_Space # Zs  [11] EN QUAD..HAIR SPACE
2028          ; White_Space # Zl       LINE SEPARATOR
2029          ; White_Space # Zp       PARAGRAPH SEPARATOR
202F          ; White_Space # Zs       NARROW NO-BREAK SPACE
205F          ; White_Space # Zs       MEDIUM MATHEMATICAL SPACE
3000          ; White_Space # Zs       IDEOGRAPHIC SPACE

This method is slightly faster than the Self::consume_ws method as it does not look for comments.

Examples found in repository?
examples/book_json_parser.rs (line 97)
95fn parse_array_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
96    parser.consume(); // Consume opening bracket.
97    parser.consume_ws_only();
98    let mut first = true;
99    let mut array = vec![];
100    while !parser.peek_and_consume_ws(']') {
101        // If not the first element, then we expect to have a comma here.  JSON requires
102        // a comma between members of an array.
103        if first {
104            first = false;
105        } else if !parser.peek_and_consume_ws(',') {
106            return Err(trivet::errors::syntax_error(
107                parser.loc(),
108                "There must be a comma (,) between members of an array.",
109            ));
110        }
111
112        // Get the value.
113        let value = parse_value_ws(parser)?;
114
115        // Add the value to the array.
116        array.push(value);
117    }
118    Ok(JSON::Array(array))
119}
Source

pub fn peek_and_consume(&mut self, ch: char) -> bool

Peek at the next character in the stream. If it is the given character, consume it and return true. Otherwise return false.

Examples found in repository?
examples/book_math_parser.rs (line 27)
25pub fn parse_primitive_ws(parser: &mut Parser) -> ParseResult<f64> {
26    // Look for leading minus sign.
27    let is_neg = parser.peek_and_consume('-');
28
29    // Look for a parenthesized expression.  Here is where our bottom-up approach
30    // otherwise breaks.
31    let value = if parser.peek_and_consume('(') {
32        let value = parse_top_expr_ws(parser)?;
33        if !parser.peek_and_consume_ws(')') {
34            return Err(syntax_error(parser.loc(), "Missing closing parenthesis."));
35        }
36        value
37    } else {
38        // Note that we have already parsed the negative sign from the number above, so
39        // we wil get back a nonnegative value here.  That's fine, since we will fix it
40        // at the end.
41        parse_number_ws(parser)?
42    };
43    Ok(if is_neg { -value } else { value })
44}
Source

pub fn expect(&mut self, ch: char) -> ParseResult<()>

Expect a character at this point in the stream and if it is found, consume it. If it nos not found, generate an error.

Examples found in repository?
examples/book_cookbook_things.rs (line 14)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    loop {
9        parser.consume_ws();
10        if parser.is_at_eof() {
11            break;
12        }
13        if parser.peek_and_consume_str_ws("string") {
14            parser.expect(':')?;
15            parser.consume_ws();
16            let ch = parser.peek();
17            if ch == '"' || ch == '\'' {
18                let string = parser.parse_string_match_delimiter_ws()?;
19                println!("Got string: {}", StringEncoder::new().encode(&string));
20            }
21        } else if parser.peek_and_consume_str_ws("integer") {
22            parser.expect(':')?;
23            parser.consume_ws();
24            let number = parser.parse_u128_ws()?;
25            println!("Got integer: {}", number);
26        } else if parser.peek_and_consume_str_ws("float") {
27            parser.expect(':')?;
28            parser.consume_ws();
29            let number = parser.parse_f64_ws()?;
30            println!("Got float: {}", number);
31        } else if parser.peek_and_consume_str_ws("json") {
32            parser.expect(':')?;
33            parser.consume_ws();
34            let json = JSONParser::new().parse_value_unstandard_ws(&mut parser)?;
35            println!("Got JSON:\n{}", json);
36        } else {
37            return Err(syntax_error(
38                parser.loc(),
39                "Unexpected element found in stream",
40            ));
41        }
42    }
43    Ok(())
44}
Source

pub fn expect_chars(&mut self, ch: &[char]) -> ParseResult<()>

Expect a character sequence at this point in the stream and if it is found, consume it. If it is not found, generate an error.

Source

pub fn peek_str(&mut self, value: &str) -> bool

Peek at the stream and determine if the next characters are the given string. True is returned if so, and false otherwise. Nothing is consumed.

Source

pub fn peek_chars_greedy(&mut self, chars: &[char]) -> bool

Check the next characters in the stream. If the next characters exactly match those given in the vector, and do not also match one position more in the stream, then true is returned. Otherwise false is returned. Nothing is consumed.

Source

pub fn peek_str_greedy(&mut self, value: &str) -> bool

Peek ahead and see if the provided string is present in the stream. This method returns false if the token is also at an offset of one, which may seem an odd choice, but allows matching end tokens where there are repeated characters, such as """.

This is a relatively costly operation.

Source

pub fn peek_and_consume_ws(&mut self, ch: char) -> bool

Peek at the next character in the stream. If it is the given character, consume it and return true. Otherwise return false. Consume any trailing whitespace iff there is a match.

Examples found in repository?
examples/book_math_parser.rs (line 33)
25pub fn parse_primitive_ws(parser: &mut Parser) -> ParseResult<f64> {
26    // Look for leading minus sign.
27    let is_neg = parser.peek_and_consume('-');
28
29    // Look for a parenthesized expression.  Here is where our bottom-up approach
30    // otherwise breaks.
31    let value = if parser.peek_and_consume('(') {
32        let value = parse_top_expr_ws(parser)?;
33        if !parser.peek_and_consume_ws(')') {
34            return Err(syntax_error(parser.loc(), "Missing closing parenthesis."));
35        }
36        value
37    } else {
38        // Note that we have already parsed the negative sign from the number above, so
39        // we wil get back a nonnegative value here.  That's fine, since we will fix it
40        // at the end.
41        parse_number_ws(parser)?
42    };
43    Ok(if is_neg { -value } else { value })
44}
45
46/// Parse an expression containing exponentiation or bitwise operators.
47///
48/// On entry the parser is assumed to be pointing at the first character.  On
49/// exit any trailing whitespace is consumed.
50///
51pub fn parse_exp_expr_ws(parser: &mut Parser) -> ParseResult<f64> {
52    // Parse an initial primitive.
53    let mut left = parse_primitive_ws(parser)?;
54    loop {
55        // Look for an operator.
56        left = if parser.peek_and_consume_str_ws("**") {
57            let right = parse_primitive_ws(parser)?;
58            left.powf(right)
59        } else {
60            break;
61        }
62    }
63    Ok(left)
64}
65
66/// Parse multiplication, division, and remainder operations.
67///
68/// On entry the parser is assumed to be pointing at the first character.  On
69/// exit any trailing whitespace is consumed.
70///
71pub fn parse_product_expr_ws(parser: &mut Parser) -> ParseResult<f64> {
72    let mut left = parse_exp_expr_ws(parser)?;
73    loop {
74        left = if parser.peek_and_consume_ws('*') {
75            left * parse_exp_expr_ws(parser)?
76        } else if parser.peek_and_consume_ws('/') {
77            left / parse_exp_expr_ws(parser)?
78        } else {
79            break;
80        }
81    }
82    Ok(left)
83}
84
85/// Parse an expression containing arithmetic and bitwise operators.
86///
87/// On entry the parser is assumed to be pointing at the first character.  On
88/// exit any trailing whitespace is consumed.
89///
90pub fn parse_top_expr_ws(parser: &mut Parser) -> ParseResult<f64> {
91    let mut left = parse_product_expr_ws(parser)?;
92    loop {
93        left = if parser.peek_and_consume_ws('+') {
94            left + parse_product_expr_ws(parser)?
95        } else if parser.peek_and_consume_ws('-') {
96            left - parse_product_expr_ws(parser)?
97        } else {
98            break;
99        };
100    }
101    Ok(left)
102}
More examples
Hide additional examples
examples/book_json_parser.rs (line 55)
50fn parse_object_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
51    parser.consume(); // Consume opening brace.
52    parser.consume_ws();
53    let mut first = true;
54    let mut map = HashMap::new();
55    while !parser.peek_and_consume_ws('}') {
56        // If not the first element, then we expect to have a comma here.  JSON requires
57        // a comma between members of an object.
58        if first {
59            first = false;
60        } else if !parser.peek_and_consume_ws(',') {
61            return Err(trivet::errors::syntax_error(
62                parser.loc(),
63                "There must be a comma (,) between members of an object.",
64            ));
65        }
66
67        // Look for the quotation mark for a string.
68        if parser.peek() != '"' {
69            return Err(trivet::errors::syntax_error(
70                parser.loc(),
71                "Names in a JSON object must be quoted strings.",
72            ));
73        }
74        let name = parser.parse_string_match_delimiter_ws()?;
75
76        // Look for the colon.
77        if !parser.peek_and_consume_ws(':') {
78            return Err(trivet::errors::syntax_error(
79                parser.loc(),
80                "Names in a JSON object must be followed by a colon (:).",
81            ));
82        }
83
84        // Get the value.
85        let value = parse_value_ws(parser)?;
86
87        // Add the name, value pair to the map.
88        map.insert(name, value);
89    }
90    Ok(JSON::Object(map))
91}
92
93/// Parse a JSON array.  On entry the parser is assumed to be pointing to the first
94/// character of the array (a square bracket `[`).  Trailing whitespace is consumed.
95fn parse_array_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
96    parser.consume(); // Consume opening bracket.
97    parser.consume_ws_only();
98    let mut first = true;
99    let mut array = vec![];
100    while !parser.peek_and_consume_ws(']') {
101        // If not the first element, then we expect to have a comma here.  JSON requires
102        // a comma between members of an array.
103        if first {
104            first = false;
105        } else if !parser.peek_and_consume_ws(',') {
106            return Err(trivet::errors::syntax_error(
107                parser.loc(),
108                "There must be a comma (,) between members of an array.",
109            ));
110        }
111
112        // Get the value.
113        let value = parse_value_ws(parser)?;
114
115        // Add the value to the array.
116        array.push(value);
117    }
118    Ok(JSON::Array(array))
119}
Source

pub fn peek_and_consume_chars_ws(&mut self, chars: &[char]) -> bool

Peek at the stream and determine if the next characters are the given characters in order. If so, consume them and any trailing whitespace, and then return true. Otherwise consume nothing and return false.

Source

pub fn peek_and_consume_str(&mut self, value: &str) -> bool

Peek at the stream and determine if the next characters are the given string. If so, consume them and return true. Otherwise return false.

Source

pub fn peek_and_consume_str_ws(&mut self, value: &str) -> bool

Peek at the stream and determine if the next characters are the given string. If so, consume them and return true. Otherwise return false. Consume trailing whitespace.

Examples found in repository?
examples/book_math_parser.rs (line 56)
51pub fn parse_exp_expr_ws(parser: &mut Parser) -> ParseResult<f64> {
52    // Parse an initial primitive.
53    let mut left = parse_primitive_ws(parser)?;
54    loop {
55        // Look for an operator.
56        left = if parser.peek_and_consume_str_ws("**") {
57            let right = parse_primitive_ws(parser)?;
58            left.powf(right)
59        } else {
60            break;
61        }
62    }
63    Ok(left)
64}
More examples
Hide additional examples
examples/book_json_parser.rs (line 31)
16pub fn parse_value_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<JSON> {
17    match parser.peek() {
18        // Check for an object.
19        '{' => parse_object_ws(parser),
20
21        // Check for an array.
22        '[' => parse_array_ws(parser),
23
24        // Check for a string.
25        '"' => Ok(JSON::String(parser.parse_string_match_delimiter_ws()?)),
26
27        // Check for a number.
28        ch if ch == '-' || ch.is_ascii_digit() => Ok(JSON::Number(parser.parse_f64_decimal_ws()?)),
29
30        // Check for Boolean true.
31        't' if parser.peek_and_consume_str_ws("true") => Ok(JSON::Boolean(true)),
32
33        // Check for Boolean false.
34        'f' if parser.peek_and_consume_str_ws("false") => Ok(JSON::Boolean(false)),
35
36        // Check for null.
37        'n' if parser.peek_and_consume_str_ws("null") => Ok(JSON::Null),
38
39        // Error.
40        ch => Err(trivet::errors::unexpected_text_error(
41            parser.loc(),
42            "the start of a JSON value",
43            &ch.to_string(),
44        )),
45    }
46}
examples/book_cookbook_things.rs (line 13)
6pub fn main() -> ParseResult<()> {
7    let mut parser = parse_from_stdin();
8    loop {
9        parser.consume_ws();
10        if parser.is_at_eof() {
11            break;
12        }
13        if parser.peek_and_consume_str_ws("string") {
14            parser.expect(':')?;
15            parser.consume_ws();
16            let ch = parser.peek();
17            if ch == '"' || ch == '\'' {
18                let string = parser.parse_string_match_delimiter_ws()?;
19                println!("Got string: {}", StringEncoder::new().encode(&string));
20            }
21        } else if parser.peek_and_consume_str_ws("integer") {
22            parser.expect(':')?;
23            parser.consume_ws();
24            let number = parser.parse_u128_ws()?;
25            println!("Got integer: {}", number);
26        } else if parser.peek_and_consume_str_ws("float") {
27            parser.expect(':')?;
28            parser.consume_ws();
29            let number = parser.parse_f64_ws()?;
30            println!("Got float: {}", number);
31        } else if parser.peek_and_consume_str_ws("json") {
32            parser.expect(':')?;
33            parser.consume_ws();
34            let json = JSONParser::new().parse_value_unstandard_ws(&mut parser)?;
35            println!("Got JSON:\n{}", json);
36        } else {
37            return Err(syntax_error(
38                parser.loc(),
39                "Unexpected element found in stream",
40            ));
41        }
42    }
43    Ok(())
44}
Source

pub fn consume_ws(&mut self) -> bool

Consume whitespace. This is the method used by all the _ws method forms. It will also use the embedded comment parser to parse and discard comments.

Examples found in repository?
examples/book_math_parser.rs (line 107)
105pub fn main() -> ParseResult<()> {
106    let mut parser = parse_from_stdin();
107    parser.consume_ws();
108    while !parser.is_at_eof() {
109        let number = parse_top_expr_ws(&mut parser)?;
110        println!("  {}", number);
111    }
112    Ok(())
113}
More examples
Hide additional examples
examples/book_keywords.rs (line 9)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    while !parser.is_at_eof() {
4        match parser.parse_keyword_ws() {
5            Err(err) => {
6                println!("ERROR: {}", err);
7                // Consume until whitespace, then resume trying.
8                parser.take_while(|ch| !ch.is_whitespace());
9                parser.consume_ws();
10            }
11            Ok(value) => {
12                println!("  {}", value);
13            }
14        }
15    }
16}
examples/book_keywords_permit.rs (line 26)
16fn main() {
17    let mut parser = trivet::parse_from_stdin();
18    parser.borrow_keyword_parser().use_permit = true;
19    parser.borrow_keyword_parser().permit = Box::new(keyword);
20    while !parser.is_at_eof() {
21        match parser.parse_keyword_ws() {
22            Err(err) => {
23                println!("ERROR: {}", err);
24                // Consume until whitespace, then resume trying.
25                parser.take_while(|ch| !ch.is_whitespace());
26                parser.consume_ws();
27            }
28            Ok(value) => {
29                println!("  {}", value);
30            }
31        }
32    }
33}
examples/book_keywords_transform.rs (line 12)
1fn main() {
2    let mut parser = trivet::parse_from_stdin();
3    parser.borrow_keyword_parser().use_transform = true;
4    parser.borrow_keyword_parser().transform =
5        Box::new(|ch| if [':', '.'].contains(&ch) { '_' } else { ch });
6    while !parser.is_at_eof() {
7        match parser.parse_keyword_ws() {
8            Err(err) => {
9                println!("ERROR: {}", err);
10                // Consume until whitespace, then resume trying.
11                parser.take_while(|ch| !ch.is_whitespace());
12                parser.consume_ws();
13            }
14            Ok(value) => {
15                println!("  {}", value);
16            }
17        }
18    }
19}
examples/book_building_sequence.rs (line 23)
21fn parse_sequence_ws(parser: &mut trivet::Parser) -> trivet::errors::ParseResult<Vec<Thing>> {
22    let mut things = Vec::new();
23    let _ = parser.consume_ws();
24    while !parser.is_at_eof() {
25        match parser.peek() {
26            ch if ch.is_ascii_digit() => {
27                things.push(Thing::Number(parser.loc(), parse_unsigned_integer(parser)?));
28            }
29            ch if ch.is_alphabetic() => {
30                things.push(Thing::Id(parser.loc(), parse_identifier(parser)));
31            }
32            ch => {
33                return Err(trivet::errors::unexpected_text_error(
34                    parser.loc(),
35                    "number or identifier",
36                    &ch.to_string(),
37                ));
38            }
39        }
40        let _ = parser.consume_ws();
41    }
42    Ok(things)
43}
examples/numbers.rs (line 20)
7pub fn main() {
8    println!("Enter a number to see how Trivet parses it.  Enter a blank line to stop.");
9    let numpar = NumberParser::new();
10    print!("> ");
11    let _ = stdout().flush();
12    for line in stdin().lock().lines() {
13        if line.is_err() {
14            break;
15        }
16        let line = line.unwrap();
17
18        // Consume any whitespace.
19        let mut parser = parse_from_string(&line);
20        parser.consume_ws();
21        if parser.is_at_eof() {
22            break;
23        }
24
25        // Try to read a number as pieces.
26        let parts = numpar.get_parts(parser.borrow_core());
27        println!("{:?}", parts);
28        if parts.is_apparent_float() {
29            let value: f64 = parts.into();
30            println!("f64: {}", value);
31        } else {
32            let value: i128 = parts.into();
33            println!("i128: {}", value);
34        }
35
36        // Go around again.
37        print!("> ");
38        let _ = stdout().flush();
39    }
40}
Source

pub fn take_until_greedy( &mut self, chars: &[char], must_match: bool, ) -> ParseResult<String>

Consume characters until the given character sequence is found. This uses greedy matching (see Self::peek_chars_greedy) and returns the characters consumed. The end token is also consumed and not returned.

If the must_match flag is true, then the end token must be matched and consumed, otherwise an error is generated.

Auto Trait Implementations§

§

impl Freeze for Parser

§

impl !RefUnwindSafe for Parser

§

impl !Send for Parser

§

impl !Sync for Parser

§

impl Unpin for Parser

§

impl !UnwindSafe for Parser

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.