Cthulhu  0.2.10
Cthulhu compiler collection
type.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 
3 #include "base/util.h"
4 #include "c89.h"
5 
6 #include "arena/arena.h"
7 #include "std/map.h"
8 #include "std/vector.h"
9 #include "std/str.h"
10 
11 #include "std/typed/vector.h"
12 
13 #include "base/panic.h"
14 
15 static const char *get_c89_digit(ssa_type_digit_t ty)
16 {
17  switch (ty.digit)
18  {
19  case eDigitChar: return (ty.sign == eSignUnsigned) ? "unsigned char" : "char";
20  case eDigitShort: return (ty.sign == eSignUnsigned) ? "unsigned short" : "short";
21  case eDigitInt: return (ty.sign == eSignUnsigned) ? "unsigned int" : "int";
22  case eDigitLong: return (ty.sign == eSignUnsigned) ? "unsigned long long" : "long long";
23  case eDigitSize: return (ty.sign == eSignSigned) ? "ptrdiff_t" : "size_t" ;
24  case eDigitPtr: return (ty.sign == eSignSigned) ? "intptr_t" : "uintptr_t";
25 
26  case eDigit8: return (ty.sign == eSignUnsigned) ? "uint8_t" : "int8_t";
27  case eDigit16: return (ty.sign == eSignUnsigned) ? "uint16_t" : "int16_t";
28  case eDigit32: return (ty.sign == eSignUnsigned) ? "uint32_t" : "int32_t";
29  case eDigit64: return (ty.sign == eSignUnsigned) ? "uint64_t" : "int64_t";
30 
31  case eDigitFast8: return (ty.sign == eSignUnsigned) ? "uint_fast8_t" : "int_fast8_t";
32  case eDigitFast16: return (ty.sign == eSignUnsigned) ? "uint_fast16_t" : "int_fast16_t";
33  case eDigitFast32: return (ty.sign == eSignUnsigned) ? "uint_fast32_t" : "int_fast32_t";
34  case eDigitFast64: return (ty.sign == eSignUnsigned) ? "uint_fast64_t" : "int_fast64_t";
35 
36  case eDigitLeast8: return (ty.sign == eSignUnsigned) ? "uint_least8_t" : "int_least8_t";
37  case eDigitLeast16: return (ty.sign == eSignUnsigned) ? "uint_least16_t" : "int_least16_t";
38  case eDigitLeast32: return (ty.sign == eSignUnsigned) ? "uint_least32_t" : "int_least32_t";
39  case eDigitLeast64: return (ty.sign == eSignUnsigned) ? "uint_least64_t" : "int_least64_t";
40 
41  case eDigitFloat: return "float";
42  case eDigitDouble: return "double";
43 
44  default: CT_NEVER("unknown digit %d", ty.digit);
45  }
46 }
47 
48 // TODO: we should emit east const types rather than west const
49 // its more consistent and should make codegen easier
50 
51 static const char *get_quals(tree_quals_t quals, type_format_t fmt, arena_t *arena)
52 {
53  if (fmt & eFormatIsConst) { return "const "; }
54  if (quals & eQualConst) { return (fmt & eFormatEmitConst) ? "const " : ""; }
55 
56  vector_t *vec = vector_new(3, arena);
57  if (quals & eQualAtomic) { vector_push(&vec, "_Atomic"); }
58  if (quals & eQualVolatile) { vector_push(&vec, "volatile"); }
59 
60  return str_join(" ", vec, arena);
61 }
62 
63 static const char *format_c89_closure(c89_emit_t *emit, const char *quals, ssa_type_closure_t type, const char *name)
64 {
65  const char *result = c89_format_type(emit, type.result, NULL, eFormatEmitConst);
66  const char *params = c89_format_params(emit, type.params, type.variadic);
67 
68  return (name == NULL)
69  ? str_format(emit->arena, "%s (*%s)(%s)", result, quals, params)
70  : str_format(emit->arena, "%s (*%s%s)(%s)", result, quals, name, params);
71 }
72 
73 static const char *format_c89_pointer(c89_emit_t *emit, ssa_type_pointer_t pointer, const char *name)
74 {
75  const char *tmp = (name == NULL) ? "*" : str_format(emit->arena, "*%s", name);
76 
77  return c89_format_type(emit, pointer.pointer, tmp, eFormatEmitConst);
78 }
79 
80 static const char *format_c89_enum(c89_emit_t *emit, const ssa_type_t *type, const char *name, const char *quals)
81 {
82  const char *padding = ctu_strlen(quals) > 0 ? " " : "";
83  return (name != NULL)
84  // TODO: this is a hack for abi stability
85  // update define_enum when this is updated
86  ? str_format(emit->arena, "%s%s%s_underlying_t %s", quals, padding, type->name, name)
87  : str_format(emit->arena, "%s%s%s_underlying_t", quals, padding, type->name);
88 }
89 
90 static const char *format_c89_struct(c89_emit_t *emit, const ssa_type_t *type, const char *name, const char *quals)
91 {
92  return (name != NULL)
93  ? str_format(emit->arena, "%sstruct %s %s", quals, type->name, name)
94  : str_format(emit->arena, "%sstruct %s", quals, type->name);
95 }
96 
97 const char *c89_format_type(c89_emit_t *emit, const ssa_type_t *type, const char *name, type_format_t flags)
98 {
99  CTASSERT(type != NULL);
100 
101  const char *quals = get_quals(type->quals, flags, emit->arena);
102 
103  switch (type->kind)
104  {
105  case eTypeUnit: return (name != NULL)
106  ? str_format(emit->arena, "void %s", name)
107  : "void";
108 
109  case eTypeBool: return (name != NULL)
110  ? str_format(emit->arena, "%sbool %s", quals, name)
111  : str_format(emit->arena, "%sbool", quals);
112 
113  case eTypeDigit: {
114  const char *digit_name = get_c89_digit(type->digit);
115  return (name != NULL)
116  ? str_format(emit->arena, "%s%s %s", quals, digit_name, name)
117  : str_format(emit->arena, "%s%s", quals, digit_name);
118  }
119 
120  case eTypeOpaque: return (name != NULL)
121  ? str_format(emit->arena, "%svoid *%s", quals, name)
122  : str_format(emit->arena, "%svoid *", quals);
123 
124  case eTypeClosure: return format_c89_closure(emit, quals, type->closure, name);
125  case eTypePointer: return format_c89_pointer(emit, type->pointer, name);
126 
127  case eTypeEnum: return format_c89_enum(emit, type, name, quals);
128 
129  case eTypeStruct: return format_c89_struct(emit, type, name, quals);
130 
131  case eTypeEmpty: CT_NEVER("cannot emit empty type `%s`", type->name);
132  default: CT_NEVER("unknown type %s", type_to_string(type, emit->arena));
133  }
134 }
135 
136 const char *c89_format_storage(c89_emit_t *emit, ssa_storage_t storage, const char *name, type_format_t flags)
137 {
138  char *it = str_format(emit->arena, "%s[%zu]", name, storage.size);
139  return c89_format_type(emit, storage.type, it, flags);
140 }
141 
142 const char *c89_format_params(c89_emit_t *emit, typevec_t *params, bool variadic)
143 {
144  CTASSERT(emit != NULL);
145  CTASSERT(params != NULL);
146 
147  size_t len = typevec_len(params);
148  if (len == 0)
149  {
150  return variadic ? "" : "void";
151  }
152 
153  vector_t *args = vector_of(len, emit->arena);
154  for (size_t i = 0; i < len; i++)
155  {
156  const ssa_param_t *param = typevec_offset(params, i);
157  const char *it = c89_format_type(emit, param->type, param->name, eFormatEmitConst);
158  vector_set(args, i, (char*)it);
159  }
160 
161  char *all = str_join(", ", args, emit->arena);
162  return variadic ? str_format(emit->arena, "%s, ...", all) : all;
163 }
type_format_t
Definition: c89.h:47
@ eFormatEmitConst
Definition: c89.h:49
@ eFormatIsConst
Definition: c89.h:54
CT_NODISCARD CT_PUREFN CT_BASE_API size_t ctu_strlen(const char *str)
get the length of a string not including the null terminator equivalent to strlen but with safety che...
Definition: util.c:87
#define CT_NEVER(...)
assert that a code path is never reached
Definition: panic.h:136
#define CTASSERT(expr)
assert a condition, prints the condition as a message
Definition: panic.h:130
CT_NODISCARD CT_STD_API char * str_join(const char *sep, const vector_t *parts, arena_t *arena)
join strings
Definition: str.c:274
CT_NODISCARD STA_FORMAT_STRING const char * fmt
Definition: str.h:68
tree_quals_t
all type qualifiers
Definition: ops.h:25
CT_TREE_API const char * digit_name(digit_t digit)
get the pretty name of a digit
Definition: ops.c:102
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
Definition: vector.c:120
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_offset(const typevec_t *vec, size_t index)
get a pointer to the value at the given index
Definition: vector.c:191
CT_NODISCARD CT_STD_API vector_t * vector_new(size_t size, arena_t *arena)
create a new vector with an initial capacity
Definition: vector.c:63
CT_NODISCARD CT_STD_API vector_t * vector_of(size_t len, arena_t *arena)
create a new vector with a specified length
Definition: vector.c:71
CT_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
Definition: vector.c:108
CT_STD_API void vector_set(vector_t *vector, size_t index, void *value)
set a value in a vector
Definition: vector.c:125
STA_DECL char * str_format(arena_t *arena, const char *fmt,...)
Definition: str.c:97
an allocator object
Definition: arena.h:86
Definition: c89.h:17
arena_t * arena
Definition: c89.h:18
const char * name
Definition: ssa.h:90
const ssa_type_t * type
Definition: ssa.h:91
ssa underlying storage type
Definition: ssa.h:78
size_t size
the number of elements in the storage
Definition: ssa.h:83
const ssa_type_t * type
the internal storage type
Definition: ssa.h:80
const ssa_type_t * result
Definition: ssa.h:131
bool variadic
Definition: ssa.h:133
typevec_t * params
Definition: ssa.h:132
digit_t digit
Definition: ssa.h:117
sign_t sign
Definition: ssa.h:116
const ssa_type_t * pointer
Definition: ssa.h:137
ssa_kind_t kind
Definition: ssa.h:146
tree_quals_t quals
Definition: ssa.h:147
ssa_type_closure_t closure
Definition: ssa.h:152
ssa_type_digit_t digit
Definition: ssa.h:151
const char * name
Definition: ssa.h:148
ssa_type_pointer_t pointer
Definition: ssa.h:153
A vector with a fixed type size.
Definition: vector.h:24
a generic vector of pointers
Definition: vector.c:16
const char * type_to_string(const ssa_type_t *type, arena_t *arena)
Definition: common.c:176
const char * c89_format_type(c89_emit_t *emit, const ssa_type_t *type, const char *name, type_format_t flags)
Definition: type.c:97
const char * c89_format_storage(c89_emit_t *emit, ssa_storage_t storage, const char *name, type_format_t flags)
Definition: type.c:136
const char * c89_format_params(c89_emit_t *emit, typevec_t *params, bool variadic)
Definition: type.c:142