Skip to content
Extraits de code Groupes Projets
Non vérifiée Valider a8fc2bc5 rédigé par Kubat's avatar Kubat
Parcourir les fichiers

[NOTEST] Parses strings, we handle Python-style strings

parent 303661f7
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
use crate::ast::Location;
use nom::{Compare, Input, Offset as _};
use nom::{Compare, FindSubstring, Input, Offset as _};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Span<'a> {
......@@ -135,3 +135,9 @@ impl Compare<&str> for Span<'_> {
self.fragment().compare_no_case(t)
}
}
impl FindSubstring<&str> for Span<'_> {
fn find_substring(&self, substr: &str) -> Option<usize> {
todo!()
}
}
......@@ -4,8 +4,14 @@ use crate::{
};
use nom::{
Parser,
bytes::complete::tag,
character::complete::{multispace0, multispace1},
branch::alt,
bytes::{
complete::{tag, take_while_m_n},
take_until,
},
character::complete::{char, digit1, multispace0, multispace1},
combinator::{peek, value, verify},
multi::fold,
sequence::{delimited, preceded},
};
......@@ -45,18 +51,118 @@ pub fn keyword<'a>(
delimited(multispace1, tag(ident), multispace1)
}
pub fn float(s: Span) -> ParserResult<f32> {
todo!()
pub fn float<'a>(s: Span<'a>) -> ParserResult<'a, f32> {
digit1
.map_res(|s: Span<'a>| str::parse::<f32>(s.fragment()))
.parse(s)
}
pub fn string(s: Span) -> ParserResult<String> {
pub fn identifier(s: Span) -> ParserResult<String> {
todo!()
}
pub fn identifier(s: Span) -> ParserResult<String> {
todo!()
pub fn number<'a>(s: Span<'a>) -> ParserResult<'a, i32> {
digit1
.map_res(|s: Span<'a>| str::parse::<i32>(s.fragment()))
.parse(s)
}
pub fn number(s: Span) -> ParserResult<i32> {
todo!()
pub fn string(span: Span) -> ParserResult<String> {
#[derive(Clone, Copy)]
enum StringFragment<'a> {
Literal(&'a str),
EscapedChar(char),
EscapedWhiteSpaces,
}
#[derive(Clone, Copy)]
enum StringDelimiterQuote {
Single,
Double,
TripleSingle,
TripleDouble,
}
impl StringDelimiterQuote {
fn as_str(&self) -> &'static str {
match self {
StringDelimiterQuote::Double => "\"",
StringDelimiterQuote::Single => "'",
StringDelimiterQuote::TripleSingle => "'''",
StringDelimiterQuote::TripleDouble => "\"\"\"",
}
}
fn get_parser<'a>(self) -> impl Parser<Span<'a>, Output = Self, Error = ParserError> {
value(self, tag(self.as_str()))
}
}
let span = multispace0(span)?.0;
let delimiter = peek(alt((
StringDelimiterQuote::Double.get_parser(),
StringDelimiterQuote::Single.get_parser(),
StringDelimiterQuote::TripleSingle.get_parser(),
StringDelimiterQuote::TripleDouble.get_parser(),
)))
.parse(span)?
.1;
// Parse an escaped character: \n, \t, \r, \u{00AC}, etc.
let parse_unicode = delimited(
tag("u{"),
take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()),
char('}'),
)
.map(Span::into_fragment)
.map_res(move |hex: &str| u32::from_str_radix(hex, 16))
.map_opt(std::char::from_u32);
let parse_escaped_char = preceded(
char('\\'),
alt((
parse_unicode,
// The `value` parser returns a fixed value (the first argument) if it parser (the
// second argument) succeeds.
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('"')),
value('\'', char('\'')),
)),
);
let parse_fragment = alt((
// Take until the end of the string
verify(take_until(delimiter.as_str()), |s: &Span| !s.is_empty())
.map(Span::into_fragment)
.map(StringFragment::Literal),
// Be aware of escaped characters
parse_escaped_char.map(StringFragment::EscapedChar),
// We handle escaped whitespaces
value(
StringFragment::EscapedWhiteSpaces,
preceded(char('\\'), multispace1),
),
));
let from_fragments = |mut string: String, fragment| {
match fragment {
StringFragment::Literal(s) => string.push_str(s),
StringFragment::EscapedChar(c) => string.push(c),
StringFragment::EscapedWhiteSpaces => {}
}
string
};
delimited(
tag(delimiter.as_str()),
fold(0.., parse_fragment, String::default, from_fragments),
tag(delimiter.as_str()),
)
.parse(span)
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter