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,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<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);
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);
}
}
}

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;
}
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.

View File

@ -90,8 +90,6 @@ where
pub environment: &'a RefCell<Environment<Stdout, Stderr>>,
working_dir: PathBuf,
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>>,
import_path: &'a Vec<PathBuf>,
pub last: Option<Rc<Val>>,
@ -303,12 +301,8 @@ where
}
pub fn eval_expr(&mut self, expr: Expression) -> Result<Rc<Val>, Box<dyn Error>> {
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();

View File

@ -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<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();
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;