Refactor: Use trait constraints instead of a trait object for our assets cache.

This commit is contained in:
Jeremy Wall 2019-05-28 18:24:02 -05:00
parent fc9595ab38
commit 1589aaf7d7
4 changed files with 56 additions and 33 deletions

View File

@ -19,6 +19,7 @@ use std::error::Error;
use std::str::Chars; use std::str::Chars;
use crate::ast::*; use crate::ast::*;
use crate::build::assets;
use crate::build::{FileBuilder, Val}; use crate::build::{FileBuilder, Val};
use crate::error; use crate::error;
@ -85,13 +86,19 @@ impl<V: Into<String> + Clone> FormatRenderer for SimpleFormatter<V> {
} }
} }
pub struct ExpressionFormatter<'a> { pub struct ExpressionFormatter<'a, C>
where
C: assets::Cache,
{
tmpl: String, tmpl: String,
builder: RefCell<FileBuilder<'a>>, builder: RefCell<FileBuilder<'a, C>>,
} }
impl<'a> ExpressionFormatter<'a> { impl<'a, C> ExpressionFormatter<'a, C>
pub fn new<S: Into<String>>(tmpl: S, builder: FileBuilder<'a>) -> Self { where
C: assets::Cache,
{
pub fn new<S: Into<String>>(tmpl: S, builder: FileBuilder<'a, C>) -> Self {
ExpressionFormatter { ExpressionFormatter {
tmpl: tmpl.into(), tmpl: tmpl.into(),
builder: RefCell::new(builder), builder: RefCell::new(builder),
@ -100,7 +107,7 @@ impl<'a> ExpressionFormatter<'a> {
fn consume_expr( fn consume_expr(
&self, &self,
builder: &mut FileBuilder, builder: &mut FileBuilder<'a, C>,
iter: &mut Chars, iter: &mut Chars,
pos: &Position, pos: &Position,
) -> Result<Val, Box<dyn Error>> { ) -> Result<Val, Box<dyn Error>> {
@ -176,7 +183,10 @@ impl<'a> ExpressionFormatter<'a> {
} }
} }
impl<'a> FormatRenderer for ExpressionFormatter<'a> { impl<'a, C> FormatRenderer for ExpressionFormatter<'a, C>
where
C: assets::Cache,
{
fn render(&self, pos: &Position) -> Result<String, Box<dyn Error>> { fn render(&self, pos: &Position) -> Result<String, Box<dyn Error>> {
let mut buf = String::new(); let mut buf = String::new();
let mut should_escape = false; let mut should_escape = false;

View File

@ -53,11 +53,14 @@ enum ProcessingOpType {
impl FuncDef { impl FuncDef {
/// Expands a ucg function using the given arguments into a new Val. /// Expands a ucg function using the given arguments into a new Val.
pub fn eval( pub fn eval<C>(
&self, &self,
parent_builder: &FileBuilder, parent_builder: &FileBuilder<C>,
mut args: Vec<Rc<Val>>, mut args: Vec<Rc<Val>>,
) -> Result<Rc<Val>, Box<dyn Error>> { ) -> Result<Rc<Val>, Box<dyn Error>>
where
C: assets::Cache,
{
// Error conditions. If the args don't match the length and types of the argdefs then this is // Error conditions. If the args don't match the length and types of the argdefs then this is
// func call error. // func call error.
if args.len() > self.argdefs.len() { if args.len() > self.argdefs.len() {
@ -98,7 +101,10 @@ pub struct AssertCollector {
} }
/// Builder handles building ucg code for a single file. /// Builder handles building ucg code for a single file.
pub struct FileBuilder<'a> { pub struct FileBuilder<'a, C>
where
C: assets::Cache,
{
working_dir: PathBuf, working_dir: PathBuf,
std: Rc<HashMap<String, &'static str>>, std: Rc<HashMap<String, &'static str>>,
import_path: &'a Vec<PathBuf>, import_path: &'a Vec<PathBuf>,
@ -117,7 +123,7 @@ pub struct FileBuilder<'a> {
// are keyed by the canonicalized import path. This acts as a cache // are keyed by the canonicalized import path. This acts as a cache
// so multiple imports of the same file don't have to be parsed // so multiple imports of the same file don't have to be parsed
// multiple times. // multiple times.
assets: Rc<RefCell<assets::Cache>>, assets: Rc<RefCell<C>>,
pub is_module: bool, pub is_module: bool,
pub last: Option<Rc<Val>>, pub last: Option<Rc<Val>>,
pub out_lock: Option<(String, Rc<Val>)>, pub out_lock: Option<(String, Rc<Val>)>,
@ -141,12 +147,15 @@ macro_rules! eval_binary_expr {
}; };
} }
impl<'a> FileBuilder<'a> { impl<'a, C> FileBuilder<'a, C>
where
C: assets::Cache,
{
/// Constructs a new Builder. /// Constructs a new Builder.
pub fn new<P: Into<PathBuf>>( pub fn new<P: Into<PathBuf>>(
working_dir: P, working_dir: P,
import_paths: &'a Vec<PathBuf>, import_paths: &'a Vec<PathBuf>,
cache: Rc<RefCell<assets::Cache>>, cache: Rc<RefCell<C>>,
) -> Self { ) -> Self {
let env_vars: Vec<(String, String)> = env::vars().collect(); let env_vars: Vec<(String, String)> = env::vars().collect();
let scope = scope::Scope::new(Rc::new(Val::Env(env_vars))); let scope = scope::Scope::new(Rc::new(Val::Env(env_vars)));

View File

@ -11,6 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::assets;
use super::assets::MemoryCache; use super::assets::MemoryCache;
use super::{FileBuilder, SelectDef, Val}; use super::{FileBuilder, SelectDef, Val};
use crate::ast::*; use crate::ast::*;
@ -19,7 +20,10 @@ use std;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
fn test_expr_to_val(mut cases: Vec<(Expression, Val)>, b: FileBuilder) { fn test_expr_to_val<'a, C: assets::Cache>(
mut cases: Vec<(Expression, Val)>,
b: FileBuilder<'a, C>,
) {
for tpl in cases.drain(0..) { for tpl in cases.drain(0..) {
assert_eq!( assert_eq!(
b.eval_expr(&tpl.0, &b.scope.spawn_child()).unwrap(), b.eval_expr(&tpl.0, &b.scope.spawn_child()).unwrap(),

View File

@ -93,13 +93,13 @@ fn run_converter(c: &traits::Converter, v: Rc<Val>, f: Option<&str>) -> traits::
c.convert(v, file.as_mut()) c.convert(v, file.as_mut())
} }
fn build_file<'a>( fn build_file<'a, C: Cache>(
file: &'a str, file: &'a str,
validate: bool, validate: bool,
strict: bool, strict: bool,
import_paths: &'a Vec<PathBuf>, import_paths: &'a Vec<PathBuf>,
cache: Rc<RefCell<Cache>>, cache: Rc<RefCell<C>>,
) -> Result<build::FileBuilder<'a>, Box<dyn Error>> { ) -> Result<build::FileBuilder<'a, C>, Box<dyn Error>> {
let mut file_path_buf = PathBuf::from(file); let mut file_path_buf = PathBuf::from(file);
if file_path_buf.is_relative() { if file_path_buf.is_relative() {
file_path_buf = std::env::current_dir()?.join(file_path_buf); file_path_buf = std::env::current_dir()?.join(file_path_buf);
@ -116,11 +116,11 @@ fn build_file<'a>(
Ok(builder) Ok(builder)
} }
fn do_validate( fn do_validate<C: Cache>(
file: &str, file: &str,
strict: bool, strict: bool,
import_paths: &Vec<PathBuf>, import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>, cache: Rc<RefCell<C>>,
) -> bool { ) -> bool {
println!("Validating {}", file); println!("Validating {}", file);
match build_file(file, true, strict, import_paths, cache) { match build_file(file, true, strict, import_paths, cache) {
@ -140,11 +140,11 @@ fn do_validate(
return true; return true;
} }
fn do_compile( fn do_compile<C: Cache>(
file: &str, file: &str,
strict: bool, strict: bool,
import_paths: &Vec<PathBuf>, import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>, cache: Rc<RefCell<C>>,
registry: &ConverterRegistry, registry: &ConverterRegistry,
) -> bool { ) -> bool {
println!("Building {}", file); println!("Building {}", file);
@ -175,13 +175,13 @@ fn do_compile(
} }
} }
fn visit_ucg_files( fn visit_ucg_files<C: Cache>(
path: &Path, path: &Path,
recurse: bool, recurse: bool,
validate: bool, validate: bool,
strict: bool, strict: bool,
import_paths: &Vec<PathBuf>, import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>, cache: Rc<RefCell<C>>,
registry: &ConverterRegistry, registry: &ConverterRegistry,
) -> Result<bool, Box<dyn Error>> { ) -> Result<bool, Box<dyn Error>> {
let our_path = String::from(path.to_string_lossy()); let our_path = String::from(path.to_string_lossy());
@ -252,10 +252,10 @@ fn visit_ucg_files(
Ok(result) Ok(result)
} }
fn inspect_command( fn inspect_command<C: Cache>(
matches: &clap::ArgMatches, matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>, import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>, cache: Rc<RefCell<C>>,
registry: &ConverterRegistry, registry: &ConverterRegistry,
strict: bool, strict: bool,
) { ) {
@ -315,10 +315,10 @@ fn inspect_command(
} }
} }
fn build_command( fn build_command<C: Cache>(
matches: &clap::ArgMatches, matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>, import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>, cache: Rc<RefCell<C>>,
registry: &ConverterRegistry, registry: &ConverterRegistry,
strict: bool, strict: bool,
) { ) {
@ -414,10 +414,10 @@ fn fmt_command(matches: &clap::ArgMatches) -> std::result::Result<(), Box<dyn Er
Ok(()) Ok(())
} }
fn test_command( fn test_command<C: Cache>(
matches: &clap::ArgMatches, matches: &clap::ArgMatches,
import_paths: &Vec<PathBuf>, import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>, cache: Rc<RefCell<C>>,
registry: &ConverterRegistry, registry: &ConverterRegistry,
strict: bool, strict: bool,
) { ) {
@ -513,9 +513,9 @@ fn env_help() {
); );
} }
fn do_repl( fn do_repl<C: Cache>(
import_paths: &Vec<PathBuf>, import_paths: &Vec<PathBuf>,
cache: Rc<RefCell<Cache>>, cache: Rc<RefCell<C>>,
) -> std::result::Result<(), Box<dyn Error>> { ) -> std::result::Result<(), Box<dyn Error>> {
let config = rustyline::Config::builder(); let config = rustyline::Config::builder();
let mut editor = rustyline::Editor::<()>::with_config( let mut editor = rustyline::Editor::<()>::with_config(
@ -580,7 +580,7 @@ fn do_repl(
} }
} }
fn repl(import_paths: &Vec<PathBuf>, cache: Rc<RefCell<Cache>>) { fn repl<C: Cache>(import_paths: &Vec<PathBuf>, cache: Rc<RefCell<C>>) {
if let Err(e) = do_repl(import_paths, cache) { if let Err(e) = do_repl(import_paths, cache) {
eprintln!("{}", e); eprintln!("{}", e);
process::exit(1); process::exit(1);
@ -590,7 +590,7 @@ fn repl(import_paths: &Vec<PathBuf>, cache: Rc<RefCell<Cache>>) {
fn main() { fn main() {
let mut app = do_flags(); let mut app = do_flags();
let app_matches = app.clone().get_matches(); let app_matches = app.clone().get_matches();
let cache: Rc<RefCell<Cache>> = Rc::new(RefCell::new(MemoryCache::new())); let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry(); let registry = ConverterRegistry::make_registry();
let mut import_paths = Vec::new(); let mut import_paths = Vec::new();
if let Some(mut p) = dirs::home_dir() { if let Some(mut p) = dirs::home_dir() {