diff --git a/schala-lang/src/parsing/combinator.rs b/schala-lang/src/parsing/combinator.rs index 253d0c9..e19abb7 100644 --- a/schala-lang/src/parsing/combinator.rs +++ b/schala-lang/src/parsing/combinator.rs @@ -2,9 +2,9 @@ use std::{cell::RefCell, rc::Rc}; use nom::{ branch::alt, - bytes::complete::{tag, take_till}, + bytes::complete::{tag, escaped_transform, take_till}, character::complete::{ - alpha1, alphanumeric0, char, line_ending, multispace0, none_of, not_line_ending, one_of, space0, + alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space0, space1, }, combinator::{map, not, opt, peek, recognize, value}, @@ -177,9 +177,36 @@ fn extended_expr(input: Span) -> ParseResult { } fn primary_expr(input: Span) -> ParseResult { - context("primary-expr", alt((float_literal, number_literal, bool_literal, identifier_expr)))(input) + context("primary-expr", alt(( + string_literal, float_literal, number_literal, bool_literal, identifier_expr)) + )(input) } +//TODO need to do something with prefix in the AST +fn string_literal(input: Span) -> ParseResult { + tok( + map(pair(opt(identifier), bare_string_literal), + |(_maybe_prefix, s)| ExpressionKind::StringLiteral(Rc::new(s))) + )(input) +} + +fn bare_string_literal(input: Span) -> ParseResult { + let string_escape_transforms = alt(( + value("\\", tag("\\")), + value("\"", tag("\"")), + value("\n", tag("n")), + value("\t", tag("t")), + )); + alt((map(tag(r#""""#), |_| String::new()), + map( + tuple(( + char('"'), + escaped_transform(none_of(r#""\"#), '\\', string_escape_transforms), + char('"'), + )), |(_, s, _)| s)))(input) +} + + fn identifier_expr(input: Span) -> ParseResult { context("identifier-expr", map(qualified_identifier, ExpressionKind::Value))(input) } @@ -330,6 +357,8 @@ mod test { fn combinator_test1() { assert_eq!(span!(digits(digit_group_dec), "342"), Ok(("", vec!['3', '4', '2']))); assert_eq!(span!(bin_literal, "0b1111qsdf"), Ok(("qsdf", 15))); + assert_eq!(span!(bare_string_literal, r#""fah""#), Ok(("", "fah".to_string()))); + assert_eq!(span!(bare_string_literal, r#""""#), Ok(("", "".to_string()))); } #[test] diff --git a/schala-lang/src/parsing/test.rs b/schala-lang/src/parsing/test.rs index 5d541ee..6808217 100644 --- a/schala-lang/src/parsing/test.rs +++ b/schala-lang/src/parsing/test.rs @@ -157,11 +157,11 @@ fn basic_literals() { fn string_literals() { use ExpressionKind::*; - assert_expr!(r#""""#, expr(StringLiteral(rc("")))); - assert_expr!(r#""hello""#, expr(StringLiteral(rc("hello")))); - assert_expr!(r#"b"some bytestring""#, expr(StringLiteral(rc("some bytestring")))); + assert_expr_comb!(r#""""#, expr(StringLiteral(rc("")))); + assert_expr_comb!(r#""hello""#, expr(StringLiteral(rc("hello")))); + assert_expr_comb!(r#"b"some bytestring""#, expr(StringLiteral(rc("some bytestring")))); //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(StringLiteral(rc(r#"Do \n \" escapes work\t"#)))); + assert_expr_comb!(r#""Do \n \" escapes work\t""#, expr(StringLiteral(rc("Do \n \" escapes work\t")))); } #[test]