Tweak port update from Claude.ai
gettimothy via Squeak-dev <[email protected]>
| Newsgroups | gmane.comp.lang.smalltalk.squeak.general |
|---|---|
| Message-ID | <[email protected]> |
# Subject: Tweak/OpenCobalt port to Squeak 6.1 — CCompiler Facade milestone **To:** mailto:[email protected] **Date:** Monday, May 25, 2026 --- Hello Squeakers, I wanted to share a meaningful milestone in the ongoing effort to port Tweak/OpenCobalt to 64-bit Squeak 6.1 alpha. --- ## Background Tweak is the constraint-based, player/costume/script UI framework that grew out of the Squeak Etoys lineage and formed the foundation of OpenCobalt. The codebase dates from the early 2000s and was designed around a parallel compiler pipeline — CCompiler, CParser, CEncoder, and a full set of C-prefixed AST node classes (CMessageNode, CBlockNode, etc.) rooted at CParseNode. The "C" stands for Croquet, not C-the-language. The challenge: none of that parallel pipeline is compatible with modern 64-bit Squeak's bytecode format (SistaV1), slot layout, or compiler architecture. --- ## The Architectural Pivot Eliot Miranda suggested the right approach: rather than porting the parallel C-node pipeline forward, make **CCompiler a Facade over the standard Squeak compiler**. CCompiler becomes a thin subclass of Compiler. CParser is wired to produce standard Squeak AST nodes (MethodNode, BlockNode, MessageNode, etc.) that the standard EncoderForSistaV1 can handle. The C-node class hierarchy remains in the image as (effectively) dead code — no need to delete it, no need to port it. This is architecturally clean and means all future maintenance rides on the standard Squeak compiler infrastructure rather than a parallel system nobody remembers how to maintain. --- ## What We Fixed This Session Getting `CCompiler superclass: Compiler` to actually work required untangling a chain of issues: 1. **`CCompiler class >> initialize`** — was `self recompileAll`. Neutralized before changing superclass (would have been catastrophic). 2. **`CParser >> encoderFromCue:`** — was hardwiring `CEncoder new`. Now respects `aCompilationCue encoderClass` or falls back to the standard encoder. 3. **`CParser >> parse:class:category:noPattern:context:notifying:ifFail:`** — was hardcoding `CEncoder new init:`. Now uses `EncoderForSistaV1` via a proper `CompilationCue`. 4. **`CCompiler >> setCue:`** — was calling `getClass` on the argument without a type check. When called with a raw class object instead of a CompilationCue, it raised MNU. Added `isKindOf: CompilationCue` guard. 5. **`CCompiler >> from:class:context:notifying:`** — was setting raw instance variables, bypassing the cue system entirely. Rewired to call `self setCue: (CompilationCue source:context:class:requestor:)`. 6. **`CCompiler >> evaluate:in:to:notifying:ifFail:logged:`** — was using the old DoIt-installation approach (addSelectorSilently: on UndefinedObject, which Squeak rightly rejects). Now delegates to `evaluateCue:ifFail:logged:` matching the modern Compiler. 7. **`MethodProperties >> propertyKeysAndValuesDo:` and `pragmasDo:`** — two methods the compilation pipeline expected but CCompiler's version of MethodProperties didn't provide. Added them. 8. **`CCompiler compileAll`** — the final and most important step. After `CCompiler superclass: Compiler`, the class gained new inherited instance variables. Any method compiled before the superclass change had stale bytecode slot indices. `compileAll` recompiled everything with the correct indices. Without this, `cue` reads in some methods were returning nil from the wrong ivar slot — leading to a confusing cascade of `UndefinedObject>>sourceStream` errors. --- ## The Result ```smalltalk CCompiler evaluate: '3 + 4' "→ 7" ``` The Facade is working. The standard Squeak compilation pipeline runs end-to-end through CCompiler and CParser, producing correct bytecode via EncoderForSistaV1. --- ## A Note on AI-Assisted Porting This session was a collaboration between myself, Claude claude.ai (used for diagnosis and architectural reasoning), and Claude Code (automated execution of fix attempts via an MCP-TCP bridge into the live Squeak image). The combination works well: claude.ai reasons about the Squeak class hierarchy and compiler internals; Claude Code executes targeted fixes in the live image. The pattern that emerged: claude.ai diagnoses, Claude Code applies. When Claude Code looped (it made 150+ TCP connections over the session, mostly re-diagnosing the same issue from scratch), the winning move was to apply the two-line fix manually in the Workspace: `CCompiler compileAll` followed by the test expression. Sometimes the Workspace is still the right tool. --- ## What's Next The immediate target is filing in `Tweak-Core-Object-tty.20`, which was the package that blocked progress in earlier sessions. After that: Tweak-Costume, Tweak-Basic, Tweak-Platforms, Tweak-Widgets, Tweak-Morphic, Tweak-Projects, and Tweak-ToolBuilder. The image is Squeak 6.1 alpha, 64-bit. The package cache is from the original OpenCobalt distribution. Happy to share the image or discuss the approach further. Many thanks to Eliot Miranda for the Facade suggestion — it was exactly right. --- Timothy (with Claude Sonnet 4.6) --- *Related reading:* - *Squeak Etoys*: original player/costume/script model - *OpenCobalt*: the Tweak-based collaborative 3D browser this codebase comes from - *SistaV1*: Squeak 6.x bytecode format, the compilation target for all of the above Squeak-dev mailing list -- [email protected] To unsubscribe send an email to [email protected]