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::scope::Scope;
|
||||||
use crate::build::Val;
|
use crate::build::Val;
|
||||||
|
|
||||||
|
pub mod printer;
|
||||||
pub mod walk;
|
pub mod walk;
|
||||||
|
|
||||||
|
pub use walk::Walker;
|
||||||
|
|
||||||
macro_rules! enum_type_equality {
|
macro_rules! enum_type_equality {
|
||||||
( $slf:ident, $r:expr, $( $l:pat ),* ) => {
|
( $slf:ident, $r:expr, $( $l:pat ),* ) => {
|
||||||
match $slf {
|
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() {
|
for stmt in self.statements.iter_mut() {
|
||||||
walker.walk_statement(stmt);
|
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::*;
|
use crate::ast::*;
|
||||||
|
|
||||||
pub struct AstWalker<'a> {
|
pub trait Walker {
|
||||||
handle_value: Option<&'a Fn(&mut Value)>,
|
fn walk_statement_list(&mut self, stmts: Vec<&mut Statement>) {
|
||||||
handle_expression: Option<&'a Fn(&mut Expression)>,
|
for v in stmts {
|
||||||
handle_statment: Option<&'a Fn(&mut Statement)>,
|
self.walk_statement(v);
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
fn walk_statement(&mut self, stmt: &mut Statement) {
|
||||||
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) {
|
|
||||||
self.visit_statement(stmt);
|
self.visit_statement(stmt);
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Let(ref mut def) => {
|
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() {
|
for &mut (_, ref mut expr) in fs.iter_mut() {
|
||||||
self.walk_expression(expr);
|
self.walk_expression(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_expression(&self, expr: &mut Expression) {
|
fn walk_expression(&mut self, expr: &mut Expression) {
|
||||||
self.visit_expression(expr);
|
self.visit_expression(expr);
|
||||||
match expr {
|
match expr {
|
||||||
Expression::Call(ref mut def) => {
|
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 {
|
if let Some(h) = self.handle_value {
|
||||||
h(val);
|
h(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_expression(&self, expr: &mut Expression) {
|
fn visit_expression(&mut self, expr: &mut Expression) {
|
||||||
if let Some(h) = self.handle_expression {
|
if let Some(h) = self.handle_expression {
|
||||||
h(expr);
|
h(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_statement(&self, stmt: &mut Statement) {
|
fn visit_statement(&mut self, stmt: &mut Statement) {
|
||||||
if let Some(h) = self.handle_statment {
|
if let Some(h) = self.handle_statment {
|
||||||
h(stmt);
|
h(stmt);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user