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
peekmethods look ahead at the character source. Their return is either the characters themselves or a Boolean indicating a match or failure to match. - The
consumemethods 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_consumemethod 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
_charsin the name. - Methods that work with a string have
_strin the name. These methods are absent fromParserCore.
[whitespace]
- Methods that consume trailing whitespace (possibly including comments) are suffixed
with
_ws. These methods are absent fromParserCore.
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.
| Method | Input | Return | Only in Parser |
|---|---|---|---|
Self::peek | char | ||
Self::peek_n | usize | String | |
Self::peek_n_vec | usize | Vec<char> | |
Self::peek_offset | usize | char | |
Self::peek_chars | Vec<char> | bool | |
Self::peek_chars_greedy (see below) | Vec<char> | bool | * |
Self::peek_str | &str | bool | * |
Self::peek_str_greedy (see below) | &str | bool | * |
Self::consume | |||
Self::consume_n | usize | ||
Self::consume_ws | bool | * | |
Self::peek_and_consume | char | bool | |
Self::peek_and_consume_ws | char | bool | * |
Self::peek_and_consume_chars | Vec<char> | bool | |
Self::peek_and_consume_chars_ws | Vec<char> | bool | * |
Self::peek_and_consume_str | &str | bool | * |
Self::peek_and_consume_str_ws | &str | bool | * |
Self::take_while | closure | String | |
Self::take_while_unless | closure | String | |
Self::take_until | String | String | |
Self::take_until_greedy (see below) | String | String | * |
Self::consume_while | closure | bool | |
Self::consume_until | String | bool |
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: boolIf 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
impl Parser
Sourcepub fn new(name: &str, decoder: Decode) -> Self
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.
Sourcepub fn borrow_core(&mut self) -> &mut ParserCore
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?
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
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}Sourcepub fn borrow_comment_parser(&mut self) -> &mut CommentParser
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?
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}Sourcepub fn replace_comment_parser(&mut self, compar: CommentParser) -> CommentParser
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.
Sourcepub fn borrow_number_parser(&mut self) -> &mut NumberParser
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?
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}Sourcepub fn replace_number_parser(&mut self, numpar: NumberParser) -> NumberParser
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.
Sourcepub fn borrow_string_parser(&mut self) -> &mut StringParser
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?
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}Sourcepub fn replace_string_parser(&mut self, strpar: StringParser) -> StringParser
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.
Sourcepub fn borrow_keyword_parser(&mut self) -> &mut KeywordParser
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?
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
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}Sourcepub fn replace_keyword_parser(&mut self, strpar: KeywordParser) -> KeywordParser
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.
Sourcepub fn parse_string_match_delimiter(&mut self) -> ParseResult<String>
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.
Sourcepub fn parse_string_until_delimiter(
&mut self,
delimiter: char,
) -> ParseResult<String>
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.
Sourcepub fn parse_string_match_delimiter_ws(&mut self) -> ParseResult<String>
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?
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
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}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}Sourcepub fn parse_string(&self, string: &str) -> ParseResult<String>
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.
Sourcepub fn parse_string_until_delimiter_ws(
&mut self,
terminator: char,
) -> ParseResult<String>
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?
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}Sourcepub fn parse_u128(&mut self) -> ParseResult<u128>
pub fn parse_u128(&mut self) -> ParseResult<u128>
Parse an integer. The parser should be on the first character of the integer.
Sourcepub fn parse_i128(&mut self) -> ParseResult<i128>
pub fn parse_i128(&mut self) -> ParseResult<i128>
Parse an integer. The parser should be on the first character of the integer.
Sourcepub fn parse_u64(&mut self) -> ParseResult<u64>
pub fn parse_u64(&mut self) -> ParseResult<u64>
Parse an integer. The parser should be on the first character of the integer.
Sourcepub fn parse_i64(&mut self) -> ParseResult<i64>
pub fn parse_i64(&mut self) -> ParseResult<i64>
Parse an integer. The parser should be on the first character of the integer.
Sourcepub fn parse_f64(&mut self) -> ParseResult<f64>
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.
Sourcepub fn parse_f64_decimal(&mut self) -> ParseResult<f64>
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.
Sourcepub fn parse_u128_ws(&mut self) -> ParseResult<u128>
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?
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}Sourcepub fn parse_i128_ws(&mut self) -> ParseResult<i128>
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.
Sourcepub fn parse_u64_ws(&mut self) -> ParseResult<u64>
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.
Sourcepub fn parse_i64_ws(&mut self) -> ParseResult<i64>
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.
Sourcepub fn parse_f64_ws(&mut self) -> ParseResult<f64>
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?
More examples
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}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}Sourcepub fn parse_f64_decimal_ws(&mut self) -> ParseResult<f64>
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?
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}Sourcepub fn parse_keyword(&mut self) -> ParseResult<String>
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.
Sourcepub fn parse_keyword_ws(&mut self) -> ParseResult<String>
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?
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
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}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}Sourcepub fn loc(&self) -> Loc
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?
More examples
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}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}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}Sourcepub fn is_at_eof(&self) -> bool
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?
More examples
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}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}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}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}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}Sourcepub fn peek(&mut self) -> char
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?
More examples
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}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}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}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}Sourcepub fn consume(&mut self)
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?
More examples
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}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}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}Sourcepub fn peek_offset(&mut self, n: usize) -> char
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).
Sourcepub fn peek_n(&mut self, n: usize) -> String
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?
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}Sourcepub fn peek_n_vec(&mut self, n: usize) -> Vec<char>
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.
Sourcepub fn consume_n(&mut self, n: usize)
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.
Sourcepub fn peek_chars(&mut self, chars: &[char]) -> bool
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.
Sourcepub fn peek_and_consume_chars(&mut self, chars: &[char]) -> bool
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.
Sourcepub fn take_until(&mut self, token: &str) -> String
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.
Sourcepub fn take_while<T: Fn(char) -> bool>(&mut self, include: T) -> String
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?
More examples
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}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}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}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}Sourcepub fn take_while_unless<T: Fn(char) -> bool, U: Fn(char) -> bool>(
&mut self,
include: T,
exclude: U,
) -> String
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.
Sourcepub fn take<S, K>(&mut self, skip: S, stop: K) -> (Vec<char>, Option<char>)
pub fn take<S, K>(&mut self, skip: S, stop: K) -> (Vec<char>, Option<char>)
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.
Sourcepub fn consume_while<T: Fn(char) -> bool>(&mut self, include: T) -> bool
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.
Sourcepub fn consume_until(&mut self, token: &str) -> bool
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.
Sourcepub fn consume_ws_only(&mut self) -> bool
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 SPACEThis method is slightly faster than the Self::consume_ws method as it does not
look for comments.
Examples found in repository?
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}Sourcepub fn peek_and_consume(&mut self, ch: char) -> bool
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?
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}Sourcepub fn expect(&mut self, ch: char) -> ParseResult<()>
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?
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}Sourcepub fn expect_chars(&mut self, ch: &[char]) -> ParseResult<()>
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.
Sourcepub fn peek_str(&mut self, value: &str) -> bool
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.
Sourcepub fn peek_chars_greedy(&mut self, chars: &[char]) -> bool
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.
Sourcepub fn peek_str_greedy(&mut self, value: &str) -> bool
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.
Sourcepub fn peek_and_consume_ws(&mut self, ch: char) -> bool
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?
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
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}Sourcepub fn peek_and_consume_chars_ws(&mut self, chars: &[char]) -> bool
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.
Sourcepub fn peek_and_consume_str(&mut self, value: &str) -> bool
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.
Sourcepub fn peek_and_consume_str_ws(&mut self, value: &str) -> bool
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?
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
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}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}Sourcepub fn consume_ws(&mut self) -> bool
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?
More examples
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}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}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}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}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}Sourcepub fn take_until_greedy(
&mut self,
chars: &[char],
must_match: bool,
) -> ParseResult<String>
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.