use of com.laytonsmith.core.exceptions.ConfigCompileException in project CommandHelper by EngineHub.
the class MethodScriptCompilerTest method ambigousCommandRegistrationHelper.
/**
* Checks if cmd1 and cmd2 would cause a ConfigCompileException due to being ambigous. Calls "fail(message)" when
* compile success != expectFail. The order of cmd1 and cmd2 does not matter, this method checks both orders.
*
* @param cmd1 - The first command.
* @param cmd2 - The second command.
* @param expectFail - True if cmd1 and cmd2 are expected to be ambigous, false otherwise.
*/
private void ambigousCommandRegistrationHelper(String cmd1, String cmd2, boolean expectFail) {
Script s1, s2;
try {
List<Script> scripts = MethodScriptCompiler.preprocess(MethodScriptCompiler.lex(cmd1 + "\n" + cmd2, null, false));
s1 = scripts.get(0);
s2 = scripts.get(1);
s1.compile();
s2.compile();
} catch (ConfigCompileGroupException | ConfigCompileException | IndexOutOfBoundsException e) {
fail("Encountered unexpected " + e.getClass().getSimpleName() + " with message: " + e.getMessage());
return;
}
// Check scripts 1 and 2 against eachother.
ConfigCompileException e1 = null, e2 = null;
try {
s2.checkAmbiguous(Arrays.asList(new Script[] { s1 }));
} catch (ConfigCompileException e) {
e1 = e;
}
try {
s1.checkAmbiguous(Arrays.asList(new Script[] { s2 }));
} catch (ConfigCompileException e) {
e2 = e;
}
// Fail if the behaviour of script 1 VS 2 did not match script 2 VS 1.
if ((e1 == null) != (e2 == null)) {
fail("Commands '" + cmd1 + "' and '" + cmd2 + "' are both ambigous and non-ambigous" + " depending on the command order. Since command order does not matter, this is a bug.");
}
// Fail if the result differs from the expected result.
if (expectFail) {
if (e1 == null) {
fail("Commands '" + cmd1 + "' and '" + cmd2 + "' are expected to be ambigous," + " but they did not cause the expected ConfigCompileException.");
}
} else {
if (e1 != null) {
fail("Commands '" + cmd1 + "' and '" + cmd2 + "' are expected to be non-ambigous," + " but they did cause a ConfigCompileException with message: " + e1.getMessage());
}
}
}
use of com.laytonsmith.core.exceptions.ConfigCompileException in project CommandHelper by EngineHub.
the class Main method main.
@SuppressWarnings("ResultOfObjectAllocationIgnored")
public static void main(String[] args) throws Exception {
try {
Implementation.setServerType(Implementation.Type.SHELL);
CHLog.initialize(MethodScriptFileLocations.getDefault().getJarDirectory());
Prefs.init(MethodScriptFileLocations.getDefault().getPreferencesFile());
Prefs.SetColors();
if (Prefs.UseColors()) {
// Use jansi to enable output to color properly, even on windows.
org.fusesource.jansi.AnsiConsole.systemInstall();
}
ClassDiscovery cd = ClassDiscovery.getDefaultInstance();
cd.addDiscoveryLocation(ClassDiscovery.GetClassContainer(Main.class));
ClassDiscoveryCache cdcCache = new ClassDiscoveryCache(MethodScriptFileLocations.getDefault().getCacheDirectory());
cd.setClassDiscoveryCache(cdcCache);
cd.addAllJarsInFolder(MethodScriptFileLocations.getDefault().getExtensionsDirectory());
ExtensionManager.AddDiscoveryLocation(MethodScriptFileLocations.getDefault().getExtensionsDirectory());
ExtensionManager.Cache(MethodScriptFileLocations.getDefault().getExtensionCacheDirectory());
ExtensionManager.Initialize(cd);
ExtensionManager.Startup();
if (args.length == 0) {
args = new String[] { "--help" };
}
// I'm not sure why this is in Main, but if this breaks something, it needs to be put back.
// However, if it is put back, then it needs to be figured out why this causes the terminal
// to lose focus on mac.
// AnnotationChecks.checkForceImplementation();
ArgumentParser mode;
ArgumentParser.ArgumentParserResults parsedArgs;
try {
ArgumentSuite.ArgumentSuiteResults results = ARGUMENT_SUITE.match(args, "help");
mode = results.getMode();
parsedArgs = results.getResults();
} catch (ArgumentParser.ResultUseException | ArgumentParser.ValidationException e) {
StreamUtils.GetSystemOut().println(TermColors.RED + e.getMessage() + TermColors.RESET);
mode = helpMode;
parsedArgs = null;
}
if (mode == helpMode) {
String modeForHelp = null;
if (parsedArgs != null) {
modeForHelp = parsedArgs.getStringArgument();
}
modeForHelp = ARGUMENT_SUITE.getModeFromAlias(modeForHelp);
if (modeForHelp == null) {
// Display the general help
StreamUtils.GetSystemOut().println(ARGUMENT_SUITE.getBuiltDescription());
System.exit(0);
return;
} else {
// Display the help for this mode
StreamUtils.GetSystemOut().println(ARGUMENT_SUITE.getModeFromName(modeForHelp).getBuiltDescription());
return;
}
}
// if it were, the help command would have run.
assert parsedArgs != null;
if (mode == managerMode) {
Manager.start();
System.exit(0);
} else if (mode == coreFunctionsMode) {
List<String> core = new ArrayList<>();
for (api.Platforms platform : api.Platforms.values()) {
for (FunctionBase f : FunctionList.getFunctionList(platform)) {
if (f.isCore()) {
core.add(f.getName());
}
}
}
Collections.sort(core);
StreamUtils.GetSystemOut().println(StringUtils.Join(core, ", "));
System.exit(0);
} else if (mode == interpreterMode) {
new Interpreter(parsedArgs.getStringListArgument(), parsedArgs.getStringArgument("location-----"));
System.exit(0);
} else if (mode == installCmdlineMode) {
Interpreter.install();
System.exit(0);
} else if (mode == uninstallCmdlineMode) {
Interpreter.uninstall();
System.exit(0);
} else if (mode == docgenMode) {
DocGenUI.main(args);
System.exit(0);
} else if (mode == mslpMode) {
String mslp = parsedArgs.getStringArgument();
if (mslp.isEmpty()) {
StreamUtils.GetSystemOut().println("Usage: --mslp path/to/folder");
System.exit(0);
}
MSLPMaker.start(mslp);
System.exit(0);
} else if (mode == versionMode) {
StreamUtils.GetSystemOut().println("You are running " + Implementation.GetServerType().getBranding() + " version " + loadSelfVersion());
System.exit(0);
} else if (mode == copyrightMode) {
StreamUtils.GetSystemOut().println("The MIT License (MIT)\n" + "\n" + "Copyright (c) 2012-2017 Methodscript Contributors\n" + "\n" + "Permission is hereby granted, free of charge, to any person obtaining a copy of \n" + "this software and associated documentation files (the \"Software\"), to deal in \n" + "the Software without restriction, including without limitation the rights to \n" + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of \n" + "the Software, and to permit persons to whom the Software is furnished to do so, \n" + "subject to the following conditions:\n" + "\n" + "The above copyright notice and this permission notice shall be included in all \n" + "copies or substantial portions of the Software.\n" + "\n" + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \n" + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS \n" + "FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR \n" + "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER \n" + "IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN \n" + "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.");
System.exit(0);
} else if (mode == printDBMode) {
ConnectionMixinFactory.ConnectionMixinOptions options = new ConnectionMixinFactory.ConnectionMixinOptions();
options.setWorkingDirectory(MethodScriptFileLocations.getDefault().getConfigDirectory());
PersistenceNetwork pn = new PersistenceNetwork(MethodScriptFileLocations.getDefault().getPersistenceConfig(), new URI("sqlite://" + MethodScriptFileLocations.getDefault().getDefaultPersistenceDBFile().getCanonicalPath().replace('\\', '/')), options);
Map<String[], String> values = pn.getNamespace(new String[] {});
for (String[] s : values.keySet()) {
StreamUtils.GetSystemOut().println(StringUtils.Join(s, ".") + "=" + values.get(s));
}
System.exit(0);
} else if (mode == docsMode) {
DocGen.MarkupType docs;
try {
docs = DocGen.MarkupType.valueOf(parsedArgs.getStringArgument().toUpperCase());
} catch (IllegalArgumentException e) {
StreamUtils.GetSystemOut().println("The type of documentation must be one of the following: " + StringUtils.Join(DocGen.MarkupType.values(), ", ", ", or "));
System.exit(1);
return;
}
// Documentation generator
StreamUtils.GetSystemErr().print("Creating " + docs + " documentation...");
DocGen.functions(docs, api.Platforms.INTERPRETER_JAVA, true);
StreamUtils.GetSystemErr().println("Done.");
System.exit(0);
} else if (mode == examplesMode) {
ExampleLocalPackageInstaller.run(MethodScriptFileLocations.getDefault().getJarDirectory(), parsedArgs.getStringArgument());
} else if (mode == verifyMode) {
String file = parsedArgs.getStringArgument();
if ("".equals(file)) {
StreamUtils.GetSystemErr().println("File parameter is required.");
System.exit(1);
}
File f = new File(file);
String script = FileUtil.read(f);
try {
try {
MethodScriptCompiler.compile(MethodScriptCompiler.lex(script, f, file.endsWith("ms")));
} catch (ConfigCompileException ex) {
Set<ConfigCompileException> s = new HashSet<>(1);
s.add(ex);
throw new ConfigCompileGroupException(s);
}
} catch (ConfigCompileGroupException ex) {
List<Map<String, Object>> err = new ArrayList<>();
for (ConfigCompileException e : ex.getList()) {
Map<String, Object> error = new HashMap<>();
error.put("msg", e.getMessage());
error.put("file", e.getFile().getAbsolutePath());
error.put("line", e.getLineNum());
error.put("col", e.getColumn());
// TODO: Need to track target length for this
error.put("len", 0);
err.add(error);
}
String serr = JSONValue.toJSONString(err);
StreamUtils.GetSystemOut().println(serr);
}
} else if (mode == apiMode) {
String function = parsedArgs.getStringArgument();
if ("".equals(function)) {
StreamUtils.GetSystemErr().println("Usage: java -jar CommandHelper.jar --api <function name>");
System.exit(1);
}
FunctionBase f;
try {
f = FunctionList.getFunction(function, Target.UNKNOWN);
} catch (ConfigCompileException e) {
StreamUtils.GetSystemErr().println("The function '" + function + "' was not found.");
System.exit(1);
throw new Error();
}
DocGen.DocInfo di = new DocGen.DocInfo(f.docs());
String ret = di.ret.replaceAll("</?[a-z].*?>", "");
String args2 = di.args.replaceAll("</?[a-z].*?>", "");
String desc = (di.desc + (di.extendedDesc != null ? "\n\n" + di.extendedDesc : "")).replaceAll("</?[a-z].*?>", "");
StreamUtils.GetSystemOut().println(StringUtils.Join(new String[] { function, "Returns " + ret, "Expects " + args2, desc }, " // "));
System.exit(0);
} else if (mode == syntaxMode) {
// TODO: Maybe load extensions here?
List<String> syntax = parsedArgs.getStringListArgument();
String type = (syntax.size() >= 1 ? syntax.get(0) : null);
String theme = (syntax.size() >= 2 ? syntax.get(1) : null);
StreamUtils.GetSystemOut().println(SyntaxHighlighters.generate(type, theme));
System.exit(0);
} else if (mode == optimizerTestMode) {
String path = parsedArgs.getStringArgument();
File source = new File(path);
String plain = FileUtil.read(source);
Security.setSecurityEnabled(false);
String optimized;
try {
try {
optimized = OptimizationUtilities.optimize(plain, source);
} catch (ConfigCompileException ex) {
Set<ConfigCompileException> group = new HashSet<>();
group.add(ex);
throw new ConfigCompileGroupException(group);
}
} catch (ConfigCompileGroupException ex) {
ConfigRuntimeException.HandleUncaughtException(ex, null);
System.exit(1);
return;
}
StreamUtils.GetSystemOut().println(optimized);
System.exit(0);
} else if (mode == cmdlineMode) {
// We actually can't use the parsedArgs, because there may be cmdline switches in
// the arguments that we want to ignore here, but otherwise pass through. parsedArgs
// will prevent us from seeing those, however.
List<String> allArgs = new ArrayList<>(Arrays.asList(args));
// The 0th arg is the cmdline verb though, so remove that.
allArgs.remove(0);
if (allArgs.isEmpty()) {
StreamUtils.GetSystemErr().println("Usage: path/to/file.ms [arg1 arg2]");
System.exit(1);
}
String fileName = allArgs.get(0);
allArgs.remove(0);
try {
Interpreter.startWithTTY(fileName, allArgs);
} catch (Profiles.InvalidProfileException ex) {
StreamUtils.GetSystemErr().println("Invalid profile file at " + MethodScriptFileLocations.getDefault().getProfilesFile() + ": " + ex.getMessage());
System.exit(1);
}
StaticLayer.GetConvertor().runShutdownHooks();
System.exit(0);
} else if (mode == extensionDocsMode) {
String inputJarS = parsedArgs.getStringArgument("input-jar");
String outputFileS = parsedArgs.getStringArgument("output-file");
if (inputJarS == null) {
StreamUtils.GetSystemOut().println("Usage: --input-jar extension-docs path/to/extension.jar [--output-file path/to/output.md]\n\tIf the output is blank, it is printed to stdout.");
System.exit(1);
}
File inputJar = new File(inputJarS);
OutputStream outputFile = StreamUtils.GetSystemOut();
if (outputFileS != null) {
outputFile = new FileOutputStream(new File(outputFileS));
}
ExtensionDocGen.generate(inputJar, outputFile);
} else if (mode == docExportMode) {
String extensionDirS = parsedArgs.getStringArgument("extension-dir");
String outputFileS = parsedArgs.getStringArgument("output-file");
OutputStream outputFile = StreamUtils.GetSystemOut();
if (outputFileS != null) {
outputFile = new FileOutputStream(new File(outputFileS));
}
Implementation.forceServerType(Implementation.Type.BUKKIT);
File extensionDir = new File(extensionDirS);
if (extensionDir.exists()) {
// to stderr.
for (File f : extensionDir.listFiles()) {
if (f.getName().endsWith(".jar")) {
cd.addDiscoveryLocation(f.toURI().toURL());
}
}
} else {
StreamUtils.GetSystemErr().println("Extension directory specificed doesn't exist: " + extensionDirS + ". Continuing anyways.");
}
new DocGenExportTool(cd, outputFile).export();
} else if (mode == profilerSummaryMode) {
String input = parsedArgs.getStringArgument();
if ("".equals(input)) {
StreamUtils.GetSystemErr().println(TermColors.RED + "No input file specified! Run `help profiler-summary' for usage." + TermColors.RESET);
System.exit(1);
}
double ignorePercentage = parsedArgs.getNumberArgument("ignore-percentage");
ProfilerSummary summary = new ProfilerSummary(new FileInputStream(input));
try {
summary.setIgnorePercentage(ignorePercentage);
} catch (IllegalArgumentException ex) {
StreamUtils.GetSystemErr().println(TermColors.RED + ex.getMessage() + TermColors.RESET);
System.exit(1);
}
StreamUtils.GetSystemOut().println(summary.getAnalysis());
System.exit(0);
} else if (mode == rsaKeyGenMode) {
String outputFileString = parsedArgs.getStringArgument('o');
File privOutputFile = new File(outputFileString);
File pubOutputFile = new File(outputFileString + ".pub");
String label = parsedArgs.getStringArgument('l');
if (privOutputFile.exists() || pubOutputFile.exists()) {
StreamUtils.GetSystemErr().println("Either the public key or private key file already exists. This utility will not overwrite any existing files.");
System.exit(1);
}
RSAEncrypt enc = RSAEncrypt.generateKey(label);
FileUtil.write(enc.getPrivateKey(), privOutputFile);
FileUtil.write(enc.getPublicKey(), pubOutputFile);
System.exit(0);
} else if (mode == pnViewerMode) {
if (parsedArgs.isFlagSet("server")) {
if (parsedArgs.getNumberArgument("port") == null) {
StreamUtils.GetSystemErr().println("When running as a server, port is required.");
System.exit(1);
}
int port = parsedArgs.getNumberArgument("port").intValue();
if (port > 65535 || port < 1) {
StreamUtils.GetSystemErr().println("Port must be between 1 and 65535.");
System.exit(1);
}
String password = parsedArgs.getStringArgument("password");
if ("".equals(password)) {
ConsoleReader reader = null;
try {
reader = new ConsoleReader();
reader.setExpandEvents(false);
Character cha = new Character((char) 0);
password = reader.readLine("Enter password: ", cha);
} finally {
if (reader != null) {
reader.shutdown();
}
}
}
if (password == null) {
StreamUtils.GetSystemErr().println("Warning! Running server with no password, anyone will be able to connect!");
password = "";
}
try {
PNViewer.startServer(port, password);
} catch (IOException ex) {
StreamUtils.GetSystemErr().println(ex.getMessage());
System.exit(1);
}
} else {
try {
PNViewer.main(parsedArgs.getStringListArgument().toArray(ArrayUtils.EMPTY_STRING_ARRAY));
} catch (HeadlessException ex) {
StreamUtils.GetSystemErr().println("The Persistence Network Viewer may not be run from a headless environment.");
System.exit(1);
}
}
} else if (mode == uiMode) {
if (parsedArgs.isFlagSet("in-shell")) {
// Actually launch the GUI
UILauncher.main(args);
} else {
// Relaunch the jar in a new process with the --run flag set,
// so that the process will be in its own subshell
CommandExecutor ce = new CommandExecutor("java -jar " + ClassDiscovery.GetClassContainer(Main.class).getPath() + " " + StringUtils.Join(args, " ") + " --in-shell");
ce.start();
System.exit(0);
}
} else if (mode == siteDeploy) {
boolean clearLocalCache = parsedArgs.isFlagSet("clear-local-cache");
if (clearLocalCache) {
PersistenceNetwork p = SiteDeploy.getPersistenceNetwork();
if (p == null) {
System.out.println("Cannot get reference to persistence network");
System.exit(1);
return;
}
DaemonManager dm = new DaemonManager();
p.clearKey(dm, new String[] { "site_deploy", "local_cache" });
dm.waitForThreads();
System.out.println("Local cache cleared");
System.exit(0);
}
boolean generatePrefs = parsedArgs.isFlagSet("generate-prefs");
boolean useLocalCache = parsedArgs.isFlagSet("use-local-cache");
boolean doValidation = parsedArgs.isFlagSet("do-validation");
String configString = parsedArgs.getStringArgument("config");
if ("".equals(configString)) {
System.err.println("Config file missing, check command and try again");
System.exit(1);
}
File config = new File(configString);
SiteDeploy.run(generatePrefs, useLocalCache, config, "", doValidation);
} else if (mode == newMode) {
String li = OSUtils.GetLineEnding();
for (String file : parsedArgs.getStringListArgument()) {
File f = new File(file);
if (f.exists() && !parsedArgs.isFlagSet('f')) {
System.out.println(file + " already exists, refusing to create");
continue;
}
f.createNewFile();
f.setExecutable(true);
FileUtil.write("#!/usr/bin/env /usr/local/bin/mscript" + li + "<!" + li + "\tstrict;" + li + "\tname: " + f.getName() + ";" + li + "\tauthor: " + StaticLayer.GetConvertor().GetUser(null) + ";" + li + "\tcreated: " + new Scheduling.simple_date().exec(Target.UNKNOWN, null, new CString("yyyy-MM-dd", Target.UNKNOWN)).val() + ";" + li + "\tdescription: " + ";" + li + ">" + li + li, f, true);
}
} else {
throw new Error("Should not have gotten here");
}
} catch (NoClassDefFoundError error) {
StreamUtils.GetSystemErr().println(getNoClassDefFoundErrorMessage(error));
}
}
use of com.laytonsmith.core.exceptions.ConfigCompileException in project CommandHelper by EngineHub.
the class MethodScriptCompiler method preprocess.
/**
* This function breaks the token stream into parts, separating the aliases/MethodScript from the command triggers
*
* @param tokenStream
* @return
* @throws ConfigCompileException
*/
public static List<Script> preprocess(TokenStream tokenStream) throws ConfigCompileException {
if (tokenStream == null || tokenStream.isEmpty()) {
return new ArrayList<>();
}
// Remove leading newlines.
while (!tokenStream.isEmpty() && tokenStream.getFirst().type == TType.NEWLINE) {
// Remove leading newlines.
tokenStream.removeFirst();
}
// Return an empty list if there were only newlines.
if (tokenStream.isEmpty()) {
return new ArrayList<>();
}
// Remove whitespaces and duplicate newlines.
{
ListIterator<Token> it = tokenStream.listIterator(0);
Token token = it.next();
outerLoop: while (true) {
switch(token.type) {
case WHITESPACE:
{
// Remove whitespaces.
it.remove();
if (!it.hasNext()) {
break outerLoop;
}
token = it.next();
continue outerLoop;
}
case NEWLINE:
{
while (true) {
if (!it.hasNext()) {
break outerLoop;
} else if ((token = it.next()).type == TType.NEWLINE) {
// Remove duplicate newlines.
it.remove();
} else {
continue outerLoop;
}
}
}
default:
{
if (!it.hasNext()) {
break outerLoop;
}
token = it.next();
continue outerLoop;
}
}
}
}
// Handle multiline constructs.
// Take out newlines between the '= >>>' and '<<<' tokens (also removing the '>>>' and '<<<' tokens).
// Also remove comments and also remove newlines that are behind a '\'.
boolean inside_multiline = false;
ListIterator<Token> it = tokenStream.listIterator(0);
Token token = null;
while (it.hasNext()) {
token = it.next();
switch(token.type) {
case ALIAS_END:
{
// "=".
if (it.hasNext()) {
if (it.next().type == TType.MULTILINE_START) {
// "= >>>".
inside_multiline = true;
// Remove multiline start (>>>).
it.remove();
// Select 'token' <---.
it.previous();
// Select 'token' -->.
it.next();
} else {
// Select 'next' <---.
it.previous();
}
}
continue;
}
case MULTILINE_END:
{
// Handle multiline end token (<<<) without start.
if (!inside_multiline) {
throw new ConfigCompileException("Found multiline end symbol, and no multiline start found", token.target);
}
inside_multiline = false;
// Remove multiline end (<<<).
it.remove();
continue;
}
case MULTILINE_START:
{
// Handle multiline start token (>>>) while already in multiline.
if (inside_multiline) {
throw new ConfigCompileException("Did not expect a multiline start symbol here," + " are you missing a multiline end symbol above this line?", token.target);
}
// Handle multiline start token (>>>) without alias end (=) in front.
// Select 'token' <--.
it.previous();
if (!it.hasPrevious() || it.previous().type != TType.ALIAS_END) {
throw new ConfigCompileException("Multiline symbol must follow the alias_end (=) symbol", token.target);
}
// Select 'prev' -->.
it.next();
// Select 'token' -->.
it.next();
continue;
}
case NEWLINE:
{
// Skip newlines that are inside a multiline construct.
if (inside_multiline) {
// Remove newline.
it.remove();
}
continue;
}
// Remove comments.
case COMMENT:
case SMART_COMMENT:
{
// Remove comment.
it.remove();
continue;
}
default:
{
// Remove newlines that are behind a '\'.
if (token.type != TType.STRING && token.val().equals("\\") && it.hasNext()) {
if (it.next().type == TType.NEWLINE) {
// Remove newline.
it.remove();
// Select 'token' <--.
it.previous();
// Select 'token' -->.
it.next();
} else {
// Select 'next' <--.
it.previous();
}
}
}
}
}
assert token != null;
// Handle missing multiline end token.
if (inside_multiline) {
throw new ConfigCompileException("Expecting a multiline end symbol, but your last multiline alias appears to be missing one.", token.target);
}
// Now that we have all lines minified, we should be able to split on newlines
// and easily find the left and right sides.
List<Token> left = new ArrayList<>();
List<Token> right = new ArrayList<>();
List<Script> scripts = new ArrayList<>();
tokenLoop: for (it = tokenStream.listIterator(0); it.hasNext(); ) {
Token t = it.next();
// Add all tokens until ALIAS_END (=) or end of stream.
while (t.type != TType.ALIAS_END) {
if (!it.hasNext()) {
// End of stream.
break tokenLoop;
}
left.add(t);
t = it.next();
}
// Add all tokens until NEWLINE (\n).
while (t.type != TType.NEWLINE) {
// All files end with a newline, so end of stream should be impossible here.
assert it.hasNext();
right.add(t);
t = it.next();
}
// Create a new script for the obtained left and right if end of stream has not been reached.
if (t.type == TType.NEWLINE) {
// Check for spurious symbols, which indicate an issue with the script, but ignore any whitespace.
for (int j = left.size() - 1; j >= 0; j--) {
if (left.get(j).type == TType.NEWLINE) {
if (j > 0 && left.get(j - 1).type != TType.WHITESPACE) {
throw new ConfigCompileException("Unexpected token: " + left.get(j - 1).val(), left.get(j - 1).getTarget());
}
}
}
// Create a new script from the command descriptor (left) and code (right) and add it to the list.
Script s = new Script(left, right, null, tokenStream.getFileOptions());
scripts.add(s);
// Create new left and right array for the next script.
left = new ArrayList<>();
right = new ArrayList<>();
}
}
// Return the scripts.
return scripts;
}
use of com.laytonsmith.core.exceptions.ConfigCompileException 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.exceptions.ConfigCompileException 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