diff --git a/src/FAST-Core-Tools/FASTAbstractDifferentialValidator.class.st b/src/FAST-Core-Tools/FASTAbstractDifferentialValidator.class.st new file mode 100644 index 0000000..d232a12 --- /dev/null +++ b/src/FAST-Core-Tools/FASTAbstractDifferentialValidator.class.st @@ -0,0 +1,101 @@ +" +I help checking the completness of FAST meta-model + +## Process + +For this: +- I go through all source files in a file hierarchy +- I extract a FAST model for each source file +- I re-export the source code from the FAST model +- I extract a new FAST model from the new code, and +- finally I compare the 2 FAST models (they should be the same) + +## Caveat + +This is not full-proof +- Some ASTs can be different and the code be ""the same"" for example `a + b + c` usually has different AST from `a + (b + c)` +- properties of nodes are currently not tested, so `a==b` is considered equal to `a!=b` because the #operator is not tested + +## Configuration + +There is a setting strict/not-strict (not by default) that allows to accept some minor AST differences (see above) +For this, a suitable `acceptableAST:differentFrom:` method should be defined that will receive 2 differeing nodes (one in each AST) and must decide whether the difference is acceptable + +There is a `skipPaths` list to allow skiping some paths in the main file directory +" +Class { + #name : #FASTAbstractDifferentialValidator, + #superclass : #FASTAbstractValidator, + #instVars : [ + 'comparator' + ], + #category : #'FAST-Core-Tools-Validator' +} + +{ #category : #accessing } +FASTAbstractDifferentialValidator >> comparator [ + + ^comparator ifNil: [ comparator := self comparatorClass new ] +] + +{ #category : #accessing } +FASTAbstractDifferentialValidator >> comparatorClass [ + + ^FamixModelComparator +] + +{ #category : #running } +FASTAbstractDifferentialValidator >> compare: node1 to: node2 [ + + self comparator compare: node1 to: node2 +] + +{ #category : #utilities } +FASTAbstractDifferentialValidator >> getASTFromFileReference: aFileReference [ + + ^self getTopLevelNodes: (super getASTFromFileReference: aFileReference) +] + +{ #category : #utilities } +FASTAbstractDifferentialValidator >> getRootNode: aModel [ + + ^aModel detect: [ : e | e allParents isEmpty ] +] + +{ #category : #utilities } +FASTAbstractDifferentialValidator >> getTopLevelNodes: model [ + + self subclassResponsibility +] + +{ #category : #utilities } +FASTAbstractDifferentialValidator >> reExportAST: ast [ + + self subclassResponsibility +] + +{ #category : #running } +FASTAbstractDifferentialValidator >> runOnSourceFile: aFileReference [ + + | astOrig astBis topLevelNodes | + aFileReference fullName traceCr. + + topLevelNodes := [ + self getASTFromFileReference: aFileReference + ] + on: Error + do: [ + ' ** NOT PARSEABLE **' traceCr. + "Note: If we cannot get the original AST, no use to try to regenerate it" + #() + ]. + + topLevelNodes ifNotEmpty: [ + + astOrig := self getRootNode: topLevelNodes. + astBis := self getRootNode: + (self getASTFromString: (self reExportAST: astOrig)). + + self compare: astOrig to: astBis + ] +] diff --git a/src/FAST-Core-Tools/FASTAbstractValidator.class.st b/src/FAST-Core-Tools/FASTAbstractValidator.class.st new file mode 100644 index 0000000..38ea112 --- /dev/null +++ b/src/FAST-Core-Tools/FASTAbstractValidator.class.st @@ -0,0 +1,103 @@ +Class { + #name : #FASTAbstractValidator, + #superclass : #Object, + #instVars : [ + 'skipPaths', + 'encoding' + ], + #category : #'FAST-Core-Tools-Validator' +} + +{ #category : #accessing } +FASTAbstractValidator >> defaultEncoding [ + "other possibilities are 'latin1', 'utf8', ... + see `ZnCharacterEncoder knownEncodingIdentifiers` for all possibilities" + ^encoding ifNil: [ 'iso-8859-1' ] +] + +{ #category : #accessing } +FASTAbstractValidator >> encoding [ + + ^encoding +] + +{ #category : #accessing } +FASTAbstractValidator >> encoding: aString [ + + encoding := aString +] + +{ #category : #utilities } +FASTAbstractValidator >> getASTFromFileReference: aFileReference [ + + ^aFileReference readStreamEncoded: self defaultEncoding do: [ :stream | + self getASTFromString: stream contents ] + +] + +{ #category : #utilities } +FASTAbstractValidator >> getASTFromString: stream [ + + self subclassResponsibility +] + +{ #category : #initialization } +FASTAbstractValidator >> initialize [ + + super initialize. + + skipPaths := #(). +] + +{ #category : #testing } +FASTAbstractValidator >> isSourceFile: aFileReference [ + + self subclassResponsibility +] + +{ #category : #'instance creation' } +FASTAbstractValidator >> on: aDirectoryName [ + + self runOnFileReference: aDirectoryName asFileReference +] + +{ #category : #running } +FASTAbstractValidator >> runOnDirectory: aDirectory [ + + aDirectory isDirectory + ifFalse: [ Exception signal: aDirectory fullName , ' not a directory' ]. + + aDirectory children do: [ :fileRef | self runOnFileReference: fileRef ] +] + +{ #category : #running } +FASTAbstractValidator >> runOnFileReference: aFileReference [ + + (self skipPaths includes: aFileReference fullName) + ifTrue: [ ^self ]. + + aFileReference isDirectory + ifTrue: [ ^self runOnDirectory: aFileReference ]. + + (self isSourceFile: aFileReference) + ifTrue: [ ^self runOnSourceFile: aFileReference ]. + +] + +{ #category : #testing } +FASTAbstractValidator >> runOnSourceFile: aFileReference [ + + self subclassResponsibility +] + +{ #category : #accessing } +FASTAbstractValidator >> skipPaths [ + + ^ skipPaths +] + +{ #category : #accessing } +FASTAbstractValidator >> skipPaths: anObject [ + + skipPaths := anObject +]