function ApplyPatchMultiChunk(script, diff_array, new_source, preview_only,
      change_log) {

    var old_source = script.source;

    // Gather compile information about old version of script.
    var old_compile_info = GatherCompileInfo(old_source, script);

    // Build tree structures for old and new versions of the script.
    var root_old_node = BuildCodeInfoTree(old_compile_info);

    var pos_translator = new PosTranslator(diff_array);

    // Analyze changes.
    MarkChangedFunctions(root_old_node, pos_translator.GetChunks());

    // Find all SharedFunctionInfo's that were compiled from this script.
    FindLiveSharedInfos(root_old_node, script);

    // Gather compile information about new version of script.
    var new_compile_info;
    try {
      new_compile_info = GatherCompileInfo(new_source, script);
    } catch (e) {
      var failure =
          new Failure("Failed to compile new version of script: " + e);
      if (e instanceof SyntaxError) {
        var details = {
          type: "liveedit_compile_error",
          syntaxErrorMessage: e.message
        };
        CopyErrorPositionToDetails(e, details);
        failure.details = details;
      }
      throw failure;
    }
    var root_new_node = BuildCodeInfoTree(new_compile_info);

    // Link recompiled script data with other data.
    FindCorrespondingFunctions(root_old_node, root_new_node);

    // Prepare to-do lists.
    var replace_code_list = new GlobalArray();
    var link_to_old_script_list = new GlobalArray();
    var link_to_original_script_list = new GlobalArray();
    var update_positions_list = new GlobalArray();

    function HarvestTodo(old_node) {
      function CollectDamaged(node) {
        link_to_old_script_list.push(node);
        for (var i = 0; i < node.children.length; i++) {
          CollectDamaged(node.children[i]);
        }
      }

      // Recursively collects all newly compiled functions that are going into
      // business and should have link to the actual script updated.
      function CollectNew(node_list) {
        for (var i = 0; i < node_list.length; i++) {
          link_to_original_script_list.push(node_list[i]);
          CollectNew(node_list[i].children);
        }
      }

      if (old_node.status == FunctionStatus.DAMAGED) {
        CollectDamaged(old_node);
        return;
      }
      if (old_node.status == FunctionStatus.UNCHANGED) {
        update_positions_list.push(old_node);
      } else if (old_node.status == FunctionStatus.SOURCE_CHANGED) {
        update_positions_list.push(old_node);
      } else if (old_node.status == FunctionStatus.CHANGED) {
        replace_code_list.push(old_node);
        CollectNew(old_node.unmatched_new_nodes);
      }
      for (var i = 0; i < old_node.children.length; i++) {
        HarvestTodo(old_node.children[i]);
      }
    }

    var preview_description = {
        change_tree: DescribeChangeTree(root_old_node),
        textual_diff: {
          old_len: old_source.length,
          new_len: new_source.length,
          chunks: diff_array
        },
        updated: false
    };

    if (preview_only) {
      return preview_description;
    }

    HarvestTodo(root_old_node);

    // Collect shared infos for functions whose code need to be patched.
    var replaced_function_old_infos = new GlobalArray();
    var replaced_function_new_infos = new GlobalArray();
    for (var i = 0; i < replace_code_list.length; i++) {
      var old_infos = replace_code_list[i].live_shared_function_infos;
      var new_info =
          replace_code_list[i].corresponding_node.info.shared_function_info;

      if (old_infos) {
        for (var j = 0; j < old_infos.length; j++) {
          replaced_function_old_infos.push(old_infos[j]);
          replaced_function_new_infos.push(new_info);
        }
      }
    }

    // We haven't changed anything before this line yet.
    // Committing all changes.

    // Check that function being patched is not currently on stack or drop them.
    var dropped_functions_number =
        CheckStackActivations(replaced_function_old_infos,
                              replaced_function_new_infos,
                              change_log);

    // Our current implementation requires client to manually issue "step in"
    // command for correct stack state if the stack was modified.
    preview_description.stack_modified = dropped_functions_number != 0;

    // Start with breakpoints. Convert their line/column positions and
    // temporary remove.
    var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log);

    var old_script;

    // Create an old script only if there are function that should be linked
    // to old version.
    if (link_to_old_script_list.length == 0) {
      %LiveEditReplaceScript(script, new_source, null);
      old_script = UNDEFINED;
    } else {
      var old_script_name = CreateNameForOldScript(script);

      // Update the script text and create a new script representing an old
      // version of the script.
      old_script = %LiveEditReplaceScript(script, new_source,
          old_script_name);

      var link_to_old_script_report = new GlobalArray();
      change_log.push( { linked_to_old_script: link_to_old_script_report } );

      // We need to link to old script all former nested functions.
      for (var i = 0; i < link_to_old_script_list.length; i++) {
        LinkToOldScript(link_to_old_script_list[i], old_script,
            link_to_old_script_report);
      }

      preview_description.created_script_name = old_script_name;
    }

    // Link to an actual script all the functions that we are going to use.
    for (var i = 0; i < link_to_original_script_list.length; i++) {
      %LiveEditFunctionSetScript(
          link_to_original_script_list[i].info.shared_function_info, script);
    }

    for (var i = 0; i < replace_code_list.length; i++) {
      PatchFunctionCode(replace_code_list[i], change_log);
    }

    var position_patch_report = new GlobalArray();
    change_log.push( {position_patched: position_patch_report} );

    for (var i = 0; i < update_positions_list.length; i++) {
      // TODO(LiveEdit): take into account whether it's source_changed or
      // unchanged and whether positions changed at all.
      PatchPositions(update_positions_list[i], diff_array,
          position_patch_report);

      if (update_positions_list[i].live_shared_function_infos) {
        update_positions_list[i].live_shared_function_infos.
            forEach(function (info) {
                %LiveEditFunctionSourceUpdated(info.raw_array);
              });
      }
    }

    break_points_restorer(pos_translator, old_script);

    preview_description.updated = true;
    return preview_description;
  }
