diff --git a/.travis.yml b/.travis.yml index 3c2656d5..938b01f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,13 @@ language: c +os: + - osx + - linux compiler: - gcc - clang +env: + - WREN_OPTIONS="" CI_ARCHS="ci_32 ci_64" + - WREN_OPTIONS="-DWREN_NAN_TAGGING=0" CI_ARCHS="ci_64" # Travis VMs are 64-bit but we compile both for 32 and 64 bit. To enable the # 32-bit builds to work, we need gcc-multilib. addons: @@ -10,4 +16,4 @@ addons: - gcc-multilib - g++-multilib sudo: false # Enable container-based builds. -script: make all && make test +script: make WREN_CFLAGS=${WREN_OPTIONS} ${CI_ARCHS} diff --git a/Makefile b/Makefile index f8bdb84b..c2347b99 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,28 @@ all: debug release $(V) $(MAKE) -f util/wren.mk MODE=debug ARCH=64 $(V) $(MAKE) -f util/wren.mk MODE=debug LANG=cpp ARCH=64 +ci: ci_32 ci_64 + +ci_32: + $(V) $(MAKE) -f util/wren.mk MODE=debug LANG=c ARCH=32 vm cli test + $(V) ./util/test.py --suffix=d-32 $(suite) + $(V) $(MAKE) -f util/wren.mk MODE=debug LANG=cpp ARCH=32 vm cli test + $(V) ./util/test.py --suffix=d-cpp-32 $(suite) + $(V) $(MAKE) -f util/wren.mk MODE=release LANG=c ARCH=32 vm cli test + $(V) ./util/test.py --suffix=-32 $(suite) + $(V) $(MAKE) -f util/wren.mk MODE=release LANG=cpp ARCH=32 vm cli test + $(V) ./util/test.py --suffix=-cpp-32 $(suite) + +ci_64: + $(V) $(MAKE) -f util/wren.mk MODE=debug LANG=c ARCH=64 vm cli test + $(V) ./util/test.py --suffix=d-64 $(suite) + $(V) $(MAKE) -f util/wren.mk MODE=debug LANG=cpp ARCH=64 vm cli test + $(V) ./util/test.py --suffix=d-cpp-64 $(suite) + $(V) $(MAKE) -f util/wren.mk MODE=release LANG=c ARCH=64 vm cli test + $(V) ./util/test.py --suffix=-64 $(suite) + $(V) $(MAKE) -f util/wren.mk MODE=release LANG=cpp ARCH=64 vm cli test + $(V) ./util/test.py --suffix=-cpp-64 $(suite) + # Remove all build outputs and intermediate files. Does not remove downloaded # dependencies. Use cleanall for that. clean: @@ -80,4 +102,4 @@ gh-pages: docs amalgamation: src/include/wren.h src/vm/*.h src/vm/*.c ./util/generate_amalgamation.py > build/wren.c -.PHONY: all amalgamation builtin clean debug docs gh-pages release test vm watchdocs +.PHONY: all amalgamation builtin clean debug docs gh-pages release test vm watchdocs ci ci_32 ci_64 diff --git a/example/syntax.wren b/example/syntax.wren index bb60e35b..8e2f5d54 100644 --- a/example/syntax.wren +++ b/example/syntax.wren @@ -129,8 +129,10 @@ class Literals is SyntaxExample { 3.14159 1.0 -12.34 - 0xdeadbeef - 0x1234567890ABCDEF + 0x1000000 +// Literals larger than 0x1000000 are only valid in 64 bit builds +// 0xdeadbeef +// 0x1234567890ABCDEF } strings { diff --git a/src/vm/wren_core.c b/src/vm/wren_core.c index 5f1a2007..b1044a9c 100644 --- a/src/vm/wren_core.c +++ b/src/vm/wren_core.c @@ -618,7 +618,9 @@ DEF_PRIMITIVE(num_bangeq) DEF_PRIMITIVE(num_bitwiseNot) { // Bitwise operators always work on 32-bit unsigned ints. - RETURN_NUM(~(uint32_t)AS_NUM(args[0])); + uint64_t wideVal = AS_NUM(args[0]); + uint32_t val = wideVal & 0xFFFFFFFF; + RETURN_NUM(~(uint32_t)val); } DEF_PRIMITIVE(num_dotDot) diff --git a/src/vm/wren_value.c b/src/vm/wren_value.c index 48239a63..fcdecf04 100644 --- a/src/vm/wren_value.c +++ b/src/vm/wren_value.c @@ -742,9 +742,16 @@ Value wrenNumToString(WrenVM* vm, double value) // Corner case: If the value is NaN, different versions of libc produce // different outputs (some will format it signed and some won't). To get // reliable output, handle that ourselves. - if (value != value) return CONST_STRING(vm, "nan"); - if (value == INFINITY) return CONST_STRING(vm, "infinity"); - if (value == -INFINITY) return CONST_STRING(vm, "-infinity"); + switch (fpclassify(value)) + { + case FP_INFINITE: + if (signbit(value)) + return CONST_STRING(vm, "-infinity"); + else + return CONST_STRING(vm, "infinity"); + case FP_NAN: + return CONST_STRING(vm, "nan"); + } // This is large enough to hold any double converted to a string using // "%.14g". Example: diff --git a/test/api/slots.c b/test/api/slots.c index da9cea68..c82b61c2 100644 --- a/test/api/slots.c +++ b/test/api/slots.c @@ -19,7 +19,7 @@ static void getSlots(WrenVM* vm) if (length != 5) result = false; if (memcmp(bytes, "by\0te", length) != 0) result = false; - if (wrenGetSlotDouble(vm, 3) != 12.34) result = false; + if (wrenGetSlotDouble(vm, 3) != 1.5) result = false; if (strcmp(wrenGetSlotString(vm, 4), "str") != 0) result = false; WrenHandle* handle = wrenGetSlotHandle(vm, 5); @@ -28,13 +28,14 @@ static void getSlots(WrenVM* vm) { // Otherwise, return the value so we can tell if we captured it correctly. wrenSetSlotHandle(vm, 0, handle); - wrenReleaseHandle(vm, handle); } else { // If anything failed, return false. wrenSetSlotBool(vm, 0, false); } + + wrenReleaseHandle(vm, handle); } static void setSlots(WrenVM* vm) @@ -43,7 +44,7 @@ static void setSlots(WrenVM* vm) wrenSetSlotBool(vm, 1, true); wrenSetSlotBytes(vm, 2, "by\0te", 5); - wrenSetSlotDouble(vm, 3, 12.34); + wrenSetSlotDouble(vm, 3, 1.5); wrenSetSlotString(vm, 4, "str"); // TODO: wrenSetSlotNull(). @@ -57,21 +58,22 @@ static void setSlots(WrenVM* vm) const char* bytes = wrenGetSlotBytes(vm, 2, &length); if (length != 5) result = false; if (memcmp(bytes, "by\0te", length) != 0) result = false; - - if (wrenGetSlotDouble(vm, 3) != 12.34) result = false; + + if (wrenGetSlotDouble(vm, 3) != 1.5) result = false; if (strcmp(wrenGetSlotString(vm, 4), "str") != 0) result = false; if (result) { // Move the value into the return position. wrenSetSlotHandle(vm, 0, handle); - wrenReleaseHandle(vm, handle); } else { // If anything failed, return false. wrenSetSlotBool(vm, 0, false); } + + wrenReleaseHandle(vm, handle); } static void slotTypes(WrenVM* vm) diff --git a/test/api/slots.wren b/test/api/slots.wren index ef0f8d79..2a8c7219 100644 --- a/test/api/slots.wren +++ b/test/api/slots.wren @@ -18,7 +18,7 @@ foreign class ForeignType { System.print(Slots.noSet == Slots) // expect: true var value = ["value"] -System.print(Slots.getSlots(true, "by\0te", 12.34, "str", value) == value) +System.print(Slots.getSlots(true, "by\0te", 1.5, "str", value) == value) // expect: true System.print(Slots.setSlots(value, 0, 0, 0) == value) diff --git a/test/core/number/cos.wren b/test/core/number/cos.wren index b7672271..74f0db30 100644 --- a/test/core/number/cos.wren +++ b/test/core/number/cos.wren @@ -3,4 +3,4 @@ System.print(Num.pi.cos) // expect: -1 System.print((2 * Num.pi).cos) // expect: 1 // this should of course be 0, but it's not that precise -System.print((Num.pi / 2).cos) // expect: 6.1232339957368e-17 +System.print((Num.pi / 2).cos.abs < 1.0e-16) // expect: true diff --git a/test/core/number/sin.wren b/test/core/number/sin.wren index e83c1073..f0a1d7a9 100644 --- a/test/core/number/sin.wren +++ b/test/core/number/sin.wren @@ -2,5 +2,5 @@ System.print(0.sin) // expect: 0 System.print((Num.pi / 2).sin) // expect: 1 // these should of course be 0, but it's not that precise -System.print(Num.pi.sin) // expect: 1.2246467991474e-16 -System.print((2 * Num.pi).sin) // expect: -2.4492935982947e-16 +System.print(Num.pi.sin.abs < 1.0e-15) // expect: true +System.print((2 * Num.pi).sin.abs < 1.0e-15) // expect: true diff --git a/test/os/process/all_arguments.wren b/test/os/process/all_arguments.wren index efb55aca..47542a58 100644 --- a/test/os/process/all_arguments.wren +++ b/test/os/process/all_arguments.wren @@ -5,7 +5,7 @@ System.print(args is List) // expect: true System.print(args.count) // expect: 2 // Includes wren executable and file being run. -System.print(args[0].endsWith("wrend")) // expect: true +System.print(args[0].contains("wren")) // expect: true System.print(args[1]) // expect: test/os/process/all_arguments.wren // TODO: Test passing additional args once we have an API to spawn a process. diff --git a/util/libuv.py b/util/libuv.py index 00272cf3..b2f23a8b 100755 --- a/util/libuv.py +++ b/util/libuv.py @@ -11,7 +11,7 @@ import shutil import subprocess import sys -LIB_UV_VERSION = "v1.8.0" +LIB_UV_VERSION = "v1.10.0" LIB_UV_DIR = "deps/libuv" def python2_binary(): diff --git a/util/test.py b/util/test.py index cdd033ed..e9b3b19d 100755 --- a/util/test.py +++ b/util/test.py @@ -2,6 +2,7 @@ from __future__ import print_function +from argparse import ArgumentParser from collections import defaultdict from os import listdir from os.path import abspath, basename, dirname, isdir, isfile, join, realpath, relpath, splitext @@ -10,10 +11,22 @@ from subprocess import Popen, PIPE import sys from threading import Timer +parser = ArgumentParser() +parser.add_argument('--suffix', default='d') +parser.add_argument('suite', nargs='?') + +args = parser.parse_args(sys.argv[1:]) + +config=args.suffix.lstrip('d') +is_debug=args.suffix.startswith('d') +config_dir=("debug" if is_debug else "release") + config # Runs the tests. WREN_DIR = dirname(dirname(realpath(__file__))) -WREN_APP = join(WREN_DIR, 'bin', 'wrend') -TEST_APP = join(WREN_DIR, 'build', 'debug', 'test', 'wrend') +WREN_APP = join(WREN_DIR, 'bin', 'wren' + args.suffix) +TEST_APP = join(WREN_DIR, 'build', config_dir, 'test', 'wren' + args.suffix) + +print("WREN_APP=" + WREN_APP) +print("TEST_APP=" + TEST_APP) EXPECT_PATTERN = re.compile(r'// expect: ?(.*)') EXPECT_ERROR_PATTERN = re.compile(r'// expect error(?! line)') @@ -114,7 +127,7 @@ class Test: test_arg = self.path proc = Popen([app, test_arg], stdin=PIPE, stdout=PIPE, stderr=PIPE) - # If a test takes longer than two seconds, kill it. + # If a test takes longer than five seconds, kill it. # # This is mainly useful for running the tests while stress testing the GC, # which can make a few pathological tests much slower. @@ -123,7 +136,7 @@ class Test: timed_out[0] = True p.kill() - timer = Timer(2, kill_process, [proc]) + timer = Timer(5, kill_process, [proc]) try: timer.start() @@ -313,9 +326,9 @@ def run_script(app, path, type): return # Check if we are just running a subset of the tests. - if len(sys.argv) == 2: + if args.suite: this_test = relpath(path, join(WREN_DIR, 'test')) - if not this_test.startswith(sys.argv[1]): + if not this_test.startswith(args.suite): return # Update the status line. diff --git a/util/wren.mk b/util/wren.mk index 2ada261c..efdef641 100644 --- a/util/wren.mk +++ b/util/wren.mk @@ -42,6 +42,7 @@ ifeq ($(VERBOSE),1) V := endif +C_OPTIONS := $(WREN_CFLAGS) C_WARNINGS := -Wall -Wextra -Werror -Wno-unused-parameter # Wren uses callbacks heavily, so -Wunused-parameter is too painful to enable.