ucglib/build/opcode/
environment.rs1use std::collections::{BTreeMap, BTreeSet};
15use std::fs::File;
16use std::io::{Read, Write};
17use std::path::{Path, PathBuf};
18use std::rc::Rc;
19
20use super::pointer::OpPointer;
21use super::Error;
22use super::{cache, Primitive};
23use super::{Composite, Value};
24use crate::build::AssertCollector;
25use crate::build::Val;
26use crate::convert::{ConverterRegistry, ImporterRegistry};
27use crate::iter::OffsetStrIter;
28use crate::parse::parse;
29use crate::{ast::Position, build::stdlib};
30
31pub struct Environment<Stdout, Stderr>
33where
34 Stdout: Write + Clone,
35 Stderr: Write + Clone,
36{
37 pub val_cache: BTreeMap<String, Rc<Value>>,
38 pub op_cache: cache::Ops,
39 pub converter_registry: ConverterRegistry,
40 pub importer_registry: ImporterRegistry,
41 pub assert_results: AssertCollector,
42 pub stdout: Stdout,
43 pub stderr: Stderr,
44 pub env_vars: BTreeMap<String, String>, pub out_lock: BTreeSet<PathBuf>,
46}
47
48impl<Stdout: Write + Clone, Stderr: Write + Clone> Environment<Stdout, Stderr> {
49 pub fn new(out: Stdout, err: Stderr) -> Self {
50 Self::new_with_vars(out, err, BTreeMap::new())
52 }
53
54 pub fn new_with_vars(out: Stdout, err: Stderr, vars: BTreeMap<String, String>) -> Self {
55 let mut me = Self {
56 val_cache: BTreeMap::new(),
57 env_vars: vars,
58 op_cache: cache::Ops::new(),
59 assert_results: AssertCollector::new(),
60 converter_registry: ConverterRegistry::make_registry(),
61 importer_registry: ImporterRegistry::make_registry(),
62 stdout: out,
63 stderr: err,
64 out_lock: BTreeSet::new(),
65 };
66 me.populate_stdlib();
67 return me;
68 }
69
70 pub fn get_env_vars_tuple(&self) -> Value {
71 let mut fields = Vec::new();
72 let mut positions = Vec::new();
73 for (key, val) in self.env_vars.iter() {
74 fields.push((key.clone(), Rc::new(Value::P(Primitive::Str(val.clone())))));
75 positions.push((Position::new(0, 0, 0), Position::new(0, 0, 0)));
76 }
77 Value::C(Composite::Tuple(fields, positions))
78 }
79
80 pub fn get_cached_path_val(&self, path: &String) -> Option<Rc<Value>> {
81 self.val_cache.get(path).cloned()
82 }
83
84 pub fn update_path_val(&mut self, path: &String, val: Rc<Value>) {
85 self.val_cache.insert(path.clone(), val);
86 }
87
88 pub fn get_ops_for_path<P>(&mut self, path: P) -> Result<OpPointer, Error>
89 where
90 P: Into<PathBuf> + Clone,
91 {
92 let path_copy = path.clone();
93 self.op_cache.entry(path.clone()).get_pointer_or_else(
94 || {
95 let p = path.into();
97 let root = p.parent().unwrap();
98 let mut f = File::open(&p)?;
100 let mut contents = String::new();
102 f.read_to_string(&mut contents)?;
103 let iter = OffsetStrIter::new(&contents).with_src_file(&p);
104 let stmts = parse(iter, None).unwrap();
106 let ops = super::translate::AST::translate(stmts, &root);
108 Ok(ops)
109 },
110 path_copy,
111 )
112 }
113
114 fn add_ops_for_path_and_content<P>(&mut self, path: P, contents: &str) -> Result<(), Error>
115 where
116 P: Into<PathBuf> + Clone,
117 {
118 let path_copy = path.clone();
119 self.op_cache.entry(path.clone()).get_pointer_or_else(
120 || {
121 let p = path.into();
122 let root = p.parent().unwrap();
123 let iter = OffsetStrIter::new(contents).with_src_file(&p);
124 let stmts = parse(iter, None).unwrap();
126 let ops = super::translate::AST::translate(stmts, &root);
128 Ok(ops)
129 },
130 path_copy,
131 )?;
132 Ok(())
133 }
134
135 fn populate_stdlib(&mut self) {
136 for (p, s) in stdlib::get_libs().drain() {
137 self.add_ops_for_path_and_content(p, s).unwrap();
140 }
141 }
142
143 pub fn record_assert_result(&mut self, desc: &str, ok: bool) {
144 self.assert_results.record_assert_result(desc, ok);
145 }
146
147 pub fn get_out_lock_for_path<P: AsRef<Path>>(&self, path: P) -> bool {
148 self.out_lock.contains(path.as_ref())
149 }
150
151 pub fn set_out_lock_for_path<P: Into<PathBuf>>(&mut self, path: P) {
152 self.out_lock.insert(path.into());
153 }
154
155 pub fn reset_out_lock_for_path<P: AsRef<Path>>(&mut self, path: P) {
156 self.out_lock.remove(path.as_ref());
157 }
158
159 pub fn stdout(&self) -> Stdout {
160 self.stdout.clone()
161 }
162 pub fn stderr(&self) -> Stderr {
163 self.stderr.clone()
164 }
165
166 pub fn convert_val(&mut self, typ: &str, writer: &mut dyn Write, val: Rc<Val>) -> bool {
167 match self.converter_registry.get_converter(typ) {
168 Some(c) => {
169 if let Err(e) = c.convert(val, writer) {
170 writeln!(&mut self.stderr, "{}", e).unwrap();
171 return false;
172 }
173 }
174 None => {
175 writeln!(
176 &mut self.stderr,
177 "No such format {}\nrun `ucg converters` to see available formats.",
178 typ
179 )
180 .unwrap();
181 return false;
182 }
183 }
184 return true;
185 }
186}