scarpet corountines idea
This commit is contained in:
1 parent
23ed35a398
commit
146573803c
11 files changed
+284
-17
No files matched your search
@@ -866,7 +866,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
assertAppIntegrity(function.getModule());
|
assertAppIntegrity(function.getModule());
|
||||||
Context context = new CarpetContext(this, source);
|
Context context = new CarpetContext(this, source);
|
||||||
return function.getExpression().evalValue(
|
return function.getExpression().evalValue(
|
||||||
() -> function.execute(context, Context.VOID, function.getExpression(), function.getToken(), argv),
|
() -> function.execute(context, Context.VOID, function.getExpression(), function.getToken(), argv, null),
|
||||||
context,
|
context,
|
||||||
Context.VOID
|
Context.VOID
|
||||||
);
|
);
|
||||||
@@ -903,7 +903,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
assertAppIntegrity(fun.getModule());
|
assertAppIntegrity(fun.getModule());
|
||||||
Context context = new CarpetContext(this, source, origin);
|
Context context = new CarpetContext(this, source, origin);
|
||||||
return fun.getExpression().evalValue(
|
return fun.getExpression().evalValue(
|
||||||
() -> fun.execute(context, Context.VOID, fun.getExpression(), fun.getToken(), argv),
|
() -> fun.execute(context, Context.VOID, fun.getExpression(), fun.getToken(), argv, null),
|
||||||
context,
|
context,
|
||||||
Context.VOID);
|
Context.VOID);
|
||||||
}
|
}
|
||||||
@@ -1215,4 +1215,10 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSynchronouslyExecute()
|
||||||
|
{
|
||||||
|
return !scriptServer().server.isSameThread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package carpet.script;
|
package carpet.script;
|
||||||
|
|
||||||
import carpet.script.exception.InternalExpressionException;
|
import carpet.script.exception.InternalExpressionException;
|
||||||
|
import carpet.script.value.ThreadValue;
|
||||||
import carpet.script.value.Value;
|
import carpet.script.value.Value;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -30,6 +31,8 @@ public class Context
|
|||||||
|
|
||||||
public final ScriptHost host;
|
public final ScriptHost host;
|
||||||
|
|
||||||
|
private ThreadValue threadContext = null;
|
||||||
|
|
||||||
public Context(ScriptHost host)
|
public Context(ScriptHost host)
|
||||||
{
|
{
|
||||||
this.host = host;
|
this.host = host;
|
||||||
@@ -69,10 +72,21 @@ public class Context
|
|||||||
public Context recreate()
|
public Context recreate()
|
||||||
{
|
{
|
||||||
Context ctx = duplicate();
|
Context ctx = duplicate();
|
||||||
|
ctx.threadContext = threadContext;
|
||||||
ctx.initialize();
|
ctx.initialize();
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setThreadContext(ThreadValue callingThread)
|
||||||
|
{
|
||||||
|
this.threadContext = callingThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThreadValue getThreadContext()
|
||||||
|
{
|
||||||
|
return threadContext;
|
||||||
|
}
|
||||||
|
|
||||||
protected void initialize()
|
protected void initialize()
|
||||||
{
|
{
|
||||||
//special variables for second order functions so we don't need to check them all the time
|
//special variables for second order functions so we don't need to check them all the time
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ public abstract class ScriptHost
|
|||||||
return scriptServer.resolveResource(suffix);
|
return scriptServer.resolveResource(suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canSynchronouslyExecute()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static class ModuleData
|
public static class ModuleData
|
||||||
{
|
{
|
||||||
Module parent;
|
Module parent;
|
||||||
|
|||||||
@@ -143,6 +143,9 @@ public class Loops
|
|||||||
for (int i = 0; iterator.hasNext(); i++)
|
for (int i = 0; iterator.hasNext(); i++)
|
||||||
{
|
{
|
||||||
Value next = iterator.next();
|
Value next = iterator.next();
|
||||||
|
if(next == Value.EOL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String variable = next.boundVariable;
|
String variable = next.boundVariable;
|
||||||
next.bindTo("_");
|
next.bindTo("_");
|
||||||
int doYouReally = i;
|
int doYouReally = i;
|
||||||
@@ -197,6 +200,9 @@ public class Loops
|
|||||||
for (int i = 0; iterator.hasNext(); i++)
|
for (int i = 0; iterator.hasNext(); i++)
|
||||||
{
|
{
|
||||||
Value next = iterator.next();
|
Value next = iterator.next();
|
||||||
|
if(next == Value.EOL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String veriable = next.boundVariable;
|
String veriable = next.boundVariable;
|
||||||
next.bindTo("_");
|
next.bindTo("_");
|
||||||
int seriously = i;
|
int seriously = i;
|
||||||
@@ -254,6 +260,9 @@ public class Loops
|
|||||||
for (int i = 0; iterator.hasNext(); i++)
|
for (int i = 0; iterator.hasNext(); i++)
|
||||||
{
|
{
|
||||||
Value next = iterator.next();
|
Value next = iterator.next();
|
||||||
|
if(next == Value.EOL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String variable = next.boundVariable;
|
String variable = next.boundVariable;
|
||||||
next.bindTo("_");
|
next.bindTo("_");
|
||||||
int seriously = i;
|
int seriously = i;
|
||||||
@@ -311,6 +320,9 @@ public class Loops
|
|||||||
for (int i = 0; iterator.hasNext(); i++)
|
for (int i = 0; iterator.hasNext(); i++)
|
||||||
{
|
{
|
||||||
Value next = iterator.next();
|
Value next = iterator.next();
|
||||||
|
if(next == Value.EOL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String variable = next.boundVariable;
|
String variable = next.boundVariable;
|
||||||
next.bindTo("_");
|
next.bindTo("_");
|
||||||
int seriously = i;
|
int seriously = i;
|
||||||
@@ -381,6 +393,9 @@ public class Loops
|
|||||||
for (int i = 0; iterator.hasNext(); i++)
|
for (int i = 0; iterator.hasNext(); i++)
|
||||||
{
|
{
|
||||||
Value next = iterator.next();
|
Value next = iterator.next();
|
||||||
|
if(next == Value.EOL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String variable = next.boundVariable;
|
String variable = next.boundVariable;
|
||||||
next.bindTo("_");
|
next.bindTo("_");
|
||||||
int seriously = i;
|
int seriously = i;
|
||||||
@@ -452,6 +467,9 @@ public class Loops
|
|||||||
for (int i = 0; iterator.hasNext(); i++)
|
for (int i = 0; iterator.hasNext(); i++)
|
||||||
{
|
{
|
||||||
Value next = iterator.next();
|
Value next = iterator.next();
|
||||||
|
if(next == Value.EOL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String variable = next.boundVariable;
|
String variable = next.boundVariable;
|
||||||
next.bindTo("_");
|
next.bindTo("_");
|
||||||
Value promiseWontChangeYou = acc;
|
Value promiseWontChangeYou = acc;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package carpet.script.language;
|
package carpet.script.language;
|
||||||
|
|
||||||
|
import carpet.script.Context;
|
||||||
import carpet.script.Expression;
|
import carpet.script.Expression;
|
||||||
import carpet.script.argument.FunctionArgument;
|
import carpet.script.argument.FunctionArgument;
|
||||||
import carpet.script.exception.ExitStatement;
|
import carpet.script.exception.ExitStatement;
|
||||||
@@ -128,5 +129,63 @@ public class Threading
|
|||||||
}
|
}
|
||||||
return (cc, tt) -> new NumericValue(time); // pass through for variables
|
return (cc, tt) -> new NumericValue(time); // pass through for variables
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expression.addLazyFunction("yield", (c, t, lv) ->
|
||||||
|
{
|
||||||
|
if (c.getThreadContext() == null)
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("'yield' can only be used in a task");
|
||||||
|
}
|
||||||
|
if (lv.isEmpty())
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("'yield' requires at least one argument");
|
||||||
|
}
|
||||||
|
boolean lock = lv.size() > 1 && lv.get(1).evalValue(c, Context.BOOLEAN).getBoolean();
|
||||||
|
Value value = lv.get(0).evalValue(c);
|
||||||
|
Value ret = c.getThreadContext().ping(value, lock);
|
||||||
|
return (cc, tt) -> ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
expression.addLazyFunction("task_send", 2, (c, t, lv) ->
|
||||||
|
{
|
||||||
|
Value threadValue = lv.get(0).evalValue(c);
|
||||||
|
if (!(threadValue instanceof ThreadValue thread))
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("'task_next' requires a task value");
|
||||||
|
}
|
||||||
|
if (!thread.isCoroutine)
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("'task_next' requires a coroutine task value");
|
||||||
|
}
|
||||||
|
Value ret = lv.get(1).evalValue(c);
|
||||||
|
thread.send(ret);
|
||||||
|
return (cc, tt) -> Value.NULL;
|
||||||
|
});
|
||||||
|
|
||||||
|
expression.addLazyFunction("task_await", 1, (c, t, lv) ->
|
||||||
|
{
|
||||||
|
Value threadValue = lv.get(0).evalValue(c);
|
||||||
|
if (!(threadValue instanceof ThreadValue thread))
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("'task_await' requires a task value");
|
||||||
|
}
|
||||||
|
if (!thread.isCoroutine)
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("'task_await' requires a coroutine task value");
|
||||||
|
}
|
||||||
|
Value ret = thread.next();
|
||||||
|
return ret == Value.EOL ? ((cc, tt) -> Value.NULL) : ((cc, tt) -> ret);
|
||||||
|
});
|
||||||
|
|
||||||
|
expression.addLazyFunction("task_ready", 1, (c, t, lv) ->
|
||||||
|
{
|
||||||
|
Value threadValue = lv.get(0).evalValue(c);
|
||||||
|
if (!(threadValue instanceof ThreadValue thread))
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("'task_ready' requires a task value");
|
||||||
|
}
|
||||||
|
boolean ret = thread.isCoroutine && thread.hasNext();
|
||||||
|
return (cc, tt) -> BooleanValue.of(ret);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,13 +3,21 @@ package carpet.script.value;
|
|||||||
import carpet.script.exception.InternalExpressionException;
|
import carpet.script.exception.InternalExpressionException;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class AbstractListValue extends Value implements Iterable<Value>
|
public abstract class AbstractListValue extends Value implements Iterable<Value>
|
||||||
{
|
{
|
||||||
public List<Value> unpack()
|
public List<Value> unpack()
|
||||||
{
|
{
|
||||||
List<Value> retVal = Lists.newArrayList(iterator());
|
ArrayList<Value> retVal = Lists.newArrayList();
|
||||||
|
for (Value value : this)
|
||||||
|
{
|
||||||
|
if (value != Value.EOL)
|
||||||
|
{
|
||||||
|
retVal.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
fatality();
|
fatality();
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import java.util.function.Consumer;
|
|||||||
import net.minecraft.nbt.StringTag;
|
import net.minecraft.nbt.StringTag;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class FunctionValue extends Value implements Fluff.ILazyFunction
|
public class FunctionValue extends Value implements Fluff.ILazyFunction
|
||||||
{
|
{
|
||||||
private final Expression expression;
|
private final Expression expression;
|
||||||
@@ -158,7 +160,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return execute(c, type, expression, token, params);
|
return execute(c, type, expression, token, params, null);
|
||||||
}
|
}
|
||||||
catch (ExpressionException exc)
|
catch (ExpressionException exc)
|
||||||
{
|
{
|
||||||
@@ -214,10 +216,10 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
public LazyValue lazyEval(Context c, Context.Type type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
|
public LazyValue lazyEval(Context c, Context.Type type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
|
||||||
{
|
{
|
||||||
List<Value> resolvedParams = unpackArgs(lazyParams, c);
|
List<Value> resolvedParams = unpackArgs(lazyParams, c);
|
||||||
return execute(c, type, e, t, resolvedParams);
|
return execute(c, type, e, t, resolvedParams, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LazyValue execute(Context c, Context.Type type, Expression e, Tokenizer.Token t, List<Value> params)
|
public LazyValue execute(Context c, Context.Type type, Expression e, Tokenizer.Token t, List<Value> params, @Nullable ThreadValue freshNewCallingThread)
|
||||||
{
|
{
|
||||||
assertArgsOk(params, fixedArgs -> {
|
assertArgsOk(params, fixedArgs -> {
|
||||||
if (fixedArgs) // wrong number of args for fixed args
|
if (fixedArgs) // wrong number of args for fixed args
|
||||||
@@ -237,6 +239,10 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
Context newFrame = c.recreate();
|
Context newFrame = c.recreate();
|
||||||
|
if (freshNewCallingThread != null)
|
||||||
|
{
|
||||||
|
newFrame.setThreadContext(freshNewCallingThread);
|
||||||
|
}
|
||||||
|
|
||||||
if (outerState != null)
|
if (outerState != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -137,7 +137,12 @@ public abstract class LazyListValue extends AbstractListValue implements Iterato
|
|||||||
public List<Value> unroll()
|
public List<Value> unroll()
|
||||||
{
|
{
|
||||||
List<Value> result = new ArrayList<>();
|
List<Value> result = new ArrayList<>();
|
||||||
this.forEachRemaining(result::add);
|
this.forEachRemaining(v -> {
|
||||||
|
if (v != Value.EOL)
|
||||||
|
{
|
||||||
|
result.add(v);
|
||||||
|
}
|
||||||
|
});
|
||||||
fatality();
|
fatality();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,34 +7,39 @@ import carpet.script.exception.ExitStatement;
|
|||||||
import carpet.script.exception.ExpressionException;
|
import carpet.script.exception.ExpressionException;
|
||||||
import carpet.script.exception.InternalExpressionException;
|
import carpet.script.exception.InternalExpressionException;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
|
||||||
public class ThreadValue extends Value
|
public class ThreadValue extends LazyListValue
|
||||||
{
|
{
|
||||||
private final CompletableFuture<Value> taskFuture;
|
private final CompletableFuture<Value> taskFuture;
|
||||||
private final long id;
|
private final long id;
|
||||||
private static long sequence = 0L;
|
private static long sequence = 0L;
|
||||||
|
private final Deque<Value> coState = new ArrayDeque<>();
|
||||||
public ThreadValue(CompletableFuture<Value> taskFuture)
|
private final AtomicReference<Value> coLock = new AtomicReference<>(Value.EOL);
|
||||||
{
|
public final boolean isCoroutine;
|
||||||
this.taskFuture = taskFuture;
|
|
||||||
this.id = sequence++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
|
public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
|
||||||
{
|
{
|
||||||
this(getCompletableFutureFromFunction(pool, function, expr, token, ctx, args));
|
this.id = sequence++;
|
||||||
|
this.isCoroutine = ctx.host.canSynchronouslyExecute();
|
||||||
|
this.taskFuture = getCompletableFutureFromFunction(pool, function, expr, token, ctx, args);
|
||||||
|
|
||||||
Thread.yield();
|
Thread.yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompletableFuture<Value> getCompletableFutureFromFunction(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
|
public CompletableFuture<Value> getCompletableFutureFromFunction(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List<Value> args)
|
||||||
{
|
{
|
||||||
ExecutorService executor = ctx.host.getExecutor(pool);
|
ExecutorService executor = ctx.host.getExecutor(pool);
|
||||||
|
ThreadValue callingThread = isCoroutine ? this : null;
|
||||||
if (executor == null)
|
if (executor == null)
|
||||||
{
|
{
|
||||||
// app is shutting down - no more threads can be spawned.
|
// app is shutting down - no more threads can be spawned.
|
||||||
@@ -45,7 +50,7 @@ public class ThreadValue extends Value
|
|||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return function.execute(ctx, Context.NONE, expr, token, args).evalValue(ctx);
|
return function.execute(ctx, Context.NONE, expr, token, args, callingThread).evalValue(ctx);
|
||||||
}
|
}
|
||||||
catch (ExitStatement exit)
|
catch (ExitStatement exit)
|
||||||
{
|
{
|
||||||
@@ -137,4 +142,143 @@ public class ThreadValue extends Value
|
|||||||
{
|
{
|
||||||
return "task";
|
return "task";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fatality()
|
||||||
|
{
|
||||||
|
// we signal that won't be interested in the co-thread anymore
|
||||||
|
// but threads run client code, so we can't just kill them
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset()
|
||||||
|
{
|
||||||
|
//throw new InternalExpressionException("Illegal operation on a task");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Value> iterator()
|
||||||
|
{
|
||||||
|
if (!isCoroutine)
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("Cannot iterate over this task");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext()
|
||||||
|
{
|
||||||
|
return !(coState.isEmpty() && taskFuture.isDone());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value next()
|
||||||
|
{
|
||||||
|
Value popped = null;
|
||||||
|
synchronized (coState)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (!coState.isEmpty())
|
||||||
|
{
|
||||||
|
popped = coState.pop();
|
||||||
|
}
|
||||||
|
else if (taskFuture.isDone())
|
||||||
|
{
|
||||||
|
popped = Value.EOL;
|
||||||
|
}
|
||||||
|
if (popped != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
coState.wait(1);
|
||||||
|
}
|
||||||
|
catch (InterruptedException ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
coState.notifyAll();
|
||||||
|
}
|
||||||
|
return popped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(Value value)
|
||||||
|
{
|
||||||
|
synchronized (coLock)
|
||||||
|
{
|
||||||
|
coLock.set(value);
|
||||||
|
coLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value ping(Value value, boolean lock)
|
||||||
|
{
|
||||||
|
synchronized (coState)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!lock)
|
||||||
|
{
|
||||||
|
coState.add(value);
|
||||||
|
return Value.NULL;
|
||||||
|
}
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (coState.isEmpty())
|
||||||
|
{
|
||||||
|
coState.add(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
coState.wait(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (InterruptedException ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
coState.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// locked mode
|
||||||
|
|
||||||
|
synchronized (coLock)
|
||||||
|
{
|
||||||
|
Value ret;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Value current = coLock.get();
|
||||||
|
if (current != Value.EOL)
|
||||||
|
{
|
||||||
|
ret = current;
|
||||||
|
coLock.set(Value.EOL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
coLock.wait(1);
|
||||||
|
}
|
||||||
|
catch (InterruptedException ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
coLock.notifyAll();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import net.minecraft.nbt.Tag;
|
|||||||
public class UndefValue extends NullValue
|
public class UndefValue extends NullValue
|
||||||
{
|
{
|
||||||
public static final UndefValue UNDEF = new UndefValue();
|
public static final UndefValue UNDEF = new UndefValue();
|
||||||
|
public static final UndefValue EOL = new UndefValue();
|
||||||
|
|
||||||
private RuntimeException getError()
|
private RuntimeException getError()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public abstract class Value implements Comparable<Value>, Cloneable
|
|||||||
|
|
||||||
public static final NullValue NULL = NullValue.NULL;
|
public static final NullValue NULL = NullValue.NULL;
|
||||||
public static final UndefValue UNDEF = UndefValue.UNDEF;
|
public static final UndefValue UNDEF = UndefValue.UNDEF;
|
||||||
|
public static final UndefValue EOL = UndefValue.EOL;
|
||||||
|
|
||||||
public String boundVariable;
|
public String boundVariable;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user