Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File encoding #37

Merged
merged 2 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 25 additions & 118 deletions src/FAST-Core-Tools/FASTDifferentialValidator.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -28,122 +28,54 @@ Class {
#superclass : #Object,
#instVars : [
'skipPaths',
'strict'
'comparator',
'encoding'
],
#category : #'FAST-Core-Tools'
#category : #'FAST-Core-Tools-Validator'
}

{ #category : #comparison }
FASTDifferentialValidator >> ast: node1 acceptableDifferenceTo: node2 [
"In non strict mode, some differences could be accepted"

^false
]

{ #category : #comparison }
FASTDifferentialValidator >> ast: node1 acceptableDifferenceTo: node2 property: property [

^#(startPos endPos) includes: property
]

{ #category : #comparison }
FASTDifferentialValidator >> ast: node1 differ: node2 [

self strict ifTrue: [ Exception signal: 'ASTs differ' ].

(self ast: node1 acceptableDifferenceTo: node2)
ifTrue: [
(' ** difference in ignored, position in source: ' , node1 startPos asString)
traceCr.
Notification signal
]
ifFalse: [ Exception signal: 'ASTs differ' ]
]

{ #category : #comparison }
FASTDifferentialValidator >> ast: node1 differ: node2 property: property [

(self ast: node1 acceptableDifferenceTo: node2 property: property)
ifFalse: [ Exception signal: 'ASTs differ on property: ' , property implementingSelector ]
]

{ #category : #configuration }
FASTDifferentialValidator >> beStrict [
{ #category : #accessing }
FASTDifferentialValidator >> comparator [

self strict: true
^comparator ifNil: [ comparator := self comparatorClass new ]
]

{ #category : #utilities }
FASTDifferentialValidator >> childrenNodes: astNode [

^OrderedCollection withAll:
(astNode children sorted: [:a :b | a startPos <= b startPos])
{ #category : #accessing }
FASTDifferentialValidator >> comparatorClass [

^FamixModelComparator
]

{ #category : #comparison }
{ #category : #running }
FASTDifferentialValidator >> compare: node1 to: node2 [
"check the two nodes have the same class
then check they have the same properties (attributes with primitive types)
then check recursively that they ahev the same sub-nodes"

self compareClasses: node1 to: node2.
self compareProperties: node1 to: node2.
self compareChildren: node1 to: node2

self comparator compare: node1 to: node2
]

{ #category : #comparison }
FASTDifferentialValidator >> compareChildren: node1 to: node2 [
"comparing the two lists of children may seem a bit complicate, but it is trying
to give more info when the children starts to differ
For example comparing using #with:collect: gives very little information if the two lists
differ in size"

| size1 children1 size2 children2 |
children1 := self childrenNodes: node1.
children2 := self childrenNodes: node2.

size1 := children1 size.
size2 := children2 size.

1 to: size1 do: [ :i |
size2 < i
ifTrue: [ self ast: (children1 at: i) differ: nil ]
ifFalse: [ self compare: (children1 at: i) to: (children2 at: i) ] ].

children2 size > children1 size ifTrue: [
self ast: nil differ: (children2 at: children1 size + 1) ]
{ #category : #accessing }
FASTDifferentialValidator >> defaultEncoding [
"other possibilities are 'latin1', 'utf8', ...
see `ZnCharacterEncoder knownEncodingIdentifiers` for all possibilities"
^encoding ifNil: [ 'iso-8859-1' ]
]

{ #category : #comparison }
FASTDifferentialValidator >> compareClasses: node1 to: node2 [
{ #category : #accessing }
FASTDifferentialValidator >> encoding [

node1 class = node2 class ifFalse: [
self ast: node1 differ: node2 ]
^encoding
]

{ #category : #comparison }
FASTDifferentialValidator >> compareProperties: node1 to: node2 [
"compare the values of the 'properties' (attributes with primitive types) of the two nodes
since the two nodes should be the same class, they have the same properties"

(node1 class mooseDescription allPrimitiveProperties) do: [ :property || value1 value2 |
(self propertyToCompare: property) ifTrue: [
value1 := node1 perform: property implementingSelector.
value2 := node2 perform: property implementingSelector.

(value1 = value2) ifFalse: [
self ast: node1 differ: node2 property: property
]]
]
{ #category : #accessing }
FASTDifferentialValidator >> encoding: aString [

encoding := aString
]

{ #category : #utilities }
FASTDifferentialValidator >> getASTFromFileReference: aFileReference [

| model |
aFileReference readStreamDo: [ :stream |
aFileReference readStreamEncoded: self defaultEncoding do: [ :stream |
model := self getASTFromString: stream contents ].

^self getTopLevelNodes: model
Expand Down Expand Up @@ -172,7 +104,6 @@ FASTDifferentialValidator >> initialize [

super initialize.

strict := false.
skipPaths := #().
]

Expand All @@ -188,16 +119,6 @@ FASTDifferentialValidator >> on: aDirectoryName [
self runOnFileReference: aDirectoryName asFileReference
]

{ #category : #testing }
FASTDifferentialValidator >> propertyToCompare: aFMProperty [
"do not compare on derived (ie. computed) properties, only those with a stored value
do not compare on startPos/endPos as they are not meaningfull"

aFMProperty isDerived ifTrue: [^false].
(#(startPos endPos) includes: aFMProperty implementingSelector) ifTrue: [^false].
^true
]

{ #category : #utilities }
FASTDifferentialValidator >> reExportAST: ast [

Expand Down Expand Up @@ -241,9 +162,7 @@ FASTDifferentialValidator >> runOnSourceFile: aFileReference [
astBis := self getRootNode:
(self getASTFromString: (self reExportAST: astOrig)).

[self compare: astOrig to: astBis]
on: Notification
do: [ "continue" ]
self compare: astOrig to: astBis
]
]

Expand All @@ -258,15 +177,3 @@ FASTDifferentialValidator >> skipPaths: anObject [

skipPaths := anObject
]

{ #category : #accessing }
FASTDifferentialValidator >> strict [

^ strict
]

{ #category : #accessing }
FASTDifferentialValidator >> strict: anObject [

strict := anObject
]
182 changes: 182 additions & 0 deletions src/FAST-Core-Tools/FamixModelComparator.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
Class {
#name : #FamixModelComparator,
#superclass : #Object,
#instVars : [
'strict'
],
#category : #'FAST-Core-Tools-Validator'
}

{ #category : #comparison }
FamixModelComparator >> ast: node1 acceptableDifferenceTo: node2 [
"In non strict mode, some differences could be accepted"

^false
]

{ #category : #comparison }
FamixModelComparator >> ast: node1 acceptableDifferenceTo: node2 property: property [
"returns nil if the difference is not acceptable
otherwise, must return a block testing where the comparison process might resume"

^nil
]

{ #category : #comparison }
FamixModelComparator >> ast: node1 differ: node2 [

self strict ifTrue: [ self differenceNotResumable ].

(self ast: node1 acceptableDifferenceTo: node2)
ifTrue: [ self differenceResumableInParent ]
ifFalse: [ self differenceNotResumable ]
]

{ #category : #comparison }
FamixModelComparator >> ast: node1 differ: node2 property: property [

self strict ifTrue: [ self differenceNotResumable ].

(self ast: node1 acceptableDifferenceTo: node2 property: property)
ifNil: [ self differenceNotResumable ]
ifNotNil: [ :recovery | self differenceResumableOncondition: recovery ]
]

{ #category : #configuration }
FamixModelComparator >> beStrict [

self strict: true
]

{ #category : #utilities }
FamixModelComparator >> childrenNodes: astNode [

^OrderedCollection withAll:
(astNode children sorted: [:a :b | a startPos <= b startPos])

]

{ #category : #comparison }
FamixModelComparator >> compare: node1 to: node2 [
"check the two nodes have the same class
then check they have the same properties (attributes with primitive types)
then check recursively that they ahev the same sub-nodes

Upon error (differing asts) check a condition,
if it is true, do nothing (ie. resume comparison)
if it is false, resend the exception to be treated up in the calling stack"

[
self compareClasses: node1 to: node2.
self compareProperties: node1 to: node2.
self compareChildren: node1 to: node2
]
on: FamixModelComparatorRecoveryException
do: [ :exception |
(exception condition value: node1 value: node2)
ifFalse: [ exception pass ]
]
]

{ #category : #comparison }
FamixModelComparator >> compareChildren: node1 to: node2 [
"comparing the two lists of children may seem a bit complicate, but it is trying
to give more info when the children starts to differ
For example comparing using #with:collect: gives very little information if the two lists
differ in size"

| size1 children1 size2 children2 |
children1 := self childrenNodes: node1.
children2 := self childrenNodes: node2.

size1 := children1 size.
size2 := children2 size.

1 to: size1 do: [ :i |
size2 < i
ifTrue: [ self ast: (children1 at: i) differ: nil ]
ifFalse: [ self compare: (children1 at: i) to: (children2 at: i) ] ].

children2 size > children1 size ifTrue: [
self ast: nil differ: (children2 at: children1 size + 1) ]
]

{ #category : #comparison }
FamixModelComparator >> compareClasses: node1 to: node2 [

node1 class = node2 class ifFalse: [
self ast: node1 differ: node2 ]
]

{ #category : #comparison }
FamixModelComparator >> compareProperties: node1 to: node2 [
"compare the values of the 'properties' (attributes with primitive types) of the two nodes
since the two nodes should be the same class, they have the same properties"

(node1 class mooseDescription allPrimitiveProperties)
select: [ :property | self propertyToCompare: property ]
thenDo: [ :property || value1 value2 |
value1 := node1 perform: property implementingSelector.
value2 := node2 perform: property implementingSelector.

(value1 = value2) ifFalse: [
self ast: node1 differ: node2 property: property
]
]

]

{ #category : #exceptionbuilder }
FamixModelComparator >> differenceNotResumable [

FamixModelComparatorRecoveryException signal: 'ASTs differ'

]

{ #category : #exceptionbuilder }
FamixModelComparator >> differenceResumableInParent [
"raises an exception with a 'true' condition.
Process will resume in immediate parent"

FamixModelComparatorRecoveryException new
condition: [ :node1 : node2 | true ] ;
signal: 'Overlooking difference in AST'
]

{ #category : #exceptionbuilder }
FamixModelComparator >> differenceResumableOncondition: aBlock [

FamixModelComparatorRecoveryException new
condition: aBlock ;
signal: 'Overlooking difference in AST'
]

{ #category : #initialization }
FamixModelComparator >> initialize [

super initialize.

strict := false.
]

{ #category : #testing }
FamixModelComparator >> propertyToCompare: aFMProperty [
"do not compare on derived (ie. computed) properties, only those with a stored value
do not compare on startPos/endPos as they are not meaningfull"

aFMProperty isDerived ifTrue: [^false].
(#(startPos endPos) includes: aFMProperty implementingSelector) ifTrue: [^false].
^true
]

{ #category : #accessing }
FamixModelComparator >> strict [

^ strict
]

{ #category : #accessing }
FamixModelComparator >> strict: anObject [

strict := anObject
]
Loading
Loading