PetitCommonMark/software/petitcompiler/PPCNodeVisitor.class.st

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
]