Order of function resolution is different. Function prototypes resolved first. Same with LLVM gen. Designated initializer and anonymous fields fixed mostly.

This commit is contained in:
Christoffer Lerno
2020-04-12 19:59:00 +02:00
committed by Christoffer Lerno
parent 9bf89574f9
commit 1d73338fb0
15 changed files with 514 additions and 154 deletions

View File

@@ -38,10 +38,15 @@ Things missing:
- Bitstruct - Bitstruct
- Enumset - Enumset
- Typeid - Typeid
- Ranges
* Arrays
- Allow fixed arrays with no larger size than 32 bit unsigned.
* Struct / union * Struct / union
- Cast to union? - Cast to union?
- Structural typed anonymous structs and casts to them. - Structural typed anonymous structs and casts to them.
- Auto deref on access.
* Expressions * Expressions
- Disallow x >= 0 and x < 0 on unsigned types unless in a macro. - Disallow x >= 0 and x < 0 on unsigned types unless in a macro.
@@ -69,4 +74,5 @@ Things missing:
- Values: min, max, array - Values: min, max, array
- Functions: fomOrdinal, ordinal, fromName, name, fromFullName, fullName, fromQualifiedName, qualifiedName, <value>(), fromValue() - Functions: fomOrdinal, ordinal, fromName, name, fromFullName, fullName, fromQualifiedName, qualifiedName, <value>(), fromValue()
* Error reporting
- When a variable fails to parse correctly, store it to prevent follow up errors.

View File

