compiler/PPCTokenizingCodeGenerator.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Mon, 17 Aug 2015 12:13:16 +0100
changeset 515 b5316ef15274
parent 502 1e45d3c96ec5
child 516 3b81c9e53352
child 524 f6f68d32de73
permissions -rw-r--r--
Updated to PetitCompiler-JanKurs.160, PetitCompiler-Tests-JanKurs.112, PetitCompiler-Extras-Tests-JanKurs.25, PetitCompiler-Benchmarks-JanKurs.17 Name: PetitCompiler-JanKurs.160 Author: JanKurs Time: 17-08-2015, 09:52:26.291 AM UUID: 3b4bfc98-8098-4951-af83-a59e2585b121 Name: PetitCompiler-Tests-JanKurs.112 Author: JanKurs Time: 16-08-2015, 05:00:32.936 PM UUID: 85613d47-08f3-406f-9823-9cdab451e805 Name: PetitCompiler-Extras-Tests-JanKurs.25 Author: JanKurs Time: 16-08-2015, 05:00:10.328 PM UUID: 09731810-51a1-4151-8d3a-56b636fbd1f7 Name: PetitCompiler-Benchmarks-JanKurs.17 Author: JanKurs Time: 05-08-2015, 05:29:32.407 PM UUID: e544b5f1-bcf8-470b-93a6-d2363e4dfc8a

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

"{ NameSpace: Smalltalk }"

PPCCodeGenerator subclass:#PPCTokenizingCodeGenerator
	instanceVariableNames:'tokenGenerator'
	classVariableNames:''
	poolDictionaries:''
	category:'PetitCompiler-Visitors'
!

!PPCTokenizingCodeGenerator methodsFor:'accessing'!

guards
    "When tokenizing, do not use guards"
    ^ false
!

tokenGenerator
    self error: 'deprecated'.
    
    tokenGenerator isNil ifTrue: [ 
        tokenGenerator := (PPCTokenCodeGenerator on: compiler)
            arguments: arguments;
            yourself.
    ].
    ^ tokenGenerator
!

tokenGenerator: whatever
    tokenGenerator := whatever
!

tokenGuards
    "When tokenizing, do not use guards"
    ^ arguments guards
! !

!PPCTokenizingCodeGenerator methodsFor:'guards'!

addGuard: node ifTrue: trueBlock ifFalse: falseBlock
    |  guard id |
    guard := PPCTokenGuard on: node.
    (self guards not or: guard makesSense not) ifTrue: [ ^ false ].
    
    id := compiler idFor: guard firstToken.

    compiler add: 'self ', id asString.

    trueBlock isNil ifFalse: [ 
        compiler addOnLine: ' ifTrue: ['.
        compiler indent.
        trueBlock value.
        compiler dedent.
        falseBlock isNil 	ifTrue: [ compiler addOnLine: '].' ]
                              		ifFalse: [ compiler add: ']'. ]
    ].
    falseBlock isNil ifFalse: [ 
        compiler addOnLine: ' ifFalse: ['.
        compiler indent.
        falseBlock value.
        compiler dedent.
        compiler addOnLine: '].'.
    ].
    ^ true
! !

!PPCTokenizingCodeGenerator methodsFor:'scanner'!

compileScanner
    compiler addConstant: self tokenGenerator compileScanner as: #scannerClass.
! !

!PPCTokenizingCodeGenerator methodsFor:'visiting'!

visitAndNode: node
    | mementoVar currentTokenVar |
    
    mementoVar := compiler allocateTemporaryVariableNamed: 'memento'.
    currentTokenVar := compiler allocateTemporaryVariableNamed: 'currentToken'.

    compiler smartRemember: node child to: mementoVar.
    compiler codeAssign: '{ currentTokenValue . currentTokenType }.' to: currentTokenVar.

    compiler 
          codeAssignParsedValueOf:[ self visit:node child ]
          to:self retvalVar.

    compiler smartRestore: node child from: mementoVar.
    compiler codeAssign: '(', currentTokenVar, ' at: 1).' to: 'currentTokenValue'.
    compiler codeAssign: '(', currentTokenVar, ' at: 2).' to: 'currentTokenType'.

    compiler codeReturn.
