From 7a8b8e46eb992565493247d069c187ae1ccdbb2e Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Mon, 25 May 2020 13:26:57 -0400 Subject: [PATCH] DEV: Link all the packages upfront --- src/build/mod.rs | 44 ++++++++++++++++++++++++++++------- src/build/opcode/mod.rs | 2 +- src/build/opcode/runtime.rs | 2 ++ src/build/opcode/translate.rs | 8 +++---- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/build/mod.rs b/src/build/mod.rs index f1c9651..337d09a 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -14,8 +14,7 @@ //! The build stage of the ucg compiler. use std::cell::RefCell; -use std::collections::HashMap; -use std::convert::TryInto; +use std::collections::{BTreeSet, HashMap}; use std::error::Error; use std::path::PathBuf; use std::process; @@ -28,6 +27,7 @@ use rustyline::error::ReadlineError; use simple_error; use crate::ast::*; +#[macro_use] use crate::build::opcode::pointer::OpPointer; use crate::build::opcode::translate; use crate::build::opcode::translate::OpsMap; @@ -168,7 +168,34 @@ where self.validate_mode = true; } + fn link_ops(&self, ops: &OpPointer) -> BuildResult { + let mut links = Vec::new(); + for (link, pos) in &ops.pos_map.links { + links.push((link.clone(), pos.clone())); + } + let mut found = BTreeSet::new(); + loop { + let (link, path_pos) = match links.pop() { + Some(t) => t, + None => break, + }; + if found.contains(&link) { + continue; + } + let ops = match self.environment.borrow_mut().get_ops_for_path(link.clone()) { + Ok(ops) => ops, + Err(e) => return Err(Box::new(e.with_pos(path_pos))), + }; + found.insert(link); + for (link, pos) in &ops.pos_map.links { + links.push((link.clone(), pos.clone())); + } + } + Ok(()) + } + fn eval_ops(&mut self, ops: OpPointer, path: Option) -> BuildResult { + self.link_ops(&ops)?; let mut vm = VM::with_pointer(self.strict, ops, &self.working_dir); if path.is_some() { vm.set_path(path.unwrap()); @@ -303,13 +330,12 @@ where pub fn eval_expr(&mut self, expr: Expression) -> Result, Box> { 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(); - } - vm.run(self.environment)?; - if let Some((val, _)) = vm.last.clone() { - return Ok(Rc::new(val.try_into()?)); + self.eval_ops( + OpPointer::new(Rc::new(ops_map)), + Some(self.working_dir.clone()), + )?; + if let Some(val) = &self.last { + return Ok(val.clone()); } unreachable!(); } diff --git a/src/build/opcode/mod.rs b/src/build/opcode/mod.rs index 42d46e6..4e25627 100644 --- a/src/build/opcode/mod.rs +++ b/src/build/opcode/mod.rs @@ -18,7 +18,7 @@ mod debug; mod display; pub mod environment; #[macro_use] -mod error; +pub mod error; mod convert; pub mod pointer; mod runtime; diff --git a/src/build/opcode/runtime.rs b/src/build/opcode/runtime.rs index 7f90628..9ca3331 100644 --- a/src/build/opcode/runtime.rs +++ b/src/build/opcode/runtime.rs @@ -194,6 +194,8 @@ impl Builtins { let path = stack.pop(); if let Some((val, path_pos)) = path { if let &Value::P(Str(ref path)) = val.as_ref() { + // FIXME(jwall): Most of this is no longer necessary since + // we do it before hand at the linker step. // TODO(jwall): A bit hacky we should probably change import stacks to be pathbufs. let normalized = decorate_error!(path_pos => self.normalize_path(base_path, false, path))?; diff --git a/src/build/opcode/translate.rs b/src/build/opcode/translate.rs index 73225e4..bc38fff 100644 --- a/src/build/opcode/translate.rs +++ b/src/build/opcode/translate.rs @@ -29,7 +29,7 @@ pub struct AST(); pub struct OpsMap { pub ops: Vec, pub pos: Vec, - pub links: BTreeMap, + pub links: BTreeMap, } impl OpsMap { @@ -47,8 +47,8 @@ impl OpsMap { self } - pub fn add_link(&mut self, path: String) { - self.links.insert(path, self.len() - 1); + pub fn add_link(&mut self, path: String, pos: Position) { + self.links.insert(path, pos); } pub fn len(&self) -> usize { @@ -444,9 +444,9 @@ impl AST { } Expression::Import(def) => { let link_path = def.path.fragment.clone(); + ops.add_link(link_path, def.path.pos.clone()); ops.push(Op::Val(Primitive::Str(def.path.fragment)), def.path.pos); ops.push(Op::Runtime(Hook::Import), def.pos); - ops.add_link(link_path); } Expression::Include(def) => { ops.push(Op::Val(Primitive::Str(def.typ.fragment)), def.typ.pos);