use of com.laytonsmith.core.constructs.Construct in project CommandHelper by EngineHub.
the class Static method AssertType.
/**
* This verifies that the type required is actually present, and returns the value, cast to the appropriate type,
* or, if not the correct type, a CRE.
* <p>
* Note that this does not do type coersion, and therefore does not work on primitives, and is only meant for
* arrays, closures, and other complex types.
*
* @param <T> The type desired to be cast to
* @param type The type desired to be cast to
* @param args The array of arguments.
* @param argNumber The argument number, used both for grabbing the correct argument from args, and building the
* error message if the cast cannot occur.
* @param func The function, in case this errors out, to build the error message.
* @param t The code target
* @return The value, cast to the desired type.
*/
public static <T extends Construct> T AssertType(Class<T> type, Construct[] args, int argNumber, Function func, Target t) {
Construct value = args[argNumber];
if (!type.isAssignableFrom(value.getClass())) {
typeof todesired = type.getAnnotation(typeof.class);
CClassType toactual = value.typeof();
if (todesired != null) {
throw new CRECastException("Argument " + (argNumber + 1) + " of " + func.getName() + " was expected to be a " + todesired.value() + ", but " + toactual + " \"" + value.val() + "\" was found.", t);
} else {
// If the typeof annotation isn't present, this is a programming error.
throw new IllegalArgumentException("");
}
} else {
return (T) value;
}
}
use of com.laytonsmith.core.constructs.Construct in project CommandHelper by EngineHub.
the class Procedure method execute.
/**
* Executes this procedure, with the arguments that were passed in
*
* @param args
* @param env
* @param t
* @return
*/
public Construct execute(List<Construct> args, Environment env, Target t) {
env.getEnv(GlobalEnv.class).SetVarList(new IVariableList());
// This is what will become our @arguments var
CArray arguments = new CArray(Target.UNKNOWN);
for (String key : originals.keySet()) {
Construct c = originals.get(key);
env.getEnv(GlobalEnv.class).GetVarList().set(new IVariable(Auto.TYPE, key, c, Target.UNKNOWN));
arguments.push(c, t);
}
// new Script(null, null);
Script fakeScript = Script.GenerateScript(tree, env.getEnv(GlobalEnv.class).GetLabel());
for (int i = 0; i < args.size(); i++) {
Construct c = args.get(i);
arguments.set(i, c, t);
if (varIndex.size() > i) {
String varname = varIndex.get(i).getVariableName();
if (c instanceof CNull || InstanceofUtil.isInstanceof(c, varIndex.get(i).getDefinedType()) || varIndex.get(i).getDefinedType().equals(Auto.TYPE)) {
env.getEnv(GlobalEnv.class).GetVarList().set(new IVariable(varIndex.get(i).getDefinedType(), varname, c, c.getTarget()));
} else {
throw new CRECastException("Procedure \"" + name + "\" expects a value of type " + varIndex.get(i).getDefinedType().val() + " in argument " + (i + 1) + ", but" + " a value of type " + c.typeof() + " was found instead.", c.getTarget());
}
}
}
env.getEnv(GlobalEnv.class).GetVarList().set(new IVariable(CArray.TYPE, "@arguments", arguments, Target.UNKNOWN));
StackTraceManager stManager = env.getEnv(GlobalEnv.class).GetStackTraceManager();
stManager.addStackTraceElement(new ConfigRuntimeException.StackTraceElement("proc " + name, getTarget()));
try {
if (tree.getData() instanceof CFunction && "sconcat".equals(tree.getData().val())) {
// compiler proper.
for (ParseTree child : tree.getChildren()) {
fakeScript.eval(child, env);
}
} else {
fakeScript.eval(tree, env);
}
} catch (FunctionReturnException e) {
// Normal exit
stManager.popStackTraceElement();
Construct ret = e.getReturn();
if (!InstanceofUtil.isInstanceof(ret, returnType)) {
throw new CRECastException("Expected procedure \"" + name + "\" to return a value of type " + returnType.val() + " but a value of type " + ret.typeof() + " was returned instead", ret.getTarget());
}
return ret;
} catch (LoopManipulationException ex) {
// Not exactly normal, but pop anyways
stManager.popStackTraceElement();
// a compile error.
throw ConfigRuntimeException.CreateUncatchableException("Loop manipulation operations (e.g. break() or continue()) cannot" + " bubble up past procedures.", t);
} catch (ConfigRuntimeException e) {
if (e instanceof AbstractCREException) {
((AbstractCREException) e).freezeStackTraceElements(stManager);
}
stManager.popStackTraceElement();
throw e;
} catch (Throwable th) {
// Not sure. Pop, but rethrow
stManager.popStackTraceElement();
throw th;
}
// Normal exit, but no return.
stManager.popStackTraceElement();
// If we got here, then there was no return value. This is fine, but only for returnType void or auto.
if (!(returnType.equals(Auto.TYPE) || returnType.equals(CVoid.TYPE))) {
throw new CRECastException("Expecting procedure \"" + name + "\" to return a value of type " + returnType.val() + "," + " but no value was returned.", tree.getTarget());
}
return CVoid.VOID;
}
use of com.laytonsmith.core.constructs.Construct in project CommandHelper by EngineHub.
the class Script method run.
public void run(final List<Variable> vars, Environment myEnv, final MethodScriptComplete done) {
// Some things, such as the label are determined at compile time
this.CurrentEnv = myEnv;
this.CurrentEnv.getEnv(GlobalEnv.class).SetLabel(this.label);
MCCommandSender p = myEnv.getEnv(CommandHelperEnvironment.class).GetCommandSender();
if (!hasBeenCompiled || compilerError) {
Target target = Target.UNKNOWN;
if (left.size() >= 1) {
try {
target = new Target(left.get(0).line_num, left.get(0).file, left.get(0).column);
} catch (NullPointerException e) {
// Oh well, we tried to get more information
}
}
throw ConfigRuntimeException.CreateUncatchableException("Unable to run command, script not yet compiled," + " or a compiler error occurred for that command. To see the compile error, run /reloadaliases", target);
}
enforceLabelPermissions();
try {
for (ParseTree rootNode : cright) {
if (rootNode == null) {
continue;
}
for (Construct tempNode : rootNode.getAllData()) {
if (tempNode instanceof Variable) {
if (left_vars == null) {
throw ConfigRuntimeException.CreateUncatchableException("$variables may not be used in this context." + " Only @variables may be.", tempNode.getTarget());
}
Construct c = Static.resolveDollarVar(left_vars.get(((Variable) tempNode).getVariableName()), vars);
((Variable) tempNode).setVal(new CString(c.toString(), tempNode.getTarget()));
}
}
MethodScriptCompiler.registerAutoIncludes(CurrentEnv, this);
MethodScriptCompiler.execute(rootNode, CurrentEnv, done, this);
}
} catch (ConfigRuntimeException ex) {
// We don't know how to handle this really, so let's pass it up the chain.
throw ex;
} catch (CancelCommandException e) {
// p.sendMessage(e.getMessage());
// The message in the exception is actually empty
} catch (LoopBreakException e) {
if (p != null) {
p.sendMessage("The break() function must be used inside a for() or foreach() loop");
}
StreamUtils.GetSystemOut().println("The break() function must be used inside a for() or foreach() loop");
} catch (LoopContinueException e) {
if (p != null) {
p.sendMessage("The continue() function must be used inside a for() or foreach() loop");
}
StreamUtils.GetSystemOut().println("The continue() function must be used inside a for() or foreach() loop");
} catch (FunctionReturnException e) {
if (myEnv.getEnv(GlobalEnv.class).GetEvent() != null) {
// Oh, we're running in an event handler. Those know how to catch it too.
throw e;
}
if (p != null) {
p.sendMessage("The return() function must be used inside a procedure.");
}
StreamUtils.GetSystemOut().println("The return() function must be used inside a procedure.");
} catch (Throwable t) {
StreamUtils.GetSystemOut().println("An unexpected exception occurred during the execution of a script.");
t.printStackTrace();
if (p != null) {
p.sendMessage("An unexpected exception occurred during the execution of your script." + " Please check the console for more information.");
}
}
if (done != null) {
done.done(null);
}
}
use of com.laytonsmith.core.constructs.Construct 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.constructs.Construct in project CommandHelper by EngineHub.
the class Script method match.
public boolean match(String command) {
if (cleft == null) {
// we can't match it, nor can we even tell if it's what they intended for us to run.
return false;
}
boolean case_sensitive = Prefs.CaseSensitive();
String[] cmds = command.split(" ");
List<String> args = new ArrayList<>(Arrays.asList(cmds));
boolean isAMatch = true;
StringBuilder lastVar = new StringBuilder();
int lastJ = 0;
for (int j = 0; j < cleft.size(); j++) {
if (!isAMatch) {
break;
}
lastJ = j;
Construct c = cleft.get(j);
if (args.size() <= j) {
if (c.getCType() != ConstructType.VARIABLE || !((Variable) c).isOptional()) {
isAMatch = false;
}
break;
}
String arg = args.get(j);
if (c.getCType() != ConstructType.VARIABLE) {
if (case_sensitive && !c.val().equals(arg) || !case_sensitive && !c.val().equalsIgnoreCase(arg)) {
isAMatch = false;
continue;
}
} else {
// args isn't greater than the size of cleft, it's a match
if (((Variable) c).isOptional()) {
if (args.size() <= cleft.size()) {
return true;
} else {
Construct fin = cleft.get(cleft.size() - 1);
if (fin instanceof Variable) {
if (((Variable) fin).isFinal()) {
return true;
}
}
return false;
}
}
}
if (j == cleft.size() - 1) {
if (cleft.get(j).getCType() == ConstructType.VARIABLE) {
Variable lv = (Variable) cleft.get(j);
if (lv.isFinal()) {
for (int a = j; a < args.size(); a++) {
if (lastVar.length() == 0) {
lastVar.append(args.get(a));
} else {
lastVar.append(" ").append(args.get(a));
}
}
}
}
}
}
boolean lastIsFinal = false;
if (cleft.get(cleft.size() - 1) instanceof Variable) {
Variable v = (Variable) cleft.get(cleft.size() - 1);
if (v.isFinal()) {
lastIsFinal = true;
}
}
if ((cleft.get(lastJ) instanceof Variable && ((Variable) cleft.get(lastJ)).isOptional())) {
return true;
}
if (cleft.size() != cmds.length && !lastIsFinal) {
isAMatch = false;
}
return isAMatch;
}
Aggregations