mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-12 14:48:40 +01:00
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:
2
.gitignore
vendored
2
.gitignore
vendored
@ -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/
|
||||
|
||||
46
Makefile
46
Makefile
@ -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)
|
||||
|
||||
@ -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("[");
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user