From 35d616a538f69f1ba6264209a4ebc289e045f25c Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sat, 17 May 2025 10:32:14 -0500 Subject: [PATCH] Implement closure in ast building, unparsing, and pretty printing. --- sketching/may_2025/closure.dm | 8 +++ src/ast/build.rs | 93 ++++++++++++++++++++++++++++++++- src/ast/mod.rs | 46 ++++++++++++++++- src/ast/pretty_print.rs | 80 ++++++++++++++++++++++++++++- src/ast/unparse.rs | 97 +++++++++++++++++++++++++++++++++-- src/parser/deimos.pest | 6 +-- 6 files changed, 320 insertions(+), 10 deletions(-) create mode 100644 sketching/may_2025/closure.dm diff --git a/sketching/may_2025/closure.dm b/sketching/may_2025/closure.dm new file mode 100644 index 0000000..d729423 --- /dev/null +++ b/sketching/may_2025/closure.dm @@ -0,0 +1,8 @@ +fn main() { + let x = 42; + let cl = mut |&mut x| { i -> + let result = x + i; + x = x + 1; + result + }; +} \ No newline at end of file diff --git a/src/ast/build.rs b/src/ast/build.rs index 35aff88..a5830bd 100644 --- a/src/ast/build.rs +++ b/src/ast/build.rs @@ -1214,7 +1214,98 @@ fn build_object_index(file_id: usize, inner_pair: Pair) -> ObjectNavigatio } fn build_closure(file_id: usize, closure_pair: Pair) -> Closure { - todo!() + let mut modifier = None; + let mut is_move = false; + let mut captures = ClosureCaptures::default(); + let mut parameters = ClosureParameters::default(); + let mut statements = vec![]; + let mut expression = None; + + for inner_pair in closure_pair.into_inner() { + match inner_pair.as_rule() { + Rule::Cons => { + modifier = Some(ClosureModifier::Cons) + }, + Rule::Mut => { + modifier = Some(ClosureModifier::Mut) + }, + Rule::ClosureCaptures => { + captures = build_closure_captures(file_id, inner_pair); + }, + Rule::ClosureParameters => { + parameters = build_closure_parameters(file_id, inner_pair); + }, + Rule::Statement => { + statements.push(build_statement(file_id, inner_pair)); + }, + Rule::Expression => { + expression = Some(Box::new(build_expression(file_id, inner_pair))); + } + _ => unreachable!(), + } + } + + Closure { + modifier, + is_move, + captures, + parameters, + statements, + expression, + } +} + +fn build_closure_captures(file_id: usize, captures_pair: Pair) -> ClosureCaptures { + ClosureCaptures(captures_pair.into_inner().map(|capture_pair| { + expect_and_use(file_id, capture_pair, Rule::ClosureCapture, build_closure_capture) + }).collect()) +} + +fn build_closure_capture(file_id: usize, capture_pair: Pair) -> ClosureCapture { + let mut borrow_count = 0; + let mut is_mutable = false; + let mut identifier = None; + + for inner_pair in capture_pair.into_inner() { + match inner_pair.as_rule() { + Rule::Borrow => { + borrow_count += 1; + }, + Rule::Mut => { + is_mutable = true; + }, + Rule::Identifier => { + identifier = Some(Box::new(build_identifier(file_id, inner_pair))); + } + _ => unreachable!(), + } + } + + ClosureCapture { + borrow_count, + is_mutable, + identifier: identifier.unwrap() + } +} + +fn build_closure_parameters(file_id: usize, parameters_pair: Pair) -> ClosureParameters { + ClosureParameters(parameters_pair.into_inner().map(|parameter_pair| { + expect_and_use(file_id, parameter_pair, Rule::ClosureParameter, build_closure_parameter) + }).collect()) +} + +fn build_closure_parameter(file_id: usize, parameter_pair: Pair) -> ClosureParameter { + let mut inner = parameter_pair.into_inner(); + let identifier = expect_and_use(file_id, inner.next().unwrap(), Rule::Identifier, build_identifier); + let type_use = if let Some(type_use_pair) = inner.next() { + Some(expect_and_use(file_id, type_use_pair, Rule::TypeUse, build_type_use)) + } else { + None + }; + ClosureParameter { + identifier, + type_use + } } fn build_literal(file_id: usize, literal_pair: Pair) -> Literal { diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 100e7c2..b9b1a52 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -575,7 +575,51 @@ pub struct CallArguments(pub Vec); pub struct CallArgument(pub Box); #[derive(Debug)] -pub struct Closure {} +pub struct Closure { + pub modifier: Option, + pub is_move: bool, + pub captures: ClosureCaptures, + pub parameters: ClosureParameters, + pub statements: Vec, + pub expression: Option>, +} + +#[derive(Debug)] +pub enum ClosureModifier { + Cons, + Mut +} + +#[derive(Debug, Default)] +pub struct ClosureCaptures(pub Vec); + +impl ClosureCaptures { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +#[derive(Debug)] +pub struct ClosureCapture { + pub borrow_count: usize, + pub is_mutable: bool, + pub identifier: Box, +} + +#[derive(Debug, Default)] +pub struct ClosureParameters(pub Vec); + +impl ClosureParameters { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +#[derive(Debug)] +pub struct ClosureParameter { + pub identifier: Identifier, + pub type_use: Option, +} #[derive(Debug)] pub struct ObjectAccess { diff --git a/src/ast/pretty_print.rs b/src/ast/pretty_print.rs index fbd565e..616b7a2 100644 --- a/src/ast/pretty_print.rs +++ b/src/ast/pretty_print.rs @@ -820,7 +820,85 @@ impl PrettyPrint for CallArgument { impl PrettyPrint for Closure { fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { - todo!() + writer.writeln_indented(&format!("Closure(is_move = {})", self.is_move))?; + writer.increase_indent(); + if let Some(modifier) = &self.modifier { + modifier.pretty_print(writer)?; + } + self.captures.pretty_print(writer)?; + self.parameters.pretty_print(writer)?; + if !self.statements.is_empty() { + writer.writeln_indented("ClosureStatements")?; + writer.increase_indent(); + for statement in &self.statements { + statement.pretty_print(writer)?; + } + writer.decrease_indent(); + } + if let Some(expression) = &self.expression { + expression.pretty_print(writer)?; + } + writer.decrease_indent(); + Ok(()) + } +} + +impl PrettyPrint for ClosureModifier { + fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.writeln_indented(&format!("ClosureModifier({})", match self { + ClosureModifier::Mut => "mut", + ClosureModifier::Cons => "cons" + })) + } +} + +impl PrettyPrint for ClosureCaptures { + fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.writeln_indented("ClosureCaptures")?; + writer.increase_indent(); + for capture in &self.0 { + capture.pretty_print(writer)?; + } + writer.decrease_indent(); + Ok(()) + } +} + +impl PrettyPrint for ClosureCapture { + fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.writeln_indented(&format!( + "ClosureCapture(borrow_count = {}, is_mutable = {})", + self.borrow_count, self.is_mutable + ))?; + writer.increase_indent(); + self.identifier.pretty_print(writer)?; + writer.decrease_indent(); + Ok(()) + } +} + +impl PrettyPrint for ClosureParameters { + fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.writeln_indented("ClosureParameters")?; + writer.increase_indent(); + for parameter in &self.0 { + parameter.pretty_print(writer)?; + } + writer.decrease_indent(); + Ok(()) + } +} + +impl PrettyPrint for ClosureParameter { + fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.writeln_indented("ClosureParameter")?; + writer.increase_indent(); + self.identifier.pretty_print(writer)?; + if let Some(type_use) = &self.type_use { + type_use.pretty_print(writer)?; + } + writer.decrease_indent(); + Ok(()) } } diff --git a/src/ast/unparse.rs b/src/ast/unparse.rs index d30cd2e..1b8c824 100644 --- a/src/ast/unparse.rs +++ b/src/ast/unparse.rs @@ -653,9 +653,7 @@ impl Unparse for FunctionBody { } Block(body) => { writer.writeln("{")?; - writer.increase_indent(); body.unparse_inner(writer)?; - writer.decrease_indent(); writer.writeln_indented("}") } Alias(identifier) => { @@ -994,7 +992,100 @@ impl Unparse for CallArgument { impl Unparse for Closure { fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { - writer.write("{{ -> TODO }}") + if let Some(modifier) = &self.modifier { + match modifier { + ClosureModifier::Cons => writer.write("cons "), + ClosureModifier::Mut => writer.write("mut "), + }?; + } + if self.is_move { + writer.write("move ")?; + } + if !self.captures.is_empty() { + self.captures.unparse(writer)?; + writer.write(" ")?; + } + + writer.write("{ ")?; + + if !self.parameters.is_empty() { + self.parameters.unparse(writer)?; + writer.write(" -> ")?; + } + + if !self.statements.is_empty() { + writer.write("\n")?; + writer.increase_indent(); + for statement in &self.statements { + statement.unparse(writer)?; + } + writer.decrease_indent(); + } + if let Some(expression) = &self.expression { + if self.statements.is_empty() { + expression.unparse(writer)?; + writer.write(" }")?; + } else { + writer.increase_indent(); + writer.write_indented("")?; + expression.unparse(writer)?; + writer.write("\n")?; + writer.decrease_indent(); + writer.write_indented("}")?; + } + } else if !self.statements.is_empty() { + writer.write_indented(" }")?; + } else { + writer.write(" }")?; + } + Ok(()) + } +} + +impl Unparse for ClosureCaptures { + fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + writer.write("|")?; + for (i, capture) in self.0.iter().enumerate() { + capture.unparse(writer)?; + if i != self.0.len() - 1 { + writer.write(", ")?; + } + } + writer.write("|")?; + Ok(()) + } +} + +impl Unparse for ClosureCapture { + fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + for _ in 0..self.borrow_count { + writer.write("&")?; + } + if self.is_mutable { + writer.write("mut ")?; + } + self.identifier.unparse(writer)?; + Ok(()) + } +} + +impl Unparse for ClosureParameters { + fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + for parameter in &self.0 { + parameter.unparse(writer)?; + } + Ok(()) + } +} + +impl Unparse for ClosureParameter { + fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { + self.identifier.unparse(writer)?; + if let Some(type_use) = &self.type_use { + writer.write(": ")?; + type_use.unparse(writer)?; + } + Ok(()) } } diff --git a/src/parser/deimos.pest b/src/parser/deimos.pest index c48f750..ff549dc 100644 --- a/src/parser/deimos.pest +++ b/src/parser/deimos.pest @@ -721,10 +721,8 @@ ClosureCaptures = { } ClosureCapture = { - ( - Mut - | ( Borrow ~ Mut? )* - )? + Borrow* + ~ Mut? ~ Identifier }