1use crate::engine::{Config, Engine, ImportKey, SourceRead};
6use crate::vfs::VirtualFs;
7use crate::ErrorList;
8use go_parser::Map;
9use std::io;
10use std::path::{Path, PathBuf};
11use std::rc::Rc;
12
13pub fn run(
14 config: Config,
15 source: &SourceReader,
16 path: &Path,
17 panic_handler: Option<Rc<dyn Fn(String, String)>>,
18) -> Result<(), ErrorList> {
19 let engine = Engine::new();
20 #[cfg(feature = "go_std")]
21 engine.set_std_io(config.std_in, config.std_out, config.std_err);
22 engine.run_source(
23 config.trace_parser,
24 config.trace_checker,
25 source,
26 path,
27 panic_handler,
28 )
29}
30
31pub struct SourceReader {
32 base_dir: Option<PathBuf>,
34 working_dir: PathBuf,
36 vfs: Box<dyn VirtualFs>,
38}
39
40impl SourceReader {
41 pub fn new(
42 base_dir: Option<PathBuf>,
43 working_dir: PathBuf,
44 vfs: Box<dyn VirtualFs>,
45 ) -> SourceReader {
46 SourceReader {
47 base_dir,
48 working_dir,
49 vfs,
50 }
51 }
52
53 #[cfg(feature = "read_fs")]
55 pub fn local_fs(base_dir: PathBuf, working_dir: PathBuf) -> SourceReader {
56 SourceReader::new(Some(base_dir), working_dir, Box::new(crate::VfsFs {}))
57 }
58
59 #[cfg(feature = "read_fs")]
61 pub fn fs_lib_and_string(
62 base_dir: PathBuf,
63 source: std::borrow::Cow<'static, str>,
64 ) -> (SourceReader, PathBuf) {
65 let temp_file_name = "temp_file.gos";
66 let vfs_map_name = "vfs_map";
67 let vfs_fs_name = "vfs_fs";
68 (
69 SourceReader::new(
70 Some(Path::new(vfs_fs_name).join(base_dir)),
71 PathBuf::from(format!("{}/", vfs_map_name)),
72 Box::new(crate::CompoundFs::new(Map::from([
73 (
74 vfs_fs_name.to_owned(),
75 Box::new(crate::VfsFs {}) as Box<dyn VirtualFs>,
76 ),
77 (
78 vfs_map_name.to_owned(),
79 Box::new(crate::VfsMap::new(Map::from([(
80 PathBuf::from(temp_file_name),
81 source,
82 )]))),
83 ),
84 ]))),
85 ),
86 PathBuf::from(format!("./{}", temp_file_name)),
87 )
88 }
89
90 #[cfg(feature = "read_zip")]
93 pub fn zip_lib_and_string(
94 archive: std::borrow::Cow<'static, [u8]>,
95 base_dir: PathBuf,
96 source: std::borrow::Cow<'static, str>,
97 ) -> (SourceReader, PathBuf) {
98 let temp_file_name = "temp_file.gos";
99 let vfs_map_name = "vfs_map";
100 let vfs_zip_name = "vfs_zip";
101 (
102 SourceReader::new(
103 Some(Path::new(vfs_zip_name).join(base_dir)),
104 PathBuf::from(format!("{}/", vfs_map_name)),
105 Box::new(crate::CompoundFs::new(Map::from([
106 (
107 vfs_zip_name.to_owned(),
108 Box::new(crate::VfsZip::new(archive).unwrap()) as Box<dyn VirtualFs>,
109 ),
110 (
111 vfs_map_name.to_owned(),
112 Box::new(crate::VfsMap::new(Map::from([(
113 PathBuf::from(temp_file_name),
114 source,
115 )]))),
116 ),
117 ]))),
118 ),
119 PathBuf::from(format!("./{}", temp_file_name)),
120 )
121 }
122
123 #[cfg(feature = "read_zip")]
127 pub fn zip_lib_and_local_fs(
128 archive: std::borrow::Cow<'static, [u8]>,
129 base_dir: PathBuf,
130 working_dir: PathBuf,
131 ) -> SourceReader {
132 let vfs_fs_name = "local_fs";
133 let vfs_zip_name = "vfs_zip";
134
135 SourceReader::new(
136 Some(Path::new(vfs_zip_name).join(base_dir)),
137 Path::new(&vfs_fs_name).join(working_dir),
138 Box::new(crate::CompoundFs::new(Map::from([
139 (
140 vfs_fs_name.to_owned(),
141 Box::new(crate::VfsFs {}) as Box<dyn VirtualFs>,
142 ),
143 (
144 vfs_zip_name.to_owned(),
145 Box::new(crate::VfsZip::new(archive).unwrap()) as Box<dyn VirtualFs>,
146 ),
147 ]))),
148 )
149 }
150}
151
152impl SourceRead for SourceReader {
153 fn working_dir(&self) -> &Path {
154 &self.working_dir
155 }
156
157 fn base_dir(&self) -> Option<&Path> {
158 self.base_dir.as_ref().map(|x| x.as_path())
159 }
160
161 fn read_file(&self, path: &Path) -> io::Result<String> {
162 self.vfs.read_file(path)
163 }
164
165 fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
166 self.vfs.read_dir(path)
167 }
168
169 fn is_file(&self, path: &Path) -> bool {
170 self.vfs.is_file(path)
171 }
172
173 fn is_dir(&self, path: &Path) -> bool {
174 self.vfs.is_dir(path)
175 }
176
177 fn canonicalize_import(&self, key: &ImportKey) -> io::Result<(PathBuf, String)> {
178 let mut import_path = key.path.clone();
179 let path = if self.vfs.is_local(&key.path) {
180 let mut wd = self.working_dir().to_owned();
181 wd.push(self.vfs.strip_prefix(Path::new(&key.dir)));
182 wd.push(&key.path);
183 if let Some(base) = &self.base_dir() {
184 if let Ok(rel) = wd.as_path().strip_prefix(base) {
185 import_path = rel.to_string_lossy().to_string()
186 }
187 }
188 wd
189 } else {
190 if let Some(base) = &self.base_dir() {
191 let mut p = PathBuf::new();
192 p.push(base);
193 p.push(&key.path);
194 p
195 } else {
196 return Err(io::Error::new(
197 io::ErrorKind::Other,
198 format!("base dir required for path: {}", key.path),
199 ));
200 }
201 };
202 self.vfs.canonicalize_path(&path).map(|p| (p, import_path))
203 }
204}