@@ -117,41 +117,6 @@ union SimpleUnion
double f; double f;
} }
struct AnonStruct
{
int a;
struct sune
{
int b;
int c;
}
struct
{
int b1;
int c1;
}
union
{
int b2;
int c2;
}
int x;
}
func void testAnonStruct()
{
AnonStruct s = { b2 = 3, b1 = 7, sune.b = 1 };
AnonStruct foo;
s.sune.b = 1;
s.b1 = 2;
s.b2 = 3;
s.c2 = 4;
}
func void testUnion() func void testUnion()
{ {
SimpleUnion s; SimpleUnion s;
@@ -160,7 +125,7 @@ func void testUnion()
s = { 1 }; s = { 1 };
int x = 2; int x = 2;
s = { (x = 2) }; s = { (x = 2) };
//s = { f = 1.0 }; s = { f = 1.0 };
TestUnion tu = { e = TestStruct2 { c = 1 } }; TestUnion tu = { e = TestStruct2 { c = 1 } };
tu.e = TestStruct2 { c = 1 }; tu.e = TestStruct2 { c = 1 };
} }
@@ -290,6 +255,69 @@ func int barok() throws Error, OtherError
return 100; return 100;
} }
struct SimpleStruct
{
int a;
int b;
double c;
double d;
char z1;
char z2;
}
func void testSimpleStruct(int x)
{
SimpleStruct snoinit;
SimpleStruct sinit = { b = 1, d = 3.0, z1 = 1 };
sinit.a = 1;
sinit.b = 2;
printf("a = %d, b = %d (1), c = %f, d = %f (3.0), z1 = %d (1), z2 = %d\n", sinit.a, sinit.b, sinit.c, sinit.d, cast(sinit.z1, int), cast(sinit.z2, int));
snoinit.b = 1;
snoinit.a = 100;
snoinit.d = 3.0;
snoinit.c = 2.0;
snoinit.z1 = 1;
snoinit.z2 = 2;
printf("b = %d (1), d = %f (3.0), z1 = %d (1)\n", snoinit.b, snoinit.d, snoinit.z1);
}
struct AnonStruct
{
int a;
struct sune
{
int b;
int c;
}
struct
{
int b1;
int c1;
}
union
{
int b2;
int c2;
}
int x;
}
func void testAnonStruct()
{
AnonStruct s = { b2 = 3, b1 = 7, sune.b = 1 };
AnonStruct foo;
printf("a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.sune.b, s.sune.c, s.b1, s.c1, s.b2, s.c2, s.x);
s.sune.b = 100;
s.sune.c = 99;
s.b1 = 3;
s.b2 = 5;
s.c2 = 7;
printf("a = %d, b = %d (100), c = %d (99), b1 = %d (3), c1 = %d, b2 = %d (7), c2 = %d (7), x = %d\n", s.a, s.sune.b, s.sune.c, s.b1, s.c1, s.b2, s.c2, s.x);
}
func int boba(int y, int j) func int boba(int y, int j)
{ {
// hello(); // hello();
@@ -526,6 +554,34 @@ func int testReturnDefer()
return i; return i;
} }
struct WithArray
{
int[4] x;
}
func void testArray()
{
//int[4] zebra = { [0] = 1 };
WithArray boo;
boo.x[0] = 2;
printf("boo.x[0] = %d\n", boo.x[0]);
printf("boo.x[2] = %d\n", boo.x[2]);
int[4] x;
x[1] = 1;
x[0] = 3;
int y = x[1];
int z = 1;
int* b = &z;
printf("b: %d\n", *b);
*b = 3;
printf("b: %d\n", *b);
printf("z: %d\n", z);
for (int i = 0; i < 4; i++)
{
printf("x[%d] = %d\n", i, x[i]);
}
}
func void testDefer() func void testDefer()
{ {
printf("1 == %d\n", testReturnDefer()); printf("1 == %d\n", testReturnDefer());
@@ -557,12 +613,17 @@ JUMP:
defer printf("7"); defer printf("7");
printf("6"); printf("6");
} }
func int main(int x) func int main(int x)
{ {
printf("Helo!\n"); printf("Helo!\n");
testDefault(y = 99); testDefault(y = 99);
testPointers(2, 3); testPointers(2, 3);
testDefer(); testDefer();
testArray();
testAnonStruct();
testSimpleStruct(0);
int efd = 9; int efd = 9;
uint fefoek = 1; uint fefoek = 1;
printf("Helo: %d\n", efd + cast(fefoek, int)); printf("Helo: %d\n", efd + cast(fefoek, int));
@@ -723,4 +784,5 @@ func void test2(int* x, int y, int z)
x + 1; x + 1;
int j1 = x[0]; int j1 = x[0];
j1 = *x; j1 = *x;
} }

View File

@@ -1896,7 +1896,14 @@ const char *bigint_to_error_string(const BigInt *bigint, uint64_t base)
if (bigint->digit_count == 1 && base == 10) if (bigint->digit_count == 1 && base == 10)
{ {
char *res = NULL; char *res = NULL;
asprintf(&res, "%" PRIu64, bigint->digit); if (bigint->is_negative)
{
asprintf(&res, "-%" PRIu64, bigint->digit);
}
else
{
asprintf(&res, "%" PRIu64, bigint->digit);
}
return res; return res;
} }
size_t len = bigint->digit_count * 64; size_t len = bigint->digit_count * 64;

View File

@@ -133,6 +133,23 @@ typedef struct _Path
uint32_t len; uint32_t len;
} Path; } Path;
typedef enum
{
DESIGNATED_IDENT,
DESIGNATED_SUBSCRIPT
} DesignatedPathKind;
typedef struct _DesignatedPath
{
DesignatedPathKind kind;
struct _DesignatedPath *sub_path;
Type *type;
union
{
unsigned index;
Expr *index_expr;
};
} DesignatedPath;
typedef struct typedef struct
{ {
unsigned char bitsize; unsigned char bitsize;
@@ -508,6 +525,12 @@ typedef struct
Ast **stmts; Ast **stmts;
} ExprFuncBlock; } ExprFuncBlock;
typedef struct
{
Expr *left;
Expr *right;
} ExprRange;
typedef enum typedef enum
{ {
INITIALIZER_UNKNOWN, INITIALIZER_UNKNOWN,
@@ -522,6 +545,11 @@ typedef struct
Expr** initializer_expr; Expr** initializer_expr;
} ExprInitializer; } ExprInitializer;
typedef struct
{
DesignatedPath *path;
Expr* value;
} ExprDesignatedInit;
struct _Expr struct _Expr
{ {
@@ -530,9 +558,11 @@ struct _Expr
SourceRange span; SourceRange span;
Type *type; Type *type;
union { union {
ExprDesignatedInit designated_init_expr;
Expr *group_expr; Expr *group_expr;
ExprCast cast_expr; ExprCast cast_expr;
ExprConst const_expr; ExprConst const_expr;
ExprRange range_expr;
ExprStructValue struct_value_expr; ExprStructValue struct_value_expr;
ExprTypeRef type_access; ExprTypeRef type_access;
ExprTry try_expr; ExprTry try_expr;
@@ -1151,6 +1181,7 @@ static inline Token wrap(const char *string)
Type *type_get_ptr(Type *ptr_type); Type *type_get_ptr(Type *ptr_type);
Type *type_get_meta(Type *meta_type); Type *type_get_meta(Type *meta_type);
Type *type_get_indexed_type(Type *type);
Type *type_get_array(Type *arr_type, uint64_t len); Type *type_get_array(Type *arr_type, uint64_t len);
Type *type_signed_int_by_bitsize(unsigned bytesize); Type *type_signed_int_by_bitsize(unsigned bytesize);
Type *type_unsigned_int_by_bitsize(unsigned bytesize); Type *type_unsigned_int_by_bitsize(unsigned bytesize);

View File

@@ -230,6 +230,8 @@ typedef enum
EXPR_SCOPED_EXPR, EXPR_SCOPED_EXPR,
EXPR_MACRO_EXPR, EXPR_MACRO_EXPR,
EXPR_EXPR_BLOCK, EXPR_EXPR_BLOCK,
EXPR_RANGE,
EXPR_DESIGNATED_INITIALIZER,
} ExprKind; } ExprKind;

View File

@@ -200,6 +200,11 @@ void llvm_codegen(Context *context)
{ {
gencontext_emit_function_decl(&gen_context, context->functions[i]); gencontext_emit_function_decl(&gen_context, context->functions[i]);
} }
VECEACH(context->functions, i)
{
Decl *decl = context->functions[i];
if (decl->func.body) gencontext_emit_function_body(&gen_context, decl);
}
gencontext_print_llvm_ir(&gen_context); gencontext_print_llvm_ir(&gen_context);

View File

@@ -82,6 +82,18 @@ static inline LLVMValueRef gencontext_emit_subscript_addr_from_value(GenContext
llvm_type(parent_type->pointer), llvm_type(parent_type->pointer),
parent, &index, 1, "[]"); parent, &index, 1, "[]");
case TYPE_ARRAY: case TYPE_ARRAY:
// TODO insert trap on overflow.
{
LLVMValueRef zero = LLVMConstInt(LLVMIntType(32), 0, false);
LLVMValueRef indices[2] = {
zero,
index,
};
return LLVMBuildInBoundsGEP2(context->builder,
llvm_type(parent_type),
parent, indices, 2, "[x]");
}
case TYPE_VARARRAY: case TYPE_VARARRAY:
case TYPE_SUBARRAY: case TYPE_SUBARRAY:
case TYPE_STRING: case TYPE_STRING:
@@ -93,14 +105,45 @@ static inline LLVMValueRef gencontext_emit_subscript_addr_from_value(GenContext
} }
static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr) static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr)
{ {
LLVMValueRef parent = gencontext_emit_expr(context, expr->subscript_expr.expr); Expr *parent = expr->subscript_expr.expr;
return gencontext_emit_subscript_addr_from_value(context, parent, expr->subscript_expr.expr->type->canonical, expr->subscript_expr.index); Expr *index = expr->subscript_expr.index;
LLVMValueRef index_value = gencontext_emit_expr(context, index);
LLVMValueRef parent_value;
switch (parent->type->canonical->type_kind)
{
case TYPE_POINTER:
parent_value = gencontext_emit_expr(context, expr->subscript_expr.expr);
return LLVMBuildGEP2(context->builder,
llvm_type(parent->type->canonical),
parent_value, &index_value, 1, "[]");
case TYPE_ARRAY:
{
// TODO insert trap on overflow.
LLVMValueRef zero = LLVMConstInt(LLVMIntType(32), 0, false);
LLVMValueRef indices[2] = {
zero,
index_value,
};
parent_value = gencontext_emit_address(context, expr->subscript_expr.expr);
return LLVMBuildInBoundsGEP2(context->builder,
llvm_type(parent->type),
parent_value, indices, 2, "[x]");
}
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
case TYPE_STRING:
TODO
default:
UNREACHABLE
}
} }
static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRef value, Decl *parent, Decl *member) static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRef value, Decl *parent, Decl *member)
{ {
unsigned index; unsigned index;
Decl *current_parent; Decl *current_parent;
assert(member->resolve_status == RESOLVE_DONE);
if (decl_is_struct_type(member)) if (decl_is_struct_type(member))
{ {
index = member->strukt.id; index = member->strukt.id;
@@ -119,9 +162,9 @@ static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRe
if (current_parent->decl_kind == DECL_UNION) if (current_parent->decl_kind == DECL_UNION)
{ {
return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), "unionref"); return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), member->name ?: "anon");
} }
return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, "structref"); return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, member->name ?: "anon");
} }
@@ -151,8 +194,13 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
{ {
switch (expr->expr_kind) switch (expr->expr_kind)
{ {
case EXPR_RANGE:
TODO
case EXPR_EXPR_BLOCK: case EXPR_EXPR_BLOCK:
TODO TODO
case EXPR_DESIGNATED_INITIALIZER:
// Should only appear when generating designated initializers.
UNREACHABLE
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
return expr->identifier_expr.decl->var.backend_ref; return expr->identifier_expr.decl->var.backend_ref;
case EXPR_UNARY: case EXPR_UNARY:
@@ -252,28 +300,7 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
} }
static inline LLVMValueRef gencontext_emit_designated_initializer(GenContext *context, Type *parent_type, LLVMValueRef parent, Expr *expr)
{
assert(parent_type == parent_type->canonical);
switch (expr->expr_kind)
{
case EXPR_SUBSCRIPT:
if (expr->subscript_expr.expr)
{
parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->subscript_expr.expr);
parent_type = expr->subscript_expr.expr->type->canonical;
}
return gencontext_emit_subscript_addr_from_value(context, parent, parent_type, expr->subscript_expr.index);
case EXPR_ACCESS:
parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->access_expr.parent);
parent_type = expr->subscript_expr.expr->type->canonical;
return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->access_expr.ref);
case EXPR_IDENTIFIER:
return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->identifier_expr.decl);
default:
UNREACHABLE
}
}
/** /**
* Emit a Foo { .... } literal. * Emit a Foo { .... } literal.
@@ -293,7 +320,7 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con
LLVMConstInt(llvm_type(type_byte), 0, false), LLVMConstInt(llvm_type(type_byte), 0, false),
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false), LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false),
expr->type->decl->strukt.abi_alignment); expr->type->decl->strukt.abi_alignment);
return ref; return LLVMBuildLoad2(context->builder, type, ref, "");
} }
Expr **elements = expr->expr_initializer.initializer_expr; Expr **elements = expr->expr_initializer.initializer_expr;
@@ -307,7 +334,7 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con
LLVMValueRef init_value = gencontext_emit_expr(context, elements[0]); LLVMValueRef init_value = gencontext_emit_expr(context, elements[0]);
LLVMValueRef u = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(elements[0]->type->canonical), 0), ""); LLVMValueRef u = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(elements[0]->type->canonical), 0), "");
LLVMBuildStore(context->builder, init_value, u); LLVMBuildStore(context->builder, init_value, u);
return ref; return LLVMBuildLoad2(context->builder, type, ref, "");
} }
VECEACH(elements, i) VECEACH(elements, i)
{ {
@@ -316,7 +343,7 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con
LLVMValueRef subref = LLVMBuildStructGEP2(context->builder, type, ref, i, ""); LLVMValueRef subref = LLVMBuildStructGEP2(context->builder, type, ref, i, "");
LLVMBuildStore(context->builder, init_value, subref); LLVMBuildStore(context->builder, init_value, subref);
} }
return ref; return LLVMBuildLoad2(context->builder, type, ref, "");
} }
@@ -328,11 +355,48 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con
VECEACH(elements, i) VECEACH(elements, i)
{ {
Expr *element = elements[i]; Expr *element = elements[i];
LLVMValueRef sub_value = gencontext_emit_expr(context, element->binary_expr.right); DesignatedPath *path = element->designated_init_expr.path;
LLVMValueRef sub_ref = gencontext_emit_designated_initializer(context, expr->type->canonical, ref, element->binary_expr.left); LLVMValueRef sub_value = gencontext_emit_expr(context, element->designated_init_expr.value);
LLVMValueRef sub_ref = ref;
Type *parent_type = expr->type->canonical;
while (path)
{
switch (path->kind)
{
case DESIGNATED_IDENT:
if (parent_type->canonical->type_kind == TYPE_UNION)
{
sub_ref = LLVMBuildBitCast(context->builder, sub_ref, LLVMPointerType(llvm_type(path->type), 0), "unionref");
}
else
{
sub_ref = LLVMBuildStructGEP2(context->builder, llvm_type(parent_type), sub_ref, path->index, "structref");
}
break;
case DESIGNATED_SUBSCRIPT:
{
// TODO range, more arrays
LLVMValueRef zero = LLVMConstInt(LLVMIntType(32), 0, false);
LLVMValueRef index = gencontext_emit_expr(context, path->index_expr);
LLVMValueRef indices[2] = {
zero,
index,
};
sub_ref = LLVMBuildInBoundsGEP2(context->builder,
llvm_type(parent_type),
sub_ref, indices, 2, "[x]");
break;
}
default:
UNREACHABLE;
}
parent_type = path->type;
path = path->sub_path;
}
LLVMBuildStore(context->builder, sub_value, sub_ref); LLVMBuildStore(context->builder, sub_value, sub_ref);
} }
return ref; return LLVMBuildLoad2(context->builder, type, ref, "");
} }
static inline LLVMValueRef gencontext_emit_inc_dec_change(GenContext *context, bool use_mod, LLVMValueRef current_value, Expr *expr, int diff) static inline LLVMValueRef gencontext_emit_inc_dec_change(GenContext *context, bool use_mod, LLVMValueRef current_value, Expr *expr, int diff)
@@ -902,14 +966,6 @@ LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr)
static inline LLVMValueRef gencontext_emit_access_expr(GenContext *context, Expr *expr)
{
// Improve, add string description to the access?
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
LLVMValueRef val = LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, expr->access_expr.ref->var.id, "");
return LLVMBuildLoad2(context->builder, gencontext_get_llvm_type(context, expr->type), val, "");
}
static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *context, Expr *expr) static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *context, Expr *expr)
{ {
LLVMValueRef value = NULL; LLVMValueRef value = NULL;
@@ -965,8 +1021,13 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
{ {
switch (expr->expr_kind) switch (expr->expr_kind)
{ {
case EXPR_RANGE:
TODO
case EXPR_POISONED: case EXPR_POISONED:
UNREACHABLE UNREACHABLE
case EXPR_DESIGNATED_INITIALIZER:
// Should only appear when generating designated initializers.
UNREACHABLE
case EXPR_EXPR_BLOCK: case EXPR_EXPR_BLOCK:
return gencontext_emit_expr_block(context, expr); return gencontext_emit_expr_block(context, expr);
case EXPR_SCOPED_EXPR: case EXPR_SCOPED_EXPR:
@@ -990,13 +1051,12 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
UNREACHABLE UNREACHABLE
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
case EXPR_SUBSCRIPT: case EXPR_SUBSCRIPT:
case EXPR_ACCESS:
return gencontext_load_expr(context, gencontext_emit_address(context, expr)); return gencontext_load_expr(context, gencontext_emit_address(context, expr));
case EXPR_CALL: case EXPR_CALL:
return gencontext_emit_call_expr(context, expr); return gencontext_emit_call_expr(context, expr);
case EXPR_GROUP: case EXPR_GROUP:
return gencontext_emit_expr(context, expr->group_expr); return gencontext_emit_expr(context, expr->group_expr);
case EXPR_ACCESS:
return gencontext_emit_access_expr(context, expr);
case EXPR_INITIALIZER_LIST: case EXPR_INITIALIZER_LIST:
return gencontext_emit_initializer_list_expr(context, expr); return gencontext_emit_initializer_list_expr(context, expr);
case EXPR_EXPRESSION_LIST: case EXPR_EXPRESSION_LIST:

View File

@@ -223,7 +223,6 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl)
0); 0);
LLVMSetSubprogram(decl->func.backend_value, context->debug.function); LLVMSetSubprogram(decl->func.backend_value, context->debug.function);
} }
if (decl->func.body) gencontext_emit_function_body(context, decl);
} }
void gencontext_emit_extern_decl(GenContext *context, Decl *decl) void gencontext_emit_extern_decl(GenContext *context, Decl *decl)

View File

@@ -98,7 +98,7 @@ static inline LLVMBasicBlockRef gencontext_create_free_block(GenContext *context
{ {
return LLVMCreateBasicBlockInContext(context->context, name); return LLVMCreateBasicBlockInContext(context->context, name);
} }
void gencontext_emit_function_body(GenContext *context, Decl *decl);
void gencontext_emit_implicit_return(GenContext *context); void gencontext_emit_implicit_return(GenContext *context);
void gencontext_emit_function_decl(GenContext *context, Decl *decl); void gencontext_emit_function_decl(GenContext *context, Decl *decl);
void gencontext_emit_extern_decl(GenContext *context, Decl *decl); void gencontext_emit_extern_decl(GenContext *context, Decl *decl);

View File

@@ -110,14 +110,13 @@ static inline LLVMTypeRef llvm_type_from_ptr(LLVMContextRef context, Type *type)
static inline LLVMTypeRef llvm_type_from_array(LLVMContextRef context, Type *type) static inline LLVMTypeRef llvm_type_from_array(LLVMContextRef context, Type *type)
{ {
LLVMTypeRef base_llvm_type = llvm_get_type(context, type->array.base);
if (type->canonical != type) if (type->canonical != type)
{ {
return type->backend_type = llvm_get_type(context, type->canonical); return type->backend_type = llvm_get_type(context, type->canonical);
} }
return type->backend_type = LLVMPointerType(base_llvm_type, /** TODO **/0); LLVMTypeRef base_llvm_type = llvm_get_type(context, type->array.base);
return type->backend_type = LLVMArrayType(base_llvm_type, type->array.len);
} }
LLVMTypeRef llvm_func_type(LLVMContextRef context, Type *type) LLVMTypeRef llvm_func_type(LLVMContextRef context, Type *type)
@@ -206,7 +205,7 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type)
return type->backend_type = llvm_type_from_ptr(context, type); return type->backend_type = llvm_type_from_ptr(context, type);
case TYPE_STRING: case TYPE_STRING:
// TODO // TODO
return type->backend_type = LLVMPointerType(LLVMTYPE(type_char), 0); return type->backend_type = LLVMPointerType(llvm_get_type(context, type_char), 0);
case TYPE_ARRAY: case TYPE_ARRAY:
return type->backend_type = llvm_type_from_array(context, type); return type->backend_type = llvm_type_from_array(context, type);
case TYPE_SUBARRAY: case TYPE_SUBARRAY:

