@@ -112,6 +112,7 @@ var curVisualizerID = 1; // global to uniquely identify each ExecutionVisualizer
112112// pyCrazyMode - run with Py2crazy, which provides expression-level
113113// granularity instead of line-level granularity (HIGHLY EXPERIMENTAL!)
114114// hideCode - hide the code display and show only the data structure viz
115+ // tabularView - render a tabular view of ALL steps at once (EXPERIMENTAL)
115116function ExecutionVisualizer ( domRootID , dat , params ) {
116117 this . curInputCode = dat . code . rtrim ( ) ; // kill trailing spaces
117118 this . curTrace = dat . trace ;
@@ -193,6 +194,7 @@ function ExecutionVisualizer(domRootID, dat, params) {
193194 this . drawParentPointers = ( this . params . drawParentPointers == true ) ;
194195 this . textualMemoryLabels = ( this . params . textualMemoryLabels == true ) ;
195196 this . showOnlyOutputs = ( this . params . showOnlyOutputs == true ) ;
197+ this . tabularView = ( this . params . tabularView == true ) ;
196198
197199 this . executeCodeWithRawInputFunc = this . params . executeCodeWithRawInputFunc ;
198200
@@ -353,6 +355,11 @@ ExecutionVisualizer.prototype.render = function() {
353355 </table>\
354356 </div>' ;
355357
358+ // override
359+ if ( myViz . tabularView ) {
360+ codeVizHTML = '<div id="optTabularView"></div>' ;
361+ }
362+
356363 var vizHeaderHTML =
357364 '<div id="vizHeader">\
358365 <textarea class="vizTitleText" id="vizTitleEditor" cols="60" rows="1"></textarea>\
@@ -613,6 +620,11 @@ ExecutionVisualizer.prototype.render = function() {
613620 this . renderPyCodeOutput ( ) ;
614621 }
615622
623+ // EXPERIMENTAL!
624+ if ( this . tabularView ) {
625+ this . renderTabularView ( ) ;
626+ }
627+
616628 this . updateOutput ( ) ;
617629
618630 this . hasRendered = true ;
@@ -2073,6 +2085,10 @@ var rightwardNudgeHack = true; // suggested by John DeNero, toggle with global
20732085ExecutionVisualizer . prototype . renderDataStructures = function ( curEntry , curToplevelLayout ) {
20742086 var myViz = this ; // to prevent confusion of 'this' inside of nested functions
20752087
2088+ if ( myViz . tabularView ) {
2089+ return ; // return EARLY!!!
2090+ }
2091+
20762092 myViz . resetJsPlumbManager ( ) ; // very important!!!
20772093
20782094 // for simplicity (but sacrificing some performance), delete all
@@ -2804,6 +2820,152 @@ ExecutionVisualizer.prototype.renderDataStructures = function(curEntry, curTople
28042820}
28052821
28062822
2823+ // render a tabular visualization where each row is an execution step,
2824+ // and each column is a variable
2825+ ExecutionVisualizer . prototype . renderTabularView = function ( ) {
2826+ var myViz = this ; // to prevent confusion of 'this' inside of nested functions
2827+
2828+ myViz . resetJsPlumbManager ( ) ; // very important!!!
2829+
2830+ var allGlobalVars = [ ] ;
2831+ // Key: function name
2832+ // Value: list of ordered variables for function
2833+ var funcNameToOrderedVars = { } ;
2834+ var orderedFuncNames = [ ] ; // function names in order of appearance
2835+
2836+ // iterate through the entire trace and find all global variables, and
2837+ // all local variables in all functions, in order of appearance in the trace
2838+ $ . each ( myViz . curTrace , function ( i , elt ) {
2839+ $ . each ( elt . ordered_globals , function ( i , g ) {
2840+ // don't add duplicates into this list,
2841+ // but need to use a list to maintain ORDERING
2842+ if ( $ . inArray ( g , allGlobalVars ) === - 1 ) {
2843+ allGlobalVars . push ( g ) ;
2844+ }
2845+ } ) ;
2846+
2847+ $ . each ( elt . stack_to_render , function ( i , sf ) {
2848+ var funcVarsList = funcNameToOrderedVars [ sf . func_name ] ;
2849+ if ( funcVarsList === undefined ) {
2850+ funcVarsList = [ ] ;
2851+ funcNameToOrderedVars [ sf . func_name ] = funcVarsList ;
2852+ orderedFuncNames . push ( sf . func_name ) ;
2853+ }
2854+ $ . each ( sf . ordered_varnames , function ( i , v ) {
2855+ // don't add duplicates into this list,
2856+ // but need to use a list to maintain ORDERING
2857+ // (ignore the special __return__ value)
2858+ if ( $ . inArray ( v , funcVarsList ) === - 1 && v !== '__return__' ) {
2859+ funcVarsList . push ( v ) ;
2860+ }
2861+ } ) ;
2862+ } ) ;
2863+ } ) ;
2864+
2865+ /*
2866+ console.log("allGlobalVars:", allGlobalVars);
2867+ console.log("orderedFuncNames:", orderedFuncNames);
2868+ $.each(funcNameToOrderedVars, function(k, v) {
2869+ console.log("funcNameToOrderedVars[", k, "] =", v);
2870+ });
2871+ */
2872+
2873+ var allVarNames = [ ] ;
2874+
2875+ $ . each ( allGlobalVars , function ( i , e ) {
2876+ allVarNames . push ( e ) ;
2877+ } ) ;
2878+ $ . each ( orderedFuncNames , function ( i , funcName ) {
2879+ $ . each ( funcNameToOrderedVars [ funcName ] , function ( i , v ) {
2880+ allVarNames . push ( funcName + ':' + v ) ;
2881+ } ) ;
2882+ } ) ;
2883+ console . log ( allVarNames ) ;
2884+
2885+ // get the values of all objects in trace entry e
2886+ function getAllOrderedValues ( curEntry ) {
2887+ var allVarValues = [ ] ;
2888+
2889+ $ . each ( allGlobalVars , function ( i , e ) {
2890+ allVarValues . push ( curEntry . globals [ e ] ) ;
2891+ } ) ;
2892+
2893+ // for local variables, grab only the values in the highlighted
2894+ // frame (if any)
2895+ var highlightedFrame = null ;
2896+ $ . each ( curEntry . stack_to_render , function ( i , sf ) {
2897+ if ( sf . is_highlighted ) {
2898+ highlightedFrame = sf ;
2899+ }
2900+ } ) ;
2901+
2902+ $ . each ( orderedFuncNames , function ( i , funcName ) {
2903+ $ . each ( funcNameToOrderedVars [ funcName ] , function ( i , v ) {
2904+ var found = false ;
2905+ if ( highlightedFrame && funcName == highlightedFrame . func_name ) {
2906+ var obj = highlightedFrame . encoded_locals [ v ] ;
2907+ if ( obj ) {
2908+ allVarValues . push ( obj ) ;
2909+ found = true ;
2910+ }
2911+ }
2912+
2913+ // push an empty value if not found since we want everything to
2914+ // align with allVarNames
2915+ if ( ! found ) {
2916+ allVarValues . push ( undefined ) ;
2917+ }
2918+ } ) ;
2919+ } ) ;
2920+
2921+ // TODO: also walk up parent pointers to also display variable
2922+ // values in enclosing frames
2923+
2924+ return allVarValues ;
2925+ }
2926+
2927+
2928+ var tblRoot = myViz . domRootD3 . select ( "#optTabularView" ) ;
2929+ var tbl = tblRoot . append ( "table" ) ;
2930+ var tHead = tbl . append ( 'thead' ) . append ( 'tr' ) ;
2931+ tHead . selectAll ( 'thead td' )
2932+ . data ( allVarNames )
2933+ . enter ( )
2934+ . append ( 'td' )
2935+ . html ( function ( d ) { return d ; } )
2936+
2937+ var tBody = tbl . append ( 'tbody' ) ;
2938+
2939+ var stepsAndTraceEntries = [ ] ;
2940+ $ . each ( myViz . curTrace , function ( i , e ) {
2941+ stepsAndTraceEntries . push ( [ i , e ] ) ;
2942+ } ) ;
2943+
2944+ var tr = tBody . selectAll ( 'tbody tr' )
2945+ . data ( stepsAndTraceEntries )
2946+ . enter ( )
2947+ . append ( "tr" )
2948+ . attr ( "step" , function ( d , i ) { return i ; } ) ;
2949+
2950+ var td = tr . selectAll ( "td" )
2951+ . data ( function ( e ) { return getAllOrderedValues ( e [ 1 ] ) ; } )
2952+ . enter ( )
2953+ . append ( "td" )
2954+ . each ( function ( obj , i ) {
2955+ $ ( this ) . empty ( ) ;
2956+ // TODO: fixme -- this is super kludgy; must be a better way
2957+ var step = parseInt ( $ ( this ) . closest ( 'tr' ) . attr ( 'step' ) ) ;
2958+
2959+ if ( obj === undefined ) {
2960+ // keep this table cell EMPTY
2961+ }
2962+ else {
2963+ myViz . renderNestedObject ( obj , step , $ ( this ) , 'tabular' ) ;
2964+ }
2965+ } ) ;
2966+ }
2967+
2968+
28072969// rendering functions, which all take a d3 dom element to anchor the
28082970// new element to render
28092971ExecutionVisualizer . prototype . renderPrimitiveObject = function ( obj , d3DomElement ) {
0 commit comments