function ApplyPatchMultiChunk(script, diff_array, new_source, preview_only,
      change_log) {

    var old_source = script.source;

    
    var old_compile_info = GatherCompileInfo(old_source, script);

    
    var root_old_node = BuildCodeInfoTree(old_compile_info);

    var pos_translator = new PosTranslator(diff_array);

    
    MarkChangedFunctions(root_old_node, pos_translator.GetChunks());

    
    FindLiveSharedInfos(root_old_node, script);

    
    var new_compile_info;
    try {
      new_compile_info = GatherCompileInfo(new_source, script);
    } catch (e) {
      var failure =
          new Failure("Failed to compile new version of script: " + e);
      if (e instanceof SyntaxError) {
        var details = {
          type: "liveedit_compile_error",
          syntaxErrorMessage: e.message
        };
        CopyErrorPositionToDetails(e, details);
        failure.details = details;
      }
      throw failure;
    }
    var root_new_node = BuildCodeInfoTree(new_compile_info);

    
    FindCorrespondingFunctions(root_old_node, root_new_node);

    
    var replace_code_list = new GlobalArray();
    var link_to_old_script_list = new GlobalArray();
    var link_to_original_script_list = new GlobalArray();
    var update_positions_list = new GlobalArray();

    function HarvestTodo(old_node) {
      function CollectDamaged(node) {
        link_to_old_script_list.push(node);
        for (var i = 0; i < node.children.length; i++) {
          CollectDamaged(node.children[i]);
        }
      }

      
      
      function CollectNew(node_list) {
        for (var i = 0; i < node_list.length; i++) {
          link_to_original_script_list.push(node_list[i]);
          CollectNew(node_list[i].children);
        }
      }

      if (old_node.status == FunctionStatus.DAMAGED) {
        CollectDamaged(old_node);
        return;
      }
      if (old_node.status == FunctionStatus.UNCHANGED) {
        update_positions_list.push(old_node);
      } else if (old_node.status == FunctionStatus.SOURCE_CHANGED) {
        update_positions_list.push(old_node);
      } else if (old_node.status == FunctionStatus.CHANGED) {
        replace_code_list.push(old_node);
        CollectNew(old_node.unmatched_new_nodes);
      }
      for (var i = 0; i < old_node.children.length; i++) {
        HarvestTodo(old_node.children[i]);
      }
    }

    var preview_description = {
        change_tree: DescribeChangeTree(root_old_node),
        textual_diff: {
          old_len: old_source.length,
          new_len: new_source.length,
          chunks: diff_array
        },
        updated: false
    };

    if (preview_only) {
      return preview_description;
    }

    HarvestTodo(root_old_node);

    
    var replaced_function_old_infos = new GlobalArray();
    var replaced_function_new_infos = new GlobalArray();
    for (var i = 0; i < replace_code_list.length; i++) {
      var old_infos = replace_code_list[i].live_shared_function_infos;
      var new_info =
          replace_code_list[i].corresponding_node.info.shared_function_info;

      if (old_infos) {
        for (var j = 0; j < old_infos.length; j++) {
          replaced_function_old_infos.push(old_infos[j]);
          replaced_function_new_infos.push(new_info);
        }
      }
    }

    
    

    
    var dropped_functions_number =
        CheckStackActivations(replaced_function_old_infos,
                              replaced_function_new_infos,
                              change_log);

    
    
    preview_description.stack_modified = dropped_functions_number != 0;

    
    
    var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log);

    var old_script;

    
    
    if (link_to_old_script_list.length == 0) {
      %LiveEditReplaceScript(script, new_source, null);
      old_script = UNDEFINED;
    } else {
      var old_script_name = CreateNameForOldScript(script);

      
      
      old_script = %LiveEditReplaceScript(script, new_source,
          old_script_name);

      var link_to_old_script_report = new GlobalArray();
      change_log.push( { linked_to_old_script: link_to_old_script_report } );

      
      for (var i = 0; i < link_to_old_script_list.length; i++) {
        LinkToOldScript(link_to_old_script_list[i], old_script,
            link_to_old_script_report);
      }

      preview_description.created_script_name = old_script_name;
    }

    
    for (var i = 0; i < link_to_original_script_list.length; i++) {
      %LiveEditFunctionSetScript(
          link_to_original_script_list[i].info.shared_function_info, script);
    }

    for (var i = 0; i < replace_code_list.length; i++) {
      PatchFunctionCode(replace_code_list[i], change_log);
    }

    var position_patch_report = new GlobalArray();
    change_log.push( {position_patched: position_patch_report} );

    for (var i = 0; i < update_positions_list.length; i++) {
      
      
      PatchPositions(update_positions_list[i], diff_array,
          position_patch_report);

      if (update_positions_list[i].live_shared_function_infos) {
        update_positions_list[i].live_shared_function_infos.
            forEach(function (info) {
                %LiveEditFunctionSourceUpdated(info.raw_array);
              });
      }
    }

    break_points_restorer(pos_translator, old_script);

    preview_description.updated = true;
    return preview_description;
  }
