UnaryNode.st
author Claus Gittinger <cg@exept.de>
Mon, 16 Feb 2009 14:10:39 +0100
changeset 2165 4dde25bad190
parent 2111 ecfcbcbe299f
child 2227 5b45a572dc15
permissions -rw-r--r--
automatic checkIn

"
 COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
"{ Package: 'stx:libcomp' }"

MessageNode subclass:#UnaryNode
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	category:'System-Compiler-Support'
!

!UnaryNode class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    node for parse-trees, representing unary messages
    This is a helper class for the compiler.

    [author:]
        Claus Gittinger
"
! !

!UnaryNode class methodsFor:'instance creation'!

receiver:r selector:s
    "return a new UnaryNode for sending selector s to receiver r.
     Fold constants."

    ^ self receiver:r selector:s fold:true
!

receiver:r selector:selectorString fold:folding
    "return a new UnaryNode for sending selector selectorString to receiver r.
     If folding is true, fold constant expressions."

    |result recVal selector canFold globalName|

"
    The constant folding code can usually not optimize things - this may change
    when some kind of constant declaration is added to smalltalk.
"

    canFold := false.

    (folding notNil and:[folding ~~ false]) ifTrue:[
        selector := selectorString asSymbolIfInterned.
        selector notNil ifTrue:[
            "/
            "/ do constant folding ...
            "/ evaluate at compile time:
            "/      Character tab
            "/      Character cr
            "/          ... 
            "/      Float pi
            "/      Float e
            "/          ... 
            "/      String cr
            "/      String crlf
            "/          ... 
            "/      #(...) asFloatArray

            r isGlobal ifTrue:[
                globalName := r name.
                recVal := r evaluate.

                (globalName = 'Character') ifTrue:[
                    ( #( tab cr lf return space backspace esc ) includes:selector)
                    ifTrue:[
                        canFold := true
                    ]
                ].
                (globalName = 'Float') ifTrue:[
                    ( #( pi e NaN unity zero ) includes:selector)
                    ifTrue:[
                        (recVal respondsTo:selector) ifTrue:[
                            canFold := true
                        ]
                    ]
                ].
                (globalName = 'String') ifTrue:[
                    ( #( cr crlf lf ) includes:selector)
                    ifTrue:[
                        (recVal respondsTo:selector) ifTrue:[
                            canFold := true
                        ]
                    ]
                ].

"/ no, this 'optimization' is not good -
"/ if bytecode is transported to another machine.
"/ However, the JIT compiler compensates for this ;-)
"/                (globalName = 'Smalltalk') ifTrue:[
"/                    ( #( isSmalltalkX isVisualWorks isSqueak
"/                         isSmalltalkMT isDolphinSmalltalk isVisualAge 
"/                         isSmalltalkV) includes:selector)
"/                    ifTrue:[
"/                        (recVal respondsTo:selector) ifTrue:[
"/                            canFold := true
"/                        ]
"/                    ]
"/                ].

"/ no, this 'optimization' is not good -
"/ if bytecode is transported to another machine.
"/ However, the JIT compiler compensates for this ;-)
"/                (globalName = 'SmallInteger') ifTrue:[
"/                    ( #( minVal maxVal ) includes:selector)
"/                    ifTrue:[
"/                        (recVal respondsTo:selector) ifTrue:[
"/                            canFold := true
"/                        ]
"/                    ]
"/                ]
            ].

            r isConstant ifTrue:[
                "check if we can do it ..."
                recVal := r evaluate.

                "
                 we could do much more here - but then, we need a dependency from
                 the folded selectors method to the method we generate code for ...
                 limit optimizations to those that will never change 
                 (or, if you change them, it will crash badly anyway ...)
                "
                recVal respondsToArithmetic ifTrue:[
                    (#( negated abs asPoint degreesToRadians radiansToDegrees
                        exp ln log sqrt reciprocal 
                        arcCos arcSin arcTan sin cos tan) includes:selector)
                    ifTrue:[
                        canFold := true
                    ]
                ].
                recVal isCharacter ifTrue:[
                    (#( asciiValue asInteger digitValue asString) includes:selector) 
                    ifTrue:[
                        canFold := true
                    ]
                ].
                recVal isString ifTrue:[
                    (selector == #withCRs) ifTrue:[
                        canFold := folding isSymbol
                                   and:[(folding >= #level2) or:[folding == #full]]
                    ].
                    (selector == #size) ifTrue:[
                        canFold := folding isSymbol
                                   and:[(folding >= #level1) or:[folding == #full]]
                    ].
                    (selector == #asSymbol) ifTrue:[
                        canFold := folding isSymbol
                                   and:[(folding >= #level1) or:[folding == #full]]
                    ].
                ].
                (recVal isMemberOf:Array) ifTrue:[
                    (#(asFloatArray asDoubleArray) includes:selector) ifTrue:[
                        canFold := folding isSymbol
                                   and:[(folding >= #level2) or:[folding == #full]]
                    ]
                ]
            ]
        ].

        canFold ifTrue:[
            (recVal respondsTo:selector) ifTrue:[
                SignalSet anySignal "Number domainErrorSignal" handle:[:ex |
                    "in case of an error, abort fold and return original"
                    ex return
                ] do:[
                    result := recVal perform:selector.
                    ^ ConstantNode type:(ConstantNode typeOfConstant:result) value:result
                ].
                "when we reach here, something went wrong (something like 0.0 log)"
                ^ ParseErrorNode errorString:'error occured while evaluating constant expression'
            ].
        ].
    ].

    ^ (self basicNew) receiver:r selector:selectorString args:nil lineno:0

    "Modified: / 05-03-2007 / 15:11:26 / cg"
! !

!UnaryNode methodsFor:'checks'!

plausibilityCheckIn:aParser
    "check for funny selector - careful to do string compare instead
     of symbol identity compare: I dont want to introduce these as symbols
     into the system (would make the '... is nowhere implemented' warning
     go away."

    |selectorSymbol|

    selectorSymbol := selector asSymbolIfInterned.
    selectorSymbol notNil ifTrue:[
        ((selectorSymbol == #self) or:[
         (selectorSymbol == #super) or:[
         (selectorSymbol == #thisContext) or:[
         (selectorSymbol == #nil) or:[
         (selectorSymbol == #true) or:[
         (selectorSymbol == #false) or:[
         (Smalltalk includesKey:selectorSymbol)]]]]]]) ifTrue:[
            (aParser alreadyWarnedUnimplementedSelectors includes:selectorSymbol) ifFalse:[
                aParser alreadyWarnedUnimplementedSelectors add:selectorSymbol.
                ^ 'funny selector: ',selectorSymbol allBold,' (known as global); possible missing ''.'' or keyword-colon.'
            ].
        ].
    ].

    "
     more to come 
     ...
    "

    ^ super plausibilityCheckIn:aParser

    "Modified: / 16-07-2006 / 16:16:25 / cg"
! !

!UnaryNode methodsFor:'code generation'!

codeOn:aStream inBlock:b for:aCompiler
    "append bytecode for the receiver to aStream."

    |rSel notSelector|

    "
     optimize 
        (a == b) not -> (a ~~ b)
        (a ~~ b) not -> (a == b)
    "
    (selector == #not) ifTrue:[
        (receiver class == BinaryNode) ifTrue:[
            ((rSel := receiver selector) == #==) ifTrue:[
                notSelector := #~~
            ] ifFalse:[
                (rSel == #~~) ifTrue:[
                    notSelector := #==
                ]
            ].
            notSelector notNil ifTrue:[
                aCompiler addLiteral:selector; addLiteral:rSel.

                (BinaryNode 
                        receiver:(receiver receiver)
                        selector:notSelector
                        arg:(receiver arg)) 
                    codeOn:aStream 
                    inBlock:b 
                    for:aCompiler.
                ^ self
            ]
        ]
    ].

    ^ super codeOn:aStream inBlock:b for:aCompiler

    "Modified: / 05-03-2007 / 15:11:35 / cg"
! !

!UnaryNode methodsFor:'evaluation'!

evaluateIn:anEnvironment
    "evaluate the expression represented by the receiver"

    |r|

    selector := selector asSymbol.
    receiver isSuper ifTrue:[
        ^ super evaluateIn:anEnvironment
    ].
    r := receiver evaluateIn:anEnvironment.
    selector == #class ifTrue:[
        ^ r class.
    ].
    ^ r perform:selector

    "Modified: / 04-06-2007 / 17:46:31 / cg"
! !

!UnaryNode methodsFor:'printing & storing'!

printOn:aStream indent:i 
    "prettyprint the expression represented by the receiver"
    
    receiver printOn:aStream indent:i parenthized:(receiver precedence < self precedence).
    aStream space.
    selector printString printOn:aStream.

    "Modified: / 20-04-2005 / 14:36:26 / cg"
! !

!UnaryNode methodsFor:'queries'!

isUnaryMessage
    "return true, if this node is one for a unary message"

    ^ true

    "Modified: 23.10.1997 / 02:05:18 / cg"
!

precedence
    ^ 100

    "Created: / 20-04-2005 / 14:10:34 / cg"
! !

!UnaryNode class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libcomp/UnaryNode.st,v 1.52 2008-10-14 08:00:31 cg Exp $'
! !