Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Tuple to the language #1153

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/vm/wren_compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,7 @@ typedef struct
// Forward declarations since the grammar is recursive.
static GrammarRule* getRule(TokenType type);
static void expression(Compiler* compiler);
static void maybeTuple(Compiler* compiler);
static void statement(Compiler* compiler);
static void definition(Compiler* compiler);
static void parsePrecedence(Compiler* compiler, Precedence precedence);
Expand Down Expand Up @@ -2138,7 +2139,7 @@ static void loadCoreVariable(Compiler* compiler, const char* name)
// A parenthesized expression.
static void grouping(Compiler* compiler, bool canAssign)
{
expression(compiler);
maybeTuple(compiler);
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
}

Expand Down Expand Up @@ -2857,6 +2858,16 @@ void expression(Compiler* compiler)
parsePrecedence(compiler, PREC_LOWEST);
}

void maybeTuple(Compiler* compiler)
{
expression(compiler);

if (peek(compiler) == TOKEN_COMMA)
{
error(compiler, "Cannot create a tuple.");
}
}

// Returns the number of bytes for the arguments to the instruction
// at [ip] in [fn]'s bytecode.
static int getByteCountForArguments(const uint8_t* bytecode,
Expand Down
161 changes: 161 additions & 0 deletions src/vm/wren_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,13 @@ DEF_PRIMITIVE(list_subscriptSetter)
RETURN_VAL(args[2]);
}

DEF_PRIMITIVE(list_toTuple)
{
ObjList* list = AS_LIST(args[0]);

RETURN_OBJ(wrenNewTuple(vm, list->elements.data, list->elements.count));
}

DEF_PRIMITIVE(map_new)
{
RETURN_OBJ(wrenNewMap(vm));
Expand Down Expand Up @@ -1197,6 +1204,134 @@ DEF_PRIMITIVE(string_toString)
RETURN_VAL(args[0]);
}

static bool tuple_new(WrenVM* vm, Value* args, int numArgs)
{
RETURN_OBJ(wrenNewTuple(vm, &args[1], numArgs));
}

DEF_PRIMITIVE(tuple_filled)
{
if (!validateInt(vm, args[1], "Size")) return false;
if (AS_NUM(args[1]) < 0) RETURN_ERROR("Size cannot be negative.");

size_t size = (size_t)AS_NUM(args[1]);

// FIXME: Add a wrenNewTupleFilled?
ObjMemorySegment* ms = wrenNewTuple(vm, NULL, size);

// wrenNewTuple fills with `null` by default
if (IS_NULL(args[2])) RETURN_OBJ(ms);

for (size_t i = 0; i < size; i++)
{
ms->data[i] = args[2];
}

RETURN_OBJ(ms);
}

