@@ -9,9 +9,9 @@ use crate::js_string::{string_from_char_code, string_from_code_point, string_raw
99use crate :: {
1010 JSError , JSErrorKind , PropertyKey , Value ,
1111 core:: {
12- BinaryOp , ClosureData , DestructuringElement , EvalError , Expr , JSObjectDataPtr , ObjectDestructuringElement , Statement ,
13- StatementKind , create_error, env_get, env_set, env_set_recursive, is_error, new_js_object_data , obj_get_key_value ,
14- obj_set_key_value, value_to_string,
12+ BinaryOp , ClosureData , DestructuringElement , EvalError , ExportSpecifier , Expr , ImportSpecifier , JSObjectDataPtr ,
13+ ObjectDestructuringElement , Statement , StatementKind , create_error, env_get, env_set, env_set_recursive, is_error,
14+ new_js_object_data , obj_get_key_value , obj_set_key_value, value_to_string,
1515 } ,
1616 js_math:: handle_math_call,
1717 raise_eval_error, raise_reference_error,
@@ -169,6 +169,22 @@ fn hoist_declarations<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>
169169 StatementKind :: Class ( name, ..) => {
170170 env_set ( mc, env, name, Value :: Uninitialized ) ?;
171171 }
172+ StatementKind :: Import ( specifiers, _) => {
173+ for spec in specifiers {
174+ match spec {
175+ ImportSpecifier :: Default ( name) => {
176+ env_set ( mc, env, name, Value :: Uninitialized ) ?;
177+ }
178+ ImportSpecifier :: Named ( name, alias) => {
179+ let binding_name = alias. as_ref ( ) . unwrap_or ( name) ;
180+ env_set ( mc, env, binding_name, Value :: Uninitialized ) ?;
181+ }
182+ ImportSpecifier :: Namespace ( name) => {
183+ env_set ( mc, env, name, Value :: Uninitialized ) ?;
184+ }
185+ }
186+ }
187+ }
172188 StatementKind :: LetDestructuringArray ( pattern, _) | StatementKind :: ConstDestructuringArray ( pattern, _) => {
173189 let mut names = Vec :: new ( ) ;
174190 collect_names_from_destructuring ( pattern, & mut names) ;
@@ -280,6 +296,123 @@ fn eval_res<'gc>(
280296 * last_value = Value :: Undefined ;
281297 Ok ( None )
282298 }
299+ StatementKind :: Import ( specifiers, source) => {
300+ // Try to deduce base path from env or use current dir
301+ let base_path = if let Some ( cell) = env_get ( env, "__script_name" ) {
302+ if let Value :: String ( s) = cell. borrow ( ) . clone ( ) {
303+ Some ( crate :: unicode:: utf16_to_utf8 ( & s) )
304+ } else {
305+ None
306+ }
307+ } else {
308+ None
309+ } ;
310+
311+ let exports = crate :: js_module:: load_module ( mc, source, base_path. as_deref ( ) )
312+ . map_err ( |e| EvalError :: Throw ( Value :: String ( utf8_to_utf16 ( & e. message ( ) ) ) , Some ( stmt. line ) , Some ( stmt. column ) ) ) ?;
313+
314+ if let Value :: Object ( exports_obj) = exports {
315+ for spec in specifiers {
316+ match spec {
317+ ImportSpecifier :: Named ( name, alias) => {
318+ let binding_name = alias. as_ref ( ) . unwrap_or ( name) ;
319+
320+ let val_ptr_res = obj_get_key_value ( & exports_obj, & name. into ( ) ) ;
321+ let val = if let Ok ( Some ( cell) ) = val_ptr_res {
322+ cell. borrow ( ) . clone ( )
323+ } else {
324+ Value :: Undefined
325+ } ;
326+ env_set ( mc, env, binding_name, val) ?;
327+ }
328+ ImportSpecifier :: Default ( name) => {
329+ let val_ptr_res = obj_get_key_value ( & exports_obj, & "default" . into ( ) ) ;
330+ let val = if let Ok ( Some ( cell) ) = val_ptr_res {
331+ cell. borrow ( ) . clone ( )
332+ } else {
333+ Value :: Undefined
334+ } ;
335+ env_set ( mc, env, name, val) ?;
336+ }
337+ ImportSpecifier :: Namespace ( name) => {
338+ env_set ( mc, env, name, Value :: Object ( exports_obj) ) ?;
339+ }
340+ }
341+ }
342+ }
343+ * last_value = Value :: Undefined ;
344+ Ok ( None )
345+ }
346+ StatementKind :: Export ( specifiers, inner_stmt) => {
347+ // 1. Evaluate inner statement if present, to bind variables in current env
348+ if let Some ( stmt) = inner_stmt {
349+ // Recursively evaluate inner statement
350+ // Note: inner_stmt is a Box<Statement>. We need to call eval_res or evaluate_statements on it.
351+ // Since evaluate_statements expects a slice, we can wrap it.
352+ let mut stmts = vec ! [ * stmt. clone( ) ] ;
353+ match evaluate_statements ( mc, env, & mut stmts) {
354+ Ok ( _) => { } // Declarations are hoisted or executed, binding should be in env
355+ Err ( e) => return Err ( e) ,
356+ }
357+
358+ // If inner stmt was a declaration, we need to export the declared names.
359+ // For now, we handle named exports via specifiers only for `export { ... }`.
360+ // For `export var x = 1`, the parser should have produced specifiers?
361+ // My parser implementation for export var/function didn't produce specifiers, just inner_stmt.
362+ // So we need to look at inner_stmt kind to determine what to export.
363+
364+ match & stmt. kind {
365+ StatementKind :: Var ( decls) | StatementKind :: Let ( decls) => {
366+ for ( name, _) in decls {
367+ if let Some ( cell) = env_get ( env, name) {
368+ let val = cell. borrow ( ) . clone ( ) ;
369+ crate :: core:: eval:: export_value ( mc, env, name, val) ?;
370+ }
371+ }
372+ }
373+ StatementKind :: Const ( decls) => {
374+ for ( name, _) in decls {
375+ if let Some ( cell) = env_get ( env, name) {
376+ let val = cell. borrow ( ) . clone ( ) ;
377+ crate :: core:: eval:: export_value ( mc, env, name, val) ?;
378+ }
379+ }
380+ }
381+ StatementKind :: FunctionDeclaration ( name, _, _, _) => {
382+ if let Some ( cell) = env_get ( env, name) {
383+ let val = cell. borrow ( ) . clone ( ) ;
384+ crate :: core:: eval:: export_value ( mc, env, name, val) ?;
385+ }
386+ }
387+ _ => { }
388+ }
389+ }
390+
391+ // 2. Handle explicit specifiers
392+ for spec in specifiers {
393+ match spec {
394+ crate :: core:: statement:: ExportSpecifier :: Named ( name, alias) => {
395+ // export { name as alias }
396+ // value should be in env
397+ if let Some ( cell) = env_get ( env, name) {
398+ let val = cell. borrow ( ) . clone ( ) ;
399+ let export_name = alias. as_ref ( ) . unwrap_or ( name) ;
400+ crate :: core:: eval:: export_value ( mc, env, export_name, val) ?;
401+ } else {
402+ return Err ( EvalError :: Js ( raise_reference_error ! ( format!( "{} is not defined" , name) ) ) ) ;
403+ }
404+ }
405+ crate :: core:: statement:: ExportSpecifier :: Default ( expr) => {
406+ // export default expr
407+ let val = evaluate_expr ( mc, env, expr) ?;
408+ crate :: core:: eval:: export_value ( mc, env, "default" , val) ?;
409+ }
410+ }
411+ }
412+
413+ * last_value = Value :: Undefined ;
414+ Ok ( None )
415+ }
283416 StatementKind :: Return ( expr_opt) => {
284417 let val = if let Some ( expr) = expr_opt {
285418 match evaluate_expr ( mc, env, expr) {
@@ -442,6 +575,28 @@ fn eval_res<'gc>(
442575 }
443576}
444577
578+ pub fn export_value < ' gc > ( mc : & MutationContext < ' gc > , env : & JSObjectDataPtr < ' gc > , name : & str , val : Value < ' gc > ) -> Result < ( ) , EvalError < ' gc > > {
579+ if let Some ( exports_cell) = env_get ( env, "exports" ) {
580+ let exports = exports_cell. borrow ( ) . clone ( ) ;
581+ if let Value :: Object ( exports_obj) = exports {
582+ obj_set_key_value ( mc, & exports_obj, & name. into ( ) , val) . map_err ( |e| EvalError :: Js ( e) ) ?;
583+ return Ok ( ( ) ) ;
584+ }
585+ }
586+
587+ if let Some ( module_cell) = env_get ( env, "module" ) {
588+ let module = module_cell. borrow ( ) . clone ( ) ;
589+ if let Value :: Object ( module_obj) = module {
590+ if let Ok ( Some ( exports_val) ) = obj_get_key_value ( & module_obj, & "exports" . into ( ) ) {
591+ if let Value :: Object ( exports_obj) = & * exports_val. borrow ( ) {
592+ obj_set_key_value ( mc, exports_obj, & name. into ( ) , val) . map_err ( |e| EvalError :: Js ( e) ) ?;
593+ }
594+ }
595+ }
596+ }
597+ Ok ( ( ) )
598+ }
599+
445600fn refresh_error_by_additional_stack_frame < ' gc > (
446601 mc : & MutationContext < ' gc > ,
447602 env : & JSObjectDataPtr < ' gc > ,
@@ -987,7 +1142,24 @@ pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>,
9871142 Err ( EvalError :: Js ( raise_eval_error ! ( "Not a function" ) ) )
9881143 }
9891144 }
990- _ => Err ( EvalError :: Js ( raise_eval_error ! ( "Not a function" ) ) ) ,
1145+ Value :: Closure ( cl) => {
1146+ let call_env = crate :: core:: new_js_object_data ( mc) ;
1147+ call_env. borrow_mut ( mc) . prototype = Some ( cl. env ) ;
1148+ call_env. borrow_mut ( mc) . is_function_scope = true ;
1149+
1150+ for ( i, param) in cl. params . iter ( ) . enumerate ( ) {
1151+ if let DestructuringElement :: Variable ( name, _) = param {
1152+ let arg_val = eval_args. get ( i) . cloned ( ) . unwrap_or ( Value :: Undefined ) ;
1153+ env_set ( mc, & call_env, name, arg_val) ?;
1154+ }
1155+ }
1156+ let mut body_clone = cl. body . clone ( ) ;
1157+ match evaluate_statements ( mc, & call_env, & mut body_clone) {
1158+ Ok ( v) => Ok ( v) ,
1159+ Err ( e) => Err ( e) ,
1160+ }
1161+ }
1162+ _ => Err ( EvalError :: Js ( raise_eval_error ! ( format!( "Value {func_val:?} is not callable yet" ) ) ) ) ,
9911163 }
9921164 }
9931165 Expr :: New ( ctor, args) => {
@@ -1180,6 +1352,40 @@ pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>,
11801352 } ;
11811353 Ok ( Value :: String ( utf8_to_utf16 ( type_str) ) )
11821354 }
1355+ Expr :: LogicalAnd ( left, right) => {
1356+ let lhs = evaluate_expr ( mc, env, left) ?;
1357+ let is_truthy = match & lhs {
1358+ Value :: Boolean ( b) => * b,
1359+ Value :: Number ( n) => * n != 0.0 && !n. is_nan ( ) ,
1360+ Value :: String ( s) => !s. is_empty ( ) ,
1361+ Value :: Null | Value :: Undefined => false ,
1362+ Value :: Object ( _)
1363+ | Value :: Function ( _)
1364+ | Value :: Closure ( _)
1365+ | Value :: AsyncClosure ( _)
1366+ | Value :: GeneratorFunction ( ..)
1367+ | Value :: ClassDefinition ( _) => true ,
1368+ _ => false ,
1369+ } ;
1370+ if !is_truthy { Ok ( lhs) } else { evaluate_expr ( mc, env, right) }
1371+ }
1372+ Expr :: LogicalOr ( left, right) => {
1373+ let lhs = evaluate_expr ( mc, env, left) ?;
1374+ let is_truthy = match & lhs {
1375+ Value :: Boolean ( b) => * b,
1376+ Value :: Number ( n) => * n != 0.0 && !n. is_nan ( ) ,
1377+ Value :: String ( s) => !s. is_empty ( ) ,
1378+ Value :: Null | Value :: Undefined => false ,
1379+ Value :: Object ( _)
1380+ | Value :: Function ( _)
1381+ | Value :: Closure ( _)
1382+ | Value :: AsyncClosure ( _)
1383+ | Value :: GeneratorFunction ( ..)
1384+ | Value :: ClassDefinition ( _) => true ,
1385+ _ => false ,
1386+ } ;
1387+ if is_truthy { Ok ( lhs) } else { evaluate_expr ( mc, env, right) }
1388+ }
11831389 _ => Ok ( Value :: Undefined ) ,
11841390 }
11851391}
0 commit comments