compiler/tests/PPCNodeFirstFollowNextTests.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Tue, 18 Aug 2015 22:46:10 +0100
changeset 523 09afcf28ed60
parent 464 f6d77fee9811
child 529 439c4057517f
permissions -rw-r--r--
Fixed PEGFsaTransition>>disjunction: - xor: does not take blocks as xor is not subject to lazy evaluation. While in Pharo it worked, it does not work well under Smalltalk/X which does not send value to the passed argument. (partially because xor: is inlined by the stc/JIT compiler)

"{ Package: 'stx:goodies/petitparser/compiler/tests' }"

"{ NameSpace: Smalltalk }"

TestCase subclass:#PPCNodeFirstFollowNextTests
	instanceVariableNames:'tree first node followSet configuration'
	classVariableNames:''
	poolDictionaries:''
	category:'PetitCompiler-Tests-Nodes'
!

PPCNodeFirstFollowNextTests class instanceVariableNames:'first'

"
 The following class instance variables are inherited by this class:

	TestCase - lastOutcomes
	TestAsserter - 
	Object - 
"
!


!PPCNodeFirstFollowNextTests methodsFor:'setup'!

setUp
    configuration := PPCConfiguration default.
    configuration arguments generate: false.
! !

!PPCNodeFirstFollowNextTests methodsFor:'support'!

assert: set anyMatchesType: whatever
    self assert: (set anySatisfy: [:e | e isKindOf: whatever ])
!

assert: set anySatisfy: whateverBlock
    self assert: (set anySatisfy: [:e |  [whateverBlock value: e]  on: Error do: [ false ] ])
!

assert: set noneMatchesType: whatever
    self assert: (set noneSatisfy: [:e | e isKindOf: whatever ])
!

assert: set noneSatisfy: whateverBlock
    self assert: (set noneSatisfy: [:e |  [whateverBlock value: e]  on: Error do: [ false ] ])
!

assert: set size: anInteger
    self assert: (set size = anInteger )
!

first: aNode 
    ^ aNode firstSet
!

first: aNode suchThat: aBlock
    ^ (aNode firstSetsSuchThat: aBlock) at: aNode
!

followOf: name in: rootNode
    node := (rootNode allNodes select: [ :n | n name = name ] )anyOne.
    ^ rootNode followSets at: node
!

followOf: name in: rootNode suchThat: aBlock
    node := (rootNode allNodes select: [ :n | n name = name ] )anyOne.
    ^ (rootNode followSetsSuchThat: aBlock) at: node
!

followOfNodeIn: rootNode
    ^ self followOf: 'node' in: rootNode
!

treeFrom: parser
    ^ parser compileWithConfiguration: configuration
! !

!PPCNodeFirstFollowNextTests methodsFor:'testing - first'!

testFirst1
    tree := self treeFrom: nil asParser / 'a' asParser.
    
    self assert: (self first: tree) anyMatchesType: PPCNilNode.
    self assert: (self first: tree) anyMatchesType: PPCAbstractLiteralNode.
!

testFirst2
    tree := self treeFrom: 'a' asParser optional, 'b' asParser.
    
    self assert: (self first: tree) anySatisfy: [ :e | e literal = 'a' ].
    self assert: (self first: tree) anySatisfy: [ :e | e literal = 'b' ].
!

testFirst3
    tree := ('a' asParser optional, 'b' asParser asParser optional), 'c' asParser.
    
    self assert: (self first: tree) anySatisfy: [ :e | e literal = 'a' ].
    self assert: (self first: tree) anySatisfy: [ :e | e literal = 'b' ].
    self assert: (self first: tree) anySatisfy: [ :e | e literal = 'c' ].
!

testFirstChoice1
    tree := self treeFrom: nil asParser / '' asParser.
    
    self assert: (self first: tree) anySatisfy: [:e | e literal = ''].
    self assert: (self first: tree) anyMatchesType: PPCNilNode.
!

testFirstChoice2
    tree := self treeFrom: 'a' asParser / nil asParser / 'b' asParser.
    
    first := (self first: tree).
    
    self assert: first anySatisfy: [:e | e literal =  'a'].
    self assert: first anySatisfy: [:e | e literal = 'b'].
    self assert: first anyMatchesType: PPCNilNode.
!

