diff -r 09afcf28ed60 -r 751532c8f3db compiler/PPCScannerCodeGenerator.st --- a/compiler/PPCScannerCodeGenerator.st Tue Aug 18 22:46:10 2015 +0100 +++ b/compiler/PPCScannerCodeGenerator.st Mon Aug 24 15:56:20 2015 +0100 @@ -3,22 +3,13 @@ "{ NameSpace: Smalltalk }" Object subclass:#PPCScannerCodeGenerator - instanceVariableNames:'codeGen fsa backlinkStates backlinkTransitions arguments openSet - incommingTransitions methodCache id resultStrategy fsaCache' + instanceVariableNames:'codeGen fsa arguments incommingTransitions resultStrategy + fsaCache' classVariableNames:'' poolDictionaries:'' category:'PetitCompiler-Scanner' ! - -!PPCScannerCodeGenerator class methodsFor:'instance creation'! - -new - "return an initialized instance" - - ^ self basicNew initialize. -! ! - !PPCScannerCodeGenerator methodsFor:'accessing'! arguments @@ -26,7 +17,8 @@ ! arguments: anObject - arguments := anObject + arguments := anObject. + codeGen arguments: anObject. ! codeGen @@ -39,26 +31,24 @@ !PPCScannerCodeGenerator methodsFor:'analysis'! -analyzeBacklinks - backlinkTransitions := fsa backTransitions. - backlinkStates := IdentityDictionary new. - - backlinkTransitions do: [ :t | - (self backlinksTo: (t destination)) add: t. - ]. -! - analyzeDistinctRetvals - (fsa hasDistinctRetvals) ifTrue: [ - resultStrategy := PPCDistinctResultStrategy new + (fsa hasNoRetvals) ifTrue: [ + ^ resultStrategy := PPCNoResultStrategy new codeGen: codeGen; yourself - ] ifFalse: [ - resultStrategy := PPCUniversalResultStrategy new + ]. + + + (fsa hasDistinctRetvals) ifTrue: [ + ^ resultStrategy := PPCDistinctResultStrategy new codeGen: codeGen; - tokens: fsa retvals asArray; yourself - ] + ]. + + resultStrategy := PPCUniversalResultStrategy new + codeGen: codeGen; + tokens: fsa retvals asArray; + yourself ! analyzeTransitions @@ -72,8 +62,8 @@ ]. ! -backlinksTo: state - ^ backlinkStates at: state ifAbsentPut: [ OrderedCollection new ] +clazz: aPPCClass + codeGen clazz: aPPCClass ! containsBacklink: state @@ -92,12 +82,23 @@ ^ incommingTransitions at: state ifAbsentPut: [ IdentitySet new ] ! -isBacklink: transition - ^ backlinkTransitions includes: transition +isSingleTerminatingRetval: state + (state retvals size == 1 and: [ state isFinal ]) ifFalse: [ ^ false ]. + + state transitions isEmpty ifTrue: [ ^ true ]. + ((state transitions size == 1) and: [state destination == state]) ifTrue: [ ^ self startsSimpleLoop: state ]. + + ^ false ! -isBacklinkDestination: state - ^ (self backlinksTo: state) isEmpty not +isSingleTransitionFsa + fsa allTransitions size == 1 ifFalse: [ ^ false ]. + "do not allow loop!!" + fsa startState destination == fsa startState ifTrue: [ ^ false ]. + "so far only single char allowed" + fsa startState transition isCharacterTransition ifFalse: [ ^ false ]. + fsa startState transition isSingleCharacter ifFalse: [ ^ false ]. + ^ true ! startsSimpleLoop: state @@ -115,7 +116,7 @@ !PPCScannerCodeGenerator methodsFor:'caching'! cache: anFsa method: method - fsaCache at: anFsa put: method + ^ fsaCache at: anFsa put: method ! cachedValueForIsomorphicFsa: anFsa @@ -125,37 +126,33 @@ ! isomorphicIsCached: anFsa - ^ fsaCache keys anySatisfy: [ :e | e isIsomorphicTo: anFsa ] + ^ fsaCache keys anySatisfy: [ :e | (e isIsomorphicTo: anFsa) and: [ e name = anFsa name ] ] ! ! !PPCScannerCodeGenerator methodsFor:'code generation'! generate - | method | self assert: fsa isDeterministic. self assert: fsa isWithoutEpsilons. self assert: fsa checkConsistency. (self isomorphicIsCached: fsa) ifTrue: [ + "JK: please not, right now, checks for isomorphism and name + this might be improved in future and name can be 'reused' + " ^ self cachedValueForIsomorphicFsa: fsa ]. - self analyzeBacklinks. self analyzeTransitions. self analyzeDistinctRetvals. - openSet := IdentitySet new. codeGen startMethod: (codeGen idFor: fsa). - codeGen codeComment: (Character codePoint: 13) asString, fsa asString. +" codeGen codeComment: (Character codePoint: 13) asString, fsa asString." resultStrategy reset. self generateFor: fsa startState. - method := codeGen stopMethod. - self cache: fsa method: method. - - ^ method. - + ^ self cache: fsa method: codeGen stopMethod. ! @@ -191,6 +188,16 @@ ! generateFinalFor: state offset: offset + "Handle one retval specially" + (self isSingleTerminatingRetval: state) ifTrue: [ + state isFsaFailure ifTrue: [ + resultStrategy returnFailure: state retval offset: offset. + ] ifFalse: [ + resultStrategy returnMatch: state retval offset: offset. + ]. + ^ self + ]. + state retvalsAndInfosDo: [:retval :info | info isFinal ifTrue: [ info isFsaFailure ifTrue: [ @@ -203,12 +210,26 @@ ! generateFor: state - codeGen cachedValue: (codeGen idFor: state) ifPresent: [ :method | + codeGen cachedMethod: (codeGen idFor: state) ifPresent: [ :method | "if state is already cached, it has multiple incomming links. In such a case, it is compiled as a method, thus return immediatelly" ^ codeGen codeAbsoluteReturn: method call ]. + self flag: 'TODO JK: Hack alert, fix this:'. + (state isKindOf: PEGFsaParserState) ifTrue: [ + | id | + self assert: state transitions isEmpty. + id := codeGen idFor: state parser defaultName: 'parser'. + codeGen addConstant: state parser as: id. + codeGen code: id, ' parseOn: context'. + ^ self + ]. + + (self isSingleTransitionFsa) ifTrue: [ + ^ self generateForSingleTransitionFsa: state. + ]. + (self startsSimpleLoop: state) ifTrue: [ ^ self generateSimpleLoopFor: state ]. @@ -216,29 +237,31 @@ ^ self generateStandardFor: state ! -generateForSingleTransition: t from: state +generateForSingleTransitionFsa: startState + | transition | + self assert: fsa startState == startState. - (self isJoinPoint: t destination) ifTrue: [ self removeJoinTransition: t ]. + transition := startState transition. - codeGen codeAssertPeek: t ifFalse: [ - resultStrategy returnResult: state - ]. -" (self isBacklink: t) ifTrue: [ - codeGen add: 'true' + transition isSingleCharacter ifTrue: [ + codeGen codeIf: 'context peek == ', transition character storeString then: [ + codeGen code: 'self step'; codeDot. + self generateFinalFor: transition destination. + ]. + codeGen codeReturn: 'false'. ] ifFalse: [ - self generateFor: t destination. + self error: 'should be implemented' ] -" - self generateFor: t destination ! generateForTransition: t from: state -" (self isBacklink: t) ifTrue: [ +" + (self isBacklink: t) ifTrue: [ codeGen codeAssertPeek: (t characterSet) ifTrue: [ codeGen add: 'true' ] ] ifFalse: [ - codeGen codeAssertPeek: (t characterSet) ifTrue: [. + codeGen codeAssertPeek: (t characterSet) ifTrue: [ self generateFor: t destination. ]. ]. @@ -255,8 +278,12 @@ ! generateReturnFor: state - codeGen codeNl. - resultStrategy returnResult: state. +" codeGen codeNl." + (self isSingleTerminatingRetval: state) ifFalse: [ + resultStrategy returnResult: state. + ] ifTrue: [ + "return already generated within the match" + ] ! generateSimpleLoopFor: state @@ -271,7 +298,9 @@ "Last transition did not passed the loop, therefore, we have to record succes with offset -1" self generateFinalFor: state offset: 1. - self generateTransitions: (state transitions reject: [ :t | t == selfTransition ]) for: state. + self generateTransitions: (state transitions reject: [ :t | t == selfTransition ]) + for: state + offset: 1. ! @@ -285,6 +314,7 @@ ! generateStartMethod: state + | id | id := codeGen idFor: state. codeGen codeComment: 'START - Generated from state: ', state asString. @@ -306,19 +336,18 @@ codeGen codeComment: 'STOP - Generated from state: ', state asString. ! -generateTransitions: transitions for: state +generateTransitions: transitions for: state offset: offset (transitions size = 0) ifTrue: [ - self generateReturnFor: state. + (offset > 0 and: [ state isFinal not ]) ifTrue: [ + codeGen codeIf: 'currentChar isNil' then: nil else: [ + codeGen codeOnLine: 'context skip: -', offset asString + ]. + ]. ^ self ]. -" (state transitions size = 1) ifTrue: [ - self generateForSingleTransition: state transitions anyOne from: state. - ^ self - ]." - - codeGen codeNl. - transitions do: [ :t | +" codeGen codeNl. +" transitions do: [ :t | self generateForTransition: t from: state ]. @@ -326,8 +355,8 @@ self generateReturnFor: state. codeGen dedent. codeGen codeNl. - transitions size timesRepeat: [ codeGen addOnLine: ']' ]. - codeGen addOnLine: '.'. + transitions size timesRepeat: [ codeGen codeOnLine: ']' ]. + codeGen codeDot. " self closedJoinPoints isEmpty ifFalse: [ @@ -342,7 +371,7 @@ ! generateTransitionsFor: state - ^ self generateTransitions: state transitions for: state + ^ self generateTransitions: state transitions for: state offset: 0 ! setMaxNumericId @@ -374,9 +403,9 @@ builder := PPCClassBuilder new. builder compiledClassName: arguments scannerName. - builder compiledSuperclass: PPCScanner. - builder methodDictionary: codeGen methodDictionary. - builder constants: codeGen constants. + builder compiledSuperclass: arguments scannerSuperclass. + builder methodDictionary: codeGen clazz methodDictionary. + builder constants: codeGen clazz constants. ^ builder compileClass. ! ! @@ -391,10 +420,3 @@ fsaCache := IdentityDictionary new. ! ! -!PPCScannerCodeGenerator class methodsFor:'documentation'! - -version_HG - - ^ '$Changeset: $' -! ! -