!

visitChoiceNode: node
"       true ifTrue: [ ^ super visitChoiceNode: node ]."
    | possibleError |
    possibleError := true.

    node children do: [ :child |
        | tokenMethodName |

        "TODO: JK: fix this in a proper way. Commented for now to make LRPParser cimpilable 
         with tokenizing"
        child acceptsEpsilon "false" ifTrue: [  
            possibleError := false.
            compiler codeIf: 'true' then: [ 
                compiler codeAssignParsedValueOf:[ self visit:child ] to:self retvalVar.
                compiler codeReturn
            ].
        ] ifFalse: [
            child firstSetWithTokens do: [ :first |
                "For each child, for each first compile this:"
            
                tokenMethodName := compiler idFor: first.
                compiler add: '(self ', tokenMethodName asString, ')'.
                compiler addOnLine: ' ifTrue: ['.
                compiler indent.
                    compiler codeAssignParsedValueOf:[ self visit:child ] to:self retvalVar.
                    compiler add: 'error ifFalse: ['.
                    compiler indent.
                        compiler codeReturn: self retvalVar.
                    compiler dedent.
                    compiler add: '] ifTrue: ['.
                    compiler indent.
                        compiler codeClearError.
                        compiler codeAssign: 'nil.' to: 'currentTokenType'.
                        compiler add: 'context position: currentTokenValue start - 1.'.
                    compiler dedent.
                    compiler add: ']'.
                compiler dedent.
                compiler add: '].'
            ]
        ]
    ].
    possibleError ifTrue: [
        compiler codeError: 'no choice found'.
    ]

    "Modified: / 31-07-2015 / 08:07:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

visitDeterministicChoiceNode: node
    | dictionary isInlined |
    dictionary := IdentityDictionary new.
    
    isInlined := node isMarkedForInline.
    
    node children do: [ :child |
        | firstSet |
        firstSet := child firstSetWithTokens.
        self assert: firstSet size = 1.
        dictionary at: child put: firstSet anyOne.
    ].
    "Tokens are unique"
    self assert: dictionary values asSet size = node children size.
    
    node children do: [ :child |
        | tokenMethodName |
        tokenMethodName := compiler idFor: (dictionary at: child).
        compiler add: '(self ', tokenMethodName asString, ')'.
        compiler addOnLine: ' ifTrue: ['.
        compiler indent.
        compiler codeReturnParsedValueOf:[ self visit:child ].
        compiler dedent.
        isInlined ifTrue:[
            compiler add: '] ifFalse: ['
        ] ifFalse:[
            compiler add: '].'.
        ]
    ].
    compiler codeError: 'no choice found'.
    isInlined ifTrue:[
        node children size timesRepeat: [ compiler addOnLine: ']' ].
        compiler addOnLine: '.'.
    ]

    "Modified: / 21-05-2015 / 15:31:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

visitTokenChoiceNode: node
    | trimmingToken |
    self assert: (node children allSatisfy: [ :e | e isMarkedForInline not ]).
    
    node children do: [ :child |
        self tokenGenerator visit: child
    ]
    
"	
    trimmingToken := node children detect: [ :e | e isTrimmingTokenNode ] ifNone: [ nil ].
    trimmingToken isNil ifFalse: [ 
        compiler codeStoreValueOf: [ self visit: trimmingToken whitespace ] intoVariable: #whatever.
    ].
    super visitChoiceNode: node."
!

visitTokenConsumeNode: node
    "dont do anything here"
    ^ node
!

visitTokenNode: node
    self error: 'should not happen!!'
!

visitTokenizingParserNode: node
    self visit: node whitespace.
    
    compiler codeHaltIfShiftPressed.
    compiler 
          codeAssignParsedValueOf:[ self visit:node parser ]
          to:self retvalVar.
    compiler codeReturn.
!

visitTrimmingTokenCharacterNode: node
    self error: 'should not happen!!'
!

visitTrimmingTokenNode: node
    self error: 'should not happen!!'
! !