Conversation
frostney
commented
Apr 11, 2026
- Parse, evaluate, and compile tagged templates
- Add String.raw and raw template coverage
- Update docs, benchmarks, and language restrictions
- Parse, evaluate, and compile tagged templates - Add String.raw and raw template coverage - Update docs, benchmarks, and language restrictions
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds ES2015 tagged template literal parsing, AST, compilation, VM evaluation, and a Changes
Sequence Diagram(s)sequenceDiagram
participant Source as Source
participant Lexer as Lexer
participant Parser as Parser
participant AST as AST
participant Compiler as Compiler
participant Bytecode as Bytecode
participant VM as VM
participant Evaluator as Evaluator
participant Tag as TagFunction
Source->>Lexer: encounter tagged template `tag\`...\``
Lexer-->>Parser: token (cooked#1raw)
Parser->>AST: TGocciaTaggedTemplateExpression(tag, cooked[], raw[], exprs)
AST->>Compiler: CompileTaggedTemplate(...)
Compiler->>Compiler: build cooked/raw arrays, define non-enumerable `.raw`, freeze
Compiler->>Bytecode: emit OP_CALL or OP_CALL_METHOD + args
Bytecode-->>VM: execute emitted code
VM->>Evaluator: evaluate tagged template runtime
Evaluator->>Evaluator: create/freeze template object, evaluate substitutions
Evaluator->>Tag: call(tag, templateObj, ...subs)
Tag-->>Evaluator: return value
Evaluator-->>VM: final result
sequenceDiagram
participant Code as Code
participant Parser as Parser
participant Evaluator as Evaluator
participant StringRaw as String.raw
participant Result as Result
Code->>Parser: String.raw`\n\t${x}`
Parser-->>Evaluator: tagged-template node (String.raw)
Evaluator->>Evaluator: build cooked & raw arrays
Note over Evaluator: raw = ["\\n\\t"]\ncooked = [newline, tab]
Evaluator->>StringRaw: call(String.raw, templateObj, x)
StringRaw->>StringRaw: interleave templateObj.raw with args
StringRaw-->>Result: string preserving raw escapes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (2)
units/Goccia.Lexer.pas (1)
472-475: Add the function-level ES annotation aboveScanTemplate.The inline step comment is useful, but the repo rule also asks for the
// ES2026 §...annotation immediately above the function body itself.As per coding guidelines "When implementing ECMAScript-specified behavior, annotate each function or method with a comment referencing the relevant spec section using the format
// ESYYYY §X.Y.Z SpecMethodName(specParams)whereYYYYis the current edition year. Place the annotation immediately above the function body in theimplementationsection."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@units/Goccia.Lexer.pas` around lines 472 - 475, Add the required ECMAScript spec annotation immediately above the implementation of procedure TGocciaLexer.ScanTemplate: insert a comment in the format "// ES2026 §X.Y.Z ScanTemplate()" (replace X.Y.Z with the correct spec section) directly above the "procedure TGocciaLexer.ScanTemplate;" line in the implementation section so it sits just above the function body, matching the repo guideline format.units/Goccia.Compiler.Expressions.pas (1)
1713-1715: Use the shared property-name constant forfreeze.Line 1714 hardcodes a runtime property key even though this unit already depends on
Goccia.Constants.PropertyNames. Please route this through the shared constant instead of introducing another string literal here.As per coding guidelines, "Use runtime constants from
Goccia.Constants.PropertyNames,Goccia.Constants.TypeNames,Goccia.Constants.ErrorNames,Goccia.Constants.ConstructorNames, andGoccia.Constants.SymbolNamesinstead of hardcoded string literals."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@units/Goccia.Compiler.Expressions.pas` around lines 1713 - 1715, Replace the hardcoded 'freeze' literal passed to ACtx.Template.AddConstantString with the shared property-name constant from Goccia.Constants.PropertyNames (e.g., PropertyNames.Freeze) so the code uses the centralized runtime constant; update the call that sets FreezeIdx to use that constant instead of the string literal and keep the surrounding checks (ObjectIdx/FreezeIdx bounds) unchanged.
🤖 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.Compiler.Expressions.pas`:
- Around line 1775-1803: The current code builds fresh cooked/raw arrays at
runtime with OP_NEW_ARRAY and sets .raw via OP_SET_PROP_CONST (within
EmitInstruction/EncodeABC and EmitObjectFreeze using TempReg/Arg0Reg and
ACtx.Template.AddConstantString), but tagged-template semantics require a single
frozen template object per call site that reuses identity; change this to emit a
compile-time template object or lookup via a GetTemplateObject-style mechanism
instead of creating arrays each execution, store the cooked array (Arg0Reg) as
the per-call-site constant/template object, attach the raw array as a
non-enumerable/internal slot (not with OP_SET_PROP_CONST) and ensure both arrays
are frozen (use EmitObjectFreeze semantics) and inserted into the
constant/template pool so the same object identity is returned on every call.
- Around line 1741-1769: The tagged-template callee path only special-cases
TGocciaMemberExpression, so it mis-handles super.foo`...` and private-name
calls; update the block that sets IsMethodCall / handles MemberExpr to mirror
CompileCall's callee-shape handling by also recognizing TGocciaSuperExpression
and the private-identifier node (e.g., TGocciaPrivateIdentifier or the project’s
private-name class), allocating ObjReg and BaseReg the same way, compiling the
appropriate callee parts (object/super target and property expression or
constant name) and emitting the same opcodes/emit-paths CompileCall uses for
computed vs constant properties so the receiver is passed the same way for
tagged templates as for ordinary calls.
- Around line 1742-1743: The code computes ArgCount := 1 +
AExpr.Expressions.Count and later casts it to UInt8 without checking bounds,
which can overflow for >254 substitutions; add a guard before the cast in the
tagged-template paths (the assignment at ArgCount := 1 + AExpr.Expressions.Count
and the similar block at 1813-1816) to validate ArgCount <= 255 and handle
violations by emitting a compilation error/exception or returning failure (same
behavior as CompileCall when rejecting oversized argument lists) instead of
performing the unchecked UInt8(ArgCount) cast.
In `@units/Goccia.Evaluator.pas`:
- Around line 2927-2945: GetTemplateObject currently rebuilds RawArray and
CookedArray on every call and uses AssignProperty for PROP_RAW which makes .raw
enumerable/writable/configurable; change TGocciaTaggedTemplateExpression to
cache the built template object in a FTemplateObject field so GetTemplateObject
returns the same frozen object on repeated calls, and replace the
AssignProperty(PROP_RAW, RawArray) call with DefineProperty using a
non-enumerable, non-writable, non-configurable descriptor (clear pfEnumerable,
pfWritable, pfConfigurable flags) before freezing CookedArray; apply the same
cache-and-DefineProperty fixes in the tagged-template bytecode generation path
so both interpreter GetTemplateObject and the compiler-emitted path produce
identical, memoized template objects.
In `@units/Goccia.Lexer.pas`:
- Around line 504-533: The lexer currently eagerly throws on malformed \u/\x
escapes inside ProcessEscapeSequence, which prevents representing
tagged-template raw segments; change ProcessEscapeSequence to not raise on
malformed escapes but instead return a boolean or status (e.g., ResultValid:
Boolean) and consume the same source range so RawSB/RawStart/FCurrent/FSource
still capture the raw text; in the template-segment handling (the backslash
branch that appends to SB/RawSB) track a per-segment flag (e.g.,
SegmentEscapeValid) set from ProcessEscapeSequence's result and only append to
SB the cooked characters when valid, otherwise leave cooked unset and ensure
RawSB contains the exact source; after finishing a template literal, if the
template is untagged then validate the segment flags and raise syntax errors for
invalid escapes (throwing as before), but if tagged, preserve cooked as
undefined and defer errors to the evaluator.
In `@units/Goccia.Parser.pas`:
- Around line 949-961: The code currently extracts ParsedExpr from ProgramNode
but then frees ProgramNode, leaving ParsedExpr pointing to freed memory; fix by
either parsing the interpolation as an expression directly (add/use a
ParseExpression method on TGocciaParser/ParseUnchecked) or explicitly transfer
ownership of the node out of ProgramNode before freeing it: after obtaining
ParsedExpr from TGocciaExpressionStatement(ProgramNode.Body[0]).Expression,
detach the statement/expression from ProgramNode (e.g. use
ProgramNode.Body.Extract(ProgramNode.Body[0]) or set ProgramNode.Body[0] := nil
/ remove the item so it is not freed) and only then call
Expressions.Add(ParsedExpr) and ProgramNode.Free so the AST node ownership is
correctly transferred.
- Around line 890-1017: The scanner must not treat synthetic leading backtick or
cooked escapes as real interpolation boundaries: before splitting, drop the
synthetic leading backtick from CookedFull/RawFull if present, and detect ${...}
boundaries based on the raw content (RawFull) or by ensuring the '${' is not
escaped (i.e. the previous character is not a backslash) when iterating the
loops that build CookedStrings/RawStrings and Expressions; update the while
loops that check (CookedFull[I] = '$') and (RawFull[I] = '$') to also verify the
preceding character isn't '\' (or use RawFull for the boundary test) so
sequences like \${x} are treated as literal text and the first segment does not
retain a synthetic '`' (affecting TGocciaTaggedTemplateExpression creation).
---
Nitpick comments:
In `@units/Goccia.Compiler.Expressions.pas`:
- Around line 1713-1715: Replace the hardcoded 'freeze' literal passed to
ACtx.Template.AddConstantString with the shared property-name constant from
Goccia.Constants.PropertyNames (e.g., PropertyNames.Freeze) so the code uses the
centralized runtime constant; update the call that sets FreezeIdx to use that
constant instead of the string literal and keep the surrounding checks
(ObjectIdx/FreezeIdx bounds) unchanged.
In `@units/Goccia.Lexer.pas`:
- Around line 472-475: Add the required ECMAScript spec annotation immediately
above the implementation of procedure TGocciaLexer.ScanTemplate: insert a
comment in the format "// ES2026 §X.Y.Z ScanTemplate()" (replace X.Y.Z with the
correct spec section) directly above the "procedure TGocciaLexer.ScanTemplate;"
line in the implementation section so it sits just above the function body,
matching the repo guideline format.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 82a2f000-6259-4c6e-9577-35310eb53c0a
📒 Files selected for processing (15)
benchmarks/strings.jsdocs/built-ins.mddocs/bytecode-vm.mddocs/language-restrictions.mdtests/built-ins/String/raw.jstests/language/expressions/string/tagged-templates.jsunits/Goccia.AST.Expressions.pasunits/Goccia.Builtins.GlobalString.pasunits/Goccia.Compiler.Expressions.pasunits/Goccia.Compiler.pasunits/Goccia.Constants.PropertyNames.pasunits/Goccia.Evaluator.pasunits/Goccia.Lexer.pasunits/Goccia.Parser.pasunits/Goccia.VM.pas
Benchmark Results364 benchmarks Interpreted: 🟢 63 improved · 🔴 112 regressed · 🆕 8 new · 181 unchanged · avg -0.9% arraybuffer.js — Interp: 🟢 2, 🔴 2, 10 unch. · avg -0.0% · Bytecode: 🔴 14 · avg -11.0%
arrays.js — Interp: 🟢 5, 🔴 2, 12 unch. · avg +0.6% · Bytecode: 🔴 19 · avg -10.3%
async-await.js — Interp: 🔴 1, 5 unch. · avg +0.1% · Bytecode: 🔴 6 · avg -11.4%
base64.js — Interp: 🟢 3, 🔴 1, 6 unch. · avg +0.3% · Bytecode: 🔴 10 · avg -9.3%
classes.js — Interp: 🟢 1, 🔴 6, 24 unch. · avg -0.3% · Bytecode: 🟢 1, 🔴 18, 12 unch. · avg -6.6%
closures.js — Interp: 🔴 9, 2 unch. · avg -2.6% · Bytecode: 🔴 8, 3 unch. · avg -4.7%
collections.js — Interp: 🟢 2, 🔴 6, 4 unch. · avg -0.9% · Bytecode: 🟢 2, 🔴 9, 1 unch. · avg -3.8%
destructuring.js — Interp: 🟢 4, 🔴 4, 14 unch. · avg -0.0% · Bytecode: 🔴 19, 3 unch. · avg -5.8%
fibonacci.js — Interp: 🟢 2, 🔴 4, 2 unch. · avg -0.1% · Bytecode: 🔴 7, 1 unch. · avg -9.2%
float16array.js — Interp: 🟢 12, 🔴 9, 11 unch. · avg -4.6% · Bytecode: 🔴 31, 1 unch. · avg -13.2%
for-of.js — Interp: 🟢 1, 6 unch. · avg +0.9% · Bytecode: 🔴 7 · avg -7.5%
helpers/bench-module.js — Interp: 0 · Bytecode: 0
iterators.js — Interp: 🟢 14, 🔴 8, 20 unch. · avg +0.7% · Bytecode: 🔴 42 · avg -11.5%
json.js — Interp: 🔴 1, 19 unch. · avg -0.3% · Bytecode: 🔴 20 · avg -10.6%
jsx.jsx — Interp: 🟢 11, 10 unch. · avg +1.9% · Bytecode: 🔴 21 · avg -9.9%
modules.js — Interp: 🔴 1, 8 unch. · avg -1.0% · Bytecode: 🔴 9 · avg -10.0%
numbers.js — Interp: 🔴 6, 5 unch. · avg -2.5% · Bytecode: 🔴 11 · avg -14.0%
objects.js — Interp: 🟢 2, 🔴 3, 2 unch. · avg -0.6% · Bytecode: 🔴 7 · avg -10.1%
promises.js — Interp: 🔴 10, 2 unch. · avg -2.8% · Bytecode: 🔴 12 · avg -11.3%
regexp.js — Interp: 🔴 8, 3 unch. · avg -2.5% · Bytecode: 🔴 11 · avg -8.7%
strings.js — Interp: 🔴 10, 🆕 8, 1 unch. · avg -4.5% · Bytecode: 🔴 11, 🆕 8 · avg -9.8%
typed-arrays.js — Interp: 🟢 2, 🔴 11, 9 unch. · avg -1.1% · Bytecode: 🔴 22 · avg -12.5%
uint8array-encoding.js — Interp: 🟢 2, 🔴 10, 6 unch. · avg -1.9% · Bytecode: 🟢 4, 🔴 13, 1 unch. · avg -5.9%
Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context. |
Suite Timing
Measured on ubuntu-latest x64. |
- Guard tagged template compiler against >254 substitutions overflowing UInt8
argument count, consistent with CompileCall's existing guard
- Define .raw on the template object as non-enumerable/non-writable/non-configurable
per ES2026 §13.2.8.3 step 8, replacing AssignProperty (which defaulted to
enumerable) with DefineProperty([], ...) in the interpreter path
- Add EmitDefineNonEnumerableProperty helper in the compiler that calls
Object.defineProperty({value: rawArray}) — omitting enumerable/writable/configurable
defaults them all to false per spec — replacing OP_SET_PROP_CONST for the .raw
attachment in the bytecode path
- Add test asserting .raw is non-enumerable, non-writable, non-configurable
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (2)
units/Goccia.Compiler.Expressions.pas (2)
1701-1748: Consider extracting'defineProperty'to a constant.The string literal
'defineProperty'at line 1718 is hardcoded. For consistency with the project conventions, consider adding a constant (e.g.,PROP_DEFINE_PROPERTY) toGoccia.Constants.PropertyNamesand using it here.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@units/Goccia.Compiler.Expressions.pas` around lines 1701 - 1748, The hardcoded string 'defineProperty' in EmitDefineNonEnumerableProperty should be moved to a named constant to follow project conventions; add a constant (e.g., PROP_DEFINE_PROPERTY) to Goccia.Constants.PropertyNames and replace the inline literal used to initialize DefPropIdx (the AddConstantString call) with that constant, ensuring EmitDefineNonEnumerableProperty, DefPropIdx and any other callers use the new constant name instead of the literal.
1750-1778: Consider extracting'freeze'to a constant.Similar to the above, the string literal
'freeze'at line 1763 could be extracted to a constant for consistency with the guideline to use runtime constants fromGoccia.Constants.PropertyNamesinstead of hardcoded string literals.As per coding guidelines: "Use runtime constants from
Goccia.Constants.PropertyNames... instead of hardcoded string literals."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@units/Goccia.Compiler.Expressions.pas` around lines 1750 - 1778, Extract the hardcoded 'freeze' string in EmitObjectFreeze and use the runtime constant from Goccia.Constants.PropertyNames instead: replace ACtx.Template.AddConstantString('freeze') with ACtx.Template.AddConstantString(<PropertyNames.FreezeConstant>) (use the appropriate identifier from Goccia.Constants.PropertyNames), and update the FreezeIdx usage accordingly so the code references the constant symbol rather than a literal; keep the existing ObjectIdx/FreezeIdx overflow check and subsequent EmitInstruction calls intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@units/Goccia.Compiler.Expressions.pas`:
- Around line 1701-1748: The hardcoded string 'defineProperty' in
EmitDefineNonEnumerableProperty should be moved to a named constant to follow
project conventions; add a constant (e.g., PROP_DEFINE_PROPERTY) to
Goccia.Constants.PropertyNames and replace the inline literal used to initialize
DefPropIdx (the AddConstantString call) with that constant, ensuring
EmitDefineNonEnumerableProperty, DefPropIdx and any other callers use the new
constant name instead of the literal.
- Around line 1750-1778: Extract the hardcoded 'freeze' string in
EmitObjectFreeze and use the runtime constant from
Goccia.Constants.PropertyNames instead: replace
ACtx.Template.AddConstantString('freeze') with
ACtx.Template.AddConstantString(<PropertyNames.FreezeConstant>) (use the
appropriate identifier from Goccia.Constants.PropertyNames), and update the
FreezeIdx usage accordingly so the code references the constant symbol rather
than a literal; keep the existing ObjectIdx/FreezeIdx overflow check and
subsequent EmitInstruction calls intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d05a9831-17fc-499d-88fb-8269ed8335da
📒 Files selected for processing (3)
tests/language/expressions/string/tagged-templates.jsunits/Goccia.Compiler.Expressions.pasunits/Goccia.Evaluator.pas
🚧 Files skipped from review as they are similar to previous changes (1)
- units/Goccia.Evaluator.pas
…ants Add PROP_FREEZE = 'freeze' to Goccia.Constants.PropertyNames and use the existing PROP_DEFINE_PROPERTY constant (already present in the Proxy trap section) in EmitDefineNonEnumerableProperty and EmitObjectFreeze instead of inline string literals, per project convention. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (2)
units/Goccia.Compiler.Expressions.pas (2)
1795-1819: Consider extracting the shared callee/call lowering withCompileCall.
CompileTaggedTemplatenow carries its own copy of the member-vs-plain callee setup and finalOP_CALL/OP_CALL_METHODemission. Pulling that into a small helper would reduce drift the next time call semantics change in one path but not the other.Also applies to: 1860-1864
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@units/Goccia.Compiler.Expressions.pas` around lines 1795 - 1819, The callee setup and call emission logic duplicated in CompileTaggedTemplate (the IsMethodCall branch handling TGocciaMemberExpression, AllocateRegister, ACtx.CompileExpression, emitting OP_ARRAY_GET or OP_GET_PROP_CONST with Template.AddConstantString, and the final OP_CALL / OP_CALL_METHOD emission) should be extracted into a helper CompileCall; implement CompileCall to take the expression/tag and return the resolved callee/base/obj registers and the appropriate call opcode, reuse it from CompileTaggedTemplate and the other location (lines ~1860-1864) to replace the duplicated code, and ensure existing EmitInstruction and constant-pool overflow handling are preserved inside the helper.
1701-1705: Use the repo’s spec-annotation format on these new tagged-template routines.These comments reference the spec, but they do not use the required
// ESYYYY §X.Y.Z SpecMethodName(specParams)form. Please normalize the annotations aboveEmitDefineNonEnumerableProperty,EmitObjectFreeze, andCompileTaggedTemplateso this path stays consistent with the rest of the spec-annotated compiler code.As per coding guidelines, "When implementing ECMAScript-specified behavior, annotate each function or method with a comment referencing the relevant spec section using the format
// ESYYYY §X.Y.Z SpecMethodName(specParams)... Place the annotation immediately above the function body in theimplementationsection."Also applies to: 1750-1753, 1780-1781
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@units/Goccia.Compiler.Expressions.pas` around lines 1701 - 1705, Replace the free-form spec comments above EmitDefineNonEnumerableProperty, EmitObjectFreeze, and CompileTaggedTemplate (and the duplicate spots noted around the other two comment blocks) with the repository's standardized spec-annotation line immediately above each function body in the implementation section, using the format "// ESYYYY §X.Y.Z SpecMethodName(specParams)"; e.g. for EmitDefineNonEnumerableProperty use the ES2026 reference already mentioned (// ES2026 §13.2.8.3 DefineProperty(AObjReg, propName, descriptor)) and create analogous ES-prefixed annotations for EmitObjectFreeze and CompileTaggedTemplate so each routine has a single-line spec annotation directly above its implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@units/Goccia.Compiler.Expressions.pas`:
- Around line 1795-1819: The callee setup and call emission logic duplicated in
CompileTaggedTemplate (the IsMethodCall branch handling TGocciaMemberExpression,
AllocateRegister, ACtx.CompileExpression, emitting OP_ARRAY_GET or
OP_GET_PROP_CONST with Template.AddConstantString, and the final OP_CALL /
OP_CALL_METHOD emission) should be extracted into a helper CompileCall;
implement CompileCall to take the expression/tag and return the resolved
callee/base/obj registers and the appropriate call opcode, reuse it from
CompileTaggedTemplate and the other location (lines ~1860-1864) to replace the
duplicated code, and ensure existing EmitInstruction and constant-pool overflow
handling are preserved inside the helper.
- Around line 1701-1705: Replace the free-form spec comments above
EmitDefineNonEnumerableProperty, EmitObjectFreeze, and CompileTaggedTemplate
(and the duplicate spots noted around the other two comment blocks) with the
repository's standardized spec-annotation line immediately above each function
body in the implementation section, using the format "// ESYYYY §X.Y.Z
SpecMethodName(specParams)"; e.g. for EmitDefineNonEnumerableProperty use the
ES2026 reference already mentioned (// ES2026 §13.2.8.3 DefineProperty(AObjReg,
propName, descriptor)) and create analogous ES-prefixed annotations for
EmitObjectFreeze and CompileTaggedTemplate so each routine has a single-line
spec annotation directly above its implementation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e7a8338e-5b87-434c-9377-58f2c0d2661e
📒 Files selected for processing (2)
units/Goccia.Compiler.Expressions.pasunits/Goccia.Constants.PropertyNames.pas
✅ Files skipped from review due to trivial changes (1)
- units/Goccia.Constants.PropertyNames.pas
…te helpers - Extract CompileTagCalleeRegisters from CompileTaggedTemplate to isolate the member-expression vs regular-expression callee shape detection and register allocation, mirroring CompileCall's non-super member branch - Replace free-form comments on EmitDefineNonEnumerableProperty, EmitObjectFreeze, and CompileTaggedTemplate with standardized ES2026 §X.Y.Z spec annotations per project convention Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>