compiler/TParser.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Sun, 20 Sep 2015 12:01:42 +0100
changeset 13 97090c2baa33
parent 9 569bf5707c7e
child 14 fa42d3f1a578
permissions -rw-r--r--
Fixes/refactoring of scopes and bindings. Fixed initialization of scopes and bindings. Make typechecker to seed types.

"{ Package: 'jv:tea/compiler' }"

"{ NameSpace: Smalltalk }"

RBParser subclass:#TParser
	instanceVariableNames:'parsingInlineAssembly'
	classVariableNames:''
	poolDictionaries:''
	category:'Languages-Tea-Compiler-AST'
!

!TParser class methodsFor:'parsing'!

parseMethod: aString 
    ^ self parseMethod: aString onError: [:msg :pos | self error: msg , ' at ', pos printString ]

    "Created: / 20-08-2015 / 17:04:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseMethodHeader: aString 
        | parser |
        parser := self new.
        parser errorBlock: [:msg :pos | self error: msg , ' at ', pos printString ].
        parser initializeParserWith: aString type: #searchOn:errorBlock:.
        ^parser parseMessagePattern

    "Created: / 13-09-2015 / 06:39:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 13-09-2015 / 07:55:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TParser methodsFor:'accessing'!

initializeParserWith: aString type: aSymbol 
        |stream|

        stream := ReadStream on: aString.
        source := aString.
        self scanner: (TScanner 
                                perform: aSymbol
                                with: stream
                                with: self errorBlock)

    "Created: / 02-09-2015 / 05:57:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TParser methodsFor:'initialization & release'!

scanner: aScanner 
    parsingInlineAssembly := false.
    super scanner: aScanner.

    "Created: / 02-09-2015 / 06:34:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TParser methodsFor:'private-parsing'!

parseArgOrLocal
    "Parse either method/block argument or a local (inside | | )"

    | variable |

    variable := self parseVariableNode.
    variable typeSpec: (self parseTypeSpec: false).
    ^ variable

    "Created: / 20-08-2015 / 16:57:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 21-08-2015 / 21:20:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseBinaryPattern
    | method |

    method := super parseBinaryPattern.
    method returnTypeSpec: (self parseTypeSpec: true).
    ^ method

    "Created: / 21-08-2015 / 22:55:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseBlockArgsInto: node
    | verticalBar args colons |
    args := OrderedCollection new: 2.
    colons := OrderedCollection new: 2.
    verticalBar := false.
    [currentToken isSpecial and: [currentToken value == $:]] whileTrue: [
        colons add: currentToken start.
        self step.      ":"
        verticalBar := true.
        args add: self parseArgOrLocal
    ].   
    (currentToken isBinary and:[ currentToken value == #< ]) ifTrue:[ 
        "Return type spec"
        node returnTypeSpec: (self parseTypeSpec: true).
        verticalBar := true.
    ].
    verticalBar ifTrue:[ 
        currentToken isBinary ifTrue: [
            node bar: currentToken start.
            currentToken value == #| ifTrue: [
                self step
            ] ifFalse: [
                currentToken value == #'||' ifTrue:[
                    "Hack the current token to be the start 
                     of temps bar"
                    currentToken
                            value: #|;
                            start: currentToken start + 1
                ] ifFalse: [
                    self parserError: '''|'' expected'
                ]
            ]
        ] ifFalse: [
            (currentToken isSpecial and: [currentToken value == $]]) ifFalse: [
                self parserError: '''|'' expected'
            ]
        ].                    
    ].
    node
        arguments: args;
        colons: colons.
    ^node

    "Created: / 14-09-2015 / 14:35:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseInlineAssembly
        | position blockNode firstLine prevScope|

        position := currentToken start.
        firstLine := currentToken lineNumber.
        parsingInlineAssembly := true.
        self step. "/ To eat %[ token
        blockNode := self parseBlockArgsInto: TInlineAssemblyNode new.
