22using Asynkron . JsEngine ;
33using Asynkron . JsEngine . JsTypes ;
44using Asynkron . JsEngine . Runtime ;
5+ using Asynkron . JsEngine . StdLib ;
56
67namespace Asynkron . JsEngine . Ast ;
78
@@ -289,6 +290,8 @@ public override string ToString()
289290
290291 private void EnsureAsyncGeneratorIntrinsics ( )
291292 {
293+ var engine = _realmState . Engine ?? throw new InvalidOperationException ( "Engine reference is missing." ) ;
294+
292295 // %AsyncIteratorPrototype% (inherits from %Object.prototype%)
293296 if ( _realmState . AsyncIteratorPrototype is null )
294297 {
@@ -328,13 +331,15 @@ private void EnsureAsyncGeneratorIntrinsics()
328331 HasConfigurable = true
329332 } ) ;
330333
331- // Minimal AsyncGeneratorFunction constructor so constructor.prototype.prototype matches spec shape
332334 if ( _realmState . AsyncGeneratorFunctionConstructor is null )
333335 {
334- var constructor = new HostFunction ( _ => null ) ;
335- constructor . Properties . SetPrototype ( _realmState . FunctionPrototype ) ;
336- constructor . SetProperty ( "prototype" , asyncGenFuncProto ) ;
337- _realmState . AsyncGeneratorFunctionConstructor = constructor ;
336+ _realmState . AsyncGeneratorFunctionConstructor =
337+ CreateAsyncGeneratorFunctionConstructor ( engine , _realmState ) ;
338+ }
339+
340+ if ( _realmState . AsyncGeneratorFunctionConstructor is { } asyncGenCtor )
341+ {
342+ asyncGenCtor . SetProperty ( "prototype" , asyncGenFuncProto ) ;
338343 }
339344
340345 asyncGenFuncProto . DefineProperty ( "constructor" ,
@@ -354,6 +359,124 @@ private void EnsureAsyncGeneratorIntrinsics()
354359 }
355360 }
356361
362+ private static HostFunction CreateAsyncGeneratorFunctionConstructor ( JsEngine engine , RealmState realm )
363+ {
364+ HostFunction constructor = null ! ;
365+
366+ constructor = new HostFunction ( ( _ , args ) =>
367+ AsyncGeneratorFunctionConstructorBody ( args , constructor , engine , realm ) )
368+ {
369+ RealmState = realm
370+ } ;
371+
372+ constructor . SetInvokeWithContext ( ( args , _ , _ , newTarget ) =>
373+ AsyncGeneratorFunctionConstructorBody ( args , newTarget as IJsCallable ?? constructor , engine , realm ) ) ;
374+
375+ StandardLibrary . DefineConstantProperty ( constructor , "length" , 1d , configurable : true ) ;
376+ StandardLibrary . DefineConstantProperty ( constructor , "name" , "AsyncGeneratorFunction" , configurable : true ) ;
377+
378+ if ( realm . FunctionPrototype is { } functionPrototype )
379+ {
380+ constructor . Properties . SetPrototype ( functionPrototype ) ;
381+ }
382+
383+ return constructor ;
384+ }
385+
386+ private static object ? AsyncGeneratorFunctionConstructorBody (
387+ IReadOnlyList < object ? > args ,
388+ IJsCallable newTarget ,
389+ JsEngine engine ,
390+ RealmState realm )
391+ {
392+ var evalContext = realm . CreateContext ( ) ;
393+ var argCount = args . Count ;
394+ var bodyValue = argCount > 0 ? args [ argCount - 1 ] : string . Empty ;
395+ var parameterCount = Math . Max ( argCount - 1 , 0 ) ;
396+
397+ var parameters = new string [ parameterCount ] ;
398+ for ( var i = 0 ; i < parameterCount ; i ++ )
399+ {
400+ var paramText = ToFunctionArgumentString ( args [ i ] , evalContext , realm ) ;
401+ parameters [ i ] = paramText ;
402+ }
403+
404+ var bodySource = ToFunctionArgumentString ( bodyValue , evalContext , realm ) ;
405+ var paramList = string . Join ( "," , parameters ) ;
406+ var functionSource = $ "(async function* anonymous({ paramList } \n ) {{\n { bodySource } \n }})";
407+
408+ var scriptGoalOptions = new JsEngineOptions
409+ {
410+ AllowImportMeta = false
411+ } ;
412+
413+ ParsedProgram program ;
414+ try
415+ {
416+ program = engine . ParseForExecution ( functionSource , options : scriptGoalOptions ) ;
417+ }
418+ catch ( Parser . ParseException parseException )
419+ {
420+ var message = parseException . Message ?? "SyntaxError" ;
421+ throw new ThrowSignal ( StandardLibrary . CreateSyntaxError ( message , evalContext , realm ) ) ;
422+ }
423+
424+ var created = engine . ExecuteProgram (
425+ program ,
426+ engine . GlobalEnvironment ,
427+ CancellationToken . None ) ;
428+
429+ if ( created is IJsObjectLike objectLike )
430+ {
431+ var proto = StandardLibrary . ResolveConstructPrototype (
432+ newTarget ,
433+ realm . AsyncGeneratorFunctionConstructor ,
434+ realm ) ;
435+ if ( proto is not null )
436+ {
437+ objectLike . SetPrototype ( proto ) ;
438+ }
439+ }
440+
441+ return created ;
442+ }
443+
444+ private static string ToFunctionArgumentString ( object ? value , EvaluationContext evalContext , RealmState realm )
445+ {
446+ var primitive = Runtime . JsOps . ToPrimitive ( value , "string" , evalContext ) ;
447+ if ( evalContext . IsThrow )
448+ {
449+ throw new ThrowSignal ( evalContext . FlowValue ) ;
450+ }
451+
452+ switch ( primitive )
453+ {
454+ case null :
455+ return "null" ;
456+ case Symbol sym when ReferenceEquals ( sym , Symbol . Undefined ) :
457+ return "undefined" ;
458+ case Symbol :
459+ case TypedAstSymbol :
460+ throw StandardLibrary . ThrowTypeError ( "Cannot convert a Symbol value to a string" , evalContext , realm ) ;
461+ case bool flag :
462+ return flag ? "true" : "false" ;
463+ case string s :
464+ return s ;
465+ case JsBigInt bigInt :
466+ return bigInt . Value . ToString ( System . Globalization . CultureInfo . InvariantCulture ) ;
467+ case double d when double . IsNaN ( d ) :
468+ return "NaN" ;
469+ case double d when double . IsPositiveInfinity ( d ) :
470+ return "Infinity" ;
471+ case double d when double . IsNegativeInfinity ( d ) :
472+ return "-Infinity" ;
473+ case double d :
474+ return d . ToString ( System . Globalization . CultureInfo . InvariantCulture ) ;
475+ }
476+
477+ return Convert . ToString ( primitive , System . Globalization . CultureInfo . InvariantCulture ) ?? string . Empty ;
478+ }
479+
357480 private void InitializeProperties ( )
358481 {
359482 EnsureAsyncGeneratorIntrinsics ( ) ;
0 commit comments