harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

typedef.c (11255B)


      1 #include <assert.h>
      2 #include <ctype.h>
      3 #include <inttypes.h>
      4 #include <math.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include "check.h"
      8 #include "expr.h"
      9 #include "identifier.h"
     10 #include "typedef.h"
     11 #include "util.h"
     12 
     13 static const char *
     14 storage_to_suffix(enum type_storage storage)
     15 {
     16 	switch (storage) {
     17 	case STORAGE_CHAR:
     18 		return "";
     19 	case STORAGE_F32:
     20 		return "f32";
     21 	case STORAGE_F64:
     22 		return "f64";
     23 	case STORAGE_FCONST:
     24 		return "";
     25 	case STORAGE_I16:
     26 		return "i16";
     27 	case STORAGE_I32:
     28 		return "i32";
     29 	case STORAGE_I64:
     30 		return "i64";
     31 	case STORAGE_I8:
     32 		return "i8";
     33 	case STORAGE_ICONST:
     34 		return "";
     35 	case STORAGE_INT:
     36 		return "i";
     37 	case STORAGE_SIZE:
     38 		return "z";
     39 	case STORAGE_U16:
     40 		return "u16";
     41 	case STORAGE_U32:
     42 		return "u32";
     43 	case STORAGE_U64:
     44 		return "u64";
     45 	case STORAGE_U8:
     46 		return "u8";
     47 	case STORAGE_UINT:
     48 		return "u";
     49 	case STORAGE_UINTPTR:
     50 		return "u64: uintptr";
     51 	case STORAGE_VALIST:
     52 		return "valist";
     53 	default:
     54 		assert(0);
     55 	}
     56 }
     57 
     58 static void
     59 emit_const(const struct expression *expr, FILE *out)
     60 {
     61 	assert(expr->type == EXPR_CONSTANT);
     62 	const struct expression_constant *val = &expr->constant;
     63 	assert(!val->object);
     64 	switch (type_dealias(expr->result)->storage) {
     65 	case STORAGE_BOOL:
     66 		fprintf(out, "%s", val->bval ? "true" : "false");
     67 		break;
     68 	case STORAGE_F32:
     69 	case STORAGE_F64:
     70 	case STORAGE_FCONST:
     71 	{
     72 		const char *suffix = storage_to_suffix(expr->result->storage);
     73 		if (isnan(val->fval)) {
     74 			fprintf(out, "0.0%s / 0.0%s", suffix, suffix);
     75 		} else if (isinf(val->fval)) {
     76 			fprintf(out, "%s1.0%s / 0.0%s",
     77 				(val->fval > 0) ? "" : "-", suffix, suffix);
     78 		} else {
     79 			fprintf(out, "%lf%s", val->fval, suffix);
     80 		}
     81 		break;
     82 	}
     83 	case STORAGE_I16:
     84 	case STORAGE_I32:
     85 	case STORAGE_I64:
     86 	case STORAGE_I8:
     87 	case STORAGE_ICONST:
     88 	case STORAGE_INT:
     89 		fprintf(out, "%" PRIiMAX "%s", val->ival,
     90 			storage_to_suffix(type_dealias(expr->result)->storage));
     91 		break;
     92 	case STORAGE_NULL:
     93 		fprintf(out, "null");
     94 		break;
     95 	case STORAGE_SIZE:
     96 	case STORAGE_U16:
     97 	case STORAGE_U32:
     98 	case STORAGE_U64:
     99 	case STORAGE_U8:
    100 	case STORAGE_UINT:
    101 	case STORAGE_UINTPTR:
    102 		fprintf(out, "%" PRIuMAX "%s", val->uval,
    103 			storage_to_suffix(type_dealias(expr->result)->storage));
    104 		break;
    105 	case STORAGE_VOID:
    106 		fprintf(out, "void");
    107 		break;
    108 	case STORAGE_RCONST:
    109 	case STORAGE_RUNE:
    110 		fprintf(out, "\'\\U%08" PRIx32 "\'", (uint32_t)val->uval);
    111 		break;
    112 	case STORAGE_STRING:
    113 		fprintf(out, "\"");
    114 		for (size_t i = 0; i < val->string.len; i += 1) {
    115 			char c = val->string.value[i];
    116 			if (isalnum((unsigned char)c)) {
    117 				fprintf(out, "%c", c);
    118 			} else {
    119 				fprintf(out, "\\x%02X", c);
    120 			}
    121 		};
    122 		fprintf(out, "\"");
    123 		break;
    124 	case STORAGE_ENUM: {
    125 		const struct type *t = type_dealias(expr->result);
    126 		char *ident = identifier_unparse(&expr->result->alias.ident);
    127 		if (t->alias.type->storage == STORAGE_CHAR) {
    128 			fprintf(out, "%" PRIuMAX, val->uval);
    129 		} else if (t->alias.type->storage == STORAGE_UINTPTR) {
    130 			fprintf(out, "%" PRIuMAX ": uintptr", val->uval);
    131 		} else if (type_is_signed(t->alias.type)) {
    132 			fprintf(out, "%" PRIiMAX "%s: %s", val->ival,
    133 				storage_to_suffix(t->alias.type->storage), ident);
    134 		} else {
    135 			fprintf(out, "%" PRIuMAX "%s: %s", val->uval,
    136 				storage_to_suffix(t->alias.type->storage), ident);
    137 		}
    138 		free(ident);
    139 		break;
    140 	}
    141 	case STORAGE_ALIAS:
    142 	case STORAGE_ARRAY:
    143 	case STORAGE_SLICE:
    144 	case STORAGE_STRUCT:
    145 	case STORAGE_TUPLE:
    146 	case STORAGE_UNION:
    147 		assert(0); // TODO
    148 	case STORAGE_CHAR:
    149 	case STORAGE_FUNCTION:
    150 	case STORAGE_POINTER:
    151 	case STORAGE_TAGGED:
    152 	case STORAGE_VALIST:
    153 		assert(0); // Invariant
    154 	}
    155 }
    156 
    157 static int
    158 field_compar(const void *_a, const void *_b)
    159 {
    160 	const struct struct_field **a = (const struct struct_field **)_a;
    161 	const struct struct_field **b = (const struct struct_field **)_b;
    162 	return (*a)->offset - (*b)->offset;
    163 }
    164 
    165 static bool
    166 emit_struct(const struct type *type, FILE *out)
    167 {
    168 	bool ret = true;
    169 	size_t n = 0;
    170 	for (const struct struct_field *f = type->struct_union.fields;
    171 			f; f = f->next) {
    172 		++n;
    173 	}
    174 	const struct struct_field **fields = xcalloc(
    175 		sizeof(const struct struct_field *), n);
    176 	n = 0;
    177 	for (const struct struct_field *f = type->struct_union.fields;
    178 			f; f = f->next) {
    179 		fields[n++] = f;
    180 	}
    181 
    182 	qsort(fields, n, sizeof(fields[0]), field_compar);
    183 
    184 	fprintf(out, "%s { ", type->storage == STORAGE_STRUCT
    185 			? "struct" : "union");
    186 	for (size_t i = 0; i < n; ++i) {
    187 		const struct struct_field *f = fields[i];
    188 		if (!type->struct_union.c_compat) {
    189 			fprintf(out, "@offset(%zd) ", f->offset);
    190 		}
    191 		if (f->name) {
    192 			fprintf(out, "%s: ", f->name);
    193 		}
    194 		ret &= emit_type(f->type, out);
    195 		fprintf(out, ", ");
    196 	}
    197 	fprintf(out, "}");
    198 	return ret;
    199 }
    200 
    201 bool
    202 emit_type(const struct type *type, FILE *out)
    203 {
    204 	bool ret = true;
    205 	if (type->flags & TYPE_CONST) {
    206 		fprintf(out, "const ");
    207 	}
    208 	if (type->flags & TYPE_ERROR) {
    209 		fprintf(out, "!");
    210 	}
    211 
    212 	char *ident;
    213 	switch (type->storage) {
    214 	case STORAGE_BOOL:
    215 	case STORAGE_CHAR:
    216 	case STORAGE_F32:
    217 	case STORAGE_F64:
    218 	case STORAGE_FCONST:
    219 	case STORAGE_I16:
    220 	case STORAGE_I32:
    221 	case STORAGE_I64:
    222 	case STORAGE_I8:
    223 	case STORAGE_INT:
    224 	case STORAGE_NULL:
    225 	case STORAGE_RCONST:
    226 	case STORAGE_RUNE:
    227 	case STORAGE_SIZE:
    228 	case STORAGE_STRING:
    229 	case STORAGE_U16:
    230 	case STORAGE_U32:
    231 	case STORAGE_U64:
    232 	case STORAGE_U8:
    233 	case STORAGE_UINT:
    234 	case STORAGE_UINTPTR:
    235 	case STORAGE_VALIST:
    236 	case STORAGE_VOID:
    237 		fprintf(out, "%s", type_storage_unparse(type->storage));
    238 		break;
    239 	case STORAGE_POINTER:
    240 		fprintf(out, "%s*", type->pointer.flags & PTR_NULLABLE
    241 				? "nullable " : "");
    242 		ret &= emit_type(type->pointer.referent, out);
    243 		break;
    244 	case STORAGE_ARRAY:
    245 		if (type->array.length == SIZE_UNDEFINED) {
    246 			fprintf(out, "[*]");
    247 		} else {
    248 			fprintf(out, "[%zd]", type->array.length);
    249 		}
    250 		ret &= emit_type(type->array.members, out);
    251 		break;
    252 	case STORAGE_SLICE:
    253 		fprintf(out, "[]");
    254 		ret &= emit_type(type->array.members, out);
    255 		break;
    256 	case STORAGE_ALIAS:
    257 		ret &= type->alias.exported;
    258 		ident = identifier_unparse(&type->alias.ident);
    259 		fprintf(out, "%s", ident);
    260 		free(ident);
    261 		break;
    262 	case STORAGE_TAGGED:
    263 		fprintf(out, "(");
    264 		for (const struct type_tagged_union *tu = &type->tagged;
    265 				tu; tu = tu->next) {
    266 			ret &= emit_type(tu->type, out);
    267 			if (tu->next) {
    268 				fprintf(out, " | ");
    269 			}
    270 		}
    271 		fprintf(out, ")");
    272 		break;
    273 	case STORAGE_STRUCT:
    274 	case STORAGE_UNION:
    275 		ret &= emit_struct(type, out);
    276 		break;
    277 	case STORAGE_FUNCTION:
    278 		if (type->func.flags & FN_NORETURN) {
    279 			fprintf(out, "@noreturn ");
    280 		}
    281 		fprintf(out, "fn(");
    282 		for (const struct type_func_param *param = type->func.params;
    283 				param; param = param->next) {
    284 			fprintf(out, "_: ");
    285 			if (param->next) {
    286 				ret &= emit_type(param->type, out);
    287 				fprintf(out, ", ");
    288 			} else if (type->func.variadism == VARIADISM_HARE) {
    289 				ret &= emit_type(param->type->array.members, out);
    290 				fprintf(out, "...");
    291 			} else if (type->func.variadism == VARIADISM_C) {
    292 				ret &= emit_type(param->type, out);
    293 				fprintf(out, ", ...");
    294 			} else {
    295 				ret &= emit_type(param->type, out);
    296 			}
    297 		}
    298 		fprintf(out, ") ");
    299 		ret &= emit_type(type->func.result, out);
    300 		break;
    301 	case STORAGE_ENUM:
    302 		ret &= type->alias.exported;
    303 		ident = identifier_unparse(&type->alias.ident);
    304 		fprintf(out, "%s", ident);
    305 		free(ident);
    306 		break;
    307 	case STORAGE_TUPLE:
    308 		fprintf(out, "(");
    309 		for (const struct type_tuple *tuple = &type->tuple;
    310 				tuple; tuple = tuple->next) {
    311 			ret &= emit_type(tuple->type, out);
    312 			if (tuple->next) {
    313 				fprintf(out, ", ");
    314 			}
    315 		}
    316 		fprintf(out, ")");
    317 		break;
    318 	case STORAGE_ICONST:
    319 		fprintf(out, "[iconst min=%jd max=%jd]", type->_const.min,
    320 			type->_const.max);
    321 		break;
    322 	}
    323 	return ret;
    324 }
    325 
    326 static void
    327 emit_exported_type(const struct type *type, FILE *out, const char *ident)
    328 {
    329 	if (!emit_type(type, out)) {
    330 		// XXX: Hack
    331 		struct type *_type = (struct type *)type;
    332 		_type->alias.exported = true;
    333 		fprintf(stderr, "Cannot use unexported type ");
    334 		emit_type(type, stderr);
    335 		fprintf(stderr, " in exported declaration '%s'\n", ident);
    336 		exit(EXIT_FAILURE);
    337 	}
    338 }
    339 
    340 static void
    341 emit_decl_const(struct declaration *decl, FILE *out)
    342 {
    343 	char *ident = identifier_unparse(&decl->ident);
    344 	fprintf(out, "export def %s: ", ident);
    345 	emit_exported_type(decl->constant.type, out, ident);
    346 	free(ident);
    347 	fprintf(out, " = ");
    348 	emit_const(decl->constant.value, out);
    349 	fprintf(out, ";\n");
    350 }
    351 
    352 static void
    353 emit_decl_func(struct declaration *decl, FILE *out)
    354 {
    355 	char *ident = identifier_unparse(&decl->ident);
    356 	const struct type *fntype = decl->func.type;
    357 	fprintf(out, "export");
    358 	if (decl->symbol) {
    359 		fprintf(out, " @symbol(\"%s\")", decl->symbol);
    360 	}
    361 	fprintf(out, "%s fn %s(",
    362 		(fntype->func.flags & FN_NORETURN) ? " @noreturn" : "",
    363 		ident);
    364 
    365 	for (struct type_func_param *param = fntype->func.params;
    366 			param; param = param->next) {
    367 		fprintf(out, "_: ");
    368 		if (param->next) {
    369 			emit_exported_type(param->type, out, ident);
    370 			fprintf(out, ", ");
    371 		} else if (fntype->func.variadism == VARIADISM_HARE) {
    372 			emit_exported_type(param->type->array.members, out, ident);
    373 			fprintf(out, "...");
    374 		} else if (fntype->func.variadism == VARIADISM_C) {
    375 			emit_exported_type(param->type, out, ident);
    376 			fprintf(out, ", ...");
    377 		} else {
    378 			emit_exported_type(param->type, out, ident);
    379 		}
    380 	}
    381 
    382 	fprintf(out, ") ");
    383 	emit_exported_type(fntype->func.result, out, ident);
    384 	fprintf(out, ";\n");
    385 	free(ident);
    386 }
    387 
    388 static void
    389 emit_decl_global(struct declaration *decl, FILE *out)
    390 {
    391 	char *ident = identifier_unparse(&decl->ident);
    392 	fprintf(out, "export let ");
    393 	if (decl->symbol) {
    394 		fprintf(out, "@symbol(\"%s\") ", decl->symbol);
    395 	}
    396 	fprintf(out, "%s: ", ident);
    397 	emit_exported_type(decl->global.type, out, ident);
    398 	fprintf(out, ";\n");
    399 	free(ident);
    400 }
    401 
    402 static void
    403 emit_decl_type(struct declaration *decl, FILE *out)
    404 {
    405 	char *ident = identifier_unparse(&decl->ident);
    406 	fprintf(out, "export type %s = ", ident);
    407 	assert(decl->_type->storage == STORAGE_ALIAS
    408 			|| decl->_type->storage == STORAGE_ENUM);
    409 	if (decl->_type->storage == STORAGE_ENUM) {
    410 		const struct type *type = decl->_type;
    411 		fprintf(out, "enum %s { ",
    412 			type_storage_unparse(type->alias.type->storage));
    413 		for (const struct scope_object *ev = type->_enum.values->objects;
    414 				ev; ev = ev->lnext) {
    415 			if (ev->otype == O_SCAN) {
    416 				continue;
    417 			}
    418 			fprintf(out, "%s = ", ev->name.name);
    419 			emit_const(ev->value, out);
    420 			fprintf(out, ", ");
    421 		}
    422 		fprintf(out, "}");
    423 	} else {
    424 		emit_exported_type(decl->_type->alias.type, out, ident);
    425 	}
    426 	fprintf(out, "; // size: %zd, align: %zd, id: %u\n",
    427 		decl->_type->size, decl->_type->align, decl->_type->id);
    428 	free(ident);
    429 }
    430 
    431 void
    432 emit_typedefs(struct unit *unit, FILE *out)
    433 {
    434 	for (struct identifiers *imports = unit->imports;
    435 			imports; imports = imports->next) {
    436 		char *ident = identifier_unparse(&imports->ident);
    437 		fprintf(out, "use %s;\n", ident);
    438 		free(ident);
    439 	}
    440 
    441 	for (struct declarations *decls = unit->declarations;
    442 			decls; decls = decls->next) {
    443 		struct declaration *decl = decls->decl;
    444 		if (!decl->exported) {
    445 			continue;
    446 		}
    447 
    448 		switch (decl->type) {
    449 		case DECL_CONST:
    450 			emit_decl_const(decl, out);
    451 			break;
    452 		case DECL_FUNC:
    453 			emit_decl_func(decl, out);
    454 			break;
    455 		case DECL_GLOBAL:
    456 			emit_decl_global(decl, out);
    457 			break;
    458 		case DECL_TYPE:
    459 			emit_decl_type(decl, out);
    460 			break;
    461 		}
    462 	}
    463 }