testFirstComplex1
    tree := self treeFrom: ('a' asParser / nil asParser), 'c' asParser.
    
    first := (self first: tree).
    
    self assert: first size: 2.
    self assert: first anySatisfy: [:e | e literal = 'a'].
    self assert: first anySatisfy: [:e | e literal = 'c'].
    self assert: first noneMatchesType: PPCNilNode.
!

testFirstComplex2
    tree := self treeFrom: ('a' asParser / nil asParser / 'b' asParser), 'c' asParser.
    
    
    first := (self first: tree).
    
    self assert: first size: 3.
    self assert: first anySatisfy: [:e | e literal = 'a'].
    self assert: first anySatisfy: [:e | e literal = 'b'].
    self assert: first anySatisfy: [:e | e literal = 'c'].
!

testFirstComplex3
    tree := self treeFrom: ('a' asParser / nil asParser / 'b' asParser), 'c' asParser not.
    
    first := (self first: tree).
    
    self assert: first anySatisfy: [:e | e literal = 'a'].
    self assert: first anySatisfy: [:e | e literal = 'b'].
    self assert: first anySatisfy: [:e | (e isKindOf: PPCNotNode) and: [e child literal = 'c']].
!

testFirstComplex4
    tree := self treeFrom: (('a' asParser / nil asParser / 'b' asParser), 'c' asParser not) wrapped.
    
    first := (self first: tree).
    
    self assert: first anySatisfy: [:e | e literal = 'a'].
    self assert: first anySatisfy: [:e | e literal = 'b'].
    self assert: first anySatisfy: [:e | (e isKindOf: PPCNotNode) and: [ e child literal = 'c' ]].
    self assert: first noneMatchesType: PPCNilNode.
!

testFirstNegate1
    configuration arguments specialize: true.
    tree := self treeFrom: ('a' asParser negate, 'b' asParser).
    
    first := self first: tree.

    self assert: first size: 1.
    self assert: first anyMatchesType: PPCNotNode.
    self assert: first anyOne child literal = 'a'.
!

testFirstNot
    tree := self treeFrom: ('a' asParser not star, 'b' asParser).
    
    first := self first: tree.
        
    self assert: first size: 2.
    self assert: first anyMatchesType: PPCNotNode.
    self assert: first anyMatchesType: PPCLiteralNode.
!

testFirstNot2
    configuration arguments specialize: true.
    tree := self treeFrom: (#letter asParser not star, #letter asParser).
    
    first := self first: tree.
        
    self assert: first size: 2.
    self assert: first anyMatchesType: PPCNotNode.
    self assert: first anyMatchesType: PPCPredicateNode.
!

testFirstNot4
    tree := self treeFrom: (#letter asParser negate plus, #letter asParser).
    
    first := self first: tree.
        
    self assert: first size: 1.
    self assert: (first anyOne predicate value: $a) not.
    self assert: (first anyOne predicate value: $1).
!

testFirstNot5
    tree := self treeFrom: (#letter asParser negate star, #letter asParser).
    
    first := self first: tree.
        
    self assert: first size: 2.
    self assert: first anySatisfy: [ :e |	(e predicate value: $a) not ].
    self assert: first anySatisfy: [ :e |	(e predicate value: $1) ].


    self assert: first anySatisfy: [ :e |	(e predicate value: $a) ].
    self assert: first anySatisfy: [ :e |	(e predicate value: $1) not ].
!

testFirstOptional
    tree := 'a' asParser optional asCompilerTree.
    
    first := (self first: tree).
    
    self assert: first anyMatchesType: PPCNilNode.
    self assert: first anyMatchesType: PPCLiteralNode.
!

testFirstOptional2
    tree := ('a' asParser optional, 'b' asParser) asCompilerTree.
    
    first := (self first: tree).
    
    self assert: first size: 2.
    self assert: first anySatisfy: [ :e | e literal = 'a' ].
    self assert: first anySatisfy: [ :e | e literal = 'b' ].
!

testFirstRepeat1
    tree := ('a' asParser / nil asParser) plus asCompilerTree.
    
    first := self first: tree.

    self assert: first anySatisfy: [:e | e literal = 'a' ].
    self assert: first anyMatchesType: PPCNilNode.	
!

testFirstRepeat2
    tree := ('a' asParser star, 'b' asParser) asCompilerTree.
    
    first := self first: tree.

    self assert: first anySatisfy: [:e | e literal = 'a' ].
    self assert: first anySatisfy: [:e | e literal = 'b' ].
!

testFirstRepeat3
    tree := ('a' asParser negate plus, 'b' asParser) asCompilerTree.
    
    first := self first: tree.

    self assert: first size: 1.
    self assert: first anyMatchesType: PPCNotNode.
!

testFirstRepeat4
    tree := ('a' asParser negate star, 'b' asParser) asCompilerTree.
    
    first := self first: tree.

    self assert: first size: 2.
    self assert: first anySatisfy: [:e | (e isKindOf: PPCNotNode) and: [e child literal = 'a']].
    self assert: first anySatisfy: [ :e | e literal = 'b' ]
!

testFirstSequence1
    tree := self treeFrom: 'a' asParser, 'b' asParser .
    
    first := self first: tree.
    
    self assert: first size: 1.
    self assert: first anySatisfy: [ :e | e literal = 'a' ].
!

testFirstSequence2
    tree := nil asParser, 'a' asParser, 'b' asParser .
    
    first := self first: tree.
    
    self assert: first size: 1.
    self assert: first anySatisfy: [ :e | e literal = 'a' ].
!

testFirstSequence3
    tree := self treeFrom: nil asParser, nil asParser.
    
    first := self first: tree.
    
    self assert: first size: 1.
    self assert: first anyMatchesType: PPCNilNode.
!

testFirstSequence4
    tree := self treeFrom: ((nil asParser / 'a' asParser) plus), 'b' asParser.
    
    first := self first: tree.
    
    self assert: first size: 2.
    self assert: first anySatisfy: [ :e | e literal = 'a' ].
    self assert: first anySatisfy: [ :e | e literal = 'b' ].
    self assert: first noneMatchesType: PPCNilNode.
!

testFirstSequence5
    tree := self treeFrom: ((nil asParser / 'a' asParser) star), 'b' asParser.
    
    first := self first: tree.
    
    self assert: first size: 2.
    self assert: first anySatisfy: [ :e | e literal = 'a' ].
    self assert: first anySatisfy: [ :e | e literal = 'b' ].
    self assert: first noneMatchesType: PPCNilNode.
!

testFirstSequence6
    configuration arguments specialize: true.
    tree := self treeFrom: #space asParser star, 'a' asParser.
    
    tree firstFollowCache: nil.
    self should: [ self first: tree. ] raise: Exception.
!

testFirstSequence7
    tree := self treeFrom: #space asParser star, 'a' asParser.
    
    first := self first: tree.
    
    self assert: first size: 2.
    self assert: first anySatisfy: [ :e | e literal = 'a' ].
    self assert: first anyMatchesType: PPCPredicateNode.
!

testFirstStarMessagePredicate
    tree := self treeFrom: #space asParser star.
    
    first := self first: tree.
    
    self assert: first size: 2.
    self assert: first anyMatchesType: PPCMessagePredicateNode.
    self assert: first anyMatchesType: PPCSentinelNode.
!

testFirstStarMessagePredicate2
    configuration arguments specialize: true.
    tree := self treeFrom: #space asParser star.
    
    first := self first: tree.
    
    self assert: first size: 2.
    self assert: first anyMatchesType: PPCMessagePredicateNode.
    self assert: first anyMatchesType: PPCSentinelNode.
    
    
!

testFirstTerminal
    configuration arguments specialize: true.
    tree := self treeFrom: 'a' asParser not.

    first := self first: tree.
    
    self assert: first size: 1.
    self assert: (self first: tree) anyMatchesType: PPCNotLiteralNode.
!

testFirstTerminal2
    tree := self treeFrom: 'a' asParser and.
    
    first := self first: tree.
    
    self assert: first size: 1.
    self assert: first anySatisfy: [: e | e literal = 'a' ]
!

testFirstTrim
    tree := self treeFrom: 'a' asParser trim.

    first := self first: tree.
    
    self assert: first size: 2.
    self assert: first anyMatchesType: PPCLiteralNode.
    self assert: first anyMatchesType: PPCMessagePredicateNode.
!

testFirstTrimmingToken
    tree := self treeFrom: 'a' asParser token trim.

    first := self first: tree.
    
    self assert: first size: 1.
    self assert: (self first: tree) anyMatchesType: PPCLiteralNode.
! !

!PPCNodeFirstFollowNextTests methodsFor:'testing - first production'!

testFirstProduction1
    tree := self treeFrom: ('a' asParser name: 'a'; yourself), 'b' asParser .
    
    first := tree firstSetWithProductions.
    
    self assert: first size: 1.
    self assert: first anySatisfy: [ :e | e literal = 'a' ].
!

testFirstProduction2
    tree := self treeFrom: ('a' asParser name: nil; yourself), 'b' asParser .
    
    first := tree firstSetWithProductions.
    
    self assert: first isEmpty.
!

testFirstProduction3
    | foo bar |
    foo := 'foo' asParser name: 'foo'; yourself.
    bar := 'bar' asParser.
    
    tree := self treeFrom: (foo, bar) / foo.
    
    first := tree firstSetWithProductions.
    
    self assert: first size = 1.
    self assert: first anyOne name = 'foo'.
! !

!PPCNodeFirstFollowNextTests methodsFor:'testing - first tokens'!

testFirstTokenStar
    | token  |
    token := '.' asParser token.
    
    tree := self treeFrom: token star.
    
    first := tree firstSetWithTokens.
    self assert: first size = 2.
    self assert: first anySatisfy: [ :e | e isTokenNode ].
    self assert: first anySatisfy: [ :e | e = PPCSentinelNode instance ].
! !

!PPCNodeFirstFollowNextTests methodsFor:'testing - follow'!

testFollowSet1
    node := 'a' asParser name: 'node'; yourself.
    tree := self treeFrom: (node star, 'b' asParser).
    
    followSet := self followOfNodeIn: tree.
    
    self assert: followSet size: 2.
    self assert: followSet anySatisfy: [:e | e literal = 'a'].
    self assert: followSet anySatisfy: [:e | e literal = 'b'].
!

testFollowSet10
    | a b c |
    
    a := 'a' asParser name: 'a'; yourself.
    b := 'b' asParser optional name: 'b'; yourself.
    c := 'c' asParser name: 'c'; yourself.
    
    
        
    tree := self treeFrom: a plus, b, c.

    followSet := self followOf: 'a' in: tree.

    self assert: followSet size: 3.
    self assert: followSet anySatisfy: [:e | e literal = 'a' ].	
    self assert: followSet anySatisfy: [:e | e literal =  'b' ].
    self assert: followSet anySatisfy: [:e | e literal = 'c' ].
!

testFollowSet2
    | follow |
    node := 'a' asParser name: 'node'; yourself.
    follow := 'b' asParser, 'c' asParser.
    
    tree := self treeFrom: (node, follow).

    followSet := self followOfNodeIn: tree.

    self assert: followSet size: 1.
    self assert: followSet anySatisfy: [:e | e literal = 'b'].
    self assert: followSet noneSatisfy: [:e | e literal = 'c'].	
!

testFollowSet3
    | follow |

    node := 'a' asParser name: 'node'; yourself.
    follow := ('b' asParser, 'c' asParser) / ('d' asParser).
    
    
    tree := self treeFrom: (node, follow).

    followSet := self followOfNodeIn: tree.

    self assert: followSet size: 2.
    self assert: followSet anySatisfy: [:e | e literal = 'b' ].
    self assert: followSet anySatisfy: [:e | e literal = 'd' ].
!

testFollowSet4
    | follow |

    node := 'a' asParser name: 'node'; yourself.
    follow := ('b' asParser, 'c' asParser).
    
    
    tree := self treeFrom: (node star, follow).

    followSet := self followOfNodeIn: tree.

    self assert: followSet anySatisfy: [:e | e literal = 'b' ].
    self assert: followSet anySatisfy: [:e | e literal = 'a' ].
!

testFollowSet5
    | follow1 follow2 |

    node := 'a' asParser name: 'node'; yourself.
    follow1 := ('b' asParser, 'c' asParser) / nil asParser.
    follow2 := 'd' asParser.
    
    
    tree := self treeFrom: (node, follow1, follow2).

    followSet := self followOfNodeIn: tree.

    self assert: followSet anySatisfy: [:e | e literal = 'b' ].
    self assert: followSet anySatisfy: [:e | e literal = 'd' ].
!

testFollowSet6
    | follow follow1 follow2 |

    node := 'a' asParser name: 'node'; yourself.
    follow1 := ('b' asParser, 'c' asParser) / nil asParser.
    follow2 := 'd' asParser.
    
    follow := (follow1, follow2).
    
    tree  := self treeFrom: (node, follow).

    followSet := self followOfNodeIn: tree.

    self assert: followSet anySatisfy: [:e | e literal = 'b' ].
    self assert: followSet anySatisfy: [:e | e literal = 'd' ].
!

testFollowSet7
    |  r1 r2 follow1 follow2 |

    node := 'a' asParser name: 'node'; yourself.
    follow1 := ('b' asParser, 'c' asParser) / nil asParser.
    follow2 := 'd' asParser / nil asParser .
    
    r1 := (node, follow1).
    r2 := (r1, follow2).
    
    tree  := self treeFrom: r2.

    followSet := self followOfNodeIn: tree.

    self assert: followSet anySatisfy: [:e | e literal = 'b' ].
    self assert: followSet anySatisfy: [:e | e literal = 'd' ].
!

testFollowSet8
    node := 'a' asParser name: 'node'; yourself.
    tree := self treeFrom: node.
    
    followSet := self followOfNodeIn: tree.

    self assert: followSet anyMatchesType: PPCNilNode.
!

testFollowSet9
    | a b c |
    
    a := 'a' asParser name: 'a'; yourself.
    b := 'b' asParser optional name: 'b'; yourself.
    c := 'c' asParser name: 'c'; yourself.
    
    
    tree := self treeFrom: a, b, c.
    followSet := self followOf: 'c' in: tree.
    self assert: followSet anyMatchesType: PPCNilNode.
    
    followSet := self followOf: 'b' in: tree.
    self assert: followSet anySatisfy: [:e | e literal = 'c' ].

    followSet := self followOf: 'a' in: tree.
    self assert: followSet anySatisfy: [:e | e literal = 'b' ].
    self assert: followSet anySatisfy: [:e | e literal = 'c' ].
!

testFollowSetChoice1
    | follow |

    node := 'a' asParser name: 'node'; yourself.
    follow := 'b' asParser / 'c' asParser .
    
    tree := self treeFrom: node, follow.

    followSet := self followOfNodeIn: tree.

    self assert: followSet size: 2.	
    self assert: followSet anySatisfy: [:e | e literal = 'b' ].
    self assert: followSet anySatisfy: [:e | e literal = 'c' ].
!

testFollowSetOptional1
    |  follow1 follow2 |

    node := 'a' asParser name: 'node'; yourself.
    follow1 := 'b' asParser optional.
    follow2 := 'c' asParser.
    
    tree := self treeFrom: node, follow1, follow2.

    followSet := self followOfNodeIn: tree.

    self assert: followSet size: 2.
    self assert: followSet anySatisfy: [:e | e literal = 'b'].
    self assert: followSet anySatisfy: [:e | e literal = 'c'].
!

testFollowSetRepeat1

    node := 'a' asParser name: 'node'; yourself.
    tree := self treeFrom: node plus.
    
    followSet := self followOfNodeIn: tree.
    
    self assert: followSet anySatisfy: [:e | e literal = 'a' ].
    self assert: followSet anyMatchesType: PPCNilNode
!

testFollowSetRepeat2

    node := 'a' asParser.
    tree := self treeFrom: (node plus name: 'node'; yourself).
    
    followSet := self followOfNodeIn: tree.
    
    self assert: followSet size: 1.
    self assert: followSet anyMatchesType: PPCNilNode
!

testFollowTrimmingToken
    | token1 token2 |
    configuration arguments specialize: false.
    token1 := #letter asParser plus trimmingToken name: 'token1'; yourself.
    token2 := #letter asParser plus trimmingToken name: 'token2'; yourself.
    
    
    tree := self treeFrom: token1, token2.
    followSet := self 	followOf: 'token1' 
                            in: tree 
                            suchThat: [:e | e isFirstSetTerminal or: [e isKindOf: PPCTrimmingTokenNode ]].

    self assert: followSet size: 1.
    self assert: followSet anyMatchesType: PPCTrimmingTokenNode. 
! !

!PPCNodeFirstFollowNextTests class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
! !