Explainer.st
changeset 2 0aae80a0ae84
child 6 0cd4e7480440
--- /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
+! !