function ApplyPatchMultiChunk ( script , diff_array , new_source , preview_only , change_log ) { var old_source = script . source ; // Gather compile information about old version of script. var old_compile_info = GatherCompileInfo ( old_source , script ) ; // Build tree structures for old and new versions of the script. var root_old_node = BuildCodeInfoTree ( old_compile_info ) ; var pos_translator = new PosTranslator ( diff_array ) ; // Analyze changes. MarkChangedFunctions ( root_old_node , pos_translator . GetChunks ( ) ) ; // Find all SharedFunctionInfo's that were compiled from this script. FindLiveSharedInfos ( root_old_node , script ) ; // Gather compile information about new version of script. var new_compile_info ; try { new_compile_info = GatherCompileInfo ( new_source , script ) ; } catch ( e ) { var failure = new Failure ( "Failed to compile new version of script: " + e ) ; if ( e instanceof SyntaxError ) { var details = { type : "liveedit_compile_error" , syntaxErrorMessage : e . message } ; CopyErrorPositionToDetails ( e , details ) ; failure . details = details ; } throw failure ; } var root_new_node = BuildCodeInfoTree ( new_compile_info ) ; // Link recompiled script data with other data. FindCorrespondingFunctions ( root_old_node , root_new_node ) ; // Prepare to-do lists. var replace_code_list = new GlobalArray ( ) ; var link_to_old_script_list = new GlobalArray ( ) ; var link_to_original_script_list = new GlobalArray ( ) ; var update_positions_list = new GlobalArray ( ) ; function HarvestTodo ( old_node ) { function CollectDamaged ( node ) { link_to_old_script_list . push ( node ) ; for ( var i = 0 ; i < node . children . length ; i ++ ) { CollectDamaged ( node . children [ i ] ) ; } } // Recursively collects all newly compiled functions that are going into // business and should have link to the actual script updated. function CollectNew ( node_list ) { for ( var i = 0 ; i < node_list . length ; i ++ ) { link_to_original_script_list . push ( node_list [ i ] ) ; CollectNew ( node_list [ i ] . children ) ; } } if ( old_node . status == FunctionStatus . DAMAGED ) { CollectDamaged ( old_node ) ; return ; } if ( old_node . status == FunctionStatus . UNCHANGED ) { update_positions_list . push ( old_node ) ; } else if ( old_node . status == FunctionStatus . SOURCE_CHANGED ) { update_positions_list . push ( old_node ) ; } else if ( old_node . status == FunctionStatus . CHANGED ) { replace_code_list . push ( old_node ) ; CollectNew ( old_node . unmatched_new_nodes ) ; } for ( var i = 0 ; i < old_node . children . length ; i ++ ) { HarvestTodo ( old_node . children [ i ] ) ; } } var preview_description = { change_tree : DescribeChangeTree ( root_old_node ) , textual_diff : { old_len : old_source . length , new_len : new_source . length , chunks : diff_array } , updated : false } ; if ( preview_only ) { return preview_description ; } HarvestTodo ( root_old_node ) ; // Collect shared infos for functions whose code need to be patched. var replaced_function_old_infos = new GlobalArray ( ) ; var replaced_function_new_infos = new GlobalArray ( ) ; for ( var i = 0 ; i < replace_code_list . length ; i ++ ) { var old_infos = replace_code_list [ i ] . live_shared_function_infos ; var new_info = replace_code_list [ i ] . corresponding_node . info . shared_function_info ; if ( old_infos ) { for ( var j = 0 ; j < old_infos . length ; j ++ ) { replaced_function_old_infos . push ( old_infos [ j ] ) ; replaced_function_new_infos . push ( new_info ) ; } } } // We haven't changed anything before this line yet. // Committing all changes. // Check that function being patched is not currently on stack or drop them. var dropped_functions_number = CheckStackActivations ( replaced_function_old_infos , replaced_function_new_infos , change_log ) ; // Our current implementation requires client to manually issue "step in" // command for correct stack state if the stack was modified. preview_description . stack_modified = dropped_functions_number != 0 ; // Start with breakpoints. Convert their line/column positions and // temporary remove. var break_points_restorer = TemporaryRemoveBreakPoints ( script , change_log ) ; var old_script ; // Create an old script only if there are function that should be linked // to old version. if ( link_to_old_script_list . length == 0 ) { % LiveEditReplaceScript ( script , new_source , null ) ; old_script = UNDEFINED ; } else { var old_script_name = CreateNameForOldScript ( script ) ; // Update the script text and create a new script representing an old // version of the script. old_script = % LiveEditReplaceScript ( script , new_source , old_script_name ) ; var link_to_old_script_report = new GlobalArray ( ) ; change_log . push ( { linked_to_old_script : link_to_old_script_report } ) ; // We need to link to old script all former nested functions. for ( var i = 0 ; i < link_to_old_script_list . length ; i ++ ) { LinkToOldScript ( link_to_old_script_list [ i ] , old_script , link_to_old_script_report ) ; } preview_description . created_script_name = old_script_name ; } // Link to an actual script all the functions that we are going to use. for ( var i = 0 ; i < link_to_original_script_list . length ; i ++ ) { % LiveEditFunctionSetScript ( link_to_original_script_list [ i ] . info . shared_function_info , script ) ; } for ( var i = 0 ; i < replace_code_list . length ; i ++ ) { PatchFunctionCode ( replace_code_list [ i ] , change_log ) ; } var position_patch_report = new GlobalArray ( ) ; change_log . push ( { position_patched : position_patch_report } ) ; for ( var i = 0 ; i < update_positions_list . length ; i ++ ) { // TODO(LiveEdit): take into account whether it's source_changed or // unchanged and whether positions changed at all. PatchPositions ( update_positions_list [ i ] , diff_array , position_patch_report ) ; if ( update_positions_list [ i ] . live_shared_function_infos ) { update_positions_list [ i ] . live_shared_function_infos . forEach ( function ( info ) { % LiveEditFunctionSourceUpdated ( info . raw_array ) ; } ) ; } } break_points_restorer ( pos_translator , old_script ) ; preview_description . updated = true ; return preview_description ; }
Applies the change to the script. The change is in form of list of chunks encoded in a single array as a series of triplets (pos1_start, pos1_end, pos2_end)
Applies the change to the script . The change is in form of list of chunks encoded in a single array as a series of triplets ( pos1_start pos1_end pos2_end )