compiler/TSourceReader.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Fri, 25 Sep 2015 03:51:15 +0100
changeset 16 17a2d1d9f205
parent 8 eec72263ed75
permissions -rw-r--r--
Added standalone Tea compiler - teak It allows for compilation of .tea files from the command line.

"
    Copyright (C) 2015-now Jan Vrany

    This code is not an open-source (yet). You may use this code
    for your own experiments and projects, given that:

    * all modification to the code will be sent to the
      original author for inclusion in future releases
    * this is not used in any commercial software

    This license is provisional and may (will) change in
    a future.
"
"{ Package: 'jv:tea/compiler' }"

"{ NameSpace: Smalltalk }"

Object subclass:#TSourceReader
	instanceVariableNames:'stream unit currentChunk currentChunkTree'
	classVariableNames:''
	poolDictionaries:''
	category:'Languages-Tea-Compiler-Model'
!

!TSourceReader class methodsFor:'documentation'!

copyright
"
    Copyright (C) 2015-now Jan Vrany

    This code is not an open-source (yet). You may use this code
    for your own experiments and projects, given that:

    * all modification to the code will be sent to the
      original author for inclusion in future releases
    * this is not used in any commercial software

    This license is provisional and may (will) change in
    a future.
"
! !

!TSourceReader class methodsFor:'reading'!

read: aStringOrFilenameOrStream
    ^ self new read: aStringOrFilenameOrStream

    "Created: / 31-08-2015 / 15:26:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TSourceReader methodsFor:'processing'!

process
    "raise an error: this method should be implemented (TODO)"

    currentChunkTree isMessage ifTrue:[ 
        | handler |

        handler := ('process_' , (currentChunkTree selector copyReplaceAll: $: with: $_)) asSymbolIfInterned.
        (handler notNil and:[ self respondsTo: handler ]) ifTrue:[ 
            self perform: handler.
            ^ self.
        ].
    ].
    self error: 'Unknown chunk'

    "Created: / 28-08-2015 / 07:12:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 31-08-2015 / 15:49:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

process_methodsFor_
    self processMethodDefinitions

    "Created: / 31-08-2015 / 15:57:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

process_subclass_category_
    self processClassDefinition

    "Created: / 31-08-2015 / 15:50:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

process_subclass_instanceVariableNames_classVariableNames_poolDictionaries_category_
    self processClassDefinition

    "Created: / 28-08-2015 / 07:15:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TSourceReader methodsFor:'processing-helpers'!

processClassDefinition
    | superName className class |

    currentChunkTree receiver isVariable ifTrue:[
        superName := currentChunkTree receiver name.
    ] ifFalse:[ 
        currentChunkTree receiver isLiteral ifTrue:[ 
            currentChunkTree receiver value isNil ifTrue:[ 
                superName := nil.
            ] ifFalse:[ 
                self error:'Invalid superclass'
            ].
        ] ifFalse:[ 
            self error:'Invalid superclass'
        ].
    ].
    className := currentChunkTree arguments first value.
    class := TClassDefinition newClass.
    class superclassName: superName.
    class name: className.
    2 to: currentChunkTree selectorParts size do:[:i | 
        | property value |

        property := (currentChunkTree selectorParts at: i) value.
        value    := (currentChunkTree arguments at: i) value.

        property = 'instanceVariableNames:' ifTrue:[ 
            class instanceVariableNamed: value.
        ] ifFalse:[ 
        property = 'classVariableNames:' ifTrue:[ 
            class classVariableNames: value.
        ] ifFalse:[
        property = 'poolDictionaries:' ifTrue:[ 
            class poolDictionaryNames: value.
        ] ifFalse:[
        property = 'category:' ifTrue:[ 
            class category: value.
        ]]]].
    ].

    unit addElement: class.

    "Created: / 28-08-2015 / 07:16:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 13-09-2015 / 07:56:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

processMethodDefinitions
    | className classIsMeta category source |

    currentChunkTree receiver isVariable ifTrue:[ 
        className := currentChunkTree receiver name.
        classIsMeta := false.
    ] ifFalse:[ 
        currentChunkTree receiver isMessage ifTrue:[ 
            currentChunkTree receiver receiver isVariable ifTrue:[ 
                currentChunkTree receiver selector = #class ifTrue:[ 
                    className := currentChunkTree receiver receiver name.
                    classIsMeta := true.
                ] ifFalse:[ 
                    self error: 'Invalid class name'
                ].
            ] ifFalse:[ 
                self error: 'Invalid class name'
            ].
        ] ifFalse:[ 
            self error: 'Invalid class name'
        ].
    ].
    currentChunkTree arguments first isLiteralNode ifTrue:[ 
        category := currentChunkTree arguments first value.
    ] ifFalse:[ 
        self error: 'Invalid category name'.
    ].

    [ source := stream nextChunk. source notEmptyOrNil ] whileTrue:[ 
        | method |
        method := TMethodDefinition new.
        method source: source.
        method category: category.
        classIsMeta ifTrue:[
            method className: className , ' class'.
        ] ifFalse:[ 
            method className: className.
        ].
        unit addElement: method
    ].

    "Created: / 31-08-2015 / 16:02:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 13-09-2015 / 07:56:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!TSourceReader methodsFor:'reading'!

read: aStringOrFilenameOrStream
    "Read Tea source from source and return a compilation unit from it (as TCompilationUnitDefinition)"

    unit := TCompilationUnitDefinition new.
    stream := aStringOrFilenameOrStream readStream.
    stream isEncodedStream ifFalse:[
        "/ By default, Tea sources are UTF8 encoded...
        stream := EncodedStream stream: stream encoder:(CharacterEncoder encoderToEncodeFrom:#utf8 into:#unicode). 
    ].

    [ stream atEnd ] whileFalse:[ 
        currentChunk := nil.
        currentChunkTree := nil.
        [ currentChunk isEmptyOrNil and:[ stream atEnd not ] ] whileTrue:[  
            currentChunk := stream nextChunk
        ].
        currentChunk notEmptyOrNil ifTrue:[
            currentChunkTree := TParser 
                        parseExpression: currentChunk 
                        onError: [:msg :pos | ChangeSet invalidChangeChunkError raiseRequestErrorString: ('Invalid chunk: %1 at %2' bindWith: msg with: pos) ].
            self process
        ].
    ].
    ^ unit

    "Created: / 31-08-2015 / 15:23:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 13-09-2015 / 07:56:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !