Add proper string parser for Instruction
This commit is contained in:
parent
faad8e2ed0
commit
bc9951f84f
2 changed files with 105 additions and 16 deletions
|
|
@ -63,7 +63,7 @@ impl Selector for &str {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description(&self) -> String {
|
fn description(&self) -> String {
|
||||||
format!("text == \"{}\"", self.escape_default())
|
format!("text == {self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +91,7 @@ impl Selector for Id {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description(&self) -> String {
|
fn description(&self) -> String {
|
||||||
format!("id == {:?}", self)
|
format!("id == {self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,7 +106,7 @@ impl Selector for Point {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description(&self) -> String {
|
fn description(&self) -> String {
|
||||||
format!("bounds contains {:?}", self)
|
format!("bounds contains {self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -421,10 +421,13 @@ mod parser {
|
||||||
|
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::character::complete::{char, multispace0, satisfy};
|
use nom::bytes::{is_not, take_while_m_n};
|
||||||
use nom::combinator::{cut, map, opt, recognize, success};
|
use nom::character::complete::{char, multispace0, multispace1};
|
||||||
|
use nom::combinator::{
|
||||||
|
cut, map, map_opt, map_res, opt, success, value, verify,
|
||||||
|
};
|
||||||
use nom::error::ParseError;
|
use nom::error::ParseError;
|
||||||
use nom::multi::many0;
|
use nom::multi::fold;
|
||||||
use nom::number::float;
|
use nom::number::float;
|
||||||
use nom::sequence::{delimited, preceded, separated_pair};
|
use nom::sequence::{delimited, preceded, separated_pair};
|
||||||
use nom::{Finish, IResult, Parser};
|
use nom::{Finish, IResult, Parser};
|
||||||
|
|
@ -521,16 +524,6 @@ mod parser {
|
||||||
.parse(input)
|
.parse(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string(input: &str) -> IResult<&str, String> {
|
|
||||||
// TODO: Proper string literal parsing
|
|
||||||
delimited(
|
|
||||||
char('"'),
|
|
||||||
map(recognize(many0(satisfy(|c| c != '"'))), str::to_owned),
|
|
||||||
char('"'),
|
|
||||||
)
|
|
||||||
.parse(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn point(input: &str) -> IResult<&str, Point> {
|
fn point(input: &str) -> IResult<&str, Point> {
|
||||||
let comma = whitespace(char(','));
|
let comma = whitespace(char(','));
|
||||||
|
|
||||||
|
|
@ -553,4 +546,100 @@ mod parser {
|
||||||
{
|
{
|
||||||
delimited(multispace0, inner, multispace0)
|
delimited(multispace0, inner, multispace0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Taken from https://github.com/rust-bakery/nom/blob/51c3c4e44fa78a8a09b413419372b97b2cc2a787/examples/string.rs
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014-2019 Geoffroy Couprie
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
fn string(input: &str) -> IResult<&str, String> {
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Fragment<'a> {
|
||||||
|
Literal(&'a str),
|
||||||
|
EscapedChar(char),
|
||||||
|
EscapedWS,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fragment(input: &str) -> IResult<&str, Fragment<'_>> {
|
||||||
|
alt((
|
||||||
|
map(string_literal, Fragment::Literal),
|
||||||
|
map(escaped_char, Fragment::EscapedChar),
|
||||||
|
value(Fragment::EscapedWS, escaped_whitespace),
|
||||||
|
))
|
||||||
|
.parse(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_literal<'a, E: ParseError<&'a str>>(
|
||||||
|
input: &'a str,
|
||||||
|
) -> IResult<&'a str, &'a str, E> {
|
||||||
|
let not_quote_slash = is_not("\"\\");
|
||||||
|
|
||||||
|
verify(not_quote_slash, |s: &str| !s.is_empty()).parse(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unicode(input: &str) -> IResult<&str, char> {
|
||||||
|
let parse_hex =
|
||||||
|
take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit());
|
||||||
|
|
||||||
|
let parse_delimited_hex =
|
||||||
|
preceded(char('u'), delimited(char('{'), parse_hex, char('}')));
|
||||||
|
|
||||||
|
let parse_u32 = map_res(parse_delimited_hex, move |hex| {
|
||||||
|
u32::from_str_radix(hex, 16)
|
||||||
|
});
|
||||||
|
|
||||||
|
map_opt(parse_u32, std::char::from_u32).parse(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn escaped_char(input: &str) -> IResult<&str, char> {
|
||||||
|
preceded(
|
||||||
|
char('\\'),
|
||||||
|
alt((
|
||||||
|
unicode,
|
||||||
|
value('\n', char('n')),
|
||||||
|
value('\r', char('r')),
|
||||||
|
value('\t', char('t')),
|
||||||
|
value('\u{08}', char('b')),
|
||||||
|
value('\u{0C}', char('f')),
|
||||||
|
value('\\', char('\\')),
|
||||||
|
value('/', char('/')),
|
||||||
|
value('"', char('"')),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.parse(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn escaped_whitespace(input: &str) -> IResult<&str, &str> {
|
||||||
|
preceded(char('\\'), multispace1).parse(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
let build_string =
|
||||||
|
fold(0.., fragment, String::new, |mut string, fragment| {
|
||||||
|
match fragment {
|
||||||
|
Fragment::Literal(s) => string.push_str(s),
|
||||||
|
Fragment::EscapedChar(c) => string.push(c),
|
||||||
|
Fragment::EscapedWS => {}
|
||||||
|
}
|
||||||
|
string
|
||||||
|
});
|
||||||
|
|
||||||
|
delimited(char('"'), build_string, char('"')).parse(input)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue