Skip to content
Snippets Groups Projects
printer.rs 6 KiB
Newer Older
Louis's avatar
Louis committed
use crate::parser::ast::*;
use crate::runtime::executor::Visitor;

pub struct TreePrinter {
	indent: usize,
	buffer: String,
}

impl TreePrinter {
	pub fn new() -> Self {
		Self {
			indent: 0,
			buffer: String::new(),
		}
	}

	pub fn increment(&mut self) {
		self.indent = self.indent.saturating_add(1);
	}

	pub fn decrement(&mut self) {
		self.indent = self.indent.saturating_sub(1);
	}

	pub fn get_indent(&self) -> String {
		vec!["\t"; self.indent].join("")
	}

	fn write(&mut self, value: impl ToString) {
		self.buffer.push_str(value.to_string().as_str());
	}
	fn writeln(&mut self, value: impl ToString) {
		self.buffer.push_str(value.to_string().as_str());
		self.buffer.push('\n');
	}
	fn write_indent(&mut self) {
		self.write(self.get_indent());
	}
	fn new_line(&mut self) {
		self.buffer.push('\n');
	}

	fn format_expression_list(&self, list: &ExpressionList) -> String {
		let mut inner_printer = TreePrinter::new();
		inner_printer.indent = self.indent;

		let len = list.len();
		let mut iter = list.expressions.iter();
		let mut counter = 1;

		while let Some(value) = iter.next() {
			inner_printer.evaluate_expression(value);
			if counter < len {
				inner_printer.writeln(";");
			}
			counter += 1;
		}

		if list.is_void {
			inner_printer.writeln(";");
		}

		inner_printer.buffer
	}

	pub fn value(&self) -> &str {
		self.buffer.as_str()
	}

	pub fn take_value(&mut self) -> String {
		std::mem::take(&mut self.buffer)
	}
}

impl Visitor for TreePrinter {
	fn evaluate_value_expression(&mut self, expression: &ValueExpression) {
		match expression {
			ValueExpression::Unary { operand, operator } => {
				self.write(operator);
				self.evaluate_value_expression(operand.as_ref());
			}
			ValueExpression::Binary { operator, rhs, lhs } => {
				self.evaluate_value_expression(lhs.as_ref());
				self.write(operator);
				self.evaluate_value_expression(rhs.as_ref());
			}
			ValueExpression::Block(list) => {
				self.writeln("{");
				self.increment();
				self.write(self.format_expression_list(list));
				self.decrement();
				self.writeln("}");
			}
			ValueExpression::Literal(value) => self.write(value),
			ValueExpression::DeclareIdentifier(dec_ident) => match dec_ident {
				DeclareIdent::WithoutValue(ident) => {
					self.write("let ");
					self.write(ident);
				}
				DeclareIdent::WithValue(assign) => {
					self.write("let ");
					self.write(&assign.ident);
					self.write(" = ");
					self.evaluate_value_expression(assign.value.as_ref());
				}
			},
			ValueExpression::Assignment(assign) => {
				self.write(&assign.ident);
				self.write(" = ");
				self.evaluate_value_expression(assign.value.as_ref());
			}
			ValueExpression::ConditionalBlock(condition) => {
				let mut iter = condition.blocks.iter();
				let mut curr = 1;
				let count = iter.len();
				while let Some(item) = iter.next() {
					self.write("if ");
					self.evaluate_value_expression(item.guard.as_ref());
					self.writeln(" {");
					self.increment();
					self.write(self.format_expression_list(&item.block));
					self.decrement();
					if curr < count {
						self.write("} else ");
					} else {
						self.write("}");
					}
				}

				if let Some(fall) = &condition.fallback {
					self.writeln(" else {");
					self.increment();
					self.write(self.format_expression_list(fall));
					self.decrement();
					self.writeln("}");
				}
			}
			ValueExpression::Grouped(GroupedExpression { inner }) => {
				self.write("(");
				self.evaluate_value_expression(inner.as_ref());
				self.write(")");
			}
			ValueExpression::Identifier(ident) => {
				self.write(ident);
			}
Louis's avatar
Louis committed
			ValueExpression::FunctionCall(call) => {
				self.write(&call.name);
				self.write("(");
				let list = call
					.params
					.iter()
					.map(|param| {
						let mut inner = TreePrinter {
							indent: self.indent,
							buffer: String::new(),
						};
						inner.evaluate_value_expression(param);
						inner.take_value()
					})
					.collect::<Vec<String>>();
				self.write(list.as_slice().join(", "));
				self.write(")");
			}
Louis's avatar
Louis committed
			ValueExpression::DeclareFunction(declare) => {
				self.write("fn ");
				self.write(&declare.ident);
				self.write("(");
				let list = declare
					.params
					.iter()
					.map(|param| {
						let mut inner = TreePrinter {
							indent: self.indent,
							buffer: String::new(),
						};

						match param {
							DeclareIdent::WithValue(assign) => {
								inner.write(&assign.ident);
								inner.write(" = ");
								inner.evaluate_value_expression(assign.value.as_ref());
							}
							DeclareIdent::WithoutValue(identifier) => inner.write(identifier),
						}

						inner.take_value()
					})
					.collect::<Vec<String>>();

				self.write(list.as_slice().join(", "));
				self.writeln(") {");
				self.increment();
				self.writeln(self.format_expression_list(&declare.body));
				self.decrement();
				self.writeln("}");
			}
Louis's avatar
Louis committed
		}
	}

	fn evaluate_void_expression(&mut self, expression: &VoidExpression) {
		match expression {
			VoidExpression::ConditionLoop(cond) => {
				self.write("while ");
				self.evaluate_value_expression(cond.block.guard.as_ref());
				self.writeln(" {");
				self.increment();
				self.writeln(self.format_expression_list(&cond.block.block));
				self.decrement();
				self.writeln(" {");
			}
			VoidExpression::Import(import) => {
				self.write("import { ");
				let ident_list = import
					.items
					.iter()
					.map(|idn| format!("{}", idn))
					.collect::<Vec<String>>();

				self.write(ident_list.as_slice().join(", "));
				self.write(" } from \"");
				self.write(&import.source);
				self.write("\"");
			}
			VoidExpression::Export(export) => {
				self.write("export {");
				let ident_list = export
					.items
					.iter()
					.map(|idn| format!("{}", idn))
					.collect::<Vec<String>>();

				self.write(ident_list.as_slice().join(", "));
				self.write("}");
			}
			VoidExpression::Print(print) => {
				self.write("print ");
				self.evaluate_value_expression(print.expr.as_ref());
			}
		}
	}

	fn evaluate_program(&mut self, program: &Program) {
		self.writeln(self.format_expression_list(&program.0));
	}
}