|
2 | 2 |
|
3 | 3 | use crate::core::{Gc, GcCell, MutationContext}; |
4 | 4 | use crate::js_array::handle_array_static_method; |
| 5 | +use crate::js_bigint::bigint_constructor; |
5 | 6 | use crate::js_date::{handle_date_method, handle_date_static_method}; |
6 | 7 | use crate::js_os::handle_os_method; |
7 | 8 | use crate::js_string::{string_from_char_code, string_from_code_point, string_raw}; |
@@ -469,6 +470,34 @@ fn refresh_error_by_additional_stack_frame<'gc>( |
469 | 470 | e |
470 | 471 | } |
471 | 472 |
|
| 473 | +fn get_primitive_prototype_property<'gc>( |
| 474 | + mc: &MutationContext<'gc>, |
| 475 | + env: &JSObjectDataPtr<'gc>, |
| 476 | + obj_val: &Value<'gc>, |
| 477 | + key: &PropertyKey<'gc>, |
| 478 | +) -> Result<Value<'gc>, EvalError<'gc>> { |
| 479 | + let proto_name = match obj_val { |
| 480 | + Value::BigInt(_) => "BigInt", |
| 481 | + Value::Number(_) => "Number", |
| 482 | + Value::String(_) => "String", |
| 483 | + Value::Boolean(_) => "Boolean", |
| 484 | + _ => return Ok(Value::Undefined), |
| 485 | + }; |
| 486 | + |
| 487 | + if let Ok(ctor) = evaluate_var(mc, env, proto_name) { |
| 488 | + if let Value::Object(ctor_obj) = ctor { |
| 489 | + if let Some(proto_ref) = obj_get_key_value(&ctor_obj, &"prototype".into())? { |
| 490 | + if let Value::Object(proto) = &*proto_ref.borrow() { |
| 491 | + if let Some(val) = obj_get_key_value(proto, key)? { |
| 492 | + return Ok(val.borrow().clone()); |
| 493 | + } |
| 494 | + } |
| 495 | + } |
| 496 | + } |
| 497 | + } |
| 498 | + Ok(Value::Undefined) |
| 499 | +} |
| 500 | + |
472 | 501 | pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>, expr: &Expr) -> Result<Value<'gc>, EvalError<'gc>> { |
473 | 502 | match expr { |
474 | 503 | Expr::Number(n) => Ok(Value::Number(*n)), |
@@ -663,7 +692,7 @@ pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>, |
663 | 692 | } else if matches!(obj_val, Value::Undefined | Value::Null) { |
664 | 693 | return Err(EvalError::Js(raise_eval_error!("Cannot read properties of null or undefined"))); |
665 | 694 | } else { |
666 | | - Value::Undefined |
| 695 | + get_primitive_prototype_property(mc, env, &obj_val, &key.as_str().into())? |
667 | 696 | }; |
668 | 697 | (f_val, Some(obj_val)) |
669 | 698 | } |
@@ -703,6 +732,11 @@ pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>, |
703 | 732 | } else if let Some(method) = name.strip_prefix("os.") { |
704 | 733 | let this_val = this_val.clone().unwrap_or(Value::Object(*env)); |
705 | 734 | Ok(handle_os_method(mc, this_val, method, &eval_args, env).map_err(EvalError::Js)?) |
| 735 | + } else if let Some(method) = name.strip_prefix("BigInt.prototype.") { |
| 736 | + let this_v = this_val.clone().unwrap_or(Value::Undefined); |
| 737 | + Ok(crate::js_bigint::handle_bigint_object_method(this_v, method, &eval_args).map_err(EvalError::Js)?) |
| 738 | + } else if let Some(method) = name.strip_prefix("BigInt.") { |
| 739 | + Ok(crate::js_bigint::handle_bigint_static_method(method, &eval_args, env).map_err(EvalError::Js)?) |
706 | 740 | } else if let Some(method) = name.strip_prefix("Math.") { |
707 | 741 | Ok(handle_math_call(mc, method, &eval_args, env).map_err(EvalError::Js)?) |
708 | 742 | } else if let Some(method) = name.strip_prefix("Date.prototype.") { |
@@ -843,6 +877,8 @@ pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>, |
843 | 877 | Value::String(name) => { |
844 | 878 | if name == &crate::unicode::utf8_to_utf16("String") { |
845 | 879 | Ok(crate::js_string::string_constructor(mc, &eval_args, env)?) |
| 880 | + } else if name == &crate::unicode::utf8_to_utf16("BigInt") { |
| 881 | + Ok(bigint_constructor(&eval_args, env)?) |
846 | 882 | } else { |
847 | 883 | Err(EvalError::Js(raise_eval_error!("Not a function"))) |
848 | 884 | } |
@@ -911,39 +947,44 @@ pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>, |
911 | 947 | } |
912 | 948 | Expr::Property(obj_expr, key) => { |
913 | 949 | let obj_val = evaluate_expr(mc, env, obj_expr)?; |
914 | | - if let Value::Object(obj) = obj_val { |
915 | | - if let Some(val) = obj_get_key_value(&obj, &key.as_str().into())? { |
916 | | - Ok(val.borrow().clone()) |
| 950 | + |
| 951 | + if let Value::Object(obj) = &obj_val { |
| 952 | + if let Some(val) = obj_get_key_value(obj, &key.as_str().into())? { |
| 953 | + return Ok(val.borrow().clone()); |
917 | 954 | } else { |
918 | | - Ok(Value::Undefined) |
| 955 | + return Ok(Value::Undefined); |
919 | 956 | } |
920 | | - } else if matches!(obj_val, Value::Undefined | Value::Null) { |
921 | | - Err(EvalError::Js(raise_eval_error!("Cannot read properties of null or undefined"))) |
922 | | - } else { |
923 | | - Ok(Value::Undefined) |
924 | 957 | } |
| 958 | + |
| 959 | + if matches!(obj_val, Value::Undefined | Value::Null) { |
| 960 | + return Err(EvalError::Js(raise_eval_error!("Cannot read properties of null or undefined"))); |
| 961 | + } |
| 962 | + |
| 963 | + get_primitive_prototype_property(mc, env, &obj_val, &key.as_str().into()) |
925 | 964 | } |
926 | 965 | Expr::Index(obj_expr, key_expr) => { |
927 | 966 | let obj_val = evaluate_expr(mc, env, obj_expr)?; |
928 | 967 | let key_val = evaluate_expr(mc, env, key_expr)?; |
929 | 968 |
|
930 | | - if let Value::Object(obj) = obj_val { |
931 | | - let key = match key_val { |
932 | | - Value::String(s) => PropertyKey::String(utf16_to_utf8(&s)), |
933 | | - Value::Number(n) => PropertyKey::String(n.to_string()), |
934 | | - _ => PropertyKey::String(value_to_string(&key_val)), |
935 | | - }; |
| 969 | + let key = match key_val { |
| 970 | + Value::String(s) => PropertyKey::String(utf16_to_utf8(&s)), |
| 971 | + Value::Number(n) => PropertyKey::String(n.to_string()), |
| 972 | + _ => PropertyKey::String(value_to_string(&key_val)), |
| 973 | + }; |
936 | 974 |
|
937 | | - if let Some(val) = obj_get_key_value(&obj, &key)? { |
938 | | - Ok(val.borrow().clone()) |
| 975 | + if let Value::Object(obj) = &obj_val { |
| 976 | + if let Some(val) = obj_get_key_value(obj, &key)? { |
| 977 | + return Ok(val.borrow().clone()); |
939 | 978 | } else { |
940 | | - Ok(Value::Undefined) |
| 979 | + return Ok(Value::Undefined); |
941 | 980 | } |
942 | | - } else if matches!(obj_val, Value::Undefined | Value::Null) { |
943 | | - Err(EvalError::Js(raise_eval_error!("Cannot read properties of null or undefined"))) |
944 | | - } else { |
945 | | - Ok(Value::Undefined) |
946 | 981 | } |
| 982 | + |
| 983 | + if matches!(obj_val, Value::Undefined | Value::Null) { |
| 984 | + return Err(EvalError::Js(raise_eval_error!("Cannot read properties of null or undefined"))); |
| 985 | + } |
| 986 | + |
| 987 | + get_primitive_prototype_property(mc, env, &obj_val, &key) |
947 | 988 | } |
948 | 989 | Expr::TemplateString(parts) => { |
949 | 990 | let mut result = Vec::new(); |
|
0 commit comments