diff --git a/src/Famix-Value-Entities-Extensions/FamixValueOfObjectAttribute.extension.st b/src/Famix-Value-Entities-Extensions/FamixValueOfObjectAttribute.extension.st index 10090ea..9d6b4c4 100644 --- a/src/Famix-Value-Entities-Extensions/FamixValueOfObjectAttribute.extension.st +++ b/src/Famix-Value-Entities-Extensions/FamixValueOfObjectAttribute.extension.st @@ -9,3 +9,11 @@ FamixValueOfObjectAttribute >> mooseNameOn: aStream [ ifNil: [ '' ]) << $=. value printValueOn: aStream ] + +{ #category : #'*Famix-Value-Entities-Extensions' } +FamixValueOfObjectAttribute >> varName [ + + ^ self attribute + ifNotNil: [ :attribute | attribute name ] + ifNil: [ value varName ] +] diff --git a/src/Famix-Value-Entities/FamixValueOfObjectAttribute.class.st b/src/Famix-Value-Entities/FamixValueOfObjectAttribute.class.st index e42721a..7322d5f 100644 --- a/src/Famix-Value-Entities/FamixValueOfObjectAttribute.class.st +++ b/src/Famix-Value-Entities/FamixValueOfObjectAttribute.class.st @@ -78,11 +78,3 @@ FamixValueOfObjectAttribute >> value: anObject [ value := anObject ] - -{ #category : #generate } -FamixValueOfObjectAttribute >> varName [ - - ^ self attribute - ifNotNil: [ :attribute | attribute name ] - ifNil: [ value varName ] -] diff --git a/src/Famix-Value-Entities/FamixValueOfType.class.st b/src/Famix-Value-Entities/FamixValueOfType.class.st index a1aea66..b5c8540 100644 --- a/src/Famix-Value-Entities/FamixValueOfType.class.st +++ b/src/Famix-Value-Entities/FamixValueOfType.class.st @@ -70,27 +70,6 @@ FamixValueOfType >> addValueInDictionary: anObject [ ^ self valueInDictionaries add: anObject ] -{ #category : #'ston persistence' } -FamixValueOfType >> asJsonString [ - "Currently does not work. Ideas: - - Find a way to serialize any object while handling circular dependencies. - - Use the json stored in the root value to read it into raw objects and traverse the path to this value." - - self flag: #TODO. - ^ self asNeoJSONObject asString -] - -{ #category : #'ston persistence' } -FamixValueOfType >> asNeoJSONObject [ - - self flag: #TODO. "see #asJsonString" - ^ self typedEntity - ifNotNil: [ "at root" - NeoJSONObject fromString: (self cacheAt: #json ifAbsent: '{}') ] - ifNil: [ "how to iterate until root?" - NeoJSONObject fromString: (self cacheAt: #json ifAbsent: '{}') ] -] - { #category : #accessing } FamixValueOfType >> attributeInObjects [ "Relation named: #attributeInObjects type: #FamixValueOfObjectAttribute opposite: #value" diff --git a/src/Famix-Value-Exporter/FASTBuilder.class.st b/src/Famix-Value-Exporter/FASTBuilder.class.st index d187053..d469115 100644 --- a/src/Famix-Value-Exporter/FASTBuilder.class.st +++ b/src/Famix-Value-Exporter/FASTBuilder.class.st @@ -1,10 +1,13 @@ +" +I am a helper for the `FamixValue2ASTVisitor` hierarchy of classes to build AST. +" Class { #name : #FASTBuilder, #superclass : #Object, #instVars : [ 'model' ], - #category : #'Famix-Value-Exporter' + #category : #'Famix-Value-Exporter-Helpers' } { #category : #testing } diff --git a/src/Famix-Value-Exporter/FASTJavaBuilder.class.st b/src/Famix-Value-Exporter/FASTJavaBuilder.class.st index 0544146..dbc29e5 100644 --- a/src/Famix-Value-Exporter/FASTJavaBuilder.class.st +++ b/src/Famix-Value-Exporter/FASTJavaBuilder.class.st @@ -1,10 +1,13 @@ +" +I am used to handle Java type references and imports. +" Class { #name : #FASTJavaBuilder, #superclass : #FASTBuilder, #instVars : [ 'typeNameDictionary' ], - #category : #'Famix-Value-Exporter' + #category : #'Famix-Value-Exporter-Helpers' } { #category : #ast } diff --git a/src/Famix-Value-Exporter/FamixValue2ASTVisitor.class.st b/src/Famix-Value-Exporter/FamixValue2ASTVisitor.class.st index 2a7ac45..3d24a9d 100644 --- a/src/Famix-Value-Exporter/FamixValue2ASTVisitor.class.st +++ b/src/Famix-Value-Exporter/FamixValue2ASTVisitor.class.st @@ -10,7 +10,7 @@ Class { 'id', 'statementBlock' ], - #category : #'Famix-Value-Exporter' + #category : #'Famix-Value-Exporter-Visitors' } { #category : #testing } diff --git a/src/Famix-Value-Exporter/FamixValue2FASTJavaVisitor.class.st b/src/Famix-Value-Exporter/FamixValue2FASTJavaVisitor.class.st index 394a9ab..fd7c6d6 100644 --- a/src/Famix-Value-Exporter/FamixValue2FASTJavaVisitor.class.st +++ b/src/Famix-Value-Exporter/FamixValue2FASTJavaVisitor.class.st @@ -1,12 +1,12 @@ " -A visitor for exporting a FamixValue model to FASTJava. +A visitor to export a FamixValue model to FASTJava. The generated code is a block statement with a variable declared for each value. Object attributes are initialized by finding the corresponding setters. -Collections and Dictionaries are constructed with the `add(element)` and `put(key, value)` methods respectively. +Collections and Dictionaries are constructed with the methods `add(element)` and `put(key, value)` respectively. -When exporting a `FamixValueOfObjectAttribute`, if the setter for its `FamixTAttribute` cannot be found, they are set using the Java Reflection API. -All attributes that fall in this category are added as `markedForReflection`. +When exporting a `FamixValueOfObjectAttribute`, if the setter for its `FamixTAttribute` cannot be found, it is set using the Java Reflection API. +All attributes that fall into this category are added as `markedForReflection`. " Class { #name : #FamixValue2FASTJavaVisitor, @@ -16,10 +16,9 @@ Class { 'markedForReflection', 'constructorCache', 'staticAttributesCache', - 'objectExportStrategy', - 'setterCache' + 'objectExportStrategy' ], - #category : #'Famix-Value-Exporter' + #category : #'Famix-Value-Exporter-Visitors' } { #category : #private } @@ -37,8 +36,10 @@ FamixValue2FASTJavaVisitor >> addAttributesFrom: object asArgumentsTo: newExpres object value detect: [ :objAttribute | "find the matching value attribute" objAttribute attribute == paramAttribute ] - ifFound: [ :objAttribute | - self makeVariableExpression: objAttribute value ] + ifFound: [ :objAttribute | "dispatch for var naming context" + objectExportStrategy + makeVariableExpression: objAttribute value + on: self ] ifNone: [ "the object does not have the attribute set" paramAttribute declaredType asFASTJavaDefaultValueOn: self model ] ]) ] @@ -72,21 +73,16 @@ FamixValue2FASTJavaVisitor >> constructObject: object [ FamixValue2FASTJavaVisitor >> filterAttributesToSet: attributes for: object [ "No need to set attributes that are set in the constructor." - ^ (setterCache at: object type ifAbsentPut: [ - | famixAttributes | - famixAttributes := attributes collect: [ :attribute | - attribute attribute ]. - constructorCache - at: object type - ifPresent: [ :constructor | - constructorCache - at: constructor - ifPresent: [ :constructorAttributes | - famixAttributes difference: constructorAttributes ] - ifAbsent: [ famixAttributes ] ] - ifAbsent: [ famixAttributes ] ]) ifNotEmpty: [ :famixAttributes | - attributes select: [ :attribute | - famixAttributes includes: attribute attribute ] ] + ^ constructorCache + at: object type + ifPresent: [ :constructor | + constructorCache + at: constructor + ifPresent: [ :constructorAttributes | + attributes reject: [ :attribute | + constructorAttributes includes: attribute attribute ] ] + ifAbsent: [ attributes ] ] + ifAbsent: [ attributes ] ] { #category : #private } @@ -136,7 +132,6 @@ FamixValue2FASTJavaVisitor >> findStaticAttributeMatching: object [ FamixValue2FASTJavaVisitor >> initialize [ constructorCache := IdentityDictionary new. - setterCache := IdentityDictionary new. staticAttributesCache := IdentityDictionary new ] @@ -191,49 +186,7 @@ FamixValue2FASTJavaVisitor >> makeHelperClass [ expression: (model newNewExpression type: (model newClassTypeExpression typeName: - (model newTypeName name: 'ObjectMapper')))) }). - (model newMethodEntity - typeParameters: - { (model newTypeParameterExpression name: 'T') }; - type: - (model newClassTypeExpression typeName: - (model newTypeName name: 'T')); - name: 'deserialize'; - parameters: { - (model newParameter - variable: (model newVariableExpression name: 'json'); - type: (model newClassTypeExpression typeName: - (model newTypeName name: 'String'))). - (model newParameter - variable: (model newVariableExpression name: 'clazz'); - type: (model newClassTypeExpression - typeName: (model newTypeName name: 'Class'); - arguments: { (model newClassTypeExpression typeName: - (model newTypeName name: 'T')) })) }; - modifiers: { - (model newModifier token: 'public'). - (model newModifier token: 'static') }; - statementBlock: (model newStatementBlock statements: { - (model newTryCatchStatement - try: (model newStatementBlock statements: - { (model newReturnStatement expression: - (model newMethodInvocation - receiver: (model newIdentifier name: 'mapper'); - name: 'readValue'; - arguments: { - (model newVariableExpression name: 'json'). - (model newVariableExpression name: 'clazz') })) }); - catches: { (model newCatchPartStatement - catchedTypes: - { (model newClassTypeExpression typeName: - (model newTypeName name: 'IOException')) }; - body: (model newStatementBlock statements: - { (model newExpressionStatement expression: - (model newMethodInvocation - receiver: (model newIdentifier name: 'e'); - name: 'printStackTrace')) }); - parameter: (model newVariableExpression name: 'e')) }). - (model newReturnStatement expression: model newNullLiteral) })) } + (model newTypeName name: 'ObjectMapper')))) }) } ] { #category : #ast } @@ -455,20 +408,9 @@ FamixValue2FASTJavaVisitor >> visitObjectOfRegularType: object [ { #category : #visiting } FamixValue2FASTJavaVisitor >> visitObjectStub: object [ + "Previously tried to recreate stubs by deserializing their JSON representation, but getting a correct JSON string is a challenge." - self statementBlock addStatement: (self model newVarDeclStatement - type: (object asFASTJavaTypeExpressionOn: self); - addDeclarator: (self model newVariableDeclarator - variable: (self makeVariableExpression: object); - expression: (model newMethodInvocation - name: 'deserialize'; - arguments: { - (model newStringLiteral primitiveValue: - object asJsonString). - (model newClassProperty - type: (object asFASTJavaTypeExpressionOn: self); - fieldName: 'class') })); - yourself) + self shouldBeImplemented ] { #category : #visiting } diff --git a/src/Famix-Value-Exporter/FamixValue2PharoVisitor.class.st b/src/Famix-Value-Exporter/FamixValue2PharoVisitor.class.st index d9f7652..d4cb92e 100644 --- a/src/Famix-Value-Exporter/FamixValue2PharoVisitor.class.st +++ b/src/Famix-Value-Exporter/FamixValue2PharoVisitor.class.st @@ -1,13 +1,14 @@ " -A visitor for exporting a FamixValue model to the Pharo AST, see `RBEntity` and `RBNode`. +A visitor for exporting a FamixValue model to the Pharo AST, see `RBNode`. Object attributes are initialized by finding the corresponding setters. -Collections and Dictionaries are constructed with the `withAll:` class method. +Collections are constructed using the `withAll:` class method. +Dictionaries are constructed using the `newFrom:` class method. " Class { #name : #FamixValue2PharoVisitor, #superclass : #FamixValue2ASTVisitor, - #category : #'Famix-Value-Exporter' + #category : #'Famix-Value-Exporter-Visitors' } { #category : #visiting } diff --git a/src/Famix-Value-Exporter/FamixValueAbstractObjectExportStrategy.class.st b/src/Famix-Value-Exporter/FamixValueAbstractObjectExportStrategy.class.st index 13b516b..108cdec 100644 --- a/src/Famix-Value-Exporter/FamixValueAbstractObjectExportStrategy.class.st +++ b/src/Famix-Value-Exporter/FamixValueAbstractObjectExportStrategy.class.st @@ -1,3 +1,7 @@ +" +I am a strategy for exporting objects used by the `FamixValue2ASTVisitor` hierarchy of classes. +Objects can be complex to recreate due to deep nesting and circular dependencies, resulting in a lot of code. My subclasses define where that code goes. +" Class { #name : #FamixValueAbstractObjectExportStrategy, #superclass : #Object, diff --git a/src/Famix-Value-Exporter/FamixValueHelperObjectExportStrategy.class.st b/src/Famix-Value-Exporter/FamixValueHelperObjectExportStrategy.class.st index d18b9e3..d5c368e 100644 --- a/src/Famix-Value-Exporter/FamixValueHelperObjectExportStrategy.class.st +++ b/src/Famix-Value-Exporter/FamixValueHelperObjectExportStrategy.class.st @@ -1,3 +1,7 @@ +" +I generate the code to recreate objects in helper functions. +For each object, a dedicated function is generated that takes no arguments and returns the recreated object. +" Class { #name : #FamixValueHelperObjectExportStrategy, #superclass : #FamixValueAbstractObjectExportStrategy, @@ -133,3 +137,11 @@ FamixValueHelperObjectExportStrategy >> makeSetterInvocationsFor: attributes on: named: attribute varName ] ifNil: [ visitor makeReflectionSetterInvocation: attribute ] ] ] + +{ #category : #ast } +FamixValueHelperObjectExportStrategy >> makeVariableExpression: value on: visitor [ + "Used when constructing an object to correctly name the argument variable. + For helpers, the var name is the same as the helper method parameter." + + ^ visitor model newVariableExpression name: value varName +] diff --git a/src/Famix-Value-Exporter/FamixValueInlineObjectExportStrategy.class.st b/src/Famix-Value-Exporter/FamixValueInlineObjectExportStrategy.class.st index 9a49156..2106171 100644 --- a/src/Famix-Value-Exporter/FamixValueInlineObjectExportStrategy.class.st +++ b/src/Famix-Value-Exporter/FamixValueInlineObjectExportStrategy.class.st @@ -1,3 +1,7 @@ +" +I recreate objects inline. +The context of the visitor will contain the code to recreate the objects. +" Class { #name : #FamixValueInlineObjectExportStrategy, #superclass : #FamixValueAbstractObjectExportStrategy, @@ -11,3 +15,11 @@ FamixValueInlineObjectExportStrategy >> export: object on: visitor [ (visitor filterAttributesToSet: object relevantAttributes for: object) do: [ :attribute | visitor visitObjectAttribute: attribute ] ] + +{ #category : #ast } +FamixValueInlineObjectExportStrategy >> makeVariableExpression: value on: visitor [ + "Used when constructing an object to correctly name the argument variable. + When inline, the visitor can handle naming the variable on its own." + + ^ visitor makeVariableExpression: value +]