From 159af40e7c063c587a5bcfe5fae5a4769944d845 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Mon, 25 May 2020 11:56:41 -0400 Subject: [PATCH] DEV: Unify the path rewriting --- src/ast/mod.rs | 114 ++++++++++++++++++---------------- src/ast/walk.rs | 19 ++++-- src/build/mod.rs | 10 +-- src/build/opcode/translate.rs | 17 ++--- 4 files changed, 85 insertions(+), 75 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d55b8a8..8bd8c08 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -605,64 +605,72 @@ impl ModuleDef { pub fn set_out_expr(&mut self, expr: Expression) { self.out_expr = Some(Box::new(expr)); } +} - pub fn imports_to_absolute(&mut self, base: PathBuf) { - &base; - let rewrite_import = |e: &mut Expression| { - let main_separator = format!("{}", std::path::MAIN_SEPARATOR); - if let Expression::Include(ref mut def) = e { - let path = PathBuf::from(&def.path.fragment); - #[cfg(not(windows))] - { - if path.is_relative() { - def.path.fragment = base - .join(path) - .canonicalize() - .unwrap() - .to_string_lossy() - .to_string(); - } - } - #[cfg(windows)] - { - if path.is_relative() { - def.path.fragment = base.join(path).to_string_lossy().to_string(); - } +pub struct Rewriter { + base: PathBuf, +} + +impl Rewriter { + pub fn new>(base: P) -> Self { + Self { base: base.into() } + } +} + +impl walk::Walker for Rewriter { + fn visit_expression(&mut self, expr: &mut Expression) { + // Rewrite all paths except for stdlib paths to absolute. + let main_separator = format!("{}", std::path::MAIN_SEPARATOR); + if let Expression::Include(ref mut def) = expr { + let path = PathBuf::from(&def.path.fragment); + #[cfg(not(windows))] + { + if path.is_relative() { + def.path.fragment = self + .base + .join(path) + .canonicalize() + .unwrap() + .to_string_lossy() + .to_string(); } } - if let Expression::Import(ref mut def) = e { - let path = PathBuf::from( - &def.path - .fragment - .replace("/", &main_separator) - .replace("\\", &main_separator), - ); - // std/ paths are special and do not get made into absolute paths. - if path.starts_with(format!("std{}", main_separator)) { - return; - } - #[cfg(not(windows))] - { - if path.is_relative() { - def.path.fragment = base - .join(path) - .canonicalize() - .unwrap() - .to_string_lossy() - .to_string(); - } - } - #[cfg(windows)] - { - if path.is_relative() { - def.path.fragment = base.join(path).to_string_lossy().to_string(); - } + #[cfg(windows)] + { + if path.is_relative() { + def.path.fragment = self.base.join(path).to_string_lossy().to_string(); + } + } + } + if let Expression::Import(ref mut def) = expr { + let path = PathBuf::from( + &def.path + .fragment + .replace("/", &main_separator) + .replace("\\", &main_separator), + ); + // std/ paths are special and do not get made into absolute paths. + if path.starts_with(format!("std{}", main_separator)) { + return; + } + #[cfg(not(windows))] + { + if path.is_relative() { + def.path.fragment = self + .base + .join(path) + .canonicalize() + .unwrap() + .to_string_lossy() + .to_string(); + } + } + #[cfg(windows)] + { + if path.is_relative() { + def.path.fragment = self.base.join(path).to_string_lossy().to_string(); } } - }; - 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/walk.rs b/src/ast/walk.rs index ea8a90c..0a10b11 100644 --- a/src/ast/walk.rs +++ b/src/ast/walk.rs @@ -142,23 +142,30 @@ pub trait Walker { } } - fn visit_import(&mut self, i: &mut ImportDef) { + // TODO(jwall): Should this have exit versions as well? + fn visit_import(&mut self, _i: &mut ImportDef) { // noop by default; } - fn visit_include(&mut self, i: &mut IncludeDef) { + fn visit_include(&mut self, _i: &mut IncludeDef) { // noop by default; } - fn visit_fail(&mut self, f: &mut FailDef) { + fn visit_fail(&mut self, _f: &mut FailDef) { // noop by default; } - fn visit_value(&mut self, val: &mut Value); + fn visit_value(&mut self, _val: &mut Value) { + // noop by default + } - fn visit_expression(&mut self, expr: &mut Expression); + fn visit_expression(&mut self, _expr: &mut Expression) { + // noop by default + } - fn visit_statement(&mut self, stmt: &mut Statement); + fn visit_statement(&mut self, _stmt: &mut Statement) { + // noop by default + } } // TODO this would be better implemented as a Trait I think. diff --git a/src/build/mod.rs b/src/build/mod.rs index 8676d94..f1c9651 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -90,8 +90,6 @@ where pub environment: &'a RefCell>, working_dir: PathBuf, strict: bool, - // FIXME(jwall): These need to be compiled and added to the op cache. - // specifically in the environment. std: Rc>, import_path: &'a Vec, pub last: Option>, @@ -303,12 +301,8 @@ where } pub fn eval_expr(&mut self, expr: Expression) -> Result, Box> { - let mut ops_map = translate::OpsMap::new(); - translate::AST::translate_stmt( - Statement::Expression(expr), - &mut ops_map, - &self.working_dir, - ); + let ops_map = + translate::AST::translate(vec![Statement::Expression(expr)], &self.working_dir); let mut vm = VM::new(self.strict, Rc::new(ops_map), &self.working_dir); if self.validate_mode { vm.enable_validate_mode(); diff --git a/src/build/opcode/translate.rs b/src/build/opcode/translate.rs index 9a0eb9c..73225e4 100644 --- a/src/build/opcode/translate.rs +++ b/src/build/opcode/translate.rs @@ -14,11 +14,11 @@ use std::collections::BTreeMap; use std::path::Path; +use crate::ast::walk::Walker; use crate::ast::{ - BinaryExprType, BinaryOpDef, Expression, FormatArgs, Position, PositionedItem, SelectDef, - Statement, Token, TokenType, Value, + BinaryExprType, BinaryOpDef, Expression, FormatArgs, FuncOpDef, Position, PositionedItem, + Rewriter, SelectDef, Statement, TemplatePart, Token, TokenType, Value, }; -use crate::ast::{FuncOpDef, TemplatePart}; use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser}; use crate::build::opcode::Primitive; use crate::build::opcode::{Hook, Op}; @@ -66,13 +66,16 @@ impl OpsMap { } impl AST { - pub fn translate>(stmts: Vec, root: &P) -> OpsMap { + pub fn translate>(mut stmts: Vec, root: &P) -> OpsMap { + let mut rewriter = Rewriter::new(root.as_ref()); + let mut_stmts = stmts.iter_mut().collect(); + rewriter.walk_statement_list(mut_stmts); let mut ops = OpsMap::new(); Self::translate_stmts(stmts, &mut ops, root.as_ref()); return ops; } - pub fn translate_stmt(stmt: Statement, mut ops: &mut OpsMap, root: &Path) { + fn translate_stmt(stmt: Statement, mut ops: &mut OpsMap, root: &Path) { match stmt { Statement::Expression(expr) => { let expr_pos = expr.pos().clone(); @@ -210,7 +213,6 @@ impl AST { Self::translate_expr(*def.right.clone(), &mut ops, root); // Symbols on the left side should be converted to strings to satisfy // the Index operation contract. - // FIXME(jwall): List checks should not use symbol translation. match *def.left.clone() { Expression::Simple(Value::Symbol(name)) => { // We really just want an expression that turns a symbol @@ -451,8 +453,7 @@ impl AST { ops.push(Op::Val(Primitive::Str(def.path.fragment)), def.path.pos); ops.push(Op::Runtime(Hook::Include), def.pos); } - Expression::Module(mut def) => { - def.imports_to_absolute(root.to_path_buf()); + Expression::Module(def) => { let argset = def.arg_set; let out_expr = def.out_expr; let stmts = def.statements;