1use crate::runner::ds::env_record::{
4 new_declarative_environment, new_global_environment, EnvironmentRecord, EnvironmentRecordType,
5};
6use crate::runner::ds::error::JErrorType;
7use crate::runner::ds::execution_context::ExecutionContextStack;
8use crate::runner::ds::heap::{Heap, HeapConfig};
9use crate::runner::ds::lex_env::JsLexEnvironmentType;
10use crate::runner::ds::object::{JsObject, JsObjectType, ObjectBase, ObjectType};
11use crate::runner::ds::value::JsValue;
12use crate::parser::ast::FunctionData;
13use super::super_global::SuperGlobalEnvironment;
14use std::cell::RefCell;
15use std::collections::HashMap;
16use std::rc::Rc;
17
18pub type SharedHeap = Rc<RefCell<Heap>>;
20
21pub type SharedSuperGlobal = Rc<RefCell<SuperGlobalEnvironment>>;
23
24pub struct EvalContext {
52 pub global_this: Option<JsValue>,
54 pub heap: SharedHeap,
56 pub lex_env: JsLexEnvironmentType,
58 pub var_env: JsLexEnvironmentType,
60 pub ctx_stack: ExecutionContextStack,
62 pub strict: bool,
64 pub lex_env_version: u64,
66 pub super_global: SharedSuperGlobal,
68}
69
70impl EvalContext {
71 pub fn new() -> Self {
87 let global_obj: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(
89 SimpleObject::new(),
90 ))));
91 let global_env = new_global_environment(global_obj.clone());
92
93 EvalContext {
94 global_this: Some(JsValue::Object(global_obj)),
95 heap: Rc::new(RefCell::new(Heap::default())),
96 lex_env: global_env.clone(),
97 var_env: global_env,
98 ctx_stack: ExecutionContextStack::new(),
99 strict: false,
100 lex_env_version: 0,
101 super_global: Rc::new(RefCell::new(SuperGlobalEnvironment::new())),
102 }
103 }
104
105 pub fn with_heap_config(config: HeapConfig) -> Self {
122 let global_obj: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(
123 SimpleObject::new(),
124 ))));
125 let global_env = new_global_environment(global_obj.clone());
126
127 EvalContext {
128 global_this: Some(JsValue::Object(global_obj)),
129 heap: Rc::new(RefCell::new(Heap::new(config))),
130 lex_env: global_env.clone(),
131 var_env: global_env,
132 ctx_stack: ExecutionContextStack::new(),
133 strict: false,
134 lex_env_version: 0,
135 super_global: Rc::new(RefCell::new(SuperGlobalEnvironment::new())),
136 }
137 }
138
139 pub fn current_lex_env_version(&self) -> u64 {
141 self.lex_env_version
142 }
143
144 pub fn add_resolver(&mut self, resolver: Box<dyn super::resolver::PluginResolver>) {
180 self.super_global.borrow_mut().add_resolver(resolver);
181 }
182
183 pub fn install_core_builtins(&mut self, registry: super::registry::BuiltInRegistry) {
200 self.add_resolver(Box::new(super::core_resolver::CorePluginResolver::new(registry)));
201 }
202
203 pub fn allocate(&self, bytes: usize) -> Result<(), JErrorType> {
205 self.heap.borrow_mut().allocate(bytes)
206 }
207
208 pub fn deallocate(&self, bytes: usize) {
210 self.heap.borrow_mut().deallocate(bytes)
211 }
212
213 pub fn heap_usage(&self) -> usize {
215 self.heap.borrow().get_allocated()
216 }
217
218 pub fn new_tracked_object(&self) -> Result<SimpleObject, JErrorType> {
220 SimpleObject::new_tracked(self.heap.clone())
221 }
222
223 pub fn get_binding(&mut self, name: &str) -> Result<JsValue, JErrorType> {
225 let name_string = name.to_string();
226 self.resolve_binding(&name_string)
227 }
228
229 pub fn get_binding_with_env(
231 &mut self,
232 name: &str,
233 ) -> Result<(JsValue, JsLexEnvironmentType), JErrorType> {
234 let name_string = name.to_string();
235 let mut current_env = Some(self.lex_env.clone());
236 let mut last_env: Option<JsLexEnvironmentType> = None;
237
238 while let Some(env) = current_env {
239 let env_borrowed = env.borrow();
240 if env_borrowed.inner.as_env_record().has_binding(&name_string) {
241 drop(env_borrowed);
242 let value = env
243 .borrow()
244 .inner
245 .as_env_record()
246 .get_binding_value(&mut self.ctx_stack, &name_string)?;
247 return Ok((value, env));
248 }
249 last_env = Some(env.clone());
250 current_env = env_borrowed.outer.clone();
251 }
252
253 let sg = self.super_global.clone();
256 let result = sg.borrow_mut().resolve_binding(&name_string, self);
257 let value = result?;
258 let env = last_env.unwrap_or_else(|| self.lex_env.clone());
259 Ok((value, env))
260 }
261
262 pub fn get_binding_in_env(
264 &mut self,
265 env: &JsLexEnvironmentType,
266 name: &str,
267 ) -> Result<JsValue, JErrorType> {
268 let name_string = name.to_string();
269 env.borrow()
270 .inner
271 .as_env_record()
272 .get_binding_value(&mut self.ctx_stack, &name_string)
273 }
274
275 pub fn resolve_binding(&mut self, name: &String) -> Result<JsValue, JErrorType> {
278 let mut current_env = Some(self.lex_env.clone());
279
280 while let Some(env) = current_env {
281 let env_borrowed = env.borrow();
282 if env_borrowed.inner.as_env_record().has_binding(name) {
283 drop(env_borrowed);
284 return env
285 .borrow()
286 .inner
287 .as_env_record()
288 .get_binding_value(&mut self.ctx_stack, name);
289 }
290 current_env = env_borrowed.outer.clone();
291 }
292
293 let sg = self.super_global.clone();
295 let result = sg.borrow_mut().resolve_binding(name, self);
296 result
297 }
298
299 pub fn set_binding(&mut self, name: &str, value: JsValue) -> Result<(), JErrorType> {
301 let name_string = name.to_string();
302 self.resolve_and_set_binding(&name_string, value)
303 }
304
305 pub fn set_binding_with_env(
307 &mut self,
308 name: &str,
309 value: JsValue,
310 ) -> Result<JsLexEnvironmentType, JErrorType> {
311 let name_string = name.to_string();
312 let mut current_env = Some(self.lex_env.clone());
313
314 while let Some(env) = current_env.clone() {
315 let has_binding = env.borrow().inner.as_env_record().has_binding(&name_string);
316 if has_binding {
317 self.set_binding_in_env(&env, &name_string, value)?;
318 return Ok(env);
319 }
320 current_env = env.borrow().outer.clone();
321 }
322
323 if !self.strict {
324 let env = self.var_env.clone();
325 self.set_binding_in_env(&env, &name_string, value)?;
326 return Ok(env);
327 }
328
329 Err(JErrorType::ReferenceError(format!("{} is not defined", name)))
330 }
331
332 pub fn set_binding_in_env_cached(
334 &mut self,
335 env: &JsLexEnvironmentType,
336 name: &str,
337 value: JsValue,
338 ) -> Result<(), JErrorType> {
339 let name_string = name.to_string();
340 self.set_binding_in_env(env, &name_string, value)
341 }
342
343 fn resolve_and_set_binding(&mut self, name: &String, value: JsValue) -> Result<(), JErrorType> {
345 let mut current_env = Some(self.lex_env.clone());
346
347 while let Some(env) = current_env.clone() {
348 let has_binding = env.borrow().inner.as_env_record().has_binding(name);
349 if has_binding {
350 return self.set_binding_in_env(&env, name, value);
351 }
352 current_env = env.borrow().outer.clone();
353 }
354
355 if !self.strict {
357 return self.set_binding_in_env(&self.var_env.clone(), name, value);
358 }
359
360 Err(JErrorType::ReferenceError(format!("{} is not defined", name)))
361 }
362
363 fn set_binding_in_env(
365 &mut self,
366 env: &JsLexEnvironmentType,
367 name: &String,
368 value: JsValue,
369 ) -> Result<(), JErrorType> {
370 let mut env_borrowed = env.borrow_mut();
371 match env_borrowed.inner.as_mut() {
372 EnvironmentRecordType::Declarative(rec) => {
373 rec.set_mutable_binding(&mut self.ctx_stack, name.clone(), value)
374 }
375 EnvironmentRecordType::Function(rec) => {
376 rec.set_mutable_binding(&mut self.ctx_stack, name.clone(), value)
377 }
378 EnvironmentRecordType::Global(rec) => {
379 rec.set_mutable_binding(&mut self.ctx_stack, name.clone(), value)
380 }
381 EnvironmentRecordType::Object(rec) => {
382 rec.set_mutable_binding(&mut self.ctx_stack, name.clone(), value)
383 }
384 }
385 }
386
387 pub fn create_binding(&mut self, name: &str, is_const: bool) -> Result<(), JErrorType> {
389 let mut env = self.lex_env.borrow_mut();
390 let name_string = name.to_string();
391 match env.inner.as_mut() {
392 EnvironmentRecordType::Declarative(rec) => {
393 if is_const {
394 rec.create_immutable_binding(name_string)?
395 } else {
396 rec.create_mutable_binding(name_string, false)?
397 }
398 }
399 EnvironmentRecordType::Function(rec) => {
400 if is_const {
401 rec.create_immutable_binding(name_string)?
402 } else {
403 rec.create_mutable_binding(name_string, false)?
404 }
405 }
406 EnvironmentRecordType::Global(rec) => {
407 if is_const {
408 rec.create_immutable_binding(name_string)?
409 } else {
410 rec.create_mutable_binding(name_string, false)?
411 }
412 }
413 EnvironmentRecordType::Object(rec) => {
414 rec.create_mutable_binding(name_string, false)?
415 }
416 }
417 self.lex_env_version = self.lex_env_version.wrapping_add(1);
418 Ok(())
419 }
420
421 pub fn create_var_binding(&mut self, name: &str) -> Result<(), JErrorType> {
423 let mut env = self.var_env.borrow_mut();
424 let name_string = name.to_string();
425 match env.inner.as_mut() {
426 EnvironmentRecordType::Declarative(rec) => {
427 rec.create_mutable_binding(name_string, true)?
428 }
429 EnvironmentRecordType::Function(rec) => rec.create_mutable_binding(name_string, true)?,
430 EnvironmentRecordType::Global(rec) => rec.create_mutable_binding(name_string, true)?,
431 EnvironmentRecordType::Object(rec) => rec.create_mutable_binding(name_string, true)?,
432 }
433 self.lex_env_version = self.lex_env_version.wrapping_add(1);
434 Ok(())
435 }
436
437 pub fn initialize_binding(&mut self, name: &str, value: JsValue) -> Result<(), JErrorType> {
439 let name_string = name.to_string();
440 let mut env = self.lex_env.borrow_mut();
441 match env.inner.as_mut() {
442 EnvironmentRecordType::Declarative(rec) => {
443 rec.initialize_binding(&mut self.ctx_stack, name_string, value)?;
444 Ok(())
445 }
446 EnvironmentRecordType::Function(rec) => {
447 rec.initialize_binding(&mut self.ctx_stack, name_string, value)?;
448 Ok(())
449 }
450 EnvironmentRecordType::Global(rec) => {
451 rec.initialize_binding(&mut self.ctx_stack, name_string, value)?;
452 Ok(())
453 }
454 EnvironmentRecordType::Object(rec) => {
455 rec.initialize_binding(&mut self.ctx_stack, name_string, value)?;
456 Ok(())
457 }
458 }
459 }
460
461 pub fn initialize_var_binding(&mut self, name: &str, value: JsValue) -> Result<(), JErrorType> {
463 let name_string = name.to_string();
464 let mut env = self.var_env.borrow_mut();
465 match env.inner.as_mut() {
466 EnvironmentRecordType::Declarative(rec) => {
467 rec.initialize_binding(&mut self.ctx_stack, name_string, value)?;
468 Ok(())
469 }
470 EnvironmentRecordType::Function(rec) => {
471 rec.initialize_binding(&mut self.ctx_stack, name_string, value)?;
472 Ok(())
473 }
474 EnvironmentRecordType::Global(rec) => {
475 rec.initialize_binding(&mut self.ctx_stack, name_string, value)?;
476 Ok(())
477 }
478 EnvironmentRecordType::Object(rec) => {
479 rec.initialize_binding(&mut self.ctx_stack, name_string, value)?;
480 Ok(())
481 }
482 }
483 }
484
485 pub fn has_var_binding(&self, name: &str) -> bool {
487 let env = self.var_env.borrow();
488 env.inner.as_env_record().has_binding(&name.to_string())
489 }
490
491 pub fn set_var_binding(&mut self, name: &str, value: JsValue) -> Result<(), JErrorType> {
493 let name_string = name.to_string();
494 let mut env = self.var_env.borrow_mut();
495 match env.inner.as_mut() {
496 EnvironmentRecordType::Declarative(rec) => {
497 rec.set_mutable_binding(&mut self.ctx_stack, name_string, value)
498 }
499 EnvironmentRecordType::Function(rec) => {
500 rec.set_mutable_binding(&mut self.ctx_stack, name_string, value)
501 }
502 EnvironmentRecordType::Global(rec) => {
503 rec.set_mutable_binding(&mut self.ctx_stack, name_string, value)
504 }
505 EnvironmentRecordType::Object(rec) => {
506 rec.set_mutable_binding(&mut self.ctx_stack, name_string, value)
507 }
508 }
509 }
510
511 pub fn push_block_scope(&mut self) {
513 let new_env = new_declarative_environment(Some(self.lex_env.clone()));
514 self.lex_env = new_env;
515 self.lex_env_version = self.lex_env_version.wrapping_add(1);
516 }
517
518 pub fn pop_block_scope(&mut self) {
520 let outer = self.lex_env.borrow().outer.clone();
521 if let Some(outer_env) = outer {
522 self.lex_env = outer_env;
523 }
524 self.lex_env_version = self.lex_env_version.wrapping_add(1);
525 }
526
527 pub fn has_binding(&self, name: &str) -> bool {
530 let name_string = name.to_string();
531 let mut current_env = Some(self.lex_env.clone());
532
533 while let Some(env) = current_env {
534 let env_borrowed = env.borrow();
535 if env_borrowed.inner.as_env_record().has_binding(&name_string) {
536 return true;
537 }
538 current_env = env_borrowed.outer.clone();
539 }
540
541 self.super_global.borrow().has_name(name)
543 }
544}
545
546impl Default for EvalContext {
547 fn default() -> Self {
548 Self::new()
549 }
550}
551
552pub struct SimpleObject {
554 base: ObjectBase,
555 heap: Option<SharedHeap>,
556 allocated_bytes: usize,
557}
558
559impl SimpleObject {
560 pub fn new() -> Self {
561 SimpleObject {
562 base: ObjectBase::new(),
563 heap: None,
564 allocated_bytes: 0,
565 }
566 }
567
568 pub fn new_tracked(heap: SharedHeap) -> Result<Self, JErrorType> {
569 const SIMPLE_OBJECT_ALLOCATION_BYTES: usize = 64;
570 heap.borrow_mut().allocate(SIMPLE_OBJECT_ALLOCATION_BYTES)?;
571 Ok(SimpleObject {
572 base: ObjectBase::new(),
573 heap: Some(heap),
574 allocated_bytes: SIMPLE_OBJECT_ALLOCATION_BYTES,
575 })
576 }
577}
578
579impl Drop for SimpleObject {
580 fn drop(&mut self) {
581 if let Some(heap) = &self.heap {
582 heap.borrow_mut().deallocate(self.allocated_bytes);
583 }
584 }
585}
586
587impl JsObject for SimpleObject {
588 fn get_object_base_mut(&mut self) -> &mut ObjectBase {
589 &mut self.base
590 }
591
592 fn get_object_base(&self) -> &ObjectBase {
593 &self.base
594 }
595
596 fn as_js_object(&self) -> &dyn JsObject {
597 self
598 }
599
600 fn as_js_object_mut(&mut self) -> &mut dyn JsObject {
601 self
602 }
603}
604
605pub type NativeFn = fn(
608 ctx: &mut EvalContext,
609 this: JsValue,
610 args: Vec<JsValue>,
611) -> Result<JsValue, JErrorType>;
612
613pub enum BuiltInFn {
615 Native(NativeFn),
617
618 Plugin(Box<dyn Fn(&mut EvalContext, JsValue, Vec<JsValue>) -> Result<JsValue, JErrorType> + Send + Sync>),
620
621 Script(Rc<FunctionData>),
623}
624
625impl BuiltInFn {
626 pub fn call(
628 &self,
629 ctx: &mut EvalContext,
630 this: JsValue,
631 args: Vec<JsValue>,
632 ) -> Result<JsValue, JErrorType> {
633 match self {
634 BuiltInFn::Native(f) => f(ctx, this, args),
635 BuiltInFn::Plugin(f) => f(ctx, this, args),
636 BuiltInFn::Script(_f) => {
637 Err(JErrorType::TypeError("Script built-ins not yet implemented".to_string()))
639 }
640 }
641 }
642}
643
644pub struct BuiltInObject {
647 pub name: String,
649
650 pub prototype: Option<String>,
652
653 pub methods: HashMap<String, BuiltInFn>,
655
656 pub properties: HashMap<String, JsValue>,
658
659 pub constructor: Option<BuiltInFn>,
661}
662
663impl BuiltInObject {
664 pub fn new(name: impl Into<String>) -> Self {
666 BuiltInObject {
667 name: name.into(),
668 prototype: Some("Object".to_string()),
669 methods: HashMap::new(),
670 properties: HashMap::new(),
671 constructor: None,
672 }
673 }
674
675 pub fn with_prototype(mut self, prototype: impl Into<String>) -> Self {
677 self.prototype = Some(prototype.into());
678 self
679 }
680
681 pub fn with_no_prototype(mut self) -> Self {
683 self.prototype = None;
684 self
685 }
686
687 pub fn add_method(mut self, name: impl Into<String>, func: NativeFn) -> Self {
689 self.methods.insert(name.into(), BuiltInFn::Native(func));
690 self
691 }
692
693 pub fn add_property(mut self, name: impl Into<String>, value: JsValue) -> Self {
695 self.properties.insert(name.into(), value);
696 self
697 }
698
699 pub fn with_constructor(mut self, constructor: NativeFn) -> Self {
701 self.constructor = Some(BuiltInFn::Native(constructor));
702 self
703 }
704}
705
706#[derive(Debug, Clone)]
709pub struct PluginInfo {
710 pub name: String,
712
713 pub version: String,
715
716 pub provides: Vec<String>,
718}
719
720impl PluginInfo {
721 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
722 PluginInfo {
723 name: name.into(),
724 version: version.into(),
725 provides: Vec::new(),
726 }
727 }
728
729 pub fn with_provides(mut self, provides: Vec<String>) -> Self {
730 self.provides = provides;
731 self
732 }
733}
734