use of com.laytonsmith.core.functions.FunctionBase in project CommandHelper by EngineHub.
the class Script method eval.
/**
* Given the parse tree and environment, executes the tree.
*
* @param c
* @param env
* @return
* @throws CancelCommandException
*/
public Construct eval(ParseTree c, final Environment env) throws CancelCommandException {
if (env.getEnv(GlobalEnv.class).IsInterrupted()) {
// unconditionally.
throw new CancelCommandException("", Target.UNKNOWN);
}
final Construct m = c.getData();
CurrentEnv = env;
if (m.getCType() != ConstructType.FUNCTION) {
if (m.getCType() == ConstructType.VARIABLE) {
return new CString(m.val(), m.getTarget());
} else {
return m;
}
}
StackTraceManager stManager = env.getEnv(GlobalEnv.class).GetStackTraceManager();
boolean addedRootStackElement = false;
try {
// If it's an unknown target, this is not user generated code, and we want to skip adding the element here.
if (stManager.isStackEmpty() && !m.getTarget().equals(Target.UNKNOWN)) {
stManager.addStackTraceElement(new ConfigRuntimeException.StackTraceElement("<<main code>>", m.getTarget()));
addedRootStackElement = true;
}
stManager.setCurrentTarget(c.getTarget());
env.getEnv(GlobalEnv.class).SetScript(this);
if (m.val().charAt(0) == '_' && m.val().charAt(1) != '_') {
// Not really a function, so we can't put it in Function.
Procedure p = getProc(m.val());
if (p == null) {
throw new CREInvalidProcedureException("Unknown procedure \"" + m.val() + "\"", m.getTarget());
}
Environment newEnv = env;
try {
newEnv = env.clone();
} catch (CloneNotSupportedException e) {
}
ProfilePoint pp = env.getEnv(GlobalEnv.class).GetProfiler().start(m.val() + " execution", LogLevel.INFO);
Construct ret;
try {
ret = p.cexecute(c.getChildren(), newEnv, m.getTarget());
} finally {
pp.stop();
}
return ret;
}
final Function f;
try {
f = (Function) FunctionList.getFunction(m);
} catch (ConfigCompileException e) {
// Turn it into a config runtime exception. This shouldn't ever happen though.
throw ConfigRuntimeException.CreateUncatchableException("Unable to find function " + m.val(), m.getTarget());
}
ArrayList<Construct> args = new ArrayList<>();
try {
if (f.isRestricted() && !Static.hasCHPermission(f.getName(), env)) {
throw new CREInsufficientPermissionException("You do not have permission to use the " + f.getName() + " function.", m.getTarget());
}
if (f.useSpecialExec()) {
ProfilePoint p = null;
if (f.shouldProfile() && env.getEnv(GlobalEnv.class).GetProfiler() != null && env.getEnv(GlobalEnv.class).GetProfiler().isLoggable(f.profileAt())) {
p = env.getEnv(GlobalEnv.class).GetProfiler().start(f.profileMessageS(c.getChildren()), f.profileAt());
}
Construct ret;
try {
ret = f.execs(m.getTarget(), env, this, c.getChildren().toArray(new ParseTree[] {}));
} finally {
if (p != null) {
p.stop();
}
}
return ret;
}
for (ParseTree c2 : c.getChildren()) {
args.add(eval(c2, env));
}
Object[] a = args.toArray();
Construct[] ca = new Construct[a.length];
for (int i = 0; i < a.length; i++) {
ca[i] = (Construct) a[i];
// CArray, CBoolean, CDouble, CInt, CNull, CString, CVoid, CEntry, CLabel (only to sconcat).
if (!(ca[i] instanceof CArray || ca[i] instanceof CBoolean || ca[i] instanceof CDouble || ca[i] instanceof CInt || ca[i] instanceof CNull || ca[i] instanceof CString || ca[i] instanceof CVoid || ca[i] instanceof IVariable || ca[i] instanceof CEntry || ca[i] instanceof CLabel) && (!f.getName().equals("__autoconcat__") && (ca[i] instanceof CLabel))) {
throw new CRECastException("Invalid Construct (" + ca[i].getClass() + ") being passed as an argument to a function (" + f.getName() + ")", m.getTarget());
}
while (f.preResolveVariables() && ca[i] instanceof IVariable) {
IVariable cur = (IVariable) ca[i];
ca[i] = env.getEnv(GlobalEnv.class).GetVarList().get(cur.getVariableName(), cur.getTarget()).ival();
}
}
{
// It takes a moment to generate the toString of some things, so lets not do it
// if we actually aren't going to profile
ProfilePoint p = null;
if (f.shouldProfile() && env.getEnv(GlobalEnv.class).GetProfiler() != null && env.getEnv(GlobalEnv.class).GetProfiler().isLoggable(f.profileAt())) {
p = env.getEnv(GlobalEnv.class).GetProfiler().start(f.profileMessage(ca), f.profileAt());
}
Construct ret;
try {
ret = f.exec(m.getTarget(), env, ca);
} finally {
if (p != null) {
p.stop();
}
}
return ret;
}
// We want to catch and rethrow the ones we know how to catch, and then
// catch and report anything else.
} catch (ConfigRuntimeException | ProgramFlowManipulationException e) {
if (e instanceof AbstractCREException) {
((AbstractCREException) e).freezeStackTraceElements(stManager);
}
throw e;
} catch (InvalidEnvironmentException e) {
if (!e.isDataSet()) {
e.setData(f.getName());
}
throw e;
} catch (Exception e) {
String brand = Implementation.GetServerType().getBranding();
SimpleVersion version = Static.getVersion();
String culprit = brand;
outer: for (ExtensionTracker tracker : ExtensionManager.getTrackers().values()) {
for (FunctionBase b : tracker.getFunctions()) {
if (b.getName().equals(f.getName())) {
// name instead of the core plugin's name.
for (Extension extension : tracker.getExtensions()) {
culprit = extension.getName();
break outer;
}
}
}
}
String emsg = TermColors.RED + "Uh oh! You've found an error in " + TermColors.CYAN + culprit + TermColors.RED + ".\n" + "This happened while running your code, so you may be able to find a workaround," + " but is ultimately an issue in " + culprit + ".\n" + "The following code caused the error:\n" + TermColors.WHITE;
List<String> args2 = new ArrayList<>();
Map<String, String> vars = new HashMap<>();
for (Construct cc : args) {
if (cc instanceof IVariable) {
Construct ccc = env.getEnv(GlobalEnv.class).GetVarList().get(((IVariable) cc).getVariableName(), cc.getTarget()).ival();
String vval = ccc.val();
if (ccc instanceof CString) {
vval = ccc.asString().getQuote();
}
vars.put(((IVariable) cc).getVariableName(), vval);
}
if (cc == null) {
args2.add("java-null");
} else if (cc instanceof CString) {
args2.add(cc.asString().getQuote());
} else if (cc instanceof IVariable) {
args2.add(((IVariable) cc).getVariableName());
} else {
args2.add(cc.val());
}
}
if (!vars.isEmpty()) {
emsg += StringUtils.Join(vars, " = ", "\n") + "\n";
}
emsg += f.getName() + "(";
emsg += StringUtils.Join(args2, ", ");
emsg += ")\n";
emsg += TermColors.RED + "on or around " + TermColors.YELLOW + m.getTarget().file() + TermColors.WHITE + ":" + TermColors.CYAN + m.getTarget().line() + TermColors.RED + ".\n";
// Server might not be available in this platform, so let's be sure to ignore those exceptions
String modVersion;
try {
modVersion = StaticLayer.GetConvertor().GetServer().getAPIVersion();
} catch (Exception ex) {
modVersion = Implementation.GetServerType().name();
}
String extensionData = "";
for (ExtensionTracker tracker : ExtensionManager.getTrackers().values()) {
for (Extension extension : tracker.getExtensions()) {
try {
extensionData += TermColors.CYAN + extension.getName() + TermColors.RED + " (" + TermColors.RESET + extension.getVersion() + TermColors.RED + ")\n";
} catch (AbstractMethodError ex) {
// This happens with an old style extensions. Just skip it.
extensionData += TermColors.CYAN + "Unknown Extension" + TermColors.RED + "\n";
}
}
}
if (extensionData.isEmpty()) {
extensionData = "NONE\n";
}
emsg += "Please report this to the developers, and be sure to include the version numbers:\n" + TermColors.CYAN + "Server" + TermColors.RED + " version: " + TermColors.RESET + modVersion + TermColors.RED + ";\n" + TermColors.CYAN + brand + TermColors.RED + " version: " + TermColors.RESET + version + TermColors.RED + ";\n" + "Loaded extensions and versions:\n" + extensionData + "Here's the stacktrace:\n" + TermColors.RESET + Static.GetStacktraceString(e);
Static.getLogger().log(Level.SEVERE, emsg);
throw new CancelCommandException(null, Target.UNKNOWN);
}
} finally {
if (addedRootStackElement && stManager.isStackSingle()) {
stManager.popStackTraceElement();
}
}
}
use of com.laytonsmith.core.functions.FunctionBase in project CommandHelper by EngineHub.
the class MethodScriptStaticCompiler method go.
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()));
}
}
}
use of com.laytonsmith.core.functions.FunctionBase in project CommandHelper by EngineHub.
the class RandomTests method testAllBoilerplate.
/**
* This function automatically tests all the boilerplate portions of all functions. Note that this can be disabled
* in the StaticTest class, so that high quality test coverage can be measured.
*/
@Test
@SuppressWarnings({ "ThrowableResultIgnored", "CallToPrintStackTrace" })
public void testAllBoilerplate() {
Map<String, Throwable> uhohs = new HashMap<>();
String[] requiredMethods = new String[] { "toString", "equals", "hashCode" };
// Ensure that all the abstraction objects overloaded
StaticTest.InstallFakeServerFrontend();
outer: for (Class c : ClassDiscovery.getDefaultInstance().loadClassesThatExtend(AbstractionObject.class)) {
inner: for (Class inter : c.getInterfaces()) {
for (Class extended : inter.getInterfaces()) {
if (extended == AbstractionObject.class && !c.isInterface()) {
// to ensure that the equals, toString, and hashCode methods are overloaded.
break inner;
}
}
// It's not, so just skip it.
continue outer;
}
Method[] methods = c.getDeclaredMethods();
required: for (String required : requiredMethods) {
for (Method method : methods) {
if (method.getName().equals(required)) {
continue required;
}
}
uhohs.put(c.getName() + " " + required, new NoSuchMethodException(c.getSimpleName() + " does not define " + required));
}
}
Set<String> classDocs = new TreeSet<>();
for (FunctionBase f : FunctionList.getFunctionList(null)) {
try {
if (testedFunctions.contains(f.getName())) {
continue;
}
testedFunctions.add(f.getName());
StaticTest.TestBoilerplate(f, f.getName());
Class upper = f.getClass().getEnclosingClass();
if (upper == null) {
fail(f.getName() + " is not enclosed in an upper class.");
return;
}
try {
Method m = upper.getMethod("docs", new Class[] {});
try {
String docs = m.invoke(null, new Object[] {}).toString();
if (!classDocs.contains(docs)) {
StaticTest.TestClassDocs(docs, upper);
classDocs.add(docs);
}
} catch (NullPointerException ex) {
fail(upper.getName() + "'s docs function should be static");
}
} catch (IllegalAccessException | IllegalArgumentException | SecurityException ex) {
Logger.getLogger(RandomTests.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
fail(upper.getName() + " throws an exception!");
} catch (NoSuchMethodException ex) {
fail(upper.getName() + " does not include a class level documentation function.");
} catch (HeadlessException ex) {
// Hmm. Whatever's running us doesn't have a head, and we just tested a function
// that requires a head. Whatever, just skip it and move on. It'll have to be tested
// manually.
}
} catch (Throwable t) {
uhohs.put(f.getClass().getName(), t);
t.printStackTrace();
}
}
if (!StaticTest.brokenJunk.isEmpty()) {
System.err.println("There " + StringUtils.PluralTemplateHelper(StaticTest.brokenJunk.size(), "is %d test that has", "are %d tests that have") + " a failure in extreme circumstances.");
for (String s : StaticTest.brokenJunk) {
uhohs.put(s, null);
}
}
if (!uhohs.isEmpty()) {
StringBuilder b = new StringBuilder();
for (String key : uhohs.keySet()) {
b.append(key).append(" threw: ").append(uhohs.get(key)).append("\n");
}
String output = ("There was/were " + uhohs.size() + " boilerplate failure(s). Output:\n" + b.toString());
StreamUtils.GetSystemOut().println(output);
fail(output);
}
}
use of com.laytonsmith.core.functions.FunctionBase in project CommandHelper by EngineHub.
the class DocGen method functions.
/**
* 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
*/
@SuppressWarnings("StringConcatenationInsideStringBufferAppend")
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 view examples for how to use a" + " particular function.\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")) {
// Skip Sandbox functions
continue;
}
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 | IllegalArgumentException | InvocationTargetException | NoSuchMethodException ex) {
} catch (Exception e) {
e.printStackTrace(StreamUtils.GetSystemErr());
StreamUtils.GetSystemErr().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<Class<? extends CREThrowable>> thrownList = Arrays.asList(((Function) f).thrown());
for (int i = 0; i < thrownList.size(); i++) {
String t = ((Class<? extends CREThrowable>) thrownList.get(i)).getAnnotation(typeof.class).value();
if (type == MarkupType.HTML || type == MarkupType.TEXT) {
if (i != 0) {
thrown.append((type == MarkupType.HTML ? "<br />\n" : " | "));
}
thrown.append(t);
} else {
if (i != 0) {
thrown.append("<br />\n");
}
thrown.append("[[CommandHelper/Exceptions#").append(t).append("|").append(t).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{{Back to top}}\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{{Back to top}}\n{{LearningTrail}}\n");
}
return out.toString();
}
use of com.laytonsmith.core.functions.FunctionBase in project CommandHelper by EngineHub.
the class DocGen method examples.
public static String examples(String function, boolean staged) throws Exception {
FunctionBase fb = FunctionList.getFunction(new CFunction(function, Target.UNKNOWN));
if (fb instanceof Function) {
Function f = (Function) fb;
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>";
String optimizationMessage = "None";
if (f instanceof Optimizable) {
Set<Optimizable.OptimizationOption> options = ((Optimizable) f).optimizationOptions();
List<String> list = new ArrayList<String>();
for (Optimizable.OptimizationOption option : options) {
list.add("[[CommandHelper/" + (staged ? "Staged/" : "") + "Optimizer#" + option.name() + "|" + option.name() + "]]");
}
optimizationMessage = StringUtils.Join(list, "<br />");
}
DocInfo di = new DocInfo(f.docs());
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++) {
String t = ((Class<? extends CREThrowable>) thrownList.get(i)).getAnnotation(typeof.class).value();
if (i != 0) {
thrown.append("<br />\n");
}
thrown.append("[[CommandHelper/Exceptions#").append(t).append("|").append(t).append("]]");
}
}
String tableUsages = di.originalArgs.replace("|", "<hr />");
String[] usages = di.originalArgs.split("\\|");
StringBuilder usageBuilder = new StringBuilder();
for (String usage : usages) {
usageBuilder.append("<pre>\n").append(f.getName()).append("(").append(usage.trim()).append(")\n</pre>");
}
StringBuilder exampleBuilder = new StringBuilder();
if (f.examples() != null && f.examples().length > 0) {
int count = 1;
// If the output was automatically generated, change the color of the pre
for (ExampleScript es : f.examples()) {
exampleBuilder.append("====Example ").append(count).append("====\n").append(es.getDescription()).append("\n\n" + "Given the following code:\n");
exampleBuilder.append(SimpleSyntaxHighlighter.Highlight(es.getScript(), true)).append("\n");
String style = "";
if (es.isAutomatic()) {
style = " style=\"background-color: #BDC7E9\"";
exampleBuilder.append("\n\nThe output would be:\n<pre");
} else {
exampleBuilder.append("\n\nThe output might be:\n<pre");
}
exampleBuilder.append(style).append(">").append(es.getOutput()).append("</pre>\n");
count++;
}
} else {
exampleBuilder.append("Sorry, there are no examples for this function! :(");
}
Class[] seeAlso = f.seeAlso();
String seeAlsoText = "";
if (seeAlso != null && seeAlso.length > 0) {
seeAlsoText += "===See Also===\n";
boolean first = true;
for (Class c : seeAlso) {
if (!first) {
seeAlsoText += ", ";
}
first = false;
if (Function.class.isAssignableFrom(c)) {
Function f2 = (Function) c.newInstance();
seeAlsoText += "<code>[[CommandHelper/" + (staged ? "Staged/" : "") + "API/" + f2.getName() + "|" + f2.getName() + "]]</code>";
} else if (Template.class.isAssignableFrom(c)) {
Template t = (Template) c.newInstance();
seeAlsoText += "[[CommandHelper/" + (staged ? "Staged/" : "") + t.getName() + "|Learning Trail: " + t.getDisplayName() + "]]";
} else {
throw new Error("Unsupported class found in @seealso annotation: " + c.getName());
}
}
}
Map<String, String> templateFields = new HashMap<>();
templateFields.put("function_name", f.getName());
templateFields.put("returns", di.ret);
templateFields.put("tableUsages", tableUsages);
templateFields.put("throws", thrown.toString());
templateFields.put("since", f.since().toString());
templateFields.put("restricted", restricted);
templateFields.put("optimizationMessage", optimizationMessage);
templateFields.put("description", di.extendedDesc == null ? di.desc : di.topDesc + "\n\n" + di.extendedDesc);
templateFields.put("usages", usageBuilder.toString());
templateFields.put("examples", exampleBuilder.toString());
templateFields.put("staged", staged ? "Staged/" : "");
templateFields.put("seeAlso", seeAlsoText);
String template = StreamUtils.GetString(DocGenTemplates.class.getResourceAsStream("/templates/example_templates"));
// Find all the %%templates%% in the template
Matcher m = Pattern.compile("%%(.*?)%%").matcher(template);
try {
while (m.find()) {
String name = m.group(1);
String templateValue = templateFields.get(name);
template = template.replaceAll("%%" + Pattern.quote(name) + "%%", templateValue.replace("$", "\\$").replaceAll("\\'", "\\\\'"));
}
return template;
} catch (RuntimeException e) {
throw new RuntimeException("Caught a runtime exception while generating template for " + function, e);
}
} else {
throw new RuntimeException(function + " does not implement Function");
}
}
Aggregations