Explainer.st
changeset 2 0aae80a0ae84
child 6 0cd4e7480440
equal deleted inserted replaced
1:77da9f5728e5 2:0aae80a0ae84
       
     1 "
       
     2  COPYRIGHT (c) 1993 by Claus Gittinger
       
     3               All Rights Reserved
       
     4 
       
     5  This software is furnished under a license and may be used
       
     6  only in accordance with the terms of that license and with the
       
     7  inclusion of the above copyright notice.   This software may not
       
     8  be provided or otherwise made available to, or used by, any
       
     9  other person.  No title to or ownership of the software is
       
    10  hereby transferred.
       
    11 "
       
    12 
       
    13 Parser subclass:#Explainer 
       
    14        instanceVariableNames:''
       
    15        classVariableNames:''
       
    16        poolDictionaries:''
       
    17        category:'System-Compiler'
       
    18 !
       
    19 
       
    20 Explainer comment:'
       
    21 
       
    22 COPYRIGHT (c) 1993 by Claus Gittinger
       
    23              All Rights Reserved
       
    24 
       
    25 $Header: /cvs/stx/stx/libcomp/Explainer.st,v 1.1 1993-10-13 00:25:45 claus Exp $
       
    26 '!
       
    27 
       
    28 !Explainer class methodsFor:'documentation'!
       
    29 
       
    30 documentation
       
    31 "
       
    32 a very simple explainer - much more should be added ...
       
    33 "
       
    34 ! !
       
    35 
       
    36 !Explainer class methodsFor:'explaining'!
       
    37 
       
    38 explain:someText in:source forClass:aClass
       
    39     "this is just a q&d implementation - there could be much more.
       
    40      Given a source and a substring of it, return a string containing
       
    41      an explanation."
       
    42 
       
    43     |parser variables v c string sym list count tmp
       
    44      commonSuperClass|
       
    45 
       
    46     string := someText withoutSeparators.
       
    47     parser := self parseMethod:source in:aClass.
       
    48     parser notNil ifTrue:[
       
    49         "look for variables"
       
    50 
       
    51         variables := parser methodVars.
       
    52         (variables notNil and:[variables includes:string]) ifTrue:[
       
    53             ^ string , ' is a method variable'
       
    54         ].
       
    55         variables := parser methodArgs.
       
    56         (variables notNil and:[variables includes:string]) ifTrue:[
       
    57             ^ string , ' is a method argument'
       
    58         ]
       
    59     ].
       
    60     parser isNil ifTrue:[
       
    61         parser := self for:(ReadStream on:source) in:aClass
       
    62     ].
       
    63 
       
    64     "instvars"
       
    65     variables := aClass allInstVarNames.
       
    66     (variables notNil and:[variables includes:string]) ifTrue:[
       
    67         "where is it"
       
    68         c := aClass.
       
    69         [c notNil] whileTrue:[
       
    70             v := c instVarNames.
       
    71             (v notNil and:[v includes:string]) ifTrue:[
       
    72                 ^ string , ' is an instance variable in ' , c name
       
    73             ].
       
    74             c := c superclass
       
    75         ].
       
    76         self error:'oops'
       
    77     ].
       
    78 
       
    79     "class instvars"
       
    80     variables := aClass class allInstVarNames.
       
    81     (variables notNil and:[variables includes:string]) ifTrue:[
       
    82         "where is it"
       
    83         c := aClass.
       
    84         [c notNil] whileTrue:[
       
    85             v := c class instVarNames.
       
    86             (v notNil and:[v includes:string]) ifTrue:[
       
    87                 ^ string , ' is a class instance variable in ' , c name
       
    88             ].
       
    89             c := c superclass
       
    90         ].
       
    91         self error:'oops'
       
    92     ].
       
    93 
       
    94     "classvars"
       
    95     c := parser inWhichClassIsClassVar:string.
       
    96     c notNil ifTrue:[
       
    97         ^ string , ' is a class variable in ' , c name
       
    98     ].
       
    99 
       
   100     string knownAsSymbol ifTrue:[
       
   101         "globals"
       
   102         sym := string asSymbol.
       
   103         (Smalltalk includesKey:sym) ifTrue:[
       
   104             (Smalltalk at:sym) isBehavior ifTrue:[
       
   105                 ^ string , ' is a global variable.
       
   106 
       
   107 ' , string , ' is a class in category ' , (Smalltalk at:sym) category , '.'
       
   108             ] ifFalse:[
       
   109                 ^ string , ' is a global variable.
       
   110 
       
   111 Its current value is ' , (Smalltalk at:sym) classNameWithArticle , '.'
       
   112             ]
       
   113         ].
       
   114 
       
   115         list := OrderedCollection new.
       
   116         "selectors"
       
   117         Smalltalk allBehaviorsDo:[:c|
       
   118             (c implements:sym) ifTrue:[
       
   119                 list add:(c name)
       
   120             ].
       
   121             (c class implements:sym) ifTrue:[
       
   122                 list add:(c name , 'class')
       
   123             ]
       
   124         ].
       
   125         count := list size.
       
   126         (count ~~ 0) ifTrue:[
       
   127             tmp := ' is a selector implemented in '.
       
   128             (count == 1) ifTrue:[
       
   129                 ^ string , tmp , (list at:1) , '.'
       
   130             ].
       
   131             (count == 2) ifTrue:[
       
   132                 ^ string , tmp , (list at:1) , ' and ' , (list at:2) , '.'
       
   133             ].
       
   134             (count == 3) ifTrue:[
       
   135                 ^ string , tmp , '
       
   136 ' , (list at:1) , ', ' , (list at:2) , ' and ' , (list at:3) , '.'
       
   137             ].
       
   138             (count == 4) ifTrue:[
       
   139                 ^ string , tmp , '
       
   140 ' , (list at:1) , ', ' , (list at:2) , ', ' , (list at:3), ' and ' , (list at:4) , '.'
       
   141             ].
       
   142 
       
   143 	    commonSuperClass := self commonSuperClassOf:list.
       
   144 	    commonSuperClass ~~ Object ifTrue:[
       
   145 		^ string , tmp, count printString , ' subclasses of ' , commonSuperClass name
       
   146 	    ].
       
   147 
       
   148             ^ string , tmp , count printString , ' classes.'
       
   149         ]
       
   150     ].
       
   151 
       
   152     "try for some obvious things"
       
   153     tmp := self explainPseudoVariable:string in:aClass.
       
   154     tmp notNil ifTrue:[ ^ tmp].
       
   155 
       
   156     "try syntax ..."
       
   157 
       
   158     ((string = ':=') or:[string = '_']) ifTrue:[
       
   159         ^ '<variable> := <expression>
       
   160 
       
   161 := and _ (which is left-arrow in some fonts) mean assignment.
       
   162 The variable is bound to (i.e. points to) the value of <expression>.'
       
   163     ].
       
   164 
       
   165     (string = '^') ifTrue:[
       
   166         ^ '^ <expression>
       
   167 
       
   168 return the value of <expression> as value from the method.
       
   169 A return from within a block exits the method where the block is defined.'
       
   170     ].
       
   171 
       
   172     (string = ';') ifTrue:[
       
   173         ^ '<expression> ; selector1 ; .... ; selectorN
       
   174 
       
   175 a cascade expression; evaluate expression, and send messages 
       
   176 <selector1> ... <selectorN> to the first expressions receiver. 
       
   177 Returns the value of the last send. The cascade sends may also have arguments.'
       
   178     ].
       
   179 
       
   180     (string = '|') ifTrue:[
       
   181         ^ '| locals |  or: [:arg | statements]
       
   182 
       
   183 | is used to mark a local variable declaration or separates arguments
       
   184 from the statements in a block. Notice, that in a block-argument declaration
       
   185 these must be prefixed by a colon character.
       
   186 | is also a selector understood by Booleans.'
       
   187     ].
       
   188 
       
   189     ((string startsWith:'(') or:[string endsWith:')']) ifTrue:[
       
   190         ^ '(<expression>)
       
   191 
       
   192 expression grouping.'
       
   193     ].
       
   194 
       
   195     ((string startsWith:'[') or:[string endsWith:']']) ifTrue:[
       
   196         ^ '[arguments | statements]
       
   197 
       
   198 defines a block. 
       
   199 Blocks represent pieces of executable code. Definition of a block does
       
   200 not evaluate it. The block is evaluated by sending it a value/value:
       
   201 message.
       
   202 Blocks are often passed as arguments to Booleans (i.e. ifTrue:[...]) or
       
   203 collections (i.e. do:[...]).'
       
   204     ].
       
   205 
       
   206     string knownAsSymbol ifTrue:[
       
   207         ^ string , ' is known as a symbol.
       
   208 
       
   209 Symbols are unique strings, meaning that there exists
       
   210 exactly one instance of a given symbol. Therefore symbols can
       
   211 be compared using == (identity compare) instead of = (contents compare).'
       
   212     ].
       
   213 
       
   214     (string startsWith:'#' ) ifTrue:[
       
   215         (string startsWith:'#(' ) ifTrue:[
       
   216             ^ 'is a constant Array.
       
   217 
       
   218 The elements of a constant Array must be Number-constants, nil, true or false.
       
   219 (notice, that not all smalltalk implementations allow true, false and nil as
       
   220  constant-Array elements).'
       
   221         ].
       
   222 
       
   223         (string startsWith:'#[') ifTrue:[
       
   224             ^ 'is a constant ByteArray.
       
   225 
       
   226 The elements of a constant ByteArray must be Integer constants in the range
       
   227 0 .. 255.
       
   228 (notice, that not all smalltalk implementations support constant ByteArrays).'
       
   229         ].
       
   230 
       
   231         ^ 'is a symbol.
       
   232 
       
   233 Symbols are unique strings, meaning that there exists
       
   234 exactly one instance of a given symbol. Therefore symbols can
       
   235 be compared using == (identity compare) instead of = (contents compare).'
       
   236     ].
       
   237 
       
   238     parser isNil ifTrue:[
       
   239         ^ 'parse error -no explanation'
       
   240     ].
       
   241     ^ 'cannot explain this - select individual tokens for an explanation.'
       
   242 !
       
   243 
       
   244 explainPseudoVariable:string in:aClass
       
   245     "return explanation for the pseudoVariables self, super etc."
       
   246 
       
   247     (string = 'self') ifTrue:[
       
   248         ^ 'self refers to the object which received the message.
       
   249 
       
   250 In this case, it will be an instance of ' , aClass name , '
       
   251 or one of its subclasses.'
       
   252     ].
       
   253 
       
   254     (string = 'super') ifTrue:[
       
   255         ^ 'like self, super refers to the object which received the message.
       
   256 
       
   257 However, when sending a message to super the search for methods
       
   258 implementing this message will start in the superclass (' , aClass superclass name , ')
       
   259 instead of selfs class.'
       
   260     ].
       
   261 
       
   262     (string = 'true') ifTrue:[
       
   263         ^ 'true is a pseudo variable (i.e. it is built in).
       
   264 
       
   265 True represents logical truth. It is the one and only instance of class True.'
       
   266     ].
       
   267 
       
   268     (string = 'thisContext') ifTrue:[
       
   269         ^ 'thisContext is a pseudo variable (i.e. it is built in).
       
   270 
       
   271 ThisContext always refers to the context object for the currently executed Method or
       
   272 Block (an instance of Context or BlockContext respectively). The calling chain and calling
       
   273 selectors can be accessed via thisContext.'
       
   274     ].
       
   275 
       
   276     (string = 'false') ifTrue:[
       
   277         ^ 'false is a pseudo variable (i.e. it is built in).
       
   278 
       
   279 False represents logical falseness. It is the one and only instance of class False.'
       
   280     ].
       
   281 
       
   282     (string = 'nil') ifTrue:[
       
   283         ^ 'nil is a pseudo variable (i.e. it is built in).
       
   284 
       
   285 Nil is used for unitialized variables (among other uses).
       
   286 Nil is the one and only instance of class UndefinedObject.'
       
   287     ].
       
   288     ^ nil
       
   289 !
       
   290 
       
   291 
       
   292 commonSuperClassOf:listOfClassNames
       
   293     |common found|
       
   294 
       
   295     listOfClassNames do:[:className |
       
   296 	|class|
       
   297 
       
   298 	((className endsWith:'class') and:[className ~= 'Metaclass']) ifTrue:[
       
   299 	    class := Smalltalk at:(className copyFrom:1 to:(className size - 5)) asSymbol class
       
   300 	] ifFalse:[
       
   301 	    class := Smalltalk at:(className asSymbol).
       
   302 	].
       
   303 	common isNil ifTrue:[
       
   304 	    common := class
       
   305 	] ifFalse:[
       
   306 	    (class isSubclassOf:common) ifTrue:[
       
   307 		"keep common"
       
   308 	    ] ifFalse:[
       
   309 		(common isSubclassOf:class) ifTrue:[
       
   310 		    common := class
       
   311 		] ifFalse:[
       
   312 		    "walk up, checking"
       
   313 		    found := false.
       
   314 		    common allSuperclassesDo:[:sup |
       
   315 			(class isSubclassOf:sup) ifTrue:[
       
   316 			    common := sup
       
   317 			]
       
   318 		    ].
       
   319 		    found ifFalse:[
       
   320 		        class allSuperclassesDo:[:sup |
       
   321 			    (common isSubclassOf:sup) ifTrue:[
       
   322 			        common := sup
       
   323 			    ]
       
   324 		        ].
       
   325 		    ].
       
   326 		]
       
   327 	    ].
       
   328 	].
       
   329 	common == Object ifTrue:[^ common]
       
   330     ].
       
   331     ^ common
       
   332 ! !