diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 041fbba..f3f4b2c 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -31,8 +31,11 @@ use abortable_parser; use crate::build::scope::Scope; use crate::build::Val; +pub mod printer; pub mod walk; +pub use walk::Walker; + macro_rules! enum_type_equality { ( $slf:ident, $r:expr, $( $l:pat ),* ) => { match $slf { @@ -593,7 +596,7 @@ impl ModuleDef { } } }; - let walker = walk::AstWalker::new().with_expr_handler(&rewrite_import); + let mut walker = walk::AstWalker::new().with_expr_handler(&rewrite_import); for stmt in self.statements.iter_mut() { walker.walk_statement(stmt); } diff --git a/src/ast/printer.rs b/src/ast/printer.rs new file mode 100644 index 0000000..6a2ebb2 --- /dev/null +++ b/src/ast/printer.rs @@ -0,0 +1,116 @@ +// Copyright 2019 Jeremy Wall +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +use std::borrow::BorrowMut; +use std::error::Error; +use std::io::Write; + +use crate::ast::walk::Walker; +use crate::ast::*; + +// TODO(jwall): We really need a way to preserve comments for these. +// Perhaps for code formatting we actually want to work on the token stream instead? + +pub struct Printer { + indent: u8, + curr_indent: u8, + w: Box, + pub errs: Vec>, +} + +impl Printer { + pub fn new(indent: u8, w: Box) -> Self { + Printer { + indent: indent, + curr_indent: 0, + w: w, + errs: Vec::new(), + } + } + + pub fn render_list_def(&mut self, def: &ListDef) -> std::io::Result<()> { + panic!("Unimplemented"); + Ok(()) + } + + pub fn render_tuple_def(&mut self, def: &Vec<(Token, Expression)>) -> std::io::Result<()> { + panic!("Unimplemented"); + Ok(()) + } + + pub fn render_value(&mut self, v: &Value) { + // TODO + let w: &mut Write = self.w.borrow_mut(); + let result = match v { + Value::Boolean(b) => write!(w, "{}", b), + Value::Empty(_) => write!(w, "NULL"), + // TODO(jwall): Should we maintain precision for floats? + Value::Float(f) => write!(w, "{}", f), + Value::Int(i) => write!(w, "{}", i), + // TODO(jwall): Make sure that we properly escape quotes here when rendering this? + Value::Str(s) => write!(w, "\"{}\"", s), + Value::Symbol(s) => write!(w, "{}", s), + Value::List(l) => self.render_list_def(l), + Value::Tuple(tpl) => self.render_tuple_def(&tpl.val), + }; + if let Err(e) = result { + self.errs.push(Box::new(e)); + } + } + + fn render_expr(&mut self, expr: &Expression) { + match expr { + Expression::Binary(_def) => {} + Expression::Call(_def) => {} + Expression::Copy(_def) => {} + Expression::Debug(_def) => {} + Expression::Fail(_def) => {} + Expression::Format(_def) => {} + Expression::Func(_def) => {} + Expression::FuncOp(_def) => {} + Expression::Grouped(_expr, _) => {} + Expression::Import(_def) => {} + Expression::Include(_def) => {} + Expression::Module(_def) => {} + Expression::Not(_def) => {} + Expression::Range(_def) => {} + Expression::Select(_def) => {} + Expression::Simple(_def) => {} + } + } + + fn render_stmt(&mut self, stmt: &Statement) { + match stmt { + Statement::Let(_def) => {} + Statement::Expression(_expr) => {} + Statement::Assert(_def) => {} + Statement::Output(_, _tok, _expr) => {} + } + } + + pub fn render(&mut self, stmts: Vec<&mut Statement>) { + self.walk_statement_list(stmts); + } +} + +impl Walker for Printer { + fn visit_value(&mut self, val: &mut Value) { + self.render_value(val); + } + fn visit_expression(&mut self, expr: &mut Expression) { + self.render_expr(expr); + } + fn visit_statement(&mut self, stmt: &mut Statement) { + self.render_stmt(stmt); + } +} diff --git a/src/ast/walk.rs b/src/ast/walk.rs index 023de26..df402df 100644 --- a/src/ast/walk.rs +++ b/src/ast/walk.rs @@ -1,36 +1,13 @@ use crate::ast::*; -pub struct AstWalker<'a> { - handle_value: Option<&'a Fn(&mut Value)>, - handle_expression: Option<&'a Fn(&mut Expression)>, - handle_statment: Option<&'a Fn(&mut Statement)>, -} - -impl<'a> AstWalker<'a> { - pub fn new() -> Self { - AstWalker { - handle_value: None, - handle_expression: None, - handle_statment: None, +pub trait Walker { + fn walk_statement_list(&mut self, stmts: Vec<&mut Statement>) { + for v in stmts { + self.walk_statement(v); } } - pub fn with_value_handler(mut self, h: &'a Fn(&mut Value)) -> Self { - self.handle_value = Some(h); - self - } - - pub fn with_expr_handler(mut self, h: &'a Fn(&mut Expression)) -> Self { - self.handle_expression = Some(h); - self - } - - pub fn with_stmt_handler(mut self, h: &'a Fn(&mut Statement)) -> Self { - self.handle_statment = Some(h); - self - } - - pub fn walk_statement(&self, stmt: &mut Statement) { + fn walk_statement(&mut self, stmt: &mut Statement) { self.visit_statement(stmt); match stmt { Statement::Let(ref mut def) => { @@ -48,13 +25,13 @@ impl<'a> AstWalker<'a> { } } - fn walk_fieldset(&self, fs: &mut FieldList) { + fn walk_fieldset(&mut self, fs: &mut FieldList) { for &mut (_, ref mut expr) in fs.iter_mut() { self.walk_expression(expr); } } - pub fn walk_expression(&self, expr: &mut Expression) { + fn walk_expression(&mut self, expr: &mut Expression) { self.visit_expression(expr); match expr { Expression::Call(ref mut def) => { @@ -135,19 +112,59 @@ impl<'a> AstWalker<'a> { } } - fn visit_value(&self, val: &mut Value) { + fn visit_value(&mut self, val: &mut Value); + + fn visit_expression(&mut self, expr: &mut Expression); + + fn visit_statement(&mut self, stmt: &mut Statement); +} + +// TODO this would be better implemented as a Trait I think. +pub struct AstWalker<'a> { + handle_value: Option<&'a Fn(&mut Value)>, + handle_expression: Option<&'a Fn(&mut Expression)>, + handle_statment: Option<&'a Fn(&mut Statement)>, +} + +impl<'a> AstWalker<'a> { + pub fn new() -> Self { + AstWalker { + handle_value: None, + handle_expression: None, + handle_statment: None, + } + } + + pub fn with_value_handler(mut self, h: &'a Fn(&mut Value)) -> Self { + self.handle_value = Some(h); + self + } + + pub fn with_expr_handler(mut self, h: &'a Fn(&mut Expression)) -> Self { + self.handle_expression = Some(h); + self + } + + pub fn with_stmt_handler(mut self, h: &'a Fn(&mut Statement)) -> Self { + self.handle_statment = Some(h); + self + } +} + +impl<'a> Walker for AstWalker<'a> { + fn visit_value(&mut self, val: &mut Value) { if let Some(h) = self.handle_value { h(val); } } - fn visit_expression(&self, expr: &mut Expression) { + fn visit_expression(&mut self, expr: &mut Expression) { if let Some(h) = self.handle_expression { h(expr); } } - fn visit_statement(&self, stmt: &mut Statement) { + fn visit_statement(&mut self, stmt: &mut Statement) { if let Some(h) = self.handle_statment { h(stmt); }