diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 7f30d67..cf02134 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Display}; use colored::Colorize; use serde::{Deserialize, Serialize}; -use crate::{AnnotatedError, Formatter, Identifier, Instruction, Operation, Span, Type, Value}; +use crate::{AnnotatedError, Identifier, Instruction, Operation, Span, Type, Value}; #[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)] pub struct Chunk { @@ -514,6 +514,7 @@ impl<'a> ChunkDisassembler<'a> { }; let push_function_disassembly = |function_disassembly: &str, disassembly: &mut String| { disassembly.push_str(function_disassembly); + disassembly.push('\n'); }; let mut disassembly = String::new(); let top_border = "┌".to_string() + &"─".repeat(self.width - 2) + "┐"; @@ -656,6 +657,7 @@ impl<'a> ChunkDisassembler<'a> { ); } + disassembly.pop(); // Remove the last newline character disassembly } diff --git a/dust-lang/src/formatter.rs b/dust-lang/src/formatter.rs index 3df3ce3..6c6b8c6 100644 --- a/dust-lang/src/formatter.rs +++ b/dust-lang/src/formatter.rs @@ -1,91 +1,198 @@ -use annotate_snippets::{renderer::Style, Level, Renderer, Snippet}; -use colored::{Colorize, CustomColor}; +use colored::{ColoredString, Colorize, CustomColor}; use crate::{lex, Token}; -#[derive(Debug, Copy, Clone)] +#[derive(Debug)] pub struct Formatter<'src> { source: &'src str, - origin: Option<&'src str>, - footer: Option<&'src str>, + lines: Vec<(String, LineKind, usize)>, + next_line: String, + indent: usize, } impl<'src> Formatter<'src> { pub fn new(source: &'src str) -> Self { Self { source, - origin: None, - footer: None, + lines: Vec::new(), + next_line: String::new(), + indent: 0, } } - pub fn origin(&mut self, origin: &'src str) -> &mut Self { - self.origin = Some(origin); - - self - } - pub fn footer(&mut self, footer: &'src str) -> &mut Self { self.source = footer; self } - pub fn format(&self) -> String { + pub fn format(&mut self) -> String { let tokens = match lex(self.source) { Ok(tokens) => tokens, Err(error) => return format!("{}", error), }; - let mut block_depth = 0; - let mut formatted = String::new(); - let line_break = |formatted: &mut String, block_depth: i32| { - formatted.push('\n'); - - for _ in 0..block_depth { - formatted.push_str(" "); - } - }; + let mut line_kind = LineKind::Empty; for (token, _) in tokens { + use Token::*; + match token { - Token::Boolean(boolean) => formatted.push_str(&boolean.red()), - Token::Byte(byte) => formatted.push_str(&byte.green()), - Token::Character(character) => formatted.push_str( - &character - .to_string() - .custom_color(CustomColor::new(225, 150, 150)), - ), - Token::Float(float) => formatted.push_str(&float.yellow()), - Token::Identifier(identifier) => { - formatted.push_str(&identifier.blue()); - formatted.push(' '); - } - Token::Integer(integer) => formatted.push_str(&integer.cyan()), - Token::String(string) => formatted.push_str(&string.magenta()), - Token::LeftCurlyBrace => { - block_depth += 1; + Boolean(boolean) => { + self.push_colored(boolean.red()); - formatted.push_str(token.as_str()); - line_break(&mut formatted, block_depth) + if line_kind != LineKind::Assignment { + line_kind = LineKind::Expression; + } } - Token::RightCurlyBrace => { - block_depth -= 1; + Byte(byte) => { + self.push_colored(byte.green()); - line_break(&mut formatted, block_depth); - formatted.push_str(token.as_str()); + if line_kind != LineKind::Assignment { + line_kind = LineKind::Expression; + } } - Token::Semicolon => { - formatted.push_str(token.as_str()); - line_break(&mut formatted, block_depth); + Character(character) => { + self.push_colored( + character + .to_string() + .custom_color(CustomColor::new(225, 150, 150)), + ); + + if line_kind != LineKind::Assignment { + line_kind = LineKind::Expression; + } } - Token::Eof => continue, + Float(float) => { + self.push_colored(float.yellow()); + + if line_kind != LineKind::Assignment { + line_kind = LineKind::Expression; + } + } + Identifier(identifier) => { + self.push_colored(identifier.blue()); + self.next_line.push(' '); + + if line_kind != LineKind::Assignment { + line_kind = LineKind::Expression; + } + } + Integer(integer) => { + self.push_colored(integer.cyan()); + + if line_kind != LineKind::Assignment { + line_kind = LineKind::Expression; + } + } + String(string) => { + self.push_colored(string.magenta()); + + if line_kind != LineKind::Assignment { + line_kind = LineKind::Expression; + } + } + LeftCurlyBrace => { + self.next_line.push_str(token.as_str()); + self.commit_line(LineKind::OpenBlock); + + self.indent += 1; + } + RightCurlyBrace => { + self.commit_line(LineKind::CloseBlock); + self.next_line.push_str(token.as_str()); + + self.indent -= 1; + } + Semicolon => { + if line_kind != LineKind::Assignment { + line_kind = LineKind::Statement; + } + + self.next_line.push_str(token.as_str()); + self.commit_line(line_kind); + } + Let => { + line_kind = LineKind::Assignment; + + self.push_colored(token.as_str().bold()); + self.next_line.push(' '); + } + Break | Loop | Return | While => { + line_kind = LineKind::Statement; + + self.push_colored(token.as_str().bold()); + self.next_line.push(' '); + } + Eof => continue, token => { - formatted.push_str(token.as_str()); - formatted.push(' '); + self.next_line.push_str(token.as_str()); + self.next_line.push(' '); } } } - formatted + let mut previous_index = 0; + let mut current_index = 1; + + while current_index < self.lines.len() { + let (_, previous, _) = &self.lines[previous_index]; + let (_, current, _) = &self.lines[current_index]; + + println!("{:?} {:?}", previous, current); + + match (previous, current) { + (LineKind::Empty, _) + | (_, LineKind::Empty) + | (LineKind::OpenBlock, _) + | (_, LineKind::CloseBlock) => {} + (left, right) if left == right => {} + _ => { + self.lines + .insert(current_index, ("".to_string(), LineKind::Empty, 0)); + } + } + + previous_index += 1; + current_index += 1; + } + + let formatted = String::with_capacity( + self.lines + .iter() + .fold(0, |total, (line, _, _)| total + line.len()), + ); + + self.lines + .iter() + .enumerate() + .fold(formatted, |acc, (index, (line, _, indent))| { + let left_pad = " ".repeat(*indent); + + if index == 0 { + return format!("{:<3}| {}{}", index + 1, left_pad, line); + } + format!("{}\n{:<3}| {}{}", acc, index + 1, left_pad, line) + }) + } + + fn push_colored(&mut self, colored: ColoredString) { + self.next_line.push_str(&format!("{}", colored)); + } + + fn commit_line(&mut self, line_kind: LineKind) { + self.lines + .push((self.next_line.clone(), line_kind, self.indent)); + self.next_line.clear(); } } + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum LineKind { + Assignment, + FunctionCall, + Statement, + Expression, + Empty, + OpenBlock, + CloseBlock, +}