roan_engine/context.rs
1use crate::{
2 module::{loaders::ModuleLoader, Module},
3 vm::VM,
4};
5use anyhow::Result;
6use bon::bon;
7use roan_error::print_diagnostic;
8use std::{cell::RefCell, fmt::Debug, path::PathBuf, rc::Rc};
9use tracing::debug;
10
11/// Struct to interact with the runtime.
12///
13/// # Example
14/// ```rs
15/// let ctx = Context::new();
16/// let src_code = r#"
17/// use { println, eprintln } from "std::io";
18///
19/// fn add(a: float, b: float) -> float {
20/// return a + b;
21/// }
22///
23/// fn main() -> int {
24/// let i = 3.14;
25/// let j = true;
26///
27/// if j {
28/// i = add(i, 2.0);
29/// } else {
30/// eprintln("Goodbye, world!");
31/// }
32///
33/// return 0;
34/// }
35///
36/// main();
37/// "#;
38///
39/// let source = Source::from_string(src_code);
40/// let module = Module::from_source(source, ctx)?;
41///
42/// let result = ctx.eval(module);
43///
44/// assert_eq!(result, Ok(Value::Int(3)));
45/// ```
46#[derive(Clone, Debug)]
47pub struct Context {
48 pub module_loader: Rc<RefCell<dyn ModuleLoader>>,
49 pub cwd: PathBuf,
50}
51
52#[bon]
53impl Context {
54 /// Create a new context.
55 #[builder]
56 pub fn new(
57 #[builder] module_loader: Rc<RefCell<dyn ModuleLoader>>,
58 #[builder(default = std::env::current_dir().unwrap())] cwd: PathBuf,
59 ) -> Self {
60 Self { module_loader, cwd }
61 }
62}
63
64impl Context {
65 /// Evaluate a module by parsing and interpreting it.
66 ///
67 /// # Arguments
68 ///
69 /// * `module` - The module to evaluate.
70 /// * `vm` - The virtual machine instance.
71 ///
72 /// # Returns
73 ///
74 /// The result of the evaluation.
75 pub fn eval(&mut self, module: &mut Module, vm: &mut VM) -> Result<()> {
76 self.parse(module)?;
77
78 self.interpret(module, vm)?;
79
80 Ok(())
81 }
82
83 /// Parse a module to prepare it for interpretation.
84 ///
85 /// # Arguments
86 ///
87 /// * `module` - The module to parse.
88 ///
89 /// # Returns
90 ///
91 /// An empty result if successful, otherwise returns an error.
92 pub fn parse(&mut self, module: &mut Module) -> Result<()> {
93 match module.parse() {
94 Ok(_) => Ok(()),
95 Err(e) => {
96 print_diagnostic(e, Some(module.source().content()));
97 std::process::exit(1);
98 }
99 }
100 }
101
102 /// Interpret a parsed module in the virtual machine.
103 ///
104 /// # Arguments
105 ///
106 /// * `module` - The module to interpret.
107 /// * `vm` - The virtual machine instance.
108 ///
109 /// # Returns
110 ///
111 /// An empty result if successful, otherwise returns an error.
112 pub fn interpret(&mut self, module: &mut Module, vm: &mut VM) -> Result<()> {
113 match module.interpret(self, vm) {
114 Ok(_) => Ok(()),
115 Err(e) => {
116 print_diagnostic(e, Some(module.source().content()));
117 std::process::exit(1);
118 }
119 }
120 }
121
122 /// Insert a module into the context.
123 ///
124 /// # Arguments
125 /// - `name` - The name of the module.
126 /// - `module` - The module to insert.
127 pub fn insert_module(&mut self, name: String, module: Module) {
128 debug!("Inserting module: {}", name);
129 self.module_loader.borrow_mut().insert(name, module);
130 }
131
132 /// Query a module from the context.
133 ///
134 /// # Arguments
135 /// - `name` - The name of the module to query.
136 pub fn query_module(&self, name: &str) -> Option<Module> {
137 self.module_loader.borrow().get(name)
138 }
139
140 /// Load a module from the context.
141 ///
142 /// This function is different from `query_module` in that it will attempt to load the module from the cache
143 /// if it is not found it will try to resolve the path and load the module.
144 ///
145 /// # Arguments
146 /// - `referrer` - The module that is requesting the module.
147 /// - `spec` - The name of the module to load.
148 pub fn load_module(&mut self, referrer: &Module, spec: &str) -> Result<Module> {
149 Ok(self.module_loader.borrow_mut().load(referrer, spec, self)?)
150 }
151
152 pub fn module_keys(&self) -> Vec<String> {
153 self.module_loader.borrow().keys()
154 }
155
156 /// Inserts or updates a module in the context.
157 pub fn upsert_module(&mut self, name: String, module: Module) {
158 debug!("Upserting module: {}", name);
159 self.module_loader.borrow_mut().insert(name, module);
160 }
161}