1use crate::parser::ast::{
7 AssignmentOperator, BinaryOperator, ClassData, ExpressionOrSpreadElement, ExpressionOrSuper,
8 ExpressionType, ExpressionPatternType, FunctionData, LiteralData, LiteralType, MemberExpressionType,
9 MethodDefinitionKind, PatternOrExpression, PatternType, PropertyData, PropertyKind, UnaryOperator,
10 UpdateOperator, LogicalOperator,
11};
12use crate::runner::ds::error::JErrorType;
13use crate::runner::ds::object::{JsObject, JsObjectType, ObjectBase, ObjectType};
14use crate::runner::ds::object_property::{PropertyDescriptor, PropertyDescriptorAccessor, PropertyDescriptorData, PropertyKey};
15use crate::runner::ds::value::{JsValue, JsNumberType};
16use crate::runner::plugin::types::{EvalContext, SimpleObject};
17
18use std::cell::RefCell;
19use std::rc::Rc;
20
21use super::types::ValueResult;
22
23pub fn evaluate_expression(
25 expr: &ExpressionType,
26 ctx: &mut EvalContext,
27) -> ValueResult {
28 match expr {
29 ExpressionType::Literal(lit) => evaluate_literal(lit),
30
31 ExpressionType::ExpressionWhichCanBePattern(pattern) => {
32 evaluate_expression_pattern(pattern, ctx)
33 }
34
35 ExpressionType::ThisExpression { .. } => {
36 Ok(ctx.global_this.clone().unwrap_or(JsValue::Undefined))
37 }
38
39 ExpressionType::ArrayExpression { elements, .. } => {
40 evaluate_array_expression(elements, ctx)
41 }
42
43 ExpressionType::ObjectExpression { properties, .. } => {
44 evaluate_object_expression(properties, ctx)
45 }
46
47 ExpressionType::FunctionOrGeneratorExpression(func_data) => {
48 create_function_object(func_data, ctx)
49 }
50
51 ExpressionType::UnaryExpression { operator, argument, .. } => {
52 evaluate_unary_expression(operator, argument, ctx)
53 }
54
55 ExpressionType::BinaryExpression { operator, left, right, .. } => {
56 evaluate_binary_expression(operator, left, right, ctx)
57 }
58
59 ExpressionType::LogicalExpression { operator, left, right, .. } => {
60 evaluate_logical_expression(operator, left, right, ctx)
61 }
62
63 ExpressionType::UpdateExpression { operator, argument, prefix, .. } => {
64 evaluate_update_expression(operator, argument, *prefix, ctx)
65 }
66
67 ExpressionType::AssignmentExpression { operator, left, right, .. } => {
68 evaluate_assignment_expression(operator, left, right, ctx)
69 }
70
71 ExpressionType::ConditionalExpression { test, consequent, alternate, .. } => {
72 evaluate_conditional_expression(test, consequent, alternate, ctx)
73 }
74
75 ExpressionType::CallExpression { callee, arguments, .. } => {
76 evaluate_call_expression(callee, arguments, ctx)
77 }
78
79 ExpressionType::NewExpression { callee, arguments, .. } => {
80 evaluate_new_expression(callee, arguments, ctx)
81 }
82
83 ExpressionType::SequenceExpression { expressions, .. } => {
84 evaluate_sequence_expression(expressions, ctx)
85 }
86
87 ExpressionType::TemplateLiteral(_) => {
88 Err(JErrorType::TypeError("Template literal not yet implemented".to_string()))
89 }
90
91 ExpressionType::TaggedTemplateExpression { .. } => {
92 Err(JErrorType::TypeError("Tagged template expression not yet implemented".to_string()))
93 }
94
95 ExpressionType::ClassExpression(class_data) => {
96 evaluate_class_expression(class_data, ctx)
97 }
98
99 ExpressionType::YieldExpression { argument, delegate, .. } => {
100 if *delegate {
101 return Err(JErrorType::TypeError("yield* not yet implemented".to_string()));
103 }
104 let value = if let Some(arg) = argument {
106 evaluate_expression(arg, ctx)?
107 } else {
108 JsValue::Undefined
109 };
110 Err(JErrorType::YieldValue(value))
112 }
113
114 ExpressionType::MetaProperty { .. } => {
115 Err(JErrorType::TypeError("Meta property not yet implemented".to_string()))
116 }
117
118 ExpressionType::ArrowFunctionExpression { .. } => {
119 Err(JErrorType::TypeError("Arrow function expression not yet implemented".to_string()))
120 }
121
122 ExpressionType::MemberExpression(member_expr) => {
123 evaluate_member_expression(member_expr, ctx)
124 }
125 }
126}
127
128fn evaluate_literal(lit: &LiteralData) -> ValueResult {
130 Ok(match &lit.value {
131 LiteralType::NullLiteral => JsValue::Null,
132 LiteralType::BooleanLiteral(b) => JsValue::Boolean(*b),
133 LiteralType::StringLiteral(s) => JsValue::String(s.clone()),
134 LiteralType::NumberLiteral(n) => {
135 use crate::parser::ast::NumberLiteralType;
136 match n {
137 NumberLiteralType::IntegerLiteral(i) => JsValue::Number(JsNumberType::Integer(*i)),
138 NumberLiteralType::FloatLiteral(f) => JsValue::Number(JsNumberType::Float(*f)),
139 }
140 }
141 LiteralType::RegExpLiteral { .. } => {
142 return Err(JErrorType::TypeError("RegExp literal not yet implemented".to_string()));
143 }
144 })
145}
146
147fn evaluate_array_expression(
149 elements: &[Option<ExpressionOrSpreadElement>],
150 ctx: &mut EvalContext,
151) -> ValueResult {
152 use crate::runner::ds::object::JsObject;
153
154 let mut array_obj = ctx.new_tracked_object()?;
156
157 let mut index = 0;
158 for element in elements {
159 if let Some(elem) = element {
160 match elem {
161 ExpressionOrSpreadElement::Expression(expr) => {
162 let value = evaluate_expression(expr, ctx)?;
163 let key = PropertyKey::Str(index.to_string());
165 array_obj.get_object_base_mut().properties.insert(
166 key,
167 PropertyDescriptor::Data(PropertyDescriptorData {
168 value,
169 writable: true,
170 enumerable: true,
171 configurable: true,
172 }),
173 );
174 index += 1;
175 }
176 ExpressionOrSpreadElement::SpreadElement(spread_expr) => {
177 let spread_value = evaluate_expression(spread_expr, ctx)?;
179
180 if let JsValue::Object(spread_obj) = spread_value {
182 let borrowed = spread_obj.borrow();
183 let base = borrowed.as_js_object().get_object_base();
184
185 let length = if let Some(PropertyDescriptor::Data(prop)) =
187 base.properties.get(&PropertyKey::Str("length".to_string()))
188 {
189 match &prop.value {
190 JsValue::Number(JsNumberType::Integer(n)) => *n as usize,
191 JsValue::Number(JsNumberType::Float(n)) => *n as usize,
192 _ => 0,
193 }
194 } else {
195 0
196 };
197
198 for i in 0..length {
200 let elem_key = PropertyKey::Str(i.to_string());
201 let elem_value = if let Some(PropertyDescriptor::Data(prop)) =
202 base.properties.get(&elem_key)
203 {
204 prop.value.clone()
205 } else {
206 JsValue::Undefined
207 };
208
209 let key = PropertyKey::Str(index.to_string());
211 array_obj.get_object_base_mut().properties.insert(
212 key,
213 PropertyDescriptor::Data(PropertyDescriptorData {
214 value: elem_value,
215 writable: true,
216 enumerable: true,
217 configurable: true,
218 }),
219 );
220 index += 1;
221 }
222 } else if let JsValue::String(s) = spread_value {
223 for ch in s.chars() {
225 let key = PropertyKey::Str(index.to_string());
226 array_obj.get_object_base_mut().properties.insert(
227 key,
228 PropertyDescriptor::Data(PropertyDescriptorData {
229 value: JsValue::String(ch.to_string()),
230 writable: true,
231 enumerable: true,
232 configurable: true,
233 }),
234 );
235 index += 1;
236 }
237 } else {
238 return Err(JErrorType::TypeError(
239 "Spread requires an iterable".to_string(),
240 ));
241 }
242 }
243 }
244 } else {
245 index += 1;
247 }
248 }
249
250 array_obj.get_object_base_mut().properties.insert(
252 PropertyKey::Str("length".to_string()),
253 PropertyDescriptor::Data(PropertyDescriptorData {
254 value: JsValue::Number(JsNumberType::Integer(index as i64)),
255 writable: true,
256 enumerable: false,
257 configurable: false,
258 }),
259 );
260
261 let obj: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(array_obj))));
263 Ok(JsValue::Object(obj))
264}
265
266fn evaluate_object_expression(
268 properties: &[PropertyData<Box<ExpressionType>>],
269 ctx: &mut EvalContext,
270) -> ValueResult {
271 use std::collections::HashMap;
272
273 let mut obj = ctx.new_tracked_object()?;
275
276 let mut accessors: HashMap<String, (Option<JsObjectType>, Option<JsObjectType>)> = HashMap::new();
278
279 for prop in properties {
280 let key = get_object_property_key(&prop.key, prop.computed, ctx)?;
282
283 match prop.kind {
284 PropertyKind::Init => {
285 let value = evaluate_expression(&prop.value, ctx)?;
287
288 obj.get_object_base_mut().properties.insert(
290 PropertyKey::Str(key),
291 PropertyDescriptor::Data(PropertyDescriptorData {
292 value,
293 writable: true,
294 enumerable: true,
295 configurable: true,
296 }),
297 );
298 }
299 PropertyKind::Get => {
300 if let ExpressionType::FunctionOrGeneratorExpression(func_data) = prop.value.as_ref() {
302 let getter_fn = create_function_object(func_data, ctx)?;
303 if let JsValue::Object(getter_obj) = getter_fn {
304 let entry = accessors.entry(key).or_insert((None, None));
305 entry.0 = Some(getter_obj);
306 }
307 } else {
308 return Err(JErrorType::TypeError("Getter must be a function".to_string()));
309 }
310 }
311 PropertyKind::Set => {
312 if let ExpressionType::FunctionOrGeneratorExpression(func_data) = prop.value.as_ref() {
314 let setter_fn = create_function_object(func_data, ctx)?;
315 if let JsValue::Object(setter_obj) = setter_fn {
316 let entry = accessors.entry(key).or_insert((None, None));
317 entry.1 = Some(setter_obj);
318 }
319 } else {
320 return Err(JErrorType::TypeError("Setter must be a function".to_string()));
321 }
322 }
323 }
324 }
325
326 for (key, (getter, setter)) in accessors {
328 obj.get_object_base_mut().properties.insert(
329 PropertyKey::Str(key),
330 PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
331 get: getter,
332 set: setter,
333 enumerable: true,
334 configurable: true,
335 }),
336 );
337 }
338
339 let obj_ref: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(obj))));
341 Ok(JsValue::Object(obj_ref))
342}
343
344fn get_object_property_key(
346 key_expr: &ExpressionType,
347 computed: bool,
348 ctx: &mut EvalContext,
349) -> Result<String, JErrorType> {
350 if computed {
351 let key_value = evaluate_expression(key_expr, ctx)?;
353 Ok(to_string(&key_value))
354 } else {
355 match key_expr {
357 ExpressionType::ExpressionWhichCanBePattern(ExpressionPatternType::Identifier(id)) => {
358 Ok(id.name.clone())
359 }
360 ExpressionType::Literal(lit) => match &lit.value {
361 LiteralType::StringLiteral(s) => Ok(s.clone()),
362 LiteralType::NumberLiteral(n) => {
363 use crate::parser::ast::NumberLiteralType;
364 match n {
365 NumberLiteralType::IntegerLiteral(i) => Ok(i.to_string()),
366 NumberLiteralType::FloatLiteral(f) => Ok(f.to_string()),
367 }
368 }
369 _ => Err(JErrorType::TypeError("Invalid property key".to_string())),
370 },
371 _ => Err(JErrorType::TypeError("Invalid property key".to_string())),
372 }
373 }
374}
375
376fn evaluate_expression_pattern(
378 pattern: &ExpressionPatternType,
379 ctx: &mut EvalContext,
380) -> ValueResult {
381 match pattern {
382 ExpressionPatternType::Identifier(id) => {
383 ctx.get_binding(&id.name)
385 }
386 }
387}
388
389fn evaluate_member_expression(
391 member_expr: &MemberExpressionType,
392 ctx: &mut EvalContext,
393) -> ValueResult {
394 match member_expr {
395 MemberExpressionType::SimpleMemberExpression { object, property, .. } => {
396 let obj_value = evaluate_expression_or_super(object, ctx)?;
398 let prop_name = &property.name;
399
400 get_property_with_ctx(&obj_value, prop_name, ctx)
402 }
403 MemberExpressionType::ComputedMemberExpression { object, property, .. } => {
404 let obj_value = evaluate_expression_or_super(object, ctx)?;
406
407 let prop_value = evaluate_expression(property, ctx)?;
409 let prop_name = to_property_key(&prop_value);
410
411 get_property_with_ctx(&obj_value, &prop_name, ctx)
413 }
414 }
415}
416
417fn evaluate_expression_or_super(
419 expr_or_super: &ExpressionOrSuper,
420 ctx: &mut EvalContext,
421) -> ValueResult {
422 match expr_or_super {
423 ExpressionOrSuper::Expression(expr) => evaluate_expression(expr, ctx),
424 ExpressionOrSuper::Super => {
425 Err(JErrorType::TypeError("super not yet supported".to_string()))
426 }
427 }
428}
429
430fn evaluate_call_expression(
432 callee: &ExpressionOrSuper,
433 arguments: &[ExpressionOrSpreadElement],
434 ctx: &mut EvalContext,
435) -> ValueResult {
436 if let ExpressionOrSuper::Expression(expr) = callee {
439 if let ExpressionType::MemberExpression(member) = expr.as_ref() {
440 if let MemberExpressionType::SimpleMemberExpression { object, property, .. } = member {
441 if let ExpressionOrSuper::Expression(obj_expr) = object {
443 if let ExpressionType::ExpressionWhichCanBePattern(
444 ExpressionPatternType::Identifier(id)
445 ) = obj_expr.as_ref() {
446 let obj_name = &id.name;
447 let method_name = &property.name;
448
449 let args = evaluate_arguments(arguments, ctx)?;
451
452 let sg = ctx.super_global.clone();
454 let this_value = ctx.resolve_binding(obj_name).unwrap_or(JsValue::Undefined);
455
456 let sg_result = sg.borrow().call_method(
457 obj_name,
458 method_name,
459 ctx,
460 this_value.clone(),
461 args.clone(),
462 );
463
464 if let Some(result) = sg_result {
465 return result;
466 }
467
468 }
470 }
471 }
472 }
473 }
474
475 let callee_value = evaluate_expression_or_super(callee, ctx)?;
477
478 let this_value = get_call_this_value(callee, ctx);
480
481 let args = evaluate_arguments(arguments, ctx)?;
483
484 call_value(&callee_value, this_value, args, ctx)
486}
487
488fn evaluate_new_expression(
490 callee: &ExpressionType,
491 arguments: &[ExpressionOrSpreadElement],
492 ctx: &mut EvalContext,
493) -> ValueResult {
494 if let ExpressionType::ExpressionWhichCanBePattern(
497 ExpressionPatternType::Identifier(id)
498 ) = callee {
499 let ctor_name = &id.name;
500
501 let args = evaluate_arguments(arguments, ctx)?;
503
504 let sg = ctx.super_global.clone();
506 let sg_result = sg.borrow().call_constructor(ctor_name, ctx, args.clone());
507
508 if let Some(result) = sg_result {
509 return result;
510 }
511
512 }
514
515 let constructor = evaluate_expression(callee, ctx)?;
517
518 let ctor_obj = match &constructor {
520 JsValue::Object(obj) => {
521 if !obj.borrow().is_callable() {
522 return Err(JErrorType::TypeError(format!(
523 "{} is not a constructor",
524 constructor
525 )));
526 }
527 obj.clone()
528 }
529 _ => {
530 return Err(JErrorType::TypeError(format!(
531 "{} is not a constructor",
532 constructor
533 )));
534 }
535 };
536
537 let new_obj = create_new_object_for_constructor(&ctor_obj)?;
539
540 let args = evaluate_arguments(arguments, ctx)?;
542
543 let result = call_value(&constructor, JsValue::Object(new_obj.clone()), args, ctx)?;
545
546 match result {
548 JsValue::Object(_) => Ok(result),
549 _ => Ok(JsValue::Object(new_obj)),
550 }
551}
552
553fn create_new_object_for_constructor(
556 constructor: &JsObjectType,
557) -> Result<JsObjectType, JErrorType> {
558 use crate::runner::ds::object::{JsObject, ObjectType};
559 use crate::runner::ds::object_property::{PropertyDescriptor, PropertyKey};
560
561 let mut new_obj = SimpleObject::new();
563
564 let ctor_borrowed = constructor.borrow();
566 let prototype_key = PropertyKey::Str("prototype".to_string());
567
568 if let Some(PropertyDescriptor::Data(data)) =
569 ctor_borrowed.as_js_object().get_object_base().properties.get(&prototype_key)
570 {
571 if let JsValue::Object(proto_obj) = &data.value {
572 new_obj.get_object_base_mut().prototype = Some(proto_obj.clone());
574 }
575 }
576
577 drop(ctor_borrowed);
578
579 let obj: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(new_obj))));
580 Ok(obj)
581}
582
583fn get_call_this_value(callee: &ExpressionOrSuper, ctx: &mut EvalContext) -> JsValue {
585 match callee {
586 ExpressionOrSuper::Expression(expr) => {
587 match expr.as_ref() {
588 ExpressionType::MemberExpression(member) => {
590 match member {
591 MemberExpressionType::SimpleMemberExpression { object, .. } |
592 MemberExpressionType::ComputedMemberExpression { object, .. } => {
593 match object {
594 ExpressionOrSuper::Expression(obj_expr) => {
595 evaluate_expression(obj_expr, ctx).unwrap_or(JsValue::Undefined)
596 }
597 ExpressionOrSuper::Super => JsValue::Undefined,
598 }
599 }
600 }
601 }
602 _ => ctx.global_this.clone().unwrap_or(JsValue::Undefined),
604 }
605 }
606 ExpressionOrSuper::Super => JsValue::Undefined,
607 }
608}
609
610fn evaluate_arguments(
612 arguments: &[ExpressionOrSpreadElement],
613 ctx: &mut EvalContext,
614) -> Result<Vec<JsValue>, JErrorType> {
615 let mut args = Vec::with_capacity(arguments.len());
616 for arg in arguments {
617 match arg {
618 ExpressionOrSpreadElement::Expression(expr) => {
619 args.push(evaluate_expression(expr, ctx)?);
620 }
621 ExpressionOrSpreadElement::SpreadElement(spread_expr) => {
622 let spread_value = evaluate_expression(spread_expr, ctx)?;
624
625 if let JsValue::Object(spread_obj) = spread_value {
627 let borrowed = spread_obj.borrow();
628 let base = borrowed.as_js_object().get_object_base();
629
630 let length = if let Some(PropertyDescriptor::Data(prop)) =
632 base.properties.get(&PropertyKey::Str("length".to_string()))
633 {
634 match &prop.value {
635 JsValue::Number(JsNumberType::Integer(n)) => *n as usize,
636 JsValue::Number(JsNumberType::Float(n)) => *n as usize,
637 _ => 0,
638 }
639 } else {
640 0
641 };
642
643 for i in 0..length {
645 let elem_key = PropertyKey::Str(i.to_string());
646 let elem_value = if let Some(PropertyDescriptor::Data(prop)) =
647 base.properties.get(&elem_key)
648 {
649 prop.value.clone()
650 } else {
651 JsValue::Undefined
652 };
653 args.push(elem_value);
654 }
655 } else if let JsValue::String(s) = spread_value {
656 for ch in s.chars() {
658 args.push(JsValue::String(ch.to_string()));
659 }
660 } else {
661 return Err(JErrorType::TypeError(
662 "Spread requires an iterable".to_string(),
663 ));
664 }
665 }
666 }
667 }
668 Ok(args)
669}
670
671fn call_value(
673 callee: &JsValue,
674 this_value: JsValue,
675 args: Vec<JsValue>,
676 ctx: &mut EvalContext,
677) -> ValueResult {
678 match callee {
679 JsValue::Object(obj) => {
680 let obj_ref = obj.borrow();
681 if obj_ref.is_callable() {
682 drop(obj_ref);
683 call_function_object(obj, this_value, args, ctx)
688 } else {
689 Err(JErrorType::TypeError(format!(
690 "{} is not a function",
691 callee
692 )))
693 }
694 }
695 _ => Err(JErrorType::TypeError(format!(
696 "{} is not a function",
697 callee
698 ))),
699 }
700}
701
702pub fn call_function_object(
704 func: &crate::runner::ds::object::JsObjectType,
705 this_value: JsValue,
706 args: Vec<JsValue>,
707 ctx: &mut EvalContext,
708) -> ValueResult {
709 let func_ref = func.borrow();
710
711 match &*func_ref {
712 ObjectType::Function(func_obj) => {
713 let body = func_obj.get_function_object_base().body_code.clone();
715 let params = func_obj.get_function_object_base().formal_parameters.clone();
716 let func_env = func_obj.get_function_object_base().environment.clone();
717
718 drop(func_ref);
719
720 let saved_lex_env = ctx.lex_env.clone();
722 let saved_var_env = ctx.var_env.clone();
723
724 use crate::runner::ds::env_record::new_declarative_environment;
726 let func_scope = new_declarative_environment(Some(func_env));
727 ctx.lex_env = func_scope.clone();
728 ctx.var_env = func_scope;
729
730 for (i, param) in params.iter().enumerate() {
732 if let crate::parser::ast::PatternType::PatternWhichCanBeExpression(
733 ExpressionPatternType::Identifier(id)
734 ) = param {
735 let arg_value = args.get(i).cloned().unwrap_or(JsValue::Undefined);
736 ctx.create_binding(&id.name, false)?;
737 ctx.initialize_binding(&id.name, arg_value)?;
738 }
739 }
740
741 use super::statement::execute_statement;
743 use super::types::CompletionType;
744
745 let mut result_completion = super::types::Completion::normal();
746
747 for stmt in body.body.iter() {
748 let completion = execute_statement(stmt, ctx)?;
749
750 match completion.completion_type {
751 CompletionType::Return => {
752 result_completion = completion;
753 break;
754 }
755 CompletionType::Throw => {
756 ctx.lex_env = saved_lex_env;
758 ctx.var_env = saved_var_env;
759 return Err(JErrorType::TypeError(format!(
760 "Uncaught exception: {:?}",
761 completion.value
762 )));
763 }
764 CompletionType::Break | CompletionType::Continue | CompletionType::Yield => {
765 result_completion = completion;
767 break;
768 }
769 CompletionType::Normal => {
770 result_completion = completion;
771 }
772 }
773 }
774
775 ctx.lex_env = saved_lex_env;
777 ctx.var_env = saved_var_env;
778
779 match result_completion.completion_type {
781 CompletionType::Return => Ok(result_completion.get_value()),
782 _ => Ok(JsValue::Undefined),
783 }
784 }
785 ObjectType::Ordinary(obj) => {
786 let marker = PropertyKey::Str("__simple_function__".to_string());
788 let default_ctor_marker = PropertyKey::Str("__default_constructor__".to_string());
789
790 let generator_marker = PropertyKey::Str("__generator__".to_string());
791 let generator_next_marker = PropertyKey::Str("__generator_next__".to_string());
792
793 if obj.get_object_base().properties.contains_key(&default_ctor_marker) {
794 drop(func_ref);
796 Ok(JsValue::Undefined)
797 } else if let Some(PropertyDescriptor::Data(data)) = obj.get_object_base().properties.get(&generator_next_marker) {
798 let gen_obj = match &data.value {
800 JsValue::Object(o) => o.clone(),
801 _ => return Err(JErrorType::TypeError("Invalid generator reference".to_string())),
802 };
803 drop(func_ref);
804
805 let mut gen_borrowed = gen_obj.borrow_mut();
807
808 match &mut *gen_borrowed {
810 ObjectType::Ordinary(inner_obj) => {
811 let gen_marker = PropertyKey::Str("__generator_object__".to_string());
812 if inner_obj.get_object_base().properties.contains_key(&gen_marker) {
813 let gen_ptr = inner_obj.as_mut() as *mut dyn JsObject as *mut GeneratorObject;
815 drop(gen_borrowed);
816 unsafe {
818 let gen = &mut *gen_ptr;
819 gen.next(ctx)
820 }
821 } else {
822 Err(JErrorType::TypeError("Not a generator object".to_string()))
823 }
824 }
825 _ => Err(JErrorType::TypeError("Not a generator object".to_string())),
826 }
827 } else if obj.get_object_base().properties.contains_key(&generator_marker) {
828 let obj_ptr = obj.as_ref() as *const dyn JsObject;
830 drop(func_ref);
831
832 unsafe {
834 let simple_func = &*(obj_ptr as *const SimpleFunctionObject);
835 create_generator_object(
837 simple_func.body_ptr,
838 simple_func.params_ptr,
839 simple_func.environment.clone(),
840 args,
841 ctx,
842 )
843 }
844 } else if obj.get_object_base().properties.contains_key(&marker) {
845 let obj_ptr = obj.as_ref() as *const dyn JsObject;
848 drop(func_ref);
849
850 unsafe {
852 let simple_func = &*(obj_ptr as *const SimpleFunctionObject);
854 simple_func.call_with_this(this_value, args, ctx)
855 }
856 } else {
857 Err(JErrorType::TypeError("Object is not callable".to_string()))
858 }
859 }
860 }
861}
862
863
864fn get_property_with_ctx(value: &JsValue, prop_name: &str, ctx: &mut EvalContext) -> ValueResult {
866 get_property_with_receiver(value, value, prop_name, ctx)
868}
869
870fn get_property_with_receiver(
873 receiver: &JsValue,
874 lookup_target: &JsValue,
875 prop_name: &str,
876 ctx: &mut EvalContext,
877) -> ValueResult {
878 match lookup_target {
879 JsValue::Object(obj) => {
880 let is_gen_obj = {
882 let obj_ref = obj.borrow();
883 let marker = PropertyKey::Str("__generator_object__".to_string());
884 obj_ref.as_js_object().get_object_base().properties.contains_key(&marker)
885 };
886
887 if is_gen_obj && prop_name == "next" {
888 return create_generator_next_method(obj.clone());
891 }
892
893 let prop_key = PropertyKey::Str(prop_name.to_string());
894
895 let desc = {
897 let obj_ref = obj.borrow();
898 obj_ref.as_js_object().get_own_property(&prop_key)?.cloned()
899 };
900
901 if let Some(desc) = desc {
902 match desc {
903 PropertyDescriptor::Data(data) => Ok(data.value.clone()),
904 PropertyDescriptor::Accessor(accessor) => {
905 if let Some(getter) = accessor.get {
907 call_accessor_function(&getter, receiver.clone(), vec![], ctx)
908 } else {
909 Ok(JsValue::Undefined)
910 }
911 }
912 }
913 } else {
914 let proto = obj.borrow().as_js_object().get_prototype_of();
916 if let Some(proto) = proto {
917 get_property_with_receiver(receiver, &JsValue::Object(proto), prop_name, ctx)
918 } else {
919 Ok(JsValue::Undefined)
920 }
921 }
922 }
923 JsValue::String(s) => {
924 if prop_name == "length" {
926 Ok(JsValue::Number(JsNumberType::Integer(s.len() as i64)))
927 } else if let Ok(index) = prop_name.parse::<usize>() {
928 if index < s.len() {
930 Ok(JsValue::String(s.chars().nth(index).unwrap().to_string()))
931 } else {
932 Ok(JsValue::Undefined)
933 }
934 } else {
935 Ok(JsValue::Undefined)
937 }
938 }
939 JsValue::Undefined => {
940 Err(JErrorType::TypeError("Cannot read property of undefined".to_string()))
941 }
942 JsValue::Null => {
943 Err(JErrorType::TypeError("Cannot read property of null".to_string()))
944 }
945 _ => {
946 Ok(JsValue::Undefined)
948 }
949 }
950}
951
952fn call_accessor_function(
954 func: &JsObjectType,
955 this_value: JsValue,
956 args: Vec<JsValue>,
957 ctx: &mut EvalContext,
958) -> ValueResult {
959 let func_ref = func.borrow();
960
961 if let ObjectType::Ordinary(obj) = &*func_ref {
963 if is_simple_function_object(obj.as_ref()) {
964 let simple_func = unsafe {
968 let ptr = obj.as_ref() as *const dyn JsObject as *const SimpleFunctionObject;
970 &*ptr
971 };
972 drop(func_ref);
973 return simple_func.call_with_this(this_value, args, ctx);
974 }
975
976 drop(func_ref);
978 call_function_object(func, this_value, args, ctx)
979 } else if let ObjectType::Function(func_obj) = &*func_ref {
980 let body = func_obj.get_function_object_base().body_code.clone();
982 let params = func_obj.get_function_object_base().formal_parameters.clone();
983 let func_env = func_obj.get_function_object_base().environment.clone();
984
985 drop(func_ref);
986
987 call_function_with_body(body, params, func_env, this_value, args, ctx)
988 } else {
989 Err(JErrorType::TypeError("Not a function".to_string()))
990 }
991}
992
993fn call_function_with_body(
995 body: Rc<crate::parser::ast::FunctionBodyData>,
996 params: Rc<Vec<PatternType>>,
997 func_env: crate::runner::ds::lex_env::JsLexEnvironmentType,
998 this_value: JsValue,
999 args: Vec<JsValue>,
1000 ctx: &mut EvalContext,
1001) -> ValueResult {
1002 use crate::runner::ds::env_record::new_declarative_environment;
1003 use super::statement::execute_statement;
1004 use super::types::CompletionType;
1005
1006 let saved_lex_env = ctx.lex_env.clone();
1008 let saved_var_env = ctx.var_env.clone();
1009 let saved_this = ctx.global_this.clone();
1010
1011 let func_scope = new_declarative_environment(Some(func_env));
1013 ctx.lex_env = func_scope.clone();
1014 ctx.var_env = func_scope;
1015 ctx.global_this = Some(this_value);
1016
1017 for (i, param) in params.iter().enumerate() {
1019 if let PatternType::PatternWhichCanBeExpression(
1020 ExpressionPatternType::Identifier(id)
1021 ) = param {
1022 let arg_value = args.get(i).cloned().unwrap_or(JsValue::Undefined);
1023 ctx.create_binding(&id.name, false)?;
1024 ctx.initialize_binding(&id.name, arg_value)?;
1025 }
1026 }
1027
1028 let mut result_completion = super::types::Completion::normal();
1030
1031 for stmt in body.body.iter() {
1032 let completion = execute_statement(stmt, ctx)?;
1033
1034 match completion.completion_type {
1035 CompletionType::Return => {
1036 result_completion = completion;
1037 break;
1038 }
1039 CompletionType::Throw => {
1040 ctx.lex_env = saved_lex_env;
1042 ctx.var_env = saved_var_env;
1043 ctx.global_this = saved_this;
1044 return Err(JErrorType::TypeError(format!(
1045 "Uncaught exception: {:?}",
1046 completion.value
1047 )));
1048 }
1049 CompletionType::Break | CompletionType::Continue | CompletionType::Yield => {
1050 result_completion = completion;
1051 break;
1052 }
1053 CompletionType::Normal => {
1054 result_completion = completion;
1055 }
1056 }
1057 }
1058
1059 ctx.lex_env = saved_lex_env;
1061 ctx.var_env = saved_var_env;
1062 ctx.global_this = saved_this;
1063
1064 match result_completion.completion_type {
1066 CompletionType::Return => Ok(result_completion.get_value()),
1067 _ => Ok(JsValue::Undefined),
1068 }
1069}
1070
1071fn to_property_key(value: &JsValue) -> String {
1073 to_string(value)
1074}
1075
1076fn evaluate_assignment_expression(
1078 operator: &AssignmentOperator,
1079 left: &PatternOrExpression,
1080 right: &ExpressionType,
1081 ctx: &mut EvalContext,
1082) -> ValueResult {
1083 if let PatternOrExpression::Expression(expr) = left {
1085 if let ExpressionType::MemberExpression(member) = expr.as_ref() {
1086 return evaluate_member_assignment(operator, member, right, ctx);
1087 }
1088 }
1089
1090 if let PatternOrExpression::Pattern(pattern) = left {
1092 if !matches!(
1093 &**pattern,
1094 PatternType::PatternWhichCanBeExpression(ExpressionPatternType::Identifier(_))
1095 ) {
1096 if !matches!(operator, AssignmentOperator::Equals) {
1097 return Err(JErrorType::TypeError(
1098 "Compound assignment not supported for destructuring patterns".to_string(),
1099 ));
1100 }
1101 let rhs_value = evaluate_expression(right, ctx)?;
1102 assign_pattern(pattern, rhs_value.clone(), ctx)?;
1103 return Ok(rhs_value);
1104 }
1105 }
1106
1107 let name = match left {
1109 PatternOrExpression::Pattern(pattern) => get_pattern_name(pattern)?,
1110 PatternOrExpression::Expression(expr) => get_expression_name(expr)?,
1111 };
1112
1113 let rhs_value = evaluate_expression(right, ctx)?;
1115
1116 let final_value = match operator {
1118 AssignmentOperator::Equals => rhs_value,
1119 AssignmentOperator::AddEquals => {
1120 let current = ctx.get_binding(&name)?;
1121 add_values(¤t, &rhs_value)?
1122 }
1123 AssignmentOperator::SubtractEquals => {
1124 let current = ctx.get_binding(&name)?;
1125 subtract_values(¤t, &rhs_value)?
1126 }
1127 AssignmentOperator::MultiplyEquals => {
1128 let current = ctx.get_binding(&name)?;
1129 multiply_values(¤t, &rhs_value)?
1130 }
1131 AssignmentOperator::DivideEquals => {
1132 let current = ctx.get_binding(&name)?;
1133 divide_values(¤t, &rhs_value)?
1134 }
1135 AssignmentOperator::ModuloEquals => {
1136 let current = ctx.get_binding(&name)?;
1137 modulo_values(¤t, &rhs_value)?
1138 }
1139 AssignmentOperator::BitwiseLeftShiftEquals => {
1140 let current = ctx.get_binding(&name)?;
1141 left_shift(¤t, &rhs_value)?
1142 }
1143 AssignmentOperator::BitwiseRightShiftEquals => {
1144 let current = ctx.get_binding(&name)?;
1145 right_shift(¤t, &rhs_value)?
1146 }
1147 AssignmentOperator::BitwiseUnsignedRightShiftEquals => {
1148 let current = ctx.get_binding(&name)?;
1149 unsigned_right_shift(¤t, &rhs_value)?
1150 }
1151 AssignmentOperator::BitwiseOrEquals => {
1152 let current = ctx.get_binding(&name)?;
1153 bitwise_or(¤t, &rhs_value)?
1154 }
1155 AssignmentOperator::BitwiseAndEquals => {
1156 let current = ctx.get_binding(&name)?;
1157 bitwise_and(¤t, &rhs_value)?
1158 }
1159 AssignmentOperator::BitwiseXorEquals => {
1160 let current = ctx.get_binding(&name)?;
1161 bitwise_xor(¤t, &rhs_value)?
1162 }
1163 };
1164
1165 ctx.set_binding(&name, final_value.clone())?;
1167 Ok(final_value)
1168}
1169
1170fn assign_pattern(
1172 pattern: &PatternType,
1173 value: JsValue,
1174 ctx: &mut EvalContext,
1175) -> Result<(), JErrorType> {
1176 match pattern {
1177 PatternType::PatternWhichCanBeExpression(ExpressionPatternType::Identifier(id)) => {
1178 ctx.set_binding(&id.name, value)?;
1179 Ok(())
1180 }
1181 PatternType::ObjectPattern { properties, .. } => {
1182 for prop in properties {
1183 let prop_data = &prop.0;
1184 let key_name = get_assignment_property_key(prop_data, ctx)?;
1185 let prop_value = get_object_property_value(&value, &key_name, ctx)?;
1186 assign_pattern(&prop_data.value, prop_value, ctx)?;
1187 }
1188 Ok(())
1189 }
1190 PatternType::ArrayPattern { elements, .. } => {
1191 for (index, element) in elements.iter().enumerate() {
1192 if let Some(elem_pattern) = element {
1193 if let PatternType::RestElement { argument, .. } = elem_pattern.as_ref() {
1194 let rest_value = get_rest_elements_for_assignment(&value, index, ctx)?;
1195 assign_pattern(argument, rest_value, ctx)?;
1196 } else {
1197 let elem_value = get_array_element_for_assignment(&value, index, ctx)?;
1198 assign_pattern(elem_pattern, elem_value, ctx)?;
1199 }
1200 }
1201 }
1202 Ok(())
1203 }
1204 PatternType::AssignmentPattern { left, right, .. } => {
1205 let actual_value = if matches!(value, JsValue::Undefined) {
1206 evaluate_expression(right, ctx)?
1207 } else {
1208 value
1209 };
1210 assign_pattern(left, actual_value, ctx)
1211 }
1212 PatternType::RestElement { argument, .. } => assign_pattern(argument, value, ctx),
1213 }
1214}
1215
1216fn get_assignment_property_key(
1217 prop: &PropertyData<Box<PatternType>>,
1218 ctx: &mut EvalContext,
1219) -> Result<String, JErrorType> {
1220 if prop.computed {
1221 let key_value = evaluate_expression(prop.key.as_ref(), ctx)?;
1222 Ok(to_string(&key_value))
1223 } else {
1224 match prop.key.as_ref() {
1225 ExpressionType::ExpressionWhichCanBePattern(ExpressionPatternType::Identifier(id)) => {
1226 Ok(id.name.clone())
1227 }
1228 ExpressionType::Literal(lit_data) => match &lit_data.value {
1229 LiteralType::StringLiteral(s) => Ok(s.clone()),
1230 LiteralType::NumberLiteral(num) => {
1231 use crate::parser::ast::NumberLiteralType;
1232 match num {
1233 NumberLiteralType::IntegerLiteral(n) => Ok(n.to_string()),
1234 NumberLiteralType::FloatLiteral(n) => Ok(n.to_string()),
1235 }
1236 }
1237 _ => Err(JErrorType::TypeError(
1238 "Invalid property key in destructuring assignment".to_string(),
1239 )),
1240 },
1241 _ => Err(JErrorType::TypeError(
1242 "Invalid property key in destructuring assignment".to_string(),
1243 )),
1244 }
1245 }
1246}
1247
1248fn get_object_property_value(
1249 obj: &JsValue,
1250 key: &str,
1251 ctx: &mut EvalContext,
1252) -> Result<JsValue, JErrorType> {
1253 match obj {
1254 JsValue::Object(_) => get_property_with_ctx(obj, key, ctx),
1255 _ => Err(JErrorType::TypeError(
1256 "Cannot destructure non-object".to_string(),
1257 )),
1258 }
1259}
1260
1261fn get_array_element_for_assignment(
1262 arr: &JsValue,
1263 index: usize,
1264 ctx: &mut EvalContext,
1265) -> Result<JsValue, JErrorType> {
1266 match arr {
1267 JsValue::Object(_) => {
1268 let key = index.to_string();
1269 get_property_with_ctx(arr, &key, ctx)
1270 }
1271 _ => Err(JErrorType::TypeError(
1272 "Cannot destructure non-array".to_string(),
1273 )),
1274 }
1275}
1276
1277fn get_rest_elements_for_assignment(
1278 arr: &JsValue,
1279 start_index: usize,
1280 ctx: &mut EvalContext,
1281) -> Result<JsValue, JErrorType> {
1282 use crate::runner::ds::object::{JsObject, JsObjectType, ObjectType};
1283 use crate::runner::ds::object_property::{PropertyDescriptor, PropertyDescriptorData, PropertyKey};
1284 use std::cell::RefCell;
1285 use std::rc::Rc;
1286
1287 let length = match arr {
1288 JsValue::Object(_) => {
1289 let length_value = get_property_with_ctx(arr, "length", ctx)?;
1290 match length_value {
1291 JsValue::Number(JsNumberType::Integer(n)) => n.max(0) as usize,
1292 JsValue::Number(JsNumberType::Float(n)) => {
1293 if n.is_nan() || n < 0.0 {
1294 0
1295 } else {
1296 n as usize
1297 }
1298 }
1299 _ => 0,
1300 }
1301 }
1302 _ => {
1303 return Err(JErrorType::TypeError(
1304 "Cannot use rest with non-array".to_string(),
1305 ))
1306 }
1307 };
1308
1309 let mut rest_obj = ctx.new_tracked_object()?;
1310 let mut rest_index = 0;
1311
1312 for i in start_index..length {
1313 let key = i.to_string();
1314 let value = get_property_with_ctx(arr, &key, ctx)?;
1315 rest_obj.get_object_base_mut().properties.insert(
1316 PropertyKey::Str(rest_index.to_string()),
1317 PropertyDescriptor::Data(PropertyDescriptorData {
1318 value,
1319 writable: true,
1320 enumerable: true,
1321 configurable: true,
1322 }),
1323 );
1324 rest_index += 1;
1325 }
1326
1327 rest_obj.get_object_base_mut().properties.insert(
1328 PropertyKey::Str("length".to_string()),
1329 PropertyDescriptor::Data(PropertyDescriptorData {
1330 value: JsValue::Number(JsNumberType::Integer(rest_index as i64)),
1331 writable: true,
1332 enumerable: false,
1333 configurable: false,
1334 }),
1335 );
1336
1337 let obj: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(rest_obj))));
1338 Ok(JsValue::Object(obj))
1339}
1340
1341fn evaluate_member_assignment(
1343 operator: &AssignmentOperator,
1344 member: &MemberExpressionType,
1345 right: &ExpressionType,
1346 ctx: &mut EvalContext,
1347) -> ValueResult {
1348 let (obj_value, prop_name) = match member {
1350 MemberExpressionType::SimpleMemberExpression { object, property, .. } => {
1351 let obj = evaluate_expression_or_super(object, ctx)?;
1352 (obj, property.name.clone())
1353 }
1354 MemberExpressionType::ComputedMemberExpression { object, property, .. } => {
1355 let obj = evaluate_expression_or_super(object, ctx)?;
1356 let prop_val = evaluate_expression(property.as_ref(), ctx)?;
1357 (obj, to_property_key(&prop_val))
1358 }
1359 };
1360
1361 let rhs_value = evaluate_expression(right, ctx)?;
1363
1364 let final_value = if matches!(operator, AssignmentOperator::Equals) {
1366 rhs_value
1367 } else {
1368 let current = get_property_with_ctx(&obj_value, &prop_name, ctx)?;
1369 match operator {
1370 AssignmentOperator::Equals => unreachable!(),
1371 AssignmentOperator::AddEquals => add_values(¤t, &rhs_value)?,
1372 AssignmentOperator::SubtractEquals => subtract_values(¤t, &rhs_value)?,
1373 AssignmentOperator::MultiplyEquals => multiply_values(¤t, &rhs_value)?,
1374 AssignmentOperator::DivideEquals => divide_values(¤t, &rhs_value)?,
1375 AssignmentOperator::ModuloEquals => modulo_values(¤t, &rhs_value)?,
1376 AssignmentOperator::BitwiseLeftShiftEquals => left_shift(¤t, &rhs_value)?,
1377 AssignmentOperator::BitwiseRightShiftEquals => right_shift(¤t, &rhs_value)?,
1378 AssignmentOperator::BitwiseUnsignedRightShiftEquals => unsigned_right_shift(¤t, &rhs_value)?,
1379 AssignmentOperator::BitwiseOrEquals => bitwise_or(¤t, &rhs_value)?,
1380 AssignmentOperator::BitwiseAndEquals => bitwise_and(¤t, &rhs_value)?,
1381 AssignmentOperator::BitwiseXorEquals => bitwise_xor(¤t, &rhs_value)?,
1382 }
1383 };
1384
1385 set_property_with_ctx(&obj_value, &prop_name, final_value.clone(), ctx)?;
1387 Ok(final_value)
1388}
1389
1390fn set_property_with_ctx(
1392 value: &JsValue,
1393 prop_name: &str,
1394 new_value: JsValue,
1395 ctx: &mut EvalContext,
1396) -> Result<(), JErrorType> {
1397 match value {
1398 JsValue::Object(obj) => {
1399 let prop_key = PropertyKey::Str(prop_name.to_string());
1400
1401 let desc = {
1403 let obj_ref = obj.borrow();
1404 obj_ref.as_js_object().get_own_property(&prop_key)?.cloned()
1405 };
1406
1407 if let Some(PropertyDescriptor::Accessor(accessor)) = desc {
1408 if let Some(setter) = accessor.set {
1410 call_accessor_function(&setter, value.clone(), vec![new_value], ctx)?;
1411 return Ok(());
1412 }
1413 }
1415
1416 let mut obj_mut = obj.borrow_mut();
1418 obj_mut.as_js_object_mut().get_object_base_mut().properties.insert(
1419 prop_key,
1420 PropertyDescriptor::Data(PropertyDescriptorData {
1421 value: new_value,
1422 writable: true,
1423 enumerable: true,
1424 configurable: true,
1425 }),
1426 );
1427 Ok(())
1428 }
1429 _ => Err(JErrorType::TypeError("Cannot set property on non-object".to_string())),
1430 }
1431}
1432
1433fn get_pattern_name(pattern: &PatternType) -> Result<String, JErrorType> {
1435 match pattern {
1436 PatternType::PatternWhichCanBeExpression(ExpressionPatternType::Identifier(id)) => {
1437 Ok(id.name.clone())
1438 }
1439 _ => Err(JErrorType::TypeError(
1440 "Complex patterns in assignment not yet supported".to_string(),
1441 )),
1442 }
1443}
1444
1445fn get_expression_name(expr: &ExpressionType) -> Result<String, JErrorType> {
1447 match expr {
1448 ExpressionType::ExpressionWhichCanBePattern(ExpressionPatternType::Identifier(id)) => {
1449 Ok(id.name.clone())
1450 }
1451 _ => Err(JErrorType::TypeError(
1452 "Assignment to non-identifier expressions not yet supported".to_string(),
1453 )),
1454 }
1455}
1456
1457fn evaluate_unary_expression(
1459 operator: &UnaryOperator,
1460 argument: &ExpressionType,
1461 ctx: &mut EvalContext,
1462) -> ValueResult {
1463 match operator {
1464 UnaryOperator::TypeOf => {
1465 let value = evaluate_expression(argument, ctx).unwrap_or(JsValue::Undefined);
1466 Ok(JsValue::String(get_typeof_string(&value)))
1467 }
1468 UnaryOperator::Void => {
1469 let _ = evaluate_expression(argument, ctx)?;
1470 Ok(JsValue::Undefined)
1471 }
1472 UnaryOperator::LogicalNot => {
1473 let value = evaluate_expression(argument, ctx)?;
1474 Ok(JsValue::Boolean(!to_boolean(&value)))
1475 }
1476 UnaryOperator::Minus => {
1477 let value = evaluate_expression(argument, ctx)?;
1478 negate_number(&value)
1479 }
1480 UnaryOperator::Plus => {
1481 let value = evaluate_expression(argument, ctx)?;
1482 to_number(&value)
1483 }
1484 UnaryOperator::BitwiseNot => {
1485 let value = evaluate_expression(argument, ctx)?;
1486 bitwise_not(&value)
1487 }
1488 UnaryOperator::Delete => {
1489 match argument {
1490 ExpressionType::MemberExpression(member) => {
1491 match member {
1492 MemberExpressionType::SimpleMemberExpression { object, property, .. } => {
1493 let obj_value = evaluate_expression_or_super(object, ctx)?;
1494 match obj_value {
1495 JsValue::Object(obj) => {
1496 let prop_key = PropertyKey::Str(property.name.clone());
1497 let result = obj.borrow_mut().as_js_object_mut().delete(&prop_key)?;
1498 Ok(JsValue::Boolean(result))
1499 }
1500 _ => Ok(JsValue::Boolean(true))
1501 }
1502 }
1503 MemberExpressionType::ComputedMemberExpression { object, property, .. } => {
1504 let obj_value = evaluate_expression_or_super(object, ctx)?;
1505 let prop_value = evaluate_expression(property.as_ref(), ctx)?;
1506 let prop_name = to_property_key(&prop_value);
1507 match obj_value {
1508 JsValue::Object(obj) => {
1509 let prop_key = PropertyKey::Str(prop_name);
1510 let result = obj.borrow_mut().as_js_object_mut().delete(&prop_key)?;
1511 Ok(JsValue::Boolean(result))
1512 }
1513 _ => Ok(JsValue::Boolean(true))
1514 }
1515 }
1516 }
1517 }
1518 _ => {
1519 let _ = evaluate_expression(argument, ctx)?;
1521 Ok(JsValue::Boolean(true))
1522 }
1523 }
1524 }
1525 }
1526}
1527
1528fn evaluate_binary_expression(
1530 operator: &BinaryOperator,
1531 left: &ExpressionType,
1532 right: &ExpressionType,
1533 ctx: &mut EvalContext,
1534) -> ValueResult {
1535 let left_val = evaluate_expression(left, ctx)?;
1536 let right_val = evaluate_expression(right, ctx)?;
1537
1538 match operator {
1539 BinaryOperator::Add => add_values(&left_val, &right_val),
1541 BinaryOperator::Subtract => subtract_values(&left_val, &right_val),
1542 BinaryOperator::Multiply => multiply_values(&left_val, &right_val),
1543 BinaryOperator::Divide => divide_values(&left_val, &right_val),
1544 BinaryOperator::Modulo => modulo_values(&left_val, &right_val),
1545
1546 BinaryOperator::LessThan => compare_values(&left_val, &right_val, |a, b| a < b),
1548 BinaryOperator::GreaterThan => compare_values(&left_val, &right_val, |a, b| a > b),
1549 BinaryOperator::LessThanEqual => compare_values(&left_val, &right_val, |a, b| a <= b),
1550 BinaryOperator::GreaterThanEqual => compare_values(&left_val, &right_val, |a, b| a >= b),
1551
1552 BinaryOperator::StrictlyEqual => Ok(JsValue::Boolean(strict_equality(&left_val, &right_val))),
1554 BinaryOperator::StrictlyUnequal => Ok(JsValue::Boolean(!strict_equality(&left_val, &right_val))),
1555 BinaryOperator::LooselyEqual => Ok(JsValue::Boolean(loose_equality(&left_val, &right_val))),
1556 BinaryOperator::LooselyUnequal => Ok(JsValue::Boolean(!loose_equality(&left_val, &right_val))),
1557
1558 BinaryOperator::BitwiseAnd => bitwise_and(&left_val, &right_val),
1560 BinaryOperator::BitwiseOr => bitwise_or(&left_val, &right_val),
1561 BinaryOperator::BitwiseXor => bitwise_xor(&left_val, &right_val),
1562 BinaryOperator::BitwiseLeftShift => left_shift(&left_val, &right_val),
1563 BinaryOperator::BitwiseRightShift => right_shift(&left_val, &right_val),
1564 BinaryOperator::BitwiseUnsignedRightShift => unsigned_right_shift(&left_val, &right_val),
1565
1566 BinaryOperator::InstanceOf => {
1568 let left_obj = match &left_val {
1570 JsValue::Object(obj) => obj.clone(),
1571 _ => return Ok(JsValue::Boolean(false)),
1572 };
1573
1574 let right_obj = match &right_val {
1576 JsValue::Object(obj) => obj.clone(),
1577 _ => return Err(JErrorType::TypeError("Right-hand side of 'instanceof' is not an object".to_string())),
1578 };
1579
1580 let proto_key = PropertyKey::Str("prototype".to_string());
1582 let right_prototype = {
1583 let right_borrowed = right_obj.borrow();
1584 if let Some(desc) = right_borrowed.as_js_object().get_own_property(&proto_key)? {
1585 match desc {
1586 PropertyDescriptor::Data(data) => {
1587 match &data.value {
1588 JsValue::Object(p) => Some(p.clone()),
1589 _ => None,
1590 }
1591 }
1592 _ => None,
1593 }
1594 } else {
1595 None
1596 }
1597 };
1598
1599 let target_proto = match right_prototype {
1601 Some(p) => p,
1602 None => return Ok(JsValue::Boolean(false)),
1603 };
1604
1605 let mut current_proto = left_obj.borrow().as_js_object().get_prototype_of();
1607
1608 while let Some(proto) = current_proto {
1609 if Rc::ptr_eq(&proto, &target_proto) {
1611 return Ok(JsValue::Boolean(true));
1612 }
1613 current_proto = proto.borrow().as_js_object().get_prototype_of();
1614 }
1615
1616 Ok(JsValue::Boolean(false))
1617 }
1618 BinaryOperator::In => {
1619 let prop_key = PropertyKey::Str(to_property_key(&left_val));
1620 match &right_val {
1621 JsValue::Object(obj) => {
1622 let has = obj.borrow().as_js_object().has_property(&prop_key);
1623 Ok(JsValue::Boolean(has))
1624 }
1625 _ => Err(JErrorType::TypeError("Cannot use 'in' operator with non-object".to_string()))
1626 }
1627 }
1628 }
1629}
1630
1631fn evaluate_logical_expression(
1633 operator: &LogicalOperator,
1634 left: &ExpressionType,
1635 right: &ExpressionType,
1636 ctx: &mut EvalContext,
1637) -> ValueResult {
1638 let left_val = evaluate_expression(left, ctx)?;
1639
1640 match operator {
1641 LogicalOperator::And => {
1642 if !to_boolean(&left_val) {
1643 Ok(left_val)
1644 } else {
1645 evaluate_expression(right, ctx)
1646 }
1647 }
1648 LogicalOperator::Or => {
1649 if to_boolean(&left_val) {
1650 Ok(left_val)
1651 } else {
1652 evaluate_expression(right, ctx)
1653 }
1654 }
1655 }
1656}
1657
1658fn evaluate_conditional_expression(
1660 test: &ExpressionType,
1661 consequent: &ExpressionType,
1662 alternate: &ExpressionType,
1663 ctx: &mut EvalContext,
1664) -> ValueResult {
1665 let test_val = evaluate_expression(test, ctx)?;
1666
1667 if to_boolean(&test_val) {
1668 evaluate_expression(consequent, ctx)
1669 } else {
1670 evaluate_expression(alternate, ctx)
1671 }
1672}
1673
1674fn evaluate_sequence_expression(
1676 expressions: &[Box<ExpressionType>],
1677 ctx: &mut EvalContext,
1678) -> ValueResult {
1679 let mut result = JsValue::Undefined;
1680 for expr in expressions {
1681 result = evaluate_expression(expr.as_ref(), ctx)?;
1682 }
1683 Ok(result)
1684}
1685
1686fn evaluate_update_expression(
1688 operator: &UpdateOperator,
1689 argument: &ExpressionType,
1690 prefix: bool,
1691 ctx: &mut EvalContext,
1692) -> ValueResult {
1693 let name = get_expression_name(argument)?;
1695
1696 let current_value = ctx.get_binding(&name)?;
1698
1699 let old_number = to_number(¤t_value)?;
1701 let old_f64 = match &old_number {
1702 JsValue::Number(n) => number_to_f64(n),
1703 _ => f64::NAN,
1704 };
1705
1706 let new_f64 = match operator {
1708 UpdateOperator::PlusPlus => old_f64 + 1.0,
1709 UpdateOperator::MinusMinus => old_f64 - 1.0,
1710 };
1711
1712 let new_value = if new_f64.fract() == 0.0 && new_f64.abs() < i64::MAX as f64 {
1714 JsValue::Number(JsNumberType::Integer(new_f64 as i64))
1715 } else {
1716 JsValue::Number(JsNumberType::Float(new_f64))
1717 };
1718
1719 ctx.set_binding(&name, new_value.clone())?;
1721
1722 if prefix {
1724 Ok(new_value)
1725 } else {
1726 Ok(old_number)
1727 }
1728}
1729
1730pub fn to_boolean(value: &JsValue) -> bool {
1736 match value {
1737 JsValue::Undefined => false,
1738 JsValue::Null => false,
1739 JsValue::Boolean(b) => *b,
1740 JsValue::Number(n) => match n {
1741 JsNumberType::Integer(0) => false,
1742 JsNumberType::Float(f) if *f == 0.0 || f.is_nan() => false,
1743 JsNumberType::NaN => false,
1744 _ => true,
1745 },
1746 JsValue::String(s) => !s.is_empty(),
1747 JsValue::Symbol(_) => true,
1748 JsValue::Object(_) => true,
1749 }
1750}
1751
1752fn get_typeof_string(value: &JsValue) -> String {
1754 match value {
1755 JsValue::Undefined => "undefined".to_string(),
1756 JsValue::Null => "object".to_string(),
1757 JsValue::Boolean(_) => "boolean".to_string(),
1758 JsValue::Number(_) => "number".to_string(),
1759 JsValue::String(_) => "string".to_string(),
1760 JsValue::Symbol(_) => "symbol".to_string(),
1761 JsValue::Object(_) => "object".to_string(),
1762 }
1763}
1764
1765fn to_number(value: &JsValue) -> ValueResult {
1767 Ok(match value {
1768 JsValue::Undefined => JsValue::Number(JsNumberType::NaN),
1769 JsValue::Null => JsValue::Number(JsNumberType::Integer(0)),
1770 JsValue::Boolean(true) => JsValue::Number(JsNumberType::Integer(1)),
1771 JsValue::Boolean(false) => JsValue::Number(JsNumberType::Integer(0)),
1772 JsValue::Number(n) => JsValue::Number(n.clone()),
1773 JsValue::String(s) => {
1774 if s.is_empty() {
1775 JsValue::Number(JsNumberType::Integer(0))
1776 } else if let Ok(i) = s.trim().parse::<i64>() {
1777 JsValue::Number(JsNumberType::Integer(i))
1778 } else if let Ok(f) = s.trim().parse::<f64>() {
1779 JsValue::Number(JsNumberType::Float(f))
1780 } else {
1781 JsValue::Number(JsNumberType::NaN)
1782 }
1783 }
1784 JsValue::Symbol(_) => {
1785 return Err(JErrorType::TypeError("Cannot convert Symbol to number".to_string()));
1786 }
1787 JsValue::Object(_) => JsValue::Number(JsNumberType::NaN),
1788 })
1789}
1790
1791fn negate_number(value: &JsValue) -> ValueResult {
1793 let num_value = to_number(value)?;
1794 Ok(match num_value {
1795 JsValue::Number(JsNumberType::Integer(i)) => JsValue::Number(JsNumberType::Integer(-i)),
1796 JsValue::Number(JsNumberType::Float(f)) => JsValue::Number(JsNumberType::Float(-f)),
1797 JsValue::Number(JsNumberType::PositiveInfinity) => JsValue::Number(JsNumberType::NegativeInfinity),
1798 JsValue::Number(JsNumberType::NegativeInfinity) => JsValue::Number(JsNumberType::PositiveInfinity),
1799 JsValue::Number(JsNumberType::NaN) => JsValue::Number(JsNumberType::NaN),
1800 _ => JsValue::Number(JsNumberType::NaN),
1801 })
1802}
1803
1804fn bitwise_not(value: &JsValue) -> ValueResult {
1806 let num = to_i32(value)?;
1807 Ok(JsValue::Number(JsNumberType::Integer(!num as i64)))
1808}
1809
1810fn to_i32(value: &JsValue) -> Result<i32, JErrorType> {
1812 match to_number(value)? {
1813 JsValue::Number(JsNumberType::Integer(i)) => Ok(i as i32),
1814 JsValue::Number(JsNumberType::Float(f)) => Ok(f as i32),
1815 JsValue::Number(JsNumberType::NaN) => Ok(0),
1816 JsValue::Number(JsNumberType::PositiveInfinity) => Ok(0),
1817 JsValue::Number(JsNumberType::NegativeInfinity) => Ok(0),
1818 _ => Ok(0),
1819 }
1820}
1821
1822fn to_u32(value: &JsValue) -> Result<u32, JErrorType> {
1824 Ok(to_i32(value)? as u32)
1825}
1826
1827fn add_values(left: &JsValue, right: &JsValue) -> ValueResult {
1832 if matches!(left, JsValue::String(_)) || matches!(right, JsValue::String(_)) {
1833 let left_str = to_string(left);
1834 let right_str = to_string(right);
1835 return Ok(JsValue::String(format!("{}{}", left_str, right_str)));
1836 }
1837
1838 let left_num = to_number(left)?;
1839 let right_num = to_number(right)?;
1840 apply_numeric_op(&left_num, &right_num, |a, b| a + b, |a, b| a + b)
1841}
1842
1843fn subtract_values(left: &JsValue, right: &JsValue) -> ValueResult {
1844 let left_num = to_number(left)?;
1845 let right_num = to_number(right)?;
1846 apply_numeric_op(&left_num, &right_num, |a, b| a - b, |a, b| a - b)
1847}
1848
1849fn multiply_values(left: &JsValue, right: &JsValue) -> ValueResult {
1850 let left_num = to_number(left)?;
1851 let right_num = to_number(right)?;
1852 apply_numeric_op(&left_num, &right_num, |a, b| a * b, |a, b| a * b)
1853}
1854
1855fn divide_values(left: &JsValue, right: &JsValue) -> ValueResult {
1856 let left_num = to_number(left)?;
1857 let right_num = to_number(right)?;
1858
1859 if matches!(right_num, JsValue::Number(JsNumberType::Integer(0)))
1860 || matches!(right_num, JsValue::Number(JsNumberType::Float(f)) if f == 0.0)
1861 {
1862 let left_f = match &left_num {
1863 JsValue::Number(n) => number_to_f64(n),
1864 _ => f64::NAN,
1865 };
1866 return Ok(if left_f.is_nan() || left_f == 0.0 {
1867 JsValue::Number(JsNumberType::NaN)
1868 } else if left_f > 0.0 {
1869 JsValue::Number(JsNumberType::PositiveInfinity)
1870 } else {
1871 JsValue::Number(JsNumberType::NegativeInfinity)
1872 });
1873 }
1874
1875 apply_numeric_op(&left_num, &right_num, |a, b| a / b, |a, b| a / b)
1876}
1877
1878fn modulo_values(left: &JsValue, right: &JsValue) -> ValueResult {
1879 let left_num = to_number(left)?;
1880 let right_num = to_number(right)?;
1881 apply_numeric_op(&left_num, &right_num, |a, b| a % b, |a, b| a % b)
1882}
1883
1884fn apply_numeric_op<F, G>(left: &JsValue, right: &JsValue, int_op: F, float_op: G) -> ValueResult
1885where
1886 F: Fn(i64, i64) -> i64,
1887 G: Fn(f64, f64) -> f64,
1888{
1889 match (left, right) {
1890 (JsValue::Number(JsNumberType::NaN), _) | (_, JsValue::Number(JsNumberType::NaN)) => {
1891 Ok(JsValue::Number(JsNumberType::NaN))
1892 }
1893 (JsValue::Number(JsNumberType::Integer(a)), JsValue::Number(JsNumberType::Integer(b))) => {
1894 Ok(JsValue::Number(JsNumberType::Integer(int_op(*a, *b))))
1895 }
1896 (JsValue::Number(a), JsValue::Number(b)) => {
1897 let a_f64 = number_to_f64(a);
1898 let b_f64 = number_to_f64(b);
1899 Ok(JsValue::Number(JsNumberType::Float(float_op(a_f64, b_f64))))
1900 }
1901 _ => Ok(JsValue::Number(JsNumberType::NaN)),
1902 }
1903}
1904
1905fn number_to_f64(n: &JsNumberType) -> f64 {
1906 match n {
1907 JsNumberType::Integer(i) => *i as f64,
1908 JsNumberType::Float(f) => *f,
1909 JsNumberType::NaN => f64::NAN,
1910 JsNumberType::PositiveInfinity => f64::INFINITY,
1911 JsNumberType::NegativeInfinity => f64::NEG_INFINITY,
1912 }
1913}
1914
1915fn compare_values<F>(left: &JsValue, right: &JsValue, cmp: F) -> ValueResult
1920where
1921 F: Fn(f64, f64) -> bool,
1922{
1923 let left_num = to_number(left)?;
1924 let right_num = to_number(right)?;
1925
1926 let result = match (&left_num, &right_num) {
1927 (JsValue::Number(JsNumberType::NaN), _) | (_, JsValue::Number(JsNumberType::NaN)) => false,
1928 (JsValue::Number(a), JsValue::Number(b)) => {
1929 cmp(number_to_f64(a), number_to_f64(b))
1930 }
1931 _ => false,
1932 };
1933
1934 Ok(JsValue::Boolean(result))
1935}
1936
1937pub fn strict_equality(left: &JsValue, right: &JsValue) -> bool {
1938 match (left, right) {
1939 (JsValue::Undefined, JsValue::Undefined) => true,
1940 (JsValue::Null, JsValue::Null) => true,
1941 (JsValue::Boolean(a), JsValue::Boolean(b)) => a == b,
1942 (JsValue::String(a), JsValue::String(b)) => a == b,
1943 (JsValue::Number(JsNumberType::NaN), _) | (_, JsValue::Number(JsNumberType::NaN)) => false,
1944 (JsValue::Number(a), JsValue::Number(b)) => {
1945 number_to_f64(a) == number_to_f64(b)
1946 }
1947 (JsValue::Object(a), JsValue::Object(b)) => std::rc::Rc::ptr_eq(a, b),
1948 _ => false,
1949 }
1950}
1951
1952fn loose_equality(left: &JsValue, right: &JsValue) -> bool {
1953 if std::mem::discriminant(left) == std::mem::discriminant(right) {
1954 return strict_equality(left, right);
1955 }
1956
1957 match (left, right) {
1958 (JsValue::Null, JsValue::Undefined) | (JsValue::Undefined, JsValue::Null) => true,
1959 (JsValue::Number(_), JsValue::String(_)) => {
1960 if let Ok(r) = to_number(right) {
1961 strict_equality(left, &r)
1962 } else {
1963 false
1964 }
1965 }
1966 (JsValue::String(_), JsValue::Number(_)) => {
1967 if let Ok(l) = to_number(left) {
1968 strict_equality(&l, right)
1969 } else {
1970 false
1971 }
1972 }
1973 (JsValue::Boolean(_), _) => {
1974 if let Ok(l) = to_number(left) {
1975 loose_equality(&l, right)
1976 } else {
1977 false
1978 }
1979 }
1980 (_, JsValue::Boolean(_)) => {
1981 if let Ok(r) = to_number(right) {
1982 loose_equality(left, &r)
1983 } else {
1984 false
1985 }
1986 }
1987 _ => false,
1988 }
1989}
1990
1991fn bitwise_and(left: &JsValue, right: &JsValue) -> ValueResult {
1996 let l = to_i32(left)?;
1997 let r = to_i32(right)?;
1998 Ok(JsValue::Number(JsNumberType::Integer((l & r) as i64)))
1999}
2000
2001fn bitwise_or(left: &JsValue, right: &JsValue) -> ValueResult {
2002 let l = to_i32(left)?;
2003 let r = to_i32(right)?;
2004 Ok(JsValue::Number(JsNumberType::Integer((l | r) as i64)))
2005}
2006
2007fn bitwise_xor(left: &JsValue, right: &JsValue) -> ValueResult {
2008 let l = to_i32(left)?;
2009 let r = to_i32(right)?;
2010 Ok(JsValue::Number(JsNumberType::Integer((l ^ r) as i64)))
2011}
2012
2013fn left_shift(left: &JsValue, right: &JsValue) -> ValueResult {
2014 let l = to_i32(left)?;
2015 let r = to_u32(right)? & 0x1f;
2016 Ok(JsValue::Number(JsNumberType::Integer((l << r) as i64)))
2017}
2018
2019fn right_shift(left: &JsValue, right: &JsValue) -> ValueResult {
2020 let l = to_i32(left)?;
2021 let r = to_u32(right)? & 0x1f;
2022 Ok(JsValue::Number(JsNumberType::Integer((l >> r) as i64)))
2023}
2024
2025fn unsigned_right_shift(left: &JsValue, right: &JsValue) -> ValueResult {
2026 let l = to_u32(left)?;
2027 let r = to_u32(right)? & 0x1f;
2028 Ok(JsValue::Number(JsNumberType::Integer((l >> r) as i64)))
2029}
2030
2031fn to_string(value: &JsValue) -> String {
2036 match value {
2037 JsValue::Undefined => "undefined".to_string(),
2038 JsValue::Null => "null".to_string(),
2039 JsValue::Boolean(true) => "true".to_string(),
2040 JsValue::Boolean(false) => "false".to_string(),
2041 JsValue::Number(n) => n.to_string(),
2042 JsValue::String(s) => s.clone(),
2043 JsValue::Symbol(_) => "[Symbol]".to_string(),
2044 JsValue::Object(_) => "[object Object]".to_string(),
2045 }
2046}
2047
2048pub struct SimpleFunctionObject {
2055 base: ObjectBase,
2056 body_ptr: *const crate::parser::ast::FunctionBodyData,
2058 params_ptr: *const Vec<PatternType>,
2060 environment: crate::runner::ds::lex_env::JsLexEnvironmentType,
2062}
2063
2064unsafe impl Send for SimpleFunctionObject {}
2066unsafe impl Sync for SimpleFunctionObject {}
2067
2068impl SimpleFunctionObject {
2069 pub fn new(
2070 body_ptr: *const crate::parser::ast::FunctionBodyData,
2071 params_ptr: *const Vec<PatternType>,
2072 environment: crate::runner::ds::lex_env::JsLexEnvironmentType,
2073 ) -> Self {
2074 SimpleFunctionObject {
2075 base: ObjectBase::new(),
2076 body_ptr,
2077 params_ptr,
2078 environment,
2079 }
2080 }
2081
2082 pub fn call_with_this(
2085 &self,
2086 this_value: JsValue,
2087 args: Vec<JsValue>,
2088 ctx: &mut EvalContext,
2089 ) -> ValueResult {
2090 use crate::runner::ds::env_record::new_declarative_environment;
2091 use super::statement::execute_statement;
2092 use super::types::CompletionType;
2093
2094 let (body, params) = unsafe {
2096 (&*self.body_ptr, &*self.params_ptr)
2097 };
2098
2099 let saved_lex_env = ctx.lex_env.clone();
2101 let saved_var_env = ctx.var_env.clone();
2102 let saved_this = ctx.global_this.clone();
2103
2104 let func_scope = new_declarative_environment(Some(self.environment.clone()));
2106 ctx.lex_env = func_scope.clone();
2107 ctx.var_env = func_scope;
2108 ctx.global_this = Some(this_value);
2109
2110 for (i, param) in params.iter().enumerate() {
2112 if let PatternType::PatternWhichCanBeExpression(
2113 ExpressionPatternType::Identifier(id)
2114 ) = param {
2115 let arg_value = args.get(i).cloned().unwrap_or(JsValue::Undefined);
2116 ctx.create_binding(&id.name, false)?;
2117 ctx.initialize_binding(&id.name, arg_value)?;
2118 }
2119 }
2120
2121 let mut result_completion = super::types::Completion::normal();
2123
2124 for stmt in body.body.iter() {
2125 let completion = execute_statement(stmt, ctx)?;
2126
2127 match completion.completion_type {
2128 CompletionType::Return => {
2129 result_completion = completion;
2130 break;
2131 }
2132 CompletionType::Throw => {
2133 ctx.lex_env = saved_lex_env;
2135 ctx.var_env = saved_var_env;
2136 ctx.global_this = saved_this;
2137 return Err(JErrorType::TypeError(format!(
2138 "Uncaught exception: {:?}",
2139 completion.value
2140 )));
2141 }
2142 CompletionType::Break | CompletionType::Continue | CompletionType::Yield => {
2143 result_completion = completion;
2144 break;
2145 }
2146 CompletionType::Normal => {
2147 result_completion = completion;
2148 }
2149 }
2150 }
2151
2152 ctx.lex_env = saved_lex_env;
2154 ctx.var_env = saved_var_env;
2155 ctx.global_this = saved_this;
2156
2157 match result_completion.completion_type {
2159 CompletionType::Return => Ok(result_completion.get_value()),
2160 _ => Ok(JsValue::Undefined),
2161 }
2162 }
2163}
2164
2165impl JsObject for SimpleFunctionObject {
2166 fn get_object_base_mut(&mut self) -> &mut ObjectBase {
2167 &mut self.base
2168 }
2169
2170 fn get_object_base(&self) -> &ObjectBase {
2171 &self.base
2172 }
2173
2174 fn as_js_object(&self) -> &dyn JsObject {
2175 self
2176 }
2177
2178 fn as_js_object_mut(&mut self) -> &mut dyn JsObject {
2179 self
2180 }
2181}
2182
2183pub fn is_simple_function_object(obj: &dyn JsObject) -> bool {
2185 let marker = PropertyKey::Str("__simple_function__".to_string());
2187 obj.get_object_base().properties.contains_key(&marker)
2188}
2189
2190pub fn create_function_object(func_data: &FunctionData, ctx: &EvalContext) -> ValueResult {
2194 let body_ptr = func_data.body.as_ref() as *const _;
2195 let params_ptr = &func_data.params.list as *const _;
2196 let environment = ctx.lex_env.clone();
2197
2198 let mut func_obj = SimpleFunctionObject::new(body_ptr, params_ptr, environment);
2199
2200 let prototype = SimpleObject::new();
2202 let prototype_ref: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(prototype))));
2203
2204 func_obj.base.properties.insert(
2206 PropertyKey::Str("prototype".to_string()),
2207 PropertyDescriptor::Data(PropertyDescriptorData {
2208 value: JsValue::Object(prototype_ref),
2209 writable: true,
2210 enumerable: false,
2211 configurable: false,
2212 }),
2213 );
2214
2215 func_obj.base.properties.insert(
2217 PropertyKey::Str("__simple_function__".to_string()),
2218 PropertyDescriptor::Data(PropertyDescriptorData {
2219 value: JsValue::Boolean(true),
2220 writable: false,
2221 enumerable: false,
2222 configurable: false,
2223 }),
2224 );
2225
2226 if func_data.generator {
2228 func_obj.base.properties.insert(
2229 PropertyKey::Str("__generator__".to_string()),
2230 PropertyDescriptor::Data(PropertyDescriptorData {
2231 value: JsValue::Boolean(true),
2232 writable: false,
2233 enumerable: false,
2234 configurable: false,
2235 }),
2236 );
2237 }
2238
2239 let obj_ref: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(func_obj))));
2240 Ok(JsValue::Object(obj_ref))
2241}
2242
2243#[derive(Debug, Clone, PartialEq)]
2249pub enum GeneratorState {
2250 SuspendedStart,
2251 SuspendedYield,
2252 Executing,
2253 Completed,
2254}
2255
2256pub struct GeneratorObject {
2258 base: ObjectBase,
2259 body_ptr: *const crate::parser::ast::FunctionBodyData,
2261 _params_ptr: *const Vec<PatternType>,
2263 environment: crate::runner::ds::lex_env::JsLexEnvironmentType,
2265 state: GeneratorState,
2267 current_index: usize,
2269 local_bindings: std::collections::HashMap<String, JsValue>,
2271}
2272
2273unsafe impl Send for GeneratorObject {}
2275unsafe impl Sync for GeneratorObject {}
2276
2277impl GeneratorObject {
2278 pub fn new(
2279 body_ptr: *const crate::parser::ast::FunctionBodyData,
2280 params_ptr: *const Vec<PatternType>,
2281 environment: crate::runner::ds::lex_env::JsLexEnvironmentType,
2282 ) -> Self {
2283 GeneratorObject {
2284 base: ObjectBase::new(),
2285 body_ptr,
2286 _params_ptr: params_ptr,
2287 environment,
2288 state: GeneratorState::SuspendedStart,
2289 current_index: 0,
2290 local_bindings: std::collections::HashMap::new(),
2291 }
2292 }
2293
2294 pub fn next(&mut self, ctx: &mut EvalContext) -> ValueResult {
2296 use crate::runner::ds::env_record::new_declarative_environment;
2297 use super::statement::execute_statement;
2298 use super::types::CompletionType;
2299
2300 match self.state {
2301 GeneratorState::Completed => {
2302 return create_iterator_result(JsValue::Undefined, true);
2304 }
2305 GeneratorState::Executing => {
2306 return Err(JErrorType::TypeError("Generator is already executing".to_string()));
2307 }
2308 GeneratorState::SuspendedStart | GeneratorState::SuspendedYield => {
2309 }
2311 }
2312
2313 self.state = GeneratorState::Executing;
2314
2315 let body = unsafe { &*self.body_ptr };
2317
2318 let saved_lex_env = ctx.lex_env.clone();
2320 let saved_var_env = ctx.var_env.clone();
2321
2322 let func_scope = new_declarative_environment(Some(self.environment.clone()));
2324 ctx.lex_env = func_scope.clone();
2325 ctx.var_env = func_scope;
2326
2327 for (name, value) in &self.local_bindings {
2329 let _ = ctx.create_binding(name, false);
2330 let _ = ctx.initialize_binding(name, value.clone());
2331 }
2332
2333 let mut result_value = JsValue::Undefined;
2335 let mut yielded = false;
2336
2337 for (idx, stmt) in body.body.iter().enumerate() {
2338 if idx < self.current_index {
2339 continue; }
2341
2342 match execute_statement(stmt, ctx) {
2343 Ok(completion) => {
2344 match completion.completion_type {
2345 CompletionType::Return => {
2346 result_value = completion.get_value();
2347 self.state = GeneratorState::Completed;
2348 break;
2349 }
2350 CompletionType::Yield => {
2351 result_value = completion.get_value();
2353 self.current_index = idx + 1;
2354 self.state = GeneratorState::SuspendedYield;
2355
2356 self.save_bindings(ctx);
2358
2359 yielded = true;
2360 break;
2361 }
2362 CompletionType::Throw => {
2363 ctx.lex_env = saved_lex_env;
2364 ctx.var_env = saved_var_env;
2365 self.state = GeneratorState::Completed;
2366 return Err(JErrorType::TypeError(format!(
2367 "Uncaught exception: {:?}",
2368 completion.value
2369 )));
2370 }
2371 _ => {
2372 result_value = completion.get_value();
2373 }
2374 }
2375 }
2376 Err(JErrorType::YieldValue(value)) => {
2377 result_value = value;
2379 self.current_index = idx + 1;
2380 self.state = GeneratorState::SuspendedYield;
2381
2382 self.save_bindings(ctx);
2384
2385 yielded = true;
2386 break;
2387 }
2388 Err(e) => {
2389 ctx.lex_env = saved_lex_env;
2390 ctx.var_env = saved_var_env;
2391 self.state = GeneratorState::Completed;
2392 return Err(e);
2393 }
2394 }
2395 }
2396
2397 if !yielded && self.state == GeneratorState::Executing {
2399 self.state = GeneratorState::Completed;
2400 }
2401
2402 ctx.lex_env = saved_lex_env;
2404 ctx.var_env = saved_var_env;
2405
2406 let done = self.state == GeneratorState::Completed;
2408 create_iterator_result(result_value, done)
2409 }
2410
2411 fn save_bindings(&mut self, ctx: &EvalContext) {
2412 self.local_bindings.clear();
2415
2416 let env = ctx.lex_env.borrow();
2418 if let Some(bindings) = env.inner.as_env_record().get_all_bindings() {
2419 for (name, value) in bindings {
2420 self.local_bindings.insert(name, value);
2421 }
2422 }
2423 }
2424}
2425
2426impl JsObject for GeneratorObject {
2427 fn get_object_base_mut(&mut self) -> &mut ObjectBase {
2428 &mut self.base
2429 }
2430
2431 fn get_object_base(&self) -> &ObjectBase {
2432 &self.base
2433 }
2434
2435 fn as_js_object(&self) -> &dyn JsObject {
2436 self
2437 }
2438
2439 fn as_js_object_mut(&mut self) -> &mut dyn JsObject {
2440 self
2441 }
2442}
2443
2444fn create_iterator_result(value: JsValue, done: bool) -> ValueResult {
2446 let mut obj = SimpleObject::new();
2447
2448 obj.get_object_base_mut().properties.insert(
2449 PropertyKey::Str("value".to_string()),
2450 PropertyDescriptor::Data(PropertyDescriptorData {
2451 value,
2452 writable: true,
2453 enumerable: true,
2454 configurable: true,
2455 }),
2456 );
2457
2458 obj.get_object_base_mut().properties.insert(
2459 PropertyKey::Str("done".to_string()),
2460 PropertyDescriptor::Data(PropertyDescriptorData {
2461 value: JsValue::Boolean(done),
2462 writable: true,
2463 enumerable: true,
2464 configurable: true,
2465 }),
2466 );
2467
2468 let obj_ref: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(obj))));
2469 Ok(JsValue::Object(obj_ref))
2470}
2471
2472fn create_generator_object(
2474 body_ptr: *const crate::parser::ast::FunctionBodyData,
2475 params_ptr: *const Vec<PatternType>,
2476 environment: crate::runner::ds::lex_env::JsLexEnvironmentType,
2477 _args: Vec<JsValue>,
2478 _ctx: &mut EvalContext,
2479) -> ValueResult {
2480 let mut gen_obj = GeneratorObject::new(body_ptr, params_ptr, environment);
2481
2482 gen_obj.base.properties.insert(
2484 PropertyKey::Str("__generator_object__".to_string()),
2485 PropertyDescriptor::Data(PropertyDescriptorData {
2486 value: JsValue::Boolean(true),
2487 writable: false,
2488 enumerable: false,
2489 configurable: false,
2490 }),
2491 );
2492
2493 let params = unsafe { &*params_ptr };
2495 for (i, param) in params.iter().enumerate() {
2496 if let PatternType::PatternWhichCanBeExpression(
2497 ExpressionPatternType::Identifier(id)
2498 ) = param {
2499 let arg_value = _args.get(i).cloned().unwrap_or(JsValue::Undefined);
2500 gen_obj.local_bindings.insert(id.name.clone(), arg_value);
2501 }
2502 }
2503
2504 let gen_ref: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(gen_obj))));
2507
2508 Ok(JsValue::Object(gen_ref))
2514}
2515
2516fn create_generator_next_method(gen_obj: JsObjectType) -> ValueResult {
2518 let mut next_obj = SimpleObject::new();
2521
2522 next_obj.get_object_base_mut().properties.insert(
2523 PropertyKey::Str("__generator_next__".to_string()),
2524 PropertyDescriptor::Data(PropertyDescriptorData {
2525 value: JsValue::Object(gen_obj),
2526 writable: false,
2527 enumerable: false,
2528 configurable: false,
2529 }),
2530 );
2531
2532 next_obj.get_object_base_mut().properties.insert(
2534 PropertyKey::Str("__simple_function__".to_string()),
2535 PropertyDescriptor::Data(PropertyDescriptorData {
2536 value: JsValue::Boolean(true),
2537 writable: false,
2538 enumerable: false,
2539 configurable: false,
2540 }),
2541 );
2542
2543 let obj_ref: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(next_obj))));
2544 Ok(JsValue::Object(obj_ref))
2545}
2546
2547pub fn evaluate_class_expression(class_data: &ClassData, ctx: &mut EvalContext) -> ValueResult {
2553 evaluate_class(class_data, ctx)
2554}
2555
2556pub fn evaluate_class(class_data: &ClassData, ctx: &mut EvalContext) -> ValueResult {
2559 let parent_proto = if let Some(super_class) = &class_data.super_class {
2561 let parent = evaluate_expression(super_class, ctx)?;
2562 match &parent {
2563 JsValue::Object(parent_obj) => {
2564 let borrowed = parent_obj.borrow();
2566 let proto_key = PropertyKey::Str("prototype".to_string());
2567 if let Some(PropertyDescriptor::Data(data)) = borrowed.as_js_object().get_object_base().properties.get(&proto_key) {
2568 if let JsValue::Object(proto) = &data.value {
2569 Some((parent_obj.clone(), proto.clone()))
2570 } else {
2571 return Err(JErrorType::TypeError("Parent class prototype is not an object".to_string()));
2572 }
2573 } else {
2574 return Err(JErrorType::TypeError("Parent class has no prototype".to_string()));
2575 }
2576 }
2577 _ => return Err(JErrorType::TypeError("Class extends value is not a constructor".to_string())),
2578 }
2579 } else {
2580 None
2581 };
2582
2583 let constructor_method = class_data.body.body.iter()
2585 .find(|m| matches!(m.kind, MethodDefinitionKind::Constructor));
2586
2587 let constructor_obj = if let Some(ctor_method) = constructor_method {
2589 create_class_constructor(&ctor_method.value, parent_proto.as_ref().map(|(p, _)| p.clone()), ctx)?
2591 } else {
2592 create_default_constructor(parent_proto.as_ref().map(|(p, _)| p.clone()), ctx)?
2594 };
2595
2596 let prototype = if let Some((_, parent_proto)) = &parent_proto {
2598 let mut proto_obj = SimpleObject::new();
2600 proto_obj.get_object_base_mut().prototype = Some(parent_proto.clone());
2601 Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(proto_obj))))
2602 } else {
2603 Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(SimpleObject::new()))))
2605 };
2606
2607 for method in &class_data.body.body {
2609 if matches!(method.kind, MethodDefinitionKind::Constructor) {
2610 continue; }
2612
2613 let key = get_object_property_key(&method.key, method.computed, ctx)?;
2615
2616 let method_fn = create_function_object(&method.value, ctx)?;
2618
2619 let target = if method.static_flag {
2621 &constructor_obj
2622 } else {
2623 &JsValue::Object(prototype.clone())
2624 };
2625
2626 match method.kind {
2627 MethodDefinitionKind::Method => {
2628 if let JsValue::Object(target_obj) = target {
2630 target_obj.borrow_mut().as_js_object_mut().get_object_base_mut().properties.insert(
2631 PropertyKey::Str(key),
2632 PropertyDescriptor::Data(PropertyDescriptorData {
2633 value: method_fn,
2634 writable: true,
2635 enumerable: false,
2636 configurable: true,
2637 }),
2638 );
2639 }
2640 }
2641 MethodDefinitionKind::Get => {
2642 if let JsValue::Object(getter_fn) = method_fn {
2644 if let JsValue::Object(target_obj) = target {
2645 let mut borrowed = target_obj.borrow_mut();
2646 let prop_key = PropertyKey::Str(key.clone());
2647 let existing = borrowed.as_js_object().get_object_base().properties.get(&prop_key).cloned();
2648
2649 let setter = if let Some(PropertyDescriptor::Accessor(acc)) = existing {
2650 acc.set
2651 } else {
2652 None
2653 };
2654
2655 borrowed.as_js_object_mut().get_object_base_mut().properties.insert(
2656 prop_key,
2657 PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
2658 get: Some(getter_fn),
2659 set: setter,
2660 enumerable: false,
2661 configurable: true,
2662 }),
2663 );
2664 }
2665 }
2666 }
2667 MethodDefinitionKind::Set => {
2668 if let JsValue::Object(setter_fn) = method_fn {
2670 if let JsValue::Object(target_obj) = target {
2671 let mut borrowed = target_obj.borrow_mut();
2672 let prop_key = PropertyKey::Str(key.clone());
2673 let existing = borrowed.as_js_object().get_object_base().properties.get(&prop_key).cloned();
2674
2675 let getter = if let Some(PropertyDescriptor::Accessor(acc)) = existing {
2676 acc.get
2677 } else {
2678 None
2679 };
2680
2681 borrowed.as_js_object_mut().get_object_base_mut().properties.insert(
2682 prop_key,
2683 PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
2684 get: getter,
2685 set: Some(setter_fn),
2686 enumerable: false,
2687 configurable: true,
2688 }),
2689 );
2690 }
2691 }
2692 }
2693 MethodDefinitionKind::Constructor => unreachable!(),
2694 }
2695 }
2696
2697 if let JsValue::Object(ctor_obj) = &constructor_obj {
2699 ctor_obj.borrow_mut().as_js_object_mut().get_object_base_mut().properties.insert(
2700 PropertyKey::Str("prototype".to_string()),
2701 PropertyDescriptor::Data(PropertyDescriptorData {
2702 value: JsValue::Object(prototype.clone()),
2703 writable: false,
2704 enumerable: false,
2705 configurable: false,
2706 }),
2707 );
2708
2709 prototype.borrow_mut().as_js_object_mut().get_object_base_mut().properties.insert(
2711 PropertyKey::Str("constructor".to_string()),
2712 PropertyDescriptor::Data(PropertyDescriptorData {
2713 value: constructor_obj.clone(),
2714 writable: true,
2715 enumerable: false,
2716 configurable: true,
2717 }),
2718 );
2719 }
2720
2721 Ok(constructor_obj)
2722}
2723
2724fn create_class_constructor(
2726 func_data: &FunctionData,
2727 _parent_ctor: Option<JsObjectType>,
2728 ctx: &EvalContext,
2729) -> ValueResult {
2730 let body_ptr = func_data.body.as_ref() as *const _;
2731 let params_ptr = &func_data.params.list as *const _;
2732 let environment = ctx.lex_env.clone();
2733
2734 let mut func_obj = SimpleFunctionObject::new(body_ptr, params_ptr, environment);
2735
2736 func_obj.base.properties.insert(
2738 PropertyKey::Str("__simple_function__".to_string()),
2739 PropertyDescriptor::Data(PropertyDescriptorData {
2740 value: JsValue::Boolean(true),
2741 writable: false,
2742 enumerable: false,
2743 configurable: false,
2744 }),
2745 );
2746
2747 func_obj.base.properties.insert(
2749 PropertyKey::Str("__class_constructor__".to_string()),
2750 PropertyDescriptor::Data(PropertyDescriptorData {
2751 value: JsValue::Boolean(true),
2752 writable: false,
2753 enumerable: false,
2754 configurable: false,
2755 }),
2756 );
2757
2758 let obj_ref: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(func_obj))));
2759 Ok(JsValue::Object(obj_ref))
2760}
2761
2762fn create_default_constructor(
2764 _parent_ctor: Option<JsObjectType>,
2765 _ctx: &EvalContext,
2766) -> ValueResult {
2767 let mut func_obj = SimpleObject::new();
2770
2771 func_obj.get_object_base_mut().properties.insert(
2773 PropertyKey::Str("__simple_function__".to_string()),
2774 PropertyDescriptor::Data(PropertyDescriptorData {
2775 value: JsValue::Boolean(true),
2776 writable: false,
2777 enumerable: false,
2778 configurable: false,
2779 }),
2780 );
2781
2782 func_obj.get_object_base_mut().properties.insert(
2784 PropertyKey::Str("__class_constructor__".to_string()),
2785 PropertyDescriptor::Data(PropertyDescriptorData {
2786 value: JsValue::Boolean(true),
2787 writable: false,
2788 enumerable: false,
2789 configurable: false,
2790 }),
2791 );
2792
2793 func_obj.get_object_base_mut().properties.insert(
2795 PropertyKey::Str("__default_constructor__".to_string()),
2796 PropertyDescriptor::Data(PropertyDescriptorData {
2797 value: JsValue::Boolean(true),
2798 writable: false,
2799 enumerable: false,
2800 configurable: false,
2801 }),
2802 );
2803
2804 let obj_ref: JsObjectType = Rc::new(RefCell::new(ObjectType::Ordinary(Box::new(func_obj))));
2805 Ok(JsValue::Object(obj_ref))
2806}
2807