Add while loop support and token pretty printing
The commit adds while loop statements and improves token display formatting: - Implements while loop syntax and evaluation - Adds a new token pretty printing module with configurable formatting - Improves token display with colors and different output modes
This commit is contained in:
@@ -14,6 +14,10 @@ do
|
|||||||
end
|
end
|
||||||
do
|
do
|
||||||
print "cavallo";
|
print "cavallo";
|
||||||
|
while cavallo < 10 do
|
||||||
|
print "loop: " + cavallo;
|
||||||
|
cavallo = cavallo + 1;
|
||||||
|
end
|
||||||
89
|
89
|
||||||
end
|
end
|
||||||
99
|
99
|
||||||
|
|||||||
@@ -320,6 +320,17 @@ impl<'a> EvaluateInterpreter<Stmt> for Interpreter<'a> {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Stmt::While { condition, body } => {
|
||||||
|
while self.interpret(*condition.clone())?.is_truthy() {
|
||||||
|
self.interpret(*body.clone())?;
|
||||||
|
}
|
||||||
|
Ok(LiteralValue::Nil)
|
||||||
|
}
|
||||||
|
Stmt::For {
|
||||||
|
variable,
|
||||||
|
iterable,
|
||||||
|
body,
|
||||||
|
} => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use std::fmt::{Debug, Display};
|
|||||||
* assignment_statement -> IDENTIFIER "=" expression ";"
|
* assignment_statement -> IDENTIFIER "=" expression ";"
|
||||||
* block_statement -> "do" statement* "end"
|
* block_statement -> "do" statement* "end"
|
||||||
* if_statement -> "if" expression "then" statement ("elif" expression "then" statement)* ("else" statement)? "end"
|
* if_statement -> "if" expression "then" statement ("elif" expression "then" statement)* ("else" statement)? "end"
|
||||||
|
* while_statement -> "while" expression "do" statement "end"
|
||||||
*
|
*
|
||||||
* expression -> assignment
|
* expression -> assignment
|
||||||
* assignment -> IDENTIFIER "=" assignment | logical_or
|
* assignment -> IDENTIFIER "=" assignment | logical_or
|
||||||
@@ -145,6 +146,15 @@ pub enum Stmt {
|
|||||||
elif_branch: Vec<(Box<Expr>, Box<Stmt>)>,
|
elif_branch: Vec<(Box<Expr>, Box<Stmt>)>,
|
||||||
else_branch: Option<Box<Stmt>>,
|
else_branch: Option<Box<Stmt>>,
|
||||||
},
|
},
|
||||||
|
While {
|
||||||
|
condition: Box<Expr>,
|
||||||
|
body: Box<Stmt>,
|
||||||
|
},
|
||||||
|
For {
|
||||||
|
variable: Box<Expr>,
|
||||||
|
iterable: Box<Expr>,
|
||||||
|
body: Box<Stmt>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Stmt {
|
impl Display for Stmt {
|
||||||
@@ -182,6 +192,12 @@ impl Display for Stmt {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
),
|
),
|
||||||
|
Stmt::While { condition, body } => todo!(),
|
||||||
|
Stmt::For {
|
||||||
|
variable,
|
||||||
|
iterable,
|
||||||
|
body,
|
||||||
|
} => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,6 +237,12 @@ impl Debug for Stmt {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\t\t\n")
|
.join("\t\t\n")
|
||||||
),
|
),
|
||||||
|
Stmt::While { condition, body } => todo!(),
|
||||||
|
Stmt::For {
|
||||||
|
variable,
|
||||||
|
iterable,
|
||||||
|
body,
|
||||||
|
} => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,6 +289,12 @@ impl AstNodeKind for Stmt {
|
|||||||
} => "if statement",
|
} => "if statement",
|
||||||
Stmt::Print { expression: _ } => "print statement",
|
Stmt::Print { expression: _ } => "print statement",
|
||||||
Stmt::Stmt { expression: _ } => "statement",
|
Stmt::Stmt { expression: _ } => "statement",
|
||||||
|
Stmt::While { condition, body } => todo!(),
|
||||||
|
Stmt::For {
|
||||||
|
variable,
|
||||||
|
iterable,
|
||||||
|
body,
|
||||||
|
} => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::frontend::source_registry::{SourceId, SourcePosition, SourceSlice};
|
use crate::frontend::source_registry::{SourceId, SourcePosition, SourceSlice};
|
||||||
use crate::frontend::tokens::{LiteralValue, Token, TokenType};
|
use crate::frontend::tokens::{LiteralValue, Token, TokenType};
|
||||||
|
use crate::logging::display_token::TokenPrettyPrintExt;
|
||||||
use crate::result::{LoxError, LoxResult};
|
use crate::result::{LoxError, LoxResult};
|
||||||
|
|
||||||
pub struct Lexer {
|
pub struct Lexer {
|
||||||
@@ -74,7 +75,7 @@ impl Lexer {
|
|||||||
}
|
}
|
||||||
tokens.push(self.make_token(TokenType::Eof));
|
tokens.push(self.make_token(TokenType::Eof));
|
||||||
println!("Tokens:");
|
println!("Tokens:");
|
||||||
tokens.iter().for_each(|val| println!("{}", val));
|
tokens.iter().for_each(|val| println!("{}", val.pretty()));
|
||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ impl Parser {
|
|||||||
self.if_statement()?,
|
self.if_statement()?,
|
||||||
self.peek().source_slice.clone(),
|
self.peek().source_slice.clone(),
|
||||||
)),
|
)),
|
||||||
|
(TokenType::While, _) => Ok(AstNode::new(
|
||||||
|
self.while_statement()?,
|
||||||
|
self.peek().source_slice.clone(),
|
||||||
|
)),
|
||||||
_ => Ok(AstNode::new(
|
_ => Ok(AstNode::new(
|
||||||
self.expression_statement()?,
|
self.expression_statement()?,
|
||||||
self.peek().source_slice.clone(),
|
self.peek().source_slice.clone(),
|
||||||
@@ -88,6 +92,16 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn while_statement(&mut self) -> LoxResult<Stmt> {
|
||||||
|
self.advance();
|
||||||
|
let condition = self.expression()?;
|
||||||
|
let body = self.block_statement()?;
|
||||||
|
Ok(Stmt::While {
|
||||||
|
condition: Box::new(condition),
|
||||||
|
body: Box::new(body),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn if_statement(&mut self) -> LoxResult<Stmt> {
|
fn if_statement(&mut self) -> LoxResult<Stmt> {
|
||||||
self.advance();
|
self.advance();
|
||||||
let condition = self.expression()?;
|
let condition = self.expression()?;
|
||||||
|
|||||||
@@ -265,7 +265,6 @@ impl PrettyPrint for Stmt {
|
|||||||
write!(f, "{}}}", indent)
|
write!(f, "{}}}", indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::Print { expression } => {
|
Stmt::Print { expression } => {
|
||||||
if ctx.config.compact {
|
if ctx.config.compact {
|
||||||
let expr_str =
|
let expr_str =
|
||||||
@@ -279,7 +278,6 @@ impl PrettyPrint for Stmt {
|
|||||||
write!(f, "{}}}", indent)
|
write!(f, "{}}}", indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::Var { name, initializer } => {
|
Stmt::Var { name, initializer } => {
|
||||||
if ctx.config.compact {
|
if ctx.config.compact {
|
||||||
match initializer {
|
match initializer {
|
||||||
@@ -306,7 +304,6 @@ impl PrettyPrint for Stmt {
|
|||||||
write!(f, "{}}}", indent)
|
write!(f, "{}}}", indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::Assign { name, value } => {
|
Stmt::Assign { name, value } => {
|
||||||
if ctx.config.compact {
|
if ctx.config.compact {
|
||||||
let value_str =
|
let value_str =
|
||||||
@@ -321,7 +318,6 @@ impl PrettyPrint for Stmt {
|
|||||||
write!(f, "{}}}", indent)
|
write!(f, "{}}}", indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::Return { expression } => {
|
Stmt::Return { expression } => {
|
||||||
if ctx.config.compact {
|
if ctx.config.compact {
|
||||||
let expr_str =
|
let expr_str =
|
||||||
@@ -335,7 +331,6 @@ impl PrettyPrint for Stmt {
|
|||||||
write!(f, "{}}}", indent)
|
write!(f, "{}}}", indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::Block { statements } => {
|
Stmt::Block { statements } => {
|
||||||
if ctx.config.compact {
|
if ctx.config.compact {
|
||||||
write!(f, "{{ ... ({} statements) }}", statements.len())
|
write!(f, "{{ ... ({} statements) }}", statements.len())
|
||||||
@@ -355,7 +350,6 @@ impl PrettyPrint for Stmt {
|
|||||||
write!(f, "{}}}", indent)
|
write!(f, "{}}}", indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::If {
|
Stmt::If {
|
||||||
condition,
|
condition,
|
||||||
then_branch,
|
then_branch,
|
||||||
@@ -410,8 +404,27 @@ impl PrettyPrint for Stmt {
|
|||||||
write!(f, "{}}}", indent)
|
write!(f, "{}}}", indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::Stmt { expression } => expression.pretty_print(ctx, f),
|
Stmt::Stmt { expression } => expression.pretty_print(ctx, f),
|
||||||
|
Stmt::While { condition, body } => {
|
||||||
|
write!(f, "{}while (", ctx.child_context(true).indent())?;
|
||||||
|
condition.pretty_print(&ctx.child_context(true), f)?;
|
||||||
|
writeln!(f, ") {{")?;
|
||||||
|
body.pretty_print(&ctx.child_context(true), f)?;
|
||||||
|
writeln!(f, "{}}}", ctx.child_context(true).indent())
|
||||||
|
}
|
||||||
|
Stmt::For {
|
||||||
|
variable,
|
||||||
|
iterable,
|
||||||
|
body,
|
||||||
|
} => {
|
||||||
|
write!(f, "{}for (", ctx.child_context(true).indent())?;
|
||||||
|
variable.pretty_print(&ctx.child_context(true), f)?;
|
||||||
|
write!(f, " in ")?;
|
||||||
|
iterable.pretty_print(&ctx.child_context(true), f)?;
|
||||||
|
writeln!(f, ") {{")?;
|
||||||
|
body.pretty_print(&ctx.child_context(true), f)?;
|
||||||
|
writeln!(f, "{}}}", ctx.child_context(true).indent())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,383 @@
|
|||||||
|
//! Pretty printing module for Token objects
|
||||||
|
//!
|
||||||
|
//! This module provides elegant and functional printing capabilities for Token objects,
|
||||||
|
//! inspired by Rust's debug formatting but optimized for readability and analysis.
|
||||||
|
|
||||||
|
use crate::frontend::{
|
||||||
|
source_registry::SourceSlice,
|
||||||
|
tokens::{LiteralValue, Token, TokenType},
|
||||||
|
};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Configuration for pretty printing tokens
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TokenPrettyConfig {
|
||||||
|
/// Show source position information
|
||||||
|
pub show_positions: bool,
|
||||||
|
/// Use compact single-line format
|
||||||
|
pub compact: bool,
|
||||||
|
/// Show literal values in detail
|
||||||
|
pub show_literals: bool,
|
||||||
|
/// Use colored output (for terminals)
|
||||||
|
pub colored: bool,
|
||||||
|
/// Show token indices in sequences
|
||||||
|
pub show_indices: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TokenPrettyConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
show_positions: true,
|
||||||
|
compact: false,
|
||||||
|
show_literals: true,
|
||||||
|
colored: false,
|
||||||
|
show_indices: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TokenPrettyConfig {
|
||||||
|
/// Create a compact configuration
|
||||||
|
pub fn compact() -> Self {
|
||||||
|
Self {
|
||||||
|
compact: true,
|
||||||
|
show_positions: false,
|
||||||
|
show_indices: false,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a minimal configuration (just type and lexeme)
|
||||||
|
pub fn minimal() -> Self {
|
||||||
|
Self {
|
||||||
|
compact: true,
|
||||||
|
show_positions: false,
|
||||||
|
show_literals: false,
|
||||||
|
show_indices: false,
|
||||||
|
colored: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a debug configuration with all details
|
||||||
|
pub fn debug() -> Self {
|
||||||
|
Self {
|
||||||
|
show_positions: true,
|
||||||
|
show_literals: true,
|
||||||
|
compact: false,
|
||||||
|
show_indices: true,
|
||||||
|
colored: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a colored configuration for terminal output
|
||||||
|
pub fn colored() -> Self {
|
||||||
|
Self {
|
||||||
|
colored: true,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for pretty printing tokens
|
||||||
|
pub trait TokenPrettyPrint {
|
||||||
|
fn pretty_print_token(&self, config: &TokenPrettyConfig) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TokenPrettyPrint for Token {
|
||||||
|
fn pretty_print_token(&self, config: &TokenPrettyConfig) -> String {
|
||||||
|
if config.compact {
|
||||||
|
self.format_compact(config)
|
||||||
|
} else {
|
||||||
|
self.format_full(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Token {
|
||||||
|
fn format_compact(&self, config: &TokenPrettyConfig) -> String {
|
||||||
|
if config.show_literals {
|
||||||
|
match &self.literal {
|
||||||
|
Some(literal) => {
|
||||||
|
if config.colored {
|
||||||
|
format!("{}[{}]", self.colored_type(), literal)
|
||||||
|
} else {
|
||||||
|
format!("{}[{}]", self.token_type_symbol(), literal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if config.colored {
|
||||||
|
format!("{}", self.colored_type())
|
||||||
|
} else {
|
||||||
|
format!("{}", self.token_type_symbol())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if config.colored {
|
||||||
|
format!("{}", self.colored_type())
|
||||||
|
} else {
|
||||||
|
format!("{}", self.token_type_symbol())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_full(&self, config: &TokenPrettyConfig) -> String {
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
|
||||||
|
// Token type
|
||||||
|
if config.colored {
|
||||||
|
parts.push(format!("type: {}", self.colored_type()));
|
||||||
|
} else {
|
||||||
|
parts.push(format!("type: {:?}", self.token_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lexeme
|
||||||
|
parts.push(format!("lexeme: {:?}", self.lexeme));
|
||||||
|
|
||||||
|
// Literal value
|
||||||
|
if config.show_literals {
|
||||||
|
match &self.literal {
|
||||||
|
Some(literal) => parts.push(format!("literal: {:?}", literal)),
|
||||||
|
None => parts.push("literal: None".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position information
|
||||||
|
if config.show_positions {
|
||||||
|
parts.push(format!("pos: {:?}", self.source_slice));
|
||||||
|
}
|
||||||
|
|
||||||
|
format!("Token {{ {} }}", parts.join(", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn token_type_symbol(&self) -> &'static str {
|
||||||
|
match self.token_type {
|
||||||
|
TokenType::LeftParen => "(",
|
||||||
|
TokenType::RightParen => ")",
|
||||||
|
TokenType::LeftBrace => "{",
|
||||||
|
TokenType::RightBrace => "}",
|
||||||
|
TokenType::LeftBracket => "[",
|
||||||
|
TokenType::RightBracket => "]",
|
||||||
|
TokenType::Comma => ",",
|
||||||
|
TokenType::Dot => ".",
|
||||||
|
TokenType::Minus => "-",
|
||||||
|
TokenType::Plus => "+",
|
||||||
|
TokenType::Semicolon => ";",
|
||||||
|
TokenType::Slash => "/",
|
||||||
|
TokenType::Star => "*",
|
||||||
|
TokenType::Percent => "%",
|
||||||
|
TokenType::Bang => "!",
|
||||||
|
TokenType::BangEqual => "!=",
|
||||||
|
TokenType::Equal => "=",
|
||||||
|
TokenType::EqualEqual => "==",
|
||||||
|
TokenType::Greater => ">",
|
||||||
|
TokenType::GreaterEqual => ">=",
|
||||||
|
TokenType::Less => "<",
|
||||||
|
TokenType::LessEqual => "<=",
|
||||||
|
TokenType::Identifier => "ID",
|
||||||
|
TokenType::String => "STR",
|
||||||
|
TokenType::Number => "NUM",
|
||||||
|
TokenType::And => "AND",
|
||||||
|
TokenType::Class => "CLASS",
|
||||||
|
TokenType::StartBlock => "DO",
|
||||||
|
TokenType::EndBlock => "END",
|
||||||
|
TokenType::False => "FALSE",
|
||||||
|
TokenType::True => "TRUE",
|
||||||
|
TokenType::Fun => "FUN",
|
||||||
|
TokenType::For => "FOR",
|
||||||
|
TokenType::While => "WHILE",
|
||||||
|
TokenType::If => "IF",
|
||||||
|
TokenType::Elif => "ELIF",
|
||||||
|
TokenType::Else => "ELSE",
|
||||||
|
TokenType::Nil => "NIL",
|
||||||
|
TokenType::Or => "OR",
|
||||||
|
TokenType::Print => "PRINT",
|
||||||
|
TokenType::Return => "RETURN",
|
||||||
|
TokenType::Super => "SUPER",
|
||||||
|
TokenType::This => "THIS",
|
||||||
|
TokenType::Var => "VAR",
|
||||||
|
TokenType::Val => "VAL",
|
||||||
|
TokenType::Eof => "EOF",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn colored_type(&self) -> String {
|
||||||
|
let (color_code, symbol) = match self.token_type {
|
||||||
|
// Operators - Red
|
||||||
|
TokenType::Plus
|
||||||
|
| TokenType::Minus
|
||||||
|
| TokenType::Star
|
||||||
|
| TokenType::Slash
|
||||||
|
| TokenType::Percent
|
||||||
|
| TokenType::Bang
|
||||||
|
| TokenType::BangEqual
|
||||||
|
| TokenType::Equal
|
||||||
|
| TokenType::EqualEqual
|
||||||
|
| TokenType::Greater
|
||||||
|
| TokenType::GreaterEqual
|
||||||
|
| TokenType::Less
|
||||||
|
| TokenType::LessEqual => ("\x1b[31m", self.token_type_symbol()),
|
||||||
|
|
||||||
|
// Keywords - Blue
|
||||||
|
TokenType::And
|
||||||
|
| TokenType::Class
|
||||||
|
| TokenType::False
|
||||||
|
| TokenType::True
|
||||||
|
| TokenType::Fun
|
||||||
|
| TokenType::For
|
||||||
|
| TokenType::While
|
||||||
|
| TokenType::If
|
||||||
|
| TokenType::Elif
|
||||||
|
| TokenType::Else
|
||||||
|
| TokenType::Nil
|
||||||
|
| TokenType::Or
|
||||||
|
| TokenType::Print
|
||||||
|
| TokenType::Return
|
||||||
|
| TokenType::Super
|
||||||
|
| TokenType::This
|
||||||
|
| TokenType::Var
|
||||||
|
| TokenType::Val => ("\x1b[34m", self.token_type_symbol()),
|
||||||
|
|
||||||
|
// Literals - Green
|
||||||
|
TokenType::Identifier | TokenType::String | TokenType::Number => {
|
||||||
|
("\x1b[32m", self.token_type_symbol())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Punctuation - Gray
|
||||||
|
TokenType::LeftParen
|
||||||
|
| TokenType::RightParen
|
||||||
|
| TokenType::LeftBrace
|
||||||
|
| TokenType::RightBrace
|
||||||
|
| TokenType::LeftBracket
|
||||||
|
| TokenType::RightBracket
|
||||||
|
| TokenType::Comma
|
||||||
|
| TokenType::Dot
|
||||||
|
| TokenType::Semicolon => ("\x1b[37m", self.token_type_symbol()),
|
||||||
|
|
||||||
|
// Block delimiters - Magenta
|
||||||
|
TokenType::StartBlock | TokenType::EndBlock => ("\x1b[35m", self.token_type_symbol()),
|
||||||
|
|
||||||
|
// EOF - Yellow
|
||||||
|
TokenType::Eof => ("\x1b[33m", self.token_type_symbol()),
|
||||||
|
};
|
||||||
|
|
||||||
|
format!("{}{}\x1b[0m", color_code, symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pretty print a sequence of tokens
|
||||||
|
pub fn pretty_print_tokens(tokens: &[Token], config: &TokenPrettyConfig) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
|
||||||
|
if config.compact {
|
||||||
|
let token_strs: Vec<String> = tokens
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, token)| {
|
||||||
|
if config.show_indices {
|
||||||
|
format!("{}:{}", i, token.pretty_print_token(config))
|
||||||
|
} else {
|
||||||
|
token.pretty_print_token(config)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
result.push_str(&token_strs.join(" "));
|
||||||
|
} else {
|
||||||
|
for (i, token) in tokens.iter().enumerate() {
|
||||||
|
if config.show_indices {
|
||||||
|
result.push_str(&format!("[{}] ", i));
|
||||||
|
}
|
||||||
|
result.push_str(&token.pretty_print_token(config));
|
||||||
|
result.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extension trait for convenience methods
|
||||||
|
pub trait TokenPrettyPrintExt {
|
||||||
|
fn pretty(&self) -> String;
|
||||||
|
fn pretty_compact(&self) -> String;
|
||||||
|
fn pretty_minimal(&self) -> String;
|
||||||
|
fn pretty_colored(&self) -> String;
|
||||||
|
fn pretty_debug(&self) -> String;
|
||||||
|
fn pretty_with_config(&self, config: &TokenPrettyConfig) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TokenPrettyPrintExt for Token {
|
||||||
|
fn pretty(&self) -> String {
|
||||||
|
self.pretty_print_token(&TokenPrettyConfig::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_compact(&self) -> String {
|
||||||
|
self.pretty_print_token(&TokenPrettyConfig::compact())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_minimal(&self) -> String {
|
||||||
|
self.pretty_print_token(&TokenPrettyConfig::minimal())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_colored(&self) -> String {
|
||||||
|
self.pretty_print_token(&TokenPrettyConfig::colored())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_debug(&self) -> String {
|
||||||
|
self.pretty_print_token(&TokenPrettyConfig::debug())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_with_config(&self, config: &TokenPrettyConfig) -> String {
|
||||||
|
self.pretty_print_token(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TokenPrettyPrintExt for Vec<Token> {
|
||||||
|
fn pretty(&self) -> String {
|
||||||
|
pretty_print_tokens(self, &TokenPrettyConfig::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_compact(&self) -> String {
|
||||||
|
pretty_print_tokens(self, &TokenPrettyConfig::compact())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_minimal(&self) -> String {
|
||||||
|
pretty_print_tokens(self, &TokenPrettyConfig::minimal())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_colored(&self) -> String {
|
||||||
|
pretty_print_tokens(self, &TokenPrettyConfig::colored())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_debug(&self) -> String {
|
||||||
|
pretty_print_tokens(self, &TokenPrettyConfig::debug())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_with_config(&self, config: &TokenPrettyConfig) -> String {
|
||||||
|
pretty_print_tokens(self, config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience functions for quick pretty printing
|
||||||
|
pub fn pretty_token(token: &Token) -> String {
|
||||||
|
token.pretty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_token_compact(token: &Token) -> String {
|
||||||
|
token.pretty_compact()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_token_minimal(token: &Token) -> String {
|
||||||
|
token.pretty_minimal()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_tokens(tokens: &[Token]) -> String {
|
||||||
|
pretty_print_tokens(tokens, &TokenPrettyConfig::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_tokens_compact(tokens: &[Token]) -> String {
|
||||||
|
pretty_print_tokens(tokens, &TokenPrettyConfig::compact())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_tokens_colored(tokens: &[Token]) -> String {
|
||||||
|
pretty_print_tokens(tokens, &TokenPrettyConfig::colored())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
pub mod display_ast;
|
pub mod display_ast;
|
||||||
|
pub mod display_token;
|
||||||
|
|||||||
Reference in New Issue
Block a user