compiler/PPCTokenCodeGenerator.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Mon, 24 Aug 2015 15:34:14 +0100
changeset 524 f6f68d32de73
parent 515 b5316ef15274
child 525 751532c8f3db
permissions -rw-r--r--
Merged in PetitCompiler-JanVrany.170, PetitCompiler-Tests-JanKurs.116, PetitCompiler-Extras-Tests-JanKurs.29, PetitCompiler-Benchmarks-JanKurs.19 Name: PetitCompiler-JanVrany.170 Author: JanVrany Time: 24-08-2015, 03:19:51.340 PM UUID: c20a744f-3b41-4aaa-bb8a-71ce74a2a952 Name: PetitCompiler-Tests-JanKurs.116 Author: JanKurs Time: 24-08-2015, 11:37:54.332 AM UUID: 549e0927-358a-4a1b-8270-050ccfcb4217 Name: PetitCompiler-Extras-Tests-JanKurs.29 Author: JanKurs Time: 24-08-2015, 11:36:52.503 AM UUID: ea1dbb67-f884-4237-8f34-adb0677c0954 Name: PetitCompiler-Benchmarks-JanKurs.19 Author: JanKurs Time: 24-08-2015, 11:48:47.045 AM UUID: 1c342fdb-8ddd-4104-9c47-a8f589c51694

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

"{ NameSpace: Smalltalk }"

PPCNodeVisitor subclass:#PPCTokenCodeGenerator
	instanceVariableNames:'codeGen'
	classVariableNames:''
	poolDictionaries:''
	category:'PetitCompiler-Visitors-CodeGenerators'
!

!PPCTokenCodeGenerator methodsFor:'accessing'!

arguments: args
    super arguments: args.
    codeGen arguments: args.
!

clazz: aPPCClass
    codeGen clazz: aPPCClass
! !

!PPCTokenCodeGenerator methodsFor:'code support'!

consumeWhitespace: node
    self assert: node isTokenNode.

    node isTrimmingTokenNode ifTrue: [ 
        codeGen code: 'self scan_consumeWhitespace.'
    ]
!

createTokenInstance: node id: idCode start: startVar end: endVar
    codeGen startInline.
    codeGen codeTranscriptShow: 'current token type: ', idCode.
    codeGen codeAssign: node tokenClass asString, ' on: (context collection) 
                                                            start: ', startVar, ' 
                                                            stop: ', endVar, '
                                                            value: nil.'
               to: self retvalVar.
    ^ codeGen stopInline
!

scan: node start: startVar end: endVar
    node child hasName ifFalse: [ 
        node child name: node name
    ].

    codeGen codeAssign: 'context position + 1.' to: startVar.
    codeGen add: ((self generateScan: node child) callOn: 'scanner').
! !

!PPCTokenCodeGenerator methodsFor:'compiling support'!

retvalVar
    ^ codeGen currentReturnVariable
!

startMethodForNode:node

    node isMarkedForInline ifTrue:[ 
        codeGen startInline: (codeGen idFor: node).
        codeGen codeComment: 'BEGIN inlined code of ' , node printString.
        codeGen indent.
    ] ifFalse:[ 
        codeGen startMethod: (codeGen idFor: node).
        codeGen currentMethod category: 'generated - tokens'.
        codeGen codeComment: 'GENERATED by ' , node printString.
        codeGen allocateReturnVariable.
    ]
!

stopMethodForNode:aPPCNode
    ^ codeGen currentMethod isInline ifTrue:[ 
                codeGen dedent.
                codeGen add: '"END inlined code of ' , aPPCNode printString , '"'.
                codeGen stopInline.
    ] ifFalse:[ 
                codeGen stopMethod
    ].
! !

!PPCTokenCodeGenerator methodsFor:'initialization'!

initialize
    super initialize.
    
    codeGen := PPCCodeGen new.
! !

!PPCTokenCodeGenerator methodsFor:'visiting'!

visitToken: tokenNode
    | scanId id |
    self assert: tokenNode isMarkedForInline not.

    self startMethodForNode: tokenNode.
    
    id := codeGen idFor: tokenNode.
    scanId := codeGen idFor: tokenNode fsa.
    
    codeGen code: 'match isNil ifFalse: [ ^ match == ', id storeString, '].'.
    codeGen profileTokenRead: id.
    
    tokenNode child hasName ifFalse: [ 
        tokenNode child name: tokenNode name
    ].

    codeGen codeIf: 'self ', scanId then: [ 
        self consumeWhitespace: tokenNode.
        codeGen codeReturn: 'true'.
    ] else: [ 
        codeGen codeReturn: 'false'.
    ].
    
    ^ self stopMethodForNode: tokenNode
!

visitTokenConsumeNode: node
    | id nextId |
    self startMethodForNode: node.
    id := (codeGen idFor: node child).
    nextId := (codeGen idFor: node nextFsa).
    
    "this will inline scanner consumeXY in the parser"
    node markForInline.
    

    codeGen codeIf: 'self ', id asString then: [
        codeGen codeAssign: [ 
            self createTokenInstance: node child
                id: id asString
                start: 'position + 1'
                end: 'matchPosition'.
        ] to: self retvalVar.


        codeGen codeAssign: 'context position' to: 'position'; codeDot.
        codeGen codeAssign: 'position' to: 'matchPosition'; codeDot.
        codeGen codeAssign: 'nil' to: 'match'; codeDot.		
    
        node nextFsa hasDistinctRetvals ifTrue: [ 
            codeGen codeIf: [ codeGen codeOnLine: ('self ', nextId) ] then: [ 
                self consumeWhitespace: node child.
            ] else: [ 
                self flag: 'imo should do something here and not wait...'.
                codeGen codeComment: 'Looks like there is an error on its way...'.
            ]
        ].
        codeGen codeReturn.
    
    "Token not found"
    ] else: [ 
"		codeGen code: 'PPCScannerError new signalWith: ''', id asString, ' expected'''."
        codeGen codeReturn: 'nil.'.
    ].

    ^ self stopMethodForNode: node
!

visitTokenNode: node
    ^ self visitToken: node
!

visitTokenizingParserNode: node
    "produces token_XY methods"
    self visit: node tokens.

    "TODO JK: hack alert, I don't like WS handling, think of something smarter,
        perhaps allow for WS unique per token...
    "
    self visitWhitespace: node whitespace.
    
    "produces tokenConsume_XY methods"
    ^ self visit: node parser
!

visitTrimmingTokenCharacterNode: node
    |  id  |
    self halt.
    self assert: node isMarkedForInline not.

    self startMethodForNode:node.
    
    id := codeGen idFor: node.
    
    codeGen add: 'match isNil ifFalse: [ ^ match == ', id storeString, '].'.
    codeGen profileTokenRead: id.

    codeGen add: '(context uncheckedPeek == ', node child character storeString, ') ifFalse: [ ^ false ].'.
    codeGen add: 'context next.'.

    self createTokenInstance: node id: id storeString  start: 'context position' end: 'context position'.
    self consumeWhitespace: node.
    
    codeGen codeReturn: 'true'.

    ^ self stopMethodForNode: node
!

visitTrimmingTokenNode: node
    ^ self visitToken: node
!

visitWhitespace: whitespaceNode
    self assert: whitespaceNode name = 'consumeWhitespace'.
! !