#define DEF_TUPLE_NEW(numArgs) \
DEF_PRIMITIVE(tuple_new##numArgs) \
{ \
return tuple_new(vm, args, numArgs); \
}

DEF_TUPLE_NEW(0)
DEF_TUPLE_NEW(1)
DEF_TUPLE_NEW(2)
DEF_TUPLE_NEW(3)
DEF_TUPLE_NEW(4)
DEF_TUPLE_NEW(5)
DEF_TUPLE_NEW(6)
DEF_TUPLE_NEW(7)
DEF_TUPLE_NEW(8)
DEF_TUPLE_NEW(9)
DEF_TUPLE_NEW(10)
DEF_TUPLE_NEW(11)
DEF_TUPLE_NEW(12)
DEF_TUPLE_NEW(13)
DEF_TUPLE_NEW(14)
DEF_TUPLE_NEW(15)
DEF_TUPLE_NEW(16)

DEF_PRIMITIVE(tuple_count)
{
ObjMemorySegment* ms = AS_MEMORYSEGMENT(args[0]);

RETURN_NUM(ms->count);
}

DEF_PRIMITIVE(tuple_subscript)
{
ObjMemorySegment* ms = AS_MEMORYSEGMENT(args[0]);

if (IS_NUM(args[1]))
{
uint32_t index = validateIndex(vm, args[1], ms->count, "Subscript");
if (index == UINT32_MAX) return false;

RETURN_VAL(ms->data[index]);
}

if (!IS_RANGE(args[1]))
{
RETURN_ERROR("Subscript must be a number or a range.");
}

int step;
uint32_t count = ms->count;
uint32_t start = calculateRange(vm, AS_RANGE(args[1]), &count, &step);
if (start == UINT32_MAX) return false;

ObjMemorySegment* result = wrenNewTuple(vm, NULL, count);
for (size_t i = 0; i < count; i++)
{
result->data[i] = ms->data[start + i * step];
}

RETURN_OBJ(result);
}

DEF_PRIMITIVE(tuple_subscriptSetter)
{
ObjMemorySegment* ms = AS_MEMORYSEGMENT(args[0]);
uint32_t index = validateIndex(vm, args[1], ms->count, "Subscript");
if (index == UINT32_MAX) return false;

ms->data[index] = args[2];
RETURN_VAL(args[2]);
}

DEF_PRIMITIVE(tuple_iterate)
{
ObjMemorySegment* ms = AS_MEMORYSEGMENT(args[0]);

// If we're starting the iteration, return the first index.
if (IS_NULL(args[1]))
{
if (ms->count == 0) RETURN_FALSE;
RETURN_NUM(0);
}

if (!validateInt(vm, args[1], "Iterator")) return false;

// Stop if we're out of bounds.
double index = AS_NUM(args[1]);
if (index < 0 || index >= ms->count - 1) RETURN_FALSE;

// Otherwise, move to the next index.
RETURN_NUM(index + 1);
}

DEF_PRIMITIVE(tuple_iteratorValue)
{
ObjMemorySegment* ms = AS_MEMORYSEGMENT(args[0]);
uint32_t index = validateIndex(vm, args[1], ms->count, "Iterator");
if (index == UINT32_MAX) return false;

RETURN_VAL(ms->data[index]);
}

DEF_PRIMITIVE(system_clock)
{
RETURN_NUM((double)clock() / CLOCKS_PER_SEC);
Expand Down Expand Up @@ -1443,6 +1578,7 @@ void wrenInitializeCore(WrenVM* vm)
PRIMITIVE(vm->listClass, "remove(_)", list_removeValue);
PRIMITIVE(vm->listClass, "indexOf(_)", list_indexOf);
PRIMITIVE(vm->listClass, "swap(_,_)", list_swap);
PRIMITIVE(vm->listClass, "toTuple", list_toTuple);

vm->mapClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Map"));
PRIMITIVE(vm->mapClass->obj.classObj, "new()", map_new);
Expand All @@ -1467,6 +1603,31 @@ void wrenInitializeCore(WrenVM* vm)
PRIMITIVE(vm->rangeClass, "iteratorValue(_)", range_iteratorValue);
PRIMITIVE(vm->rangeClass, "toString", range_toString);

vm->tupleClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Tuple"));
PRIMITIVE(vm->tupleClass->obj.classObj, "filled(_,_)", tuple_filled);
PRIMITIVE(vm->tupleClass->obj.classObj, "new()", tuple_new0);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_)", tuple_new1);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_)", tuple_new2);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_)", tuple_new3);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_)", tuple_new4);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_)", tuple_new5);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_)", tuple_new6);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_)", tuple_new7);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_)", tuple_new8);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_,_)", tuple_new9);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_,_,_)", tuple_new10);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_,_,_,_)", tuple_new11);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_,_,_,_,_)", tuple_new12);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_,_,_,_,_,_)", tuple_new13);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_,_,_,_,_,_,_)", tuple_new14);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)", tuple_new15);
PRIMITIVE(vm->tupleClass->obj.classObj, "new(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)", tuple_new16);
PRIMITIVE(vm->tupleClass, "count", tuple_count);
PRIMITIVE(vm->tupleClass, "[_]", tuple_subscript);
PRIMITIVE(vm->tupleClass, "[_]=(_)", tuple_subscriptSetter);
PRIMITIVE(vm->tupleClass, "iterate(_)", tuple_iterate);
PRIMITIVE(vm->tupleClass, "iteratorValue(_)", tuple_iteratorValue);

ObjClass* systemClass = AS_CLASS(wrenFindVariable(vm, coreModule, "System"));
PRIMITIVE(systemClass->obj.classObj, "clock", system_clock);
PRIMITIVE(systemClass->obj.classObj, "gc()", system_gc);
Expand Down
17 changes: 17 additions & 0 deletions src/vm/wren_core.wren
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class Sequence {
}
return result
}

toTuple { toList.toTuple }
}

class MapSequence is Sequence {
Expand Down Expand Up @@ -437,6 +439,21 @@ class MapValueSequence is Sequence {

class Range is Sequence {}

class Tuple is Sequence {
==(rhs) {
if (Object.same(this, rhs)) return true
if (rhs.type != Tuple || count != rhs.count) return false
for (i in 0...count) {
if (this[i] == rhs[i]) continue
return false
}
return true
}
!=(rhs) {!(this == rhs)}

toString { "(%(join(", ")))" }
}

class System {
static print() {
writeString_("\n")
Expand Down
17 changes: 17 additions & 0 deletions src/vm/wren_core.wren.inc
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ static const char* coreModuleSource =
" }\n"
" return result\n"
" }\n"
"\n"
" toTuple { toList.toTuple }\n"
"}\n"
"\n"
"class MapSequence is Sequence {\n"
Expand Down Expand Up @@ -439,6 +441,21 @@ static const char* coreModuleSource =
"\n"
"class Range is Sequence {}\n"
"\n"
"class Tuple is Sequence {\n"
" ==(rhs) {\n"
" if (Object.same(this, rhs)) return true\n"
" if (rhs.type != Tuple || count != rhs.count) return false\n"
" for (i in 0...count) {\n"
" if (this[i] == rhs[i]) continue\n"
" return false\n"
" }\n"
" return true\n"
" }\n"
" !=(rhs) {!(this == rhs)}\n"
"\n"
" toString { \"(%(join(\", \")))\" }\n"
"}\n"
"\n"
"class System {\n"
" static print() {\n"
" writeString_(\"\\n\")\n"
Expand Down
Loading