import "std/common.cup" import "std/vector.cup" enum BaseType { TYPE_VOID, TYPE_ANY, TYPE_PTR, TYPE_ARRAY, TYPE_STRUCT, TYPE_UNION, TYPE_INT, TYPE_CHAR, }; struct Type { typ: int; ptr: Type*; struct_name: char*; size: int; array_size: int; fields: Vector*; // Vector; }; fn size_for_base_type(type: int): int { if (type == TYPE_INT) return 8; if (type == TYPE_PTR) return 8; if (type == TYPE_CHAR) return 1; // Need to be initialized explicitly for compound types return 0; } fn size_for_type(typ: Type*): int { if (typ.typ == TYPE_INT) return 8; if (typ.typ == TYPE_PTR) return 8; if (typ.typ == TYPE_CHAR) return 1; if (typ.typ == TYPE_ARRAY) return typ.array_size * size_for_type(typ.ptr); if (typ.typ == TYPE_STRUCT) return typ.size; if (typ.typ == TYPE_UNION) return typ.size; if (typ.typ == TYPE_VOID) return 0; if (typ.typ == TYPE_ANY) return 8; die("Unknown type in size_for_type"); } let _type_int: Type* = null; let _type_char: Type* = null; let _type_void: Type* = null; let _type_any: Type* = null; fn type_new(typ: int): Type* { if (_type_int == null) { _type_int = malloc(sizeof(Type)); _type_int.typ = TYPE_INT; _type_int.size = 8; } if (_type_char == null) { _type_char = malloc(sizeof(Type)); _type_char.typ = TYPE_CHAR; _type_char.size = 1; } if (_type_void == null) { _type_void = malloc(sizeof(Type)); _type_void.typ = TYPE_VOID; _type_void.size = 0; } if (_type_any == null) { _type_any = malloc(sizeof(Type)); _type_any.typ = TYPE_ANY; _type_any.size = 8; } if (typ == TYPE_INT) return _type_int; if (typ == TYPE_CHAR) return _type_char; if (typ == TYPE_VOID) return _type_void; if (typ == TYPE_ANY) return _type_any; let t: Type* = malloc(sizeof(Type)); t.typ = typ; t.size = size_for_base_type(typ); return t; } fn type_new_ptr(typ: int): Type* { let ptr = type_new(TYPE_PTR); ptr.ptr = type_new(typ); return ptr; } // This is named differently because it performs an allocation fn create_type_string(typ: Type *): char* { let buf: char* = malloc(32); while (typ.typ == TYPE_PTR || typ.typ == TYPE_ARRAY) { strcat(buf, typ.typ == TYPE_PTR ? "*" : "[]"); typ = typ.ptr; } if (typ.typ == TYPE_INT) strcat(buf, "int"); else if (typ.typ == TYPE_CHAR) strcat(buf, "char"); else if (typ.typ == TYPE_VOID) strcat(buf, "void"); else if (typ.typ == TYPE_ANY) strcat(buf, "any"); else if (typ.typ == TYPE_STRUCT) strcat(buf, typ.struct_name); else die("create_type_string: unknown type"); return buf; } fn is_int_type(typ: Type*): int { if (typ.typ == TYPE_INT) return true; if (typ.typ == TYPE_CHAR) return true; return false; } fn types_equal(a: Type*, b: Type*): int { if (a == null && b == null) return true; if (a == null || b == null) return false; if (a.typ == TYPE_ANY || b.typ == TYPE_ANY) return true; return a.typ == b.typ && types_equal(a.ptr, b.ptr); } fn is_convertible(from: Type*, to: Type*): int { if (from.typ == TYPE_ANY || to.typ == TYPE_ANY) return true; // Allow converstions to and from void* to any other pointer type if (from.typ == TYPE_PTR && to.typ == TYPE_PTR) if (from.ptr.typ == TYPE_VOID || to.ptr.typ == TYPE_VOID) return true; // TODO: Should we rause a warning if the target type is narrower // than the source type? if (is_int_type(from) && is_int_type(to)) return true; return types_equal(from, to); } fn is_struct_or_structptr(typ: Type*): int { if (typ.typ == TYPE_STRUCT || typ.typ == TYPE_UNION) return true; if (typ.typ == TYPE_PTR) if (typ.ptr.typ == TYPE_STRUCT || typ.ptr.typ == TYPE_UNION) return true; return false; }