private static void go(ParseTree node, StringBuilder b, api.Platforms platform)
     throws ConfigCompileException {
   if (node.hasChildren()) {
     FunctionBase f = FunctionList.getFunction(node.getData(), platform);
     if (!(f instanceof CompiledFunction)) {
       throw new ConfigCompileException(
           "The function " + f.getName() + " is unknown in this platform.",
           node.getData().getTarget());
     }
     CompiledFunction cf = (CompiledFunction) f;
     List<String> children = new ArrayList<String>();
     for (ParseTree baby : node.getChildren()) {
       StringBuilder bb = new StringBuilder();
       go(baby, bb, platform);
       children.add(bb.toString());
     }
     b.append(
         cf.compile(node.getData().getTarget(), children.toArray(new String[children.size()])));
   } else {
     if (platform.getResolver() == null) {
       b.append(node.getData().val());
     } else {
       b.append(platform.getResolver().outputConstant(node.getData()));
     }
   }
 }
  /**
   * Returns the documentation for a single function.
   *
   * @param type The type of output to use. May be one of: html, wiki, text
   * @param platform The platform we're using
   * @param staged Is this for the staged wiki?
   * @return
   * @throws ConfigCompileException
   */
  public static String functions(MarkupType type, api.Platforms platform, boolean staged)
      throws ConfigCompileException {
    Set<FunctionBase> functions = FunctionList.getFunctionList(platform);
    HashMap<Class, ArrayList<FunctionBase>> functionlist =
        new HashMap<Class, ArrayList<FunctionBase>>();
    StringBuilder out = new StringBuilder();
    for (FunctionBase f : functions) {
      // Sort the functions into classes
      Class apiClass =
          (f.getClass().getEnclosingClass() != null ? f.getClass().getEnclosingClass() : null);
      ArrayList<FunctionBase> fl = functionlist.get(apiClass);
      if (fl == null) {
        fl = new ArrayList<FunctionBase>();
        functionlist.put(apiClass, fl);
      }
      fl.add(f);
    }
    if (type == MarkupType.HTML) {
      out.append(
          "Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
              + "and make the plugin a fully "
              + "<a href=\"http://en.wikipedia.org/wiki/Turing_Complete\">Turing Complete</a> language. "
              + "There are several functions defined, and they are grouped into \"classes\". \n");
    } else if (type == MarkupType.WIKI) {
      out.append(
          "Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
              + "and make the plugin a fully "
              + "[http://en.wikipedia.org/wiki/Turing_Complete Turing Complete] language. "
              + "There are several functions defined, and they are grouped into \"classes\". \n");
      out.append(
          "<p>Each function has its own page for documentation, where you can put examples for how to use"
              + " particular functions. Because this is a wiki, it is encouraged that you edit the pages if you see errors, "
              + "or can think of a better example to show. Please copy over [[CommandHelper/API/Function Template|this template]]"
              + " and use it.\n");
    } else if (type == MarkupType.TEXT) {
      out.append(
          "Command Helper uses a language called MethodScript, which greatly extend the capabilities of the plugin, "
              + "and make the plugin a fully "
              + "Turing Complete language [http://en.wikipedia.org/wiki/Turing_Complete].\n"
              + "There are several functions defined, and they are grouped into \"classes\".\n");
    }
    List<Map.Entry<Class, ArrayList<FunctionBase>>> entrySet =
        new ArrayList<Map.Entry<Class, ArrayList<FunctionBase>>>(functionlist.entrySet());
    Collections.sort(
        entrySet,
        new Comparator<Map.Entry<Class, ArrayList<FunctionBase>>>() {

          @Override
          public int compare(
              Map.Entry<Class, ArrayList<FunctionBase>> o1,
              Map.Entry<Class, ArrayList<FunctionBase>> o2) {
            return o1.getKey().getName().compareTo(o2.getKey().getName());
          }
        });
    int total = 0;

    int workingExamples = 0;
    for (Map.Entry<Class, ArrayList<FunctionBase>> entry : entrySet) {
      Class apiClass = entry.getKey();
      String className =
          apiClass.getName().split("\\.")[apiClass.getName().split("\\.").length - 1];
      if (className.equals("Sandbox")) {
        continue; // Skip Sandbox functions
      }
      String classDocs = null;
      try {
        Method m = apiClass.getMethod("docs", (Class[]) null);
        Object o = null;
        if ((m.getModifiers() & Modifier.STATIC) == 0) {
          try {
            o = apiClass.newInstance();
          } catch (InstantiationException ex) {
          }
        }
        classDocs = (String) m.invoke(o, (Object[]) null);
      } catch (IllegalAccessException ex) {
      } catch (IllegalArgumentException ex) {
      } catch (InvocationTargetException ex) {
      } catch (NoSuchMethodException e) {
      } catch (Exception e) {
        e.printStackTrace(System.err);
        System.err.println("Continuing however.");
      }
      StringBuilder intro = new StringBuilder();
      if (type == MarkupType.HTML) {
        if (className != null) {
          intro.append("<h1>").append(className).append("</h1>" + "\n");
          intro.append(classDocs == null ? "" : classDocs).append("\n");
        } else {
          intro.append("<h1>Other Functions</h1>" + "\n");
        }
        intro.append("<table>" + "\n");
      } else if (type == MarkupType.WIKI) {
        if (className != null) {
          intro.append("===").append(className).append("===" + "\n");
          intro.append(classDocs == null ? "" : classDocs).append("\n");
        } else {
          intro.append("===Other Functions===" + "\n");
        }
        intro.append(
            "{| width=\"100%\" cellspacing=\"1\" cellpadding=\"1\" border=\"1\" class=\"wikitable\"\n"
                + "|-\n"
                + "! scope=\"col\" width=\"6%\" | Function Name\n"
                + "! scope=\"col\" width=\"5%\" | Returns\n"
                + "! scope=\"col\" width=\"10%\" | Arguments\n"
                + "! scope=\"col\" width=\"10%\" | Throws\n"
                + "! scope=\"col\" width=\"61%\" | Description\n"
                + "! scope=\"col\" width=\"3%\" | Since\n"
                + "! scope=\"col\" width=\"5%\" | Restricted"
                + "\n");
      } else if (type == MarkupType.TEXT) {
        intro.append("\n").append(className).append("\n");
        intro.append(
            "**********************************************************************************************"
                + "\n");
        if (className != null) {
          intro.append(classDocs == null ? "" : classDocs).append("\n");
        } else {
          intro.append("Other Functions" + "\n");
        }
        intro.append(
            "**********************************************************************************************"
                + "\n");
      }
      List<FunctionBase> documentableFunctions = new ArrayList<FunctionBase>();
      for (FunctionBase f : entry.getValue()) {
        if (f.appearInDocumentation()) {
          documentableFunctions.add(f);
        }
      }
      if (!documentableFunctions.isEmpty()) {
        out.append(intro.toString() + "\n");
      }
      Collections.sort(
          documentableFunctions,
          new Comparator<FunctionBase>() {

            @Override
            public int compare(FunctionBase o1, FunctionBase o2) {
              return o1.getName().compareTo(o2.getName());
            }
          });
      for (FunctionBase f : documentableFunctions) {
        total++;
        String doc = f.docs();
        String restricted =
            (f instanceof Function && ((Function) f).isRestricted())
                ? "<div style=\"background-color: red; font-weight: bold; text-align: center;\">Yes</div>"
                : "<div style=\"background-color: green; font-weight: bold; text-align: center;\">No</div>";
        StringBuilder thrown = new StringBuilder();
        if (f instanceof Function && ((Function) f).thrown() != null) {
          List thrownList = Arrays.asList(((Function) f).thrown());
          for (int i = 0; i < thrownList.size(); i++) {
            ExceptionType t = (ExceptionType) thrownList.get(i);
            if (type == MarkupType.HTML || type == MarkupType.TEXT) {
              if (i != 0) {
                thrown.append((type == MarkupType.HTML ? "<br />\n" : " | "));
              }
              thrown.append(t.toString());
            } else {
              if (i != 0) {
                thrown.append("<br />\n");
              }
              thrown
                  .append("[[CommandHelper/Exceptions#")
                  .append(t.toString())
                  .append("|")
                  .append(t.toString())
                  .append("]]");
            }
          }
        }

        String since =
            (f instanceof Documentation ? ((Documentation) f).since().toString() : "0.0.0");
        DocInfo di = new DocInfo(doc);
        boolean hasExample = false;
        if (f instanceof Function
            && ((Function) f).examples() != null
            && ((Function) f).examples().length > 0) {
          hasExample = true;
          workingExamples++;
        }
        if (di.ret == null || di.args == null || di.desc == null) {
          out.append(
              f.getName()
                  + "'s documentation is not correctly formatted. Please check it and try again.\n");
        }
        if (type == MarkupType.HTML) {
          out.append(
              "<tr><td>"
                  + di.ret
                  + "</td><td>"
                  + di.args
                  + "</td><td>"
                  + thrown.toString()
                  + "</td><td>"
                  + di.desc
                  + "</td><td>"
                  + since
                  + "</td><td>"
                  + restricted
                  + "</td></tr>\n");
        } else if (type == MarkupType.WIKI) {
          // Turn args into a prettified version
          out.append(
              "|- id=\""
                  + f.getName()
                  + "\"\n"
                  + "! scope=\"row\" | [[CommandHelper/"
                  + (staged ? "Staged/" : "")
                  + "API/"
                  + f.getName()
                  + "|"
                  + f.getName()
                  + "]]()\n"
                  + "| "
                  + di.ret
                  + "\n"
                  + "| "
                  + di.args
                  + "\n"
                  + "| "
                  + thrown.toString()
                  + "\n"
                  + "| "
                  + (di.topDesc != null
                      ? di.topDesc
                          + " [[CommandHelper/"
                          + (staged ? "Staged/" : "")
                          + "API/"
                          + f.getName()
                          + "#Description|See More...]]"
                      : di.desc)
                  + (hasExample
                      ? "<br />([[CommandHelper/"
                          + (staged ? "Staged/" : "")
                          + "API/"
                          + f.getName()
                          + "#Examples|Examples...]])"
                      : "")
                  + "\n"
                  + "| "
                  + since
                  + "\n"
                  + "| "
                  + restricted
                  + "\n");

        } else if (type == MarkupType.TEXT) {
          out.append(
              di.ret
                  + " "
                  + f.getName()
                  + "("
                  + di.args
                  + ")"
                  + " {"
                  + thrown.toString()
                  + "}\n\t"
                  + di.desc
                  + "\n\t"
                  + since
                  + ((f instanceof Function ? ((Function) f).isRestricted() : false)
                      ? "\n\tThis function is restricted"
                      : "\n\tThis function is not restricted\n"));
        }
      }
      if (!documentableFunctions.isEmpty()) {
        if (type == MarkupType.HTML) {
          out.append("</table>\n");
        } else if (type == MarkupType.WIKI) {
          out.append("|}\n");
        } else if (type == MarkupType.TEXT) {
          out.append("\n");
        }
      }
    }
    if (type == MarkupType.HTML) {
      out.append(
          ""
              + "<h2>Errors in documentation</h2>\n"
              + "<em>Please note that this documentation is generated automatically,"
              + " if you notice an error in the documentation, please file a bug report for the"
              + " plugin itself!</em>"
              + "<div style='text-size:small; text-decoration:italics; color:grey'>There are "
              + total
              + " functions in this API page</div>\n");
    } else if (type == MarkupType.WIKI) {
      out.append(
          ""
              + "===Errors in documentation===\n"
              + "''Please note that this documentation is generated automatically,"
              + " if you notice an error in the documentation, please file a bug report for the"
              + " plugin itself!'' For information on undocumented functions, see [[CommandHelper/Sandbox|this page]]"
              + "<div style='font-size:xx-small; font-style:italic; color:grey'>There are "
              + total
              + " functions in this API page, "
              + workingExamples
              + " of which"
              + " have examples.</div>\n\n{{LearningTrail}}\n");
    }
    return out.toString();
  }