harec

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

typedef.c (12152B)


      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_TAGGED:
    142 		emit_const(expr->constant.tagged.value, out);
    143 		fprintf(out, ": ");
    144 		emit_type(expr->constant.tagged.tag, out);
    145 		break;
    146 	case STORAGE_ARRAY: {
    147 		fprintf(out, "[");
    148 		const struct type *t = type_dealias(expr->result);
    149 		struct array_constant *item = val->array;
    150 		if (t->array.expandable) {
    151 			emit_const(item->value, out);
    152 			fprintf(out, "...");
    153 		} else {
    154 			for (size_t i = 0; i < t->array.length; i += 1) {
    155 				if (i > 0) {
    156 					fprintf(out, ",");
    157 				}
    158 				emit_const(item->value, out);
    159 				item = item->next;
    160 			};
    161 		}
    162 		fprintf(out, "]");
    163 		break;
    164 	}
    165 	case STORAGE_SLICE:
    166 	case STORAGE_STRUCT:
    167 	case STORAGE_TUPLE:
    168 	case STORAGE_UNION:
    169 		assert(0); // TODO
    170 	case STORAGE_ALIAS:
    171 	case STORAGE_CHAR:
    172 	case STORAGE_ERROR:
    173 	case STORAGE_FUNCTION:
    174 	case STORAGE_POINTER:
    175 	case STORAGE_VALIST:
    176 		assert(0); // Invariant
    177 	}
    178 }
    179 
    180 static int
    181 field_compar(const void *_a, const void *_b)
    182 {
    183 	const struct struct_field **a = (const struct struct_field **)_a;
    184 	const struct struct_field **b = (const struct struct_field **)_b;
    185 	return (*a)->offset - (*b)->offset;
    186 }
    187 
    188 static bool
    189 emit_struct(const struct type *type, FILE *out)
    190 {
    191 	bool ret = true;
    192 	size_t n = 0;
    193 	for (const struct struct_field *f = type->struct_union.fields;
    194 			f; f = f->next) {
    195 		++n;
    196 	}
    197 	const struct struct_field **fields = xcalloc(
    198 		sizeof(const struct struct_field *), n);
    199 	n = 0;
    200 	for (const struct struct_field *f = type->struct_union.fields;
    201 			f; f = f->next) {
    202 		fields[n++] = f;
    203 	}
    204 
    205 	qsort(fields, n, sizeof(fields[0]), field_compar);
    206 
    207 	fprintf(out, "%s %s{ ",
    208 			type->storage == STORAGE_STRUCT ? "struct" : "union",
    209 			type->struct_union.packed ? "@packed " : "");
    210 	for (size_t i = 0; i < n; ++i) {
    211 		const struct struct_field *f = fields[i];
    212 		if (!type->struct_union.c_compat) {
    213 			fprintf(out, "@offset(%zd) ", f->offset);
    214 		}
    215 		if (f->name) {
    216 			fprintf(out, "%s: ", f->name);
    217 		}
    218 		ret &= emit_type(f->type, out);
    219 		fprintf(out, ", ");
    220 	}
    221 	fprintf(out, "}");
    222 	return ret;
    223 }
    224 
    225 bool
    226 emit_type(const struct type *type, FILE *out)
    227 {
    228 	bool ret = true;
    229 	if (type->flags & TYPE_CONST) {
    230 		fprintf(out, "const ");
    231 	}
    232 	if (type->flags & TYPE_ERROR) {
    233 		fprintf(out, "!");
    234 	}
    235 
    236 	char *ident;
    237 	switch (type->storage) {
    238 	case STORAGE_BOOL:
    239 	case STORAGE_CHAR:
    240 	case STORAGE_ERROR:
    241 	case STORAGE_F32:
    242 	case STORAGE_F64:
    243 	case STORAGE_FCONST:
    244 	case STORAGE_I16:
    245 	case STORAGE_I32:
    246 	case STORAGE_I64:
    247 	case STORAGE_I8:
    248 	case STORAGE_INT:
    249 	case STORAGE_NULL:
    250 	case STORAGE_RCONST:
    251 	case STORAGE_RUNE:
    252 	case STORAGE_SIZE:
    253 	case STORAGE_STRING:
    254 	case STORAGE_U16:
    255 	case STORAGE_U32:
    256 	case STORAGE_U64:
    257 	case STORAGE_U8:
    258 	case STORAGE_UINT:
    259 	case STORAGE_UINTPTR:
    260 	case STORAGE_VALIST:
    261 	case STORAGE_VOID:
    262 		fprintf(out, "%s", type_storage_unparse(type->storage));
    263 		break;
    264 	case STORAGE_POINTER:
    265 		fprintf(out, "%s*", type->pointer.flags & PTR_NULLABLE
    266 				? "nullable " : "");
    267 		ret &= emit_type(type->pointer.referent, out);
    268 		break;
    269 	case STORAGE_ARRAY:
    270 		if (type->array.length == SIZE_UNDEFINED) {
    271 			fprintf(out, "[*]");
    272 		} else {
    273 			fprintf(out, "[%zd]", type->array.length);
    274 		}
    275 		ret &= emit_type(type->array.members, out);
    276 		break;
    277 	case STORAGE_SLICE:
    278 		fprintf(out, "[]");
    279 		ret &= emit_type(type->array.members, out);
    280 		break;
    281 	case STORAGE_ALIAS:
    282 		ret &= type->alias.exported;
    283 		ident = identifier_unparse(&type->alias.ident);
    284 		fprintf(out, "%s", ident);
    285 		free(ident);
    286 		break;
    287 	case STORAGE_TAGGED:
    288 		fprintf(out, "(");
    289 		for (const struct type_tagged_union *tu = &type->tagged;
    290 				tu; tu = tu->next) {
    291 			ret &= emit_type(tu->type, out);
    292 			if (tu->next) {
    293 				fprintf(out, " | ");
    294 			}
    295 		}
    296 		fprintf(out, ")");
    297 		break;
    298 	case STORAGE_STRUCT:
    299 	case STORAGE_UNION:
    300 		ret &= emit_struct(type, out);
    301 		break;
    302 	case STORAGE_FUNCTION:
    303 		if (type->func.flags & FN_NORETURN) {
    304 			fprintf(out, "@noreturn ");
    305 		}
    306 		fprintf(out, "fn(");
    307 		for (const struct type_func_param *param = type->func.params;
    308 				param; param = param->next) {
    309 			fprintf(out, "_: ");
    310 			if (param->next) {
    311 				ret &= emit_type(param->type, out);
    312 				fprintf(out, ", ");
    313 			} else if (type->func.variadism == VARIADISM_HARE) {
    314 				ret &= emit_type(param->type->array.members, out);
    315 				fprintf(out, "...");
    316 			} else if (type->func.variadism == VARIADISM_C) {
    317 				ret &= emit_type(param->type, out);
    318 				fprintf(out, ", ...");
    319 			} else {
    320 				ret &= emit_type(param->type, out);
    321 			}
    322 		}
    323 		fprintf(out, ") ");
    324 		ret &= emit_type(type->func.result, out);
    325 		break;
    326 	case STORAGE_ENUM:
    327 		ret &= type->alias.exported;
    328 		ident = identifier_unparse(&type->alias.ident);
    329 		fprintf(out, "%s", ident);
    330 		free(ident);
    331 		break;
    332 	case STORAGE_TUPLE:
    333 		fprintf(out, "(");
    334 		for (const struct type_tuple *tuple = &type->tuple;
    335 				tuple; tuple = tuple->next) {
    336 			ret &= emit_type(tuple->type, out);
    337 			if (tuple->next) {
    338 				fprintf(out, ", ");
    339 			}
    340 		}
    341 		fprintf(out, ")");
    342 		break;
    343 	case STORAGE_ICONST:
    344 		fprintf(out, "[iconst min=%jd max=%jd]", type->_const.min,
    345 			type->_const.max);
    346 		break;
    347 	}
    348 	return ret;
    349 }
    350 
    351 static void
    352 emit_exported_type(const struct type *type, FILE *out, const char *ident)
    353 {
    354 	if (!emit_type(type, out)) {
    355 		// XXX: Hack
    356 		struct type *_type = (struct type *)type;
    357 		_type->alias.exported = true;
    358 		fprintf(stderr, "Cannot use unexported type ");
    359 		emit_type(type, stderr);
    360 		fprintf(stderr, " in exported declaration '%s'\n", ident);
    361 		exit(EXIT_FAILURE);
    362 	}
    363 }
    364 
    365 static void
    366 emit_decl_const(struct declaration *decl, FILE *out)
    367 {
    368 	char *ident = identifier_unparse(&decl->ident);
    369 	fprintf(out, "export def %s: ", ident);
    370 	if (decl->constant.type) {
    371 		emit_exported_type(decl->constant.type, out, ident);
    372 	} else {
    373 		emit_exported_type(decl->constant.value->result, out, ident);
    374 	};
    375 	free(ident);
    376 	fprintf(out, " = ");
    377 	emit_const(decl->constant.value, out);
    378 	fprintf(out, ";\n");
    379 }
    380 
    381 static void
    382 emit_decl_func(struct declaration *decl, FILE *out)
    383 {
    384 	char *ident = identifier_unparse(&decl->ident);
    385 	const struct type *fntype = decl->func.type;
    386 	fprintf(out, "export");
    387 	if (decl->symbol) {
    388 		fprintf(out, " @symbol(\"%s\")", decl->symbol);
    389 	}
    390 	fprintf(out, "%s fn %s(",
    391 		(fntype->func.flags & FN_NORETURN) ? " @noreturn" : "",
    392 		ident);
    393 
    394 	for (struct type_func_param *param = fntype->func.params;
    395 			param; param = param->next) {
    396 		fprintf(out, "_: ");
    397 		if (param->next) {
    398 			emit_exported_type(param->type, out, ident);
    399 			fprintf(out, ", ");
    400 		} else if (fntype->func.variadism == VARIADISM_HARE) {
    401 			emit_exported_type(param->type->array.members, out, ident);
    402 			fprintf(out, "...");
    403 		} else if (fntype->func.variadism == VARIADISM_C) {
    404 			emit_exported_type(param->type, out, ident);
    405 			fprintf(out, ", ...");
    406 		} else {
    407 			emit_exported_type(param->type, out, ident);
    408 		}
    409 	}
    410 
    411 	fprintf(out, ") ");
    412 	emit_exported_type(fntype->func.result, out, ident);
    413 	fprintf(out, ";\n");
    414 	free(ident);
    415 }
    416 
    417 static void
    418 emit_decl_global(struct declaration *decl, FILE *out)
    419 {
    420 	char *ident = identifier_unparse(&decl->ident);
    421 	fprintf(out, "export let ");
    422 	if (decl->symbol) {
    423 		fprintf(out, "@symbol(\"%s\") ", decl->symbol);
    424 	}
    425 	if (decl->global.threadlocal) {
    426 		fprintf(out, "@threadlocal ");
    427 	}
    428 	fprintf(out, "%s: ", ident);
    429 	if (decl->constant.type) {
    430 		emit_exported_type(decl->global.type, out, ident);
    431 	} else {
    432 		emit_exported_type(decl->global.value->result, out, ident);
    433 	};
    434 	fprintf(out, ";\n");
    435 	free(ident);
    436 }
    437 
    438 static void
    439 emit_decl_type(struct declaration *decl, FILE *out)
    440 {
    441 	char *ident = identifier_unparse(&decl->ident);
    442 	fprintf(out, "export type %s = ", ident);
    443 	assert(decl->_type->storage == STORAGE_ALIAS
    444 			|| decl->_type->storage == STORAGE_ENUM);
    445 	if (decl->_type->storage == STORAGE_ENUM) {
    446 		const struct type *type = decl->_type;
    447 		fprintf(out, "enum %s { ",
    448 			type_storage_unparse(type->alias.type->storage));
    449 		for (const struct scope_object *ev = type->_enum.values->objects;
    450 				ev; ev = ev->lnext) {
    451 			assert(ev->otype != O_SCAN);
    452 			fprintf(out, "%s = ", ev->name.name);
    453 			emit_const(ev->value, out);
    454 			fprintf(out, ", ");
    455 		}
    456 		fprintf(out, "}");
    457 	} else {
    458 		emit_exported_type(decl->_type->alias.type, out, ident);
    459 	}
    460 	fprintf(out, "; // size: %zd, align: %zd, id: %u\n",
    461 		decl->_type->size, decl->_type->align, decl->_type->id);
    462 	free(ident);
    463 }
    464 
    465 void
    466 emit_typedefs(struct unit *unit, FILE *out)
    467 {
    468 	for (struct identifiers *imports = unit->imports;
    469 			imports; imports = imports->next) {
    470 		char *ident = identifier_unparse(&imports->ident);
    471 		fprintf(out, "use %s;\n", ident);
    472 		free(ident);
    473 	}
    474 
    475 	for (struct declarations *decls = unit->declarations;
    476 			decls; decls = decls->next) {
    477 		struct declaration *decl = decls->decl;
    478 		if (!decl->exported) {
    479 			continue;
    480 		}
    481 
    482 		switch (decl->type) {
    483 		case DECL_CONST:
    484 			emit_decl_const(decl, out);
    485 			break;
    486 		case DECL_FUNC:
    487 			emit_decl_func(decl, out);
    488 			break;
    489 		case DECL_GLOBAL:
    490 			emit_decl_global(decl, out);
    491 			break;
    492 		case DECL_TYPE:
    493 			emit_decl_type(decl, out);
    494 			break;
    495 		}
    496 	}
    497 }