diff --git a/source/units/Goccia.Builtins.Benchmark.pas b/source/units/Goccia.Builtins.Benchmark.pas index 7270c38d..31df09d6 100644 --- a/source/units/Goccia.Builtins.Benchmark.pas +++ b/source/units/Goccia.Builtins.Benchmark.pas @@ -185,9 +185,9 @@ constructor TGocciaBenchmark.Create(const AName: string; const AScope: TGocciaSc FRegisteredBenchmarks := TObjectList.Create; FCurrentSuiteName := ''; - AScope.DefineLexicalBinding('suite', TGocciaNativeFunctionValue.Create(Suite, 'suite', 2), dtConst); - AScope.DefineLexicalBinding('bench', TGocciaNativeFunctionValue.Create(Bench, 'bench', 2), dtConst); - AScope.DefineLexicalBinding('runBenchmarks', TGocciaNativeFunctionValue.Create(RunBenchmarks, 'runBenchmarks', 0), dtConst); + AScope.DefineLexicalBinding('suite', TGocciaNativeFunctionValue.Create(Suite, 'suite', 2), dtConst, True); + AScope.DefineLexicalBinding('bench', TGocciaNativeFunctionValue.Create(Bench, 'bench', 2), dtConst, True); + AScope.DefineLexicalBinding('runBenchmarks', TGocciaNativeFunctionValue.Create(RunBenchmarks, 'runBenchmarks', 0), dtConst, True); end; destructor TGocciaBenchmark.Destroy; diff --git a/source/units/Goccia.Builtins.CSV.pas b/source/units/Goccia.Builtins.CSV.pas index 08ef6f49..f2dfce28 100644 --- a/source/units/Goccia.Builtins.CSV.pas +++ b/source/units/Goccia.Builtins.CSV.pas @@ -81,7 +81,7 @@ constructor TGocciaCSVBuiltin.Create(const AName: string; end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; destructor TGocciaCSVBuiltin.Destroy; diff --git a/source/units/Goccia.Builtins.Console.pas b/source/units/Goccia.Builtins.Console.pas index e9d98a48..e78f7cb8 100644 --- a/source/units/Goccia.Builtins.Console.pas +++ b/source/units/Goccia.Builtins.Console.pas @@ -118,7 +118,7 @@ constructor TGocciaConsole.Create(const AName: string; const AScope: TGocciaScop end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; procedure TGocciaConsole.EmitLine(const AMethod, ALine: string); diff --git a/source/units/Goccia.Builtins.DisposableStack.pas b/source/units/Goccia.Builtins.DisposableStack.pas index 476c43e8..98e74cd8 100644 --- a/source/units/Goccia.Builtins.DisposableStack.pas +++ b/source/units/Goccia.Builtins.DisposableStack.pas @@ -359,11 +359,11 @@ constructor TGocciaBuiltinDisposableStack.Create(const AName: string; DisposableStackFunc := TGocciaNativeFunctionValue.Create( DisposableStackConstructor, CONSTRUCTOR_DISPOSABLE_STACK, 0); - AScope.DefineLexicalBinding(CONSTRUCTOR_DISPOSABLE_STACK, DisposableStackFunc, dtConst); + AScope.DefineLexicalBinding(CONSTRUCTOR_DISPOSABLE_STACK, DisposableStackFunc, dtConst, True); AsyncDisposableStackFunc := TGocciaNativeFunctionValue.Create( AsyncDisposableStackConstructor, CONSTRUCTOR_ASYNC_DISPOSABLE_STACK, 0); - AScope.DefineLexicalBinding(CONSTRUCTOR_ASYNC_DISPOSABLE_STACK, AsyncDisposableStackFunc, dtConst); + AScope.DefineLexicalBinding(CONSTRUCTOR_ASYNC_DISPOSABLE_STACK, AsyncDisposableStackFunc, dtConst, True); end; function TGocciaBuiltinDisposableStack.DisposableStackConstructor( diff --git a/source/units/Goccia.Builtins.GlobalBigInt.pas b/source/units/Goccia.Builtins.GlobalBigInt.pas index 3aa5656f..4d98509e 100644 --- a/source/units/Goccia.Builtins.GlobalBigInt.pas +++ b/source/units/Goccia.Builtins.GlobalBigInt.pas @@ -98,7 +98,7 @@ constructor TGocciaGlobalBigInt.Create(const AName: string; const AScope: TGocci TGocciaPropertyDescriptorData.Create(Proto, [])); // Bind BigInt in scope - AScope.DefineLexicalBinding(AName, FBigIntFunction, dtLet); + AScope.DefineLexicalBinding(AName, FBigIntFunction, dtLet, True); end; // ES2026 §21.2.1.1 BigInt(value) — conversion function diff --git a/source/units/Goccia.Builtins.GlobalFFI.pas b/source/units/Goccia.Builtins.GlobalFFI.pas index 81073be7..0727ca2e 100644 --- a/source/units/Goccia.Builtins.GlobalFFI.pas +++ b/source/units/Goccia.Builtins.GlobalFFI.pas @@ -67,7 +67,7 @@ constructor TGocciaGlobalFFI.Create(const AName: string; const AScope: TGocciaSc end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtConst); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtConst, True); end; function TGocciaGlobalFFI.FFIOpen(const AArgs: TGocciaArgumentsCollection; const AThisValue: TGocciaValue): TGocciaValue; diff --git a/source/units/Goccia.Builtins.GlobalFetch.pas b/source/units/Goccia.Builtins.GlobalFetch.pas index ba636df4..f9f25170 100644 --- a/source/units/Goccia.Builtins.GlobalFetch.pas +++ b/source/units/Goccia.Builtins.GlobalFetch.pas @@ -107,7 +107,7 @@ constructor TGocciaGlobalFetch.Create(const AName: string; // Register fetch as a global function AScope.DefineLexicalBinding('fetch', - TGocciaNativeFunctionValue.Create(FetchCallback, 'fetch', 1), dtConst); + TGocciaNativeFunctionValue.Create(FetchCallback, 'fetch', 1), dtConst, True); end; destructor TGocciaGlobalFetch.Destroy; diff --git a/source/units/Goccia.Builtins.GlobalPromise.pas b/source/units/Goccia.Builtins.GlobalPromise.pas index 494a0d83..c74ae11c 100644 --- a/source/units/Goccia.Builtins.GlobalPromise.pas +++ b/source/units/Goccia.Builtins.GlobalPromise.pas @@ -478,7 +478,7 @@ constructor TGocciaGlobalPromise.Create(const AName: string; const AScope: TGocc end; RegisterMemberDefinitions(FPromiseConstructor, FStaticMembers); - AScope.DefineLexicalBinding(AName, FPromiseConstructor, dtLet); + AScope.DefineLexicalBinding(AName, FPromiseConstructor, dtLet, True); end; // ES2026 §27.2.4.8 get Promise [ @@species ] diff --git a/source/units/Goccia.Builtins.GlobalProxy.pas b/source/units/Goccia.Builtins.GlobalProxy.pas index d154baa5..75e50584 100644 --- a/source/units/Goccia.Builtins.GlobalProxy.pas +++ b/source/units/Goccia.Builtins.GlobalProxy.pas @@ -48,7 +48,7 @@ constructor TGocciaGlobalProxy.Create(const AScope: TGocciaScope); PROP_REVOCABLE, 2)); FConstructorValue := ConstructorFn; - AScope.DefineLexicalBinding(CONSTRUCTOR_PROXY, FConstructorValue, dtConst); + AScope.DefineLexicalBinding(CONSTRUCTOR_PROXY, FConstructorValue, dtConst, True); end; // ES2026 §28.2.1 Proxy(target, handler) diff --git a/source/units/Goccia.Builtins.GlobalReflect.pas b/source/units/Goccia.Builtins.GlobalReflect.pas index 0cc3dac5..347903e5 100644 --- a/source/units/Goccia.Builtins.GlobalReflect.pas +++ b/source/units/Goccia.Builtins.GlobalReflect.pas @@ -96,7 +96,7 @@ constructor TGocciaGlobalReflect.Create(const AName: string; const AScope: TGocc end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtConst); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtConst, True); end; // ES2026 §28.1.1 Reflect.apply(target, thisArgument, argumentsList) diff --git a/source/units/Goccia.Builtins.GlobalRegExp.pas b/source/units/Goccia.Builtins.GlobalRegExp.pas index ecbac7bf..7e633adb 100644 --- a/source/units/Goccia.Builtins.GlobalRegExp.pas +++ b/source/units/Goccia.Builtins.GlobalRegExp.pas @@ -350,7 +350,7 @@ constructor TGocciaGlobalRegExp.Create(const AName: string; end; RegisterMemberDefinitions(FRegExpConstructor, FStaticMembers); - AScope.DefineLexicalBinding(AName, FRegExpConstructor, dtConst); + AScope.DefineLexicalBinding(AName, FRegExpConstructor, dtConst, True); end; // ES2026 §22.2.4.2 get RegExp [ @@species ] diff --git a/source/units/Goccia.Builtins.GlobalSymbol.pas b/source/units/Goccia.Builtins.GlobalSymbol.pas index 4232899d..635900bc 100644 --- a/source/units/Goccia.Builtins.GlobalSymbol.pas +++ b/source/units/Goccia.Builtins.GlobalSymbol.pas @@ -116,7 +116,7 @@ constructor TGocciaGlobalSymbol.Create(const AName: string; const AScope: TGocci TGocciaPropertyDescriptorData.Create(FSymbolFunction, [pfConfigurable, pfWritable])); // Bind Symbol in scope - AScope.DefineLexicalBinding(AName, FSymbolFunction, dtLet); + AScope.DefineLexicalBinding(AName, FSymbolFunction, dtLet, True); end; destructor TGocciaGlobalSymbol.Destroy; diff --git a/source/units/Goccia.Builtins.Globals.pas b/source/units/Goccia.Builtins.Globals.pas index b523306c..7a85ced1 100644 --- a/source/units/Goccia.Builtins.Globals.pas +++ b/source/units/Goccia.Builtins.Globals.pas @@ -209,9 +209,9 @@ constructor TGocciaGlobals.Create(const AName: string; const AScope: TGocciaScop begin inherited Create(AName, AScope, AThrowError); - AScope.DefineLexicalBinding('undefined', TGocciaUndefinedLiteralValue.UndefinedValue, dtConst); - AScope.DefineLexicalBinding('NaN', TGocciaNumberLiteralValue.NaNValue, dtConst); - AScope.DefineLexicalBinding('Infinity', TGocciaNumberLiteralValue.InfinityValue, dtConst); + AScope.DefineLexicalBinding('undefined', TGocciaUndefinedLiteralValue.UndefinedValue, dtConst, True); + AScope.DefineLexicalBinding('NaN', TGocciaNumberLiteralValue.NaNValue, dtConst, True); + AScope.DefineLexicalBinding('Infinity', TGocciaNumberLiteralValue.InfinityValue, dtConst, True); FErrorProto := TGocciaObjectValue.Create; FErrorProto.DefineProperty(PROP_NAME, TGocciaPropertyDescriptorData.Create(TGocciaStringLiteralValue.Create(ERROR_NAME), [pfConfigurable, pfWritable])); @@ -323,36 +323,36 @@ constructor TGocciaGlobals.Create(const AName: string; const AScope: TGocciaScop FSuppressedErrorProto.DefineProperty(PROP_CONSTRUCTOR, TGocciaPropertyDescriptorData.Create(SuppressedErrorConstructorFunc, [pfConfigurable, pfWritable])); FDOMExceptionProto.DefineProperty(PROP_CONSTRUCTOR, TGocciaPropertyDescriptorData.Create(DOMExceptionConstructorFunc, [pfConfigurable, pfWritable])); - AScope.DefineLexicalBinding(ERROR_NAME, ErrorConstructorFunc, dtConst); - AScope.DefineLexicalBinding(TYPE_ERROR_NAME, TypeErrorConstructorFunc, dtConst); - AScope.DefineLexicalBinding(REFERENCE_ERROR_NAME, ReferenceErrorConstructorFunc, dtConst); - AScope.DefineLexicalBinding(RANGE_ERROR_NAME, RangeErrorConstructorFunc, dtConst); - AScope.DefineLexicalBinding(SYNTAX_ERROR_NAME, SyntaxErrorConstructorFunc, dtConst); - AScope.DefineLexicalBinding(URI_ERROR_NAME, URIErrorConstructorFunc, dtConst); - AScope.DefineLexicalBinding(AGGREGATE_ERROR_NAME, AggregateErrorConstructorFunc, dtConst); - AScope.DefineLexicalBinding(SUPPRESSED_ERROR_NAME, SuppressedErrorConstructorFunc, dtConst); - AScope.DefineLexicalBinding(DOM_EXCEPTION_NAME, DOMExceptionConstructorFunc, dtConst); + AScope.DefineLexicalBinding(ERROR_NAME, ErrorConstructorFunc, dtConst, True); + AScope.DefineLexicalBinding(TYPE_ERROR_NAME, TypeErrorConstructorFunc, dtConst, True); + AScope.DefineLexicalBinding(REFERENCE_ERROR_NAME, ReferenceErrorConstructorFunc, dtConst, True); + AScope.DefineLexicalBinding(RANGE_ERROR_NAME, RangeErrorConstructorFunc, dtConst, True); + AScope.DefineLexicalBinding(SYNTAX_ERROR_NAME, SyntaxErrorConstructorFunc, dtConst, True); + AScope.DefineLexicalBinding(URI_ERROR_NAME, URIErrorConstructorFunc, dtConst, True); + AScope.DefineLexicalBinding(AGGREGATE_ERROR_NAME, AggregateErrorConstructorFunc, dtConst, True); + AScope.DefineLexicalBinding(SUPPRESSED_ERROR_NAME, SuppressedErrorConstructorFunc, dtConst, True); + AScope.DefineLexicalBinding(DOM_EXCEPTION_NAME, DOMExceptionConstructorFunc, dtConst, True); AScope.DefineLexicalBinding('encodeURI', - TGocciaNativeFunctionValue.Create(EncodeURICallback, 'encodeURI', 1), dtConst); + TGocciaNativeFunctionValue.Create(EncodeURICallback, 'encodeURI', 1), dtConst, True); AScope.DefineLexicalBinding('decodeURI', - TGocciaNativeFunctionValue.Create(DecodeURICallback, 'decodeURI', 1), dtConst); + TGocciaNativeFunctionValue.Create(DecodeURICallback, 'decodeURI', 1), dtConst, True); AScope.DefineLexicalBinding('encodeURIComponent', - TGocciaNativeFunctionValue.Create(EncodeURIComponentCallback, 'encodeURIComponent', 1), dtConst); + TGocciaNativeFunctionValue.Create(EncodeURIComponentCallback, 'encodeURIComponent', 1), dtConst, True); AScope.DefineLexicalBinding('decodeURIComponent', - TGocciaNativeFunctionValue.Create(DecodeURIComponentCallback, 'decodeURIComponent', 1), dtConst); + TGocciaNativeFunctionValue.Create(DecodeURIComponentCallback, 'decodeURIComponent', 1), dtConst, True); end; procedure TGocciaGlobals.RegisterRuntimeGlobals; begin FScope.DefineLexicalBinding('queueMicrotask', - TGocciaNativeFunctionValue.Create(QueueMicrotaskCallback, 'queueMicrotask', 1), dtConst); + TGocciaNativeFunctionValue.Create(QueueMicrotaskCallback, 'queueMicrotask', 1), dtConst, True); FScope.DefineLexicalBinding('structuredClone', - TGocciaNativeFunctionValue.Create(StructuredCloneCallback, 'structuredClone', 1), dtConst); + TGocciaNativeFunctionValue.Create(StructuredCloneCallback, 'structuredClone', 1), dtConst, True); end; { NativeError ( message [ , options ] ) — §20.5.6.1.1 (shared by all NativeError constructors) diff --git a/source/units/Goccia.Builtins.JSON.pas b/source/units/Goccia.Builtins.JSON.pas index 82b8f08c..a33ec142 100644 --- a/source/units/Goccia.Builtins.JSON.pas +++ b/source/units/Goccia.Builtins.JSON.pas @@ -92,7 +92,7 @@ constructor TGocciaJSONBuiltin.Create(const AName: string; const AScope: TGoccia end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; destructor TGocciaJSONBuiltin.Destroy; diff --git a/source/units/Goccia.Builtins.JSON5.pas b/source/units/Goccia.Builtins.JSON5.pas index 75e7c360..8eb65b44 100644 --- a/source/units/Goccia.Builtins.JSON5.pas +++ b/source/units/Goccia.Builtins.JSON5.pas @@ -130,7 +130,7 @@ constructor TGocciaJSON5Builtin.Create(const AName: string; end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; destructor TGocciaJSON5Builtin.Destroy; diff --git a/source/units/Goccia.Builtins.JSONL.pas b/source/units/Goccia.Builtins.JSONL.pas index 12ad6869..5464c261 100644 --- a/source/units/Goccia.Builtins.JSONL.pas +++ b/source/units/Goccia.Builtins.JSONL.pas @@ -75,7 +75,7 @@ constructor TGocciaJSONLBuiltin.Create(const AName: string; end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; destructor TGocciaJSONLBuiltin.Destroy; diff --git a/source/units/Goccia.Builtins.Math.pas b/source/units/Goccia.Builtins.Math.pas index 08515fa1..9f4f6525 100644 --- a/source/units/Goccia.Builtins.Math.pas +++ b/source/units/Goccia.Builtins.Math.pas @@ -151,7 +151,7 @@ constructor TGocciaMath.Create(const AName: string; const AScope: TGocciaScope; end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; // §21.3.2.1 Math.abs ( x ) diff --git a/source/units/Goccia.Builtins.Performance.pas b/source/units/Goccia.Builtins.Performance.pas index 9027dfe2..d5821c90 100644 --- a/source/units/Goccia.Builtins.Performance.pas +++ b/source/units/Goccia.Builtins.Performance.pas @@ -239,7 +239,7 @@ constructor TGocciaPerformance.Create(const AName: string; const AScope: TGoccia TGocciaObjectValue.InitializeSharedPrototype; FBuiltinObject := TGocciaPerformanceValue.Create; - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; initialization diff --git a/source/units/Goccia.Builtins.TOML.pas b/source/units/Goccia.Builtins.TOML.pas index 685c8704..394ede16 100644 --- a/source/units/Goccia.Builtins.TOML.pas +++ b/source/units/Goccia.Builtins.TOML.pas @@ -63,7 +63,7 @@ constructor TGocciaTOMLBuiltin.Create(const AName: string; end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; destructor TGocciaTOMLBuiltin.Destroy; diff --git a/source/units/Goccia.Builtins.TSV.pas b/source/units/Goccia.Builtins.TSV.pas index f5da3a91..cf6467eb 100644 --- a/source/units/Goccia.Builtins.TSV.pas +++ b/source/units/Goccia.Builtins.TSV.pas @@ -81,7 +81,7 @@ constructor TGocciaTSVBuiltin.Create(const AName: string; end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; destructor TGocciaTSVBuiltin.Destroy; diff --git a/source/units/Goccia.Builtins.Temporal.pas b/source/units/Goccia.Builtins.Temporal.pas index 233b8f72..6fa5ecd6 100644 --- a/source/units/Goccia.Builtins.Temporal.pas +++ b/source/units/Goccia.Builtins.Temporal.pas @@ -140,7 +140,7 @@ constructor TGocciaTemporalBuiltin.Create(const AName: string; const AScope: TGo [pfConfigurable]); RegisterMemberDefinitions(FTemporalNamespace, TemporalMembers); - AScope.DefineLexicalBinding(AName, FTemporalNamespace, dtLet); + AScope.DefineLexicalBinding(AName, FTemporalNamespace, dtLet, True); finally TGarbageCollector.Instance.RemoveTempRoot(FTemporalNamespace); end; diff --git a/source/units/Goccia.Builtins.TestingLibrary.pas b/source/units/Goccia.Builtins.TestingLibrary.pas index 4956de56..bced84f6 100644 --- a/source/units/Goccia.Builtins.TestingLibrary.pas +++ b/source/units/Goccia.Builtins.TestingLibrary.pas @@ -2384,7 +2384,7 @@ constructor TGocciaTestAssertions.Create(const AName: string; const AScope: TGoc GlobalObject.DefineProperty(AName, TGocciaPropertyDescriptorData.Create(AValue, [pfWritable, pfConfigurable])) else - AScope.DefineLexicalBinding(AName, AValue, dtConst); + AScope.DefineLexicalBinding(AName, AValue, dtConst, True); end; begin @@ -2419,8 +2419,8 @@ constructor TGocciaTestAssertions.Create(const AName: string; const AScope: TGoc // Private aliases used by generated Test262 wrappers. Some conformance // tests intentionally declare globals named describe/test. AScope.DefineLexicalBinding('__gocciaTest262Describe', DescribeFunction, - dtConst); - AScope.DefineLexicalBinding('__gocciaTest262Test', TestFunction, dtConst); + dtConst, True); + AScope.DefineLexicalBinding('__gocciaTest262Test', TestFunction, dtConst, True); ItFunction := TGocciaNativeFunctionValue.Create(It, 'it', 2); ConfigureTestFunction(ItFunction); diff --git a/source/units/Goccia.Builtins.YAML.pas b/source/units/Goccia.Builtins.YAML.pas index c0f560e8..24c627d3 100644 --- a/source/units/Goccia.Builtins.YAML.pas +++ b/source/units/Goccia.Builtins.YAML.pas @@ -66,7 +66,7 @@ constructor TGocciaYAMLBuiltin.Create(const AName: string; end; RegisterMemberDefinitions(FBuiltinObject, FStaticMembers); - AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet); + AScope.DefineLexicalBinding(AName, FBuiltinObject, dtLet, True); end; destructor TGocciaYAMLBuiltin.Destroy; diff --git a/source/units/Goccia.Engine.pas b/source/units/Goccia.Engine.pas index 5dfc452a..3bf627aa 100644 --- a/source/units/Goccia.Engine.pas +++ b/source/units/Goccia.Engine.pas @@ -587,7 +587,7 @@ procedure TGocciaEngine.ExecuteShims; LoadShimValue(FInterpreter, Shim) else FInterpreter.GlobalScope.DefineLexicalBinding(Shim.Name, - LoadShimValue(FInterpreter, Shim), dtConst); + LoadShimValue(FInterpreter, Shim), dtConst, True); end; end; @@ -745,7 +745,7 @@ procedure TGocciaEngine.RegisterBuiltIns; FBuiltinGlobalString := TGocciaGlobalString.Create(CONSTRUCTOR_STRING, Scope, ThrowError); FBuiltinGlobals := TGocciaGlobals.Create('Globals', Scope, ThrowError); FBuiltinDisposableStack := TGocciaBuiltinDisposableStack.Create('DisposableStack', Scope, ThrowError); - Scope.DefineLexicalBinding(CONSTRUCTOR_ITERATOR, TGocciaIteratorValue.CreateGlobalObject, dtConst); + Scope.DefineLexicalBinding(CONSTRUCTOR_ITERATOR, TGocciaIteratorValue.CreateGlobalObject, dtConst, True); RegisterBuiltinConstructors; end; @@ -892,12 +892,12 @@ procedure TGocciaEngine.RegisterBuiltinConstructors; if Assigned(FBuiltinArrayBuffer) then for Key in FBuiltinArrayBuffer.BuiltinObject.GetAllPropertyNames do ArrayBufferConstructor.SetProperty(Key, FBuiltinArrayBuffer.BuiltinObject.GetProperty(Key)); - FInterpreter.GlobalScope.DefineLexicalBinding(CONSTRUCTOR_ARRAY_BUFFER, ArrayBufferConstructor, dtConst); + FInterpreter.GlobalScope.DefineLexicalBinding(CONSTRUCTOR_ARRAY_BUFFER, ArrayBufferConstructor, dtConst, True); SharedArrayBufferConstructor := TGocciaSharedArrayBufferClassValue.Create(CONSTRUCTOR_SHARED_ARRAY_BUFFER, nil); TGocciaSharedArrayBufferValue.ExposePrototype(SharedArrayBufferConstructor); SharedArrayBufferConstructor.Prototype.Prototype := ObjectConstructor.Prototype; - FInterpreter.GlobalScope.DefineLexicalBinding(CONSTRUCTOR_SHARED_ARRAY_BUFFER, SharedArrayBufferConstructor, dtConst); + FInterpreter.GlobalScope.DefineLexicalBinding(CONSTRUCTOR_SHARED_ARRAY_BUFFER, SharedArrayBufferConstructor, dtConst, True); // Create %TypedArray% intrinsic (not globally exposed per spec §23.2.1) FTypedArrayIntrinsic := TGocciaClassValue.Create('TypedArray', nil); @@ -992,7 +992,7 @@ procedure TGocciaEngine.RegisterBuiltinConstructors; TGocciaClassValue.PatchDefaultPrototype(NumberConstructor); TGocciaClassValue.PatchDefaultPrototype(BooleanConstructor); TGocciaClassValue.PatchDefaultPrototype(FunctionConstructor); - FInterpreter.GlobalScope.DefineLexicalBinding('Function', FunctionConstructor, dtConst); + FInterpreter.GlobalScope.DefineLexicalBinding('Function', FunctionConstructor, dtConst, True); // ES2026 §20.4.3: Symbol.prototype's [[Prototype]] is %Object.prototype% if Assigned(TGocciaSymbolValue.SharedPrototype) then @@ -1048,7 +1048,7 @@ procedure TGocciaEngine.RegisterTypedArrayConstructor(const AName: string; const TGocciaTypedArrayValue.SetUint8Prototype(TAConstructor.Prototype); end; - FInterpreter.GlobalScope.DefineLexicalBinding(AName, TAConstructor, dtConst); + FInterpreter.GlobalScope.DefineLexicalBinding(AName, TAConstructor, dtConst, True); end; procedure TGocciaEngine.RegisterGlobalThis; @@ -1084,7 +1084,7 @@ procedure TGocciaEngine.RegisterGlobalThis; if Scope.ContainsOwnLexicalBinding('globalThis') then Scope.ForceUpdateBinding('globalThis', GlobalThisObj) else - Scope.DefineLexicalBinding('globalThis', GlobalThisObj, dtConst); + Scope.DefineLexicalBinding('globalThis', GlobalThisObj, dtConst, True); // ES2026 §9.1.2.5 NewGlobalEnvironment: a global Environment Record's // [[GlobalThisValue]] is the global object. Top-level `this` resolves @@ -1150,7 +1150,7 @@ procedure TGocciaEngine.RegisterGocciaScriptGlobal; GocciaObj.AssignProperty('gc', GCFunc); FGocciaGlobal := GocciaObj; - FInterpreter.GlobalScope.DefineLexicalBinding('Goccia', FGocciaGlobal, dtConst); + FInterpreter.GlobalScope.DefineLexicalBinding('Goccia', FGocciaGlobal, dtConst, True); end; function TGocciaEngine.GetResolver: TGocciaModuleResolver; diff --git a/source/units/Goccia.ObjectModel.Engine.pas b/source/units/Goccia.ObjectModel.Engine.pas index cffdd780..155fd1d7 100644 --- a/source/units/Goccia.ObjectModel.Engine.pas +++ b/source/units/Goccia.ObjectModel.Engine.pas @@ -136,7 +136,7 @@ procedure RegisterTypeDefinition(const AScope: TGocciaScope; ASpeciesGetter, 'get [Symbol.species]', 0), nil, [pfConfigurable])); - AScope.DefineLexicalBinding(ATypeDefinition.ConstructorName, AConstructor, dtConst); + AScope.DefineLexicalBinding(ATypeDefinition.ConstructorName, AConstructor, dtConst, True); end; end. diff --git a/source/units/Goccia.Runtime.pas b/source/units/Goccia.Runtime.pas index 98fb8428..a48aa5fa 100644 --- a/source/units/Goccia.Runtime.pas +++ b/source/units/Goccia.Runtime.pas @@ -812,7 +812,7 @@ procedure TGocciaRuntimeExtension.RegisterRuntimeConstructors; begin PerformanceConstructor := TGocciaPerformance.CreateInterfaceObject; FEngine.Interpreter.GlobalScope.DefineLexicalBinding( - CONSTRUCTOR_PERFORMANCE, PerformanceConstructor, dtConst); + CONSTRUCTOR_PERFORMANCE, PerformanceConstructor, dtConst, True); end; end; diff --git a/source/units/Goccia.Scope.BindingMap.pas b/source/units/Goccia.Scope.BindingMap.pas index 11082d80..16dce310 100644 --- a/source/units/Goccia.Scope.BindingMap.pas +++ b/source/units/Goccia.Scope.BindingMap.pas @@ -23,6 +23,7 @@ TLexicalBinding = record Value: TGocciaValue; DeclarationType: TGocciaDeclarationType; Initialized: Boolean; + BuiltIn: Boolean; { Strict-types annotation enforced on every assignment. Default sltUntyped means no enforcement (typical untyped binding). } TypeHint: TGocciaLocalType; diff --git a/source/units/Goccia.Scope.Redeclaration.pas b/source/units/Goccia.Scope.Redeclaration.pas index 1fe235a4..8fc0b732 100644 --- a/source/units/Goccia.Scope.Redeclaration.pas +++ b/source/units/Goccia.Scope.Redeclaration.pas @@ -22,27 +22,32 @@ implementation procedure CheckPatternRedeclarations( const APattern: TGocciaDestructuringPattern; - const AScope: TGocciaScope; const ASourcePath: string); + const AScope: TGocciaScope; const ASourcePath: string; + const AIsVar: Boolean); var ObjPat: TGocciaObjectDestructuringPattern; ArrPat: TGocciaArrayDestructuringPattern; + DeclName: string; I: Integer; begin if APattern is TGocciaIdentifierDestructuringPattern then begin - if AScope.ContainsOwnLexicalBinding( - TGocciaIdentifierDestructuringPattern(APattern).Name) then + DeclName := TGocciaIdentifierDestructuringPattern(APattern).Name; + if AScope.ContainsOwnLexicalBinding(DeclName) then + begin + if AIsVar and AScope.IsBuiltInBinding(DeclName) then + Exit; raise TGocciaSyntaxError.Create( SysUtils.Format('Identifier ''%s'' has already been declared', - [TGocciaIdentifierDestructuringPattern(APattern).Name]), - 0, 0, ASourcePath, nil); + [DeclName]), 0, 0, ASourcePath, nil); + end; end else if APattern is TGocciaObjectDestructuringPattern then begin ObjPat := TGocciaObjectDestructuringPattern(APattern); for I := 0 to ObjPat.Properties.Count - 1 do CheckPatternRedeclarations(ObjPat.Properties[I].Pattern, - AScope, ASourcePath); + AScope, ASourcePath, AIsVar); end else if APattern is TGocciaArrayDestructuringPattern then begin @@ -50,16 +55,16 @@ procedure CheckPatternRedeclarations( for I := 0 to ArrPat.Elements.Count - 1 do if Assigned(ArrPat.Elements[I]) then CheckPatternRedeclarations(ArrPat.Elements[I], - AScope, ASourcePath); + AScope, ASourcePath, AIsVar); end else if APattern is TGocciaAssignmentDestructuringPattern then CheckPatternRedeclarations( TGocciaAssignmentDestructuringPattern(APattern).Left, - AScope, ASourcePath) + AScope, ASourcePath, AIsVar) else if APattern is TGocciaRestDestructuringPattern then CheckPatternRedeclarations( TGocciaRestDestructuringPattern(APattern).Argument, - AScope, ASourcePath); + AScope, ASourcePath, AIsVar); end; procedure CheckTopLevelRedeclarations(const AProgram: TGocciaProgram; @@ -80,9 +85,16 @@ procedure CheckTopLevelRedeclarations(const AProgram: TGocciaProgram; begin DeclName := VarDecl.Variables[J].Name; if AScope.ContainsOwnLexicalBinding(DeclName) then + begin + // §16.1.7: var/function declarations may shadow built-in + // globals in script mode, but not user-declared bindings. + if (VarDecl.IsVar or VarDecl.IsFunctionDeclaration) and + AScope.IsBuiltInBinding(DeclName) then + Continue; raise TGocciaSyntaxError.Create( SysUtils.Format('Identifier ''%s'' has already been declared', [DeclName]), Stmt.Line, Stmt.Column, ASourcePath, nil); + end; end; end else if Stmt is TGocciaClassDeclaration then @@ -95,7 +107,8 @@ procedure CheckTopLevelRedeclarations(const AProgram: TGocciaProgram; end else if Stmt is TGocciaDestructuringDeclaration then CheckPatternRedeclarations( - TGocciaDestructuringDeclaration(Stmt).Pattern, AScope, ASourcePath) + TGocciaDestructuringDeclaration(Stmt).Pattern, AScope, ASourcePath, + TGocciaDestructuringDeclaration(Stmt).IsVar) else if Stmt is TGocciaEnumDeclaration then begin DeclName := TGocciaEnumDeclaration(Stmt).Name; diff --git a/source/units/Goccia.Scope.pas b/source/units/Goccia.Scope.pas index ed523c47..be701bf1 100644 --- a/source/units/Goccia.Scope.pas +++ b/source/units/Goccia.Scope.pas @@ -50,7 +50,7 @@ TGocciaScope = class(TGCManagedObject) // New Define/Assign pattern procedure PredeclareLexicalBinding(const AName: string; const ADeclarationType: TGocciaDeclarationType; const ALine: Integer = 0; const AColumn: Integer = 0); - procedure DefineLexicalBinding(const AName: string; const AValue: TGocciaValue; const ADeclarationType: TGocciaDeclarationType; const ALine: Integer = 0; const AColumn: Integer = 0); + procedure DefineLexicalBinding(const AName: string; const AValue: TGocciaValue; const ADeclarationType: TGocciaDeclarationType; const ABuiltIn: Boolean = False; const ALine: Integer = 0; const AColumn: Integer = 0); procedure AssignBinding(const AName: string; const AValue: TGocciaValue; const ALine: Integer = 0; const AColumn: Integer = 0); virtual; procedure ForceUpdateBinding(const AName: string; const AValue: TGocciaValue); @@ -74,6 +74,7 @@ TGocciaScope = class(TGCManagedObject) function ResolveIdentifier(const AName: string): TGocciaValue; inline; function ContainsOwnLexicalBinding(const AName: string): Boolean; inline; + function IsBuiltInBinding(const AName: string): Boolean; function Contains(const AName: string): Boolean; inline; function GetOwnBindingNames: TGocciaStringArray; inline; @@ -344,11 +345,12 @@ procedure TGocciaScope.PredeclareLexicalBinding(const AName: string; LexicalBinding.Value := TGocciaUndefinedLiteralValue.UndefinedValue; LexicalBinding.DeclarationType := ADeclarationType; LexicalBinding.Initialized := False; + LexicalBinding.BuiltIn := False; LexicalBinding.TypeHint := sltUntyped; FLexicalBindings.Add(AName, LexicalBinding); end; -procedure TGocciaScope.DefineLexicalBinding(const AName: string; const AValue: TGocciaValue; const ADeclarationType: TGocciaDeclarationType; const ALine: Integer = 0; const AColumn: Integer = 0); +procedure TGocciaScope.DefineLexicalBinding(const AName: string; const AValue: TGocciaValue; const ADeclarationType: TGocciaDeclarationType; const ABuiltIn: Boolean = False; const ALine: Integer = 0; const AColumn: Integer = 0); var LexicalBinding: TLexicalBinding; ExistingLexicalBinding: TLexicalBinding; @@ -362,6 +364,7 @@ procedure TGocciaScope.DefineLexicalBinding(const AName: string; const AValue: T ExistingLexicalBinding.Value := AValue; ExistingLexicalBinding.DeclarationType := ADeclarationType; ExistingLexicalBinding.Initialized := True; + ExistingLexicalBinding.BuiltIn := ABuiltIn; FLexicalBindings.AddOrSetValue(AName, ExistingLexicalBinding); Exit; end; @@ -386,6 +389,7 @@ procedure TGocciaScope.DefineLexicalBinding(const AName: string; const AValue: T // - dtLet: no TDZ after declaration statement is processed // - dtParameter: parameters have no TDZ LexicalBinding.Initialized := True; + LexicalBinding.BuiltIn := ABuiltIn; LexicalBinding.TypeHint := sltUntyped; FLexicalBindings.AddOrSetValue(AName, LexicalBinding); @@ -422,9 +426,24 @@ procedure TGocciaScope.DefineVariableBinding(const AName: string; const AValue: var TargetScope: TGocciaScope; Binding: TLexicalBinding; + ExistingBuiltIn: TLexicalBinding; + EffectiveValue: TGocciaValue; GlobalObject: TGocciaObjectValue; begin TargetScope := FindFunctionOrModuleScope; + EffectiveValue := AValue; + + // §16.1.7: var/function declarations may shadow built-in globals in + // script mode. Only the global scope carries built-in bindings, so + // skip the lookup for function/module-scoped vars (the common case). + if (TargetScope.FScopeKind = skGlobal) and + TargetScope.FLexicalBindings.TryGetValue(AName, ExistingBuiltIn) and + ExistingBuiltIn.BuiltIn then + begin + if not AHasInitializer then + EffectiveValue := ExistingBuiltIn.Value; + TargetScope.FLexicalBindings.Remove(AName); + end; if (TargetScope.FScopeKind = skGlobal) and (TargetScope.FThisValue is TGocciaObjectValue) then @@ -432,7 +451,7 @@ procedure TGocciaScope.DefineVariableBinding(const AName: string; const AValue: GlobalObject := TGocciaObjectValue(TargetScope.FThisValue); if (not AHasInitializer) and GlobalObject.HasOwnProperty(AName) then Exit; - GlobalObject.AssignProperty(AName, AValue); + GlobalObject.AssignProperty(AName, EffectiveValue); Exit; end; @@ -445,16 +464,17 @@ procedure TGocciaScope.DefineVariableBinding(const AName: string; const AValue: // Redeclaration: only update if the source had a syntactic initializer. if AHasInitializer then begin - Binding.Value := AValue; + Binding.Value := EffectiveValue; TargetScope.FVarBindings.AddOrSetValue(AName, Binding); end; end else begin // First declaration: create the binding - Binding.Value := AValue; + Binding.Value := EffectiveValue; Binding.DeclarationType := dtVar; Binding.Initialized := True; + Binding.BuiltIn := False; Binding.TypeHint := sltUntyped; TargetScope.FVarBindings.AddOrSetValue(AName, Binding); end; @@ -610,6 +630,13 @@ function TGocciaScope.ContainsOwnLexicalBinding(const AName: string): Boolean; i Result := FLexicalBindings.ContainsKey(AName); end; +function TGocciaScope.IsBuiltInBinding(const AName: string): Boolean; +var + Binding: TLexicalBinding; +begin + Result := FLexicalBindings.TryGetValue(AName, Binding) and Binding.BuiltIn; +end; + function TGocciaScope.Contains(const AName: string): Boolean; inline; begin Result := ContainsOwnLexicalBinding(AName) or diff --git a/tests/language/declarations/const/cannot-shadow-builtin-globals.js b/tests/language/declarations/const/cannot-shadow-builtin-globals.js new file mode 100644 index 00000000..b11df7b4 --- /dev/null +++ b/tests/language/declarations/const/cannot-shadow-builtin-globals.js @@ -0,0 +1,20 @@ +/*--- +description: const cannot shadow built-in globals at the same scope level but can in nested blocks +features: [const-declaration] +---*/ + +test("const in a nested block shadows built-in NaN locally", () => { + { + const NaN = 42; + expect(NaN).toBe(42); + } + expect(NaN).toBeNaN(); +}); + +test("const in a nested block shadows built-in Array locally", () => { + { + const Array = "not-an-array"; + expect(Array).toBe("not-an-array"); + } + expect(typeof Array).toBe("function"); +}); diff --git a/tests/language/declarations/let/cannot-shadow-builtin-globals.js b/tests/language/declarations/let/cannot-shadow-builtin-globals.js new file mode 100644 index 00000000..2eb9ce4c --- /dev/null +++ b/tests/language/declarations/let/cannot-shadow-builtin-globals.js @@ -0,0 +1,28 @@ +/*--- +description: let cannot shadow built-in globals at the same scope level but can in nested blocks +features: [let-declaration] +---*/ + +test("let in a nested block shadows built-in NaN locally", () => { + { + let NaN = 42; + expect(NaN).toBe(42); + } + expect(NaN).toBeNaN(); +}); + +test("let in a nested block shadows built-in Infinity locally", () => { + { + let Infinity = "finite"; + expect(Infinity).toBe("finite"); + } + expect(Infinity).toBe(1 / 0); +}); + +test("let in a nested block shadows built-in Array locally", () => { + { + let Array = "not-an-array"; + expect(Array).toBe("not-an-array"); + } + expect(typeof Array).toBe("function"); +}); diff --git a/tests/language/function-keyword/shadow-builtin-globals.js b/tests/language/function-keyword/shadow-builtin-globals.js new file mode 100644 index 00000000..05b22222 --- /dev/null +++ b/tests/language/function-keyword/shadow-builtin-globals.js @@ -0,0 +1,23 @@ +/*--- +description: function declarations may shadow built-in globals in script mode (§16.1.7) +features: [compat-function, compat-var] +---*/ + +function Array() { return "custom"; } +function Object() { return "custom-object"; } +function Error() { return "custom-error"; } + +test("top-level function declaration shadows built-in Array", () => { + expect(typeof Array).toBe("function"); + expect(Array()).toBe("custom"); +}); + +test("top-level function declaration shadows built-in Object", () => { + expect(typeof Object).toBe("function"); + expect(Object()).toBe("custom-object"); +}); + +test("top-level function declaration shadows built-in Error", () => { + expect(typeof Error).toBe("function"); + expect(Error()).toBe("custom-error"); +}); diff --git a/tests/language/var/shadow-builtin-globals.js b/tests/language/var/shadow-builtin-globals.js new file mode 100644 index 00000000..c867b034 --- /dev/null +++ b/tests/language/var/shadow-builtin-globals.js @@ -0,0 +1,44 @@ +/*--- +description: top-level var declarations may shadow built-in globals in script mode (§16.1.7) +features: [compat-var] +---*/ + +var NaN; +var Infinity; +var undefined; + +test("top-level var NaN without initializer preserves the built-in value", () => { + expect(typeof NaN).toBe("number"); +}); + +test("function-scoped var NaN with initializer creates a local binding", () => { + const fn = () => { + var NaN = 42; + return NaN; + }; + expect(fn()).toBe(42); +}); + +test("top-level var Infinity without initializer preserves the built-in value", () => { + expect(typeof Infinity).toBe("number"); + expect(Infinity).toBe(1 / 0); +}); + +test("top-level var undefined without initializer preserves the built-in value", () => { + expect(typeof undefined).toBe("undefined"); +}); + +var Array = "shadowed"; + +test("top-level var with initializer shadows a writable built-in", () => { + expect(Array).toBe("shadowed"); +}); + +test("var inside a function creates a local binding, does not touch the global", () => { + const fn = () => { + var Map = "local"; + return Map; + }; + expect(fn()).toBe("local"); + expect(typeof Map).toBe("function"); +});