compiler/tests/PPCNodeCompilingTest.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Sun, 26 Oct 2014 01:03:31 +0000
changeset 391 553a5456963b
child 396 ec569977267a
permissions -rw-r--r--
Ported PetitCompiler-(Tests). Name: PetitCompiler-JanKurs.41 Author: JanKurs Time: 25-10-2014, 03:30:28 AM UUID: 105186d1-1187-4ca6-8d66-3d2d47def4d3 Repository: http://smalltalkhub.com/mc/JanKurs/PetitParser/main Name: PetitCompiler-Tests-JanKurs.4 Author: JanKurs Time: 25-10-2014, 03:30:58 AM UUID: 3e798fad-d5f6-4881-a583-f0bbffe27869 Repository: http://smalltalkhub.com/mc/JanKurs/PetitParser/main In addition, fixed some problems to make it compilable under Smalltalk/X: * Fixed PPCTokenNode>>initialize - there's no children instvar, it's initialization removed. * Fixed PPCContextMemento>>propertyAt:ifAbsent: - removed return-in-return, not compilable under Smalltalk/X (C issues) * Fixed PPCContextMemento>>hash - there's no stream instvar, access to it removed. * Fixed PPCAbstractCharacterNode>>compileWith:effect:id: - removed dot after method selector (stc does not like it)

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

PPAbstractParserTest subclass:#PPCNodeCompilingTest
	instanceVariableNames:'parser context tree result'
	classVariableNames:''
	poolDictionaries:''
	category:'PetitCompiler-Tests-Nodes'
!

!PPCNodeCompilingTest methodsFor:'context'!

context	
	^ context := PPCProfilingContext new
! !

!PPCNodeCompilingTest methodsFor:'test support'!

assert: whatever parse: input
	result := super assert: whatever parse: input.
!

compileTree: root 
	^ self compileTree: root params: #()
!

