Merge remote-tracking branch 'refs/remotes/ReadyTalk/master' into avian-pack

This commit is contained in:
Ilya Mizus 2014-03-26 09:20:38 +03:00
commit 81c8fc20ab
15 changed files with 278 additions and 78 deletions

View File

@ -31,4 +31,24 @@ public class Cell <T> {
sb.append(")"); sb.append(")");
return sb.toString(); return sb.toString();
} }
public static <Car> Cell<Car> cons(Car car, Cell<Car> cdr) {
return new Cell(car, cdr);
}
public static <T> boolean equal(T a, T b) {
return (a == null && b == null) || (a != null && a.equals(b));
}
public static <Car> boolean equal(Cell<Car> a, Cell<Car> b) {
while (a != null) {
if (b == null || (! equal(a.value, b.value))) {
return false;
}
a = a.next;
b = b.next;
}
return b == null;
}
} }

View File

@ -120,19 +120,21 @@ import java.util.concurrent.Callable;
public class Continuations { public class Continuations {
private Continuations() { } private Continuations() { }
private static final ThreadLocal<Reset> latestReset = new ThreadLocal();
/** /**
* Captures the current continuation, passing a reference to the * Captures the current continuation, passing a reference to the
* specified receiver. * specified receiver.
* *
* <p>This method will either return the result returned by * <p>This method will either return the result returned by
* <code>receiver.receive(Callback)</code>, propagate the exception * <code>receiver.call(Callback)</code>, propagate the exception
* thrown by that method, return the result passed to the * thrown by that method, return the result passed to the
* handleResult(T) method of the continuation, or throw the * handleResult(T) method of the continuation, or throw the
* exception passed to the handleException(Throwable) method of the * exception passed to the handleException(Throwable) method of the
* continuation. * continuation.
*/ */
public static native <T> T callWithCurrentContinuation public static native <T> T callWithCurrentContinuation
(CallbackReceiver<T> receiver) throws Exception; (Function<Callback<T>,T> receiver) throws Exception;
/** /**
* Calls the specified "before" and "after" tasks each time a * Calls the specified "before" and "after" tasks each time a
@ -181,6 +183,83 @@ public class Continuations {
} }
} }
public static <B,C> C reset(final Callable<B> thunk) throws Exception {
final Reset reset = new Reset(latestReset.get());
latestReset.set(reset);
try {
Object result = callWithCurrentContinuation
(new Function<Callback<Object>,Object>() {
public Object call(Callback continuation) throws Exception {
reset.continuation = continuation;
return thunk.call();
}
});
while (true) {
Cell<Function> shift = reset.shifts;
if (shift != null) {
reset.shifts = shift.next;
result = shift.value.call(result);
} else {
return (C) result;
}
}
} finally {
latestReset.set(reset.next);
}
}
public static <A,B,C> A shift
(final Function<Function<A,B>,C> receiver)
throws Exception
{
return (A) callWithCurrentContinuation
(new Function<Callback<Object>,Object>() {
public Object call(final Callback continuation) {
final Reset reset = latestReset.get();
reset.shifts = new Cell(new Function() {
public Object call(Object ignored) throws Exception {
return receiver.call
(new Function() {
public Object call(final Object argument)
throws Exception
{
return callWithCurrentContinuation
(new Function<Callback<Object>,Object>() {
public Object call
(final Callback shiftContinuation)
throws Exception
{
reset.shifts = new Cell
(new Function() {
public Object call(Object result)
throws Exception
{
shiftContinuation.handleResult(result);
throw new AssertionError();
}
},
reset.shifts);
continuation.handleResult(argument);
throw new AssertionError();
}
});
}
});
}
public void handleException(Throwable exception) {
throw new AssertionError();
}
}, reset.shifts);
reset.continuation.handleResult(null);
throw new AssertionError();
}
});
}
private static native UnwindResult dynamicWind2(Runnable before, private static native UnwindResult dynamicWind2(Runnable before,
Callable thunk, Callable thunk,
Runnable after) Runnable after)
@ -235,4 +314,14 @@ public class Continuations {
this.exception = exception; this.exception = exception;
} }
} }
private static class Reset {
public Callback continuation;
public final Reset next;
public Cell<Function> shifts;
public Reset(Reset next) {
this.next = next;
}
}
} }

View File

@ -10,6 +10,6 @@
package avian; package avian;
public interface CallbackReceiver<T> { public interface Function<A,B> {
public T receive(Callback<T> callback) throws Exception; public B call(A argument) throws Exception;
} }

View File

@ -129,7 +129,7 @@ inline bool
exists(string_t path) exists(string_t path)
{ {
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
return GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES; return GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES;
#else #else
STRUCT_STAT s; STRUCT_STAT s;
return STAT(path, &s) == 0; return STAT(path, &s) == 0;

View File

@ -191,20 +191,21 @@ ifneq ($(android),)
crypto-native := $(android)/libcore/crypto/src/main/native crypto-native := $(android)/libcore/crypto/src/main/native
crypto-cpps := $(crypto-native)/org_conscrypt_NativeCrypto.cpp
ifeq ($(platform),windows) ifeq ($(platform),windows)
crypto-cpps := $(crypto-native)/org_conscrypt_NativeCrypto.cpp
android-cflags += -D__STDC_CONSTANT_MACROS android-cflags += -D__STDC_CONSTANT_MACROS
blacklist = $(luni-native)/java_io_Console.cpp \ blacklist = $(luni-native)/java_io_Console.cpp \
$(luni-native)/java_lang_ProcessManager.cpp \ $(luni-native)/java_lang_ProcessManager.cpp \
$(luni-native)/libcore_net_RawSocket.cpp $(luni-native)/libcore_net_RawSocket.cpp \
$(luni-native)/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp \
luni-cpps := $(filter-out $(blacklist),$(luni-cpps)) luni-cpps := $(filter-out $(blacklist),$(luni-cpps))
icu-libs := $(android)/external/icu4c/lib/sicuin.a \ icu-libs := $(android)/external/icu4c/lib/sicuin.a \
$(android)/external/icu4c/lib/sicuuc.a \ $(android)/external/icu4c/lib/sicuuc.a \
$(android)/external/icu4c/lib/sicudt.a $(android)/external/icu4c/lib/sicudt.a
platform-lflags := -lgdi32 platform-lflags := -lgdi32
else else
crypto-cpps := $(crypto-native)/org_conscrypt_NativeCrypto.cpp
android-cflags += -fPIC -DHAVE_SYS_UIO_H android-cflags += -fPIC -DHAVE_SYS_UIO_H
icu-libs := $(android)/external/icu4c/lib/libicui18n.a \ icu-libs := $(android)/external/icu4c/lib/libicui18n.a \
$(android)/external/icu4c/lib/libicuuc.a \ $(android)/external/icu4c/lib/libicuuc.a \
@ -230,8 +231,6 @@ ifneq ($(android),)
$(call cpp-objects,$(libnativehelper-cpps),$(libnativehelper-native),$(build)) $(call cpp-objects,$(libnativehelper-cpps),$(libnativehelper-native),$(build))
luni-java = $(android)/libcore/luni/src/main/java luni-java = $(android)/libcore/luni/src/main/java
luni-javas := $(shell find $(luni-java) -name '*.java') luni-javas := $(shell find $(luni-java) -name '*.java')
luni-nonjavas := $(shell find $(luni-java) -not -type d -not -name '*.java')
luni-copied-nonjavas = $(call noop-files,$(luni-nonjavas),$(luni-java),)
libdvm-java = $(android)/libcore/libdvm/src/main/java libdvm-java = $(android)/libcore/libdvm/src/main/java
libdvm-javas := $(shell find $(libdvm-java) -name '*.java') libdvm-javas := $(shell find $(libdvm-java) -name '*.java')
crypto-java = $(android)/libcore/crypto/src/main/java crypto-java = $(android)/libcore/crypto/src/main/java
@ -1096,7 +1095,6 @@ c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x)))
cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x))) cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x)))
asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.$(asm-format),$(3)/%-asm.o,$(x))) asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.$(asm-format),$(3)/%-asm.o,$(x)))
java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(3)/%.class,$(x))) java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(3)/%.class,$(x)))
noop-files = $(foreach x,$(1),$(patsubst $(2)/%,$(3)/%,$(x)))
generated-code = \ generated-code = \
$(build)/type-enums.cpp \ $(build)/type-enums.cpp \
@ -1332,13 +1330,14 @@ ifneq ($(classpath),avian)
$(classpath-src)/avian/AnnotationInvocationHandler.java \ $(classpath-src)/avian/AnnotationInvocationHandler.java \
$(classpath-src)/avian/Assembler.java \ $(classpath-src)/avian/Assembler.java \
$(classpath-src)/avian/Callback.java \ $(classpath-src)/avian/Callback.java \
$(classpath-src)/avian/CallbackReceiver.java \ $(classpath-src)/avian/Cell.java \
$(classpath-src)/avian/ClassAddendum.java \ $(classpath-src)/avian/ClassAddendum.java \
$(classpath-src)/avian/InnerClassReference.java \ $(classpath-src)/avian/InnerClassReference.java \
$(classpath-src)/avian/Classes.java \ $(classpath-src)/avian/Classes.java \
$(classpath-src)/avian/ConstantPool.java \ $(classpath-src)/avian/ConstantPool.java \
$(classpath-src)/avian/Continuations.java \ $(classpath-src)/avian/Continuations.java \
$(classpath-src)/avian/FieldAddendum.java \ $(classpath-src)/avian/FieldAddendum.java \
$(classpath-src)/avian/Function.java \
$(classpath-src)/avian/IncompatibleContinuationException.java \ $(classpath-src)/avian/IncompatibleContinuationException.java \
$(classpath-src)/avian/Machine.java \ $(classpath-src)/avian/Machine.java \
$(classpath-src)/avian/MethodAddendum.java \ $(classpath-src)/avian/MethodAddendum.java \
@ -1399,6 +1398,7 @@ unittest-depends = \
ifeq ($(continuations),true) ifeq ($(continuations),true)
continuation-tests = \ continuation-tests = \
extra.ComposableContinuations \
extra.Continuations \ extra.Continuations \
extra.Coroutines \ extra.Coroutines \
extra.DynamicWind extra.DynamicWind
@ -1573,7 +1573,7 @@ $(build)/%.o: $(build)/android-src/%.cpp $(build)/android.dep
$$($(windows-path) $(<)) $(call output,$(@)) $$($(windows-path) $(<)) $(call output,$(@))
$(build)/android.dep: $(luni-javas) $(libdvm-javas) $(crypto-javas) \ $(build)/android.dep: $(luni-javas) $(libdvm-javas) $(crypto-javas) \
$(dalvik-javas) $(xml-javas) $(luni-nonjavas) $(dalvik-javas) $(xml-javas)
@echo "compiling luni classes" @echo "compiling luni classes"
@mkdir -p $(classpath-build) @mkdir -p $(classpath-build)
@mkdir -p $(build)/android @mkdir -p $(build)/android
@ -1593,13 +1593,6 @@ $(build)/android.dep: $(luni-javas) $(libdvm-javas) $(crypto-javas) \
rm $(build)/android/sun/misc/Unsafe* \ rm $(build)/android/sun/misc/Unsafe* \
$(build)/android/java/lang/reflect/Proxy* $(build)/android/java/lang/reflect/Proxy*
cp -r $(build)/android/* $(classpath-build) cp -r $(build)/android/* $(classpath-build)
for x in $(luni-copied-nonjavas); \
do cp $(luni-java)$${x} $(classpath-build)$${x} ; \
done
# fix security.properties - get rid of "com.android" in front of classes starting with "org"
sed -i -e 's/\(.*=\)com\.android\.\(org\..*\)/\1\2/g' \
$(classpath-build)/java/security/security.properties
chmod +w $(classpath-build)/java/security/security.properties
@touch $(@) @touch $(@)
$(test-build)/%.class: $(test)/%.java $(test-build)/%.class: $(test)/%.java

View File

@ -11,10 +11,10 @@
#ifndef LZMA_UTIL_H #ifndef LZMA_UTIL_H
#define LZMA_UTIL_H #define LZMA_UTIL_H
#include "avian/lzma.h" #include <avian/lzma.h>
#include "C/Types.h" #include <C/Types.h>
#include <avian/system/system.h> #include <avian/system/system.h>
#include "avian/util/allocator.h" #include <avian/util/allocator.h>
namespace vm { namespace vm {
@ -22,13 +22,13 @@ const unsigned Padding = 16;
class LzmaAllocator { class LzmaAllocator {
public: public:
LzmaAllocator(Allocator* a): a(a) { LzmaAllocator(avian::util::Allocator* a): a(a) {
allocator.Alloc = allocate; allocator.Alloc = allocate;
allocator.Free = free; allocator.Free = free;
} }
ISzAlloc allocator; ISzAlloc allocator;
Allocator* a; avian::util::Allocator* a;
static void* allocate(void* allocator, size_t size) { static void* allocate(void* allocator, size_t size) {
uint8_t* p = static_cast<uint8_t*> uint8_t* p = static_cast<uint8_t*>

View File

@ -8044,8 +8044,8 @@ callWithCurrentContinuation(MyThread* t, object receiver)
if (root(t, ReceiveMethod) == 0) { if (root(t, ReceiveMethod) == 0) {
object m = resolveMethod object m = resolveMethod
(t, root(t, Machine::BootLoader), "avian/CallbackReceiver", "receive", (t, root(t, Machine::BootLoader), "avian/Function", "call",
"(Lavian/Callback;)Ljava/lang/Object;"); "(Ljava/lang/Object;)Ljava/lang/Object;");
if (m) { if (m) {
setRoot(t, ReceiveMethod, m); setRoot(t, ReceiveMethod, m);

View File

@ -29,7 +29,7 @@ read4(const uint8_t* in)
namespace vm { namespace vm {
uint8_t* uint8_t*
decodeLZMA(System* s, Allocator* a, uint8_t* in, unsigned inSize, decodeLZMA(System* s, avian::util::Allocator* a, uint8_t* in, unsigned inSize,
unsigned* outSize) unsigned* outSize)
{ {
const unsigned PropHeaderSize = 5; const unsigned PropHeaderSize = 5;

View File

@ -176,8 +176,6 @@
(type unwindResult avian/Continuations$UnwindResult) (type unwindResult avian/Continuations$UnwindResult)
(type callbackReceiver avian/CallbackReceiver)
(type string java/lang/String (type string java/lang/String
(alias data object value) (alias data object value)
(alias length uint32_t count) (alias length uint32_t count)

View File

@ -0,0 +1,93 @@
package extra;
import static avian.Continuations.shift;
import static avian.Cell.cons;
import static avian.Cell.equal;
import avian.Cell;
import avian.Function;
import avian.Continuations;
import java.util.concurrent.Callable;
public class ComposableContinuations {
private static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
public static void main(String[] args) throws Exception {
expect(2 * Continuations.<Integer,Integer>reset(new Callable<Integer>() {
public Integer call() throws Exception {
return 1 + shift
(new Function<Function<Integer,Integer>,Integer>() {
public Integer call(Function<Integer,Integer> continuation)
throws Exception
{
return continuation.call(5);
}
});
}
}) == 12);
expect(1 + Continuations.<Integer,Integer>reset(new Callable<Integer>() {
public Integer call() throws Exception {
return 2 * shift
(new Function<Function<Integer,Integer>,Integer>() {
public Integer call(Function<Integer,Integer> continuation)
throws Exception
{
return continuation.call(continuation.call(4));
}
});
}
}) == 17);
expect
(equal
(Continuations.<Cell<Integer>,Cell<Integer>>reset
(new Callable<Cell<Integer>>() {
public Cell<Integer> call() throws Exception {
shift(new Function<Function<Cell<Integer>,Cell<Integer>>,
Cell<Integer>>()
{
public Cell<Integer> call
(Function<Cell<Integer>,Cell<Integer>> continuation)
throws Exception
{
return cons(1, continuation.call(null));
}
});
shift(new Function<Function<Cell<Integer>,Cell<Integer>>,
Cell<Integer>>()
{
public Cell<Integer> call
(Function<Cell<Integer>,Cell<Integer>> continuation)
throws Exception
{
return cons(2, continuation.call(null));
}
});
return null;
}
}), cons(1, cons(2, null))));
expect
(equal
(Continuations.<String,Integer>reset
(new Callable<String>() {
public String call() throws Exception {
return new String
(shift(new Function<Function<byte[],String>,Integer>() {
public Integer call(Function<byte[],String> continuation)
throws Exception
{
return Integer.parseInt
(continuation.call(new byte[] { 0x34, 0x32 }));
}
}), "UTF-8");
}
}), 42));
}
}

View File

@ -2,7 +2,7 @@ package extra;
import static avian.Continuations.callWithCurrentContinuation; import static avian.Continuations.callWithCurrentContinuation;
import avian.CallbackReceiver; import avian.Function;
import avian.Callback; import avian.Callback;
public class Continuations { public class Continuations {
@ -11,22 +11,26 @@ public class Continuations {
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
expect(callWithCurrentContinuation(new CallbackReceiver<Integer>() { expect
public Integer receive(Callback<Integer> continuation) { (callWithCurrentContinuation
continuation.handleResult(42); (new Function<Callback<Integer>,Integer>() {
throw new AssertionError(); public Integer call(Callback<Integer> continuation) {
} continuation.handleResult(42);
}) == 42); throw new AssertionError();
}
}) == 42);
expect(callWithCurrentContinuation(new CallbackReceiver<Integer>() { expect
public Integer receive(Callback<Integer> continuation) { (callWithCurrentContinuation
return 43; (new Function<Callback<Integer>,Integer>() {
} public Integer call(Callback<Integer> continuation) {
}) == 43); return 43;
}
}) == 43);
try { try {
callWithCurrentContinuation(new CallbackReceiver<Integer>() { callWithCurrentContinuation(new Function<Callback<Integer>,Integer>() {
public Integer receive(Callback<Integer> continuation) { public Integer call(Callback<Integer> continuation) {
continuation.handleException(new MyException()); continuation.handleException(new MyException());
throw new AssertionError(); throw new AssertionError();
} }
@ -37,8 +41,8 @@ public class Continuations {
} }
try { try {
callWithCurrentContinuation(new CallbackReceiver<Integer>() { callWithCurrentContinuation(new Function<Callback<Integer>,Integer>() {
public Integer receive(Callback<Integer> continuation) public Integer call(Callback<Integer> continuation)
throws MyException throws MyException
{ {
throw new MyException(); throw new MyException();

View File

@ -2,7 +2,7 @@ package extra;
import static avian.Continuations.callWithCurrentContinuation; import static avian.Continuations.callWithCurrentContinuation;
import avian.CallbackReceiver; import avian.Function;
import avian.Callback; import avian.Callback;
public class Coroutines { public class Coroutines {
@ -40,8 +40,8 @@ public class Coroutines {
final Consumer<Character> consumer = new Consumer<Character>() { final Consumer<Character> consumer = new Consumer<Character>() {
public void consume(final Character c) throws Exception { public void consume(final Character c) throws Exception {
callWithCurrentContinuation(new CallbackReceiver() { callWithCurrentContinuation(new Function<Callback<Object>,Object>() {
public Object receive(Callback continuation) { public Object call(Callback continuation) {
state.produceNext = continuation; state.produceNext = continuation;
state.consumeNext.handleResult(c); state.consumeNext.handleResult(c);
@ -53,9 +53,9 @@ public class Coroutines {
}; };
final Producer<Character> producer = new Producer<Character>() { final Producer<Character> producer = new Producer<Character>() {
final CallbackReceiver<Character> receiver final Function<Callback<Character>,Character> receiver
= new CallbackReceiver<Character>() { = new Function<Callback<Character>,Character>() {
public Character receive(Callback<Character> continuation) public Character call(Callback<Character> continuation)
throws Exception throws Exception
{ {
state.consumeNext = continuation; state.consumeNext = continuation;

View File

@ -3,7 +3,7 @@ package extra;
import static avian.Continuations.callWithCurrentContinuation; import static avian.Continuations.callWithCurrentContinuation;
import static avian.Continuations.dynamicWind; import static avian.Continuations.dynamicWind;
import avian.CallbackReceiver; import avian.Function;
import avian.Callback; import avian.Callback;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@ -86,24 +86,27 @@ public class DynamicWind {
}); });
} }
private void continuationUnwindTest(final CallbackReceiver<Integer> receiver) private void continuationUnwindTest
(final Function<Callback<Integer>,Integer> receiver)
throws Exception throws Exception
{ {
System.out.println("continuationUnwindTest enter"); System.out.println("continuationUnwindTest enter");
try { try {
expect(callWithCurrentContinuation(new CallbackReceiver<Integer>() { expect
public Integer receive(final Callback<Integer> continuation) (callWithCurrentContinuation
throws Exception (new Function<Callback<Integer>,Integer>() {
{ public Integer call(final Callback<Integer> continuation)
unwindTest(new Callable<Integer>() { throws Exception
public Integer call() throws Exception { {
return receiver.receive(continuation); unwindTest(new Callable<Integer>() {
} public Integer call() throws Exception {
}); return receiver.call(continuation);
throw new AssertionError(); }
} });
}) == 42); throw new AssertionError();
}
}) == 42);
} catch (MyException e) { } catch (MyException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -118,8 +121,8 @@ public class DynamicWind {
} }
private void continuationResultUnwind() throws Exception { private void continuationResultUnwind() throws Exception {
continuationUnwindTest(new CallbackReceiver<Integer>() { continuationUnwindTest(new Function<Callback<Integer>,Integer>() {
public Integer receive(final Callback<Integer> continuation) { public Integer call(final Callback<Integer> continuation) {
continuation.handleResult(42); continuation.handleResult(42);
throw new AssertionError(); throw new AssertionError();
} }
@ -127,8 +130,8 @@ public class DynamicWind {
} }
private void continuationExceptionUnwind() throws Exception { private void continuationExceptionUnwind() throws Exception {
continuationUnwindTest(new CallbackReceiver<Integer>() { continuationUnwindTest(new Function<Callback<Integer>,Integer>() {
public Integer receive(final Callback<Integer> continuation) { public Integer call(final Callback<Integer> continuation) {
continuation.handleException(new MyException()); continuation.handleException(new MyException());
throw new AssertionError(); throw new AssertionError();
} }
@ -163,8 +166,8 @@ public class DynamicWind {
task = 1; task = 1;
return callWithCurrentContinuation return callWithCurrentContinuation
(new CallbackReceiver<Integer>() { (new Function<Callback<Integer>,Integer>() {
public Integer receive(final Callback<Integer> continuation) public Integer call(final Callback<Integer> continuation)
throws Exception throws Exception
{ {
continuationReference = continuation; continuationReference = continuation;

View File

@ -18,7 +18,7 @@ fi
echo -n "" >${log} echo -n "" >${log}
printf "%12s------- Unit tests -------\n" "" printf "%20s------- Unit tests -------\n" ""
${unit_tester} 2>>${log} ${unit_tester} 2>>${log}
if [ "${?}" != "0" ]; then if [ "${?}" != "0" ]; then
trouble=1 trouble=1
@ -27,9 +27,9 @@ fi
echo echo
printf "%12s------- Java tests -------\n" "" printf "%20s------- Java tests -------\n" ""
for test in ${tests}; do for test in ${tests}; do
printf "%24s: " "${test}" printf "%32s: " "${test}"
case ${mode} in case ${mode} in
debug|debug-fast|fast|small ) debug|debug-fast|fast|small )

View File

@ -32,7 +32,7 @@ Test::Test(const char* name):
bool Test::runAll() { bool Test::runAll() {
int failures = 0; int failures = 0;
for(Test* t = Test::first; t; t = t->next) { for(Test* t = Test::first; t; t = t->next) {
printf("%24s: ", t->name); printf("%32s: ", t->name);
t->run(); t->run();
failures += t->failures; failures += t->failures;
if(t->failures > 0) { if(t->failures > 0) {
@ -49,4 +49,4 @@ int main(int argc UNUSED, char** argv UNUSED) {
return 0; return 0;
} }
return 1; return 1;
} }