#include"types.h" #include"utils.h" #include #include #include #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(); }