roan_engine/module/
mod.rs

1use crate::{
2    context::Context,
3    natives::get_stored_function,
4    value::Value,
5    vm::{native_fn::NativeFunction, VM},
6};
7use anyhow::Result;
8use roan_ast::{
9    source::Source, Ast, Expr, Fn, Lexer, Parser, StructField, StructImpl, Token, TraitDef,
10    TraitImpl,
11};
12use roan_error::{error::RoanError::VariableNotFoundError, print_diagnostic, TextSpan};
13use std::{
14    collections::HashMap,
15    fmt::Debug,
16    path::{Path, PathBuf},
17};
18use tracing::debug;
19use uuid::Uuid;
20
21pub mod loaders;
22
23#[derive(Clone, Debug)]
24pub struct StoredStruct {
25    pub defining_module: String,
26    pub struct_token: Token,
27    pub name: Token,
28    pub fields: Vec<StructField>,
29    pub public: bool,
30    pub impls: Vec<StoredImpl>,
31    pub trait_impls: Vec<StoredTraitImpl>,
32}
33
34impl StoredStruct {
35    fn find_method_internal(&self, name: &str, is_static: bool) -> Option<&Fn> {
36        self.impls
37            .iter()
38            .flat_map(|impl_stmt| impl_stmt.def.methods.iter())
39            .chain(
40                self.trait_impls
41                    .iter()
42                    .flat_map(|impl_stmt| impl_stmt.def.methods.iter()),
43            )
44            .find(|method| method.name == name && method.is_static == is_static)
45    }
46
47    pub fn find_static_method(&self, name: &str) -> Option<&Fn> {
48        self.find_method_internal(name, true)
49    }
50
51    pub fn find_method(&self, name: &str) -> Option<&Fn> {
52        self.find_method_internal(name, false)
53    }
54}
55
56#[derive(Clone, Debug)]
57pub struct StoredImpl {
58    pub def: StructImpl,
59    pub defining_module: String,
60}
61
62#[derive(Clone, Debug)]
63pub struct StoredTraitImpl {
64    pub def: TraitImpl,
65    pub defining_module: String,
66}
67
68#[derive(Clone, Debug)]
69pub struct StoredConst {
70    pub ident: Token,
71    pub value: Value,
72}
73
74#[derive(Debug, Clone)]
75pub enum ExportType {
76    Function(Fn),
77    Trait(TraitDef),
78    Struct(StoredStruct),
79    Const(StoredConst),
80}
81
82/// Represents a function stored in a module.
83#[derive(Debug, Clone)]
84pub enum StoredFunction {
85    Native(NativeFunction),
86    Function {
87        function: Fn,
88        defining_module: String,
89    },
90}
91
92#[derive(Clone)]
93pub struct Module {
94    pub source: Source,
95    pub path: Option<PathBuf>,
96    pub tokens: Vec<Token>,
97    pub ast: Ast,
98    pub functions: Vec<StoredFunction>,
99    pub exports: Vec<(String, ExportType)>,
100    pub scopes: Vec<HashMap<String, Value>>,
101    pub structs: Vec<StoredStruct>,
102    pub traits: Vec<TraitDef>,
103    pub consts: Vec<StoredConst>,
104    pub id: String,
105    pub lex_comments: bool
106}
107
108impl Debug for Module {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        f.debug_struct("Module")
111            .field("path", &self.path)
112            .field("source", &self.source)
113            // .field("tokens", &self.tokens)
114            // .field("ast", &self.ast)
115            // .field("functions", &self.functions)
116            .field("exports", &self.exports)
117            .field("scopes", &self.scopes)
118            .field("structs", &self.structs)
119            .field("traits", &self.traits)
120            .field("consts", &self.consts)
121            .finish()
122    }
123}
124
125impl Module {
126    /// Creates a new Module from the specified Source.
127    ///
128    /// # Parameters
129    /// - source - The source of the module.
130    ///
131    /// # Returns
132    /// An `Arc<Mutex<Self>>` containing the new Module.
133    pub fn new(source: Source) -> Self {
134        let path = source.path().as_deref().map(Path::to_path_buf);
135
136        Self {
137            source,
138            path,
139            tokens: vec![],
140            functions: get_stored_function(),
141            exports: vec![],
142            scopes: vec![HashMap::new()],
143            ast: Ast::new(),
144            structs: vec![],
145            traits: vec![],
146            consts: vec![],
147            id: Uuid::new_v4().to_string(),
148            lex_comments: false,
149        }
150    }
151    
152    pub fn set_lex_comments(&mut self, lex_comments: bool) {
153        self.lex_comments = lex_comments;
154    }
155
156    /// Get module id
157    pub fn id(&self) -> String {
158        self.id.clone()
159    }
160
161    /// Returns the path of the module.
162    pub fn path(&self) -> Option<PathBuf> {
163        self.path.clone()
164    }
165
166    /// Returns the source of the module.
167    pub fn source(&self) -> &Source {
168        &self.source
169    }
170
171    /// Returns tokens of the module.
172    pub fn tokens(&self) -> &Vec<Token> {
173        &self.tokens
174    }
175
176    /// Parses the module.
177    ///
178    /// First, the module is lexed into tokens. Then, the tokens are parsed into an AST.
179    pub fn parse(&mut self) -> Result<()> {
180        debug!("Parsing module from source");
181        let mut lexer = Lexer::new(self.source.clone());
182
183        let tokens = lexer.lex(self.lex_comments)?;
184        debug!("Parsed {} tokens", tokens.len());
185        self.tokens = tokens;
186
187        let mut parser = Parser::new(self.tokens.clone());
188
189        debug!("Parsing tokens into AST");
190        let ast = parser.parse()?;
191        self.ast = ast;
192
193        Ok(())
194    }
195
196    pub fn interpret(&mut self, ctx: &mut Context, vm: &mut VM) -> Result<()> {
197        for stmt in self.ast.stmts.clone() {
198            match self.interpret_stmt(stmt, ctx, vm) {
199                Ok(_) => {}
200                Err(e) => {
201                    print_diagnostic(e, Some(self.source.content()));
202                    std::process::exit(1);
203                }
204            }
205        }
206
207        Ok(())
208    }
209
210    /// Enter a new scope by pushing a new HashMap onto the scopes stack.
211    pub fn enter_scope(&mut self) {
212        debug!("Entering new scope");
213        self.scopes.push(HashMap::new());
214    }
215
216    /// Exit the current scope by popping the top HashMap from the scopes stack.
217    pub fn exit_scope(&mut self) {
218        debug!("Exiting current scope");
219        self.scopes.pop();
220    }
221
222    /// Declare a new variable in the current (innermost) scope.
223    pub fn declare_variable(&mut self, name: String, val: Value) {
224        debug!("Declaring variable '{}' in current scope", name);
225        if let Some(current_scope) = self.scopes.last_mut() {
226            current_scope.insert(name, val);
227        }
228    }
229
230    /// Set an existing variable's value in the nearest enclosing scope.
231    pub fn set_variable(&mut self, name: &str, val: Value) -> Result<()> {
232        for scope in self.scopes.iter_mut().rev() {
233            if scope.contains_key(name) {
234                debug!("Setting variable '{}' to {:?}", name, val);
235                scope.insert(name.to_string(), val);
236                return Ok(());
237            }
238        }
239        // Variable not found in any scope
240        Err(VariableNotFoundError(name.to_string(), TextSpan::default()).into())
241    }
242
243    /// Finds a variable by name, searching from the innermost scope outward.
244    pub fn find_variable(&self, name: &str) -> Option<&Value> {
245        for scope in self.scopes.iter().rev() {
246            if let Some(val) = scope.get(name) {
247                debug!("Found variable '{}' with value {:?}", name, val);
248                return Some(val);
249            }
250        }
251        debug!("Variable '{}' not found in any scope", name);
252        None
253    }
254
255    /// Finds a constant by name.
256    pub fn find_const(&self, name: &str) -> Option<&StoredConst> {
257        self.consts.iter().find(|c| c.ident.literal() == name)
258    }
259
260    pub fn name(&self) -> String {
261        self.path()
262            .unwrap()
263            .file_stem()
264            .unwrap()
265            .to_string_lossy()
266            .to_string()
267    }
268
269    pub fn extract_variable_name(expr: &Expr) -> Option<String> {
270        match expr {
271            Expr::Variable(v) => Some(v.ident.clone()),
272            Expr::Access(access) => Self::extract_variable_name(&access.base),
273            _ => None,
274        }
275    }
276
277    /// Finds a function by name.
278    pub fn find_function(&self, name: &str) -> Option<&StoredFunction> {
279        debug!("Looking for function: {}", name);
280
281        self.functions.iter().find(|f| match f {
282            StoredFunction::Native(n) => n.name == name,
283            StoredFunction::Function { function, .. } => function.name == name,
284        })
285    }
286
287    pub fn update_variable(
288        &mut self,
289        name: &str,
290        val: Value,
291        func: fn(Value, Value) -> Value,
292    ) -> Result<()> {
293        let variable = self
294            .find_variable(name)
295            .ok_or_else(|| VariableNotFoundError(name.to_string(), TextSpan::default()))?;
296
297        let new_val = func(variable.clone(), val);
298        self.set_variable(name, new_val)?;
299        Ok(())
300    }
301}