Marcel Taeumel uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-mt.973.mcz
==================== Summary ====================
Name: Tools-mt.973
Author: mt
Time: 9 June 2020, 4:18:39.208147 pm
UUID: 18cfc395-b058-ad40-b1f1-c9e12f27da62
Ancestors: Tools-mt.972
Fixes access to "stack top" in inspector for context variables (i.e. the one in the debugger), which is used in field-list menu actions such as 'inspect' or 'explore'.
=============== Diff against Tools-mt.972 ===============
Item was added:
+ ----- Method: ContextVariablesInspector>>selectionOrObject (in category 'selection - convenience') -----
+ selectionOrObject
+ "Special treatment for #stackTop. See #fieldStackTop."
+
+ ^ self selectedField
+ ifNil: [super selectionOrObject]
+ ifNotNil: [:field |
+ field key = #stackTop
+ ifTrue: [
+ self object actualStackSize > 0
+ ifTrue: [self object top]
+ ifFalse: [self error: 'There is nothing on stack top.']]
+ ifFalse: [super selectionOrObject]]
+ !
Marcel Taeumel uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-mt.971.mcz
==================== Summary ====================
Name: Tools-mt.971
Author: mt
Time: 9 June 2020, 3:48:35.364373 pm
UUID: 229a24af-36d4-ef41-bb06-07b7ffeb9486
Ancestors: Tools-mt.970
Adds an inspector for forms with a "pixels" field that embeds the form as special font to see the pixels in the value pane. I think that there is no alpha support in FormSetFont ...
=============== Diff against Tools-mt.970 ===============
Item was added:
+ ----- Method: Form>>inspectorClass (in category '*Tools-Inspector') -----
+ inspectorClass
+
+ ^ FormInspector!
Item was added:
+ Inspector subclass: #FormInspector
+ instanceVariableNames: ''
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Tools-Inspector'!
Item was added:
+ ----- Method: FormInspector>>embedForm:inText: (in category 'support') -----
+ embedForm: aForm inText: stringOrText
+
+ ^ stringOrText asText, String cr,
+ (Text string: ' ' attribute:
+ (TextFontReference toFont:
+ (FormSetFont new
+ fromFormArray: (Array with: (aForm copy offset: 0@0))
+ asciiStart: Character space asInteger
+ ascent: aForm height)))!
Item was added:
+ ----- Method: FormInspector>>fieldPixels (in category 'fields') -----
+ fieldPixels
+
+ ^ (self newFieldForType: #misc key: #extent)
+ name: 'pixels' translated; emphasizeName;
+ shouldPrintValueAsIs: true;
+ valueGetter: [:form | self embedForm: form inText: form printString];
+ yourself!
Item was added:
+ ----- Method: FormInspector>>streamBaseFieldsOn: (in category 'fields - streaming') -----
+ streamBaseFieldsOn: aStream
+
+ super streamBaseFieldsOn: aStream.
+ aStream nextPut: self fieldPixels.!
Marcel Taeumel uploaded a new version of Monticello to project The Trunk:
http://source.squeak.org/trunk/Monticello-jr.720.mcz
==================== Summary ====================
Name: Monticello-jr.720
Author: jr
Time: 8 June 2020, 10:04:25.843513 pm
UUID: 3f24029f-dae5-e345-9060-d078beba7fcd
Ancestors: Monticello-mt.719
Load class traits only after the corresponding instance traits were loaded.
The Scanner expression comes from MCTraitDefinition>>requirements.
=============== Diff against Monticello-mt.719 ===============
Item was changed:
----- Method: MCClassDefinition>>requirements (in category 'comparing') -----
requirements
^superclassName == #nil
ifTrue: [self poolDictionaries]
+ ifFalse: [{ superclassName }, self poolDictionaries,
+ (self hasTraitComposition
+ ifTrue: [(Scanner new scanTokens: self traitComposition) flattened select: [:each | each first isUppercase]]
+ ifFalse: [#()])].!
- ifFalse: [{ superclassName }, self poolDictionaries]!
Marcel Taeumel uploaded a new version of Monticello to project The Trunk:
http://source.squeak.org/trunk/Monticello-jr.722.mcz
==================== Summary ====================
Name: Monticello-jr.722
Author: jr
Time: 8 June 2020, 10:13:23.034513 pm
UUID: 7062dfdb-583b-4d46-b37d-91a3781db5b9
Ancestors: Monticello-jr.721
Log method changes only if the SystemChangeNotifer is not muted.
unload is already routed through ClassDescription>>removeSelector: which emits a system change event rather than writing to the log unconditionally.
This change is useful to avoid cluttering the changes file when tests are run that load methods via Monticello. Previously even if these tests muted the change notifications, Monticello loading would still write lots of change records.
=============== Diff against Monticello-mt.719 ===============
Item was changed:
----- Method: MCClassDefinition>>requirements (in category 'comparing') -----
requirements
^superclassName == #nil
ifTrue: [self poolDictionaries]
+ ifFalse: [{ superclassName }, self poolDictionaries,
+ (self hasTraitComposition
+ ifTrue: [(Scanner new scanTokens: self traitComposition) flattened select: [:each | each first isUppercase]]
+ ifFalse: [#()])].!
- ifFalse: [{ superclassName }, self poolDictionaries]!
Item was changed:
----- Method: MCClassTraitDefinition>>load (in category 'installing') -----
load
+ Compiler evaluate: self definitionString environment: Environment current!
- Compiler evaluate: self definitionString!
Item was changed:
----- Method: MCMethodDefinition>>asMethodAddition (in category 'converting') -----
asMethodAddition
^MethodAddition new
compile: source
classified: category
withStamp: timeStamp
notifying: nil
+ logSource: SystemChangeNotifier uniqueInstance isBroadcasting
- logSource: true
inClass: self actualClass.!
Item was changed:
----- Method: MCMethodDefinition>>load (in category 'accessing') -----
load
+ | class |
+ class := self actualClass.
+ class
- self actualClass
compile: source
classified: category
withStamp: timeStamp
+ notifying: nil
+ logSource: (SystemChangeNotifier uniqueInstance isBroadcasting and: [class acceptsLoggingOfCompilation])!
- notifying: nil!
Item was changed:
----- Method: MCScriptDefinition>>evaluate (in category 'installing') -----
evaluate
+ Compiler evaluate: script environment: Environment current!
- Compiler evaluate: script!
Marcel Taeumel uploaded a new version of FFI-Tools to project FFI:
http://source.squeak.org/FFI/FFI-Tools-mt.13.mcz
==================== Summary ====================
Name: FFI-Tools-mt.13
Author: mt
Time: 8 June 2020, 11:20:14.827961 am
UUID: bf0f2436-af2c-dc46-a314-b94d9aaee7ab
Ancestors: FFI-Tools-mt.12
Complements FFI-Kernel-mt.100. Requires Squeak 6.0alpha to be at Morphic-mt.1666.
=============== Diff against FFI-Tools-mt.12 ===============
Item was removed:
- ----- Method: ExternalData>>explorerContents (in category '*FFI-Tools') -----
- explorerContents
-
- ^ super explorerContents, ((self isNull not and: [self mightBeCString]) ifFalse: [#()] ifTrue: [
- {ObjectExplorerWrapper
- with: self fromCStringLimited
- name: 'as C string'
- model: self}])!
Item was added:
+ ----- Method: ExternalData>>explorerContentsMetaFields (in category '*FFI-Tools') -----
+ explorerContentsMetaFields
+ "Ignore because our type is already in the basic explorer fields because it is an instance variable."
+ ^ #()!
Item was added:
+ ----- Method: ExternalData>>explorerContentsStructFields (in category '*FFI-Tools') -----
+ explorerContentsStructFields
+
+ ^ (self isNull not and: [self mightBeCString]) ifFalse: [#()] ifTrue: [
+ {ObjectExplorerWrapper
+ with: self fromCStringLimited
+ name: 'as C string'
+ model: self}]!
Item was removed:
- ----- Method: ExternalData>>explorerContentsTypeFields (in category '*FFI-Tools') -----
- explorerContentsTypeFields
- "Ignore because our type is already in the basic explorer fields because it is an instance variable."
- ^ #()!
Item was added:
+ ObjectExplorerWrapper subclass: #ExternalObjectHandleWrapper
+ instanceVariableNames: ''
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'FFI-Tools'!
+
+ !ExternalObjectHandleWrapper commentStamp: 'mt 6/8/2020 10:27' prior: 0!
+ I am a wrapper around handles of external objects. I am used in the object explorer tool. My role is to fine-tune the string representation of handles that are neither ByteArray nor ExternalAddress.!
Item was added:
+ ----- Method: ExternalObjectHandleWrapper>>getHandle (in category 'accessing') -----
+ getHandle
+
+ ^ self object!
Item was added:
+ ----- Method: ExternalObjectHandleWrapper>>objectString (in category 'accessing') -----
+ objectString
+
+ self getHandle class == ExternalAddress ifTrue: [^ super objectString].
+ self getHandle class == ByteArray ifTrue: [^ super objectString].
+
+ "Type aliases to atomic types store primitive Smalltalk objects in their handle. Indicate that role of actually being a handle for the FFI plugin with a small prefix."
+ ^ '-> ', super objectString!
Item was changed:
----- Method: ExternalStructure class>>allFieldSelectors (in category '*FFI-Tools') -----
allFieldSelectors
"Answer a list of all simple getters for fields in this structure. Rely on the #fields definition but only return selectors that are actually implemented. Consequently for any change in #fields, #defineFields should be called before calling this method."
- self flag: #dicuss. "mt: To which extent should tools support type aliasing when subclassing ExternalStructure instead of subclassing ExternalTypeAlias."
^ self isTypeAlias
ifTrue: [(ExternalType typeNamed: self originalTypeName) referentClass
+ ifNil: ["i.e, type alias to atomic type (e.g., typedef long MyStruct) or pointer-type of atomic (e.g., typedef char* MyLabel)"
+ self fields first ifNil: [#()] ifNotNil: [:selector | {selector}]]
+ ifNotNil: [:structClass | "i.e., type alias to structure type (e.g., typedef MyStruct MyStructAlias) or pointer-type of structure (e.g., typedef MyStruct* MyStructPointer)"
+ structClass allFieldSelectors]]
- ifNil: [#()] ifNotNil: [:structClass | structClass allFieldSelectors]]
ifFalse: [
self fields
collect: [:spec | spec first]
+ thenSelect: [:selector | selector notNil]]!
- thenSelect: [:selector |
- selector notNil and: [self includesSelector: selector]]]!
Item was changed:
----- Method: ExternalStructure>>explorerContents (in category '*FFI-Tools') -----
explorerContents
+ "Prefix all instance variables and append extra meta information (e.g., the external type) as well as all structure fields as defined in #fields."
+
-
| basicExplorerFields |
basicExplorerFields := super explorerContents.
basicExplorerFields do: [:explorerField |
+ explorerField itemName = 'handle' ifTrue: [
+ explorerField changeClassTo: ExternalObjectHandleWrapper].
explorerField itemName: '_', explorerField itemName].
^ basicExplorerFields,
+ self explorerContentsMetaFields,
- self explorerContentsTypeFields,
self explorerContentsStructFields!
Item was added:
+ ----- Method: ExternalStructure>>explorerContentsMetaFields (in category '*FFI-Tools') -----
+ explorerContentsMetaFields
+ "Answer extra fields for the object explorer to show meta information about this structure."
+
+ ^ {ObjectExplorerWrapper
+ with: (self class externalType ifNotNil: [:type |
+ handle class == ExternalAddress ifTrue: [type asPointerType] ifFalse: [type]])
+ name: '_type'
+ model: self}!
Item was changed:
----- Method: ExternalStructure>>explorerContentsStructFields (in category '*FFI-Tools') -----
explorerContentsStructFields
+ ^ self class allFieldSelectors collect: [:simpleGetter |
- ^ self class allFieldSelectors replace: [:simpleGetter |
ObjectExplorerWrapper
+ with: (self isNull ifFalse: [self perform: simpleGetter])
- with: (self isNull ifFalse: [self value perform: simpleGetter])
name: simpleGetter
model: self]!
Item was removed:
- ----- Method: ExternalStructure>>explorerContentsTypeFields (in category '*FFI-Tools') -----
- explorerContentsTypeFields
-
- ^ {ObjectExplorerWrapper
- with: (handle isExternalAddress ifTrue: [self class externalType asPointerType] ifFalse: [self class externalType])
- name: '_type'
- model: self}!
Item was changed:
----- Method: ExternalTypeAlias class>>allFieldSelectors (in category '*FFI-Tools') -----
allFieldSelectors
"Overridden because we know that we are an alias."
^ (ExternalType typeNamed: self originalTypeName) referentClass
+ ifNil: [#() "Not needed. See #explorerContentsMetaFields."]
- ifNil: [#()]
ifNotNil: [:structClass | structClass allFieldSelectors]!
Item was added:
+ ----- Method: ExternalTypeAlias>>explorerContentsMetaFields (in category '*FFI-Tools') -----
+ explorerContentsMetaFields
+ "Add a field to -- just in case -- explore the external object after casting to it."
+
+ ^ super explorerContentsMetaFields, {ObjectExplorerWrapper
+ with: self value
+ name: '_value'
+ model: self}!
Item was removed:
- ----- Method: ExternalTypeAlias>>explorerContentsTypeFields (in category '*FFI-Tools') -----
- explorerContentsTypeFields
- "Add a field to -- just in case -- explore the external object after casting to it."
-
- ^ super explorerContentsTypeFields, {ObjectExplorerWrapper
- with: self value
- name: '_value'
- model: self}!
Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:
http://source.squeak.org/FFI/FFI-Kernel-mt.100.mcz
==================== Summary ====================
Name: FFI-Kernel-mt.100
Author: mt
Time: 8 June 2020, 11:19:01.328961 am
UUID: f04e1d02-77fb-eb43-bf53-292fbf956863
Ancestors: FFI-Kernel-mt.99
Further work on support of type aliasing and its documentation. Removes FFIObjectHandle again because that would require modification of the FFI plugin, which is not worthwhile because it only would simplify print-strings. Add documentation about this issue to ExternalStructure >> #isNull.
=============== Diff against FFI-Kernel-mt.99 ===============
Item was changed:
----- Method: ExternalData>>printPointerOn: (in category 'printing') -----
printPointerOn: stream
+ "Ignore since it is part of the type, e.g. char* or int[] etc."!
- "Ignore since it is part of the type."!
Item was removed:
- ----- Method: ExternalObject>>isExternalAddress (in category 'testing') -----
- isExternalAddress
- "Return true if the receiver describes the address of an object in the outside world"
- ^false!
Item was changed:
----- Method: ExternalStructure class>>compileTypeAliasSpec:withAccessors: (in category 'field definition - support') -----
compileTypeAliasSpec: spec withAccessors: aSymbol
"Define all the fields in the receiver.
Return the newly compiled spec."
| fieldName fieldTypeName externalType |
fieldName := spec first.
fieldTypeName := spec second.
externalType := (ExternalType typeNamed: fieldTypeName)
ifNil: [self errorTypeNotFound: spec second].
(fieldName notNil and:[self shouldGenerate: fieldName policy: aSymbol]) ifTrue:[
self generateTypeAliasAccessorsFor: fieldName type: externalType].
externalType isPointerType
ifTrue: ["Special case. Typedef for a pointer type, e.g., typedef char* LPSTR in Win32 API. Mark it as both structure and pointer. Note that #isPointerType will only answer true for the in-image pointer type, not the non-pointer alias for the pointer."
self
+ flag: #isTypeAliasForPointer;
- flag: #isTypeAliasToPointer;
setCompiledSpec: (WordArray with: (ExternalType structureSpec bitOr: ExternalType pointerSpec))
byteAlignment: ExternalType pointerAlignment]
+ ifFalse: ["Usual case. Typedef for another struct type or atomic type. Just re-use compiled spec and extras from the aliased type."
- ifFalse: ["Usual case. Typedef for another struct type. Just re-use compiled spec and extras from the aliased type."
self
flag: #isTypeAlias;
setCompiledSpec: externalType compiledSpec
byteAlignment: externalType byteAlignment].!
Item was added:
+ ----- Method: ExternalStructure>>hasStableRepresentation (in category 'testing') -----
+ hasStableRepresentation
+ "Answers whether the contents of this structure have a stable representation in memory. Basically, every handle that is not a ByteArray can be considered a stable representation. The primary examples would be handles that are 'nil' or an ExternalAddress. Additionally, there can be type aliases to atomic types, which then store the Smalltalk object, e.g. Integer or Float, for such an atomic, e.g. long or float, directly in 'handle'. Those Smalltalk objects are typically immediate (e.g., integers, characters). Note that strings map to char*, which is an (atomic) pointer type and thus accessible only through an ExternalData, which itself always holds an external address as its handle."
+
+ ^ handle class ~~ ByteArray!
Item was changed:
----- Method: ExternalStructure>>isNull (in category 'testing') -----
isNull
- self flag: #bug. "mt: We should not have (and use) #asByteArrayPointer and also think that #isNull cannot be implemented in ByteArray."
+ self flag: #ffiDesignSmell. "Type aliases to atomic types store data via handle as Smalltalk object. Consequently, #isNull and #isExternalAddress must not be sent to 'handle' without care. Actually, #isExternalAddress is rather useless at the moment."
+
+ handle class == ExternalAddress ifTrue: [^ handle isNull].
+ self hasStableRepresentation ifTrue: [^ handle isNil].
+
+ self flag: #ffiDesignSmell. "Type aliases to pointer types store pointers via handle as ByteArray, not ExternalAddress (like regular pointer types). Consequently, it is tricky to detect a NULL pointer in the general sense. Here, try to check for #isTypeAliasForPointer and only then check for all bytes being 0 in the byte array."
+
+ "self assert: [self externalType isTypeAliasForPointer => [handle class == ByteArray]]."
+ ^ self externalType isTypeAliasForPointer
+ and: [handle allSatisfy: [:byte | byte = 0 ]]!
- ^ super isNull or: [
- self externalType isTypeAliasToPointer and: [
- handle class == ByteArray
- and: [ handle allSatisfy: [:byte | byte = 0 ]]]]!
Item was added:
+ ----- Method: ExternalStructure>>printIdentityOn: (in category 'printing') -----
+ printIdentityOn: stream
+ "Reveal information about this external object's identity so that users can quickly assess the need for inspecting its contents. Users can also infer lifetime properties and consider those when passing this object around in the system. For example, objects that are created on-the-fly when accessing fields via an external address may be of less value compared to objects that are actually hold at those external addresses. See #printPointerOn:."
+
+ handle ifNil: [
+ ^ stream nextPutAll: '<UNDEFINED>'].
+
+ self isNull ifTrue: [
+ ^ stream nextPutAll: '<NULL>'].
+
+ self hasStableRepresentation
+ ifTrue: ["Object has a stable representation. No need to expose its memory address in the UI."
+ ^ self]
+ ifFalse: ["Inform the user that this data was copied into object memory."
+ ^ stream nextPut: $<; print: handle identityHash; nextPut: $>].
+ !
Item was removed:
- ----- Method: ExternalStructure>>printNullOn: (in category 'printing') -----
- printNullOn: stream
-
- handle ifNil: [
- ^ stream nextPutAll: '<UNDEFINED>'].
-
- self isNull ifTrue: [
- ^ stream nextPutAll: '<NULL>'].
-
- handle isExternalAddress ifFalse: [
- "Inform the user that this data was copied into object memory."
- ^ stream nextPut: $<; print: handle identityHash; nextPut: $>].
- !
Item was changed:
----- Method: ExternalStructure>>printOn: (in category 'printing') -----
printOn: stream
super printOn: stream.
self printPointerOn: stream.
+ self printIdentityOn: stream.!
- self printNullOn: stream.!
Item was changed:
----- Method: ExternalStructure>>printPointerOn: (in category 'printing') -----
printPointerOn: stream
+ "Indicate whether this structure points to an external address or whether its contents got copied into a byte array in object memory."
handle ifNil: [^ stream nextPutAll: '<UNDEFINED>'].
+ handle class == ExternalAddress
- handle isExternalAddress
ifTrue: [stream nextPutAll: '*'].!
Item was changed:
----- Method: ExternalType class>>initializeAtomicTypes (in category 'class initialization') -----
initializeAtomicTypes
"ExternalType initialize"
| atomicType byteSize type typeName byteAlignment |
self flag: #ffiLongVsInt. "For a discussion about long vs. int see http://forum.world.st/Re-squeak-dev-64-bit-FFI-was-porting-Croquet-to-Squea…."
#(
"name atomic id byte size byte alignment"
+ ('void' 0 0 0) "No non-pointer support in calls. Duh. ;-)"
+ ('bool' 1 1 1) "No pointer support in calls."
- ('void' 0 0 0)
- ('bool' 1 1 1)
('byte' 2 1 1)
('sbyte' 3 1 1)
('ushort' 4 2 2)
('short' 5 2 2)
"!!!!!!" ('ulong' 6 4 "!!!!!!" 4)
"!!!!!!" ('long' 7 4 "!!!!!!" 4)
('ulonglong' 8 8 8) "v.i."
('longlong' 9 8 8) "v.i."
('char' 10 1 1)
('schar' 11 1 1)
('float' 12 4 4)
('double' 13 8 8) "v.i."
"TODO: ('longdouble' 14 10 16? 4?)"
) do:[:typeSpec| | compiled |
typeName := typeSpec first.
atomicType := typeSpec second.
byteSize := typeSpec third.
byteAlignment := typeSpec fourth.
"0) On 32-bits Windows and MacOS, double and long long have an alignment of 8. But on 32-bit Linux, their alignment is 4. But not on a 32-bit Raspberry Pi OS."
(FFIPlatformDescription current wordSize = 4
and: [FFIPlatformDescription current isUnix
and: [FFIPlatformDescription current isARM not]]) ifTrue: [
(#('double' 'longlong' 'ulonglong') includes: typeName) ifTrue: [
byteAlignment := 4]].
"1) Regular type"
type := (AtomicTypes at: typeName).
compiled := WordArray with: ((byteSize bitOr: FFIFlagAtomic) bitOr:
(atomicType bitShift: FFIAtomicTypeShift)).
compiled ~= type compiledSpec
"Preserve the identity of #compiledSpec."
ifTrue: [type compiledSpec: compiled].
type byteAlignment: byteAlignment.
"2) Pointer type"
type := type asPointerType.
compiled := WordArray with: ((self pointerSpec bitOr: FFIFlagAtomic) bitOr:
(atomicType bitShift: FFIAtomicTypeShift)).
compiled ~= type compiledSpec
"Preserve the identity of #compiledSpec."
ifTrue: [type compiledSpec: compiled].
type byteAlignment: self pointerAlignment.
].!
Item was changed:
----- Method: ExternalType>>isTypeAlias (in category 'testing') -----
isTypeAlias
+ ^ self isPointerType not
+ and: [referentClass notNil and: [referentClass isTypeAlias]]!
- ^ referentClass
- ifNil: [false]
- ifNotNil: [:structClass | structClass isTypeAlias]!
Item was added:
+ ----- Method: ExternalType>>isTypeAliasForAtomic (in category 'testing') -----
+ isTypeAliasForAtomic
+ "Answer whether this type aliases an atomic type, e.g., typedef ulong ID"
+ "See ThreadedFFIPlugin >> ffiArgument: oop Spec: argSpec Class: argClass in: calloutState"
+
+ ^ self isTypeAlias and: [self isStructureType not and: [self isAtomic]]!
Item was added:
+ ----- Method: ExternalType>>isTypeAliasForPointer (in category 'testing') -----
+ isTypeAliasForPointer
+ "Answer whether this type aliases a pointer type, e.g., typedef char_ptr char*"
+ "See ThreadedFFIPlugin >> ffiArgument: oop Spec: argSpec Class: argClass in: calloutState"
+
+ "Note that self isTypeAliasForPointer => [self isPointerType not]"
+ ^ self isTypeAlias and: [self isStructureType and:[self headerWord anyMask: FFIFlagPointer]]!
Item was removed:
- ----- Method: ExternalType>>isTypeAliasToPointer (in category 'testing') -----
- isTypeAliasToPointer
- "Answer whether this type aliases a pointer type, e.g., typedef char_ptr char*"
- ^ self isTypeAlias and: [self isStructureType and:[self headerWord anyMask: FFIFlagPointer]]!
Item was changed:
----- Method: ExternalType>>readAlias (in category 'private') -----
readAlias
^ String streamContents: [:s |
referentClass == nil
ifTrue:[(self isAtomic and:[self isPointerType not])
+ ifTrue:[s nextPutAll:'^handle "', self writeFieldArgName, '"']
- ifTrue:[s nextPutAll:'^handle object "', self readFieldArgName, '"']
ifFalse:[s nextPutAll:'^ExternalData fromHandle: handle'.
self isPointerType ifTrue:[s nextPutAll:' asExternalPointer'].
s nextPutAll:' type: ';
nextPutAll: self asPointerType storeString]]
ifFalse:[s nextPutAll:'^', referentClass name,' fromHandle: handle'.
self isPointerType ifTrue:[s nextPutAll:' asExternalPointer']]]!
Item was removed:
- ----- Method: ExternalType>>readFieldArgName (in category 'private') -----
- readFieldArgName
-
- ^ self writeFieldArgName!
Item was changed:
----- Method: ExternalType>>readFieldAt: (in category 'private') -----
readFieldAt: byteOffset
"Answer a string defining the accessor to an entity of the receiver type starting at the given byte offset.
Private. Used for field definition only."
self isPointerType ifTrue:
[| accessor |
self flag: #ffiLongVsInt. "mt: Here short means 'long', which is actually 'int', and long means 'longlong'. Sigh."
accessor := self pointerSize caseOf: {
[4] -> [#shortPointerAt:].
[8] -> [#longPointerAt:] }.
^String streamContents:
[:s|
referentClass
ifNil:
[s nextPutAll: '^ExternalData fromHandle: (handle ', accessor, ' ';
print: byteOffset;
nextPutAll: ') type: ExternalType ';
nextPutAll: self atomicTypeName;
nextPutAll: ' asPointerType']
ifNotNil:
[s nextPutAll: '^';
print: referentClass;
nextPutAll: ' fromHandle: (handle ', accessor, ' ';
print: byteOffset;
nextPut: $)]]].
self isAtomic ifFalse: "structure type"
[^String streamContents:[:s|
s nextPutAll:'^';
print: referentClass;
nextPutAll:' fromHandle: (handle structAt: ';
print: byteOffset;
nextPutAll:' length: ';
print: self byteSize;
nextPutAll:')']].
self isTypeAlias ifTrue: "alias to atomic type"
[^String streamContents:[:s |
s nextPutAll:'^';
print: referentClass;
+ nextPutAll:' fromHandle: (handle ';
- nextPutAll:' fromHandle: (FFIObjectHandle on: (handle ';
nextPutAll: (AtomicSelectors at: self atomicType);
space; print: byteOffset;
+ nextPutAll:')']].
- nextPutAll:'))']].
"Atomic non-pointer types"
^String streamContents:
[:s|
s nextPutAll:'^handle ';
nextPutAll: (AtomicSelectors at: self atomicType);
space; print: byteOffset].!
Item was changed:
----- Method: ExternalType>>writeAliasWith: (in category 'private') -----
writeAliasWith: valueName
^ String streamContents: [:s |
(referentClass == nil and:[self isAtomic and:[self isPointerType not]])
+ ifTrue:[s nextPutAll:'handle := ', valueName, '.']
- ifTrue:[s nextPutAll:'handle := FFIObjectHandle on: ', valueName, '.']
ifFalse:[s nextPutAll:'handle := ', valueName,' getHandle'.
self isPointerType ifTrue:[s nextPutAll:' asByteArrayPointer']]]!
Item was changed:
----- Method: ExternalType>>writeFieldAt:with: (in category 'private') -----
writeFieldAt: byteOffset with: valueName
"Answer a string defining the accessor to an entity of the receiver type starting at the given byte offset.
Private. Used for field definition only."
self isPointerType ifTrue:
[| accessor |
self flag: #ffiLongVsInt. "mt: Here short means 'long', which is actually 'int', and long means 'longlong'. Sigh."
accessor := self pointerSize caseOf: {
[4] -> [#shortPointerAt:].
[8] -> [#longPointerAt:] }.
^String streamContents:
[:s|
s nextPutAll:'handle ', accessor, ' ';
print: byteOffset;
nextPutAll:' put: ';
nextPutAll: valueName;
nextPutAll:' getHandle.']].
self isAtomic ifFalse:[ "structure type"
^String streamContents:[:s|
s nextPutAll:'handle structAt: ';
print: byteOffset;
nextPutAll:' put: ';
nextPutAll: valueName;
nextPutAll:' getHandle';
nextPutAll:' length: ';
print: self byteSize;
nextPutAll:'.']].
self isTypeAlias ifTrue:[ "alias to atomic type"
^String streamContents:[:s|
s nextPutAll:'handle ';
nextPutAll: (AtomicSelectors at: self atomicType);
space; print: byteOffset;
nextPutAll:' put: ';
nextPutAll: valueName;
+ nextPutAll: ' getHandle']].
- nextPutAll: ' getHandle object']].
^String streamContents:[:s|
s nextPutAll:'handle ';
nextPutAll: (AtomicSelectors at: self atomicType);
space; print: byteOffset;
nextPutAll:' put: ';
nextPutAll: valueName].!
Item was removed:
- Object subclass: #FFIObjectHandle
- instanceVariableNames: 'object'
- classVariableNames: ''
- poolDictionaries: ''
- category: 'FFI-Kernel'!
-
- !FFIObjectHandle commentStamp: 'mt 6/6/2020 13:11' prior: 0!
- I am a wrapper around an object and hence, in addition to ByteArray and ExternalAddress, the third kind of handle an external object can have. I am necessary to implement type aliasing.!
Item was removed:
- ----- Method: FFIObjectHandle class>>on: (in category 'instance creation') -----
- on: anObject
-
- ^ self new object: anObject!
Item was removed:
- ----- Method: FFIObjectHandle>>asByteArrayPointer (in category 'private') -----
- asByteArrayPointer
- "Return a ByteArray describing a pointer to the contents of the receiver."
- ^self shouldNotImplement!
Item was removed:
- ----- Method: FFIObjectHandle>>isExternalAddress (in category 'testing') -----
- isExternalAddress
-
- ^ false!
Item was removed:
- ----- Method: FFIObjectHandle>>isNull (in category 'testing') -----
- isNull
-
- ^ self object isNil!
Item was removed:
- ----- Method: FFIObjectHandle>>object (in category 'accessing') -----
- object
-
- ^ object!
Item was removed:
- ----- Method: FFIObjectHandle>>object: (in category 'accessing') -----
- object: anObject
-
- object := anObject.!
Item was removed:
- ----- Method: FFIObjectHandle>>printOn: (in category 'as yet unclassified') -----
- printOn: aStream
-
- aStream
- nextPutAll: '-> ';
- print: self object.!
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1666.mcz
==================== Summary ====================
Name: Morphic-mt.1666
Author: mt
Time: 8 June 2020, 11:13:50.055961 am
UUID: 8be3a7c3-69d8-2845-8a7c-759c8bfd1470
Ancestors: Morphic-mt.1665
Adds a small hook to support parent-controlled print-strings for objects in the object explorer. Parent objects would return custom subclasses of ObjectExplorerWrapper when ansering the #explorerContents. Think of, for example, custom string representations for numbers being embedded in your domain objects.
=============== Diff against Morphic-mt.1665 ===============
Item was changed:
----- Method: ObjectExplorerWrapper>>asString (in category 'converting') -----
asString
| explorerString label separator |
explorerString :=
+ [self objectString]
- [self object asExplorerString]
on: Error
do: ['<error: ', self object class name, ' in asExplorerString: evaluate "' , self itemName , ' asExplorerString" to debug>'].
(explorerString includes: Character cr)
ifTrue: [explorerString := explorerString withSeparatorsCompacted].
label := self itemName ifNil: [''].
(label includes: Character cr)
ifTrue: [label := label withSeparatorsCompacted].
separator := self class showContentsInColumns
ifTrue: [String tab]
ifFalse: [label ifEmpty: [''] ifNotEmpty: [': ']].
^ '{1}{2}{3}' format: {label. separator. explorerString}!
Item was added:
+ ----- Method: ObjectExplorerWrapper>>objectString (in category 'accessing') -----
+ objectString
+ "Answers a string representation of the object that well be combined with #itemName when requested from the tree model. Overwrite this in custom wrappers to modify parent-specific representations without having to modify #asExplorerString in the particular object."
+
+ ^ self object asExplorerString!