mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: First make our AST Walker a little more ergonomic.
Use a trait instead of callbacks to make mutable it possible to support Walkers with mutable internal state when necessary.
This commit is contained in:
parent
c9b9d1b7ea
commit
2821d0953b
@ -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);
|
||||
}
|
||||
|
116
src/ast/printer.rs
Normal file
116
src/ast/printer.rs
Normal file
@ -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<dyn Write>,
|
||||
pub errs: Vec<Box<dyn Error>>,
|
||||
}
|
||||
|
||||
impl Printer {
|
||||
pub fn new(indent: u8, w: Box<dyn Write>) -> 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user