Skip to content

Commit 806cc03

Browse files
authored
Comparable dynamic arrays (#551)
1 parent 678f69c commit 806cc03

File tree

13 files changed

+259
-86
lines changed

13 files changed

+259
-86
lines changed

doc/lang.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,11 @@ Interface assignment copies the pointer, but not the contents of the variable th
348348

349349
### Function types
350350

351-
A constant that stores an entry point of a function has a function type. A function is characterized by its *signature* that consists of a set of parameter names, types and optional default values, and an optional set of returned value types. The type of the last parameter in the function signature may be prefixed with `..`. The type `..T` is equivalent to `[]T` within the function. Such a function is called *variadic*.
351+
A constant that stores an entry point of a function has a function type. A function is characterized by its *signature* that consists of a set of parameter names, types and optional default values, and an optional set of returned value types.
352+
353+
For a parameter to have a default value, it must be of a comparable type. As a special case, a parameter of type `any` can have the default value `null`.
354+
355+
The type of the last parameter in the function signature may be prefixed with `..`. The type `..T` is equivalent to `[]T` within the function. Such a function is called *variadic*.
352356

353357
Syntax:
354358

@@ -362,7 +366,7 @@ Each function definition in the module scope defines a constant of a function ty
362366
Examples:
363367

364368
```
365-
fn foo(code: int)
369+
fn foo(code: int = 42)
366370
fn MyFunc(p: int, x, y: real): (bool, real)
367371
fn printMsg(msg: char, values: ..real)
368372
```
@@ -395,9 +399,10 @@ A type to which the comparison operators `==`, `!=`, `<`, `<=`, `>`, `>=` may be
395399

396400
* Ordinal types
397401
* Real types
398-
* Pointer type
402+
* Pointer types
399403
* String type
400404
* Array types if their item types are comparable
405+
* Dynamic array types if their item types are comparable
401406
* Structure types if their field types are comparable
402407

403408
### Type compatibility

playground/umka.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/umka_const.c

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@ void constZero(void *lhs, int size)
2121
}
2222

2323

24-
void constDeref(const Consts *consts, Const *constant, TypeKind typeKind)
24+
bool constDeref(const Consts *consts, Const *constant, TypeKind typeKind)
2525
{
2626
if (!constant->ptrVal)
27-
consts->error->handler(consts->error->context, "Pointer is null");
27+
{
28+
if (consts)
29+
consts->error->handler(consts->error->context, "Pointer is null");
30+
return false;
31+
}
2832

2933
switch (typeKind)
3034
{
@@ -51,15 +55,26 @@ void constDeref(const Consts *consts, Const *constant, TypeKind typeKind)
5155
case TYPE_FIBER: constant->ptrVal = *(void * *)constant->ptrVal; break;
5256
case TYPE_FN: constant->intVal = *(int64_t *)constant->ptrVal; break;
5357

54-
default: consts->error->handler(consts->error->context, "Illegal type"); return;
58+
default:
59+
{
60+
if (consts)
61+
consts->error->handler(consts->error->context, "Illegal type");
62+
return false;
63+
}
5564
}
65+
66+
return true;
5667
}
5768

5869

