use of com.laytonsmith.core.functions.Function in project CommandHelper by EngineHub.
the class SiteDeploy method generateFunctionDocs.
private void generateFunctionDocs(Function f, DocGen.DocInfo docs) {
StringBuilder page = new StringBuilder();
page.append("== ").append(f.getName()).append(" ==\n");
page.append("<div>").append(docs.desc).append("</div>\n");
page.append("=== Vital Info ===\n");
page.append("{| style=\"width: 40%;\" cellspacing=\"1\" cellpadding=\"1\" border=\"1\" class=\"wikitable\"\n");
page.append("|-\n" + "! scope=\"col\" width=\"20%\" | \n" + "! scope=\"col\" width=\"80%\" | \n" + "|-\n" + "! scope=\"row\" | Name\n" + "| ").append(f.getName()).append("\n" + "|-\n" + "! scope=\"row\" | Returns\n" + "| ").append(docs.ret).append("\n" + "|-\n" + "! scope=\"row\" | Usages\n" + "| ").append(docs.args).append("\n" + "|-\n" + "! scope=\"row\" | Throws\n" + "| ");
List<String> exceptions = new ArrayList<>();
for (Class<? extends CREThrowable> c : f.thrown()) {
String t = c.getAnnotation(typeof.class).value();
exceptions.add("[[../objects/" + t + "|" + t + "]]");
}
page.append(StringUtils.Join(exceptions, "<br>"));
page.append("\n" + "|-\n" + "! scope=\"row\" | Since\n" + "| ").append(f.since()).append("\n" + "|-\n" + "! scope=\"row\" | Restricted\n");
page.append("| <div style=\"background-color: ");
page.append(f.isRestricted() ? "red" : "green");
page.append("; font-weight: bold; text-align: center;\">").append(f.isRestricted() ? "Yes" : "No").append("</div>\n" + "|-\n" + "! scope=\"row\" | Optimizations\n" + "| ");
String optimizationMessage = "None";
if (f instanceof Optimizable) {
Set<Optimizable.OptimizationOption> options = ((Optimizable) f).optimizationOptions();
List<String> list = new ArrayList<>();
for (Optimizable.OptimizationOption option : options) {
list.add("[[../../Optimizer#" + option.name() + "|" + option.name() + "]]");
}
optimizationMessage = StringUtils.Join(list, " <br /> ");
}
page.append(optimizationMessage);
page.append("\n|}");
if (docs.extendedDesc != null) {
page.append("<div>").append(docs.extendedDesc).append("</div>");
}
String[] usages = docs.originalArgs.split("\\|");
StringBuilder usageBuilder = new StringBuilder();
for (String usage : usages) {
usageBuilder.append("<pre>\n").append(f.getName()).append("(").append(usage.trim()).append(")\n</pre>");
}
page.append("\n=== Usages ===\n");
page.append(usageBuilder.toString());
StringBuilder exampleBuilder = new StringBuilder();
try {
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(HTMLUtils.escapeHTML(es.getDescription())).append("\n\n" + "Given the following code:\n");
exampleBuilder.append(SimpleSyntaxHighlighter.Highlight(es.getScript(), true)).append("\n");
String style = "";
exampleBuilder.append("\n\nThe output ");
if (es.isAutomatic()) {
style = " background-color: #BDC7E9;";
exampleBuilder.append("would");
} else {
exampleBuilder.append("might");
}
exampleBuilder.append(" be:\n<pre class=\"pre\" style=\"border-top: 1px solid blue; border-bottom: 1px solid blue;").append(style).append("\"");
exampleBuilder.append(">%%NOWIKI|").append(es.getOutput()).append("%%").append("</pre>\n");
count++;
}
} else {
exampleBuilder.append("Sorry, there are no examples for this function! :(\n");
}
} catch (ConfigCompileException | IOException | DataSourceException | URISyntaxException ex) {
exampleBuilder.append("Error while compiling the examples for ").append(f.getName());
}
page.append("\n=== Examples ===\n");
page.append(exampleBuilder.toString());
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) ReflectionUtils.newInstance(c);
seeAlsoText += "<code>[[" + f2.getName() + "|" + f2.getName() + "]]</code>";
} else if (Template.class.isAssignableFrom(c)) {
Template t = (Template) ReflectionUtils.newInstance(c);
seeAlsoText += "[[" + t.getName() + "|Learning Trail: " + t.getDisplayName() + "]]";
} else {
throw new Error("Unsupported class found in @seealso annotation: " + c.getName());
}
}
}
page.append(seeAlsoText);
Class<?> container = f.getClass();
while (container.getEnclosingClass() != null) {
container = container.getEnclosingClass();
}
String bW = "<p id=\"edit_this_page\">" + EDIT_THIS_PAGE_PREAMBLE + String.format(githubBaseUrl, "java/" + container.getName().replace(".", "/")) + ".java" + EDIT_THIS_PAGE_POSTAMBLE + " (Note this page is automatically generated from the documentation in the source code.)</p>";
page.append(bW);
String description = "";
writePage(f.getName(), page.toString(), "API/functions/" + f.getName(), Arrays.asList(new String[] { f.getName(), f.getName() + " api", f.getName() + " example", f.getName() + " description" }), description);
}
use of com.laytonsmith.core.functions.Function in project CommandHelper by EngineHub.
the class DocGenExportTool method export.
/**
* Triggers the export tool
*/
public void export() {
Set<Class<? extends Function>> functions = classDiscovery.loadClassesWithAnnotationThatExtend(api.class, Function.class, this.getClass().getClassLoader(), false);
Set<Class<? extends Event>> events = classDiscovery.loadClassesWithAnnotationThatExtend(api.class, Event.class, this.getClass().getClassLoader(), false);
Map<String, Object> topLevel = new HashMap<String, Object>();
List<Map<String, Object>> functionList = new ArrayList<Map<String, Object>>();
topLevel.put("functions", functionList);
List<Map<String, Object>> eventList = new ArrayList<Map<String, Object>>();
topLevel.put("events", eventList);
for (Class<? extends Function> functionC : functions) {
Map<String, Object> function = new HashMap<String, Object>();
Function f;
try {
f = ReflectionUtils.newInstance(functionC);
} catch (NoClassDefFoundError ex) {
StreamUtils.GetSystemErr().println("While attempting to load: " + functionC.getName() + ": " + ex.getMessage());
continue;
}
DocGen.DocInfo di = new DocGen.DocInfo(f.docs());
function.put("name", f.getName());
function.put("ret", di.ret);
function.put("args", di.originalArgs);
function.put("desc", di.desc);
functionList.add(function);
}
Pattern eventPattern = Pattern.compile("\\{(.*?)\\} *?(.*?) *?\\{(.*?)\\} *?\\{(.*?)\\}");
DocGen.MarkupType type = DocGen.MarkupType.TEXT;
for (Class<? extends Event> eventC : events) {
Map<String, Object> event = new HashMap<String, Object>();
Event e = ReflectionUtils.newInstance(eventC);
Matcher m = eventPattern.matcher(e.docs());
if (m.find()) {
String name = e.getName();
String description = m.group(2).trim();
String prefilter = DocGen.PrefilterData.Get(m.group(1).split("\\|"), type);
String eventData = DocGen.EventData.Get(m.group(3).split("\\|"), type);
String mutability = DocGen.MutabilityData.Get(m.group(4).split("\\|"), type);
event.put("name", name);
event.put("desc", description);
event.put("prefilter", prefilter);
event.put("eventData", eventData);
event.put("mutability", mutability);
eventList.add(event);
}
}
String output = JSONValue.toJSONString(topLevel) + StringUtils.nl();
try {
out.write(output.getBytes("UTF-8"));
out.flush();
} catch (IOException ex) {
Logger.getLogger(DocGenExportTool.class.getName()).log(Level.SEVERE, null, ex);
}
}
use of com.laytonsmith.core.functions.Function in project CommandHelper by EngineHub.
the class MethodScriptCompiler method optimize.
/**
* Recurses down into the tree, attempting to optimize where possible. A few things have strong coupling, for
* information on these items, see the documentation included in the source.
*
* @param tree
* @return
*/
private static void optimize(ParseTree tree, Stack<List<Procedure>> procs, Set<ConfigCompileException> compilerErrors) {
if (tree.isOptimized()) {
// Don't need to re-run this
return;
}
// }
if (!(tree.getData() instanceof CFunction)) {
// There's no way to optimize something that's not a function
return;
}
// If it is a proc definition, we need to go ahead and see if we can add it to the const proc stack
if (tree.getData().val().equals("proc")) {
procs.push(new ArrayList<Procedure>());
}
CFunction cFunction = (CFunction) tree.getData();
Function func;
try {
func = (Function) FunctionList.getFunction(cFunction);
} catch (ConfigCompileException e) {
func = null;
}
if (func != null) {
if (func.getClass().getAnnotation(nolinking.class) != null) {
// It's an unlinking function, so we need to stop at this point
return;
}
}
if (cFunction instanceof CIdentifier) {
// Add the child to the identifier
ParseTree c = ((CIdentifier) cFunction).contained();
tree.addChild(c);
c.getData().setWasIdentifier(true);
}
List<ParseTree> children = tree.getChildren();
if (func instanceof Optimizable && ((Optimizable) func).optimizationOptions().contains(OptimizationOption.PRIORITY_OPTIMIZATION)) {
// would cause an error, even though the user did in fact provide code in that section.
try {
((Optimizable) func).optimizeDynamic(tree.getTarget(), children, tree.getFileOptions());
} catch (ConfigCompileException ex) {
// If an error occurs, we will skip the rest of this element
compilerErrors.add(ex);
return;
} catch (ConfigRuntimeException ex) {
compilerErrors.add(new ConfigCompileException(ex));
return;
}
}
for (int i = 0; i < children.size(); i++) {
ParseTree t = children.get(i);
if (t.getData() instanceof CFunction) {
if (t.getData().val().startsWith("_") || (func != null && func.useSpecialExec())) {
continue;
}
Function f;
try {
f = (Function) FunctionList.getFunction(t.getData());
} catch (ConfigCompileException ex) {
compilerErrors.add(ex);
return;
}
Set<OptimizationOption> options = NO_OPTIMIZATIONS;
if (f instanceof Optimizable) {
options = ((Optimizable) f).optimizationOptions();
}
if (options.contains(OptimizationOption.TERMINAL)) {
if (children.size() > i + 1) {
// First, a compiler warning
CHLog.GetLogger().Log(CHLog.Tags.COMPILER, LogLevel.WARNING, "Unreachable code. Consider removing this code.", children.get(i + 1).getTarget());
// Now, truncate the children
for (int j = children.size() - 1; j > i; j--) {
children.remove(j);
}
break;
}
}
}
}
boolean fullyStatic = true;
boolean hasIVars = false;
for (ParseTree node : children) {
if (node.getData() instanceof CFunction) {
optimize(node, procs, compilerErrors);
}
if (node.getData().isDynamic() && !(node.getData() instanceof IVariable)) {
fullyStatic = false;
}
if (node.getData() instanceof IVariable) {
hasIVars = true;
}
}
// In all cases, at this point, we are either unable to optimize, or we will
// optimize, so set our optimized variable at this point.
tree.setOptimized(true);
if (func == null) {
// It's a proc call. Let's see if we can optimize it
Procedure p = null;
loop: for (List<Procedure> proc : procs) {
for (Procedure pp : proc) {
if (pp.getName().equals(cFunction.val())) {
p = pp;
break loop;
}
}
}
if (p != null) {
try {
Construct c = DataHandling.proc.optimizeProcedure(p.getTarget(), p, children);
if (c != null) {
tree.setData(c);
tree.removeChildren();
return;
}
// else Nope, couldn't optimize.
} catch (ConfigRuntimeException ex) {
// Cool. Caught a runtime error at compile time :D
compilerErrors.add(new ConfigCompileException(ex));
}
}
// so we can't for sure say, but we do know we can't optimize this
return;
}
if (tree.getData().val().equals("proc")) {
// Check for too few arguments
if (children.size() < 2) {
compilerErrors.add(new ConfigCompileException("Incorrect number of arguments passed to proc", tree.getData().getTarget()));
return;
}
// We just went out of scope, so we need to pop the layer of Procedures that
// are internal to us
procs.pop();
// Let's see.
try {
ParseTree root = new ParseTree(new CFunction(__autoconcat__, Target.UNKNOWN), tree.getFileOptions());
Script fakeScript = Script.GenerateScript(root, "*");
Environment env = null;
try {
if (Implementation.GetServerType().equals(Implementation.Type.BUKKIT)) {
CommandHelperPlugin plugin = CommandHelperPlugin.self;
GlobalEnv gEnv = new GlobalEnv(plugin.executionQueue, plugin.profiler, plugin.persistenceNetwork, MethodScriptFileLocations.getDefault().getConfigDirectory(), plugin.profiles, new TaskManager());
env = Environment.createEnvironment(gEnv, new CommandHelperEnvironment());
} else {
env = Static.GenerateStandaloneEnvironment(false);
}
} catch (IOException | DataSourceException | URISyntaxException | Profiles.InvalidProfileException e) {
//
}
Procedure myProc = DataHandling.proc.getProcedure(tree.getTarget(), env, fakeScript, children.toArray(new ParseTree[children.size()]));
// Yep. So, we can move on with our lives now, and if it's used later, it could possibly be static.
procs.peek().add(myProc);
} catch (ConfigRuntimeException e) {
// Well, they have an error in there somewhere
compilerErrors.add(new ConfigCompileException(e));
} catch (NullPointerException e) {
// Nope, can't optimize.
return;
}
}
// the compiler trick functions know how to deal with it specially, even if everything isn't
// static, so do this first.
String oldFunctionName = func.getName();
Set<OptimizationOption> options = NO_OPTIMIZATIONS;
if (func instanceof Optimizable) {
options = ((Optimizable) func).optimizationOptions();
}
if (options.contains(OptimizationOption.OPTIMIZE_DYNAMIC)) {
try {
ParseTree tempNode;
try {
tempNode = ((Optimizable) func).optimizeDynamic(tree.getData().getTarget(), tree.getChildren(), tree.getFileOptions());
} catch (ConfigRuntimeException e) {
// Turn it into a compile exception, then rethrow
throw new ConfigCompileException(e);
}
if (tempNode == Optimizable.PULL_ME_UP) {
if (tree.hasChildren()) {
tempNode = tree.getChildAt(0);
} else {
tempNode = null;
}
}
if (tempNode == Optimizable.REMOVE_ME) {
tree.setData(new CFunction("p", Target.UNKNOWN));
tree.removeChildren();
} else if (tempNode != null) {
tree.setData(tempNode.getData());
tree.setOptimized(tempNode.isOptimized());
tree.setChildren(tempNode.getChildren());
tree.getData().setWasIdentifier(tempNode.getData().wasIdentifier());
optimize(tree, procs, compilerErrors);
tree.setOptimized(true);
// array, so if they have reversed this, make note of that now
if (tempNode.hasBeenMadeStatic()) {
fullyStatic = true;
}
}
// else it wasn't an optimization, but a compile check
} catch (ConfigCompileException ex) {
compilerErrors.add(ex);
}
}
if (!fullyStatic) {
return;
}
// specially from here forward
if (func.preResolveVariables() && hasIVars) {
// Well, this function isn't equipped to deal with IVariables.
return;
}
// don't want to run this now
if (tree.getData().getValue().equals(oldFunctionName) && (options.contains(OptimizationOption.OPTIMIZE_CONSTANT) || options.contains(OptimizationOption.CONSTANT_OFFLINE))) {
Construct[] constructs = new Construct[tree.getChildren().size()];
for (int i = 0; i < tree.getChildren().size(); i++) {
constructs[i] = tree.getChildAt(i).getData();
}
try {
try {
Construct result;
if (options.contains(OptimizationOption.CONSTANT_OFFLINE)) {
List<Integer> numArgsList = Arrays.asList(func.numArgs());
if (!numArgsList.contains(Integer.MAX_VALUE) && !numArgsList.contains(tree.getChildren().size())) {
compilerErrors.add(new ConfigCompileException("Incorrect number of arguments passed to " + tree.getData().val(), tree.getData().getTarget()));
result = null;
} else {
result = func.exec(tree.getData().getTarget(), null, constructs);
}
} else {
result = ((Optimizable) func).optimize(tree.getData().getTarget(), constructs);
}
// If the result is null, it was just a check, it can't optimize further.
if (result != null) {
result.setWasIdentifier(tree.getData().wasIdentifier());
tree.setData(result);
tree.removeChildren();
}
} catch (ConfigRuntimeException e) {
// Turn this into a ConfigCompileException, then rethrow
throw new ConfigCompileException(e);
}
} catch (ConfigCompileException ex) {
compilerErrors.add(ex);
}
}
// It doesn't know how to optimize. Oh well.
}
use of com.laytonsmith.core.functions.Function in project CommandHelper by EngineHub.
the class Procedure method checkPossiblyConstant.
private boolean checkPossiblyConstant(ParseTree tree) {
// individual procs need to be inlined as deemed appropriate.
if (true) {
return false;
}
if (!tree.getData().isDynamic()) {
// If it isn't dynamic, it certainly could be constant
return true;
} else if (tree.getData() instanceof IVariable) {
// contract, but import() itself is dynamic, so this is not an issue.
return true;
} else if (tree.getData() instanceof CFunction) {
// If the function itself is not optimizable, we needn't recurse.
try {
FunctionBase fb = FunctionList.getFunction(tree.getData());
if (fb instanceof Function) {
Function f = (Function) fb;
if (f instanceof DataHandling._return) {
// but if the contents are optimizable, it is still considered constant.
if (!tree.hasChildren()) {
return true;
} else {
return checkPossiblyConstant(tree.getChildAt(0));
}
}
// If it's optimizable, it's possible. If it's restricted, it doesn't matter, because
// we can't optimize it out anyways, because we need to do the permission check
Set<Optimizable.OptimizationOption> o = EnumSet.noneOf(Optimizable.OptimizationOption.class);
if (f instanceof Optimizable) {
o = ((Optimizable) f).optimizationOptions();
}
if (!((o != null && (o.contains(Optimizable.OptimizationOption.OPTIMIZE_DYNAMIC) || o.contains(Optimizable.OptimizationOption.OPTIMIZE_CONSTANT))) && !f.isRestricted())) {
// Nope. Doesn't matter if the children are or not
return false;
}
} else {
return false;
}
} catch (ConfigCompileException e) {
// It's a proc. We will treat this just like any other function call,
}
// Ok, well, we have to check the children first.
for (ParseTree child : tree.getChildren()) {
if (!checkPossiblyConstant(child)) {
// Nope, since our child can't be constant, neither can we
return false;
}
}
// They all check out, so, yep, we could possibly be constant
return true;
} else {
// Uh. Ok, well, nope.
return false;
}
}
Aggregations