--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Explainer.st Wed Oct 13 01:25:45 1993 +0100
@@ -0,0 +1,332 @@
+"
+ COPYRIGHT (c) 1993 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.
+"
+
+Parser subclass:#Explainer
+ instanceVariableNames:''
+ classVariableNames:''
+ poolDictionaries:''
+ category:'System-Compiler'
+!
+
+Explainer comment:'
+
+COPYRIGHT (c) 1993 by Claus Gittinger
+ All Rights Reserved
+
+$Header: /cvs/stx/stx/libcomp/Explainer.st,v 1.1 1993-10-13 00:25:45 claus Exp $
+'!
+
+!Explainer class methodsFor:'documentation'!
+
+documentation
+"
+a very simple explainer - much more should be added ...
+"
+! !
+
+!Explainer class methodsFor:'explaining'!
+
+explain:someText in:source forClass:aClass
+ "this is just a q&d implementation - there could be much more.
+ Given a source and a substring of it, return a string containing
+ an explanation."
+
+ |parser variables v c string sym list count tmp
+ commonSuperClass|
+
+ string := someText withoutSeparators.
+ parser := self parseMethod:source in:aClass.
+ parser notNil ifTrue:[
+ "look for variables"
+
+ variables := parser methodVars.
+ (variables notNil and:[variables includes:string]) ifTrue:[
+ ^ string , ' is a method variable'
+ ].
+ variables := parser methodArgs.
+ (variables notNil and:[variables includes:string]) ifTrue:[
+ ^ string , ' is a method argument'
+ ]
+ ].
+ parser isNil ifTrue:[
+ parser := self for:(ReadStream on:source) in:aClass
+ ].
+
+ "instvars"
+ variables := aClass allInstVarNames.
+ (variables notNil and:[variables includes:string]) ifTrue:[
+ "where is it"
+ c := aClass.
+ [c notNil] whileTrue:[
+ v := c instVarNames.
+ (v notNil and:[v includes:string]) ifTrue:[
+ ^ string , ' is an instance variable in ' , c name
+ ].
+ c := c superclass
+ ].
+ self error:'oops'
+ ].
+
+ "class instvars"
+ variables := aClass class allInstVarNames.
+ (variables notNil and:[variables includes:string]) ifTrue:[
+ "where is it"
+ c := aClass.
+ [c notNil] whileTrue:[
+ v := c class instVarNames.
+ (v notNil and:[v includes:string]) ifTrue:[
+ ^ string , ' is a class instance variable in ' , c name
+ ].
+ c := c superclass
+ ].
+ self error:'oops'
+ ].
+
+ "classvars"
+ c := parser inWhichClassIsClassVar:string.
+ c notNil ifTrue:[
+ ^ string , ' is a class variable in ' , c name
+ ].
+
+ string knownAsSymbol ifTrue:[
+ "globals"
+ sym := string asSymbol.
+ (Smalltalk includesKey:sym) ifTrue:[
+ (Smalltalk at:sym) isBehavior ifTrue:[
+ ^ string , ' is a global variable.
+
+' , string , ' is a class in category ' , (Smalltalk at:sym) category , '.'
+ ] ifFalse:[
+ ^ string , ' is a global variable.
+
+Its current value is ' , (Smalltalk at:sym) classNameWithArticle , '.'
+ ]
+ ].
+
+ list := OrderedCollection new.
+ "selectors"
+ Smalltalk allBehaviorsDo:[:c|
+ (c implements:sym) ifTrue:[
+ list add:(c name)
+ ].
+ (c class implements:sym) ifTrue:[
+ list add:(c name , 'class')
+ ]
+ ].
+ count := list size.
+ (count ~~ 0) ifTrue:[
+ tmp := ' is a selector implemented in '.
+ (count == 1) ifTrue:[
+ ^ string , tmp , (list at:1) , '.'
+ ].
+ (count == 2) ifTrue:[
+ ^ string , tmp , (list at:1) , ' and ' , (list at:2) , '.'
+ ].
+ (count == 3) ifTrue:[
+ ^ string , tmp , '
+' , (list at:1) , ', ' , (list at:2) , ' and ' , (list at:3) , '.'
+ ].
+ (count == 4) ifTrue:[
+ ^ string , tmp , '
+' , (list at:1) , ', ' , (list at:2) , ', ' , (list at:3), ' and ' , (list at:4) , '.'
+ ].
+
+ commonSuperClass := self commonSuperClassOf:list.
+ commonSuperClass ~~ Object ifTrue:[
+ ^ string , tmp, count printString , ' subclasses of ' , commonSuperClass name
+ ].
+
+ ^ string , tmp , count printString , ' classes.'
+ ]
+ ].
+
+ "try for some obvious things"
+ tmp := self explainPseudoVariable:string in:aClass.
+ tmp notNil ifTrue:[ ^ tmp].
+
+ "try syntax ..."
+
+ ((string = ':=') or:[string = '_']) ifTrue:[
+ ^ '<variable> := <expression>
+
+:= and _ (which is left-arrow in some fonts) mean assignment.
+The variable is bound to (i.e. points to) the value of <expression>.'
+ ].
+
+ (string = '^') ifTrue:[
+ ^ '^ <expression>
+
+return the value of <expression> as value from the method.
+A return from within a block exits the method where the block is defined.'
+ ].
+
+ (string = ';') ifTrue:[
+ ^ '<expression> ; selector1 ; .... ; selectorN
+
+a cascade expression; evaluate expression, and send messages
+<selector1> ... <selectorN> to the first expressions receiver.
+Returns the value of the last send. The cascade sends may also have arguments.'
+ ].
+
+ (string = '|') ifTrue:[
+ ^ '| locals | or: [:arg | statements]
+
+| is used to mark a local variable declaration or separates arguments
+from the statements in a block. Notice, that in a block-argument declaration
+these must be prefixed by a colon character.
+| is also a selector understood by Booleans.'
+ ].
+
+ ((string startsWith:'(') or:[string endsWith:')']) ifTrue:[
+ ^ '(<expression>)
+
+expression grouping.'
+ ].
+
+ ((string startsWith:'[') or:[string endsWith:']']) ifTrue:[
+ ^ '[arguments | statements]
+
+defines a block.
+Blocks represent pieces of executable code. Definition of a block does
+not evaluate it. The block is evaluated by sending it a value/value:
+message.
+Blocks are often passed as arguments to Booleans (i.e. ifTrue:[...]) or
+collections (i.e. do:[...]).'
+ ].
+
+ string knownAsSymbol ifTrue:[
+ ^ string , ' is known as a symbol.
+
+Symbols are unique strings, meaning that there exists
+exactly one instance of a given symbol. Therefore symbols can
+be compared using == (identity compare) instead of = (contents compare).'
+ ].
+
+ (string startsWith:'#' ) ifTrue:[
+ (string startsWith:'#(' ) ifTrue:[
+ ^ 'is a constant Array.
+
+The elements of a constant Array must be Number-constants, nil, true or false.
+(notice, that not all smalltalk implementations allow true, false and nil as
+ constant-Array elements).'
+ ].
+
+ (string startsWith:'#[') ifTrue:[
+ ^ 'is a constant ByteArray.
+
+The elements of a constant ByteArray must be Integer constants in the range
+0 .. 255.
+(notice, that not all smalltalk implementations support constant ByteArrays).'
+ ].
+
+ ^ 'is a symbol.
+
+Symbols are unique strings, meaning that there exists
+exactly one instance of a given symbol. Therefore symbols can
+be compared using == (identity compare) instead of = (contents compare).'
+ ].
+
+ parser isNil ifTrue:[
+ ^ 'parse error -no explanation'
+ ].
+ ^ 'cannot explain this - select individual tokens for an explanation.'
+!
+
+explainPseudoVariable:string in:aClass
+ "return explanation for the pseudoVariables self, super etc."
+
+ (string = 'self') ifTrue:[
+ ^ 'self refers to the object which received the message.
+
+In this case, it will be an instance of ' , aClass name , '
+or one of its subclasses.'
+ ].
+
+ (string = 'super') ifTrue:[
+ ^ 'like self, super refers to the object which received the message.
+
+However, when sending a message to super the search for methods
+implementing this message will start in the superclass (' , aClass superclass name , ')
+instead of selfs class.'
+ ].
+
+ (string = 'true') ifTrue:[
+ ^ 'true is a pseudo variable (i.e. it is built in).
+
+True represents logical truth. It is the one and only instance of class True.'
+ ].
+
+ (string = 'thisContext') ifTrue:[
+ ^ 'thisContext is a pseudo variable (i.e. it is built in).
+
+ThisContext always refers to the context object for the currently executed Method or
+Block (an instance of Context or BlockContext respectively). The calling chain and calling
+selectors can be accessed via thisContext.'
+ ].
+
+ (string = 'false') ifTrue:[
+ ^ 'false is a pseudo variable (i.e. it is built in).
+
+False represents logical falseness. It is the one and only instance of class False.'
+ ].
+
+ (string = 'nil') ifTrue:[
+ ^ 'nil is a pseudo variable (i.e. it is built in).
+
+Nil is used for unitialized variables (among other uses).
+Nil is the one and only instance of class UndefinedObject.'
+ ].
+ ^ nil
+!
+
+
+commonSuperClassOf:listOfClassNames
+ |common found|
+
+ listOfClassNames do:[:className |
+ |class|
+
+ ((className endsWith:'class') and:[className ~= 'Metaclass']) ifTrue:[
+ class := Smalltalk at:(className copyFrom:1 to:(className size - 5)) asSymbol class
+ ] ifFalse:[
+ class := Smalltalk at:(className asSymbol).
+ ].
+ common isNil ifTrue:[
+ common := class
+ ] ifFalse:[
+ (class isSubclassOf:common) ifTrue:[
+ "keep common"
+ ] ifFalse:[
+ (common isSubclassOf:class) ifTrue:[
+ common := class
+ ] ifFalse:[
+ "walk up, checking"
+ found := false.
+ common allSuperclassesDo:[:sup |
+ (class isSubclassOf:sup) ifTrue:[
+ common := sup
+ ]
+ ].
+ found ifFalse:[
+ class allSuperclassesDo:[:sup |
+ (common isSubclassOf:sup) ifTrue:[
+ common := sup
+ ]
+ ].
+ ].
+ ]
+ ].
+ ].
+ common == Object ifTrue:[^ common]
+ ].
+ ^ common
+! !