Skip to main content

bliss_dom/
script.rs

1//! Script engine abstraction for bliss-dom
2//!
3//! This trait allows pluggable script execution engines (Boa, V8, NanoVM, etc.)
4//! to be integrated with the DOM. Script engines can execute JavaScript, Lua,
5//! Python, or other languages and handle DOM events.
6
7use crate::BaseDocument;
8use bliss_traits::events::DomEvent;
9
10/// Result of script execution
11#[derive(Debug, Clone)]
12pub enum ScriptValue {
13    Null,
14    Bool(bool),
15    Number(f64),
16    String(String),
17    Object(Vec<(String, ScriptValue)>),
18    Promise(u64), // Async result handle
19}
20
21/// Script execution errors
22#[derive(Debug, Clone)]
23pub enum ScriptError {
24    ParseError(String),
25    RuntimeError(String),
26    CapabilityDenied { operation: String, reason: String },
27    Timeout,
28    MemoryLimitExceeded,
29    UnsupportedLanguage(String),
30}
31
32/// Whether an event was handled by script
33pub enum EventHandled {
34    Handled,   // Script consumed the event
35    Propagate, // Pass to normal DOM handling
36}
37
38/// Language identifiers
39#[derive(Debug, Clone, Copy, PartialEq)]
40pub enum ScriptLanguage {
41    JavaScript,
42    TypeScript,
43    Lua,
44    Python,
45    Casm, // Direct CASM execution for optimized code
46}
47
48impl std::fmt::Display for ScriptLanguage {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        match self {
51            ScriptLanguage::JavaScript => write!(f, "javascript"),
52            ScriptLanguage::TypeScript => write!(f, "typescript"),
53            ScriptLanguage::Lua => write!(f, "lua"),
54            ScriptLanguage::Python => write!(f, "python"),
55            ScriptLanguage::Casm => write!(f, "casm"),
56        }
57    }
58}
59
60/// Context for script execution
61#[derive(Debug, Clone)]
62pub struct ExecutionContext {
63    pub source_url: Option<String>,
64    pub line_number: u32,
65    pub is_module: bool,
66}
67
68impl Default for ExecutionContext {
69    fn default() -> Self {
70        Self {
71            source_url: None,
72            line_number: 1,
73            is_module: false,
74        }
75    }
76}
77
78/// Type for script error callbacks
79pub type ScriptErrorCallback = Box<dyn Fn(&ScriptError) + Send + Sync>;
80
81/// Script engine trait - implement for Boa, V8, NanoVM, etc.
82pub trait ScriptEngine: Send {
83    /// Initialize the engine with a document
84    fn init(&mut self, document: &mut BaseDocument);
85
86    /// Execute code in the specified language
87    fn execute(
88        &mut self,
89        code: &str,
90        language: ScriptLanguage,
91        context: &ExecutionContext,
92    ) -> Result<ScriptValue, ScriptError>;
93
94    /// Handle a DOM event (keyboard, mouse, etc.)
95    /// Returns whether the event was consumed
96    fn handle_event(&mut self, event: &DomEvent) -> EventHandled;
97
98    /// Poll for async work - called by document poll()
99    /// Returns true if more work pending
100    fn tick(&mut self) -> Result<bool, ScriptError>;
101
102    /// Register an error callback
103    fn set_error_handler(&mut self, callback: Option<ScriptErrorCallback>);
104}
105
106/// A no-op script engine for when no scripting is needed
107pub struct NoopScriptEngine;
108
109impl ScriptEngine for NoopScriptEngine {
110    fn init(&mut self, _document: &mut BaseDocument) {}
111
112    fn execute(
113        &mut self,
114        _code: &str,
115        language: ScriptLanguage,
116        _context: &ExecutionContext,
117    ) -> Result<ScriptValue, ScriptError> {
118        Err(ScriptError::UnsupportedLanguage(language.to_string()))
119    }
120
121    fn handle_event(&mut self, _event: &DomEvent) -> EventHandled {
122        EventHandled::Propagate
123    }
124
125    fn tick(&mut self) -> Result<bool, ScriptError> {
126        Ok(false)
127    }
128
129    fn set_error_handler(&mut self, _callback: Option<ScriptErrorCallback>) {}
130}
131
132/// Boxed script engine for storage in documents
133pub type BoxedScriptEngine = Box<dyn ScriptEngine>;