diff --git a/src/primitives.c b/src/primitives.c index 3217fe79..c57ecafd 100644 --- a/src/primitives.c +++ b/src/primitives.c @@ -5,6 +5,7 @@ #include "compiler.h" #include "primitives.h" +#include "value.h" #define PRIMITIVE(cls, name, prim) \ { \ diff --git a/src/value.c b/src/value.c new file mode 100644 index 00000000..0c2b8288 --- /dev/null +++ b/src/value.c @@ -0,0 +1,19 @@ +#include "value.h" + +int valueIsFn(Value value) +{ + return value.type == VAL_OBJ && value.obj->type == OBJ_FN; +} + +int valueIsString(Value value) +{ + return value.type == VAL_OBJ && value.obj->type == OBJ_STRING; +} + +Value objectToValue(Obj* obj) +{ + Value value; + value.type = VAL_OBJ; + value.obj = obj; + return value; +} diff --git a/src/value.h b/src/value.h new file mode 100644 index 00000000..d51c170f --- /dev/null +++ b/src/value.h @@ -0,0 +1,153 @@ +#ifndef wren_value_h +#define wren_value_h + +// TODO(bob): This should be in VM. (Or, really, we shouldn't hardcode this at +// all and have growable symbol tables.) +#define MAX_SYMBOLS 256 + +typedef enum +{ + VAL_FALSE, + VAL_NULL, + VAL_NUM, + VAL_TRUE, + VAL_OBJ +} ValueType; + +typedef enum { + OBJ_CLASS, + OBJ_FN, + OBJ_INSTANCE, + OBJ_STRING +} ObjType; + +typedef enum +{ + // The object has been marked during the mark phase of GC. + FLAG_MARKED = 0x01, +} ObjFlags; + +typedef struct sObj +{ + ObjType type; + ObjFlags flags; + + // The next object in the linked list of all currently allocated objects. + struct sObj* next; +} Obj; + +// TODO(bob): Temp. +typedef struct +{ + ValueType type; + double num; + Obj* obj; +} Value; + +typedef struct sVM VM; +typedef struct sFiber Fiber; + +typedef Value (*Primitive)(VM* vm, Fiber* fiber, Value* args); + +typedef struct +{ + Obj obj; + unsigned char* bytecode; + Value* constants; + int numConstants; +} ObjFn; + +typedef enum +{ + METHOD_NONE, + METHOD_PRIMITIVE, + METHOD_BLOCK +} MethodType; + +typedef struct +{ + MethodType type; + union + { + Primitive primitive; + ObjFn* fn; + }; +} Method; + +typedef struct sObjClass +{ + Obj obj; + struct sObjClass* metaclass; + struct sObjClass* superclass; + // TODO(bob): Hack. Probably don't want to use this much space. + Method methods[MAX_SYMBOLS]; +} ObjClass; + +typedef struct +{ + Obj obj; + ObjClass* classObj; + // TODO(bob): Fields. +} ObjInstance; + +typedef struct +{ + Obj obj; + char* value; +} ObjString; + +// Get the class value of [value] (0 or 1), which must be a boolean. +#define AS_CLASS(value) ((ObjClass*)(value).obj) + +// Get the bool value of [obj] (0 or 1), which must be a boolean. +#define AS_BOOL(value) ((value).type == VAL_TRUE) + +// Get the function value of [obj] (0 or 1), which must be a function. +#define AS_FN(value) ((ObjFn*)(value).obj) + +// Get the double value of [obj], which must be a number. +#define AS_INSTANCE(value) ((ObjInstance*)(value).obj) + +// Get the double value of [value], which must be a number. +#define AS_NUM(v) ((v).num) + +// Get the const char* value of [v], which must be a string. +#define AS_CSTRING(v) (AS_STRING(v)->value) + +// Get the ObjString* of [v], which must be a string. +#define AS_STRING(v) ((ObjString*)(v).obj) + +// Determines if [value] is a garbage-collected object or not. +#define IS_OBJ(value) ((value).type == VAL_OBJ) + +#define IS_NULL(value) ((value).type == VAL_NULL) +#define IS_NUM(value) ((value).type == VAL_NUM) +#define IS_BOOL(value) ((value).type == VAL_FALSE || (value).type == VAL_TRUE) + +// Returns non-zero if [value] is a function object. +#define IS_FN(value) (valueIsFn(value)) + +// Returns non-zero if [value] is a string object. +#define IS_STRING(value) (valueIsString(value)) + +// Convert [obj], an `Obj*`, to a [Value]. +#define OBJ_VAL(obj) (objectToValue((Obj*)(obj))) + +// Convert [boolean], an int, to a boolean [Value]. +#define BOOL_VAL(boolean) (boolean ? TRUE_VAL : FALSE_VAL) + +// Convert [n], a raw number, to a [Value]. +#define NUM_VAL(n) ((Value){ VAL_NUM, n, NULL }) + +// TODO(bob): Not C89! +#define FALSE_VAL ((Value){ VAL_FALSE, 0.0, NULL }) +#define NULL_VAL ((Value){ VAL_NULL, 0.0, NULL }) +#define TRUE_VAL ((Value){ VAL_TRUE, 0.0, NULL }) +// TODO(bob): Gross. +#define NO_VAL ((Value){ VAL_OBJ, 0.0, NULL }) + +int valueIsFn(Value value); +int valueIsString(Value value); +Value objectToValue(Obj* obj); + +#endif diff --git a/src/vm.c b/src/vm.c index f97c3b7c..7e1a8399 100644 --- a/src/vm.c +++ b/src/vm.c @@ -8,14 +8,6 @@ static Value primitive_metaclass_new(VM* vm, Fiber* fiber, Value* args); -Value objectToValue(Obj* obj) -{ - Value value; - value.type = VAL_OBJ; - value.obj = obj; - return value; -} - VM* newVM() { // TODO(bob): Get rid of explicit malloc() here. diff --git a/src/vm.h b/src/vm.h index 215903fe..f5118244 100644 --- a/src/vm.h +++ b/src/vm.h @@ -1,135 +1,13 @@ #ifndef wren_vm_h #define wren_vm_h +#include "value.h" + // TODO(bob): Make these externally controllable. #define STACK_SIZE 1024 #define MAX_CALL_FRAMES 256 -#define MAX_SYMBOLS 256 #define MAX_PINNED 16 -// Get the class value of [value] (0 or 1), which must be a boolean. -#define AS_CLASS(value) ((ObjClass*)(value).obj) - -// Get the bool value of [obj] (0 or 1), which must be a boolean. -#define AS_BOOL(value) ((value).type == VAL_TRUE) - -// Get the function value of [obj] (0 or 1), which must be a function. -#define AS_FN(value) ((ObjFn*)(value).obj) - -// Get the double value of [obj], which must be a number. -#define AS_INSTANCE(value) ((ObjInstance*)(value).obj) - -// Get the double value of [value], which must be a number. -#define AS_NUM(v) ((v).num) - -// Get the const char* value of [v], which must be a string. -#define AS_CSTRING(v) (AS_STRING(v)->value) - -// Get the ObjString* of [v], which must be a string. -#define AS_STRING(v) ((ObjString*)(v).obj) - -// Determines if [value] is a garbage-collected object or not. -#define IS_OBJ(value) ((value).type == VAL_OBJ) - -#define IS_NULL(value) ((value).type == VAL_NULL) -#define IS_NUM(value) ((value).type == VAL_NUM) -#define IS_BOOL(value) ((value).type == VAL_FALSE || (value).type == VAL_TRUE) - -// TODO(bob): Evaluating value here twice sucks. -#define IS_FN(value) (IS_OBJ(value) && (value).obj->type == OBJ_FN) -#define IS_STRING(value) (IS_OBJ(value) && (value).obj->type == OBJ_STRING) - -typedef enum -{ - VAL_FALSE, - VAL_NULL, - VAL_NUM, - VAL_TRUE, - VAL_OBJ -} ValueType; - -typedef enum { - OBJ_CLASS, - OBJ_FN, - OBJ_INSTANCE, - OBJ_STRING -} ObjType; - -typedef enum -{ - // The object has been marked during the mark phase of GC. - FLAG_MARKED = 0x01, -} ObjFlags; - -typedef struct sObj -{ - ObjType type; - ObjFlags flags; - - // The next object in the linked list of all currently allocated objects. - struct sObj* next; -} Obj; - -// TODO(bob): Temp. -typedef struct -{ - ValueType type; - double num; - Obj* obj; -} Value; - -typedef struct sVM VM; -typedef struct sFiber Fiber; - -typedef Value (*Primitive)(VM* vm, Fiber* fiber, Value* args); - -typedef struct -{ - Obj obj; - unsigned char* bytecode; - Value* constants; - int numConstants; -} ObjFn; - -typedef enum -{ - METHOD_NONE, - METHOD_PRIMITIVE, - METHOD_BLOCK -} MethodType; - -typedef struct -{ - MethodType type; - union - { - Primitive primitive; - ObjFn* fn; - }; -} Method; - -typedef struct sObjClass -{ - Obj obj; - struct sObjClass* metaclass; - struct sObjClass* superclass; - // TODO(bob): Hack. Probably don't want to use this much space. - Method methods[MAX_SYMBOLS]; -} ObjClass; - -typedef struct -{ - Obj obj; - ObjClass* classObj; - // TODO(bob): Fields. -} ObjInstance; - -typedef struct -{ - Obj obj; - char* value; -} ObjString; - typedef enum { // Load the constant at index [arg]. @@ -276,20 +154,6 @@ struct sFiber int numFrames; }; -// TODO(bob): Temp. -#define OBJ_VAL(obj) (objectToValue((Obj*)(obj))) -Value objectToValue(Obj* obj); - -// TODO(bob): Not C89! -#define FALSE_VAL ((Value){ VAL_FALSE, 0.0, NULL }) -#define NULL_VAL ((Value){ VAL_NULL, 0.0, NULL }) -#define TRUE_VAL ((Value){ VAL_TRUE, 0.0, NULL }) -// TODO(bob): Gross. -#define NO_VAL ((Value){ VAL_OBJ, 0.0, NULL }) - -#define BOOL_VAL(b) (b ? TRUE_VAL : FALSE_VAL) -#define NUM_VAL(n) ((Value){ VAL_NUM, n, NULL }) - VM* newVM(); void freeVM(VM* vm); diff --git a/wren.xcodeproj/project.pbxproj b/wren.xcodeproj/project.pbxproj index ebcf7803..7b4cd4f7 100644 --- a/wren.xcodeproj/project.pbxproj +++ b/wren.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 292A45D51838566F00C34813 /* value.c in Sources */ = {isa = PBXBuildFile; fileRef = 292A45D41838566F00C34813 /* value.c */; }; 29AB1F291816E49C004B501E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F201816E49C004B501E /* main.c */; }; 29AB1F2F1816FA66004B501E /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F2E1816FA66004B501E /* vm.c */; }; 29AB1F3218170104004B501E /* compiler.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F3018170104004B501E /* compiler.c */; }; @@ -26,6 +27,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 292A45D31838566400C34813 /* value.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = value.h; path = src/value.h; sourceTree = SOURCE_ROOT; }; + 292A45D41838566F00C34813 /* value.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = value.c; path = src/value.c; sourceTree = SOURCE_ROOT; }; 296681E2183283A500C1407C /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = common.h; path = src/common.h; sourceTree = SOURCE_ROOT; }; 29AB1F061816E3AD004B501E /* wren */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wren; sourceTree = BUILT_PRODUCTS_DIR; }; 29AB1F201816E49C004B501E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = SOURCE_ROOT; }; @@ -75,6 +78,8 @@ 29AB1F201816E49C004B501E /* main.c */, 29AB1F2E1816FA66004B501E /* vm.c */, 29AB1F2D1816FA5B004B501E /* vm.h */, + 292A45D41838566F00C34813 /* value.c */, + 292A45D31838566400C34813 /* value.h */, ); name = src; path = wren; @@ -131,6 +136,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 292A45D51838566F00C34813 /* value.c in Sources */, 29AB1F291816E49C004B501E /* main.c in Sources */, 29FA7298181D91020089013C /* primitives.c in Sources */, 29AB1F3218170104004B501E /* compiler.c in Sources */,