nctref/src/types.c
2025-05-03 10:00:20 +03:00

385 lines
9.7 KiB
C

#include"types.h"
#include"utils.h"
#include<stdlib.h>
#include<string.h>
#include<stdint.h>
#include"ast.h"
#include"reporting.h"
#include"ntc.h"
Type TYPE_ERROR = {.type = TYPE_TYPE_ERROR};
static TypePrimitive *primitiveDatabase[128];
Type *primitive_parse(const char *src) {
size_t hash = djb2(src) % 128;
for(TypePrimitive *t = primitiveDatabase[hash]; t; t = t->next) {
if(!strcmp(src, t->src)) {
return (Type*) t;
}
}
TypePrimitive *ret = calloc(1, sizeof(*ret));
ret->type = TYPE_TYPE_PRIMITIVE;
ret->src = strdup(src);
if(*src == 'n') {
src++;
ret->isNative = 1;
} else {
ret->isNative = 0;
}
if(*src == 'u') {
src++;
ret->isUnsigned = 1;
} else if(*src == 's') {
src++;
ret->isUnsigned = 0;
} else {
free(ret);
return NULL;
}
if(*src == 'm') {
src++;
ret->isMinimum = 1;
} else {
ret->isMinimum = 0;
}
if(*src == 'f') {
src++;
ret->isFloat = 1;
} else {
ret->isFloat = 0;
}
ret->width = strtol(src, (char**) &src, 10);
if(*src == 'b') {
src++;
ret->base = strtol(src, (char**) &src, 10);
} else {
ret->base = 2;
}
if(*src == 'v') {
src++;
ret->vector = strtol(src, (char**) &src, 10);
} else {
ret->vector = 1;
}
if(*src) {
free(ret);
return NULL;
}
ret->next = primitiveDatabase[hash];
primitiveDatabase[hash] = ret;
return (Type*) ret;
}
size_t type_size(Type *t) {
if(t->type == TYPE_TYPE_PRIMITIVE) {
/* Round to nearest highest power of two. */
uint16_t w = (t->primitive.width + 7) / 8;
w--;
w |= w >> 1;
w |= w >> 2;
w |= w >> 4;
w |= w >> 8;
w++;
return w;
} else if(t->type == TYPE_TYPE_POINTER || t->type == TYPE_TYPE_FUNCTION) {
return 4;
} else if(t->type == TYPE_TYPE_ARRAY) {
return type_size(t->array.of) * t->array.length;
} else if(t->type == TYPE_TYPE_RECORD) {
size_t max = 0;
for(size_t f = 0; f < t->record.fieldCount; f++) {
size_t end = t->record.fieldOffsets[f] + type_size(t->record.fieldTypes[f]);
if(max < end) {
max = end;
}
}
return max;
}
abort();
return -1;
}
int type_equal(Type *O, Type *T) {
if(O == T) return 1;
if(O->type != T->type) return 0;
if(O->type == TYPE_TYPE_PRIMITIVE) {
TypePrimitive *o = &O->primitive, *t = &T->primitive;
return o->width == t->width \
&& o->base == t->base \
&& o->isFloat == t->isFloat \
&& o->isUnsigned == t->isUnsigned \
&& o->isNative == t->isNative \
&& o->isMinimum == t->isMinimum \
&& o->vector == t->vector;
} else if(O->type == TYPE_TYPE_POINTER) {
return type_equal(O->pointer.of, T->pointer.of);
} else if(O->type == TYPE_TYPE_ARRAY) {
if(!type_equal(O->array.of, T->array.of)) {
return 0;
}
if(O->array.lengthIsGeneric != T->array.lengthIsGeneric) {
return 0;
}
if(O->array.lengthIsGeneric) {
return O->array.lengthGenericParamIdx == T->array.lengthGenericParamIdx && !strcmp(O->array.lengthGenericParamName, T->array.lengthGenericParamName);
} else {
return O->array.length == T->array.length;
}
} else if(O->type == TYPE_TYPE_FUNCTION) {
if(!type_equal(O->function.ret, T->function.ret)) {
return 0;
}
if(O->function.argCount != T->function.argCount) {
return 0;
}
for(int i = 0; i < O->function.argCount; i++) {
if(!type_equal(O->function.args[i], T->function.args[i])) {
return 0;
}
// Don't compare argument names
}
return 1;
}
/* Consider nominal typing. */
return 0;
}
/* TODO: cache */
Type *type_pointer_wrap(Type *t) {
TypePointer *ret = calloc(1, sizeof(*ret));
ret->type = TYPE_TYPE_POINTER;
ret->of = t;
return (Type*) ret;
}
int type_is_number(Type *t) {
return t->type == TYPE_TYPE_POINTER || t->type == TYPE_TYPE_PRIMITIVE;
}
int type_is_castable(Type *from, Type *to) {
if(type_equal(from, to)) return 2;
if(from->type == TYPE_TYPE_POINTER && to->type == TYPE_TYPE_POINTER) {
return 2;
}
if(from->type == TYPE_TYPE_PRIMITIVE && to->type == TYPE_TYPE_PRIMITIVE) {
if(from->primitive.width > to->primitive.width) {
return 1;
} else {
return 2;
}
}
if(from->type == TYPE_TYPE_PRIMITIVE && to->type == TYPE_TYPE_POINTER) {
return 2;
}
return 0;
}
bool type_is_generic(Type *t) {
if(t->type == TYPE_TYPE_GENERIC) {
return true;
} else if(t->type == TYPE_TYPE_FUNCTION) {
if(type_is_generic(t->function.ret)) {
return true;
}
for(int i = 0; i < t->function.argCount; i++) {
if(type_is_generic(t->function.args[i])) {
return true;
}
}
} else if(t->type == TYPE_TYPE_RECORD) {
for(int i = 0; i < t->record.fieldCount; i++) {
if(type_is_generic(t->record.fieldTypes[i])) {
return true;
}
}
} else if(t->type == TYPE_TYPE_POINTER) {
return type_is_generic(t->pointer.of);
} else if(t->type == TYPE_TYPE_ARRAY) {
return type_is_generic(t->array.of) || t->array.lengthIsGeneric;
}
return false;
}
static void *parametrization_get_by_index(Parametrization *list, size_t idx) {
for(size_t i = 0; list && i < idx; i++) {
list = list->next;
}
return list ? list->param : NULL;
}
static void parametrization_set_by_index(Parametrization **list, size_t idx, void *param) {
if(*list == NULL) {
*list = calloc(1, sizeof(Parametrization));
}
for(size_t i = 1; i <= idx; i++) {
if((*list)->next == NULL) {
(*list)->next = calloc(1, sizeof(Parametrization));
}
list = &(*list)->next;
}
(*list)->param = param;
}
Type *type_parametrize(Type *t, Parametrizations *parametrizations, Parametrizations *renames) {
if(t->type == TYPE_TYPE_RECORD) {
t = type_shallow_copy(t);
for(size_t f = 0; f < t->record.fieldCount; f++) {
t->record.fieldTypes[f] = type_parametrize(t->record.fieldTypes[f], parametrizations, renames);
}
if(!type_is_generic(t)) {
// Now that everything is concrete we may set the field offsets
size_t nextOffset = 0;
for(size_t f = 0; f < t->record.fieldCount; f++) {
t->record.fieldOffsets[f] = nextOffset;
nextOffset += type_size(t->record.fieldTypes[f]);
}
}
} else if(t->type == TYPE_TYPE_FUNCTION) {
t = type_shallow_copy(t);
t->function.ret = type_parametrize(t->function.ret, parametrizations, renames);
for(size_t i = 0; i < t->function.argCount; i++) {
t->function.args[i] = type_parametrize(t->function.args[i], parametrizations, renames);
}
} else if(t->type == TYPE_TYPE_GENERIC) {
Type *newt = parametrization_get_by_index(parametrizations->typeParams, t->generic.paramIdx);
if(renames) {
parametrization_set_by_index(&renames->typeParams, t->generic.paramIdx, t);
}
if(newt) {
return newt;
}
} else if(t->type == TYPE_TYPE_POINTER) {
t = type_shallow_copy(t);
t->pointer.of = type_parametrize(t->pointer.of, parametrizations, renames);
} else if(t->type == TYPE_TYPE_ARRAY) {
t = type_shallow_copy(t);
t->array.of = type_parametrize(t->array.of, parametrizations, renames);
if(t->array.lengthIsGeneric) {
AST *n = parametrization_get_by_index(parametrizations->intParams, t->array.lengthGenericParamIdx);
if(n) {
while(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR && n->exprVar.thing->data.cexpr.concrete) {
n = n->exprVar.thing->data.cexpr.concrete;
}
if(n->nodeKind == AST_EXPR_PRIMITIVE) {
t->array.length = n->exprPrim.val;
t->array.lengthIsGeneric = false;
} else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR) {
t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx;
t->array.lengthGenericParamName = n->exprVar.thing->data.cexpr.paramName;
t->array.lengthIsGeneric = true;
} else {
stahp_node(n, "Invalid parametrization expression.");
}
}
parametrization_set_by_index(&renames->intParams, t->array.lengthGenericParamIdx, t->array.lengthGenericParamName);
}
}
return t;
}
Type *type_shallow_copy(Type *t) {
if(t->type == TYPE_TYPE_PRIMITIVE) {
Type *n = calloc(1, sizeof(TypePrimitive));
memcpy(n, t, sizeof(TypePrimitive));
return n;
} else if(t->type == TYPE_TYPE_POINTER) {
Type *n = calloc(1, sizeof(TypePointer));
memcpy(n, t, sizeof(TypePointer));
return n;
} else if(t->type == TYPE_TYPE_ARRAY) {
Type *n = calloc(1, sizeof(TypeArray));
memcpy(n, t, sizeof(TypeArray));
return n;
} else if(t->type == TYPE_TYPE_GENERIC) {
Type *n = calloc(1, sizeof(TypeGeneric));
memcpy(n, t, sizeof(TypeGeneric));
return n;
} else if(t->type == TYPE_TYPE_FUNCTION) {
Type *n = calloc(1, sizeof(TypeFunction));
n->type = TYPE_TYPE_FUNCTION;
n->function.ret = t->function.ret;
n->function.argCount = t->function.argCount;
n->function.argNames = calloc(n->function.argCount, sizeof(*n->function.argNames));
memcpy(n->function.argNames, t->function.argNames, n->function.argCount * sizeof(*n->function.argNames));
n->function.args = calloc(n->function.argCount, sizeof(*n->function.args));
memcpy(n->function.args, t->function.args, n->function.argCount * sizeof(*n->function.args));
return n;
} else if(t->type == TYPE_TYPE_RECORD) {
Type *n = calloc(1, sizeof(TypeRecord));
n->type = TYPE_TYPE_RECORD;
n->record.name = strdup(t->record.name);
n->record.fieldCount = t->record.fieldCount;
n->record.fieldNames = calloc(n->record.fieldCount, sizeof(*n->record.fieldNames));
memcpy(n->record.fieldNames, t->record.fieldNames, n->record.fieldCount * sizeof(*n->record.fieldNames));
n->record.fieldTypes = calloc(n->record.fieldCount, sizeof(*n->record.fieldTypes));
memcpy(n->record.fieldTypes, t->record.fieldTypes, n->record.fieldCount * sizeof(*n->record.fieldTypes));
n->record.fieldOffsets = calloc(n->record.fieldCount, sizeof(*n->record.fieldOffsets));
memcpy(n->record.fieldOffsets, t->record.fieldOffsets, n->record.fieldCount * sizeof(*n->record.fieldOffsets));
return n;
}
abort();
}