View File

@@ -75,7 +75,17 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type)
TypeInfo *type = NULL; TypeInfo *type = NULL;
Expr *expr = NULL; Expr *expr = NULL;
SourceRange start = context->tok.span; SourceRange start = context->tok.span;
if (!parse_type_or_expr(context, &expr, &type)) return false; // Special handling of [123]
if (try_consume(context, TOKEN_LBRACKET))
{
expr = TRY_EXPR_OR(parse_expr(context), false);
CONSUME_OR(TOKEN_RBRACKET, false);
expr = TRY_EXPR_OR(parse_precedence_with_left_side(context, expr, PREC_ASSIGNMENT), false);
}
else
{
if (!parse_type_or_expr(context, &expr, &type)) return false;
}
if (!expr) if (!expr)
{ {
if (!allow_type) if (!allow_type)
@@ -253,8 +263,11 @@ Expr *parse_initializer_list(Context *context)
Expr *initializer_list = EXPR_NEW_TOKEN(EXPR_INITIALIZER_LIST, context->tok); Expr *initializer_list = EXPR_NEW_TOKEN(EXPR_INITIALIZER_LIST, context->tok);
initializer_list->expr_initializer.init_type = INITIALIZER_UNKNOWN; initializer_list->expr_initializer.init_type = INITIALIZER_UNKNOWN;
CONSUME_OR(TOKEN_LBRACE, &poisoned_expr); CONSUME_OR(TOKEN_LBRACE, &poisoned_expr);
if (!parse_param_list(context, &initializer_list->expr_initializer.initializer_expr, false)) return &poisoned_expr; if (!try_consume(context, TOKEN_RBRACE))
CONSUME_OR(TOKEN_RBRACE, &poisoned_expr); {
if (!parse_param_list(context, &initializer_list->expr_initializer.initializer_expr, false)) return &poisoned_expr;
CONSUME_OR(TOKEN_RBRACE, &poisoned_expr);
}
return initializer_list; return initializer_list;
} }
@@ -315,6 +328,7 @@ static Expr *parse_subscript_expr(Context *context, Expr *left)
Expr *subscript_ast = EXPR_NEW_EXPR(EXPR_SUBSCRIPT, left); Expr *subscript_ast = EXPR_NEW_EXPR(EXPR_SUBSCRIPT, left);
subscript_ast->subscript_expr.expr = left; subscript_ast->subscript_expr.expr = left;
subscript_ast->subscript_expr.index = index; subscript_ast->subscript_expr.index = index;
RANGE_EXTEND_PREV(subscript_ast);
return subscript_ast; return subscript_ast;
} }

