439 lines
9.4 KiB
Smalltalk
439 lines
9.4 KiB
Smalltalk
"
|
|
Default Node Visitor. I am DFS visitor, I do traverse by default all the children of a node from left to right. This is implemented in visitNode: visitChildren: methods. On the other hand, my subclasses are more than free to redesign this traversing strategy.
|
|
|
|
I have some cool features as well:
|
|
|
|
1) I do keep the close set. After I visit node, I cache the return value and later I can detect cached value and return it without visiting the node again.
|
|
|
|
2) I do keep open set. So I can detect cycles. I do even fire a message openDetected in order to allow my children to react to this.
|
|
|
|
3) I do keep forbidden set. This set say, that these nodes are not allowed to be visited. This might get sometimes handy to detect some unwanted structures
|
|
"
|
|
Class {
|
|
#name : 'PPCNodeVisitor',
|
|
#superclass : 'Object',
|
|
#instVars : [
|
|
'openSet',
|
|
'closeSet',
|
|
'cache',
|
|
'forbiddenSet'
|
|
],
|
|
#category : 'PetitCompiler-Visitors'
|
|
}
|
|
|
|
{ #category : 'instance creation' }
|
|
PPCNodeVisitor class >> new [
|
|
^ self basicNew initialize
|
|
]
|
|
|
|
{ #category : 'hooks' }
|
|
PPCNodeVisitor >> afterAccept: node retval: retval [
|
|
self cache: node value: retval.
|
|
^ retval
|
|
]
|
|
|
|
{ #category : 'hooks' }
|
|
PPCNodeVisitor >> beforeAccept: node [
|
|
"nothing to do"
|
|
(forbiddenSet includes: node) ifTrue: [ self error: 'visiting forbidden node!' ]
|
|
]
|
|
|
|
{ #category : 'traversing - caching' }
|
|
PPCNodeVisitor >> cache: node value: retval [
|
|
self cache: node value: retval ifPresent: [ :e | self error: 'already cached' ]
|
|
]
|
|
|
|
{ #category : 'traversing - caching' }
|
|
PPCNodeVisitor >> cache: node value: retval ifPresent: block [
|
|
(cache includesKey: node) ifTrue: [ block value: (self cachedValue: node) ].
|
|
|
|
cache at: node put: retval
|
|
]
|
|
|
|
{ #category : 'hooks' }
|
|
PPCNodeVisitor >> cachedDetected: node [
|
|
^ self cachedValue: node
|
|
]
|
|
|
|
{ #category : 'traversing - caching' }
|
|
PPCNodeVisitor >> cachedValue: node [
|
|
^ cache at: node
|
|
]
|
|
|
|
{ #category : 'traversing' }
|
|
PPCNodeVisitor >> close: node [
|
|
| last |
|
|
self assert: (self isOpen: node) description: 'should be opened first!'.
|
|
openSet size > 500 ifTrue: [ self error: 'This seems to be a bit too much, isnt it?' ].
|
|
|
|
last := openSet removeLast.
|
|
self assert: last == node.
|
|
closeSet add: node
|
|
]
|
|
|
|
{ #category : 'hooks' }
|
|
PPCNodeVisitor >> closedDetected: node [
|
|
^ #closed
|
|
]
|
|
|
|
{ #category : 'accessing' }
|
|
PPCNodeVisitor >> forbiddenSet [
|
|
^ forbiddenSet
|
|
]
|
|
|
|
{ #category : 'accessing' }
|
|
PPCNodeVisitor >> forbiddenSet: anObject [
|
|
forbiddenSet := anObject
|
|
]
|
|
|
|
{ #category : 'initialization' }
|
|
PPCNodeVisitor >> initialize [
|
|
super initialize.
|
|
openSet := OrderedCollection new.
|
|
closeSet := IdentitySet new.
|
|
cache := IdentityDictionary new.
|
|
forbiddenSet := IdentitySet new.
|
|
]
|
|
|
|
{ #category : 'traversing - caching' }
|
|
PPCNodeVisitor >> isCached: node [
|
|
^ cache includesKey: node
|
|
]
|
|
|
|
{ #category : 'traversing' }
|
|
PPCNodeVisitor >> isClosed: child [
|
|
^ closeSet includes: child
|
|
]
|
|
|
|
{ #category : 'traversing' }
|
|
PPCNodeVisitor >> isOpen: child [
|
|
^ openSet contains: [ :e | e == child ]
|
|
]
|
|
|
|
{ #category : 'traversing' }
|
|
PPCNodeVisitor >> open: node [
|
|
self assert: (self isOpen: node) not description: 'already opened!'.
|
|
openSet size > 200 ifTrue: [ self error: 'This seems to be a bit too much, isnt it?' ].
|
|
openSet addLast: node
|
|
]
|
|
|
|
{ #category : 'hooks' }
|
|
PPCNodeVisitor >> openDetected: node [
|
|
^ #open
|
|
]
|
|
|
|
{ #category : 'traversing' }
|
|
PPCNodeVisitor >> visit: node [
|
|
| retval |
|
|
(self isOpen: node) ifTrue: [
|
|
^ self openDetected: node
|
|
].
|
|
|
|
(self isCached: node) ifTrue: [
|
|
^ self cachedDetected: node.
|
|
].
|
|
|
|
(self isClosed: node) ifTrue: [
|
|
self closedDetected: node
|
|
].
|
|
|
|
self open: node.
|
|
self beforeAccept: node.
|
|
retval := node accept: self.
|
|
retval := self afterAccept: node retval: retval.
|
|
self close: node.
|
|
|
|
^ retval
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitActionNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitAlignOLNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitAndNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitAnyNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitCharSetPredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitCharacterNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'traversing' }
|
|
PPCNodeVisitor >> visitChildren: node [
|
|
node children do: [ :child |
|
|
self visit: child
|
|
]
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitChoiceNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitColumnNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitDeterministicChoiceNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitEndOfFileNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitEndOfInputNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitFailingNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitForwardNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitIslandNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitLL1ChoiceNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitLiteralNode: node [
|
|
"default implementation"
|
|
^ self visitNode: node.
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitMappedActionNode: node [
|
|
^ self visitActionNode: node
|
|
|
|
"Created: / 02-06-2015 / 17:28:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitMessagePredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitNilNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'traversing' }
|
|
PPCNodeVisitor >> visitNode: node [
|
|
self visitChildren: node.
|
|
^ node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitNonEmptyNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitNotCharSetPredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitNotCharacterNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitNotLiteralNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitNotMessagePredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitNotNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitOptionalNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitPluggableNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitPlusMessagePredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitPlusNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitPopNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitPredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitPushNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitRecognizingSequenceNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitSequenceNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitStarAnyNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitStarCharSetPredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitStarMessagePredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitStarNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitSymbolActionNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenActionNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenChoiceNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenConsumeNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenOLNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenPlusMessagePredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenPlusNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenStarCharSetPredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenStarMessagePredicateNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenStarSeparatorNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenWhitespaceNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTokenizingParserNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTrimNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTrimmingTokenCharacterNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitTrimmingTokenNode: node [
|
|
^ self visitNode: node
|
|
]
|
|
|
|
{ #category : 'visiting' }
|
|
PPCNodeVisitor >> visitUnknownNode: node [
|
|
^ self visitNode: node
|
|
]
|