385 lines
9.7 KiB
C
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();
|
|
}
|