This is an old revision of the document!
Values porting log
Here, I try to record my steps for porting the Values package from VisualWorks to Squeak.
Starting point
In your VisualWorks 8.3 image
- have {Smalltalk Transform Project} (1.4.0.3,chaider) loaded
- have [Squeak Fileout PDFtalk] (3.0.0.2,chaider) loaded, with empty transformations:
ValuesTransform ^PackageChange new
First FileIn
File out from VW with
Squeak fileOutValues
. Start squeak, open the Transcript and file in “Values.Squeak.st” with
FileStream fileIn: 'C:\Users\Christian\Documents\image\Values.Squeak.st'
it loads 1 / 4 of the file before a syntax error occurs:
localSpecification <constant: #name class: #"Invalid literal character ->"{Printvalue}> <constant: #value class: #{Printvalue}>
The Transcript shows:
UndefinedObject»DoIt (PackageManifest is Undeclared) Attempt to create ManifestValues as a subclass of nil. Possibly a class is being loaded before its superclass.
VW literal binding syntax #{}
VisualWorks has a special syntax for specifying a class in a namespace as literal; e.g. #{PDFtalk.Name}
.
Fixed by adding add a transformation for the class method #localSpecification in any Value subclass. This translates #{Integer}
to #(#Integer)
and #{PDFtalk.Name}
to #(#PDFtalk #Name)
.
ValuesTransform ^PackageChange hierarchyChanges: (Array with: (ClassChange classReference: #{Smalltalk.Value} classChanges: (Array with: (Rewrite method: #localSpecification rule: #replaceLiteralBindingWithPath))))
Published as [Squeak Fileout PDFtalk] (3.0.0.3,chaider).
Unknown superclass
The Transcript warning complains that the class ManifestValues
cannot be created as subclass of PackageManifest
which is unknown.
Changed ChunkStream»#writeProperties:in:parents:
to
- use
Object
as superclass instead ofPackageManifest
- renamed class to
About<Package>
Published as {Smalltalk Transform Project} (1.4.0.4,chaider).
FileIn 2
FileOut from VW, then fileIn into a fresh Squeak image.
Loads about 80% until it hits the error that ColorValue is not defined.
The Transcript shows:
Class>>nameRelativeTo: (Root is Undeclared) Class>>isInScope: (NameScope is Undeclared) UndefinedObject>>DoIt (ColorValue is Undeclared) UndefinedObject>>fromBytesRed:green:blue: (ColorValue is Undeclared) UndefinedObject>>fromBytesRed:green:blue: (ColorValue is Undeclared) UndefinedObject>>DoIt (ColorValue is Undeclared) UndefinedObject>>DoIt (ColorValue is Undeclared) UndefinedObject>>DoIt (ColorValue is Undeclared) UndefinedObject>>DoIt (ColorValue is Undeclared) UndefinedObject>>DoIt (ColorValue is Undeclared)
Missing class
The system class ColorValue
of VW is roughly equivalent to Color
in Squeak. But instead of renaming all ColorValue
references to Color
, I define ColorValue
as subclass of Color
. With this, the target system is not polluted with compatibility methods for ColorValue
.
This is expressed in the transformation with #newSuperclasses. The new transform looks like:
ValuesTransform ^PackageChange newSuperclasses: (Valuemap with: #{Smalltalk.ColorValue} -> #Color) hierarchyChanges: (Array with: (ClassChange classReference: #{Smalltalk.Value} classChanges: (Array with: (Rewrite method: #localSpecification rule: #replaceLiteralBindingWithPath))))
Undeclared class references
The Transcript shows undeclared class references in two methods of class class
.
Class>>nameRelativeTo: (Root is Undeclared) Class>>isInScope: (NameScope is Undeclared)
To handle this, we add local changes to the transformation. Local changes refer to classes in the source system.
ValuesTransform ^PackageChange newSuperclasses: (Valuemap with: #{Smalltalk.ColorValue} -> #Color) hierarchyChanges: (Array with: (ClassChange classReference: #{Smalltalk.Value} classChanges: (Array with: (Rewrite method: #localSpecification rule: #replaceLiteralBindingWithPath)))) localChanges: self valuesLocalTransform valuesLocalTransform ^Array with: (ClassChange classReference: #{Class} instanceChanges: (Array with: (Replace method: #nameRelativeTo: code: #_sq_nameRelativeTo:) with: (Replace method: #isInScope: code: #_sq_isInScope:)))
These transformations replace the body of the existing methods of class Class
with the body of the #code
methods.
Published as {Smalltalk Transform Project} (1.4.0.5,chaider) with minor changes (updated comments and corrected spelling).
Published as [Squeak Fileout PDFtalk] (3.0.0.4,chaider) with the updated transformations.
FileIn 3
FileOut from VW, then fileIn into a fresh Squeak image.
Loads about 85% until it hits the error that GeneralBindingReference is not defined.
The Transcript shows:
UndefinedObject>>DoIt (GeneralBindingReference is Undeclared) UndefinedObject>>DoIt (GeneralBindingReference is Undeclared) UndefinedObject>>DoIt (GeneralBindingReference is Undeclared) UndefinedObject>>DoIt (GeneralBindingReference is Undeclared)
Since GeneralBindingReference is specific to namespaces in VW, we don't need to port the class extension methods. For this we add the class to the #unusedClasses in our #ValuesTransform PackageChange:
ValuesTransform ^PackageChange unusedClasses: #(#{Smalltalk.GeneralBindingReference}) newSuperclasses: (Valuemap with: #{Smalltalk.ColorValue} -> #Color) hierarchyChanges: (Array with: (ClassChange classReference: #{Smalltalk.Value} classChanges: (Array with: (Rewrite method: #localSpecification rule: #replaceLiteralBindingWithPath)))) localChanges: self valuesLocalTransform
Published as [Squeak Fileout PDFtalk] (3.0.0.5,chaider) with the updated transformation.
FileIn 4
FileOut from VW, then fileIn into a fresh Squeak image.
Loads about 97% until it hits the error that Timestamp is not defined.
The Transcript shows:
UndefinedObject>>DoIt (Timestamp is Undeclared) UndefinedObject>>DoIt (Timestamp is Undeclared) UndefinedObject>>DoIt (Timestamp is Undeclared) UndefinedObject>>DoIt (Timestamp is Undeclared) UndefinedObject>>DoIt (Timestamp is Undeclared)
We do the same trick as in FileIn x and set DateAndTime as superclass of Timestamp. The new Transformation is:
ValuesTransform ^PackageChange unusedClasses: #(#{Smalltalk.GeneralBindingReference}) newSuperclasses: (Valuemap with: #{Smalltalk.ColorValue} -> #Color with: #{Timestamp} -> #DateAndTime) hierarchyChanges: (Array with: (ClassChange classReference: #{Smalltalk.Value} classChanges: (Array with: (Rewrite method: #localSpecification rule: #replaceLiteralBindingWithPath)))) localChanges: self valuesLocalTransform
Published as [Squeak Fileout PDFtalk] (3.0.0.6,chaider) with the updated transformation.
FileIn 5
FileOut from VW, then fileIn into a fresh Squeak image.
Loads without errors or warnings!.
First milestone: Clean fileIn without errors or warnings!Next step: fileIn the tests.
FileIn 6 - Tests
Added Squeak class method #fileOutValuesTesting
analog to #fileOutValues
:
fileOutValuesTesting self write: ('.' asFilename construct: 'ValuesTesting.Squeak.st') pundles: (Array with: (Store.Registry packageNamed: #'Values Testing')) package: #'Values-Testing' prerequisites: nil packageChanges: (Valuemap with: 'Values Testing' -> self ValuesTestingTransform)
with the standard transformation for Value classes:
ValuesTestingTransform ^PackageChange hierarchyChanges: (Array with: (ClassChange classReference: #{Smalltalk.Value} classChanges: (Array with: (Rewrite method: #localSpecification rule: #replaceLiteralBindingWithPath))))
FileOut from VW with:
Squeak fileOutValuesTesting
then fileIn into a Squeak image with Values loaded.
Loads without errors.
The Transcript shows:
ValuemapTests>>testIndexedAccess (SubscriptOutOfBoundsError is Undeclared) ValuemapTests>>testIndexedAccess (SubscriptOutOfBoundsError is Undeclared) ValuemapTests>>testIndexedAccess (NonIntegerIndexError is Undeclared) ValuemapTests>>testIndexedAccess (NonIntegerIndexError is Undeclared) ValuemapTests>>testKeyedAccess (NotFoundError is Undeclared) ValuemapTests>>testRemoving (NotFoundError is Undeclared) ValuemapTests>>testRemoving (NotFoundError is Undeclared) ValuemapTests>>testRemoving (NotFoundError is Undeclared) ValuemapTests>>testRemoving (NotFoundError is Undeclared)
The VW error classes are not known in Squeak. We define a rewrite of the three test methods:
ValuesTestingTransform ^PackageChange hierarchyChanges: (Array with: (ClassChange classReference: #{Smalltalk.Value} classChanges: (Array with: (Rewrite method: #localSpecification rule: #replaceLiteralBindingWithPath)))) localChanges: (Array with: (ClassChange classReference: #{Smalltalk.ValuemapTests} instanceChanges: ((OrderedCollection new) add: (Rewrite method: #testIndexedAccess rule: #replaceSqueakErrorClasses); add: (Rewrite method: #testKeyedAccess rule: #replaceSqueakErrorClasses); add: (Rewrite method: #testRemoving rule: #replaceSqueakErrorClasses); yourself)))
The rule #replaceSqueakErrorClasses
in class ParseTreeRewriter
(analog to #replaceGemstoneErrorClasses
) replaces the Error classes by string replacement:
replaceSqueakErrorClasses ^(self new) replace: SubscriptOutOfBoundsError name asString with: #Error asString; replace: NonIntegerIndexError name asString with: #Error asString; replace: NotFoundError name asString with: #NotFound asString; yourself
Published as [Squeak Fileout PDFtalk] (3.0.0.7,chaider) with the updated transformation.