Skip to content

Commit

Permalink
feat: implement Display for ast::Node
Browse files Browse the repository at this point in the history
  • Loading branch information
viddrobnic committed May 27, 2024
1 parent 675d8e8 commit 80dacf4
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 0 deletions.
160 changes: 160 additions & 0 deletions parser/src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fmt::Display;

use crate::position::Range;

#[derive(Debug, PartialEq, Clone)]
Expand Down Expand Up @@ -80,6 +82,15 @@ pub enum PrefixOperatorKind {
Negative,
}

impl Display for PrefixOperatorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PrefixOperatorKind::Not => write!(f, "!"),
PrefixOperatorKind::Negative => write!(f, "-"),
}
}
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum InfixOperatorKind {
Add,
Expand All @@ -97,6 +108,26 @@ pub enum InfixOperatorKind {
Neq,
}

impl Display for InfixOperatorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InfixOperatorKind::Add => write!(f, "+"),
InfixOperatorKind::Subtract => write!(f, "-"),
InfixOperatorKind::Multiply => write!(f, "*"),
InfixOperatorKind::Divide => write!(f, "/"),
InfixOperatorKind::Modulo => write!(f, "%"),
InfixOperatorKind::And => write!(f, "&"),
InfixOperatorKind::Or => write!(f, "|"),
InfixOperatorKind::Le => write!(f, "<"),
InfixOperatorKind::Leq => write!(f, "<="),
InfixOperatorKind::Ge => write!(f, ">"),
InfixOperatorKind::Geq => write!(f, ">="),
InfixOperatorKind::Eq => write!(f, "=="),
InfixOperatorKind::Neq => write!(f, "!="),
}
}
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum NodeKind {
Expression,
Expand All @@ -123,3 +154,132 @@ impl NodeValue {
}
}
}

impl Display for Program {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let body = self
.statements
.iter()
.map(|node| node.to_string())
.collect::<Vec<_>>()
.join("\n");

write!(f, "{}", body)
}
}

impl Display for Node {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value)
}
}

impl Display for NodeValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NodeValue::Identifier(ident) => write!(f, "{ident}"),
NodeValue::IntegerLiteral(int) => write!(f, "{int}"),
NodeValue::FloatLiteral(float) => write!(f, "{float}"),
NodeValue::BoolLiteral(boolean) => write!(f, "{boolean}"),
NodeValue::StringLiteral(string) => write!(f, "\"{string}\""),
NodeValue::ArrayLiteral(arr) => {
let elts = arr
.iter()
.map(|val| val.to_string())
.collect::<Vec<_>>()
.join(", ");

write!(f, "[{elts}]")
}
NodeValue::HashLiteral(hash) => {
let elts = hash
.iter()
.map(|pair| format!("{}: {}", pair.key, pair.value))
.collect::<Vec<_>>()
.join(", ");

write!(f, "{{{elts}}}")
}
NodeValue::PrefixOperator { operator, right } => write!(f, "({operator}{right})"),
NodeValue::InfixOperator {
operator,
left,
right,
} => write!(f, "({left} {operator} {right})"),
NodeValue::Assign { ident, value } => write!(f, "({ident} = {value})"),
NodeValue::Index { left, index } => write!(f, "({left}[{index}])"),
NodeValue::If {
condition,
consequence,
alternative,
} => {
let cons = consequence
.iter()
.map(|node| node.to_string())
.collect::<Vec<_>>()
.join("\n");

let alt = alternative
.iter()
.map(|node| node.to_string())
.collect::<Vec<_>>()
.join("\n");

write!(f, "if ({condition}) {{{cons}}} else {{{alt}}}")
}
NodeValue::While { condition, body } => {
let body = body
.iter()
.map(|node| node.to_string())
.collect::<Vec<_>>()
.join("\n");

write!(f, "while ({condition}) {{{body}}}")
}
NodeValue::For {
initial,
condition,
after,
body,
} => {
let body = body
.iter()
.map(|node| node.to_string())
.collect::<Vec<_>>()
.join("\n");

write!(f, "for ({initial}; {condition}; {after}) {{{body}}}")
}
NodeValue::Break => write!(f, "break"),
NodeValue::Continue => write!(f, "continue"),
NodeValue::FunctionLiteral {
name: _,
parameters,
body,
} => {
let body = body
.iter()
.map(|node| node.to_string())
.collect::<Vec<_>>()
.join("\n");

write!(f, "fn({}) {{{}}}", parameters.join(", "), body)
}
NodeValue::FunctionCall {
function,
arguments,
} => {
let args = arguments
.iter()
.map(|node| node.to_string())
.collect::<Vec<_>>()
.join(", ");

write!(f, "({}({}))", function, args)
}
NodeValue::Return(ret) => write!(f, "return {ret}"),
NodeValue::Use(name) => write!(f, "use {name}"),
NodeValue::Comment(comment) => write!(f, "// {comment}"),
}
}
}
22 changes: 22 additions & 0 deletions parser/src/parser/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,25 @@ fn infix_opeartor() -> Result<()> {

Ok(())
}

#[test]
fn precedence() -> Result<()> {
let tests = [
("1 + 2 + 3", "((1 + 2) + 3)"),
("1 + 2 * 3", "(1 + (2 * 3))"),
("1 + 2 == 3", "((1 + 2) == 3)"),
("1 != 2 & false", "((1 != 2) & false)"),
("a & b | c", "((a & b) | c)"),
("a | b & c", "(a | (b & c))"),
("2 <= 3 == 3 > 2", "((2 <= 3) == (3 > 2))"),
("-1 + 1 * 2 % 3 / 4", "((-1) + (((1 * 2) % 3) / 4))"),
("1 + -2", "(1 + (-2))"),
];

for (input, expected) in tests {
let program = parse(input)?;
assert_eq!(program.to_string(), expected);
}

Ok(())
}

0 comments on commit 80dacf4

Please sign in to comment.