2019-08-17 12:57:40 -05:00
|
|
|
// Copyright 2019 Jeremy Wall
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2019-09-01 19:21:02 -05:00
|
|
|
use std::collections::{BTreeMap, BTreeSet};
|
2019-08-26 21:24:17 -05:00
|
|
|
use std::fs::File;
|
2019-08-28 19:11:09 -05:00
|
|
|
use std::io::{Read, Write};
|
2019-09-01 19:21:02 -05:00
|
|
|
use std::path::{Path, PathBuf};
|
2019-08-28 19:11:09 -05:00
|
|
|
use std::rc::Rc;
|
2019-08-17 12:57:40 -05:00
|
|
|
|
|
|
|
use super::cache;
|
2019-08-28 19:11:09 -05:00
|
|
|
use super::pointer::OpPointer;
|
2019-08-26 21:24:17 -05:00
|
|
|
use super::Error;
|
2019-08-28 19:11:09 -05:00
|
|
|
use super::Value;
|
2019-12-09 20:11:42 -06:00
|
|
|
use crate::build::stdlib;
|
2019-09-01 10:21:05 -05:00
|
|
|
use crate::build::AssertCollector;
|
2019-09-02 17:22:58 -05:00
|
|
|
use crate::build::Val;
|
2019-08-17 12:57:40 -05:00
|
|
|
use crate::convert::{ConverterRegistry, ImporterRegistry};
|
2019-08-26 21:24:17 -05:00
|
|
|
use crate::iter::OffsetStrIter;
|
|
|
|
use crate::parse::parse;
|
2019-08-17 12:57:40 -05:00
|
|
|
|
|
|
|
// Shared Environmental between VM's for runtime usage.
|
|
|
|
pub struct Environment<Stdout, Stderr>
|
|
|
|
where
|
2019-09-02 17:22:58 -05:00
|
|
|
Stdout: Write + Clone,
|
|
|
|
Stderr: Write + Clone,
|
2019-08-17 12:57:40 -05:00
|
|
|
{
|
|
|
|
pub val_cache: BTreeMap<String, Rc<Value>>,
|
2019-08-26 21:24:17 -05:00
|
|
|
pub op_cache: cache::Ops,
|
|
|
|
pub converter_registry: ConverterRegistry,
|
|
|
|
pub importer_registry: ImporterRegistry,
|
2019-09-01 10:21:05 -05:00
|
|
|
pub assert_results: AssertCollector,
|
2019-08-26 21:24:17 -05:00
|
|
|
pub stdout: Stdout,
|
|
|
|
pub stderr: Stderr,
|
|
|
|
pub env_vars: BTreeMap<String, String>, // Environment Variables
|
2019-09-01 19:21:02 -05:00
|
|
|
pub out_lock: BTreeSet<PathBuf>,
|
2019-08-17 12:57:40 -05:00
|
|
|
}
|
|
|
|
|
2019-09-02 17:22:58 -05:00
|
|
|
impl<Stdout: Write + Clone, Stderr: Write + Clone> Environment<Stdout, Stderr> {
|
2019-08-17 12:57:40 -05:00
|
|
|
pub fn new(out: Stdout, err: Stderr) -> Self {
|
2019-08-26 21:24:17 -05:00
|
|
|
Self::new_with_vars(out, err, BTreeMap::new())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_with_vars(out: Stdout, err: Stderr, vars: BTreeMap<String, String>) -> Self {
|
2019-08-17 12:57:40 -05:00
|
|
|
Self {
|
|
|
|
val_cache: BTreeMap::new(),
|
2019-08-26 21:24:17 -05:00
|
|
|
env_vars: vars,
|
2019-08-17 12:57:40 -05:00
|
|
|
op_cache: cache::Ops::new(),
|
2019-09-01 10:21:05 -05:00
|
|
|
assert_results: AssertCollector::new(),
|
2019-08-17 12:57:40 -05:00
|
|
|
converter_registry: ConverterRegistry::make_registry(),
|
|
|
|
importer_registry: ImporterRegistry::make_registry(),
|
|
|
|
stdout: out,
|
|
|
|
stderr: err,
|
2019-09-01 19:21:02 -05:00
|
|
|
out_lock: BTreeSet::new(),
|
2019-08-17 12:57:40 -05:00
|
|
|
}
|
|
|
|
}
|
2019-08-26 21:24:17 -05:00
|
|
|
|
|
|
|
pub fn get_cached_path_val(&self, path: &String) -> Option<Rc<Value>> {
|
|
|
|
self.val_cache.get(path).cloned()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_path_val(&mut self, path: &String, val: Rc<Value>) {
|
|
|
|
self.val_cache.insert(path.clone(), val);
|
|
|
|
}
|
|
|
|
|
2019-09-02 10:10:24 -05:00
|
|
|
pub fn get_ops_for_path<P>(&mut self, path: P) -> Result<OpPointer, Error>
|
|
|
|
where
|
|
|
|
P: Into<PathBuf> + Clone,
|
|
|
|
{
|
|
|
|
let path_copy = path.clone();
|
|
|
|
self.op_cache.entry(path.clone()).get_pointer_or_else(
|
2019-08-26 21:24:17 -05:00
|
|
|
|| {
|
|
|
|
// FIXME(jwall): We need to do proper error handling here.
|
2019-09-02 10:10:24 -05:00
|
|
|
let p = path.into();
|
2019-08-26 21:24:17 -05:00
|
|
|
let root = p.parent().unwrap();
|
|
|
|
// first we read in the file
|
2019-09-02 10:10:24 -05:00
|
|
|
let mut f = File::open(&p)?;
|
2019-08-26 21:24:17 -05:00
|
|
|
// then we parse it
|
|
|
|
let mut contents = String::new();
|
2019-08-28 19:11:09 -05:00
|
|
|
f.read_to_string(&mut contents)?;
|
2019-08-26 21:24:17 -05:00
|
|
|
let iter = OffsetStrIter::new(&contents).with_src_file(&p);
|
2019-08-28 19:11:09 -05:00
|
|
|
// FIXME(jwall): Unify BuildError and our other Error
|
2019-08-26 21:24:17 -05:00
|
|
|
let stmts = parse(iter, None).unwrap();
|
|
|
|
// then we create an ops from it
|
|
|
|
let ops = super::translate::AST::translate(stmts, &root);
|
2019-08-28 19:11:09 -05:00
|
|
|
Ok(ops)
|
2019-08-26 21:24:17 -05:00
|
|
|
},
|
2019-09-02 10:10:24 -05:00
|
|
|
path_copy,
|
2019-08-28 19:11:09 -05:00
|
|
|
)
|
2019-08-26 21:24:17 -05:00
|
|
|
}
|
2019-09-01 10:21:05 -05:00
|
|
|
|
2019-12-09 20:11:42 -06:00
|
|
|
fn add_ops_for_path_and_content<P>(&mut self, path: P, contents: &str) -> Result<(), Error>
|
|
|
|
where
|
|
|
|
P: Into<PathBuf> + Clone,
|
|
|
|
{
|
|
|
|
let path_copy = path.clone();
|
|
|
|
self.op_cache.entry(path.clone()).get_pointer_or_else(
|
|
|
|
|| {
|
|
|
|
let p = path.into();
|
|
|
|
let root = p.parent().unwrap();
|
|
|
|
let iter = OffsetStrIter::new(contents).with_src_file(&p);
|
|
|
|
// FIXME(jwall): Unify BuildError and our other Error
|
|
|
|
let stmts = parse(iter, None).unwrap();
|
|
|
|
// then we create an ops from it
|
|
|
|
let ops = super::translate::AST::translate(stmts, &root);
|
|
|
|
Ok(ops)
|
|
|
|
},
|
|
|
|
path_copy,
|
|
|
|
)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn populate_stdlib(&mut self) {
|
|
|
|
for (p, s) in stdlib::get_libs().drain() {
|
|
|
|
// We unwrap the error here since we expect stdlibs to
|
|
|
|
// always compile.
|
|
|
|
self.add_ops_for_path_and_content(p, s).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-01 10:21:05 -05:00
|
|
|
pub fn record_assert_result(&mut self, desc: &str, ok: bool) {
|
|
|
|
self.assert_results.record_assert_result(desc, ok);
|
|
|
|
}
|
2019-09-01 19:21:02 -05:00
|
|
|
|
|
|
|
pub fn get_out_lock_for_path<P: AsRef<Path>>(&self, path: P) -> bool {
|
|
|
|
self.out_lock.contains(path.as_ref())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_out_lock_for_path<P: Into<PathBuf>>(&mut self, path: P) {
|
|
|
|
self.out_lock.insert(path.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn reset_out_lock_for_path<P: AsRef<Path>>(&mut self, path: P) {
|
|
|
|
self.out_lock.remove(path.as_ref());
|
|
|
|
}
|
2019-09-02 17:22:58 -05:00
|
|
|
|
|
|
|
pub fn stdout(&self) -> Stdout {
|
|
|
|
self.stdout.clone()
|
|
|
|
}
|
|
|
|
pub fn stderr(&self) -> Stderr {
|
|
|
|
self.stderr.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn convert_val(&mut self, typ: &str, writer: &mut dyn Write, val: Rc<Val>) -> bool {
|
|
|
|
match self.converter_registry.get_converter(typ) {
|
|
|
|
Some(c) => {
|
|
|
|
if let Err(e) = c.convert(val, writer) {
|
|
|
|
writeln!(&mut self.stderr, "{}", e).unwrap();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
writeln!(
|
|
|
|
&mut self.stderr,
|
|
|
|
"No such format {}\nrun `ucg converters` to see available formats.",
|
|
|
|
typ
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2019-08-17 12:57:40 -05:00
|
|
|
}
|