Compare commits

...

2 Commits

Author SHA1 Message Date
Greg Shuflin
4b11a6622a Support \u escapes in strings 2021-11-21 02:11:20 -08:00
Greg Shuflin
884c8e515f Fix string literal escape parsing 2021-11-21 01:54:34 -08:00
3 changed files with 20 additions and 14 deletions

View File

@ -841,8 +841,15 @@ fn string_literal(input: Span) -> ParseResult<ExpressionKind> {
} }
fn bare_string_literal(input: Span) -> ParseResult<String> { fn bare_string_literal(input: Span) -> ParseResult<String> {
let string_escape_transforms = let string_escape_transforms = alt((
alt((value("\\", tag("\\")), value("\"", tag("\"")), value("\n", tag("n")), value("\t", tag("t")))); value('\\', tag("\\")),
value('"', tag("\"")),
value('\n', tag("n")),
value('\t', tag("t")),
map(delimited(tag(r#"u{"#), recognize(digit_group_hex), tag("}")), |value| {
char::from_u32(u32::from_str_radix(value.fragment(), 16).unwrap()).unwrap()
}),
));
alt(( alt((
map(tag(r#""""#), |_| String::new()), map(tag(r#""""#), |_| String::new()),
preceded( preceded(

View File

@ -423,7 +423,7 @@ peg::parser! {
rule pattern_literal() -> Pattern = rule pattern_literal() -> Pattern =
"true" { Pattern::Literal(PatternLiteral::BoolPattern(true)) } / "true" { Pattern::Literal(PatternLiteral::BoolPattern(true)) } /
"false" { Pattern::Literal(PatternLiteral::BoolPattern(false)) } / "false" { Pattern::Literal(PatternLiteral::BoolPattern(false)) } /
s:bare_string_literal() { Pattern::Literal(PatternLiteral::StringPattern(Rc::new(s.to_string()))) } / s:bare_string_literal() { Pattern::Literal(PatternLiteral::StringPattern(Rc::new(s))) } /
sign:("-"?) num:(float_literal() / nat_literal()) { sign:("-"?) num:(float_literal() / nat_literal()) {
let neg = sign.is_some(); let neg = sign.is_some();
Pattern::Literal(PatternLiteral::NumPattern { neg, num }) Pattern::Literal(PatternLiteral::NumPattern { neg, num })
@ -447,19 +447,18 @@ peg::parser! {
} }
rule string_literal() -> ExpressionKind = rule string_literal() -> ExpressionKind =
prefix:identifier()? s:bare_string_literal(){ ExpressionKind::StringLiteral{ s: Rc::new(s.to_string()), prefix:identifier()? s:bare_string_literal(){ ExpressionKind::StringLiteral{ s: Rc::new(s),
prefix: prefix.map(rc_string) prefix: prefix.map(rc_string)
} } } }
rule bare_string_literal() -> &'input str = rule bare_string_literal() -> String =
"\"" s:$(string_component()*) "\"" { s } "\"" chars:string_component()* "\"" { chars.into_iter().collect::<String>() }
rule string_component() -> &'input str = rule string_component() -> char =
r#"\\"# { "\\" } / !(r#"""# / r#"\"#) ch:$([_]) { ch.chars().next().unwrap() } /
r#"\""# { "\"" } / r#"\u{"# value:$(['0'..='9' | 'a'..='f' | 'A'..='F']+) "}" { char::from_u32(u32::from_str_radix(value, 16).unwrap()).unwrap() } /
r#"\t"# { "\t" } / r#"\n"# { '\n' } / r#"\t"# { '\t' } / r#"\""# { '"' } / r#"\\"# { '\\' } /
r#"\n"# { "\n" } / expected!("Valid escape sequence")
ch:$([^ '"' ]) { ch }
rule bool_literal() -> ExpressionKind = rule bool_literal() -> ExpressionKind =
"true" { ExpressionKind::BoolLiteral(true) } / "false" { ExpressionKind::BoolLiteral(false) } "true" { ExpressionKind::BoolLiteral(true) } / "false" { ExpressionKind::BoolLiteral(false) }

View File

@ -189,8 +189,8 @@ fn string_literals() {
r#"b"some bytestring""#, r#"b"some bytestring""#,
expr(StringLiteral { s: rc("some bytestring"), prefix: Some(rc("b")) }) expr(StringLiteral { s: rc("some bytestring"), prefix: Some(rc("b")) })
); );
//NOTE I'm not 100% sure this case is correct, but I'll deal with it later assert_expr!(r#""Do \n \" escapes work\t""#, expr(strlit("Do \n \" escapes work\t")));
//assert_expr!(r#""Do \n \" escapes work\t""#, expr(StringLiteral(rc("Do \n \" escapes work\t")))); assert_expr!(r#""Georgian letter jani \u{10ef}""#, expr(strlit("Georgian letter jani ჯ")));
} }
#[test] #[test]