Enum support#33
Conversation
📝 WalkthroughWalkthroughThis PR adds TC39-style enum support across the language stack (lexer, token, parser, AST, evaluator, interpreter, runtime EnumValue), introduces DOMException/DataCloneError plumbing for structuredClone errors, augments String well-formedness handling, and adds comprehensive docs and tests for enums and related built-ins. Changes
Sequence DiagramsequenceDiagram
participant Parser
participant Evaluator
participant Scope
participant EnumValue
participant Symbols
Parser->>Parser: Parse 'enum' declaration (name, members, optional initializers)
Parser->>Evaluator: Emit TGocciaEnumDeclaration node
Evaluator->>EnumValue: Create enum instance (name)
Evaluator->>Scope: Create child scope for member evaluation
Evaluator->>Evaluator: Evaluate each member initializer in child scope
Evaluator->>EnumValue: Populate Entries array with [key,value] pairs
Evaluator->>Scope: Bind lexical names to enum members / enum object
EnumValue->>Symbols: Initialize Symbol.iterator (entries iterator)
EnumValue->>Symbols: Initialize Symbol.toStringTag (enum name)
Evaluator->>Scope: Bind enum into current scope (name -> EnumValue)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
Benchmark Results179 benchmarks · 🟢 30 improved · 149 unchanged · avg +2.6% arrays.js — 19 unchanged · avg +0.2%
classes.js — 15 unchanged · avg +0.3%
closures.js — 11 unchanged · avg +1.3%
collections.js — 12 unchanged · avg -1.0%
destructuring.js — 14 unchanged · avg -0.8%
fibonacci.js — 6 unchanged · avg +0.5%
iterators.js — 20 unchanged · avg +0.9%
json.js — 20 unchanged · avg +1.0%
jsx.jsx — 🟢 15 improved, 6 unchanged · avg +8.4%
numbers.js — 🟢 1 improved, 10 unchanged · avg +4.0%
objects.js — 🟢 1 improved, 6 unchanged · avg +4.3%
promises.js — 🟢 10 improved, 2 unchanged · avg +9.1%
strings.js — 🟢 3 improved, 8 unchanged · avg +5.4%
Measured on ubuntu-latest x64. Changes within ±7% are considered insignificant. |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
tests/built-ins/structuredClone/errors.js (1)
6-43: Consider aligning remaining error tests with the newer assertion style.The refactored test at lines 28-32 uses the cleaner
.toThrow(TypeError)pattern, but the other error tests (lines 6-15, 17-26, 34-43) still use the verbose try/catch approach. For consistency and readability, consider refactoring them as well.♻️ Example refactor for "throws on function" test
test("throws on function", () => { - let threw = false; - try { - structuredClone(() => {}); - } catch (e) { - threw = true; - expect(e.message.includes("could not be cloned")).toBe(true); - } - expect(threw).toBe(true); + expect(() => { + structuredClone(() => {}); + }).toThrow("could not be cloned"); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/built-ins/structuredClone/errors.js` around lines 6 - 43, Convert the verbose try/catch assertions in the "throws on function", "throws on symbol", and "throws on object containing a function" tests to the concise Jest form used in the other test: replace the manual try/catch + flag pattern with expect(() => structuredClone(...)).toThrow(TypeError) or, if you want to assert the message, use expect(() => structuredClone(...)).toThrow(/could not be cloned/); update the tests named "throws on function", "throws on symbol", and "throws on object containing a function" to use this pattern for consistency.README.md (1)
150-150: Consider keeping the test-count wording resilient to drift.
Exact counts tend to go stale; a looser phrasing (e.g., “2k+”) is easier to maintain.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` at line 150, The exact test count in the README sentence "GocciaScript has 2300+ JavaScript unit tests covering language features, built-in objects, and edge cases." is likely to become stale; update that line to a looser, drift-resistant phrasing such as "2k+ JavaScript unit tests" or "2,300+ JavaScript unit tests" (whichever team style prefers) so the README remains accurate without frequent updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@units/Goccia.Builtins.Globals.pas`:
- Around line 339-343: Add a brief inline comment above the block where
StructuredCloneValue(AObj.GetProperty(Keys[I]), AMemory) is converted into a
data property and where Descriptor.Flags is changed (the call to
Result.DefineProperty with TGocciaPropertyDescriptorData and the flag expression
Descriptor.Flags - [pfConfigurable, pfWritable] + [pfEnumerable]); explain that
accessor properties on enum members are intentionally converted to
non-configurable, non-writable data properties to enforce enum immutability and
reference the relevant structuredClone/enum spec section or HTML spec for
justification. Also add a unit test that structuredClones an enum-like object
and asserts the cloned property descriptor flags match the expected
non-configurable, non-writable, enumerable state.
In `@units/Goccia.Evaluator.pas`:
- Around line 1442-1444: Add the ECMAScript spec annotation comment immediately
above the function declaration for EvaluateEnumDeclaration: insert a single-line
comment in the format // ES2024 §X.Y.Z EvaluateEnumDeclaration(const
AEnumDeclaration: TGocciaEnumDeclaration; const AContext:
TGocciaEvaluationContext) (replace §X.Y.Z with the actual spec section number if
known); place it directly above the existing "function
EvaluateEnumDeclaration(...)" line so the evaluator entry point is annotated per
project convention.
- Around line 1442-1489: EvaluateEnumDeclaration builds EnumValue and
EnumEntries in Pascal-only variables without temp-rooting and never frees
ChildScope; protect temporary GC-visible values by calling AddTempRoot on
EnumValue and EnumEntries (and any EntryPair/MemberValue as needed) before
evaluating members and RemoveTempRoot after assigning EnumValue. Also ensure
ChildScope is freed after use (after AContext.Scope.DefineLexicalBinding and
before returning) so the enum init scope is released; reference the
EvaluateEnumDeclaration function, EnumValue, EnumEntries, ChildScope,
ChildContext, InitializeEnumSymbols and PreventExtensions when applying these
AddTempRoot/RemoveTempRoot and freeing fixes.
In `@units/Goccia.Lexer.pas`:
- Around line 242-265: When parsing UTF-16 surrogate pairs in the CodePoint
combine block (where SavedCurrent is used and Advance is called to consume '\'
and 'u'), also save the current column before advancing (e.g. SavedColumn :=
FColumn) and on any backtrack paths (both the IsAtEnd break and the LowSurrogate
invalid branch) restore FColumn along with FCurrent (FCurrent := SavedCurrent;
FColumn := SavedColumn) so token/error positions stay in sync; update all
backtrack sites in that CodePoint/Advance sequence to restore SavedColumn.
In `@units/Goccia.Values.EnumValue.pas`:
- Around line 58-63: EnumSymbolIterator currently uses Self.FEntries causing
detached/borrowed iterator calls to iterate the wrong enum; modify
TGocciaEnumValue.EnumSymbolIterator to use the call receiver AThisValue: add
Goccia.Values.ErrorHelper to the implementation uses clause, check if AThisValue
is TGocciaEnumValue and if so create the iterator with (AThisValue as
TGocciaEnumValue).FEntries and akValues, otherwise call ThrowError with the
"called on non-enum" message (use ThrowError, not ThrowTypeError) to match
Array.values() patterns.
- Around line 53-56: TGocciaEnumValue.TypeName currently returns FName which
violates the object-type contract; update the method TGocciaEnumValue.TypeName
to return the OBJECT_TYPE_NAME constant from Goccia.Constants.TypeNames
(matching other TGocciaObjectValue-derived types) so enum values report as the
`"object"` type rather than the enum name.
---
Nitpick comments:
In `@README.md`:
- Line 150: The exact test count in the README sentence "GocciaScript has 2300+
JavaScript unit tests covering language features, built-in objects, and edge
cases." is likely to become stale; update that line to a looser, drift-resistant
phrasing such as "2k+ JavaScript unit tests" or "2,300+ JavaScript unit tests"
(whichever team style prefers) so the README remains accurate without frequent
updates.
In `@tests/built-ins/structuredClone/errors.js`:
- Around line 6-43: Convert the verbose try/catch assertions in the "throws on
function", "throws on symbol", and "throws on object containing a function"
tests to the concise Jest form used in the other test: replace the manual
try/catch + flag pattern with expect(() =>
structuredClone(...)).toThrow(TypeError) or, if you want to assert the message,
use expect(() => structuredClone(...)).toThrow(/could not be cloned/); update
the tests named "throws on function", "throws on symbol", and "throws on object
containing a function" to use this pattern for consistency.
| begin | ||
| ClonedValue := StructuredCloneValue(AObj.GetProperty(Keys[I]), AMemory); | ||
| Result.DefineProperty(Keys[I], | ||
| TGocciaPropertyDescriptorData.Create(ClonedValue, Descriptor.Flags - [pfConfigurable, pfWritable] + [pfEnumerable])); | ||
| end; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if there are tests covering accessor property cloning in structuredClone
rg -n "structuredClone.*get|accessor" tests/ 2>/dev/null || echo "No matches found"
# Check for any enum-related structuredClone tests
rg -n "structuredClone" tests/language/enums/ 2>/dev/null || echo "No enum tests found"
# Check broader test coverage for structuredClone
rg -l "structuredClone" tests/ | head -20Repository: frostney/GocciaScript
Length of output: 1000
🏁 Script executed:
#!/bin/bash
# Read the full context of the CloneObject function around lines 339-343
wc -l units/Goccia.Builtins.Globals.pasRepository: frostney/GocciaScript
Length of output: 102
🏁 Script executed:
#!/bin/bash
# Read the accessor cloning test
sed -n '40,70p' tests/built-ins/structuredClone/errors.jsRepository: frostney/GocciaScript
Length of output: 957
🏁 Script executed:
#!/bin/bash
# Read the code context around lines 339-343
sed -n '320,360p' units/Goccia.Builtins.Globals.pasRepository: frostney/GocciaScript
Length of output: 1375
🏁 Script executed:
#!/bin/bash
# Look at more context - check for comments explaining the flag choices
sed -n '310,350p' units/Goccia.Builtins.Globals.pas | cat -nRepository: frostney/GocciaScript
Length of output: 1779
🏁 Script executed:
#!/bin/bash
# Check the test more carefully - does it verify the descriptor flags of the cloned property?
sed -n '40,65p' tests/built-ins/structuredClone/errors.js | cat -nRepository: frostney/GocciaScript
Length of output: 912
🏁 Script executed:
#!/bin/bash
# Search for any documentation or comments about accessor cloning behavior
rg -B5 -A5 "TGocciaPropertyDescriptorAccessor" units/Goccia.Builtins.Globals.pas | head -40Repository: frostney/GocciaScript
Length of output: 624
🏁 Script executed:
#!/bin/bash
# Check if there are tests validating descriptor flags in structuredClone
rg -n "configurable|writable|enumerable" tests/built-ins/structuredClone/ -A2 -B2Repository: frostney/GocciaScript
Length of output: 448
🏁 Script executed:
#!/bin/bash
# Search for any spec comments or references in the globals file
rg -n "structuredClone|spec|HTML" units/Goccia.Builtins.Globals.pas | head -20Repository: frostney/GocciaScript
Length of output: 822
🏁 Script executed:
#!/bin/bash
# Check git history or comments for this specific change
git log --oneline -20 -- units/Goccia.Builtins.Globals.pas 2>/dev/null || echo "Git history unavailable"Repository: frostney/GocciaScript
Length of output: 143
🏁 Script executed:
#!/bin/bash
# Check what the full enum support commit changed
git show ab39941 --stat 2>/dev/null | head -30Repository: frostney/GocciaScript
Length of output: 1757
🏁 Script executed:
#!/bin/bash
# Look for any enum-related tests that might validate descriptor flags
find tests/ -name "*enum*" -type fRepository: frostney/GocciaScript
Length of output: 558
🏁 Script executed:
#!/bin/bash
# Check if there are other places in code that manipulate flags similarly for enums
rg -n "pfConfigurable.*pfWritable.*pfEnumerable|pfEnumerable.*pfConfigurable" units/Repository: frostney/GocciaScript
Length of output: 4247
🏁 Script executed:
#!/bin/bash
# Check the enum-immutability test to understand the expected behavior
cat tests/language/enums/enum-immutability.jsRepository: frostney/GocciaScript
Length of output: 741
🏁 Script executed:
#!/bin/bash
# Search for comments or documentation about enum property descriptors
rg -n "enum|immutable" units/Goccia.Builtins.Globals.pas -B2 -A2Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Let's verify what flags are set for enum accessor properties
rg -n "enum.*Accessor|DefineProperty.*PROP_" tests/language/enums/basic-enum.js -B2 -A2Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Check if structuredClone is used on enums in any tests
rg -n "structuredClone" tests/language/enums/Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Look at the broader context of how accessor properties are created for enums in the implementation
rg -B5 -A5 "DefineProperty.*Accessor.*pfEnumerable.*pfConfigurable.*pfWritable" units/ | head -50Repository: frostney/GocciaScript
Length of output: 2701
🏁 Script executed:
#!/bin/bash
# Check if there are any comments in the CloneObject function explaining the enum behavior
sed -n '306,350p' units/Goccia.Builtins.Globals.pas | cat -nRepository: frostney/GocciaScript
Length of output: 2117
🏁 Script executed:
#!/bin/bash
# Check if enum objects use accessor properties or data properties
rg -n "DefineProperty.*enum|enum.*DefineProperty" units/ -B2 -A2 | head -40Repository: frostney/GocciaScript
Length of output: 47
Add documentation explaining accessor property cloning behavior for enums.
The code correctly invokes the getter and clones the resulting value as a data property. However, the flag manipulation (removing pfConfigurable and pfWritable, adding pfEnumerable) lacks explanation. This appears intentional to support enum immutability—converting accessor properties to non-configurable, non-writable data properties—but should be documented with a comment referencing the enum behavior and/or the HTML structuredClone spec section. Additionally, consider adding a test validating structuredClone on enum objects to ensure descriptor flags match expectations.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@units/Goccia.Builtins.Globals.pas` around lines 339 - 343, Add a brief inline
comment above the block where StructuredCloneValue(AObj.GetProperty(Keys[I]),
AMemory) is converted into a data property and where Descriptor.Flags is changed
(the call to Result.DefineProperty with TGocciaPropertyDescriptorData and the
flag expression Descriptor.Flags - [pfConfigurable, pfWritable] +
[pfEnumerable]); explain that accessor properties on enum members are
intentionally converted to non-configurable, non-writable data properties to
enforce enum immutability and reference the relevant structuredClone/enum spec
section or HTML spec for justification. Also add a unit test that
structuredClones an enum-like object and asserts the cloned property descriptor
flags match the expected non-configurable, non-writable, enumerable state.
| // TC39 proposal-enum | ||
| function EvaluateEnumDeclaration(const AEnumDeclaration: TGocciaEnumDeclaration; const AContext: TGocciaEvaluationContext): TGocciaValue; | ||
| var |
There was a problem hiding this comment.
Add the ES spec annotation for the new evaluator entry point.
Please add the // ES<YYYY> §X.Y.Z EvaluateEnumDeclaration(...) comment immediately above the function body.
Based on learnings “When implementing ECMAScript-specified behavior, annotate each function or method with a comment referencing the relevant spec section using the format // ES §X.Y.Z MethodName(params) where YYYY is the current edition year.”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@units/Goccia.Evaluator.pas` around lines 1442 - 1444, Add the ECMAScript spec
annotation comment immediately above the function declaration for
EvaluateEnumDeclaration: insert a single-line comment in the format // ES2024
§X.Y.Z EvaluateEnumDeclaration(const AEnumDeclaration: TGocciaEnumDeclaration;
const AContext: TGocciaEvaluationContext) (replace §X.Y.Z with the actual spec
section number if known); place it directly above the existing "function
EvaluateEnumDeclaration(...)" line so the evaluator entry point is annotated per
project convention.
| // TC39 proposal-enum | ||
| function EvaluateEnumDeclaration(const AEnumDeclaration: TGocciaEnumDeclaration; const AContext: TGocciaEvaluationContext): TGocciaValue; | ||
| var | ||
| EnumValue: TGocciaEnumValue; | ||
| EnumEntries: TGocciaArrayValue; | ||
| ChildScope: TGocciaScope; | ||
| ChildContext: TGocciaEvaluationContext; | ||
| I: Integer; | ||
| MemberValue: TGocciaValue; | ||
| EntryPair: TGocciaArrayValue; | ||
| begin | ||
| EnumValue := TGocciaEnumValue.Create(AEnumDeclaration.Name); | ||
| EnumEntries := TGocciaArrayValue.Create; | ||
|
|
||
| ChildScope := AContext.Scope.CreateChild(skBlock); | ||
| ChildContext := AContext; | ||
| ChildContext.Scope := ChildScope; | ||
|
|
||
| ChildScope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet); | ||
|
|
||
| for I := 0 to Length(AEnumDeclaration.Members) - 1 do | ||
| begin | ||
| MemberValue := EvaluateExpression(AEnumDeclaration.Members[I].Initializer, ChildContext); | ||
|
|
||
| if not ((MemberValue is TGocciaNumberLiteralValue) or | ||
| (MemberValue is TGocciaStringLiteralValue) or | ||
| (MemberValue is TGocciaSymbolValue)) then | ||
| AContext.OnError('Enum member initializer must evaluate to a Number, String, or Symbol value', | ||
| AEnumDeclaration.Line, AEnumDeclaration.Column); | ||
|
|
||
| EnumValue.DefineProperty(AEnumDeclaration.Members[I].Name, | ||
| TGocciaPropertyDescriptorData.Create(MemberValue, [pfEnumerable])); | ||
|
|
||
| ChildScope.DefineLexicalBinding(AEnumDeclaration.Members[I].Name, MemberValue, dtLet); | ||
|
|
||
| EntryPair := TGocciaArrayValue.Create; | ||
| EntryPair.Elements.Add(TGocciaStringLiteralValue.Create(AEnumDeclaration.Members[I].Name)); | ||
| EntryPair.Elements.Add(MemberValue); | ||
| EnumEntries.Elements.Add(EntryPair); | ||
| end; | ||
|
|
||
| EnumValue.Entries := EnumEntries; | ||
| InitializeEnumSymbols(EnumValue); | ||
| EnumValue.PreventExtensions; | ||
|
|
||
| AContext.Scope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet); | ||
| Result := EnumValue; | ||
| end; |
There was a problem hiding this comment.
Protect enum construction from GC and free the child scope.
Enum entries are built while only held in Pascal variables; they should be temp-rooted, and the enum init scope should be freed after use to avoid leaks.
🔧 Suggested fix
function EvaluateEnumDeclaration(const AEnumDeclaration: TGocciaEnumDeclaration; const AContext: TGocciaEvaluationContext): TGocciaValue;
var
EnumValue: TGocciaEnumValue;
EnumEntries: TGocciaArrayValue;
ChildScope: TGocciaScope;
ChildContext: TGocciaEvaluationContext;
I: Integer;
MemberValue: TGocciaValue;
EntryPair: TGocciaArrayValue;
begin
EnumValue := TGocciaEnumValue.Create(AEnumDeclaration.Name);
EnumEntries := TGocciaArrayValue.Create;
+ TGocciaGarbageCollector.Instance.AddTempRoot(EnumValue);
+ TGocciaGarbageCollector.Instance.AddTempRoot(EnumEntries);
ChildScope := AContext.Scope.CreateChild(skBlock);
- ChildContext := AContext;
- ChildContext.Scope := ChildScope;
-
- ChildScope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet);
-
- for I := 0 to Length(AEnumDeclaration.Members) - 1 do
- begin
- MemberValue := EvaluateExpression(AEnumDeclaration.Members[I].Initializer, ChildContext);
- ...
- end;
-
- EnumValue.Entries := EnumEntries;
- InitializeEnumSymbols(EnumValue);
- EnumValue.PreventExtensions;
-
- AContext.Scope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet);
- Result := EnumValue;
+ try
+ ChildContext := AContext;
+ ChildContext.Scope := ChildScope;
+
+ ChildScope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet);
+
+ for I := 0 to Length(AEnumDeclaration.Members) - 1 do
+ begin
+ MemberValue := EvaluateExpression(AEnumDeclaration.Members[I].Initializer, ChildContext);
+ ...
+ end;
+
+ EnumValue.Entries := EnumEntries;
+ InitializeEnumSymbols(EnumValue);
+ EnumValue.PreventExtensions;
+
+ AContext.Scope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet);
+ Result := EnumValue;
+ finally
+ ChildScope.Free;
+ TGocciaGarbageCollector.Instance.RemoveTempRoot(EnumEntries);
+ TGocciaGarbageCollector.Instance.RemoveTempRoot(EnumValue);
+ end;
end;Based on learnings “Values held only by Pascal code must be protected with AddTempRoot/RemoveTempRoot.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // TC39 proposal-enum | |
| function EvaluateEnumDeclaration(const AEnumDeclaration: TGocciaEnumDeclaration; const AContext: TGocciaEvaluationContext): TGocciaValue; | |
| var | |
| EnumValue: TGocciaEnumValue; | |
| EnumEntries: TGocciaArrayValue; | |
| ChildScope: TGocciaScope; | |
| ChildContext: TGocciaEvaluationContext; | |
| I: Integer; | |
| MemberValue: TGocciaValue; | |
| EntryPair: TGocciaArrayValue; | |
| begin | |
| EnumValue := TGocciaEnumValue.Create(AEnumDeclaration.Name); | |
| EnumEntries := TGocciaArrayValue.Create; | |
| ChildScope := AContext.Scope.CreateChild(skBlock); | |
| ChildContext := AContext; | |
| ChildContext.Scope := ChildScope; | |
| ChildScope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet); | |
| for I := 0 to Length(AEnumDeclaration.Members) - 1 do | |
| begin | |
| MemberValue := EvaluateExpression(AEnumDeclaration.Members[I].Initializer, ChildContext); | |
| if not ((MemberValue is TGocciaNumberLiteralValue) or | |
| (MemberValue is TGocciaStringLiteralValue) or | |
| (MemberValue is TGocciaSymbolValue)) then | |
| AContext.OnError('Enum member initializer must evaluate to a Number, String, or Symbol value', | |
| AEnumDeclaration.Line, AEnumDeclaration.Column); | |
| EnumValue.DefineProperty(AEnumDeclaration.Members[I].Name, | |
| TGocciaPropertyDescriptorData.Create(MemberValue, [pfEnumerable])); | |
| ChildScope.DefineLexicalBinding(AEnumDeclaration.Members[I].Name, MemberValue, dtLet); | |
| EntryPair := TGocciaArrayValue.Create; | |
| EntryPair.Elements.Add(TGocciaStringLiteralValue.Create(AEnumDeclaration.Members[I].Name)); | |
| EntryPair.Elements.Add(MemberValue); | |
| EnumEntries.Elements.Add(EntryPair); | |
| end; | |
| EnumValue.Entries := EnumEntries; | |
| InitializeEnumSymbols(EnumValue); | |
| EnumValue.PreventExtensions; | |
| AContext.Scope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet); | |
| Result := EnumValue; | |
| end; | |
| // TC39 proposal-enum | |
| function EvaluateEnumDeclaration(const AEnumDeclaration: TGocciaEnumDeclaration; const AContext: TGocciaEvaluationContext): TGocciaValue; | |
| var | |
| EnumValue: TGocciaEnumValue; | |
| EnumEntries: TGocciaArrayValue; | |
| ChildScope: TGocciaScope; | |
| ChildContext: TGocciaEvaluationContext; | |
| I: Integer; | |
| MemberValue: TGocciaValue; | |
| EntryPair: TGocciaArrayValue; | |
| begin | |
| EnumValue := TGocciaEnumValue.Create(AEnumDeclaration.Name); | |
| EnumEntries := TGocciaArrayValue.Create; | |
| TGocciaGarbageCollector.Instance.AddTempRoot(EnumValue); | |
| TGocciaGarbageCollector.Instance.AddTempRoot(EnumEntries); | |
| ChildScope := AContext.Scope.CreateChild(skBlock); | |
| try | |
| ChildContext := AContext; | |
| ChildContext.Scope := ChildScope; | |
| ChildScope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet); | |
| for I := 0 to Length(AEnumDeclaration.Members) - 1 do | |
| begin | |
| MemberValue := EvaluateExpression(AEnumDeclaration.Members[I].Initializer, ChildContext); | |
| if not ((MemberValue is TGocciaNumberLiteralValue) or | |
| (MemberValue is TGocciaStringLiteralValue) or | |
| (MemberValue is TGocciaSymbolValue)) then | |
| AContext.OnError('Enum member initializer must evaluate to a Number, String, or Symbol value', | |
| AEnumDeclaration.Line, AEnumDeclaration.Column); | |
| EnumValue.DefineProperty(AEnumDeclaration.Members[I].Name, | |
| TGocciaPropertyDescriptorData.Create(MemberValue, [pfEnumerable])); | |
| ChildScope.DefineLexicalBinding(AEnumDeclaration.Members[I].Name, MemberValue, dtLet); | |
| EntryPair := TGocciaArrayValue.Create; | |
| EntryPair.Elements.Add(TGocciaStringLiteralValue.Create(AEnumDeclaration.Members[I].Name)); | |
| EntryPair.Elements.Add(MemberValue); | |
| EnumEntries.Elements.Add(EntryPair); | |
| end; | |
| EnumValue.Entries := EnumEntries; | |
| InitializeEnumSymbols(EnumValue); | |
| EnumValue.PreventExtensions; | |
| AContext.Scope.DefineLexicalBinding(AEnumDeclaration.Name, EnumValue, dtLet); | |
| Result := EnumValue; | |
| finally | |
| ChildScope.Free; | |
| TGocciaGarbageCollector.Instance.RemoveTempRoot(EnumEntries); | |
| TGocciaGarbageCollector.Instance.RemoveTempRoot(EnumValue); | |
| end; | |
| end; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@units/Goccia.Evaluator.pas` around lines 1442 - 1489, EvaluateEnumDeclaration
builds EnumValue and EnumEntries in Pascal-only variables without temp-rooting
and never frees ChildScope; protect temporary GC-visible values by calling
AddTempRoot on EnumValue and EnumEntries (and any EntryPair/MemberValue as
needed) before evaluating members and RemoveTempRoot after assigning EnumValue.
Also ensure ChildScope is freed after use (after
AContext.Scope.DefineLexicalBinding and before returning) so the enum init scope
is released; reference the EvaluateEnumDeclaration function, EnumValue,
EnumEntries, ChildScope, ChildContext, InitializeEnumSymbols and
PreventExtensions when applying these AddTempRoot/RemoveTempRoot and freeing
fixes.
| function TGocciaEnumValue.TypeName: string; | ||
| begin | ||
| Result := FName; | ||
| end; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n units/Goccia.Values.EnumValue.pas | head -80Repository: frostney/GocciaScript
Length of output: 2660
🏁 Script executed:
# Check if Goccia.Constants.TypeNames exists and what constants are available
fd -e pas 'Constants' | grep -i typename
cat -n "units/Goccia.Constants.TypeNames.pas" 2>/dev/null || find . -name "*Constants*" -type f | head -10Repository: frostney/GocciaScript
Length of output: 600
🏁 Script executed:
# Search for TypeName implementations across the codebase
rg -n "function.*TypeName" --type=pasRepository: frostney/GocciaScript
Length of output: 92
🏁 Script executed:
# Search for how TypeName is used (especially in typeof)
rg -n "\.TypeName\b" --type=pas -A 2 -B 2 | head -100Repository: frostney/GocciaScript
Length of output: 92
🏁 Script executed:
# Look for typeof implementation
rg -n "typeof" --type=pas -i -A 3 | head -100Repository: frostney/GocciaScript
Length of output: 92
🏁 Script executed:
# Check TGocciaValue base class to understand TypeName contract
rg -n "class TGocciaValue\|procedure.*TypeName\|function.*TypeName" --type=pas -A 5 | head -150Repository: frostney/GocciaScript
Length of output: 92
🏁 Script executed:
# Find TypeName implementations across value types
rg "function.*TypeName.*:" units/Goccia.Values -A 3Repository: frostney/GocciaScript
Length of output: 124
🏁 Script executed:
# Check TGocciaObjectValue implementation
rg -n "class TGocciaObjectValue\|function TypeName" units/Goccia.Values.ObjectValue.pas | head -30Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Search for typeof operator implementation
rg -n "typeof\|TypeOf\|TypeName" units/Goccia.Evaluator.pas | head -50Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Look at base TGocciaValue class
rg -n "class TGocciaValue\|function TypeName" units/Goccia.Values.Primitives.pas -B 2 -A 5 | head -80Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check how other primitive values implement TypeName
rg -A 3 "function TGoccia.*Value\.TypeName" units/Goccia.Values.Primitives.pasRepository: frostney/GocciaScript
Length of output: 550
🏁 Script executed:
# Check TGocciaObjectValue.TypeName implementation
rg -A 3 "function TGocciaObjectValue\.TypeName" units/Goccia.Values.ObjectValue.pasRepository: frostney/GocciaScript
Length of output: 143
🏁 Script executed:
# Check TGocciaArrayValue.TypeName implementation
rg -A 3 "function TGocciaArrayValue\.TypeName" units/Goccia.Values.ArrayValue.pasRepository: frostney/GocciaScript
Length of output: 142
🏁 Script executed:
# Verify the pattern: search all TypeName implementations
rg -A 2 "function.*TypeName.*string" --glob="units/*.pas" | head -80Repository: frostney/GocciaScript
Length of output: 4375
🏁 Script executed:
# Check if StringObjectValue uses constant or hardcoded 'object'
rg -B 2 -A 2 "function TGocciaStringObjectValue\.TypeName" units/Goccia.Values.StringObjectValue.pasRepository: frostney/GocciaScript
Length of output: 183
🏁 Script executed:
# Verify that FunctionBase also follows the pattern
rg -A 3 "function TGoccia.*FunctionBase.*TypeName\|function.*FunctionValue\.TypeName" units/Goccia.Values.FunctionBase.pasRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check if there's a comment or documentation about TypeName vs TypeOf difference
rg -B 5 "TypeName\|TypeOf" units/Goccia.Values.Primitives.pas | head -80Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Verify how TypeOf differs from TypeName (seems there's both methods)
rg -B 3 -A 5 "function TypeOf.*string" units/Goccia.Values.Primitives.pas | head -60Repository: frostney/GocciaScript
Length of output: 2324
🏁 Script executed:
# Check TGocciaEnumValue for TypeOf implementation
rg -B 3 -A 5 "function.*TypeOf" units/Goccia.Values.EnumValue.pasRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Verify ObjectValue's TypeOf to understand the distinction
rg -B 1 -A 4 "function TGocciaObjectValue\.TypeOf" units/Goccia.Values.ObjectValue.pasRepository: frostney/GocciaScript
Length of output: 143
🏁 Script executed:
# Check if EnumValue has its own TypeOf implementation
cat -n units/Goccia.Values.EnumValue.pas | grep -A 5 "TypeOf"Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check if enums are supposed to be treated specially anywhere
rg -B 3 -A 3 "TGocciaEnumValue\|Enum" units/Goccia.Evaluator.pas | head -80Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Verify what JavaScript semantics say about enum types
rg -B 2 -A 2 "enum" units/Goccia.Values.EnumValue.pasRepository: frostney/GocciaScript
Length of output: 293
🏁 Script executed:
# Double-check: search for any special handling of TypeName for enums
rg "EnumValue\|TGocciaEnumValue" units/ -l | xargs grep -l "typeof\|TypeName" 2>/dev/nullRepository: frostney/GocciaScript
Length of output: 49
🏁 Script executed:
# Verify parent class relationship and check if EnumValue breaks Liskov substitution
rg -B 5 "class TGocciaEnumValue" units/Goccia.Values.EnumValue.pasRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check if there's any special code path that expects EnumValue.TypeName to return the enum name
rg "TypeName" units/ --glob="*.pas" -B 2 -A 2 | grep -A 5 -B 5 "FName\|EnumValue"Repository: frostney/GocciaScript
Length of output: 1349
🏁 Script executed:
# Verify ObjectValue parent implementation once more
cat -n units/Goccia.Values.ObjectValue.pas | grep -B 10 -A 5 "function TGocciaObjectValue.TypeName"Repository: frostney/GocciaScript
Length of output: 462
🏁 Script executed:
# Check if there are tests for EnumValue TypeName
rg -B 5 -A 5 "EnumValue.*TypeName\|TypeName.*Enum" units/ --glob="*.Test.pas"Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check ClassValue.TypeName to see if it follows a different pattern
rg -B 2 -A 5 "function TGocciaClassValue\.TypeName" units/Goccia.Values.ClassValue.pasRepository: frostney/GocciaScript
Length of output: 202
🏁 Script executed:
# Verify if hardcoded 'object' strings exist elsewhere and whether they should be constants
rg "Result := 'object'" units/ --glob="*.pas" -B 2 -A 1Repository: frostney/GocciaScript
Length of output: 1021
TypeName should return OBJECT_TYPE_NAME constant instead of enum name.
As TGocciaEnumValue extends TGocciaObjectValue, returning FName breaks the type contract—enums must report as objects like all other object-type values. JavaScript semantics require typeof enum to yield "object", not the enum name. Additionally, per coding guidelines, use the OBJECT_TYPE_NAME constant from Goccia.Constants.TypeNames instead of hardcoded strings.
Suggested fix
uses
Goccia.Arguments.Collection,
+ Goccia.Constants.TypeNames,
Goccia.Values.ArrayValue,
Goccia.Values.ObjectValue,
Goccia.Values.Primitives;
@@
function TGocciaEnumValue.TypeName: string;
begin
- Result := FName;
+ Result := OBJECT_TYPE_NAME;
end;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function TGocciaEnumValue.TypeName: string; | |
| begin | |
| Result := FName; | |
| end; | |
| function TGocciaEnumValue.TypeName: string; | |
| begin | |
| Result := OBJECT_TYPE_NAME; | |
| end; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@units/Goccia.Values.EnumValue.pas` around lines 53 - 56,
TGocciaEnumValue.TypeName currently returns FName which violates the object-type
contract; update the method TGocciaEnumValue.TypeName to return the
OBJECT_TYPE_NAME constant from Goccia.Constants.TypeNames (matching other
TGocciaObjectValue-derived types) so enum values report as the `"object"` type
rather than the enum name.
| // TC39 proposal-enum: Symbol.iterator yields [key, value] entries in declaration order | ||
| function TGocciaEnumValue.EnumSymbolIterator(const AArgs: TGocciaArgumentsCollection; | ||
| const AThisValue: TGocciaValue): TGocciaValue; | ||
| begin | ||
| Result := TGocciaArrayIteratorValue.Create(FEntries, akValues); | ||
| end; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n units/Goccia.Values.EnumValue.pas | sed -n '58,63p'Repository: frostney/GocciaScript
Length of output: 406
🏁 Script executed:
# Check the complete EnumSymbolIterator implementation
rg -n -A 10 'function TGocciaEnumValue.EnumSymbolIterator' units/Goccia.Values.EnumValue.pasRepository: frostney/GocciaScript
Length of output: 494
🏁 Script executed:
# Check how native functions are invoked with AThisValue
rg -n 'InvokeCallable\|CallNative' units/Goccia.Values.NativeFunction.pas | head -20Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check the Entries property definition
rg -n 'FEntries\|property.*Entries' units/Goccia.Values.EnumValue.pasRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check similar iterator implementations in other value types
rg -n 'EnumSymbolIterator\|TGocciaArrayIteratorValue.Create' units/ --type pas | head -20Repository: frostney/GocciaScript
Length of output: 92
🏁 Script executed:
# Look for field declarations in EnumValue
rg -n 'FEntries' units/Goccia.Values.EnumValue.pas -A 2 -B 2Repository: frostney/GocciaScript
Length of output: 796
🏁 Script executed:
# Check how symbol iterators are invoked - look in evaluator
rg -n 'Symbol.iterator\|GetIteratorFromValue' units/ -lRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Look for native function invocation pattern
fd -e pas | xargs grep -l 'InvokeCallable\|CallFunction' | head -5Repository: frostney/GocciaScript
Length of output: 248
🏁 Script executed:
# Check error handling patterns in similar methods
rg -n 'ThrowTypeError\|TypeErrorBroadcast' units/Goccia.Values.EnumValue.pasRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Look for how iterators are typically called with AThisValue binding
rg -n 'TGocciaArrayIteratorValue.Create' units/ -B 5 -A 2 | head -40Repository: frostney/GocciaScript
Length of output: 2641
🏁 Script executed:
# Check error handling in EnumValue
rg -n 'ThrowError\|ThrowTypeError' units/Goccia.Values.EnumValue.pasRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check what error method is used in ErrorHelper or similar
rg -n 'ThrowTypeError' units/Goccia.Values.ErrorHelper.pasRepository: frostney/GocciaScript
Length of output: 170
🏁 Script executed:
# Check how other value types handle this in iterator context
rg -n 'not.*is TGoccia.*then.*Throw' units/Goccia.Values.ArrayValue.pas | head -5Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check exact error call in Array.values
rg -n -A 2 'Array.values called on non-array' units/Goccia.Values.ArrayValue.pasRepository: frostney/GocciaScript
Length of output: 224
🏁 Script executed:
# Check the import/uses in ArrayValue to see how it handles errors
rg -n 'uses' units/Goccia.Values.ArrayValue.pas | head -1Repository: frostney/GocciaScript
Length of output: 71
🏁 Script executed:
# Check if EnumValue imports ErrorHelper
rg -n 'uses' units/Goccia.Values.EnumValue.pasRepository: frostney/GocciaScript
Length of output: 79
🏁 Script executed:
# Get full uses section of EnumValue
rg -n -A 10 '^uses' units/Goccia.Values.EnumValue.pas | head -20Repository: frostney/GocciaScript
Length of output: 565
🏁 Script executed:
# Get full uses section of ArrayValue
rg -n -A 15 '^uses' units/Goccia.Values.ArrayValue.pas | head -25Repository: frostney/GocciaScript
Length of output: 851
🏁 Script executed:
# Check what ThrowError is - is it from a base class or global
rg -n 'procedure ThrowError' units/ --type pas | head -5Repository: frostney/GocciaScript
Length of output: 92
🏁 Script executed:
# Check Goccia.Error to see ThrowError definition
rg -n 'procedure ThrowError' units/Goccia.Error.pasRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check what TGocciaObjectValue provides - ThrowError might be a method
rg -n 'procedure ThrowError' units/Goccia.Values.ObjectValue.pasRepository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Look for ThrowError in base classes
fd -e pas | xargs grep -l 'procedure ThrowError' | head -10Repository: frostney/GocciaScript
Length of output: 188
🏁 Script executed:
# Check ErrorHelper for ThrowError definition
rg -n 'procedure ThrowError\|procedure ThrowTypeError' units/Goccia.Values.ErrorHelper.pas -A 2Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Check if ArrayValue imports ErrorHelper
rg -n 'ErrorHelper' units/Goccia.Values.ArrayValue.pasRepository: frostney/GocciaScript
Length of output: 97
🏁 Script executed:
# Check the full uses section of ArrayValue implementation
sed -n '107,130p' units/Goccia.Values.ArrayValue.pasRepository: frostney/GocciaScript
Length of output: 610
🏁 Script executed:
# Check what's exported from ErrorHelper
rg -n 'procedure\|function' units/Goccia.Values.ErrorHelper.pas | head -20Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Verify that EnumValue does not currently import ErrorHelper
cat -n units/Goccia.Values.EnumValue.pas | sed -n '7,36p'Repository: frostney/GocciaScript
Length of output: 1111
🏁 Script executed:
# Check the exact signature and behavior of ThrowError in ErrorHelper
cat units/Goccia.Values.ErrorHelper.pasRepository: frostney/GocciaScript
Length of output: 2333
🏁 Script executed:
# Verify the pattern by checking another method that uses AThisValue
rg -n -B 5 -A 10 'not.*AThisValue.*is.*Goccia' units/Goccia.Values.ArrayValue.pas | head -30Repository: frostney/GocciaScript
Length of output: 1114
Use AThisValue as the iterator receiver instead of Self.
EnumSymbolIterator currently uses the method host's FEntries instead of the call receiver. Detached calls (or borrowed iterators) will iterate the wrong enum, violating the iterator protocol. This should either iterate the correct enum or throw if this isn't an enum.
The pattern is established in Array.values() and similar Array methods, which check AThisValue is TGocciaArrayValue before proceeding. The fix requires adding Goccia.Values.ErrorHelper to the implementation uses clause and wrapping the iterator creation with a type check.
Note: Use ThrowError (not ThrowTypeError) for consistency with existing Array method patterns for "called on non-X" errors.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@units/Goccia.Values.EnumValue.pas` around lines 58 - 63, EnumSymbolIterator
currently uses Self.FEntries causing detached/borrowed iterator calls to iterate
the wrong enum; modify TGocciaEnumValue.EnumSymbolIterator to use the call
receiver AThisValue: add Goccia.Values.ErrorHelper to the implementation uses
clause, check if AThisValue is TGocciaEnumValue and if so create the iterator
with (AThisValue as TGocciaEnumValue).FEntries and akValues, otherwise call
ThrowError with the "called on non-enum" message (use ThrowError, not
ThrowTypeError) to match Array.values() patterns.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/embedding.md`:
- Line 208: Update the docs table entry for ggConsole to list the full set of
exported console methods to match the implementation in
Goccia.Builtins.Console.pas: replace the abbreviated "etc." with the missing
methods so the list reads: log, warn, error, info, debug, dir, assert, count,
countReset, time, timeEnd, timeLog, clear, group, groupEnd, trace, table; ensure
ggConsole and reference to Goccia.Builtins.Console.pas are used to locate the
implementation if needed.
---
Duplicate comments:
In `@units/Goccia.Evaluator.pas`:
- Around line 1442-1443: Add the required ES-spec-style annotation comment above
the evaluator function for the TC39 enum proposal: insert a line like "// TC39
proposal-enum §2.1 EvaluateEnumDeclaration(AEnumDeclaration, AContext)"
immediately above the function declaration for EvaluateEnumDeclaration so the
evaluator function is annotated in the project's required format.
- Around line 1442-1493: EvaluateEnumDeclaration currently risks GC and leaks:
temp-root EnumValue before any EvaluateExpression calls (use
TGocciaGarbageCollector.Instance.AddTempRoot(EnumValue) and RemoveTempRoot in
finally), temp-root each EntryPair while constructing it (AddTempRoot before
populating and RemoveTempRoot after adding to EnumEntries), and free ChildScope
(call ChildScope.Free in the finally block after using it). Update the procedure
to AddTempRoot(EnumValue) right after creating EnumValue, Add/RemoveTempRoot
around each EntryPair creation, and ensure ChildScope.Free is called in the same
finally where you RemoveTempRoot(EnumEntries)/EnumValue to avoid leaks and
premature collection.
| | Flag | Provides | Notes | | ||
| |------|----------|-------| | ||
| | `ggConsole` | `console.log` | Output to stdout | | ||
| | `ggConsole` | `console.*` | `log`, `warn`, `error`, `info`, `debug`, `dir`, `assert`, `count`, `time`, etc. | |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find all Pascal files and search for ggConsole registration/implementation
find . -name "*.pas" -o -name "*.dpr" | head -20Repository: frostney/GocciaScript
Length of output: 657
🏁 Script executed:
# Search for ggConsole definition and console method implementations
rg -n "ggConsole" --type=pascal -A 5 -B 5Repository: frostney/GocciaScript
Length of output: 2031
🏁 Script executed:
# Also search more broadly for console object and method definitions
rg -n "console\." --type=pascal | head -30Repository: frostney/GocciaScript
Length of output: 47
🏁 Script executed:
# Look for where console methods are registered (log, warn, error, etc.)
rg -n "(TMethod|procedure|function).*(log|warn|error|info|debug|dir|assert|count|time)" --type=pascal -iRepository: frostney/GocciaScript
Length of output: 50377
🏁 Script executed:
# Get the actual Console implementation file to list registered methods
cat -n units/Goccia.Builtins.Console.pas | head -150Repository: frostney/GocciaScript
Length of output: 7519
🏁 Script executed:
# Search for RegisterNativeMethod calls in Console.pas to see all registered methods
rg -n "RegisterNativeMethod" units/Goccia.Builtins.Console.pas -A 1 | head -60Repository: frostney/GocciaScript
Length of output: 1846
🏁 Script executed:
# Check the context around line 208 in embedding.md to see the full table
sed -n '200,230p' docs/embedding.mdRepository: frostney/GocciaScript
Length of output: 1610
Expand the console.* method list to match the implementation.
The listed methods (log, warn, error, info, debug, dir, assert, count, time, etc.) are accurate but incomplete. The actual implementation in Goccia.Builtins.Console.pas exports 17 methods: log, warn, error, info, debug, dir, assert, count, countReset, time, timeEnd, timeLog, clear, group, groupEnd, trace, and table. Update the table to include countReset, timeEnd, timeLog, clear, group, groupEnd, trace, and table instead of relying on "etc."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/embedding.md` at line 208, Update the docs table entry for ggConsole to
list the full set of exported console methods to match the implementation in
Goccia.Builtins.Console.pas: replace the abbreviated "etc." with the missing
methods so the list reads: log, warn, error, info, debug, dir, assert, count,
countReset, time, timeEnd, timeLog, clear, group, groupEnd, trace, table; ensure
ggConsole and reference to Goccia.Builtins.Console.pas are used to locate the
implementation if needed.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests