1#![allow(dead_code)]
27
28#![allow(unused_macros)]
30
31#![allow(clippy::upper_case_acronyms)]
33
34pub mod data;
36pub mod compiler;
37pub mod runtime;
38
39mod collections;
41mod convert;
42mod format;
43mod func;
44mod lang;
45mod modres;
46mod rng;
47mod selector;
48mod stdlib;
49mod string;
50mod util;
51mod value;
52mod var;
53
54pub use crate::collections::*;
56pub use crate::convert::*;
57pub use crate::string::*;
58pub use crate::value::*;
59pub use crate::func::*;
60pub use crate::var::*;
61pub use crate::modres::*;
62pub use crate::selector::*;
63
64use crate::compiler::*;
65use crate::lang::Sequence;
66use crate::rng::RantRng;
67use crate::runtime::{RuntimeResult, IntoRuntimeResult, RuntimeError, RuntimeErrorType, VM};
68
69use std::error::Error;
70use std::{path::Path, rc::Rc, fmt::Display, path::PathBuf, collections::HashMap};
71use std::env;
72use data::DataSource;
73use fnv::FnvBuildHasher;
74use rand::Rng;
75
76type IOErrorKind = std::io::ErrorKind;
77
78pub(crate) type InternalString = smartstring::alias::CompactString;
79
80pub const BUILD_VERSION: &str = env!("CARGO_PKG_VERSION");
82
83pub const RANT_LANG_VERSION: &str = "4.0";
85
86pub const DEFAULT_PROGRAM_NAME: &str = "program";
88
89pub const RANT_FILE_EXTENSION: &str = "rant";
91
92pub(crate) const MODULES_CACHE_KEY: &str = "__MODULES";
94
95#[derive(Debug)]
97pub struct Rant {
98 options: RantOptions,
99 module_resolver: Rc<dyn ModuleResolver>,
100 rng: Rc<RantRng>,
101 data_sources: HashMap<InternalString, Box<dyn DataSource>, FnvBuildHasher>,
102 globals: HashMap<InternalString, RantVar, FnvBuildHasher>,
103}
104
105impl Rant {
106 #[inline(always)]
108 pub fn new() -> Self {
109 Self::with_seed(0)
110 }
111
112 pub fn with_seed(seed: u64) -> Self {
114 Self::with_options(RantOptions {
115 seed,
116 .. Default::default()
117 })
118 }
119
120 pub fn with_random_seed() -> Self {
122 Self::with_options(RantOptions {
123 seed: rand::thread_rng().gen(),
124 .. Default::default()
125 })
126 }
127
128 #[inline(always)]
130 pub fn with_options(options: RantOptions) -> Self {
131 let mut rant = Self {
132 module_resolver: Rc::new(DefaultModuleResolver::default()),
133 globals: Default::default(),
134 data_sources: Default::default(),
135 rng: Rc::new(RantRng::new(options.seed)),
136 options,
137 };
138
139 if rant.options.use_stdlib {
141 stdlib::load_stdlib(&mut rant);
142 }
143
144 rant
145 }
146
147 #[inline]
149 pub fn using_module_resolver<R: ModuleResolver + 'static>(self, module_resolver: R) -> Self {
150 Self {
151 module_resolver: Rc::new(module_resolver),
152 .. self
153 }
154 }
155}
156
157impl Default for Rant {
158 fn default() -> Self {
160 Self::new()
161 }
162}
163
164impl Rant {
165 #[must_use = "compiling a program without storing or running it achieves nothing"]
167 pub fn compile<R: Reporter>(&self, source: &str, reporter: &mut R) -> Result<RantProgram, CompilerError> {
168 compiler::compile_string(source, reporter, self.options.debug_mode, RantProgramInfo {
169 name: None,
170 path: None,
171 })
172 }
173
174 #[must_use = "compiling a program without storing or running it achieves nothing"]
176 pub fn compile_named<R: Reporter>(&self, source: &str, reporter: &mut R, name: &str) -> Result<RantProgram, CompilerError> {
177 compiler::compile_string(source, reporter, self.options.debug_mode, RantProgramInfo {
178 name: Some(name.to_owned()),
179 path: None,
180 })
181 }
182
183 #[must_use = "compiling a program without storing or running it achieves nothing"]
191 pub fn compile_quiet(&self, source: &str) -> Result<RantProgram, CompilerError> {
192 compiler::compile_string(source, &mut (), self.options.debug_mode, RantProgramInfo {
193 name: None,
194 path: None,
195 })
196 }
197
198 #[must_use = "compiling a program without storing or running it achieves nothing"]
206 pub fn compile_quiet_named(&self, source: &str, name: &str) -> Result<RantProgram, CompilerError> {
207 compiler::compile_string(source, &mut (), self.options.debug_mode, RantProgramInfo {
208 name: Some(name.to_owned()),
209 path: None,
210 })
211 }
212
213 #[must_use = "compiling a program without storing or running it achieves nothing"]
215 pub fn compile_file<P: AsRef<Path>, R: Reporter>(&self, path: P, reporter: &mut R) -> Result<RantProgram, CompilerError> {
216 compiler::compile_file(path, reporter, self.options.debug_mode)
217 }
218
219 #[must_use = "compiling a program without storing or running it achieves nothing"]
227 pub fn compile_file_quiet<P: AsRef<Path>>(&self, path: P) -> Result<RantProgram, CompilerError> {
228 compiler::compile_file(path, &mut (), self.options.debug_mode)
229 }
230
231 #[inline]
237 pub fn set_global(&mut self, key: &str, value: RantValue) -> bool {
238 if let Some(global_var) = self.globals.get_mut(key) {
239 global_var.write(value)
240 } else {
241 self.globals.insert(InternalString::from(key), RantVar::ByVal(value));
242 true
243 }
244 }
245
246 #[inline]
252 pub fn set_global_const(&mut self, key: &str, value: RantValue) -> bool {
253 if let Some(global_var) = self.globals.get(key) {
254 if global_var.is_const() {
255 return false
256 }
257 }
258 self.globals.insert(InternalString::from(key), RantVar::ByValConst(value));
259 true
260 }
261
262 #[inline]
265 pub fn set_global_force(&mut self, key: &str, value: RantValue, is_const: bool) {
266 self.globals.insert(InternalString::from(key), if is_const { RantVar::ByValConst(value) } else { RantVar::ByVal(value) });
267 }
268
269 #[inline]
271 pub fn get_global(&self, key: &str) -> Option<RantValue> {
272 self.globals.get(key).map(|var| var.value_cloned())
273 }
274
275 #[inline]
277 pub(crate) fn get_global_var(&self, key: &str) -> Option<&RantVar> {
278 self.globals.get(key)
279 }
280
281 #[inline]
283 pub(crate) fn set_global_var(&mut self, key: &str, var: RantVar) {
284 self.globals.insert(InternalString::from(key), var);
285 }
286
287 #[inline]
289 pub(crate) fn get_global_var_mut(&mut self, key: &str) -> Option<&mut RantVar> {
290 self.globals.get_mut(key)
291 }
292
293 #[inline]
295 pub fn has_global(&self, key: &str) -> bool {
296 self.globals.contains_key(key)
297 }
298
299 #[inline]
301 pub fn delete_global(&mut self, key: &str) -> bool {
302 self.globals.remove(key).is_some()
303 }
304
305 #[inline]
307 pub fn global_names(&self) -> impl Iterator<Item = &str> {
308 self.globals.keys().map(|k| k.as_str())
309 }
310
311 pub fn options(&self) -> &RantOptions {
313 &self.options
314 }
315
316 pub fn seed(&self) -> u64 {
318 self.rng.seed()
319 }
320
321 pub fn set_seed(&mut self, seed: u64) {
323 self.rng = Rc::new(RantRng::new(seed));
324 }
325
326 pub fn reset_seed(&mut self) {
328 let seed = self.rng.seed();
329 self.rng = Rc::new(RantRng::new(seed));
330 }
331
332 pub fn add_data_source(&mut self, data_source: impl DataSource + 'static) -> Result<(), DataSourceRegisterError> {
334 let id = data_source.type_id();
335
336 if self.has_data_source(id) {
337 return Err(DataSourceRegisterError::AlreadyExists(id.into()))
338 }
339
340 self.data_sources.insert(id.into(), Box::new(data_source));
341 Ok(())
342 }
343
344 pub fn remove_data_source(&mut self, name: &str) -> Option<Box<dyn DataSource>> {
346 self.data_sources.remove(name)
347 }
348
349 pub fn has_data_source(&self, name: &str) -> bool {
351 self.data_sources.contains_key(name)
352 }
353
354 pub fn clear_data_sources(&mut self) {
356 self.data_sources.clear();
357 }
358
359 pub fn data_source(&self, name: &str) -> Option<&dyn DataSource> {
361 self.data_sources.get(name).map(Box::as_ref)
362 }
363
364 pub fn iter_data_sources(&self) -> impl Iterator<Item = (&'_ str, &'_ Box<dyn DataSource + 'static>)> {
366 self.data_sources.iter().map(|(k, v)| (k.as_str(), v))
367 }
368
369 pub fn run(&mut self, program: &RantProgram) -> RuntimeResult<RantValue> {
371 VM::new(self.rng.clone(), self, program).run()
372 }
373
374 pub fn run_with<A>(&mut self, program: &RantProgram, args: A) -> RuntimeResult<RantValue>
376 where A: Into<Option<HashMap<String, RantValue>>>
377 {
378 VM::new(self.rng.clone(), self, program).run_with(args)
379 }
380
381 pub fn try_load_global_module(&mut self, module_path: &str) -> Result<(), ModuleLoadError> {
382 if let Some(module_name) =
383 PathBuf::from(&module_path)
384 .with_extension("")
385 .file_name()
386 .map(|name| name.to_str())
387 .flatten()
388 .map(|name| name.to_owned())
389 {
390 if self.get_cached_module(module_name.as_ref()).is_some() {
392 return Ok(())
393 }
394
395 let module_resolver = Rc::clone(&self.module_resolver);
396
397 let module = match module_resolver.try_resolve(self, module_path, None) {
399 Ok(module_program) => match self.run(&module_program) {
400 Ok(module) => Ok(module),
401 Err(err) => Err(ModuleLoadError::RuntimeError(Rc::new(err))),
402 },
403 Err(err) => Err(ModuleLoadError::ResolveError(err)),
404 }?;
405
406 if let Some(RantValue::Map(module_cache_ref)) = self.get_global(MODULES_CACHE_KEY) {
408 module_cache_ref.borrow_mut().raw_set(&module_name, module);
409 } else {
410 let mut cache = RantMap::new();
411 cache.raw_set(&module_name, module);
412 self.set_global(MODULES_CACHE_KEY, cache.into_rant());
413 }
414
415 Ok(())
416 } else {
417 Err(ModuleLoadError::InvalidPath(format!("missing module name from path: '{module_path}'")))
418 }
419 }
420
421 #[inline]
422 pub(crate) fn get_cached_module(&self, module_name: &str) -> Option<RantValue> {
423 if let Some(RantValue::Map(module_cache_ref)) = self.get_global(MODULES_CACHE_KEY) {
424 if let Some(module @ RantValue::Map(..)) = module_cache_ref.borrow().raw_get(module_name) {
425 return Some(module.clone())
426 }
427 }
428 None
429 }
430}
431
432#[derive(Debug, Clone)]
434pub struct RantOptions {
435 pub use_stdlib: bool,
437 pub debug_mode: bool,
439 pub seed: u64,
441}
442
443impl Default for RantOptions {
444 fn default() -> Self {
445 Self {
446 use_stdlib: true,
447 debug_mode: false,
448 seed: 0,
449 }
450 }
451}
452
453#[derive(Debug)]
455pub struct RantProgram {
456 info: Rc<RantProgramInfo>,
457 root: Rc<Sequence>
458}
459
460impl RantProgram {
461 pub(crate) fn new(root: Rc<Sequence>, info: Rc<RantProgramInfo>) -> Self {
462 Self {
463 info,
464 root,
465 }
466 }
467
468 #[inline]
470 pub fn name(&self) -> Option<&str> {
471 self.info.name.as_deref()
472 }
473
474 #[inline]
476 pub fn path(&self) -> Option<&str> {
477 self.info.path.as_deref()
478 }
479
480 #[inline]
482 pub fn info(&self) -> &RantProgramInfo {
483 self.info.as_ref()
484 }
485}
486
487#[derive(Debug)]
489pub struct RantProgramInfo {
490 path: Option<String>,
491 name: Option<String>,
492}
493
494impl RantProgramInfo {
495 #[inline]
497 pub fn name(&self) -> Option<&str> {
498 self.name.as_deref()
499 }
500
501 #[inline]
503 pub fn path(&self) -> Option<&str> {
504 self.path.as_deref()
505 }
506}
507
508#[derive(Debug)]
510pub enum ModuleLoadError {
511 InvalidPath(String),
513 RuntimeError(Rc<RuntimeError>),
515 ResolveError(ModuleResolveError),
517}
518
519impl Display for ModuleLoadError {
520 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
521 match self {
522 ModuleLoadError::InvalidPath(errmsg) => write!(f, "{}", errmsg),
523 ModuleLoadError::RuntimeError(err) => write!(f, "runtime error while loading module: {}", err),
524 ModuleLoadError::ResolveError(err) => write!(f, "unable to resolve module: {}", err),
525 }
526 }
527}
528
529impl Error for ModuleLoadError {}
530
531#[derive(Debug)]
533pub enum DataSourceRegisterError {
534 InvalidTypeId(String),
536 AlreadyExists(String),
538}
539
540impl Display for DataSourceRegisterError {
541 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
542 match self {
543 Self::InvalidTypeId(id) => write!(f, "the type id '{id}' is invalid"),
544 Self::AlreadyExists(id) => write!(f, "the type id '{id}' was already registered on the context"),
545 }
546 }
547}