View File

@@ -119,6 +119,7 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
sema_set_struct_size(decl); sema_set_struct_size(decl);
} }
DEBUG_LOG("Analysis complete."); DEBUG_LOG("Analysis complete.");
decl->resolve_status = RESOLVE_DONE;
return decl_ok(decl); return decl_ok(decl);
} }
assert(decl->decl_kind == DECL_VAR); assert(decl->decl_kind == DECL_VAR);
@@ -429,7 +430,6 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
{ {
if (!sema_analyse_method_function(context, decl)) return decl_poison(decl); if (!sema_analyse_method_function(context, decl)) return decl_poison(decl);
} }
if (decl->func.body && !sema_analyse_function_body(context, decl)) return decl_poison(decl);
if (decl->name == main_name) if (decl->name == main_name)
{ {
if (decl->visibility == VISIBLE_LOCAL) if (decl->visibility == VISIBLE_LOCAL)

View File

@@ -351,11 +351,12 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
} }
} }
static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *context, Expr *expr) static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *context, Type *parent, Expr *expr)
{ {
assert(expr->expr_kind == EXPR_SUBSCRIPT); assert(expr->expr_kind == EXPR_SUBSCRIPT);
assert(expr->subscript_expr.expr->resolve_status == RESOLVE_DONE); Expr *subscripted = expr->subscript_expr.expr;
Type *type = expr->subscript_expr.expr->type->canonical; Type *type = parent ? parent->canonical : subscripted->type->canonical;
Expr *index = expr->subscript_expr.index;
Type *inner_type; Type *inner_type;
switch (type->type_kind) switch (type->type_kind)
{ {
@@ -372,16 +373,45 @@ static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *
inner_type = type_char; inner_type = type_char;
break; break;
default: default:
SEMA_ERROR(expr->subscript_expr.expr, "Cannot index '%s'.", type_to_error_string(type)); SEMA_ERROR((parent ? expr : subscripted), "Cannot index '%s'.", type_to_error_string(type));
return false; return false;
} }
if (!sema_analyse_expr(context, type_isize, expr->subscript_expr.index)) return false; if (!sema_analyse_expr(context, type_isize, index)) return false;
// Unless we already have type_usize, cast to type_isize; // Unless we already have type_usize, cast to type_isize;
if (expr->subscript_expr.index->type->canonical->type_kind != type_usize->canonical->type_kind) if (index->type->canonical->type_kind != type_usize->canonical->type_kind)
{ {
if (!cast_implicit(expr->subscript_expr.index, type_isize)) return false; if (!cast_implicit(index, type_isize)) return false;
}
// Check range
if (index->expr_kind == EXPR_CONST)
{
switch (type->type_kind)
{
case TYPE_ARRAY:
{
BigInt size;
bigint_init_unsigned(&size, type->array.len);
if (bigint_cmp(&size, &index->const_expr.i) != CMP_GT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s, exceeding max index of %llu.",
bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1);
return false;
}
// fallthrough
}
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
if (bigint_cmp_zero(&index->const_expr.i) == CMP_LT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s.", bigint_to_error_string(&index->const_expr.i, 10));
return false;
}
break;
default:
break;
}
} }
expr->type = inner_type; expr->type = inner_type;
return true; return true;
@@ -391,7 +421,7 @@ static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr
{ {
if (!sema_analyse_expr(context, NULL, expr->subscript_expr.expr)) return false; if (!sema_analyse_expr(context, NULL, expr->subscript_expr.expr)) return false;
return sema_expr_analyse_subscript_after_parent_resolution(context, expr); return sema_expr_analyse_subscript_after_parent_resolution(context, NULL, expr);
} }
static inline bool sema_expr_analyse_method_function(Context *context, Expr *expr, Decl *decl, bool is_pointer) static inline bool sema_expr_analyse_method_function(Context *context, Expr *expr, Decl *decl, bool is_pointer)
@@ -436,9 +466,10 @@ static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *exp
return true; return true;
} }
static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
static inline bool sema_expr_analyse_access_after_parent_resolution(Context *context, Expr *expr)
{ {
if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false;
assert(expr->expr_kind == EXPR_ACCESS); assert(expr->expr_kind == EXPR_ACCESS);
assert(expr->access_expr.parent->resolve_status == RESOLVE_DONE); assert(expr->access_expr.parent->resolve_status == RESOLVE_DONE);
@@ -486,12 +517,6 @@ static inline bool sema_expr_analyse_access_after_parent_resolution(Context *con
return true; return true;
} }
static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
{
if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false;
return sema_expr_analyse_access_after_parent_resolution(context, expr);
}
static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr) static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr)
{ {
@@ -550,78 +575,172 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp
return false; return false;
} }
static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr); static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *path, Expr *expr);
static Decl *sema_analyse_init_identifier_string(Context *context, Decl *strukt, const char *string) static DesignatedPath *sema_analyse_init_identifier_string(Context *context, DesignatedPath *parent_path, const char *string)
{ {
assert(decl_is_struct_type(strukt)); assert(type_is_structlike(parent_path->type));
Decl **members = strukt->strukt.members; Decl **members = parent_path->type->decl->strukt.members;
VECEACH(members, i) VECEACH(members, i)
{ {
Decl *member = members[i]; Decl *member = members[i];
if (member->name == string) return member; if (member->name == string)
{
DesignatedPath *sub_path = CALLOCS(DesignatedPath);
sub_path->type = member->type;
sub_path->kind = DESIGNATED_IDENT;
sub_path->index = i;
parent_path->sub_path = sub_path;
return sub_path;
}
if (!member->name) if (!member->name)
{ {
Decl *anonymous_member = sema_analyse_init_identifier_string(context, member->type->decl, string); DesignatedPath temp_path;
if (anonymous_member) return anonymous_member; temp_path.type = member->type;
DesignatedPath *found = sema_analyse_init_identifier_string(context, &temp_path, string);
if (!found) continue;
DesignatedPath *real_path = malloc_arena(sizeof(DesignatedPath));
*real_path = temp_path;
real_path->index = i;
real_path->kind = DESIGNATED_IDENT;
parent_path->sub_path = real_path;
return found;
} }
} }
return NULL; return NULL;
} }
static Decl *sema_analyse_init_identifier(Context *context, Decl *strukt, Expr *expr)
static DesignatedPath *sema_analyse_init_access(Context *context, DesignatedPath *parent, Expr *access_expr)
{ {
assert(expr->resolve_status == RESOLVE_NOT_DONE); DesignatedPath *last_path = sema_analyse_init_path(context, parent, access_expr->access_expr.parent);
expr->resolve_status = RESOLVE_RUNNING; if (!last_path) return NULL;
Decl *res = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier); return sema_analyse_init_identifier_string(context, last_path, access_expr->access_expr.sub_element.string);
if (!res) return NULL;
expr->identifier_expr.decl = res;
expr->resolve_status = RESOLVE_DONE;
expr->type = res->type;
return res;
} }
static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *access_expr) static bool expr_cast_to_index(Expr *index)
{ {
assert(access_expr->resolve_status == RESOLVE_NOT_DONE); if (index->expr_kind == EXPR_RANGE)
access_expr->resolve_status = RESOLVE_RUNNING;
Decl *decl = sema_analyse_init_path(context, strukt, access_expr->access_expr.parent);
if (!decl || !decl_is_struct_type(decl->type->decl))
{ {
access_expr->resolve_status = RESOLVE_DONE; TODO
return NULL;
} }
decl = access_expr->access_expr.ref = sema_analyse_init_identifier_string(context, decl->type->decl, access_expr->access_expr.sub_element.string); if (index->type->canonical->type_kind == type_usize->canonical->type_kind) return true;
access_expr->resolve_status = RESOLVE_DONE; return cast_implicit(index, type_isize);
access_expr->type = decl->type;
return decl;
} }
static Decl *sema_analyse_init_subscript(Context *context, Decl *array, Expr *subscript) static bool expr_check_index_in_range(Type *type, Expr *index)
{ {
TODO if (index->expr_kind == EXPR_RANGE)
if (array->type->type_kind != TYPE_ARRAY)
{ {
return expr_check_index_in_range(type, index->range_expr.left) & expr_check_index_in_range(type, index->range_expr.right);
} }
assert(type == type->canonical);
if (index->expr_kind == EXPR_CONST)
{
switch (type->type_kind)
{
case TYPE_ARRAY:
{
BigInt size;
bigint_init_unsigned(&size, type->array.len);
if (bigint_cmp(&size, &index->const_expr.i) != CMP_GT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s, exceeding max index of %llu.",
bigint_to_error_string(&index->const_expr.i, 10), type->array.len - 1);
return false;
}
// fallthrough
}
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
if (bigint_cmp_zero(&index->const_expr.i) == CMP_LT)
{
SEMA_ERROR(index, "Array index out of bounds, was %s.", bigint_to_error_string(&index->const_expr.i, 10));
return false;
}
break;
case TYPE_STRING:
TODO
default:
UNREACHABLE
}
}
return true;
}
static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedPath *parent, Expr *expr)
{
assert(expr->expr_kind == EXPR_SUBSCRIPT);
DesignatedPath *path = sema_analyse_init_path(context, parent, expr->subscript_expr.expr);
if (!path) return NULL;
Type *type = path->type;
if (type->canonical->type_kind == TYPE_POINTER)
{
SEMA_ERROR(expr, "It's not possible to subscript a pointer field in a designated initializer.");
return false;
}
Expr *index = expr->subscript_expr.index;
Type *inner_type = type_get_indexed_type(type);
if (!inner_type)
{
SEMA_ERROR(expr, "Not possible to index a value of type '%s'.", type_to_error_string(type));
return false;
}
if (!sema_analyse_expr(context, type_isize, index)) return false;
// Unless we already have type_usize, cast to type_isize;
if (!expr_cast_to_index(index)) return false;
// Check range
if (!expr_check_index_in_range(type->canonical, index)) return false;
DesignatedPath *sub_path = CALLOCS(DesignatedPath);
path->sub_path = sub_path;
sub_path->type = inner_type;
sub_path->kind = DESIGNATED_SUBSCRIPT;
sub_path->index_expr = index;
return sub_path;
} }
static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr) static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *parent, Expr *expr)
{ {
switch (expr->expr_kind) switch (expr->expr_kind)
{ {
case EXPR_ACCESS: case EXPR_ACCESS:
return sema_analyse_init_access(context, strukt, expr); return sema_analyse_init_access(context, parent, expr);
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
return sema_analyse_init_identifier(context, strukt, expr); return sema_analyse_init_identifier_string(context, parent, expr->identifier_expr.identifier);
case EXPR_SUBSCRIPT: case EXPR_SUBSCRIPT:
return sema_analyse_init_subscript(context, strukt, expr); return sema_analyse_init_subscript(context, parent, expr);
default: default:
return NULL; return NULL;
} }
} }
static bool sema_expr_analyse_struct_designated_initializer(Context *context, Decl *assigned, Expr *initializer) /**
* Recursively find a node in a declaration.
* @return NULL if it wasn't found, otherwise the member.
*/
DesignatedInitializer *find_initializer(Decl *decl, DesignatedInitializer *initializer, const char* name)
{
Decl** compare_members = decl->strukt.members;
VECEACH(compare_members, i)
{
Decl *member = compare_members[i];
if (!member->name)
{
DesignatedInitializer *sub_initializer = initializer->initializers[i];
DesignatedInitializer *found = find_initializer(member, sub_initializer, name);
if (found) return found;
}
else if (member->name == name) return initializer;
}
return NULL;
}
static bool sema_expr_analyse_struct_designated_initializer(Context *context, Type *assigned, Expr *initializer)
{ {
Expr **init_expressions = initializer->expr_initializer.initializer_expr; Expr **init_expressions = initializer->expr_initializer.initializer_expr;
@@ -635,15 +754,20 @@ static bool sema_expr_analyse_struct_designated_initializer(Context *context, De
SEMA_ERROR(expr, "Expected an initializer on the format 'foo = 123' here."); SEMA_ERROR(expr, "Expected an initializer on the format 'foo = 123' here.");
return false; return false;
} }
Expr *path = expr->binary_expr.left; Expr *init_expr = expr->binary_expr.left;
if (!sema_analyse_init_path(context, assigned, path)) DesignatedPath path = { .type = assigned };
DesignatedPath *last_path = sema_analyse_init_path(context, &path, init_expr);
if (!last_path)
{ {
SEMA_ERROR(path, "This is not a valid member of '%s'.", type_to_error_string(assigned->type)); SEMA_ERROR(expr, "This is not a valid member of '%s'.", type_to_error_string(assigned));
return false; return false;
} }
Expr *value = expr->binary_expr.right; Expr *value = expr->binary_expr.right;
if (!sema_analyse_expr_of_required_type(context, path->type, value)) return false; if (!sema_analyse_expr_of_required_type(context, last_path->type, value)) return false;
expr->type = path->type; expr->expr_kind = EXPR_DESIGNATED_INITIALIZER;
expr->designated_init_expr.path = path.sub_path;
expr->designated_init_expr.value = value;
expr->resolve_status = RESOLVE_DONE;
} }
initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED; initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED;
return true; return true;
@@ -702,7 +826,7 @@ static inline bool sema_expr_analyse_struct_initializer(Context *context, Type *
// this means that in this case we're actually not resolving macros here. // this means that in this case we're actually not resolving macros here.
if (init_expressions[0]->expr_kind == EXPR_BINARY && init_expressions[0]->binary_expr.operator == BINARYOP_ASSIGN) if (init_expressions[0]->expr_kind == EXPR_BINARY && init_expressions[0]->binary_expr.operator == BINARYOP_ASSIGN)
{ {
return sema_expr_analyse_struct_designated_initializer(context, assigned->decl, expr); return sema_expr_analyse_struct_designated_initializer(context, assigned, expr);
} }
// 3. Otherwise use the plain initializer. // 3. Otherwise use the plain initializer.
@@ -718,10 +842,7 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to
{ {
case TYPE_STRUCT: case TYPE_STRUCT:
case TYPE_UNION: case TYPE_UNION:
if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer(context, return sema_expr_analyse_struct_initializer(context, assigned, expr);
assigned,
expr);
break;
case TYPE_ARRAY: case TYPE_ARRAY:
TODO TODO
case TYPE_VARARRAY: case TYPE_VARARRAY:
@@ -2075,6 +2196,13 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex
Expr *expr = expr_shallow_copy(source_expr); Expr *expr = expr_shallow_copy(source_expr);
switch (source_expr->expr_kind) switch (source_expr->expr_kind)
{ {
case EXPR_DESIGNATED_INITIALIZER:
// Created during semantic analysis
UNREACHABLE
case EXPR_RANGE:
EXPR_COPY(expr->range_expr.left);
EXPR_COPY(expr->range_expr.right);
return expr;
case EXPR_EXPR_BLOCK: case EXPR_EXPR_BLOCK:
ast_copy_list_from_macro(context, macro, &expr->expr_block.stmts); ast_copy_list_from_macro(context, macro, &expr->expr_block.stmts);
return expr; return expr;
@@ -2522,12 +2650,20 @@ EXIT:
return success; return success;
} }
static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *expr)
{
TODO
}
static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *expr) static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *expr)
{ {
switch (expr->expr_kind) switch (expr->expr_kind)
{ {
case EXPR_POISONED: case EXPR_POISONED:
return false; return false;
case EXPR_DESIGNATED_INITIALIZER:
// Created during semantic analysis
UNREACHABLE
case EXPR_SCOPED_EXPR: case EXPR_SCOPED_EXPR:
UNREACHABLE UNREACHABLE
case EXPR_EXPR_BLOCK: case EXPR_EXPR_BLOCK:
@@ -2536,6 +2672,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
return sema_expr_analyse_macro_expr(context, to, expr); return sema_expr_analyse_macro_expr(context, to, expr);
case EXPR_TRY: case EXPR_TRY:
return sema_expr_analyse_try(context, to, expr); return sema_expr_analyse_try(context, to, expr);
case EXPR_RANGE:
return sema_expr_analyse_range(context, to, expr);
case EXPR_CONST: case EXPR_CONST:
return true; return true;
case EXPR_BINARY: case EXPR_BINARY:

View File

@@ -92,6 +92,13 @@ void sema_analysis_pass_conditional_compilation(Context *context)
DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors);
} }
static inline bool analyse_func_body(Context *context, Decl *decl)
{
if (!decl->func.body) return true;
if (!sema_analyse_function_body(context, decl)) return decl_poison(decl);
return true;
}
void sema_analysis_pass_decls(Context *context) void sema_analysis_pass_decls(Context *context)
{ {
DEBUG_LOG("Pass: Decl analysis %s", context->file->name); DEBUG_LOG("Pass: Decl analysis %s", context->file->name);
@@ -119,5 +126,14 @@ void sema_analysis_pass_decls(Context *context)
{ {
sema_analyse_decl(context, context->functions[i]); sema_analyse_decl(context, context->functions[i]);
} }
VECEACH(context->struct_functions, i)
{
analyse_func_body(context, context->struct_functions[i]);
}
VECEACH(context->functions, i)
{
analyse_func_body(context, context->functions[i]);
}
DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors);
} }