compileTree: root params: params
	| compiler mock |
	compiler := PPCCompiler new.
	compiler profile: true.
	mock := nil asParser.
	^ (compiler compileTree: root as: #PPGeneratedParser parser: mock params: params) new.
! !

!PPCNodeCompilingTest methodsFor:'tests - compiling'!

testCompileAction
	tree := PPCActionNode new
		block: [ :res | res collect: [:each | each asUppercase ]];
		child: #letter asParser plus asCompilerTree;
		yourself.
	parser := self compileTree: tree.
			
	self assert: parser parse: 'foo' to: { $F . $O . $O}.
	self assert: parser parse: 'bar' to: { $B . $A . $R}.
	self assert: parser fail: ''.
!

testCompileAnd
	tree := PPCAndNode new
		child: #digit asParser asCompilerNode;
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: '1' to: $1 end: 0.
	self assert: parser fail: 'a'.
	self assert: parser fail: ''.
!

testCompileAny
	tree := PPCAnyNode new.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'a' to: $a.
	self assert: parser parse: '_' to: $_.
	self assert: parser parse: '
' to: Character cr.
!

testCompileCharSetPredicate
	tree := PPCCharSetPredicateNode new 
		predicate: (PPCharSetPredicate on: [ :e | e = $a ]);
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'a'  to: $a.
	self assert: parser fail: 'b'.
!

testCompileCharacter
	tree := PPCCharacterNode new character: $a; yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'a'  to: $a.
	self assert: parser fail: 'b'.

	parser := self compileTree: (PPCCharacterNode new character: $#; yourself).
	self assert: parser parse: '#'.

	parser := self compileTree: (PPCCharacterNode new character: Character lf; yourself).
	self assert: parser parse: String lf.
!

testCompileChoice
	tree := PPCChoiceNode new
		children: { #digit asParser asCompilerNode. #letter asParser asCompilerNode };
		yourself.
		
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 4.
	
	self assert: parser parse: '1' to: $1.
	self assert: parser parse: 'a' to: $a.
	self assert: parser fail: '_'.
!

testCompileLiteral
	tree := PPCLiteralNode new
		literal: 'foo';
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 2.
	self assert: parser parse: 'foo'  to: 'foo'.
	self assert: parser parse: 'foobar'  to: 'foo' end: 3.
	self assert: parser fail: 'boo'.
!

testCompileLiteral2
	|  |
	
	tree := PPCLiteralNode new
		literal: '''''';
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: ''''''  to: ''''''.
!

testCompileNil
	tree := PPCNilNode new.
	
	parser := self compileTree: tree.
	
	self assert: parser parse: 'a' to: nil end: 0.
	self assert: parser parse: '' to: nil end: 0.
!

testCompileNot
	tree := PPCNotNode new
		child: #digit asParser asCompilerNode;
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'a' to: nil end: 0.
	self assert: parser fail: '1'.
	self assert: parser parse: '' to: nil end: 0.
!

testCompileNotCharSetPredicate
	tree := PPCNotCharSetPredicateNode new
		predicate: (PPCharSetPredicate on: [ :e | e = $a ]);
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 2.
	self assert: parser parse: 'b' to: nil end: 0.
	self assert: context invocationCount = 2.
		
	self assert: parser fail: 'a'.
	self assert: parser parse: '' to: nil end: 0.
!

testCompileNotLiteral
	tree := PPCNotLiteralNode new
		literal: 'foo';
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 2.
	self assert: parser parse: 'bar' to: nil end: 0.
	self assert: context invocationCount = 2.
		
	self assert: parser fail: 'foo'.
	self assert: parser parse: '' to: nil end: 0.
!

testCompileNotMessagePredicate
	tree := PPCNotMessagePredicateNode new
		message: #isDigit;
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 2.
	self assert: parser parse: 'a' to: nil end: 0.
	self assert: context invocationCount = 2.
		
	self assert: parser fail: '1'.
	self assert: parser parse: '' to: nil end: 0.
!

testCompileOptional
	tree := PPCOptionalNode new
		child: ($a asParser asCompilerNode);
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'b' to: nil end: 0.
	self assert: parser parse: 'a' to: $a.
	self assert: parser parse: '' to: nil end: 0.
!

testCompilePluggable
	tree := PPCPluggableNode new
		block: [:ctx | ctx next ];
		yourself.
	parser := self compileTree: tree.
		
	self assert: parser parse: 'foo' to: $f end: 1.
	self assert: parser parse: 'bar' to: $b end: 1.
	self assert: parser parse: '' to: nil.
!

testCompilePlus
	tree := PPCPlusNode new
		child: ($a asParser asCompilerNode);
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'aaa' to: #($a $a $a) end: 3.
	self assert: parser parse: 'ab' to: #( $a ) end: 1.
	self assert: parser fail: 'b'.
!

testCompileSequence
	tree := PPCSequenceNode new
		children: {  $a asParser asCompilerNode . $b asParser asCompilerNode . $c asParser asCompilerNode  }
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'abc' to: #($a $b $c) end: 3.
	self assert: parser parse: 'abcd' to: #( $a $b $c ) end: 3.
	self assert: parser fail: 'ab'.
!

testCompileStar
	tree := PPCStarNode new
		child: ($a asParser asCompilerNode);
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'aaa' to: #($a $a $a) end: 3.
	self assert: parser parse: 'ab' to: #( $a ) end: 1.
	self assert: parser parse: 'b' to: #( ) end: 0.
!

testCompileStarAny
	tree := PPCStarAnyNode new.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'abc' to: #($a $b $c).
	self assert: parser parse: 'a' to: #($a).
	self assert: parser parse: '' to: #().
!

testCompileStarCharSetPredicate
	tree := PPCStarCharSetPredicateNode new
		predicate: (PPCharSetPredicate on: [:e | e = $a ]);
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 2.
	self assert: parser parse: 'aaa1' to: #( $a $a $a) end: 3.
	self assert: context invocationCount = 2.
	self assert: parser parse: 'bba' to: #() end: 0.
	self assert: context invocationCount = 2.
	
!

testCompileStarMessagePredicate
	tree := PPCStarMessagePredicateNode new
		message: #isLetter;
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 2.
	self assert: parser parse: 'abc1' to: #( $a $b $c) end: 3.
	self assert: context invocationCount = 2.
	
	self assert: parser parse: '123a' to: #() end: 0.
	self assert: context invocationCount = 2.
	
!

testCompileSymbolAction
	tree := PPCSymbolActionNode new
		block: #second;
		child: #letter asParser plus asCompilerTree;
		yourself.
	parser := self compileTree: tree.
		
	self assert: parser parse: 'foo' to: $o.
	self assert: parser parse: 'bar' to: $a.
	self assert: parser fail: ''.
!

testCompileToken
	tree := PPCTokenNode new
		child: #letter asParser plus asCompilerTree;
		tokenClass: PPToken;
		yourself.
	
	parser := self compileTree: tree.
	
	self assert: parser parse: 'abc'.
	self assert: result class = PPToken.
	self assert: result inputValue = 'abc'.

	self assert: parser fail: '1a'.
!

testCompileTokenSequence
	tree := PPCTokenSequenceNode new.
	tree children: { #digit asParser asCompilerNode. #letter asParser asCompilerNode }.

	parser := self compileTree: tree.
	
	self assert: parser parse: '1a' to: parser.
	self assert: context rememberCount = 0.
	self assert: context lwRememberCount = 1.
	self assert: context restoreCount = 0.
	self assert: context lwRestoreCount = 0.
	
	self assert: parser parse: '1ab' to: parser end: 2.
	self assert: context lwRememberCount = 1.
	self assert: context lwRestoreCount = 0.

	self assert: parser fail: 'a1'. 	
	self assert: context lwRememberCount = 1.
	self assert: context lwRestoreCount = 0.

	self assert: parser fail: 'aa'. 	
	self assert: context lwRememberCount = 1.
	self assert: context lwRestoreCount = 0.

	self assert: parser fail: '11'. 	
	self assert: context lwRememberCount = 1.
	self assert: context lwRestoreCount = 1.
	
!

testCompileTokenStarMessagePredicate
	
	tree := PPCTokenStarMessagePredicateNode new message: #isLetter.
	parser := self compileTree: tree params: {#guards -> false}.
	
	self assert: parser class methods size = 2.
	
	self assert: parser parse: 'foo' to: parser.
	self assert: context invocationCount = 2.
	self assert: context lwRememberCount  = 0.
	self assert: context lwRestoreCount  = 0.
	self assert: context rememberCount = 0.
	
	self assert: parser parse: 'foo123' to: parser end: 3.
! !

!PPCNodeCompilingTest methodsFor:'tests - guard'!

testSequenceTokenGuard

	tree := PPCSequenceNode new
		children: { 
			'foo' asParser trimmingToken asCompilerTree optimizeTree. 
			'bar' asParser trimmingToken asCompilerTree optimizeTree. 
		}
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'foobar'.
	self assert: result first inputValue = 'foo'.
	self assert: result second inputValue = 'bar'.	

	self assert: parser parse: ' foobar'.
	self assert: result first inputValue = 'foo'.
	self assert: result second inputValue = 'bar'.	

	self assert: parser fail: ' foo'.
!

testTrimmingTokenGuard

	tree := PPCChoiceNode new
		children: { 
			'foo' asParser trimmingToken asCompilerTree optimizeTree. 
			'bar' asParser trimmingToken asCompilerTree optimizeTree
		}
		yourself.
	parser := self compileTree: tree.
	
	self assert: parser parse: 'foo'.
	self assert: result inputValue = 'foo'.	

	self assert: parser parse: 'bar'.
	self assert: result inputValue = 'bar'.	

	self assert: parser parse: ' foo'.
	self assert: result inputValue = 'foo'.	

	self assert: parser parse: ' bar'.	
	self assert: result inputValue = 'bar'.

	self assert: parser fail: 'zorg'.
	self assert: (context invocations noneSatisfy: [ :e | e beginsWith: 'token' ]).
! !

!PPCNodeCompilingTest methodsFor:'tests - inlining'!

testInlineAny
	tree := PPCSequenceNode new
		children: { PPCInlineAnyNode new. $a asParser asCompilerNode }.
	
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 3.
	self assert: parser parse: '.a' to: #($. $a).
!

testInlineCharSetPredicate
	tree := PPCPlusNode new
		child: (PPCInlineCharSetPredicateNode new 
			predicate: (PPCharSetPredicate on: [ :e | e = $a ]);
			yourself);
		yourself.
	
	parser := self compileTree: tree.

	self assert: parser class methods size = 2.
	self assert: parser parse: 'a'  to: #($a).
	self assert: parser fail: 'b'.
!

testInlineCharacter
	tree := PPCSequenceNode new
		children: { PPCInlineCharacterNode new character: $b . $a asParser asCompilerNode }.
	
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 3.
	self assert: parser parse: 'ba' to: #($b $a).
!

testInlineLiteral
	tree := PPCSequenceNode new
		children: { PPCInlineLiteralNode new literal: 'foo'. $a asParser asCompilerNode }.
	
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 3.
	self assert: parser parse: 'fooa' to: #('foo' $a).
!

testInlineNil
	tree := PPCSequenceNode new
		children: { PPCInlineNilNode new . $a asParser asCompilerNode }.
	
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 3.
	self assert: parser parse: 'a' to: #(nil $a).
!

testInlineNotLiteral
	tree := PPCSequenceNode new
		children: { PPCInlineNotLiteralNode new literal: 'foo'. $a asParser asCompilerNode }.
	
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 3.
	self assert: parser parse: 'a' to: #(nil $a).
!

testInlinePluggable
	tree := PPCSequenceNode new
		children: { PPCInlinePluggableNode new block: [ :ctx | ctx next ]. $a asParser asCompilerNode }.
	
	parser := self compileTree: tree.
	
	self assert: parser class methods size = 3.
	self assert: parser parse: 'ba' to: #($b $a).
! !