1
0
forked from Mirror/wren

Clean up "primitive" code.

This commit is contained in:
Bob Nystrom
2013-11-28 08:00:55 -08:00
parent 1fc9fe131d
commit 9d9f9c11ca
5 changed files with 143 additions and 112 deletions

View File

@ -1,8 +0,0 @@
#ifndef wren_primitives_h
#define wren_primitives_h
#include "vm.h"
void wrenLoadCore(WrenVM* vm);
#endif

View File

@ -4,9 +4,9 @@
#include "common.h"
#include "compiler.h"
#include "primitives.h"
#include "vm.h"
#include "wren.h"
#include "wren_core.h"
WrenVM* wrenNewVM(WrenReallocateFn reallocateFn)
{
@ -31,7 +31,7 @@ WrenVM* wrenNewVM(WrenReallocateFn reallocateFn)
vm->globals[i] = NULL_VAL;
}
wrenLoadCore(vm);
wrenInitializeCore(vm);
return vm;
}

View File

@ -4,39 +4,55 @@
#include <string.h>
#include <time.h>
#include "primitives.h"
#include "wren_core.h"
#include "value.h"
#define PRIMITIVE(cls, name, prim) \
// Binds a native method named [name] (in Wren) implemented using C function
// [fn] to `ObjClass` [cls].
#define NATIVE(cls, name, fn) \
{ \
int symbol = ensureSymbol(&vm->methods, name, strlen(name)); \
cls->methods[symbol].type = METHOD_PRIMITIVE; \
cls->methods[symbol].primitive = primitive_##prim; \
cls->methods[symbol].primitive = native_##fn; \
}
#define FIBER_PRIMITIVE(cls, name, prim) \
// Binds a "fiber native" method named [name] (in Wren) implemented using C
// function [fn] to `ObjClass` [cls]. Unlike regular native methods, fiber
// natives have access to the fiber itself and can do lower-level stuff like
// pushing callframes.
#define FIBER_NATIVE(cls, name, fn) \
{ \
int symbol = ensureSymbol(&vm->methods, name, strlen(name)); \
cls->methods[symbol].type = METHOD_FIBER; \
cls->methods[symbol].fiberPrimitive = primitive_##prim; \
cls->methods[symbol].fiberPrimitive = native_##fn; \
}
#define DEF_PRIMITIVE(prim) \
static Value primitive_##prim(WrenVM* vm, Value* args)
// Defines a native method whose C function name is [native]. This abstracts
// the actual type signature of a native function and makes it clear which C
// functions are intended to be invoked as natives.
#define DEF_NATIVE(native) \
static Value native_##native(WrenVM* vm, Value* args)
#define DEF_FIBER_PRIMITIVE(prim) \
static void primitive_##prim(WrenVM* vm, Fiber* fiber, Value* args)
// Defines a fiber native method whose C function name is [native].
#define DEF_FIBER_NATIVE(native) \
static void native_##native(WrenVM* vm, Fiber* fiber, Value* args)
// TODO(bob): Tune these.
// The initial (and minimum) capacity of a non-empty list object.
#define LIST_MIN_CAPACITY (16)
// The rate at which a list's capacity grows when the size exceeds the current
// capacity. The new capacity will be determined by *multiplying* the old
// capacity by this. Growing geometrically is necessary to ensure that adding
// to a list has O(1) amortized complexity.
#define LIST_GROW_FACTOR (2)
DEF_PRIMITIVE(bool_not)
DEF_NATIVE(bool_not)
{
return BOOL_VAL(!AS_BOOL(args[0]));
}
DEF_PRIMITIVE(bool_toString)
DEF_NATIVE(bool_toString)
{
// TODO(bob): Intern these strings or something.
if (AS_BOOL(args[0]))
@ -54,15 +70,15 @@ DEF_PRIMITIVE(bool_toString)
// the callstack, we again use as many arguments. That ensures that the result
// of evaluating the block goes into the slot that the caller of *this*
// primitive is expecting.
DEF_FIBER_PRIMITIVE(fn_call0) { callFunction(fiber, AS_FN(args[0]), 1); }
DEF_FIBER_PRIMITIVE(fn_call1) { callFunction(fiber, AS_FN(args[0]), 2); }
DEF_FIBER_PRIMITIVE(fn_call2) { callFunction(fiber, AS_FN(args[0]), 3); }
DEF_FIBER_PRIMITIVE(fn_call3) { callFunction(fiber, AS_FN(args[0]), 4); }
DEF_FIBER_PRIMITIVE(fn_call4) { callFunction(fiber, AS_FN(args[0]), 5); }
DEF_FIBER_PRIMITIVE(fn_call5) { callFunction(fiber, AS_FN(args[0]), 6); }
DEF_FIBER_PRIMITIVE(fn_call6) { callFunction(fiber, AS_FN(args[0]), 7); }
DEF_FIBER_PRIMITIVE(fn_call7) { callFunction(fiber, AS_FN(args[0]), 8); }
DEF_FIBER_PRIMITIVE(fn_call8) { callFunction(fiber, AS_FN(args[0]), 9); }
DEF_FIBER_NATIVE(fn_call0) { callFunction(fiber, AS_FN(args[0]), 1); }
DEF_FIBER_NATIVE(fn_call1) { callFunction(fiber, AS_FN(args[0]), 2); }
DEF_FIBER_NATIVE(fn_call2) { callFunction(fiber, AS_FN(args[0]), 3); }
DEF_FIBER_NATIVE(fn_call3) { callFunction(fiber, AS_FN(args[0]), 4); }
DEF_FIBER_NATIVE(fn_call4) { callFunction(fiber, AS_FN(args[0]), 5); }
DEF_FIBER_NATIVE(fn_call5) { callFunction(fiber, AS_FN(args[0]), 6); }
DEF_FIBER_NATIVE(fn_call6) { callFunction(fiber, AS_FN(args[0]), 7); }
DEF_FIBER_NATIVE(fn_call7) { callFunction(fiber, AS_FN(args[0]), 8); }
DEF_FIBER_NATIVE(fn_call8) { callFunction(fiber, AS_FN(args[0]), 9); }
// Grows [list] if needed to ensure it can hold [count] elements.
static void ensureListCapacity(WrenVM* vm, ObjList* list, int count)
@ -101,7 +117,7 @@ static int validateIndex(Value index, int count)
return indexNum;
}
DEF_PRIMITIVE(list_add)
DEF_NATIVE(list_add)
{
ObjList* list = AS_LIST(args[0]);
@ -110,7 +126,7 @@ DEF_PRIMITIVE(list_add)
return args[1];
}
DEF_PRIMITIVE(list_clear)
DEF_NATIVE(list_clear)
{
ObjList* list = AS_LIST(args[0]);
wrenReallocate(vm, list->elements, list->capacity * sizeof(Value), 0);
@ -119,13 +135,13 @@ DEF_PRIMITIVE(list_clear)
return NULL_VAL;
}
DEF_PRIMITIVE(list_count)
DEF_NATIVE(list_count)
{
ObjList* list = AS_LIST(args[0]);
return NUM_VAL(list->count);
}
DEF_PRIMITIVE(list_insert)
DEF_NATIVE(list_insert)
{
ObjList* list = AS_LIST(args[0]);
@ -148,7 +164,7 @@ DEF_PRIMITIVE(list_insert)
return args[1];
}
DEF_PRIMITIVE(list_removeAt)
DEF_NATIVE(list_removeAt)
{
ObjList* list = AS_LIST(args[0]);
int index = validateIndex(args[1], list->count);
@ -176,7 +192,7 @@ DEF_PRIMITIVE(list_removeAt)
return removed;
}
DEF_PRIMITIVE(list_subscript)
DEF_NATIVE(list_subscript)
{
ObjList* list = AS_LIST(args[0]);
@ -188,12 +204,12 @@ DEF_PRIMITIVE(list_subscript)
return list->elements[index];
}
DEF_PRIMITIVE(num_abs)
DEF_NATIVE(num_abs)
{
return NUM_VAL(fabs(AS_NUM(args[0])));
}
DEF_PRIMITIVE(num_toString)
DEF_NATIVE(num_toString)
{
// TODO(bob): What size should this be?
char temp[100];
@ -201,94 +217,94 @@ DEF_PRIMITIVE(num_toString)
return (Value)wrenNewString(vm, temp, strlen(temp));
}
DEF_PRIMITIVE(num_negate)
DEF_NATIVE(num_negate)
{
return NUM_VAL(-AS_NUM(args[0]));
}
DEF_PRIMITIVE(num_minus)
DEF_NATIVE(num_minus)
{
if (!IS_NUM(args[1])) return vm->unsupported;
return NUM_VAL(AS_NUM(args[0]) - AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_plus)
DEF_NATIVE(num_plus)
{
if (!IS_NUM(args[1])) return vm->unsupported;
// TODO(bob): Handle coercion to string if RHS is a string.
return NUM_VAL(AS_NUM(args[0]) + AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_multiply)
DEF_NATIVE(num_multiply)
{
if (!IS_NUM(args[1])) return vm->unsupported;
return NUM_VAL(AS_NUM(args[0]) * AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_divide)
DEF_NATIVE(num_divide)
{
if (!IS_NUM(args[1])) return vm->unsupported;
return NUM_VAL(AS_NUM(args[0]) / AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_mod)
DEF_NATIVE(num_mod)
{
if (!IS_NUM(args[1])) return vm->unsupported;
return NUM_VAL(fmod(AS_NUM(args[0]), AS_NUM(args[1])));
}
DEF_PRIMITIVE(num_lt)
DEF_NATIVE(num_lt)
{
if (!IS_NUM(args[1])) return vm->unsupported;
return BOOL_VAL(AS_NUM(args[0]) < AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_gt)
DEF_NATIVE(num_gt)
{
if (!IS_NUM(args[1])) return vm->unsupported;
return BOOL_VAL(AS_NUM(args[0]) > AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_lte)
DEF_NATIVE(num_lte)
{
if (!IS_NUM(args[1])) return vm->unsupported;
return BOOL_VAL(AS_NUM(args[0]) <= AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_gte)
DEF_NATIVE(num_gte)
{
if (!IS_NUM(args[1])) return vm->unsupported;
return BOOL_VAL(AS_NUM(args[0]) >= AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_eqeq)
DEF_NATIVE(num_eqeq)
{
if (!IS_NUM(args[1])) return FALSE_VAL;
return BOOL_VAL(AS_NUM(args[0]) == AS_NUM(args[1]));
}
DEF_PRIMITIVE(num_bangeq)
DEF_NATIVE(num_bangeq)
{
if (!IS_NUM(args[1])) return TRUE_VAL;
return BOOL_VAL(AS_NUM(args[0]) != AS_NUM(args[1]));
}
DEF_PRIMITIVE(object_eqeq)
DEF_NATIVE(object_eqeq)
{
return BOOL_VAL(wrenValuesEqual(args[0], args[1]));
}
DEF_PRIMITIVE(object_bangeq)
DEF_NATIVE(object_bangeq)
{
return BOOL_VAL(!wrenValuesEqual(args[0], args[1]));
}
DEF_PRIMITIVE(object_type)
DEF_NATIVE(object_type)
{
return OBJ_VAL(wrenGetClass(vm, args[0]));
}
DEF_PRIMITIVE(string_contains)
DEF_NATIVE(string_contains)
{
const char* string = AS_CSTRING(args[0]);
// TODO(bob): Check type of arg first!
@ -300,18 +316,18 @@ DEF_PRIMITIVE(string_contains)
return BOOL_VAL(strstr(string, search) != NULL);
}
DEF_PRIMITIVE(string_count)
DEF_NATIVE(string_count)
{
double count = strlen(AS_CSTRING(args[0]));
return NUM_VAL(count);
}
DEF_PRIMITIVE(string_toString)
DEF_NATIVE(string_toString)
{
return args[0];
}
DEF_PRIMITIVE(string_plus)
DEF_NATIVE(string_plus)
{
if (!IS_STRING(args[1])) return vm->unsupported;
// TODO(bob): Handle coercion to string of RHS.
@ -331,7 +347,7 @@ DEF_PRIMITIVE(string_plus)
return value;
}
DEF_PRIMITIVE(string_eqeq)
DEF_NATIVE(string_eqeq)
{
if (!IS_STRING(args[1])) return FALSE_VAL;
const char* a = AS_CSTRING(args[0]);
@ -339,7 +355,7 @@ DEF_PRIMITIVE(string_eqeq)
return BOOL_VAL(strcmp(a, b) == 0);
}
DEF_PRIMITIVE(string_bangeq)
DEF_NATIVE(string_bangeq)
{
if (!IS_STRING(args[1])) return TRUE_VAL;
const char* a = AS_CSTRING(args[0]);
@ -347,7 +363,7 @@ DEF_PRIMITIVE(string_bangeq)
return BOOL_VAL(strcmp(a, b) != 0);
}
DEF_PRIMITIVE(string_subscript)
DEF_NATIVE(string_subscript)
{
// TODO(bob): Instead of returning null here, all of these failure cases
// should signal an error explicitly somehow.
@ -377,14 +393,14 @@ DEF_PRIMITIVE(string_subscript)
return value;
}
DEF_PRIMITIVE(io_write)
DEF_NATIVE(io_write)
{
wrenPrintValue(args[1]);
printf("\n");
return args[1];
}
DEF_PRIMITIVE(os_clock)
DEF_NATIVE(os_clock)
{
double time = (double)clock() / CLOCKS_PER_SEC;
return NUM_VAL(time);
@ -398,70 +414,70 @@ static ObjClass* defineClass(WrenVM* vm, const char* name, ObjClass* superclass)
return classObj;
}
void wrenLoadCore(WrenVM* vm)
void wrenInitializeCore(WrenVM* vm)
{
vm->objectClass = defineClass(vm, "Object", NULL);
PRIMITIVE(vm->objectClass, "== ", object_eqeq);
PRIMITIVE(vm->objectClass, "!= ", object_bangeq);
PRIMITIVE(vm->objectClass, "type", object_type);
NATIVE(vm->objectClass, "== ", object_eqeq);
NATIVE(vm->objectClass, "!= ", object_bangeq);
NATIVE(vm->objectClass, "type", object_type);
// The "Class" class is the superclass of all metaclasses.
vm->classClass = defineClass(vm, "Class", vm->objectClass);
vm->boolClass = defineClass(vm, "Bool", vm->objectClass);
PRIMITIVE(vm->boolClass, "toString", bool_toString);
PRIMITIVE(vm->boolClass, "!", bool_not);
NATIVE(vm->boolClass, "toString", bool_toString);
NATIVE(vm->boolClass, "!", bool_not);
vm->fnClass = defineClass(vm, "Function", vm->objectClass);
FIBER_PRIMITIVE(vm->fnClass, "call", fn_call0);
FIBER_PRIMITIVE(vm->fnClass, "call ", fn_call1);
FIBER_PRIMITIVE(vm->fnClass, "call ", fn_call2);
FIBER_PRIMITIVE(vm->fnClass, "call ", fn_call3);
FIBER_PRIMITIVE(vm->fnClass, "call ", fn_call4);
FIBER_PRIMITIVE(vm->fnClass, "call ", fn_call5);
FIBER_PRIMITIVE(vm->fnClass, "call ", fn_call6);
FIBER_PRIMITIVE(vm->fnClass, "call ", fn_call7);
FIBER_PRIMITIVE(vm->fnClass, "call ", fn_call8);
FIBER_NATIVE(vm->fnClass, "call", fn_call0);
FIBER_NATIVE(vm->fnClass, "call ", fn_call1);
FIBER_NATIVE(vm->fnClass, "call ", fn_call2);
FIBER_NATIVE(vm->fnClass, "call ", fn_call3);
FIBER_NATIVE(vm->fnClass, "call ", fn_call4);
FIBER_NATIVE(vm->fnClass, "call ", fn_call5);
FIBER_NATIVE(vm->fnClass, "call ", fn_call6);
FIBER_NATIVE(vm->fnClass, "call ", fn_call7);
FIBER_NATIVE(vm->fnClass, "call ", fn_call8);
vm->listClass = defineClass(vm, "List", vm->objectClass);
PRIMITIVE(vm->listClass, "add ", list_add);
PRIMITIVE(vm->listClass, "clear", list_clear);
PRIMITIVE(vm->listClass, "count", list_count);
PRIMITIVE(vm->listClass, "insert ", list_insert);
PRIMITIVE(vm->listClass, "removeAt ", list_removeAt);
PRIMITIVE(vm->listClass, "[ ]", list_subscript);
NATIVE(vm->listClass, "add ", list_add);
NATIVE(vm->listClass, "clear", list_clear);
NATIVE(vm->listClass, "count", list_count);
NATIVE(vm->listClass, "insert ", list_insert);
NATIVE(vm->listClass, "removeAt ", list_removeAt);
NATIVE(vm->listClass, "[ ]", list_subscript);
vm->nullClass = defineClass(vm, "Null", vm->objectClass);
vm->numClass = defineClass(vm, "Num", vm->objectClass);
PRIMITIVE(vm->numClass, "abs", num_abs);
PRIMITIVE(vm->numClass, "toString", num_toString)
PRIMITIVE(vm->numClass, "-", num_negate);
PRIMITIVE(vm->numClass, "- ", num_minus);
PRIMITIVE(vm->numClass, "+ ", num_plus);
PRIMITIVE(vm->numClass, "* ", num_multiply);
PRIMITIVE(vm->numClass, "/ ", num_divide);
PRIMITIVE(vm->numClass, "% ", num_mod);
PRIMITIVE(vm->numClass, "< ", num_lt);
PRIMITIVE(vm->numClass, "> ", num_gt);
PRIMITIVE(vm->numClass, "<= ", num_lte);
PRIMITIVE(vm->numClass, ">= ", num_gte);
NATIVE(vm->numClass, "abs", num_abs);
NATIVE(vm->numClass, "toString", num_toString)
NATIVE(vm->numClass, "-", num_negate);
NATIVE(vm->numClass, "- ", num_minus);
NATIVE(vm->numClass, "+ ", num_plus);
NATIVE(vm->numClass, "* ", num_multiply);
NATIVE(vm->numClass, "/ ", num_divide);
NATIVE(vm->numClass, "% ", num_mod);
NATIVE(vm->numClass, "< ", num_lt);
NATIVE(vm->numClass, "> ", num_gt);
NATIVE(vm->numClass, "<= ", num_lte);
NATIVE(vm->numClass, ">= ", num_gte);
// TODO(bob): The only reason there are here is so that 0 != -0. Is that what
// we want?
PRIMITIVE(vm->numClass, "== ", num_eqeq);
PRIMITIVE(vm->numClass, "!= ", num_bangeq);
NATIVE(vm->numClass, "== ", num_eqeq);
NATIVE(vm->numClass, "!= ", num_bangeq);
vm->stringClass = defineClass(vm, "String", vm->objectClass);
PRIMITIVE(vm->stringClass, "contains ", string_contains);
PRIMITIVE(vm->stringClass, "count", string_count);
PRIMITIVE(vm->stringClass, "toString", string_toString)
PRIMITIVE(vm->stringClass, "+ ", string_plus);
PRIMITIVE(vm->stringClass, "== ", string_eqeq);
PRIMITIVE(vm->stringClass, "!= ", string_bangeq);
PRIMITIVE(vm->stringClass, "[ ]", string_subscript);
NATIVE(vm->stringClass, "contains ", string_contains);
NATIVE(vm->stringClass, "count", string_count);
NATIVE(vm->stringClass, "toString", string_toString)
NATIVE(vm->stringClass, "+ ", string_plus);
NATIVE(vm->stringClass, "== ", string_eqeq);
NATIVE(vm->stringClass, "!= ", string_bangeq);
NATIVE(vm->stringClass, "[ ]", string_subscript);
ObjClass* ioClass = defineClass(vm, "IO", vm->objectClass);
PRIMITIVE(ioClass, "write ", io_write);
NATIVE(ioClass, "write ", io_write);
// TODO(bob): Making this an instance is lame. The only reason we're doing it
// is because "IO.write()" looks ugly. Maybe just get used to that?
@ -469,7 +485,7 @@ void wrenLoadCore(WrenVM* vm)
vm->globals[addSymbol(&vm->globalSymbols, "io", 2)] = ioObject;
ObjClass* osClass = defineClass(vm, "OS", vm->objectClass);
PRIMITIVE(osClass->metaclass, "clock", os_clock);
NATIVE(osClass->metaclass, "clock", os_clock);
// TODO(bob): Make this a distinct object type.
ObjClass* unsupportedClass = wrenNewClass(vm, vm->objectClass, 0);

23
src/wren_core.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef wren_core_h
#define wren_core_h
#include "vm.h"
// This module defines the built-in classes and their native methods that are
// implemented directly in C code. Some languages try to implement as much of
// the core library itself in the primary language instead of in the host
// language.
//
// With Wren, we try to do as much of it in C as possible. Native methods are
// always faster than code written in Wren, and it minimizes startup time since
// we don't have to parse, compile, and execute Wren code.
//
// There is one limitation, though. Currently, native methods cannot call
// non-native ones. They can only be the top of the callstack, and immediately
// return. This makes it difficult to have native methods that rely on
// polymorphic behavior. For example, `io.write` should call `toString` on its
// argument, including user-defined `toString` methods on user-defined classes.
void wrenInitializeCore(WrenVM* vm);
#endif

View File

@ -11,7 +11,7 @@
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 */; };
29FA7298181D91020089013C /* primitives.c in Sources */ = {isa = PBXBuildFile; fileRef = 29FA7297181D91020089013C /* primitives.c */; };
29FA7298181D91020089013C /* wren_core.c in Sources */ = {isa = PBXBuildFile; fileRef = 29FA7297181D91020089013C /* wren_core.c */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -37,8 +37,8 @@
29AB1F2E1816FA66004B501E /* vm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vm.c; path = src/vm.c; sourceTree = SOURCE_ROOT; };
29AB1F3018170104004B501E /* compiler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = compiler.c; path = src/compiler.c; sourceTree = SOURCE_ROOT; };
29AB1F3118170104004B501E /* compiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = compiler.h; path = src/compiler.h; sourceTree = SOURCE_ROOT; };
29FA7296181D90F30089013C /* primitives.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = primitives.h; path = src/primitives.h; sourceTree = SOURCE_ROOT; };
29FA7297181D91020089013C /* primitives.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = primitives.c; path = src/primitives.c; sourceTree = SOURCE_ROOT; };
29FA7296181D90F30089013C /* wren_core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = wren_core.h; path = src/wren_core.h; sourceTree = SOURCE_ROOT; };
29FA7297181D91020089013C /* wren_core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wren_core.c; path = src/wren_core.c; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -83,8 +83,8 @@
296681E2183283A500C1407C /* common.h */,
29AB1F3018170104004B501E /* compiler.c */,
29AB1F3118170104004B501E /* compiler.h */,
29FA7297181D91020089013C /* primitives.c */,
29FA7296181D90F30089013C /* primitives.h */,
29FA7296181D90F30089013C /* wren_core.h */,
29FA7297181D91020089013C /* wren_core.c */,
29AB1F201816E49C004B501E /* main.c */,
29AB1F2E1816FA66004B501E /* vm.c */,
29AB1F2D1816FA5B004B501E /* vm.h */,
@ -148,7 +148,7 @@
files = (
292A45D51838566F00C34813 /* value.c in Sources */,
29AB1F291816E49C004B501E /* main.c in Sources */,
29FA7298181D91020089013C /* primitives.c in Sources */,
29FA7298181D91020089013C /* wren_core.c in Sources */,
29AB1F3218170104004B501E /* compiler.c in Sources */,
29AB1F2F1816FA66004B501E /* vm.c in Sources */,
);