compiler/PPCTokenizingCodeGenerator.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Thu, 21 May 2015 14:12:22 +0100
changeset 464 f6d77fee9811
parent 459 4751c407bb40
child 465 f729f6cd3c76
child 502 1e45d3c96ec5
permissions -rw-r--r--
Updated to PetitCompiler-JanKurs.118, PetitCompiler-Tests-JanKurs.46, PetitCompiler-Extras-Tests-JanKurs.11, and PetitCompiler-Benchmarks-JanKurs.11 Name: PetitCompiler-JanKurs.118 Author: JanKurs Time: 13-05-2015, 03:59:01.292 PM UUID: 4a8ccd94-3131-4cc7-9098-528f8e5ea0b5 Name: PetitCompiler-Tests-JanKurs.46 Author: JanKurs Time: 04-05-2015, 04:25:06.162 PM UUID: 9f4cf8b7-876e-4a13-9579-b833f016db66 Name: PetitCompiler-Extras-Tests-JanKurs.11 Author: JanKurs Time: 13-05-2015, 04:27:27.940 PM UUID: e9f30c31-fbd0-4e96-ad2a-868f88d20ea8 Name: PetitCompiler-Benchmarks-JanKurs.11 Author: JanKurs Time: 13-05-2015, 02:21:49.932 PM UUID: 6a23fd1e-a86f-46db-8221-cc41b778d32c

"{ 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
    ^ tokenGenerator isNil 
        ifTrue: [ tokenGenerator := (PPCTokenCodeGenerator on: compiler)
            arguments: arguments;
            yourself ]
        ifFalse: [ 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:'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 codeStoreValueOf: [ self visit: node child  ] intoVariable: 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 |
        
        child acceptsEpsilon ifTrue: [  
            possibleError := false.
            compiler codeStoreValueOf: [ self visit: child ] intoVariable: 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 codeStoreValueOf: [ self visit: child ] intoVariable: 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: / 10-05-2015 / 07:37:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

visitDeterministicChoiceNode: node
    | dictionary |
    dictionary := IdentityDictionary new.
    
    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 codeStoreValueOf: [ self visit: child ] intoVariable: self retvalVar.
            compiler codeReturn: self retvalVar.
        compiler dedent.
        compiler add: '].'
    ].

    compiler codeError: 'no choice found'.
!

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
    | id |
    id := (compiler idFor: node child).
    compiler add: 'self ', id asString, ' ifTrue: ['.
        compiler indent.
        compiler codeAssign: 'nil.' to: 'currentTokenType'.
        compiler codeReturn: 'currentTokenValue'.
        compiler dedent.
    compiler add: '] ifFalse: ['.
    compiler indent.
    compiler codeError: id asString, ' expected'.
    compiler dedent.
    compiler add: '].'.

"
    compiler codeReturn: 'self consume: ', (compiler idFor: node child) storeString, '.'
"
!

visitTokenNode: node
    self error: 'shoudl not happend!!'
!

visitTokenizingParserNode: node
    self visit: node tokenizer.
    self visit: node whitespace.
    
    compiler codeHaltIfShiftPressed.
    compiler codeStoreValueOf: [ self visit: node parser ] intoVariable: self retvalVar.
    compiler codeReturn.
!

visitTrimmingTokenNode: node
    self error: 'shoudl not happend!!'
! !