From a52b17930e357e96a0b5d91ccf2f629f3b1d5b6f Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 6 Jan 2024 05:00:36 -0500 Subject: [PATCH] Implement basic formatting --- src/abstract_tree/assignment.rs | 46 ++++++++++++++++--- src/abstract_tree/block.rs | 21 ++++++++- src/abstract_tree/built_in_value.rs | 12 ++++- src/abstract_tree/expression.rs | 16 +++++++ src/abstract_tree/for.rs | 21 +++++++++ src/abstract_tree/function_call.rs | 20 +++++++++ src/abstract_tree/function_expression.rs | 14 ++++++ src/abstract_tree/identifier.rs | 8 ++++ src/abstract_tree/if_else.rs | 26 +++++++++++ src/abstract_tree/index.rs | 20 +++++++++ src/abstract_tree/index_assignment.rs | 26 +++++++---- src/abstract_tree/index_expression.rs | 13 ++++++ src/abstract_tree/logic.rs | 35 +++++++++++++-- src/abstract_tree/match.rs | 24 ++++++++++ src/abstract_tree/math.rs | 26 +++++++++++ src/abstract_tree/mod.rs | 12 +++++ src/abstract_tree/statement.rs | 18 ++++++++ src/abstract_tree/value_node.rs | 57 +++++++++++++++++++++++- src/abstract_tree/while.rs | 10 +++++ src/abstract_tree/yield.rs | 8 ++++ src/interpret.rs | 8 ++++ src/main.rs | 20 ++++++--- 22 files changed, 434 insertions(+), 27 deletions(-) diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 50b092f..07e9863 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use crate::{ @@ -14,13 +16,6 @@ pub struct Assignment { syntax_position: SyntaxPosition, } -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] -pub enum AssignmentOperator { - Equal, - PlusEqual, - MinusEqual, -} - impl AbstractTree for Assignment { fn from_syntax_node(source: &str, syntax_node: SyntaxNode, context: &Map) -> Result { Error::expect_syntax_node(source, "assignment", syntax_node)?; @@ -163,3 +158,40 @@ impl AbstractTree for Assignment { Ok(Type::None) } } + +impl Display for Assignment { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Assignment { + identifier, + type_definition, + operator, + statement, + syntax_position: _, + } = self; + + write!(f, "{identifier}")?; + + if let Some(type_definition) = type_definition { + write!(f, " {type_definition}")?; + } + + write!(f, " {operator} {statement}") + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] +pub enum AssignmentOperator { + Equal, + PlusEqual, + MinusEqual, +} + +impl Display for AssignmentOperator { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + AssignmentOperator::Equal => write!(f, "="), + AssignmentOperator::PlusEqual => write!(f, "-="), + AssignmentOperator::MinusEqual => write!(f, "+="), + } + } +} diff --git a/src/abstract_tree/block.rs b/src/abstract_tree/block.rs index 18cb183..44d9b01 100644 --- a/src/abstract_tree/block.rs +++ b/src/abstract_tree/block.rs @@ -1,4 +1,7 @@ -use std::sync::RwLock; +use std::{ + fmt::{self, Display, Formatter}, + sync::RwLock, +}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -127,3 +130,19 @@ impl AbstractTree for Block { } } } + +impl Display for Block { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.is_async { + write!(f, "async {{")?; + } else { + write!(f, "{{")?; + } + + for statement in &self.statements { + write!(f, " {statement}")?; + } + + write!(f, "}}") + } +} diff --git a/src/abstract_tree/built_in_value.rs b/src/abstract_tree/built_in_value.rs index 6f9232e..164c0a9 100644 --- a/src/abstract_tree/built_in_value.rs +++ b/src/abstract_tree/built_in_value.rs @@ -1,4 +1,8 @@ -use std::{env::args, sync::OnceLock}; +use std::{ + env::args, + fmt::{self, Display, Formatter}, + sync::OnceLock, +}; use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -148,3 +152,9 @@ impl AbstractTree for BuiltInValue { Ok(self.r#type()) } } + +impl Display for BuiltInValue { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.get()) + } +} diff --git a/src/abstract_tree/expression.rs b/src/abstract_tree/expression.rs index 44b889b..8b4f11f 100644 --- a/src/abstract_tree/expression.rs +++ b/src/abstract_tree/expression.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -101,3 +103,17 @@ impl AbstractTree for Expression { } } } + +impl Display for Expression { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Expression::Value(value_node) => write!(f, "{value_node}"), + Expression::Identifier(identifier) => write!(f, "{identifier}"), + Expression::Math(math) => write!(f, "{math}"), + Expression::Logic(logic) => write!(f, "{logic}"), + Expression::FunctionCall(function_call) => write!(f, "{function_call}"), + Expression::Index(index) => write!(f, "{index}"), + Expression::Yield(r#yield) => write!(f, "{}", r#yield), + } + } +} diff --git a/src/abstract_tree/for.rs b/src/abstract_tree/for.rs index 144c47e..a183620 100644 --- a/src/abstract_tree/for.rs +++ b/src/abstract_tree/for.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use rayon::prelude::*; use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -78,3 +80,22 @@ impl AbstractTree for For { Ok(Type::None) } } + +impl Display for For { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let For { + is_async, + item_id, + collection, + block, + } = self; + + if *is_async { + write!(f, "async for ")?; + } else { + write!(f, "for ")?; + } + + write!(f, "{item_id} in {collection}, {{{block}}}") + } +} diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index 9071401..8a36e09 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -159,3 +161,21 @@ impl AbstractTree for FunctionCall { } } } + +impl Display for FunctionCall { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let FunctionCall { + function_expression, + arguments, + .. + } = self; + + write!(f, "{function_expression}(")?; + + for expression in arguments { + write!(f, "{expression}")?; + } + + write!(f, ")") + } +} diff --git a/src/abstract_tree/function_expression.rs b/src/abstract_tree/function_expression.rs index 85e7868..d4795ce 100644 --- a/src/abstract_tree/function_expression.rs +++ b/src/abstract_tree/function_expression.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -74,3 +76,15 @@ impl AbstractTree for FunctionExpression { } } } + +impl Display for FunctionExpression { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + FunctionExpression::Value(value_node) => write!(f, "{value_node}"), + FunctionExpression::Identifier(identifier) => write!(f, "{identifier}"), + FunctionExpression::FunctionCall(function_call) => write!(f, "{function_call}"), + FunctionExpression::Index(index) => write!(f, "{index}"), + FunctionExpression::Yield(r#yield) => write!(f, "{}", r#yield), + } + } +} diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index ceaabbd..377c2e8 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -53,3 +55,9 @@ impl AbstractTree for Identifier { } } } + +impl Display for Identifier { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index 1baf0ec..e879b41 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -85,3 +87,27 @@ impl AbstractTree for IfElse { self.if_block.expected_type(context) } } + +impl Display for IfElse { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let IfElse { + if_expression, + if_block, + else_if_expressions, + else_if_blocks, + else_block, + } = self; + + write!(f, "if {if_expression} {{{if_block}}}")?; + + for (expression, block) in else_if_expressions.iter().zip(else_if_blocks.iter()) { + write!(f, "else if {expression} {{{block}}}")?; + } + + if let Some(block) = else_block { + write!(f, "else {{{block}}}")?; + } + + Ok(()) + } +} diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index 32def88..10fcb35 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -98,3 +100,21 @@ impl AbstractTree for Index { } } } + +impl Display for Index { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Index { + collection, + index, + index_end, + } = self; + + write!(f, "{collection}:{index}")?; + + if let Some(expression) = index_end { + write!(f, "..{expression}")?; + } + + Ok(()) + } +} diff --git a/src/abstract_tree/index_assignment.rs b/src/abstract_tree/index_assignment.rs index 8689778..30b0224 100644 --- a/src/abstract_tree/index_assignment.rs +++ b/src/abstract_tree/index_assignment.rs @@ -1,7 +1,12 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; -use crate::{AbstractTree, Error, Index, IndexExpression, Map, Result, Statement, Type, Value}; +use crate::{ + AbstractTree, AssignmentOperator, Error, Index, IndexExpression, Map, Result, Statement, Type, + Value, +}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct IndexAssignment { @@ -10,13 +15,6 @@ pub struct IndexAssignment { statement: Statement, } -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] -pub enum AssignmentOperator { - Equal, - PlusEqual, - MinusEqual, -} - impl AbstractTree for IndexAssignment { fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result { Error::expect_syntax_node(source, "index_assignment", node)?; @@ -95,3 +93,15 @@ impl AbstractTree for IndexAssignment { Ok(Type::None) } } + +impl Display for IndexAssignment { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let IndexAssignment { + index, + operator, + statement, + } = self; + + write!(f, "{index} {operator} {statement}") + } +} diff --git a/src/abstract_tree/index_expression.rs b/src/abstract_tree/index_expression.rs index 84ccd50..c1aec2c 100644 --- a/src/abstract_tree/index_expression.rs +++ b/src/abstract_tree/index_expression.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use crate::{ @@ -66,3 +68,14 @@ impl AbstractTree for IndexExpression { } } } + +impl Display for IndexExpression { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + IndexExpression::Value(value_node) => write!(f, "{value_node}"), + IndexExpression::Identifier(identifier) => write!(f, "{identifier}"), + IndexExpression::FunctionCall(function_call) => write!(f, "{function_call}"), + IndexExpression::Index(index) => write!(f, "{index}"), + } + } +} diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index aab8ddb..fb301b8 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -40,7 +42,7 @@ impl AbstractTree for Logic { ">" => LogicOperator::Greater, "<" => LogicOperator::Less, ">=" => LogicOperator::GreaterOrEqual, - "<=" => LogicOperator::LessOrEqaul, + "<=" => LogicOperator::LessOrEqual, _ => { return Err(Error::UnexpectedSyntaxNode { expected: "==, !=, &&, ||, >, <, >= or <=".to_string(), @@ -82,7 +84,7 @@ impl AbstractTree for Logic { LogicOperator::Greater => left > right, LogicOperator::Less => left < right, LogicOperator::GreaterOrEqual => left >= right, - LogicOperator::LessOrEqaul => left <= right, + LogicOperator::LessOrEqual => left <= right, }; Ok(Value::Boolean(result)) @@ -93,6 +95,18 @@ impl AbstractTree for Logic { } } +impl Display for Logic { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Logic { + left, + operator, + right, + } = self; + + write!(f, "{left} {operator} {right}") + } +} + #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub enum LogicOperator { Equal, @@ -102,5 +116,20 @@ pub enum LogicOperator { Greater, Less, GreaterOrEqual, - LessOrEqaul, + LessOrEqual, +} + +impl Display for LogicOperator { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + LogicOperator::Equal => write!(f, "="), + LogicOperator::NotEqual => write!(f, "!="), + LogicOperator::And => write!(f, "&&"), + LogicOperator::Or => write!(f, "||"), + LogicOperator::Greater => write!(f, ">"), + LogicOperator::Less => write!(f, "<"), + LogicOperator::GreaterOrEqual => write!(f, ">="), + LogicOperator::LessOrEqual => write!(f, "<="), + } + } } diff --git a/src/abstract_tree/match.rs b/src/abstract_tree/match.rs index f0f436d..34cf543 100644 --- a/src/abstract_tree/match.rs +++ b/src/abstract_tree/match.rs @@ -3,6 +3,8 @@ //! Note that this module is called "match" but is escaped as "r#match" because //! "match" is a keyword in Rust. +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -82,3 +84,25 @@ impl AbstractTree for Match { first_statement.expected_type(context) } } + +impl Display for Match { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Match { + matcher, + options, + fallback, + } = self; + + write!(f, "match {matcher} {{")?; + + for (expression, statement) in options { + write!(f, "{expression} => {statement}")?; + } + + if let Some(statement) = fallback { + write!(f, "* => {statement}")?; + } + + write!(f, "}}") + } +} diff --git a/src/abstract_tree/math.rs b/src/abstract_tree/math.rs index 29c082f..308e86c 100644 --- a/src/abstract_tree/math.rs +++ b/src/abstract_tree/math.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -67,6 +69,18 @@ impl AbstractTree for Math { } } +impl Display for Math { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Math { + left, + operator, + right, + } = self; + + write!(f, "{left} {operator} {right}") + } +} + #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub enum MathOperator { Add, @@ -75,3 +89,15 @@ pub enum MathOperator { Divide, Modulo, } + +impl Display for MathOperator { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + MathOperator::Add => write!(f, "+"), + MathOperator::Subtract => write!(f, "-"), + MathOperator::Multiply => write!(f, "*"), + MathOperator::Divide => write!(f, "\\"), + MathOperator::Modulo => write!(f, "%"), + } + } +} diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index caf662a..79427ca 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -35,6 +35,8 @@ pub use { r#match::*, r#while::*, r#yield::*, statement::*, type_definition::*, value_node::*, }; +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -116,6 +118,16 @@ impl AbstractTree for Root { } } +impl Display for Root { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + for statement in &self.statements { + write!(f, "{statement}")?; + } + + Ok(()) + } +} + /// This trait is implemented by the Evaluator's internal types to form an /// executable tree that resolves to a single value. pub trait AbstractTree: Sized { diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index ba7555d..1c3fc4d 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -110,3 +112,19 @@ impl AbstractTree for Statement { } } } + +impl Display for Statement { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Statement::Assignment(assignment) => write!(f, "{assignment}"), + Statement::Expression(expression) => write!(f, "{expression}"), + Statement::IfElse(if_else) => write!(f, "{if_else}"), + Statement::Match(r#match) => write!(f, "{}", r#match), + Statement::While(r#while) => write!(f, "{}", r#while), + Statement::Block(block) => write!(f, "{block}"), + Statement::For(r#for) => write!(f, "{}", r#for), + Statement::IndexAssignment(index_assignment) => write!(f, "{index_assignment}"), + Statement::Return(statement) => write!(f, "{statement}"), + } + } +} diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 4766c88..a00109f 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -1,4 +1,7 @@ -use std::collections::BTreeMap; +use std::{ + collections::BTreeMap, + fmt::{self, Display, Formatter}, +}; use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -296,3 +299,55 @@ impl AbstractTree for ValueNode { Ok(r#type) } } + +impl Display for ValueNode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + ValueNode::Boolean(source) + | ValueNode::Float(source) + | ValueNode::Integer(source) + | ValueNode::String(source) => write!(f, "{source}"), + ValueNode::Function(function) => write!(f, "{function}"), + ValueNode::List(expressions) => { + for expression in expressions { + write!(f, "{expression}")?; + } + + Ok(()) + } + ValueNode::Option(option) => { + if let Some(expression) = option { + write!(f, "some({})", expression) + } else { + write!(f, "none") + } + } + ValueNode::Map(nodes) => { + writeln!(f, "{{")?; + + for (key, (statement, type_option)) in nodes { + if let Some(r#type) = type_option { + writeln!(f, " {key} <{}> = {statement}", r#type)?; + } else { + writeln!(f, " {key} = {statement}")?; + } + } + write!(f, "}}") + } + ValueNode::BuiltInValue(built_in_value) => write!(f, "{built_in_value}"), + ValueNode::Structure(nodes) => { + writeln!(f, "{{")?; + + for (key, (value_option, r#type)) in nodes { + if let Some(value) = value_option { + writeln!(f, " {key} <{}> = {value}", r#type)?; + } else { + writeln!(f, " {key} <{}>", r#type)?; + } + } + + write!(f, "}}") + } + } + } +} diff --git a/src/abstract_tree/while.rs b/src/abstract_tree/while.rs index 9828b50..2051177 100644 --- a/src/abstract_tree/while.rs +++ b/src/abstract_tree/while.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -37,3 +39,11 @@ impl AbstractTree for While { self.block.expected_type(context) } } + +impl Display for While { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let While { expression, block } = self; + + write!(f, "while {expression} {{{block}}}") + } +} diff --git a/src/abstract_tree/yield.rs b/src/abstract_tree/yield.rs index 3ae6a92..f2606c6 100644 --- a/src/abstract_tree/yield.rs +++ b/src/abstract_tree/yield.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use serde::{Deserialize, Serialize}; use tree_sitter::Node; @@ -52,3 +54,9 @@ impl AbstractTree for Yield { self.call.expected_type(context) } } + +impl Display for Yield { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.call) + } +} diff --git a/src/interpret.rs b/src/interpret.rs index 70724bf..daa802b 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -129,6 +129,14 @@ impl Interpreter { Err(Error::ParserCancelled) } } + + pub fn format(&self) -> String { + if let Some(root_node) = &self.abstract_tree { + root_node.to_string() + } else { + "".to_string() + } + } } impl Default for Interpreter { diff --git a/src/main.rs b/src/main.rs index 4146fd0..785631f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ //! Command line interface for the dust programming language. -use clap::Parser; +use clap::{Parser, Subcommand}; use rustyline::{ completion::FilenameCompleter, error::ReadlineError, @@ -8,11 +8,10 @@ use rustyline::{ history::DefaultHistory, Completer, Context, Editor, Helper, Validator, }; -use tree_sitter::Parser as TSParser; use std::{borrow::Cow, fs::read_to_string}; -use dust_lang::{language, Interpreter, Map, Value}; +use dust_lang::{Interpreter, Map, Value}; /// Command-line arguments to be parsed. #[derive(Parser, Debug)] @@ -34,10 +33,18 @@ struct Args { #[arg(short = 't', long = "tree")] show_syntax_tree: bool, + #[command(subcommand)] + cli_command: Option, + /// Location of the file to run. path: Option, } +#[derive(Subcommand, Debug)] +pub enum CliCommand { + Format, +} + fn main() { let args = Args::parse(); @@ -69,9 +76,6 @@ fn main() { .unwrap(); } - let mut parser = TSParser::new(); - parser.set_language(language()).unwrap(); - let mut interpreter = Interpreter::new(context); if args.show_syntax_tree { @@ -90,6 +94,10 @@ fn main() { } Err(error) => eprintln!("{error}"), } + + if let Some(CliCommand::Format) = args.cli_command { + println!("{}", interpreter.format()); + } } #[derive(Helper, Completer, Validator)]