Implement basic formatting

This commit is contained in:
Jeff 2024-01-06 05:00:36 -05:00
parent 9cee46cfe5
commit a52b17930e
22 changed files with 434 additions and 27 deletions

View File

@ -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<Self> {
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, "+="),
}
}
}

View File

@ -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, "}}")
}
}

View File

@ -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())
}
}

View File

@ -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),
}
}
}

View File

@ -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}}}")
}
}

View File

@ -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, ")")
}
}

View File

@ -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),
}
}
}

View File

@ -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)
}
}

View File

@ -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(())
}
}

View File

@ -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(())
}
}

View File

@ -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<Self> {
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}")
}
}

View File

@ -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}"),
}
}
}

View File

@ -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, "<="),
}
}
}

View File

@ -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, "}}")
}
}

View File

@ -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, "%"),
}
}
}

View File

@ -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 {

View File

@ -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}"),
}
}
}

View File

@ -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, "}}")
}
}
}
}

View File

@ -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}}}")
}
}

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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<CliCommand>,
/// Location of the file to run.
path: Option<String>,
}
#[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)]