"/        node arguments do:[:eachArg | eachArg parent:self].
        blockNode left: position.
        blockNode firstLineNumber:firstLine.
        prevScope := currentScope.
        currentScope := blockNode.
        self rememberLastNode:blockNode.
        blockNode body: (self parseStatements: false).
        RBParser isSmalltalkX ifTrue:[
            self addComments:(scanner getCommentsBeforeToken) afterNode:blockNode body.
        ].
        "/ ensure that right is set, even if parse aborted due to an error
        blockNode right: currentToken start-1.

        (currentToken isTInlineAssemblyEnd ) 
                ifFalse: [self parserError: '''$]'' expected'].
        "/ fix right
        blockNode right: currentToken start.
        blockNode lastLineNumber:currentToken lineNumber.
        parsingInlineAssembly := false.

        self step.
        self addComments:(scanner getCommentsBeforeToken) afterNode:blockNode.
        currentScope := prevScope.
        ^ blockNode

    "Created: / 02-09-2015 / 06:25:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseKeywordMessageWith: node 
    | message |
    message := super parseKeywordMessageWith: node.
    message ~~ node ifTrue:[ 
        "/ Check for special forms here...
        (TSpecialFormNode specialSelectors includes: message selector) ifTrue:[ 
            message := TSpecialFormNode receiver: message receiver  
                                        selectorParts: message selectorParts
                                        arguments: message arguments.
        ].
    ].
    ^ message

    "Created: / 14-09-2015 / 12:24:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseKeywordPattern
    | method |

    method := super parseKeywordPattern.
    method returnTypeSpec: (self parseTypeSpec: true).
    ^ method

    "Created: / 20-08-2015 / 17:33:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 21-08-2015 / 22:50:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseStatementList: tagBoolean into: sequenceNode 
        | statements return periods returnPosition returnLineNumber node valueNode|
        return := false.
        statements := OrderedCollection new.
        periods := OrderedCollection new.
        self addComments:(scanner getCommentsBeforeToken) beforeNode:sequenceNode.
        tagBoolean ifTrue: [self parseResourceTag].
        
        [
         "skip empty statements"
         emptyStatements ifTrue: 
                 [[currentToken isSpecial and: [currentToken value == $.]] whileTrue: 
                                 [periods add: currentToken start.
                                 self step]].

         self atEnd 
                or: [(currentToken isSpecial and: ['])}' includes: currentToken value ])
                or: [(currentToken isTInlineAssemblyEnd)]]
        ] whileFalse:[ 
            self addComments:(scanner getCommentsBeforeToken) beforeNode:node "value".

            return ifTrue: [
                self class isSmalltalkX 
                    ifTrue:
                        ["could output a warning"]
                    ifFalse:
                        [self 
                            parserError: 'End of statement list encounted (statements after return)'
                            lastNode:node]].
            (currentToken isTInlineAssemblyBegin) ifTrue:[ 
                node := self parseInlineAssembly.
                statements add: node.
            ] ifFalse:[
            (currentToken isSTXPrimitiveCode) 
                ifTrue:[
                    " primPosition := currentToken start. "
                    node := RBSTXPrimitiveCCodeNode new codeToken: currentToken.
                    self addComments:(scanner getCommentsBeforeToken) afterNode:node.
                    statements add: node.
                    self step.
                ] ifFalse:[
                    (currentToken isSpecial and: [currentToken value == $^])
                        ifTrue: 
                                [
                                returnPosition := currentToken start.
                                returnLineNumber := currentToken lineNumber.
                                self step.

                                valueNode := self parseAssignment.
                                node := RBReturnNode return: returnPosition value: valueNode.
                                node lineNumber:returnLineNumber.
                                scanner atEnd ifFalse:[
                                    self addComments:(scanner getCommentsBeforeToken) afterNode:node value.
                                ].

                                statements add: node.
                                return := true]
                        ifFalse: 
                                [
                                node := self parseAssignment.
                                node notNil ifTrue:[
                                    self addComments:(scanner getCommentsAfterTokenIfInLine:node lastLineNumber) afterNode:node.
                                    scanner atEnd ifFalse:[
                                        self addComments:(scanner getCommentsAfterToken) afterNode:node.
                                        self addComments:(scanner getCommentsBeforeToken) afterNode:node.
                                    ].

                                    statements add: node
                                ]].
                ].
            ].

            (currentToken isSpecial and: [currentToken value == $.])
                ifTrue: 
                    [periods add: currentToken start.
                    self step]
                ifFalse: 
                    [return := true].
            emptyStatements 
                ifTrue: 
                    [[currentToken isSpecial and: [currentToken value == $.]] whileTrue: 
                                    [periods add: currentToken start.
                                    self step]]].

        sequenceNode 
            statements: statements;
            periods: periods.

        self addComments:(scanner getCommentsBeforeToken) afterNode:node "value".
        ^sequenceNode

    "Created: / 02-09-2015 / 06:23:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseType
    "
    type ::= type_simple
    "
    ^ self parseTypeSimple.

    "Created: / 20-08-2015 / 17:18:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 02-09-2015 / 17:01:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseTypeSimple
    "
    type_simple::= identifier ('[' type_parameters ']')?
    "
    | type |
        
    currentToken isIdentifier ifTrue:[ 
        type  := TSimpleTypeNode new.
        type name: currentToken value.
    ] ifFalse:[ 
        (currentToken isLiteral and:[ currentToken value isNil ]) ifFalse:[
            self parserError: 'type identifier expected'.
        ].
        type := TSimpleTypeNode new.
        type name: 'nil'.
    ].
    type
        start: currentToken start;
        stop: currentToken stop;
        lineNumber: currentToken lineNumber.  
    self step. "/ eat identifier.
    ^ type

    "Created: / 20-08-2015 / 17:20:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 21-08-2015 / 21:13:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseTypeSpec: forReturn
    parsingInlineAssembly ifTrue:[ ^ nil ].
    
    (currentToken isBinary and: [currentToken value == #<]) ifTrue: [
        | start stop type |    
        start := currentToken start.
        self step.
        forReturn ifTrue:[ 
            (currentToken isSpecial and:[ currentToken value == $^ ]) ifFalse:[ 
                self parserError: '''^'' expected'.
            ].
            self step.
        ].          

        type := self parseType.

        (currentToken isBinary and: [currentToken value == #>]) 
                ifFalse: [self parserError: '''>'' expected'].
        stop := currentToken stop.
        self step.
        ^ TTypeSpecNode new
            type: type;
            start: start;
            stop: stop.
    ] ifFalse:[ 
        self parserError: 'type annotation expected'
    ].

    "Created: / 20-08-2015 / 17:13:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 02-09-2015 / 07:01:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parseUnaryPattern
    | method |

    method := super parseUnaryPattern.
    method returnTypeSpec: (self parseTypeSpec: true).
    ^ method

    "Created: / 21-08-2015 / 22:54:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !