DEV: Unify the path rewriting

This commit is contained in:
Jeremy Wall 2020-05-25 11:56:41 -04:00
parent 3052f7d7a8
commit 159af40e7c
4 changed files with 85 additions and 75 deletions

View File

@ -605,17 +605,29 @@ impl ModuleDef {
pub fn set_out_expr(&mut self, expr: Expression) { pub fn set_out_expr(&mut self, expr: Expression) {
self.out_expr = Some(Box::new(expr)); self.out_expr = Some(Box::new(expr));
} }
}
pub fn imports_to_absolute(&mut self, base: PathBuf) { pub struct Rewriter {
&base; base: PathBuf,
let rewrite_import = |e: &mut Expression| { }
impl Rewriter {
pub fn new<P: Into<PathBuf>>(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); let main_separator = format!("{}", std::path::MAIN_SEPARATOR);
if let Expression::Include(ref mut def) = e { if let Expression::Include(ref mut def) = expr {
let path = PathBuf::from(&def.path.fragment); let path = PathBuf::from(&def.path.fragment);
#[cfg(not(windows))] #[cfg(not(windows))]
{ {
if path.is_relative() { if path.is_relative() {
def.path.fragment = base def.path.fragment = self
.base
.join(path) .join(path)
.canonicalize() .canonicalize()
.unwrap() .unwrap()
@ -626,11 +638,11 @@ impl ModuleDef {
#[cfg(windows)] #[cfg(windows)]
{ {
if path.is_relative() { if path.is_relative() {
def.path.fragment = base.join(path).to_string_lossy().to_string(); def.path.fragment = self.base.join(path).to_string_lossy().to_string();
} }
} }
} }
if let Expression::Import(ref mut def) = e { if let Expression::Import(ref mut def) = expr {
let path = PathBuf::from( let path = PathBuf::from(
&def.path &def.path
.fragment .fragment
@ -644,7 +656,8 @@ impl ModuleDef {
#[cfg(not(windows))] #[cfg(not(windows))]
{ {
if path.is_relative() { if path.is_relative() {
def.path.fragment = base def.path.fragment = self
.base
.join(path) .join(path)
.canonicalize() .canonicalize()
.unwrap() .unwrap()
@ -655,15 +668,10 @@ impl ModuleDef {
#[cfg(windows)] #[cfg(windows)]
{ {
if path.is_relative() { if path.is_relative() {
def.path.fragment = base.join(path).to_string_lossy().to_string(); 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);
}
} }
} }

View File

@ -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; // noop by default;
} }
fn visit_include(&mut self, i: &mut IncludeDef) { fn visit_include(&mut self, _i: &mut IncludeDef) {
// noop by default; // noop by default;
} }
fn visit_fail(&mut self, f: &mut FailDef) { fn visit_fail(&mut self, _f: &mut FailDef) {
// noop by default; // 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. // TODO this would be better implemented as a Trait I think.

View File

@ -90,8 +90,6 @@ where
pub environment: &'a RefCell<Environment<Stdout, Stderr>>, pub environment: &'a RefCell<Environment<Stdout, Stderr>>,
working_dir: PathBuf, working_dir: PathBuf,
strict: bool, strict: bool,
// FIXME(jwall): These need to be compiled and added to the op cache.
// specifically in the environment.
std: Rc<HashMap<String, &'static str>>, std: Rc<HashMap<String, &'static str>>,
import_path: &'a Vec<PathBuf>, import_path: &'a Vec<PathBuf>,
pub last: Option<Rc<Val>>, pub last: Option<Rc<Val>>,
@ -303,12 +301,8 @@ where
} }
pub fn eval_expr(&mut self, expr: Expression) -> Result<Rc<Val>, Box<dyn Error>> { pub fn eval_expr(&mut self, expr: Expression) -> Result<Rc<Val>, Box<dyn Error>> {
let mut ops_map = translate::OpsMap::new(); let ops_map =
translate::AST::translate_stmt( translate::AST::translate(vec![Statement::Expression(expr)], &self.working_dir);
Statement::Expression(expr),
&mut ops_map,
&self.working_dir,
);
let mut vm = VM::new(self.strict, Rc::new(ops_map), &self.working_dir); let mut vm = VM::new(self.strict, Rc::new(ops_map), &self.working_dir);
if self.validate_mode { if self.validate_mode {
vm.enable_validate_mode(); vm.enable_validate_mode();

View File

@ -14,11 +14,11 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::path::Path; use std::path::Path;
use crate::ast::walk::Walker;
use crate::ast::{ use crate::ast::{
BinaryExprType, BinaryOpDef, Expression, FormatArgs, Position, PositionedItem, SelectDef, BinaryExprType, BinaryOpDef, Expression, FormatArgs, FuncOpDef, Position, PositionedItem,
Statement, Token, TokenType, Value, Rewriter, SelectDef, Statement, TemplatePart, Token, TokenType, Value,
}; };
use crate::ast::{FuncOpDef, TemplatePart};
use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser}; use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
use crate::build::opcode::Primitive; use crate::build::opcode::Primitive;
use crate::build::opcode::{Hook, Op}; use crate::build::opcode::{Hook, Op};
@ -66,13 +66,16 @@ impl OpsMap {
} }
impl AST { impl AST {
pub fn translate<P: AsRef<Path>>(stmts: Vec<Statement>, root: &P) -> OpsMap { pub fn translate<P: AsRef<Path>>(mut stmts: Vec<Statement>, 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(); let mut ops = OpsMap::new();
Self::translate_stmts(stmts, &mut ops, root.as_ref()); Self::translate_stmts(stmts, &mut ops, root.as_ref());
return ops; 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 { match stmt {
Statement::Expression(expr) => { Statement::Expression(expr) => {
let expr_pos = expr.pos().clone(); let expr_pos = expr.pos().clone();
@ -210,7 +213,6 @@ impl AST {
Self::translate_expr(*def.right.clone(), &mut ops, root); Self::translate_expr(*def.right.clone(), &mut ops, root);
// Symbols on the left side should be converted to strings to satisfy // Symbols on the left side should be converted to strings to satisfy
// the Index operation contract. // the Index operation contract.
// FIXME(jwall): List checks should not use symbol translation.
match *def.left.clone() { match *def.left.clone() {
Expression::Simple(Value::Symbol(name)) => { Expression::Simple(Value::Symbol(name)) => {
// We really just want an expression that turns a symbol // 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::Val(Primitive::Str(def.path.fragment)), def.path.pos);
ops.push(Op::Runtime(Hook::Include), def.pos); ops.push(Op::Runtime(Hook::Include), def.pos);
} }
Expression::Module(mut def) => { Expression::Module(def) => {
def.imports_to_absolute(root.to_path_buf());
let argset = def.arg_set; let argset = def.arg_set;
let out_expr = def.out_expr; let out_expr = def.out_expr;
let stmts = def.statements; let stmts = def.statements;