@Override public ParseTree optimizeDynamic(Target t, List<ParseTree> children, FileOptions fileOptions) throws ConfigCompileException, ConfigRuntimeException { // We can check 2 things here, one, that the statement isn't dynamic, and if not, then // 2, that the parameter count matches the ? count. No checks can be done for typing, // without making a connection to the db though, so we won't do that here. Construct queryData = children.get(1).getData(); if (queryData instanceof CFunction) { // If it's a concat or sconcat, warn them that this is bad if ("sconcat".equals(queryData.val()) || "concat".equals(queryData.val())) { CHLog.GetLogger() .w( CHLog.Tags.COMPILER, "Use of concatenated query detected! This" + " is very bad practice, and could lead to SQL injection vulnerabilities" + " in your code. It is highly recommended that you use prepared queries," + " which ensure that your parameters are properly escaped.", t); } } else if (queryData instanceof CString) { // It's a hard coded query, so we can double check parameter lengths int count = 0; for (char c : queryData.val().toCharArray()) { if (c == '?') { count++; } } // -2 accounts for the profile data and query if (children.size() - 2 != count) { throw new ConfigCompileException( StringUtils.PluralTemplateHelper( count, "%d parameter token was", "%d parameter tokens were") + " found in the query, but " + StringUtils.PluralTemplateHelper( children.size() - 2, "%d parameter was", "%d parameters were") + " provided to query().", t); } } return null; }
public void checkAmbiguous(List<Script> scripts) throws ConfigCompileException { // for (int i = 0; i < scripts.size(); i++) { List<Construct> thisCommand = this.cleft; for (int j = 0; j < scripts.size(); j++) { List<Construct> thatCommand = scripts.get(j).cleft; if (thatCommand == null) { // it hasn't been compiled yet. return; } if (this.cleft == scripts.get(j).cleft) { // Of course this command is going to match it's own signature continue; } boolean soFarAMatch = true; for (int k = 0; k < thisCommand.size(); k++) { try { Construct c1 = thisCommand.get(k); Construct c2 = thatCommand.get(k); if (c1.getCType() != c2.getCType() || ((c1 instanceof Variable) && !((Variable) c1).isOptional())) { soFarAMatch = false; } else { // It's a literal, check to see if it's the same literal if (c1.nval() == null || !c1.val().equals(c2.val())) { soFarAMatch = false; } } } catch (IndexOutOfBoundsException e) { /** * The two commands: /cmd $var1 [$var2] /cmd $var1 would cause this exception to be * thrown, but the signatures are the same, so the fact that they've matched this far * means they are ambiguous. However, /cmd $var1 $var2 /cmd $var1 is not ambiguous */ // thatCommand is the short one if (!(thisCommand.get(k) instanceof Variable) || (thisCommand.get(k) instanceof Variable && !((Variable) thisCommand.get(k)).isOptional())) { soFarAMatch = false; } } } if (thatCommand.size() > thisCommand.size()) { int k = thisCommand.size(); // thisCommand is the short one if (!(thatCommand.get(k) instanceof Variable) || (thatCommand.get(k) instanceof Variable && !((Variable) thatCommand.get(k)).isOptional())) { soFarAMatch = false; } } if (soFarAMatch) { String commandThis = ""; for (Construct c : thisCommand) { commandThis += c.val() + " "; } String commandThat = ""; for (Construct c : thatCommand) { commandThat += c.val() + " "; } scripts.get(j).compilerError = true; this.compilerError = true; throw new ConfigCompileException( "The command " + commandThis.trim() + " is ambiguous because it " + "matches the signature of " + commandThat.trim(), thisCommand.get(0).getTarget()); } } // //Also, check for undefined variables on the right, and unused variables on the left // ArrayList<String> left_copy = new ArrayList<String>(); // for (Map.Entry<String, Variable> v : left_vars.entrySet()) { // left_copy.add(v.getValue().getName()); // } // Arrays.asList(new String[]{}).toArray(new String[]{}); // for (ParseTree gtn : cright) { // GenericTree<Construct> tree = new GenericTree<Construct>(); // tree.setRoot(gtn); // List<ParseTree> builtTree = tree.build(GenericTreeTraversalOrderEnum.PRE_ORDER); // for (ParseTree c : builtTree) { // if (c.getData() instanceof Variable) { // for (Map.Entry<String, Variable> v : left_vars.entrySet()) { // if (v.getValue().getName().equals(((Variable) c.getData()).getName())) // { // //Found it, remove this from the left_copy, and break // left_copy.remove(v.getValue().getName()); // break; // //TODO: Layton! // } // } // } // } // } // } }
public boolean match(String command) { if (cleft == null) { // The compilation error happened during the signature declaration, so // 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; try { for (int j = 0; j < cleft.size(); j++) { if (!isAMatch) { break; } lastJ = j; Construct c = cleft.get(j); 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 { // It's a variable. If it's optional, the rest of them are optional too, so as long as the // size of // 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)); } } } } } } } catch (IndexOutOfBoundsException e) { if (cleft.get(lastJ).getCType() != ConstructType.VARIABLE || cleft.get(lastJ).getCType() == ConstructType.VARIABLE && !((Variable) cleft.get(lastJ)).isOptional()) { isAMatch = false; } } 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; } // ArrayList<Variable> vars = new ArrayList<Variable>(); // Variable v = null; // for (int j = 0; j < cleft.size(); j++) { // try { // if (cleft.get(j).getCType() == ConstructType.VARIABLE) { // if (((Variable) cleft.get(j)).getName().equals("$")) { // v = new Variable(((Variable) cleft.get(j)).getName(), // lastVar.toString(), Target.UNKNOWN); // } else { // v = new Variable(((Variable) cleft.get(j)).getName(), // args.get(j), Target.UNKNOWN); // } // } // } catch (IndexOutOfBoundsException e) { // v = new Variable(((Variable) cleft.get(j)).getName(), // ((Variable) cleft.get(j)).getDefault(), Target.UNKNOWN); // } // if (v != null) { // vars.add(v); // } // } return isAMatch; }
public Construct eval(ParseTree c, final Environment env) throws CancelCommandException { final Construct m = c.getData(); CurrentEnv = env; // TODO: Reevaluate if this line is needed. The script doesn't know the label inherently, the // environment does, and setting it this way taints the environment. CurrentEnv.getEnv(GlobalEnv.class).SetLabel(this.label); if (m.getCType() == ConstructType.FUNCTION) { env.getEnv(GlobalEnv.class).SetScript(this); if (m.val().matches("^_[^_].*")) { // Not really a function, so we can't put it in Function. Procedure p = getProc(m.val()); if (p == null) { throw new ConfigRuntimeException( "Unknown procedure \"" + m.val() + "\"", ExceptionType.InvalidProcedureException, m.getTarget()); } Environment newEnv = env; try { newEnv = env.clone(); } catch (Exception e) { } ProfilePoint pp = env.getEnv(GlobalEnv.class).GetProfiler().start(m.val() + " execution", LogLevel.INFO); Construct ret = p.cexecute(c.getChildren(), newEnv, m.getTarget()); 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 new ConfigRuntimeException("Unable to find function " + m.val(), m.getTarget()); } // We have special handling for loop and other control flow functions if (f instanceof assign) { if (c.getChildAt(0).getData() instanceof CFunction) { CFunction test = (CFunction) c.getChildAt(0).getData(); if (test.val().equals("array_get")) { env.getEnv(GlobalEnv.class).SetFlag("array_get_alt_mode", true); Construct arrayAndIndex = eval(c.getChildAt(0), env); env.getEnv(GlobalEnv.class).ClearFlag("array_get_alt_mode"); return ((assign) f) .array_assign(m.getTarget(), env, arrayAndIndex, eval(c.getChildAt(1), env)); } } } 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 = f.execs(m.getTarget(), env, this, c.getChildren().toArray(new ParseTree[] {})); if (p != null) { p.stop(); } return ret; } ArrayList<Construct> args = new ArrayList<Construct>(); for (ParseTree c2 : c.getChildren()) { args.add(eval(c2, env)); } if (f.isRestricted()) { boolean perm = Static.hasCHPermission(f.getName(), env); if (!perm) { throw new ConfigRuntimeException( "You do not have permission to use the " + f.getName() + " function.", ExceptionType.InsufficientPermissionException, m.getTarget()); } } 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 ConfigRuntimeException( "Invalid Construct (" + ca[i].getClass() + ") being passed as an argument to a function (" + f.getName() + ")", null, m.getTarget()); } if (env.getEnv(GlobalEnv.class).GetFlag("array_get_alt_mode") == Boolean.TRUE && i == 0) { continue; } while (f.preResolveVariables() && ca[i] instanceof IVariable) { IVariable cur = (IVariable) ca[i]; ca[i] = env.getEnv(GlobalEnv.class).GetVarList().get(cur.getName(), 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 = f.exec(m.getTarget(), env, ca); if (p != null) { p.stop(); } return ret; } } else if (m.getCType() == ConstructType.VARIABLE) { return new CString(m.val(), m.getTarget()); } else { return m; } }
public MCItemMeta itemMeta(Construct c, int i, Target t) { MCItemMeta meta = Static.getServer().getItemFactory().getItemMeta(StaticLayer.GetConvertor().getMaterial(i)); if (c instanceof CNull) { return meta; } CArray ma = null; if (c instanceof CArray) { ma = (CArray) c; try { if (ma.containsKey("display")) { Construct dni = ma.get("display"); if (!(dni instanceof CNull)) { meta.setDisplayName(dni.val()); } } if (ma.containsKey("lore")) { Construct li = ma.get("lore"); if (li instanceof CNull) { // do nothing } else if (li instanceof CArray) { CArray la = (CArray) li; List<String> ll = new ArrayList<String>(); for (int j = 0; j < la.size(); j++) { ll.add(la.get(j).val()); } meta.setLore(ll); } else { throw new Exceptions.FormatException("Lore was expected to be an array.", t); } } if (meta instanceof MCLeatherArmorMeta) { if (ma.containsKey("color")) { Construct ci = ma.get("color"); if (ci instanceof CNull) { // nothing } else if (ci instanceof CArray) { ((MCLeatherArmorMeta) meta).setColor(color((CArray) ci, t)); } else { throw new Exceptions.FormatException("Color was expected to be an array.", t); } } } if (meta instanceof MCBookMeta) { if (ma.containsKey("title")) { Construct title = ma.get("title"); if (!(title instanceof CNull)) { ((MCBookMeta) meta).setTitle(title.val()); } } if (ma.containsKey("author")) { Construct author = ma.get("author"); if (!(author instanceof CNull)) { ((MCBookMeta) meta).setAuthor(author.val()); } } if (ma.containsKey("pages")) { Construct pages = ma.get("pages"); if (pages instanceof CNull) { // nothing } else if (pages instanceof CArray) { CArray pa = (CArray) pages; List<String> pl = new ArrayList<String>(); for (int j = 0; j < pa.size(); j++) { pl.add(pa.get(j).val()); } ((MCBookMeta) meta).setPages(pl); } else { throw new Exceptions.FormatException("Pages field was expected to be an array.", t); } } } if (meta instanceof MCSkullMeta) { if (ma.containsKey("owner")) { Construct owner = ma.get("owner"); if (!(owner instanceof CNull)) { ((MCSkullMeta) meta).setOwner(owner.val()); } } } if (meta instanceof MCEnchantmentStorageMeta) { if (ma.containsKey("stored")) { Construct stored = ma.get("stored"); if (stored instanceof CNull) { // Still doing nothing } else if (stored instanceof CArray) { for (String index : ((CArray) stored).keySet()) { try { CArray earray = (CArray) ((CArray) stored).get(index); MCEnchantment etype = StaticLayer.GetConvertor().GetEnchantmentByName(earray.get("etype").val()); int elevel = Static.getInt32(earray.get("elevel"), t); ((MCEnchantmentStorageMeta) meta).addStoredEnchant(etype, elevel, true); } catch (Exception bade) { throw new Exceptions.FormatException( "Could not get enchantment data from index " + index, t); } } } else { throw new Exceptions.FormatException( "Stored field was expected to be an array of Enchantment arrays", t); } } } } catch (Exception ex) { throw new Exceptions.FormatException( "Could not get ItemMeta from the given information.", t); } } else { throw new Exceptions.FormatException( "An array was expected but recieved " + c + " instead.", t); } return meta; }
@Override public Construct execs(Target t, Environment env, Script parent, ParseTree... nodes) { if (nodes.length < 5) { throw new ConfigRuntimeException( "bind accepts 5 or more parameters", ExceptionType.InsufficientArgumentsException, t); } Construct name = parent.seval(nodes[0], env); Construct options = parent.seval(nodes[1], env); Construct prefilter = parent.seval(nodes[2], env); Construct event_obj = parent.eval(nodes[3], env); IVariableList custom_params = new IVariableList(); for (int a = 0; a < nodes.length - 5; a++) { Construct var = parent.eval(nodes[4 + a], env); if (!(var instanceof IVariable)) { throw new ConfigRuntimeException( "The custom parameters must be ivariables", ExceptionType.CastException, t); } IVariable cur = (IVariable) var; custom_params.set( env.getEnv(GlobalEnv.class).GetVarList().get(cur.getName(), cur.getTarget())); } Environment newEnv = env; try { newEnv = env.clone(); } catch (Exception e) { } newEnv.getEnv(GlobalEnv.class).SetVarList(custom_params); ParseTree tree = nodes[nodes.length - 1]; // Check to see if our arguments are correct if (!(options instanceof CNull || options instanceof CArray)) { throw new ConfigRuntimeException( "The options must be an array or null", ExceptionType.CastException, t); } if (!(prefilter instanceof CNull || prefilter instanceof CArray)) { throw new ConfigRuntimeException( "The prefilters must be an array or null", ExceptionType.CastException, t); } if (!(event_obj instanceof IVariable)) { throw new ConfigRuntimeException( "The event object must be an IVariable", ExceptionType.CastException, t); } CString id; if (options instanceof CNull) { options = null; } if (prefilter instanceof CNull) { prefilter = null; } Event event; try { BoundEvent be = new BoundEvent( name.val(), (CArray) options, (CArray) prefilter, ((IVariable) event_obj).getName(), newEnv, tree, t); EventUtils.RegisterEvent(be); id = new CString(be.getId(), t); event = EventList.getEvent(be.getEventName()); } catch (EventException ex) { throw new ConfigRuntimeException(ex.getMessage(), ExceptionType.BindException, t); } // Set up our bind counter, but only if the event is supposed to be added to the counter if (event.addCounter()) { synchronized (bindCounter) { if (bindCounter.get() == 0) { env.getEnv(GlobalEnv.class).GetDaemonManager().activateThread(null); StaticLayer.GetConvertor() .addShutdownHook( new Runnable() { @Override public void run() { synchronized (bindCounter) { bindCounter.set(0); } } }); } bindCounter.incrementAndGet(); } } return id; }