Merged JK's work on PetitCompiler
Name: PetitCompiler-JanKurs.57
Author: JanKurs
Time: 05-11-2014, 05:10:47 AM
UUID: 4c625efe-77fd-465d-bd63-72ead0b5d3ba
Name: PetitCompiler-Tests-JanVrany.13
Author: JanVrany
Time: 05-11-2014, 09:31:07 AM
UUID: 189ae287-6bc1-40ba-8458-b8392c4260a0
"{ Package: 'stx:goodies/petitparser/compiler/tests' }"
PPAbstractParserTest subclass:#PPCCompilerTest
instanceVariableNames:'parser result context'
classVariableNames:''
poolDictionaries:''
category:'PetitCompiler-Tests-Core'
!
!PPCCompilerTest methodsFor:'context'!
context
^ context := PPCProfilingContext new
! !
!PPCCompilerTest methodsFor:'running'!
tearDown
| parserClass |
parserClass := (Smalltalk at: #PPGeneratedParser).
parserClass notNil ifTrue:[
parserClass removeFromSystem
].
"Created: / 30-10-2014 / 22:56:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!PPCCompilerTest methodsFor:'test support'!
assert: p parse: whatever
^ result := super assert: p parse: whatever.
!
compile: aPPParser
| compiler |
compiler := PPCCompiler new.
compiler profile: true.
^ (compiler compile: aPPParser as: #PPGeneratedParser) new.
!
compile: aPPParser params: params
| compiler |
compiler := PPCCompiler new.
compiler profile: true.
^ (compiler compile: aPPParser as: #PPGeneratedParser params: params) new.
!
compileInlining: aPPParser
| compiler |
compiler := PPCCompiler new.
compiler inlining: true.
compiler profile: true.
^ (compiler compile: aPPParser as: #PPGeneratedParser) new.
!
compileTree: tree params: params
| compiler mock |
compiler := PPCCompiler new.
compiler profile: true.
mock := nil asParser.
^ (compiler compileTree: tree as: #PPGeneratedParser parser: mock params: params) new.
!
parse: whatever
^ result := super parse: whatever.
! !
!PPCCompilerTest methodsFor:'tests - compiling'!
testCompileAnd
parser := #digit asParser and compile.
self assert: parser parse: '1' to: $1 end: 0.
self assert: parser fail: 'a'.
self assert: parser fail: ''.
parser := ('foo' asParser, ($: asParser and)) compile.
self assert: parser parse: 'foo:' to: { 'foo'. $: } end: 3.
!
testCompileAny
parser := #any asParser compile.
self assert: parser parse: 'a' to: $a.
self assert: parser parse: '_' to: $_.
self assert: parser parse: '
' to: Character cr.
!
testCompileAnyStar
parser := #any asParser star compile.
self assert: parser parse: 'aaa' to: { $a. $a . $a }.
self assert: parser parse: '' to: { }.
!
testCompileBlock
parser := (#letter asParser) plus ==> [ :res | res collect: [:each | each asUppercase ]].
parser := parser compile.
self assert: parser parse: 'foo' to: { $F . $O . $O}.
self assert: parser parse: 'bar' to: { $B . $A . $R}.
self assert: parser fail: ''.
!
testCompileCharacter
parser := $a asParser compile.
self assert: parser parse: 'a' to: $a.
self assert: parser fail: 'b'.
parser := $# asParser compile.
self assert: parser parse: '#'.
!
testCompileChoice
parser := (#digit asParser / #letter asParser) compile.
self assert: parser parse: '1' to: $1.
self assert: parser parse: 'a' to: $a.
self assert: parser fail: '_'.
!
testCompileLiteral
parser := 'foo' asParser compile.
self assert: parser parse: 'foo' to: 'foo'.
self assert: parser parse: 'foobar' to: 'foo' end: 3.
self assert: parser fail: 'boo'.
parser := '#[' asParser compile.
self assert: parser parse: '#[1]' to: '#[' end: 2.
!
testCompileLiteral2
| quote |
quote := '''' asParser.
parser := (quote, $a asParser )compile: #PPCompilerTest.
self assert: parser parse: '''a' to: {'''' . $a}.
!
testCompileNegate
parser := #letter asParser negate star, #letter asParser.
parser := parser compile.
self assert: parser parse: '...a' to: { { $. . $. . $. } . $a }.
self assert: parser parse: 'aaa' to: { {} . $a } end: 1.
self assert: parser fail: '...'.
!
testCompileNil
parser := nil asParser compile.
self assert: parser parse: 'a' to: nil end: 0.
self assert: parser parse: '' to: nil end: 0.
parser := nil asParser, 'foo' asParser.
self assert: parser parse: 'foo' to: { nil . 'foo' }
!
testCompileNot
parser := #digit asParser not compile.
self assert: parser parse: 'a' to: nil end: 0.
self assert: parser fail: '1'.
self assert: parser parse: '' to: nil end: 0.
parser := 'foo' asParser, $: asParser not.
parser := parser compile: #PPCompilerTest.
self assert: parser parse: 'foo' to: { 'foo'. nil } end: 3.
parser := 'foo' asParser, $: asParser not, 'bar' asParser.
parser := parser compile: #PPCompilerTest.
self assert: parser parse: 'foobar' to: { 'foo'. nil . 'bar' } end: 6.
!
testCompileNot2
parser := ($a asParser, $b asParser) not compile.
self assert: parser parse: '' to: nil end: 0.
self assert: parser parse: 'a' to: nil end: 0.
self assert: parser parse: 'aa' to: nil end: 0.
self assert: parser fail: 'ab'.
!
testCompileNot3
parser := ('foo' asParser not, 'fee' asParser) compile.
self assert: parser parse: 'fee' to: #(nil 'fee').
self assert: parser fail: 'foo'.
!
testCompileNotLiteral
parser := 'foo' asParser not compile.
self assert: parser class methods size = 2.
self assert: parser parse: 'bar' to: nil end: 0.
self assert: parser fail: 'foo'.
self assert: parser parse: '' to: nil end: 0.
parser := '''' asParser not compile.
self assert: parser class methods size = 2.
self assert: parser parse: 'a' to: nil end: 0.
self assert: parser fail: ''''.
self assert: parser parse: '' to: nil end: 0.
parser := ('foo' asParser, 'bar' asParser not) compile.
self assert: parser parse: 'foofoo' to: { 'foo'. nil } end: 3.
parser := ('foo' asParser, 'foo' asParser not, #any asParser star) compile.
self assert: parser parse: 'foobar' to: { 'foo'. nil . #($b $a $r) } end: 6.
self assert: parser fail: 'foofoo'.
!
testCompileOptional
parser := #digit asParser optional compile.
self assert: parser parse: '1' to: $1.
self assert: parser parse: 'a' to: nil end: 0.
self assert: parser class parsers isEmpty.
parser := (#digit asParser optional, #letter asParser) compile.
self assert: parser parse: '1a' to: { $1 . $a }.
self assert: parser parse: 'a' to: { nil . $a }.
self assert: parser class parsers isEmpty.
!
testCompilePlus
parser := #letter asParser plus compile: #PPCompilerTest.
self assert: parser parse: 'lorem' to: {$l. $o. $r. $e. $m} .
self assert: parser parse: 'a123' to: {$a} end: 1.
self assert: parser parse: 'ab123' to: {$a . $b} end: 2.
self assert: parser fail: ''.
self assert: parser fail: '123'.
!
testCompilePredicate
parser := #digit asParser compile.
self assert: parser parse: '1' to: $1.
self assert: parser parse: '0' to: $0.
self assert: parser fail: 'a'.
!
testCompilePredicate2
parser := #space asParser compile.
self assert: parser parse: ' ' to: Character space.
self assert: parser fail: 'a'.
!
testCompileSequence
parser := (#digit asParser, #letter asParser) compile.
self assert: parser parse: '1a' to: {$1 .$a}.
!
testCompileSequence2
parser := (#digit asParser, #space asParser, #letter asParser) compile: #PPCompilerTest.
self assert: parser parse: '9 c' to: {$9 . Character space. $c }.
self assert: parser fail: '9c'.
!
testCompileSequence3
parser := (#any asParser, #any asParser, #any asParser) compile.
self assert: parser parse: 'foo' to: #($f $o $o).
self assert: parser fail: 'fo'.
!
testCompileStar
parser := #letter asParser star compile.
self assert: parser parse: 'lorem' to: {$l. $o. $r. $e. $m} .
self assert: parser parse: '' to: {}.
self assert: parser parse: '123' to: {} end: 0.
self assert: parser parse: 'ab123' to: {$a . $b} end: 2.
!
testCompileStarLiteral
parser := 'foo' asParser star compile.
self assert: parser parse: 'foo' to: #('foo' ) .
self assert: parser parse: 'foofoo' to: #('foo' 'foo') .
self assert: parser parse: 'foofoofoo' to: #('foo' 'foo' 'foo') .
self assert: parser parse: '' to: #().
self assert: parser parse: 'bar' to: #() end: 0.
!
testCompileStarPredicate
parser := #letter asParser star compile.
self assert: parser parse: 'foo' to: #($f $o $o ) .
self assert: parser parse: '' to: #().
self assert: parser parse: '123' to: #() end: 0.
!
testCompileSymbolBlock
parser := (#letter asParser) plus ==> #second.
parser := parser compile: #PPCompilerTest.
self assert: parser parse: 'foo' to: $o.
self assert: parser parse: 'bar' to: $a.
self assert: parser fail: ''.
self should: [ parser parse: 'f' ] raise: Error.
!
testTrim
parser := self compile: $a asParser trim.
self assert: parser fail: ''.
self assert: parser parse: 'a' to: $a.
self assert: parser parse: ' a' to: $a.
self assert: parser parse: 'a ' to: $a.
self assert: parser parse: ' a ' to: $a.
! !
!PPCCompilerTest methodsFor:'tests - extra'!
testCompileSmalltalkToken
parser := (#letter asParser, ((#letter asParser / #digit asParser) star)) smalltalkToken compile.
self assert: parser parse: 'foo'.
self assert: result inputValue = 'foo'.
self assert: parser parse: 'a'.
self assert: result inputValue = 'a'.
self assert: parser parse: 'f123a'.
self assert: result inputValue = 'f123a'.
self assert: parser fail: ''.
self assert: parser fail: '12'.
self assert: parser parse: ' "comment" foo'.
self assert: result inputValue = 'foo'.
self assert: parser parse: ' "comment" bar "another comment" '.
self assert: result inputValue = 'bar'.
self assert: parser parse: '
"b"
"b"
foo
"and yet, another comment"
"one more to make sure :)"
'.
self assert: result inputValue = 'foo'.
!
testCycle
| p1 block |
p1 := PPDelegateParser new.
block := ${ asParser, p1, $} asParser / nil asParser.
p1 setParser: block.
parser := block compile: #PPCompilerTest.
self assert: parser parse: '{}' to: { ${. nil . $} }.
self assert: parser parse: '{{}}' to: { ${. { ${ . nil . $} } . $} }.
!
testGuardSmalltlakToken
| charSet |
charSet := PPCCompiler new guardCharSet: 'foo' asParser smalltalkToken.
self assert: (charSet equals: (PPCharSetPredicate on: [ :char | char = $f ])).
parser := (#letter asParser, #word asParser star) smalltalkToken compileWithParameters: { #profile -> true }.
self assert: parser parse: 'bar'.
self assert: (context invocations anySatisfy: [ :e | e beginsWith: 'seq' ]).
self assert: parser fail: '123'.
self assert: (context invocations noneSatisfy: [ :e | e beginsWith: 'seq' ]).
!
testSmalltalkToken
parser := (#letter asParser, (#digit asParser / #letter asParser) star) smalltalkToken compileWithParameters: {#profile -> true}.
self assert: parser class methods size = 6.
self assert: parser parse: 'foo'.
self assert: result inputValue = 'foo'.
self assert: context invocationCount = 9.
self assert: context rememberCount = 0.
self assert: context lwRememberCount = 1.
self assert: context lwRestoreCount = 0.
!
testSmalltalkToken2
|id|
id := (#letter asParser, (#digit asParser / #letter asParser) star)
name: 'identifier';
yourself.
parser := (id, $: asParser) smalltalkToken
name: 'kw';
yourself.
parser := parser compileWithParameters: {#profile -> true}.
self assert: parser parse: 'foo:'.
self assert: result inputValue = 'foo:'.
!
testToken
parser := (#letter asParser, (#digit asParser / #letter asParser) star) flatten compile.
self assert: parser parse: 'foo' to: 'foo'.
self assert: parser parse: 'a' to: 'a'.
self assert: parser parse: 'f123a' to: 'f123a'.
self assert: parser fail: ''.
!
testToken2
parser := (#letter asParser, (#digit asParser / #letter asParser) star) token compileWithParameters: {#profile -> true}.
self assert: parser class methods size = 5.
self assert: parser parse: 'foo'.
self assert: result inputValue = 'foo'.
self assert: context invocationCount = 7.
self assert: context rememberCount = 0.
self assert: context lwRememberCount = 1.
self assert: context lwRestoreCount = 0.
!
testTrimmingToken
parser := (#letter asParser, (#digit asParser / #letter asParser) star) trimmingToken compileWithParameters: { #profile -> true }.
self assert: parser class methods size = 6.
self assert: parser parse: 'foo'.
self assert: result inputValue = 'foo'.
self assert: context invocationCount = 9.
self assert: context rememberCount = 0.
self assert: context lwRememberCount = 1.
self assert: context lwRestoreCount = 0.
self assert: parser parse: ' foo '.
self assert: result inputValue = 'foo'.
self assert: parser fail: '123'.
self assert: context invocationCount = 3.
self assert: context rememberCount = 0.
self assert: context lwRememberCount = 0.
self assert: context lwRestoreCount = 0.
self assert: parser fail: ''.
! !
!PPCCompilerTest methodsFor:'tests - first set'!
testFirstSetSuchThat
| a b fs at |
a := $a asParser.
at := a trim.
b := $b asParser.
parser := b optional, at.
fs := parser firstSetSuchThat: [ :e | (e isKindOf: PPTrimmingParser) or: [ e isTerminal ] ].
self assert: (fs anySatisfy: [ :e | e = at ]).
self assert: (fs anySatisfy: [ :e | e = b ]).
self assert: (fs noneSatisfy: [ :e | e = a ]).
!
testFirstSetSuchThat2
| a b fs at bt |
a := $a asParser optional.
at := a trim.
b := $b asParser.
bt := b trim.
parser := at, bt.
fs := parser firstSetSuchThat: [ :e | (e isKindOf: PPTrimmingParser) or: [ e isTerminal ] ].
self assert: (fs anySatisfy: [ :e | e = at ]).
self assert: (fs anySatisfy: [ :e | e = bt ]).
self assert: fs size = 2.
!
testFirstSetSuchThat3
| a b c fs at bt ct |
a := $a asParser optional.
at := a trim.
b := $b asParser.
bt := b trim.
c := $c asParser.
ct := c trim.
parser := (at, bt optional) wrapped, at, ct.
fs := parser firstSetSuchThat: [ :e | (e isKindOf: PPTrimmingParser) or: [ e isTerminal ] ].
self assert: (fs anySatisfy: [ :e | e = at ]).
self assert: (fs anySatisfy: [ :e | e = bt ]).
self assert: (fs anySatisfy: [ :e | e = ct ]).
self assert: fs size = 3.
! !
!PPCCompilerTest methodsFor:'tests - guard'!
testChoiceGuard
parser := ('foo' asParser trimmingToken / 'bar' asParser trimmingToken / $d asParser trimmingToken plus)
compileWithParameters: {#profile -> true}.
self assert: parser parse: 'foo'.
self assert: result inputValue = 'foo'.
self assert: (context invocations anySatisfy: [ :e | e beginsWith: 'token' ]).
self assert: parser parse: 'bar'.
self assert: result inputValue = 'bar'.
self assert: parser parse: ' foo'.
self assert: result inputValue = 'foo'.
self assert: parser parse: ' d'.
self assert: result first inputValue = 'd'.
self assert: parser fail: ''.
self assert: (context invocations noneSatisfy: [ :e | e beginsWith: 'predicate' ]).
self assert: (context invocations noneSatisfy: [ :e | e beginsWith: 'token' ]).
self assert: parser fail: 'zorg'.
self assert: (context invocations noneSatisfy: [ :e | e beginsWith: 'token' ]).
!
testEmptyChoiceGuard
parser := ('foo' asParser trimmingToken / 'bar' asParser trimmingToken / $d asParser trimmingToken star)
compileWithParameters: {#profile -> true}.
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: ' d'.
self assert: result first inputValue = 'd'.
self assert: parser parse: ''.
self assert: parser parse: 'zorg' end: 0.
!
testGuard1
| charSet |
charSet := PPCCompiler new guardCharSet: $a asParser.
self assert: (charSet equals: (PPCharSetPredicate on: [ :char | char = $a ])).
!
testGuard2
| charSet |
charSet := PPCCompiler new guardCharSet: #letter asParser.
self assert: (charSet equals: (PPCharSetPredicate on: [ :char | char isLetter ])).
!
testGuard3
| charSet |
charSet := PPCCompiler new guardCharSet: #letter asParser not.
self assert: (charSet equals: (PPCharSetPredicate on: [ :char | char isLetter not ])).
!
testGuard4
| charSet |
charSet := PPCCompiler new guardCharSet: (#letter asParser, #word asParser star).
self assert: (charSet equals: (PPCharSetPredicate on: [ :char | char isLetter ])).
!
testGuard5
| charSet |
charSet := PPCCompiler new guardCharSet: 'foo' asParser.
self assert: (charSet equals: (PPCharSetPredicate on: [ :char | char = $f ])).
!
testGuard6
| charSet |
charSet := PPCCompiler new guardCharSet: ('foo' asParser trimmingToken asCompilerTree optimizeTree).
self assert: (charSet equals: (PPCharSetPredicate on: [ :char | (char = $f) ]))
!
testGuard7
| charSet |
charSet := PPCCompiler new guardCharSet: ('foo' asParser trimmingToken / 'bar' asParser trimmingToken) asCompilerTree optimizeTree.
self assert: (charSet equals: (PPCharSetPredicate on: [ :char | (char = $f) or: [ char = $b ]] )).
!
testSequenceGuard
parser := ((#any asParser, #any asParser) wrapped, (#any asParser, #any asParser)) compile.
self assert: parser parse: 'fooo' to: #(#($f $o) #($o $o)).
self assert: parser parse: 'fo oo' to: #(#($f $o) #($ $o)) end: 4.
self assert: parser fail: 'fo'.
!
testTrimmerGuard
parser := $a asParser trim, $b asParser compile: #PPGeneratedParser parameters: { #profile -> true }.
self assert: parser parse: 'ab'.
self assert: parser parse: ' ab'.
! !
!PPCCompilerTest methodsFor:'tests - verification'!
testClass
| compiledParser normalParser source |
normalParser := PPSmalltalkGrammar new.
compiledParser := normalParser compile.
Class methods do: [ :m |
source := m sourceCode.
self assert: (normalParser parse: source)
equals: (compiledParser parse: source withContext: self context).
].
!
testObject
| compiledParser normalParser source |
normalParser := PPSmalltalkGrammar new.
compiledParser := normalParser compile.
Object methodsDo: [ :m |
source := m sourceCode.
self assert: (normalParser parse: source)
equals: (compiledParser parse: source withContext: self context).
].
"Modified: / 30-10-2014 / 23:22:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
testWhitespace
| compiledParser normalParser source |
normalParser := PPSmalltalkGrammar new.
compiledParser := normalParser compile.
source := ' foo ^ 1'.
self assert: (normalParser parse: source)
equals: (compiledParser parse: source withContext: self context).
! !
!PPCCompilerTest class methodsFor:'documentation'!
version_HG
^ '$Changeset: <not expanded> $'
! !