reports/Builder__ReportSourceInfo.st
changeset 168 0cbcad0521b6
child 194 cea07153d29c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reports/Builder__ReportSourceInfo.st	Tue Jun 25 20:28:28 2013 +0200
@@ -0,0 +1,243 @@
+"{ Package: 'stx:goodies/builder/reports' }"
+
+"{ NameSpace: Builder }"
+
+Object subclass:#ReportSourceInfo
+	instanceVariableNames:'klass filename offsets lineEnds'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'Builder-Reports-Utils'
+!
+
+Stream subclass:#LineCountingStream
+	instanceVariableNames:'position lineEnds'
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:ReportSourceInfo
+!
+
+!ReportSourceInfo class methodsFor:'documentation'!
+
+documentation
+"
+    Utility class to map line numbers in methods to global 
+    line number in source file (in chunk-formatted .st file)
+
+    [author:]
+        Jan Vrany <jan.vrany@fit.cvut.cz>
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!ReportSourceInfo class methodsFor:'instance creation'!
+
+for: aClass
+    ^self new setClass: aClass
+
+    "Created: / 01-03-2013 / 17:50:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!ReportSourceInfo methodsFor:'initialization'!
+
+setClass: aClass
+    klass := aClass theNonMetaclass.
+    self setup.
+
+    "Created: / 01-03-2013 / 17:49:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+setup
+    "To be called after class is set"
+
+    | stream |
+
+    stream := LineCountingStream new.
+    offsets := Dictionary new.
+
+    [
+        self fileOutOn: stream.
+    ] on: AbstractSourceFileWriter methodSourceRewriteQuery do:[:rewriteQuery |
+        | m |
+
+        m := rewriteQuery method.
+        offsets at: m put: stream position + 1.
+        rewriteQuery proceed.
+    ].
+    lineEnds := stream lineEnds
+
+    "
+        SourceInfo for: Builder::ReportRunner
+    "
+
+    "Created: / 01-03-2013 / 17:30:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 03-03-2013 / 11:09:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!ReportSourceInfo methodsFor:'queries'!
+
+lineAndColumnOfOffset: offset
+    | low high middle element line col |
+
+    low := 1.
+    high := lineEnds size.
+    [low > high] whileFalse:[
+        middle := (low + high) // 2.
+        element := lineEnds at:middle.
+        element < offset ifTrue:[
+            "middleelement is smaller than object"
+            low := middle + 1
+        ] ifFalse:[
+            high := middle - 1
+        ]
+    ].
+
+    line := low.
+    col := offset - (line > 1 ifTrue:[lineEnds at: line - 1] ifFalse:[0]).
+    ^line @ col.
+
+    "Created: / 03-03-2013 / 10:50:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+offsetOfMethod: aMethod
+    ^offsets at: aMethod
+
+    "Created: / 03-03-2013 / 10:49:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!ReportSourceInfo methodsFor:'utilities'!
+
+fileOutOn:aStream
+    klass fileOutOn: aStream withTimeStamp:false
+
+    "Created: / 01-03-2013 / 17:51:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!ReportSourceInfo::LineCountingStream class methodsFor:'instance creation'!
+
+new
+    "return an initialized instance"
+
+    ^ self basicNew initialize.
+! !
+
+!ReportSourceInfo::LineCountingStream methodsFor:'accessing'!
+
+contents
+    "return the entire contents of the stream.
+     For a readStream, that is the rest (i.e. upToEnd),
+     for a writeStream, that is the collected data. As we do not know here,
+     what we are, this is the responsibility of a subclass..."
+
+    ^ self shouldNotImplement
+
+    "Modified: / 01-03-2013 / 17:36:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+lineEnds
+    ^ lineEnds
+!
+
+position
+    ^ position
+! !
+
+!ReportSourceInfo::LineCountingStream methodsFor:'initialization'!
+
+initialize
+    "Invoked when a new instance is created."
+
+    "/ please change as required (and remove this comment)
+    position := 0.
+    lineEnds := OrderedCollection new.
+
+    "/ super initialize.   -- commented since inherited method does nothing
+
+    "Modified: / 01-03-2013 / 17:39:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!ReportSourceInfo::LineCountingStream methodsFor:'queries'!
+
+isReadable
+    "return true, if reading is supported by the recevier.
+     This has to be redefined in concrete subclasses."
+
+    ^ false
+
+    "Modified: / 01-03-2013 / 17:36:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+isWritable
+    "return true, if writing is supported by the recevier.
+     This has to be redefined in concrete subclasses."
+
+    ^ true
+
+    "Modified: / 01-03-2013 / 17:37:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+size
+    "return the number of elements in the streamed collection."
+
+    ^ self shouldImplement
+! !
+
+!ReportSourceInfo::LineCountingStream methodsFor:'reading'!
+
+next
+    "return the next element of the stream
+     - we do not know here how to do it, it must be redefined in subclass"
+
+    ^ self shouldNotImplement
+
+    "Modified: / 01-03-2013 / 17:37:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!ReportSourceInfo::LineCountingStream methodsFor:'testing'!
+
+atEnd
+    "return true if the end of the stream has been reached;
+     - we do not know here how to do it, it must be redefined in subclass"
+
+    ^ false
+
+    "Modified: / 01-03-2013 / 17:37:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+isEmpty
+    "return true, if the contents of the stream is empty"
+
+    ^ self shouldNotImplement
+
+    "Modified: / 01-03-2013 / 17:37:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!ReportSourceInfo::LineCountingStream methodsFor:'writing'!
+
+nextPut:aCharacter
+    "put the argument, anObject onto the receiver
+     - we do not know here how to do it, it must be redefined in subclass"
+
+     position := position + 1.
+    aCharacter == Character cr ifTrue:[
+        lineEnds add: position
+    ].
+
+    "Modified: / 01-03-2013 / 17:39:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!ReportSourceInfo class methodsFor:'documentation'!
+
+version
+    ^ '$Header$'
+!
+
+version_CVS
+    ^ '$Header$'
+! !
+