59-
void constAssign(const Consts *consts, void *lhs, const Const *rhs, TypeKind typeKind, int size)
70+
bool constAssign(const Consts *consts, void *lhs, const Const *rhs, TypeKind typeKind, int size)
6071
{
6172
if (typeOverflow(typeKind, *rhs))
62-
consts->error->handler(consts->error->context, "Overflow in assignment to %s", typeKindSpelling(typeKind));
73+
{
74+
if (consts)
75+
consts->error->handler(consts->error->context, "Overflow in assignment to %s", typeKindSpelling(typeKind));
76+
return false;
77+
}
6378

6479
switch (typeKind)
6580
{
@@ -86,12 +101,19 @@ void constAssign(const Consts *consts, void *lhs, const Const *rhs, TypeKind typ
86101
case TYPE_FIBER: *(void * *)lhs = rhs->ptrVal; break;
87102
case TYPE_FN: *(int64_t *)lhs = rhs->intVal; break;
88103

89-
default: consts->error->handler(consts->error->context, "Illegal type"); return;
104+
default:
105+
{
106+
if (consts)
107+
consts->error->handler(consts->error->context, "Illegal type");
108+
return false;
109+
}
90110
}
111+
112+
return true;
91113
}
92114

93115

94-
static int64_t constCompare(const Consts *consts, Const *lhs, const Const *rhs, const Type *type)
116+
int64_t constCompare(const Consts *consts, const Const *lhs, const Const *rhs, const Type *type)
95117
{
96118
switch (type->kind)
97119
{
@@ -115,11 +137,11 @@ static int64_t constCompare(const Consts *consts, Const *lhs, const Const *rhs,
115137
case TYPE_WEAKPTR: return lhs->weakPtrVal - rhs->weakPtrVal;
116138
case TYPE_STR:
117139
{
118-
const char *lhsStr = (const char *)lhs->ptrVal;
140+
const char *lhsStr = lhs->ptrVal;
119141
if (!lhsStr)
120142
lhsStr = "";
121143

122-
const char *rhsStr = (const char *)rhs->ptrVal;
144+
const char *rhsStr = rhs->ptrVal;
123145
if (!rhsStr)
124146
rhsStr = "";
125147

@@ -128,6 +150,9 @@ static int64_t constCompare(const Consts *consts, Const *lhs, const Const *rhs,
128150
case TYPE_ARRAY:
129151
case TYPE_STRUCT:
130152
{
153+
if (!lhs->ptrVal || !rhs->ptrVal)
154+
return (char *)lhs->ptrVal - (char *)rhs->ptrVal;
155+
131156
for (int i = 0; i < type->numItems; i++)
132157
{
133158
const Type *itemType = (type->kind == TYPE_ARRAY) ? type->base : type->field[i]->type;
@@ -136,17 +161,55 @@ static int64_t constCompare(const Consts *consts, Const *lhs, const Const *rhs,
136161
Const lhsItem = {.ptrVal = (char *)lhs->ptrVal + itemOffset};
137162
Const rhsItem = {.ptrVal = (char *)rhs->ptrVal + itemOffset};
138163

139-
constDeref(consts, &lhsItem, itemType->kind);
140-
constDeref(consts, &rhsItem, itemType->kind);
164+
if (!constDeref(consts, &lhsItem, itemType->kind) || !constDeref(consts, &rhsItem, itemType->kind))
165+
return (char *)lhs->ptrVal - (char *)rhs->ptrVal;
141166

142167
const int64_t itemDiff = constCompare(consts, &lhsItem, &rhsItem, itemType);
143168
if (itemDiff != 0)
144169
return itemDiff;
145170
}
146171
return 0;
147172
}
173+
case TYPE_DYNARRAY:
174+
{
175+
if (!lhs->ptrVal || !rhs->ptrVal)
176+
return (char *)lhs->ptrVal - (char *)rhs->ptrVal;
177+
178+
const DynArray *lhsArray = lhs->ptrVal;
179+
const int64_t lhsLen = lhsArray->data ? getDims(lhsArray)->len : 0;
148180

149-
default: consts->error->handler(consts->error->context, "Illegal type"); return 0;
181+
const DynArray *rhsArray = rhs->ptrVal;
182+
const int64_t rhsLen = rhsArray->data ? getDims(rhsArray)->len : 0;
183+
184+
for (int i = 0; ; i++)
185+
{
186+
if (i == lhsLen && i == rhsLen)
187+
return 0;
188+
if (i == lhsLen)
189+
return -1;
190+
if (i == rhsLen)
191+
return 1;
192+
193+
const int itemOffset = i * type->base->size;
194+
195+
Const lhsItem = {.ptrVal = (char *)lhsArray->data + itemOffset};
196+
Const rhsItem = {.ptrVal = (char *)rhsArray->data + itemOffset};
197+
198+
if (!constDeref(consts, &lhsItem, type->base->kind) || !constDeref(consts, &rhsItem, type->base->kind))
199+
return (char *)lhs->ptrVal - (char *)rhs->ptrVal;
200+
201+
const int64_t itemDiff = constCompare(consts, &lhsItem, &rhsItem, type->base);
202+
if (itemDiff != 0)
203+
return itemDiff;
204+
}
205+
return 0;
206+
}
207+
default:
208+
{
209+
if (consts)
210+
consts->error->handler(consts->error->context, "Illegal type");
211+
return 0;
212+
}
150213
}
151214
}
152215

@@ -224,7 +287,7 @@ void constBinary(const Consts *consts, Const *lhs, const Const *rhs, TokenKind o
224287
default: consts->error->handler(consts->error->context, "Illegal operator"); return;
225288
}
226289
}
227-
else if (type->kind == TYPE_ARRAY || type->kind == TYPE_STRUCT)
290+
else if (type->kind == TYPE_ARRAY || type->kind == TYPE_DYNARRAY || type->kind == TYPE_STRUCT)
228291
{
229292
switch (op)
230293
{

src/umka_const.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ typedef struct
2222

2323
void constInit(Consts *consts, Error *error);
2424
void constZero(void *lhs, int size);
25-
void constDeref(const Consts *consts, Const *constant, TypeKind typeKind);
26-
void constAssign(const Consts *consts, void *lhs, const Const *rhs, TypeKind typeKind, int size);
25+
bool constDeref(const Consts *consts, Const *constant, TypeKind typeKind);
26+
bool constAssign(const Consts *consts, void *lhs, const Const *rhs, TypeKind typeKind, int size);
27+
int64_t constCompare(const Consts *consts, const Const *lhs, const Const *rhs, const Type *type);
28+
2729
void constUnary(const Consts *consts, Const *arg, TokenKind op, const Type *type);
2830
void constBinary(const Consts *consts, Const *lhs, const Const *rhs, TokenKind op, const Type *type);
2931
void constCallBuiltin(const Consts *consts, Const *arg, const Const *arg2, TypeKind argTypeKind, BuiltinFunc builtinVal);

src/umka_decl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ static void parseSignature(Compiler *comp, Signature *sig)
139139
if (paramType->isVariadicParamList)
140140
comp->error.handler(comp->error.context, "Variadic parameter list cannot have default value");
141141

142+
if (!typeComparable(paramType) && !typeEquivalent(paramType, comp->anyType))
143+
comp->error.handler(comp->error.context, "Parameter must be of comparable or 'any' type to have default value");
144+
142145
lexNext(&comp->lex);
143146

144147
const Type *defaultType = paramType;

src/umka_types.c

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "umka_vm.h"
99
#include "umka_types.h"
1010
#include "umka_ident.h"
11+
#include "umka_const.h"
1112

1213

1314
static const char *spelling [] =
@@ -255,30 +256,36 @@ bool typeHasPtr(const Type *type, bool alsoWeakPtr)
255256
}
256257

257258

258-
static bool typeDefaultParamEqual(const Const *left, const Const *right, const Type *type)
259+
bool typeComparable(const Type *type)
259260
{
260-
if (typeOrdinal(type) || type->kind == TYPE_FN)
261-
return left->intVal == right->intVal;
262-
263-
if (typeReal(type))
264-
return left->realVal == right->realVal;
261+
if (typeOrdinal(type) || typeReal(type) || type->kind == TYPE_PTR || type->kind == TYPE_WEAKPTR || type->kind == TYPE_STR)
262+
return true;
265263

266-
if (type->kind == TYPE_WEAKPTR)
267-
return left->weakPtrVal == right->weakPtrVal;
264+
if (type->kind == TYPE_ARRAY || type->kind == TYPE_DYNARRAY)
265+
return typeComparable(type->base);
268266

269-
if (!left->ptrVal || !right->ptrVal)
270-
return left->ptrVal == right->ptrVal;
267+
if (type->kind == TYPE_STRUCT)
268+
{
269+
for (int i = 0; i < type->numItems; i++)
270+
if (!typeComparable(type->field[i]->type))
271+
return false;
272+
return true;
273+
}
271274

272-
if (type->kind == TYPE_PTR)
273-
return left->ptrVal == right->ptrVal;
275+
return false;
276+
}
274277

275-
if (type->kind == TYPE_STR)
276-
return strcmp((char *)left->ptrVal, (char *)right->ptrVal) == 0;
277278

278-
if (type->kind == TYPE_ARRAY || type->kind == TYPE_STRUCT || type->kind == TYPE_CLOSURE)
279-
return memcmp(left->ptrVal, right->ptrVal, type->size) == 0;
279+
static bool typeDefaultParamEqual(const Const *left, const Const *right, const Type *type)
280+
{
281+
if (type->kind == TYPE_INTERFACE)
282+
{
283+
const Interface *leftInterface = left->ptrVal;
284+
const Interface *rightInterface = right->ptrVal;
285+
return leftInterface && rightInterface && leftInterface->self == rightInterface->self;
286+
}
280287

281-
return false;
288+
return constCompare(NULL, left, right, type) == 0;
282289
}
283290

284291

@@ -377,7 +384,7 @@ static bool typeEquivalentRecursive(const Type *left, const Type *right, Visited
377384
return false;
378385

379386
// Parameters (skip interface method receiver)
380-
int iStart = left->sig.offsetFromSelf == 0 ? 0 : 1;
387+
const int iStart = left->sig.offsetFromSelf == 0 ? 0 : 1;
381388
for (int i = iStart; i < left->sig.numParams; i++)
382389
{
383390
// Type
@@ -462,26 +469,6 @@ void typeAssertCompatibleBuiltin(const Types *types, const Type *type, /*Builtin
462469
}
463470

464471

465-
static bool typeComparable(const Type *type)
466-
{
467-
if (typeOrdinal(type) || typeReal(type) || type->kind == TYPE_PTR || type->kind == TYPE_WEAKPTR || type->kind == TYPE_STR)
468-
return true;
469-
470-
if (type->kind == TYPE_ARRAY)
471-
return typeComparable(type->base);
472-
473-
if (type->kind == TYPE_STRUCT)
474-
{
475-
for (int i = 0; i < type->numItems; i++)
476-
if (!typeComparable(type->field[i]->type))
477-
return false;
478-
return true;
479-
}
480-
481-
return false;
482-
}
483-
484-
485472
bool typeValidOperator(const Type *type, TokenKind op)
486473
{
487474
switch (op)

src/umka_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ static inline bool typeExprListStruct(const Type *type)
227227
}
228228

229229

230+
bool typeComparable (const Type *type);
230231
bool typeEquivalent (const Type *left, const Type *right);
231232
bool typeSameExceptMaybeIdent (const Type *left, const Type *right);
232233
bool typeCompatible (const Type *left, const Type *right);

src/umka_vm.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ static FORCE_INLINE void doCheckStr(const char *str, Error *error)
713713

714714

715715
static FORCE_INLINE char *doGetEmptyStr(void);
716+
static FORCE_INLINE void doGetEmptyDynArray(DynArray *array, const Type *type);
716717

717718

718719
static FORCE_INLINE void doHook(Fiber *fiber, const HookFunc *hooks, HookEvent event)
@@ -849,11 +850,11 @@ static int64_t doCompare(Slot lhs, Slot rhs, const Type *type, Error *error)
849850
case TYPE_WEAKPTR: return lhs.weakPtrVal - rhs.weakPtrVal;
850851
case TYPE_STR:
851852
{
852-
char *lhsStr = (char *)lhs.ptrVal;
853+
const char *lhsStr = lhs.ptrVal;
853854
if (!lhsStr)
854855
lhsStr = doGetEmptyStr();
855856

856-
char *rhsStr = (char *)rhs.ptrVal;
857+
const char *rhsStr = rhs.ptrVal;
857858
if (!rhsStr)
858859
rhsStr = doGetEmptyStr();
859860

@@ -882,6 +883,44 @@ static int64_t doCompare(Slot lhs, Slot rhs, const Type *type, Error *error)
882883
}
883884
return 0;
884885
}
886+
case TYPE_DYNARRAY:
887+
{
888+
const DynArray *lhsArray = lhs.ptrVal;
889+
if (UNLIKELY(!lhsArray))
890+
error->runtimeHandler(error->context, ERR_RUNTIME, "Dynamic array is null");
891+
892+
const int64_t lhsLen = lhsArray->data ? getDims(lhsArray)->len : 0;
893+
894+
const DynArray *rhsArray = rhs.ptrVal;
895+
if (UNLIKELY(!rhsArray))
896+
error->runtimeHandler(error->context, ERR_RUNTIME, "Dynamic array is null");
897+
898+
const int64_t rhsLen = rhsArray->data ? getDims(rhsArray)->len : 0;
899+
900+
for (int i = 0; ; i++)
901+
{
902+
if (i == lhsLen && i == rhsLen)
903+
return 0;
904+
if (i == lhsLen)
905+
return -1;
906+
if (i == rhsLen)
907+
return 1;
908+
909+
const int itemOffset = i * type->base->size;
910+
911+
Slot lhsItem = {.ptrVal = (char *)lhsArray->data + itemOffset};
912+
Slot rhsItem = {.ptrVal = (char *)rhsArray->data + itemOffset};
913+
914+
doDerefImpl(&lhsItem, type->base->kind, error);
915+
doDerefImpl(&rhsItem, type->base->kind, error);
916+
917+
const int64_t itemDiff = doCompare(lhsItem, rhsItem, type->base, error);
918+
if (itemDiff != 0)
919+
return itemDiff;
920+
}
921+
return 0;
922+
}
923+
885924
default: error->runtimeHandler(error->context, ERR_RUNTIME, "Illegal type"); return 0;
886925
}
887926
}
@@ -3282,7 +3321,7 @@ static FORCE_INLINE void doBinary(Fiber *fiber, HeapPages *pages, Error *error)
32823321
default: error->runtimeHandler(error->context, ERR_RUNTIME, "Illegal instruction"); return;
32833322
}
32843323
}
3285-
else if (type->kind == TYPE_ARRAY || type->kind == TYPE_STRUCT)
3324+
else if (type->kind == TYPE_ARRAY || type->kind == TYPE_DYNARRAY || type->kind == TYPE_STRUCT)
32863325
{
32873326
switch (op)
32883327
{

0 commit comments

Comments
 (0)