/** Returns the FunctionSource object for the given script or function. */
 private FunctionSource getFunctionSource(DebuggableScript fnOrScript) {
   FunctionSource fsource = functionSource(fnOrScript);
   if (fsource == null) {
     String url = getNormalizedUrl(fnOrScript);
     SourceInfo si = sourceInfo(url);
     if (si == null) {
       if (!fnOrScript.isGeneratedScript()) {
         // Not eval or Function, try to load it from URL
         String source = loadSource(url);
         if (source != null) {
           DebuggableScript top = fnOrScript;
           for (; ; ) {
             DebuggableScript parent = top.getParent();
             if (parent == null) {
               break;
             }
             top = parent;
           }
           registerTopScript(top, source);
           fsource = functionSource(fnOrScript);
         }
       }
     }
   }
   return fsource;
 }
  /** Registers the given script as a top-level script in the debugger. */
  private void registerTopScript(DebuggableScript topScript, String source) {
    if (!topScript.isTopLevel()) {
      throw new IllegalArgumentException();
    }
    String url = getNormalizedUrl(topScript);
    DebuggableScript[] functions = getAllFunctions(topScript);
    final SourceInfo sourceInfo = new SourceInfo(source, functions, url);

    synchronized (urlToSourceInfo) {
      SourceInfo old = urlToSourceInfo.get(url);
      if (old != null) {
        sourceInfo.copyBreakpointsFrom(old);
      }
      urlToSourceInfo.put(url, sourceInfo);
      for (int i = 0; i != sourceInfo.functionSourcesTop(); ++i) {
        FunctionSource fsource = sourceInfo.functionSource(i);
        String name = fsource.name();
        if (name.length() != 0) {
          functionNames.put(name, fsource);
        }
      }
    }

    synchronized (functionToSource) {
      for (int i = 0; i != functions.length; ++i) {
        FunctionSource fsource = sourceInfo.functionSource(i);
        functionToSource.put(functions[i], fsource);
      }
    }

    callback.updateSourceText(sourceInfo);
  }
    /** Called when compilation is finished. */
    public void handleCompilationDone(Context cx, DebuggableScript fnOrScript, String source) {
      if (type != IPROXY_DEBUG) Kit.codeBug();

      if (!fnOrScript.isTopLevel()) {
        return;
      }
      dim.registerTopScript(fnOrScript, source);
    }
 /** Returns the source URL for the given script or function. */
 private String getNormalizedUrl(DebuggableScript fnOrScript) {
   String url = fnOrScript.getSourceName();
   if (url == null) {
     url = "<stdin>";
   } else {
     // Not to produce window for eval from different lines,
     // strip line numbers, i.e. replace all #[0-9]+\(eval\) by
     // (eval)
     // Option: similar teatment for Function?
     char evalSeparator = '#';
     StringBuffer sb = null;
     int urlLength = url.length();
     int cursor = 0;
     for (; ; ) {
       int searchStart = url.indexOf(evalSeparator, cursor);
       if (searchStart < 0) {
         break;
       }
       String replace = null;
       int i = searchStart + 1;
       while (i != urlLength) {
         int c = url.charAt(i);
         if (!('0' <= c && c <= '9')) {
           break;
         }
         ++i;
       }
       if (i != searchStart + 1) {
         // i points after #[0-9]+
         if ("(eval)".regionMatches(0, url, i, 6)) {
           cursor = i + 6;
           replace = "(eval)";
         }
       }
       if (replace == null) {
         break;
       }
       if (sb == null) {
         sb = new StringBuffer();
         sb.append(url.substring(0, searchStart));
       }
       sb.append(replace);
     }
     if (sb != null) {
       if (cursor != urlLength) {
         sb.append(url.substring(cursor));
       }
       url = sb.toString();
     }
   }
   return url;
 }
 /** Helper function for {@link #getAllFunctions(DebuggableScript)}. */
 private static void collectFunctions_r(DebuggableScript function, ObjArray array) {
   array.add(function);
   for (int i = 0; i != function.getFunctionCount(); ++i) {
     collectFunctions_r(function.getFunction(i), array);
   }
 }