From 78e7271950d0d62bf3023b70c64781bf93c5a182 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sat, 17 May 2025 08:36:55 -0500 Subject: [PATCH] Add DString building. --- sketching/may_2025/name_one.dm | 4 +++ src/ast/build.rs | 51 ++++++++++++++++++++++++++++++++-- src/ast/mod.rs | 41 +++++++++++++++++++++++++++ src/ast/pretty_print.rs | 23 +++++++++++++++ src/ast/unparse.rs | 25 +++++++++++++++++ src/parser/deimos.pest | 9 +++--- 6 files changed, 146 insertions(+), 7 deletions(-) diff --git a/sketching/may_2025/name_one.dm b/sketching/may_2025/name_one.dm index 67ad445..30b8469 100644 --- a/sketching/may_2025/name_one.dm +++ b/sketching/may_2025/name_one.dm @@ -10,4 +10,8 @@ fn main(x: String) { let z = 'z'; let test = 'oops.'; }; +} + +pub mod test { + } \ No newline at end of file diff --git a/src/ast/build.rs b/src/ast/build.rs index 569f4a8..2e947ae 100644 --- a/src/ast/build.rs +++ b/src/ast/build.rs @@ -1276,7 +1276,31 @@ fn build_single_quote_string(file_id: usize, pair: Pair) -> Literal { } fn build_double_quote_string(file_id: usize, pair: Pair) -> Literal { - todo!() + let mut parts: Vec = vec![]; + let inner = pair.into_inner(); + for inner_pair in inner { + match inner_pair.as_rule() { + Rule::DStringInner => { + parts.push(DStringPart::from_string(inner_pair.as_span().as_str())); + } + Rule::DStringExpression => { + let expression_pair = inner_pair.into_inner().next().unwrap(); + parts.push(DStringPart::from_expression(expect_and_use( + file_id, + expression_pair, + Rule::Expression, + build_expression, + ))); + } + _ => unreachable!(), + } + } + + if parts.len() == 1 && parts[0].is_string() { + Literal::String(parts.pop().unwrap().unwrap_string()) + } else { + Literal::DString(DString(parts)) + } } fn build_backtick_string(file_id: usize, pair: Pair) -> Literal { @@ -1290,12 +1314,13 @@ mod tests { use crate::parser::DeimosParser; use indoc::indoc; - fn assert_builds(src: &str) -> CompilationUnit { + fn assert_builds(src: &str) { let parse_result = DeimosParser::parse(Rule::CompilationUnit, src); if let Err(e) = parse_result { panic!("Parsing failed.\n{}", e) } else { - build_ast(0, parse_result.unwrap().next().unwrap()) + let ast = build_ast(0, parse_result.unwrap().next().unwrap()); + dbg!(ast); } } @@ -1331,4 +1356,24 @@ mod tests { fn double_literal() { assert_builds("fn main() { 1.0 }"); } + + #[test] + fn d_string_no_expressions() { + assert_builds("fn main() { \"Hello, World!\" }"); + } + + #[test] + fn d_string_one_expression() { + assert_builds("fn main() { \"${foo}\" }"); + } + + #[test] + fn d_string_literal_and_expression() { + assert_builds("fn main() { \"Hello, ${foo}!\" }"); + } + + #[test] + fn d_string_literal_expression_literal() { + assert_builds("fn main() { \"Hello, ${foo}! It is a nice day.\" }"); + } } diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 8561e90..944e1f8 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -599,5 +599,46 @@ pub enum Literal { Double(f64), USize(usize), String(String), + DString(DString), Boolean(bool), } + +#[derive(Debug)] +pub struct DString(pub Vec); + +#[derive(Debug)] +pub enum DStringPart { + String(String), + Expression(Box), +} + +impl DStringPart { + pub fn from_string(s: &str) -> DStringPart { + DStringPart::String(String::from(s)) + } + + pub fn from_expression(e: Expression) -> DStringPart { + DStringPart::Expression(Box::new(e)) + } + + pub fn is_string(&self) -> bool { + match self { + DStringPart::String(_) => true, + _ => false, + } + } + + pub fn unwrap_string(self) -> String { + match self { + DStringPart::String(s) => s, + _ => panic!(), + } + } + + pub fn is_expression(&self) -> bool { + match self { + DStringPart::Expression(_) => true, + _ => false, + } + } +} diff --git a/src/ast/pretty_print.rs b/src/ast/pretty_print.rs index 559103e..8a721ed 100644 --- a/src/ast/pretty_print.rs +++ b/src/ast/pretty_print.rs @@ -877,7 +877,30 @@ impl PrettyPrint for Literal { Double(d) => writer.writeln_indented(&format!("Double({})", d)), USize(u) => writer.writeln_indented(&format!("USize({})", u)), String(s) => writer.writeln_indented(&format!("String({})", s)), + DString(d_string) => d_string.pretty_print(writer), Boolean(b) => writer.writeln_indented(&format!("Boolean({})", b)), } } } + +impl PrettyPrint for DString { + fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.writeln_indented("DString")?; + writer.increase_indent(); + for part in &self.0 { + part.pretty_print(writer)?; + } + Ok(()) + } +} + +impl PrettyPrint for DStringPart { + fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.writeln_indented("DStringPart")?; + writer.increase_indent(); + match self { + DStringPart::String(s) => writer.writeln_indented(&format!("String({})", s)), + DStringPart::Expression(e) => e.pretty_print(writer), + } + } +} diff --git a/src/ast/unparse.rs b/src/ast/unparse.rs index e3306cd..a62cd35 100644 --- a/src/ast/unparse.rs +++ b/src/ast/unparse.rs @@ -1042,7 +1042,32 @@ impl Unparse for Literal { Double(d) => writer.write(&format!("{}", d)), USize(u) => writer.write(&format!("{}", u)), String(s) => writer.write(&format!("\"{}\"", s)), + DString(d_string) => d_string.unparse(writer), Boolean(b) => writer.write(&format!("{}", b)), } } } + +impl Unparse for DString { + fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.write("\"")?; + for part in &self.0 { + part.unparse(writer)?; + } + writer.write("\"")?; + Ok(()) + } +} + +impl Unparse for DStringPart { + fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + match self { + DStringPart::String(s) => writer.write(s), + DStringPart::Expression(e) => { + writer.write("${")?; + e.unparse(writer)?; + writer.write("}") + } + } + } +} diff --git a/src/parser/deimos.pest b/src/parser/deimos.pest index cc08a00..c48f750 100644 --- a/src/parser/deimos.pest +++ b/src/parser/deimos.pest @@ -795,14 +795,15 @@ StringChar = { DStringInner = @{ DStringChar+ } DStringChar = { - !( "\"" | "\\" ) ~ ANY + !( "\"" | "\\" | "${" ) ~ ANY | "\\" ~ ( "\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t" | "$" ) | "\\" ~ ( "u" ~ ASCII_HEX_DIGIT{4} ) } DStringExpression = { - "$" - ~ BlockStatement + "${" + ~ Expression + ~ "}" } BacktickString = { @@ -815,7 +816,7 @@ BacktickString = { BacktickInner = @{ BacktickStringChar+ } BacktickStringChar = { - !( "\\`" | "\\" ) ~ ANY + !( "\\`" | "\\" | "${" ) ~ ANY | "\\" ~ ( "`" | "\\" | "/" | "b" | "f" | "n" | "r" | "t" | "$" ) | "\\" ~ ( "u" ~ ASCII_HEX_DIGIT{4} ) }