Skip to content

Commit

Permalink
Added call_proc_array, fixed cmdline msg, and console msg.
Browse files Browse the repository at this point in the history
call_proc_array allows for a dynamic number of arguments to be passed
to a proc, instead of just the name being dynamic. msg() now works
from a cmdline script, and using msg when running a console command
supports colors.
  • Loading branch information
LadyCailin committed Jan 24, 2013
1 parent 4a01cb4 commit dfcf827
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 31 deletions.
1 change: 1 addition & 0 deletions nb-configuration.xml
Expand Up @@ -22,5 +22,6 @@ Any value defined here will override the pom.xml file value but is only applicab
<org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>false</org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>
<org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>
<org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>
<netbeans.hint.jdkPlatform>JDK_1.6</netbeans.hint.jdkPlatform>
</properties>
</project-shared-configuration>
8 changes: 6 additions & 2 deletions src/main/java/com/laytonsmith/core/Static.java
Expand Up @@ -516,8 +516,12 @@ public static void SendMessage(final MCCommandSender m, String msg, final Target
}
p.sendMessage(line);
} else {
if (m != null) {
m.sendMessage(line);
if (m != null && m instanceof MCConsoleCommandSender) {
if(msg.matches("(?m).*\033.*")){
//We have terminal colors, we need to reset them at the end
msg += TermColors.reset();
}
com.laytonsmith.core.Static.getLogger().log(Level.INFO, msg);
} else {
System.out.println(line);
}
Expand Down
Expand Up @@ -38,6 +38,10 @@ public final <T extends EnvironmentImpl> T getEnv(Class<T> clazz){
private void addEnv(EnvironmentImpl mixin){
environments.put(mixin.getClass(), mixin);
}

public boolean hasEnv(Class<? extends EnvironmentImpl> clazz) {
return environments.containsKey(clazz);
}

@Override
public Environment clone() throws CloneNotSupportedException {
Expand Down
85 changes: 68 additions & 17 deletions src/main/java/com/laytonsmith/core/functions/DataHandling.java
Expand Up @@ -1805,7 +1805,7 @@ public Construct optimize(Target t, Construct... args) throws ConfigCompileExcep
}

@api
public static class call_proc extends AbstractFunction {
public static class call_proc extends AbstractFunction implements Optimizable {

public String getName() {
return "call_proc";
Expand All @@ -1817,8 +1817,10 @@ public Integer[] numArgs() {

public String docs() {
return "mixed {proc_name, [var1...]} Dynamically calls a user defined procedure. call_proc(_myProc, 'var1') is the equivalent of"
+ " _myProc('var1'), except you could dynamically build the procedure name if need be. This is useful for having callbacks"
+ " in procedures. Throws an InvalidProcedureException if the procedure isn't defined.";
+ " _myProc('var1'), except you could dynamically build the procedure name if need be. This is useful for dynamic coding,"
+ " however, closures work best for callbacks. Throws an InvalidProcedureException if the procedure isn't defined. If you are"
+ " hardcoding the first parameter, a warning will be issued, because it is much more efficient and safe to directly use"
+ " a procedure if you know what its name is beforehand.";
}

public ExceptionType[] thrown() {
Expand All @@ -1838,19 +1840,9 @@ public Boolean runAsync() {
}

public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException {
return new CVoid(t);
}

@Override
public Construct execs(Target t, Environment env, Script parent, ParseTree... nodes) {
if (nodes.length < 1) {
throw new ConfigRuntimeException("Expecting at least one argument to call_proc", ExceptionType.InsufficientArgumentsException, t);
}
Construct[] args = new Construct[nodes.length];
for (int i = 0; i < nodes.length; i++) {
args[i] = parent.seval(nodes[i], env);
if (args.length < 1) {
throw new ConfigRuntimeException("Expecting at least one argument to " + getName(), ExceptionType.InsufficientArgumentsException, t);
}

Procedure proc = env.getEnv(GlobalEnv.class).GetProcs().get(args[0].val());
if (proc != null) {
List<Construct> vars = new ArrayList<Construct>(Arrays.asList(args));
Expand All @@ -1867,10 +1859,69 @@ public Construct execs(Target t, Environment env, Script parent, ParseTree... no
ExceptionType.InvalidProcedureException, t);
}

public Set<OptimizationOption> optimizationOptions() {
return EnumSet.of(OptimizationOption.OPTIMIZE_DYNAMIC);
}

@Override
public boolean useSpecialExec() {
return true;
public ParseTree optimizeDynamic(Target t, List<ParseTree> children) throws ConfigCompileException, ConfigRuntimeException {
if(children.size() < 1){
throw new ConfigRuntimeException("Expecting at least one argument to " + getName(), ExceptionType.InsufficientArgumentsException, t);
}
if(children.get(0).isConst()){
CHLog.GetLogger().Log(CHLog.Tags.COMPILER, LogLevel.WARNING, "Hardcoding procedure name in " + getName() + ", which is inefficient."
+ " Consider calling the procedure directly if the procedure name is known at compile time.", t);
}
return null;
}

}

@api
public static class call_proc_array extends call_proc {

@Override
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
CArray ca = Static.getArray(args[1], t);
if(ca.inAssociativeMode()){
throw new Exceptions.CastException("Expected the array passed to " + getName() + " to be non-associative.", t);
}
Construct [] args2 = new Construct[(int)ca.size() + 1];
args2[0] = args[0];
for(int i = 1; i < args2.length; i++){
args2[i] = ca.get(i - 1);
}
return super.exec(t, environment, args2);
}

@Override
public String getName() {
return "call_proc_array";
}

@Override
public Integer[] numArgs() {
return new Integer[]{2};
}

@Override
public String docs() {
return "mixed {proc_name, array} Works like call_proc, but allows for variable or unknown number of arguments to be passed to"
+ " a proc. The array parameter is \"flattened\", and call_proc is essentially called. If the array is associative, an"
+ " exception is thrown.";
}

@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}

@Override
public ParseTree optimizeDynamic(Target t, List<ParseTree> children) throws ConfigCompileException, ConfigRuntimeException {
//If they hardcode the name, that's fine, because the variables may just be the only thing that's variable.
return null;
}

}

@api(environments=CommandHelperEnvironment.class)
Expand Down
19 changes: 9 additions & 10 deletions src/main/java/com/laytonsmith/core/functions/Echoes.java
Expand Up @@ -87,7 +87,9 @@ public Set<OptimizationOption> optimizationOptions() {
}
}

@api(environments={CommandHelperEnvironment.class})
//Technically it needs CommandHelperEnvironment, but we have special exception handling in case we're running
//in cmdline mode.
@api(environments={})
@noboilerplate
public static class msg extends AbstractFunction{

Expand All @@ -100,19 +102,16 @@ public Integer[] numArgs() {
}

public Construct exec(final Target t, Environment env, final Construct... args) throws CancelCommandException, ConfigRuntimeException {
final MCCommandSender p = env.getEnv(CommandHelperEnvironment.class).GetCommandSender();
StringBuilder b = new StringBuilder();
for(int i = 0; i < args.length; i++){
b.append(args[i].val());
}
Static.SendMessage(p, b.toString(), t);
// int start = 0;
// String s = b.toString();
// while(true){
// if(start >= s.length()) break;
// p.sendMessage(s.substring(start, start + 100 >= s.length()?s.length():start + 100));
// start += 100;
// }
if(env.hasEnv(CommandHelperEnvironment.class)){
final MCCommandSender p = env.getEnv(CommandHelperEnvironment.class).GetCommandSender();
Static.SendMessage(p, b.toString(), t);
} else {
System.out.println(Static.MCToANSIColors(b.toString()));
}
return new CVoid(t);
}

Expand Down
19 changes: 17 additions & 2 deletions src/main/resources/docs/Persistance_Network
Expand Up @@ -48,9 +48,14 @@ A note on file based URIs: The file path is specified after two forward slashes,
path on unix looks like this: yml:///path/to/file, and an absolute path on windows looks like
this: yml://C:/path/to/file (alternatively yml://C:\path\to\file will also work). On all
platforms, a relative path would look like this: yml://path/to/file. Additionally, file based
connections are '''always''' going to be much slower, and much less reliable than SQL based
connections are '''usually''' going to be much faster, but less reliable than SQL based
connections, so it is HIGHLY recommended that you use SQL connections, if nothing else, using
the zero config SQLite (which is the default).
the zero config SQLite (which is the default). The only case for a file based connection type is
when using frequently read/written data, in which case a subset of your keys may be written
out to a file based protocol. The <code>ser</code> protocol is the fastest and most compact,
but as it stores the data in a lump binary form, it is not (easily) editable by hand, and
is prone to total data corruption in the event of any section of the file being corrupted.
For a full rundown of the speed comparisons, see the chart below.

There are special implementation considerations you must take into account if you are writing
an external system that integrates with the persistance network, (including if you edit the
Expand Down Expand Up @@ -237,4 +242,14 @@ ser | 16 ms | 23 ms | 83 ms | 114 ms | 164 K
yml | 33 ms | 14 ms | 2.105 sec | 46.640 sec | 112 K
-------+---------------------------------------------------------------------------------
</pre>

An important observation that could be made based on this data is that SQLite is
considerably slower than any of the other protocols. This is because SQLite
is less prone to data corruption, and is multiprocess safe. SQLite manages its own
locking and journaling systems, so it is unlikely to corrupt if a bad write
occurs, or if multiple processes are accessing it at once. Due to this, it is the
default storage mechanism, despite its slower runtime. The tradeoff of data protection
vs. script speed vs. interoperability is not something that can be generically decided
in all cases though, so feel free to change defaults as you see fit. Each protocol
has pros and cons, so you must decide which one to use.
{{LearningTrail}}
Expand Up @@ -276,6 +276,7 @@ public void testInclude() throws ConfigCompileException, IOException {
verify(fakePlayer).sendMessage("hello");
//delete the test file
test.delete();
test.deleteOnExit();
}

@Test(timeout = 10000)
Expand Down

0 comments on commit dfcf827

Please sign in to comment.