nl_tokens: Applies a list of the textual diff chunks onto the tree of functions . Determines status of each function ( from unchanged to damaged ) . However children of unchanged functions are ignored .
pl_tokens: function MarkChangedFunctions ( code_info_tree , chunks ) { // A convenient iterator over diff chunks that also translates // positions from old to new in a current non-changed part of script. var chunk_it = new function ( ) { var chunk_index = 0 ; var pos_diff = 0 ; this . current = function ( ) { return chunks [ chunk_index ] ; } ; this . next = function ( ) { var chunk = chunks [ chunk_index ] ; pos_diff = chunk . pos2 + chunk . len2 - ( chunk . pos1 + chunk . len1 ) ; chunk_index ++ ; } ; this . done = function ( ) { return chunk_index >= chunks . length ; } ; this . TranslatePos = function ( pos ) { return pos + pos_diff ; } ; } ; // A recursive function that processes internals of a function and all its // inner functions. Iterator chunk_it initially points to a chunk that is // below function start. function ProcessInternals ( info_node ) { info_node . new_start_pos = chunk_it . TranslatePos ( info_node . info . start_position ) ; var child_index = 0 ; var code_changed = false ; var source_changed = false ; // Simultaneously iterates over child functions and over chunks. while ( ! chunk_it . done ( ) && chunk_it . current ( ) . pos1 < info_node . info . end_position ) { if ( child_index < info_node . <mask> . length ) { var child = info_node . children [ child_index ] ; if ( child . info . end_position <= chunk_it . current ( ) . pos1 ) { ProcessUnchangedChild ( child ) ; child_index ++ ; continue ; } else if ( child . info . start_position >= chunk_it . current ( ) . pos1 + chunk_it . current ( ) . len1 ) { code_changed = true ; chunk_it . next ( ) ; continue ; } else if ( child . info . start_position <= chunk_it . current ( ) . pos1 && child . info . end_position >= chunk_it . current ( ) . pos1 + chunk_it . current ( ) . len1 ) { ProcessInternals ( child ) ; source_changed = source_changed || ( child . status != FunctionStatus . UNCHANGED ) ; code_changed = code_changed || ( child . status == FunctionStatus . DAMAGED ) ; child_index ++ ; continue ; } else { code_changed = true ; child . status = FunctionStatus . DAMAGED ; child . status_explanation = "Text diff overlaps with function boundary" ; child_index ++ ; continue ; } } else { if ( chunk_it . current ( ) . pos1 + chunk_it . current ( ) . len1 <= info_node . info . end_position ) { info_node . status = FunctionStatus . CHANGED ; chunk_it . next ( ) ; continue ; } else { info_node . status = FunctionStatus . DAMAGED ; info_node . status_explanation = "Text diff overlaps with function boundary" ; return ; } } Assert ( "Unreachable" , false ) ; } while ( child_index < info_node . children . length ) { var child = info_node . children [ child_index ] ; ProcessUnchangedChild ( child ) ; child_index ++ ; } if ( code_changed ) { info_node . status = FunctionStatus . CHANGED ; } else if ( source_changed ) { info_node . status = FunctionStatus . SOURCE_CHANGED ; } info_node . new_end_pos = chunk_it . TranslatePos ( info_node . info . end_position ) ; } function ProcessUnchangedChild ( node ) { node . new_start_pos = chunk_it . TranslatePos ( node . info . start_position ) ; node . new_end_pos = chunk_it . TranslatePos ( node . info . end_position ) ; } ProcessInternals ( code_info_tree ) ; }