Finish making Wren compile as C++98.

- Get Value, the hard part, compiling as C++.
- Add some rudimentary C++ support to the makefile, mainly for testing.
This commit is contained in:
Bob Nystrom
2015-01-15 21:12:51 -08:00
parent 3a2432eef7
commit 6e369fc639
4 changed files with 100 additions and 49 deletions

2
.gitignore vendored
View File

@ -6,8 +6,10 @@ build_xcode/
# Built files at the top level.
wren
wrend
wren-cpp
libwren.a
libwrend.a
libwren-cpp.a
# XCode user-specific stuff.
xcuserdata/

View File

@ -2,6 +2,7 @@ AR = ar rcu
# Compiler flags.
CFLAGS = -std=c99 -Wall -Werror
# TODO: Add -Wextra.
CPPFLAGS = -std=c++98 -Wall -Werror
DEBUG_CFLAGS = -O0 -DDEBUG -g
RELEASE_CFLAGS = -Os
@ -11,9 +12,13 @@ HEADERS = $(wildcard src/*.h)
OBJECTS = $(SOURCES:.c=.o)
# Don't include main.c in the shared library.
DEBUG_OBJECTS = $(subst build/debug/main.o,,$(addprefix build/debug/, $(notdir $(OBJECTS))))
RELEASE_OBJECTS = $(subst build/release/main.o,,$(addprefix build/release/, $(notdir $(OBJECTS))))
DEBUG_OBJECTS = $(addprefix build/debug/, $(notdir $(OBJECTS)))
RELEASE_OBJECTS = $(addprefix build/release/, $(notdir $(OBJECTS)))
RELEASE_CPP_OBJECTS = $(addprefix build/release-cpp/, $(notdir $(OBJECTS)))
DEBUG_LIB_OBJECTS = $(subst build/debug/main.o,,$(DEBUG_OBJECTS))
RELEASE_LIB_OBJECTS = $(subst build/release/main.o,,$(RELEASE_OBJECTS))
RELEASE_CPP_LIB_OBJECTS = $(subst build/release-cpp/main.o,,$(RELEASE_CPP_OBJECTS))
.PHONY: all clean test builtin docs watchdocs
@ -23,38 +28,53 @@ clean:
@rm -rf build wren wrend libwren.a libwrend.a
prep:
@mkdir -p build/debug build/release
@mkdir -p build/debug build/release build/release-cpp
# Debug build.
debug: prep wrend
debug: prep wrend libwrend.a
# Debug shared lib
libwrend.a: $(DEBUG_OBJECTS)
# Debug shared library.
libwrend.a: $(DEBUG_LIB_OBJECTS)
$(AR) $@ $^
# Debug command-line interpreter.
wrend: build/debug/main.o libwrend.a
$(CC) $(CFLAGS) $(DEBUG_CFLAGS) -Iinclude -o wrend $^ -lm
wrend: $(DEBUG_OBJECTS)
$(CC) $(CFLAGS) $(DEBUG_CFLAGS) -Iinclude -o $@ $^ -lm
# Debug object files.
build/debug/%.o: src/%.c include/wren.h $(HEADERS)
$(CC) -c -fPIC $(CFLAGS) $(DEBUG_CFLAGS) -Iinclude -o $@ $<
# Release build.
release: prep wren
release: prep wren libwren.a
# Release shared lib
libwren.a: $(RELEASE_OBJECTS)
# Release shared library.
libwren.a: $(RELEASE_LIB_OBJECTS)
$(AR) $@ $^
# Release command-line interpreter.
wren: build/release/main.o libwren.a
$(CC) $(CFLAGS) $(RELEASE_CFLAGS) -Iinclude -o wren $^ -lm
wren: $(RELEASE_OBJECTS)
$(CC) $(CFLAGS) $(RELEASE_CFLAGS) -Iinclude -o $@ $^ -lm
# Release object files.
build/release/%.o: src/%.c include/wren.h $(HEADERS)
$(CC) -c -fPIC $(CFLAGS) $(RELEASE_CFLAGS) -Iinclude -o $@ $<
# Release C++ build.
release-cpp: prep wren-cpp libwren-cpp.a
# Release C++ shared lib
libwren-cpp.a: $(RELEASE_CPP_LIB_OBJECTS)
$(AR) $@ $^
# Release C++ command-line interpreter.
wren-cpp: $(RELEASE_CPP_OBJECTS)
$(CC) $(CPPFLAGS) $(RELEASE_CFLAGS) -Iinclude -o $@ $^ -lm
# Release C++ object files.
build/release-cpp/%.o: src/%.c include/wren.h $(HEADERS)
$(CC) -c -fPIC $(CPPFLAGS) $(RELEASE_CFLAGS) -Iinclude -o $@ -x c++ $<
# Run the tests against the debug build of Wren.
test: debug
@./script/test.py $(suite)

View File

@ -628,19 +628,6 @@ ObjClass* wrenGetClass(WrenVM* vm, Value value)
return wrenGetClassInline(vm, value);
}
bool wrenValuesEqual(Value a, Value b)
{
#if WREN_NAN_TAGGING
// Value types have unique bit representations and we compare object types
// by identity (i.e. pointer), so all we need to do is compare the bits.
return a.bits == b.bits;
#else
if (a.type != b.type) return false;
if (a.type == VAL_NUM) return a.num == b.num;
return a.obj == b.obj;
#endif
}
static void printList(ObjList* list)
{
printf("[");

View File

@ -82,11 +82,7 @@ typedef struct sObj
#if WREN_NAN_TAGGING
typedef union
{
double num;
uint64_t bits;
} Value;
typedef uint64_t Value;
#else
@ -378,7 +374,7 @@ typedef struct
#define AS_LIST(value) ((ObjList*)AS_OBJ(value))
// Value -> double.
#define AS_NUM(v) ((v).num)
#define AS_NUM(value) (wrenValueToNum(value))
// Value -> ObjRange*.
#define AS_RANGE(v) ((ObjRange*)AS_OBJ(v))
@ -392,6 +388,9 @@ typedef struct
// Convert [boolean] to a boolean [Value].
#define BOOL_VAL(boolean) (boolean ? TRUE_VAL : FALSE_VAL)
// double -> Value.
#define NUM_VAL(num) (wrenNumToValue(num))
// Convert [obj], an `Obj*`, to a [Value].
#define OBJ_VAL(obj) (wrenObjectToValue((Obj*)(obj)))
@ -482,18 +481,18 @@ typedef struct
#define QNAN ((uint64_t)0x7ffc000000000000)
// If the NaN bits are set, it's not a number.
#define IS_NUM(value) (((value).bits & QNAN) != QNAN)
#define IS_NUM(value) (((value) & QNAN) != QNAN)
// Singleton values are NaN with the sign bit cleared. (This includes the
// normal value of the actual NaN value used in numeric arithmetic.)
#define IS_SINGLETON(value) (((value).bits & (QNAN | SIGN_BIT)) == QNAN)
#define IS_SINGLETON(value) (((value) & (QNAN | SIGN_BIT)) == QNAN)
// An object pointer is a NaN with a set sign bit.
#define IS_OBJ(value) (((value).bits & (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT))
#define IS_OBJ(value) (((value) & (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT))
#define IS_FALSE(value) ((value).bits == FALSE_VAL.bits)
#define IS_NULL(value) ((value).bits == (QNAN | TAG_NULL))
#define IS_UNDEFINED(value) ((value).bits == (QNAN | TAG_UNDEFINED))
#define IS_FALSE(value) ((value) == FALSE_VAL)
#define IS_NULL(value) ((value) == (QNAN | TAG_NULL))
#define IS_UNDEFINED(value) ((value) == (QNAN | TAG_UNDEFINED))
// Masks out the tag bits used to identify the singleton value.
#define MASK_TAG (7)
@ -508,14 +507,11 @@ typedef struct
#define TAG_UNUSED3 (6)
#define TAG_UNUSED4 (7)
// double -> Value.
#define NUM_VAL(n) ((Value)(double)(n))
// Value -> 0 or 1.
#define AS_BOOL(value) ((value).bits == TRUE_VAL.bits)
#define AS_BOOL(value) ((value) == TRUE_VAL)
// Value -> Obj*.
#define AS_OBJ(value) ((Obj*)((value).bits & ~(SIGN_BIT | QNAN)))
#define AS_OBJ(value) ((Obj*)((value) & ~(SIGN_BIT | QNAN)))
// Singleton values.
#define NULL_VAL ((Value)(uint64_t)(QNAN | TAG_NULL))
@ -524,7 +520,7 @@ typedef struct
#define UNDEFINED_VAL ((Value)(uint64_t)(QNAN | TAG_UNDEFINED))
// Gets the singleton type tag for a Value (which must be a singleton).
#define GET_TAG(value) ((int)((value).bits & MASK_TAG))
#define GET_TAG(value) ((int)((value) & MASK_TAG))
#else
@ -542,9 +538,6 @@ typedef struct
#define IS_NUM(value) ((value).type == VAL_NUM)
#define IS_UNDEFINED(value) ((value).type == VAL_UNDEFINED)
// double -> Value.
#define NUM_VAL(n) ((Value){ VAL_NUM, n, NULL })
// Singleton values.
#define FALSE_VAL ((Value){ VAL_FALSE, 0.0, NULL })
#define NULL_VAL ((Value){ VAL_NULL, 0.0, NULL })
@ -645,7 +638,18 @@ ObjClass* wrenGetClass(WrenVM* vm, Value value);
// Returns true if [a] and [b] are strictly equal using built-in equality
// semantics. This is identity for object values, and value equality for others.
bool wrenValuesEqual(Value a, Value b);
static inline bool wrenValuesEqual(Value a, Value b)
{
#if WREN_NAN_TAGGING
// Value types have unique bit representations and we compare object types
// by identity (i.e. pointer), so all we need to do is compare the bits.
return a == b;
#else
if (a.type != b.type) return false;
if (a.type == VAL_NUM) return a.num == b.num;
return a.obj == b.obj;
#endif
}
// TODO: Need to decide if this is for user output of values, or for debug
// tracing.
@ -656,7 +660,7 @@ void wrenPrintValue(Value value);
static inline bool wrenIsBool(Value value)
{
#if WREN_NAN_TAGGING
return value.bits == TRUE_VAL.bits || value.bits == FALSE_VAL.bits;
return value == TRUE_VAL || value == FALSE_VAL;
#else
return value.type == VAL_FALSE || value.type == VAL_TRUE;
#endif
@ -682,4 +686,42 @@ static inline Value wrenObjectToValue(Obj* obj)
#endif
}
// Interprets [value] as a [double].
static inline double wrenValueToNum(Value value)
{
#if WREN_NAN_TAGGING
// Use a union to let us reinterpret the uint64_t bits back to the double
// value it actually stores.
union
{
uint64_t bits;
double num;
} data;
data.bits = value;
return data.num;
#else
return value.num;
#endif
}
// Converts [num] to a [Value].
static inline Value wrenNumToValue(double num)
{
#if WREN_NAN_TAGGING
// Use a union to let us reinterpret the bits making up the double as an
// opaque blob of bits.
union
{
uint64_t bits;
double num;
} data;
data.num = num;
return data.bits;
#else
return (Value){ VAL_NUM, n, NULL };
#endif
}
#endif