" 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 " ] { #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 ]