PetitCommonMark/software/petitcompiler/PPCMergingVisitor.class.st

85 lines
2.2 KiB
Smalltalk

"
As I traverste the graph, I find equivalent nodes and I merge the equivalent nodes under the single one.
This saves compiler time, number of instance variables needed and makes compiled class more compact.
I am using `node:equals:` because of performance (I do cache allNodes) which took too much time to constantly compute...
"
Class {
#name : 'PPCMergingVisitor',
#superclass : 'PPCRewritingVisitor',
#instVars : [
'nodeSet',
'childrenCache'
],
#category : 'PetitCompiler-Visitors'
}
{ #category : 'children cache' }
PPCMergingVisitor >> cachedChildren: node [
^ childrenCache at: node ifAbsentPut: [
node dfsOrder
]
]
{ #category : 'node comparison' }
PPCMergingVisitor >> equivalentNode: node [
self halt: 'not used?'.
^ nodeSet detect: [ :e | self node: e equals: node ]
]
{ #category : 'node comparison' }
PPCMergingVisitor >> equivalentNode: node ifNone: block [
^ nodeSet detect: [ :e | self node: e equals: node ] ifNone: block
]
{ #category : 'node comparison' }
PPCMergingVisitor >> hasEquivalentNode: node [
^ nodeSet contains: [ :e | self node: e equals: node ]
]
{ #category : 'initialization' }
PPCMergingVisitor >> initialize [
super initialize.
"Though this is IdentitySet, I do assert node:equals: befoere inserting node into the set"
nodeSet := IdentitySet new.
childrenCache := IdentityDictionary new.
]
{ #category : 'node comparison' }
PPCMergingVisitor >> node: node equals: anotherNode [
| children anotherChildren |
(node equals: anotherNode) ifFalse: [ ^ false ].
children := self cachedChildren: node.
anotherChildren := self cachedChildren: anotherNode.
(children size = anotherChildren size) ifFalse: [ ^ false ].
children with: anotherChildren do: [ :n1 :n2 |
(n1 equals: n2) ifFalse: [ ^ false ]
].
^ true
]
{ #category : 'node comparison' }
PPCMergingVisitor >> store: node [
self assert: (self hasEquivalentNode: node) not.
nodeSet add: node
]
{ #category : 'traversing' }
PPCMergingVisitor >> visitNode: node [
| equivalent |
"merge the conntent of the node"
super visitNode: node.
(equivalent := self equivalentNode: node ifNone: nil ) isNil ifFalse: [
self cache: node value: equivalent.
^ equivalent
].
self store: node.
^ node
]