View File

@@ -334,6 +334,27 @@ Type *type_get_meta(Type *meta_type)
return type_generate_meta(meta_type, false); return type_generate_meta(meta_type, false);
} }
Type *type_get_indexed_type(Type *type)
{
switch (type->type_kind)
{
case TYPE_POINTER:
return type->pointer;
case TYPE_VARARRAY:
case TYPE_ARRAY:
case TYPE_SUBARRAY:
return type->array.base;
case TYPE_STRING:
return type_char;
default:
break;
}
Type *canonical = type->canonical;
if (canonical != type) return type_get_indexed_type(type);
return NULL;
}
Type *type_create_array(Type *arr_type, uint64_t len, bool canonical) Type *type_create_array(Type *arr_type, uint64_t len, bool canonical)
{ {
@@ -376,7 +397,7 @@ Type *type_create_array(Type *arr_type, uint64_t len, bool canonical)
} }
Type *array = type_new(TYPE_ARRAY, strformat("%s[%llu]", arr_type->name, len)); Type *array = type_new(TYPE_ARRAY, strformat("%s[%llu]", arr_type->name, len));
array->array.base = arr_type; array->array.base = arr_type;
array->array.len = 0; array->array.len = len;
if (arr_type->canonical == arr_type) if (arr_type->canonical == arr_type)
{ {
array->canonical = array; array->canonical = array;