Cthulhu  0.2.10
Cthulhu compiler collection
main.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-3.0-only
2 
3 #include "base/panic.h"
4 #include "config/config.h"
5 #include "core/macros.h"
8 #include "setup/setup.h"
9 #include "io/console.h"
10 #include "io/io.h"
11 #include "std/map.h"
12 #include "std/str.h"
13 #include "std/typed/vector.h"
14 #include "std/vector.h"
15 #include "support/loader.h"
16 #include "argparse/argparse.h"
17 #include "arena/arena.h"
18 
19 #include "memory/memory.h"
20 #include "support/support.h"
21 
22 static const frontend_t kFrontendInfo = {
23  .info = {
24  .id = "frontend-diag",
25  .name = "Diagnostic query tool",
26  .version = {
27  .license = "GPLv3",
28  .author = "Elliot Haisley",
29  .desc = "Cthulhu diagnostic lookup and query tool",
30  .version = CT_NEW_VERSION(0, 0, 1),
31  },
32  },
33 };
34 
35 static const cfg_info_t kGroupInfo = {
36  .name = "diagnostics",
37  .brief = "Diagnostic query options"
38 };
39 
40 static const cfg_arg_t kPrintLangsArgs[] = { CT_ARG_LONG("all-langs") };
41 
42 static const cfg_info_t kPrintLangsInfo = {
43  .name = "langs",
44  .brief = "Print info about all available languages",
45  .args = CT_ARGS(kPrintLangsArgs),
46 };
47 
48 static const cfg_arg_t kPrintSingleLangArgs[] = { CT_ARG_LONG("single-lang"), CT_ARG_LONG("lang") };
49 
50 static const cfg_info_t kPrintSingleLangInfo = {
51  .name = "lang",
52  .brief = "Print information about a specific language",
53  .args = CT_ARGS(kPrintSingleLangArgs),
54 };
55 
56 static const cfg_arg_t kPrintDiagInfoArgs[] = { CT_ARG_LONG("all") };
57 
58 static const cfg_info_t kPrintDiagsInfo = {
59  .name = "diags",
60  .brief = "Print all available diagnostics for all languages",
61  .args = CT_ARGS(kPrintDiagInfoArgs),
62 };
63 
64 static const cfg_arg_t kPrintSingleDiagInfoArgs[] = { CT_ARG_LONG("diag") };
65 
66 static const cfg_info_t kPrintSingleDiagInfo = {
67  .name = "lang-diag",
68  .brief = "Print all available diagnostics for a specific language",
69  .args = CT_ARGS(kPrintSingleDiagInfoArgs)
70 };
71 
72 typedef struct tool_t
73 {
75 
78 
81 
83 } tool_t;
84 
85 static tool_t make_config(typevec_t *langs, arena_t *arena)
86 {
87  cfg_group_t *root = config_root(&kGroupInfo, arena);
88  size_t len = typevec_len(langs);
89 
90  cfg_choice_t *lang_choices = ARENA_MALLOC(sizeof(cfg_choice_t) * (len + 1), "lang_choices", root, arena);
91  cfg_choice_t none_choice = {
92  .text = "none",
93  .value = 0
94  };
95 
96  lang_choices[0] = none_choice;
97 
98  for (size_t i = 0; i < len; i++)
99  {
100  const language_t *lang = typevec_offset(langs, i);
101  module_info_t info = lang->info;
102  cfg_choice_t choice = {
103  .text = info.id,
104  .value = i + 1
105  };
106 
107  lang_choices[i + 1] = choice;
108  }
109 
110  cfg_enum_t lang_options = {
111  .options = lang_choices,
112  .count = len + 1,
113  .initial = 0
114  };
115 
116  setup_options_t options = setup_options(kFrontendInfo.info.version, root);
117 
118  cfg_field_t *print_all_langs = config_bool(root, &kPrintLangsInfo, false);
119 
120  cfg_field_t *print_one_lang = config_enum(root, &kPrintSingleLangInfo, lang_options);
121 
122  cfg_field_t *print_all_diags = config_bool(root, &kPrintDiagsInfo, false);
123 
124  cfg_field_t *print_one_diag = config_enum(root, &kPrintSingleDiagInfo, lang_options);
125 
126  tool_t config = {
127  .root = root,
128  .print_all_langs = print_all_langs,
129  .print_one_lang = print_one_lang,
130 
131  .print_all_diags = print_all_diags,
132  .print_one_diag = print_one_diag,
133 
134  .options = options,
135  };
136 
137  return config;
138 }
139 
140 typedef struct diag_search_t
141 {
143 
145 } diag_search_t;
146 
147 static void add_diagnostic(diag_search_t *ctx, const diagnostic_t *diag)
148 {
149  const diagnostic_t *old = map_get(ctx->ids, diag->id);
150  CTASSERTF(old == NULL, "duplicate diagnostic id: %s (old message %s)", diag->id, old->brief);
151 
152  map_set(ctx->ids, diag->id, (diagnostic_t*)diag);
153  typevec_push(ctx->diagnostics, diag);
154 }
155 
156 static void add_diagnostics(diag_search_t *ctx, diagnostic_list_t diagnostics)
157 {
158  for (size_t i = 0; i < diagnostics.count; i++)
159  {
160  add_diagnostic(ctx, diagnostics.diagnostics[i]);
161  }
162 }
163 
164 static size_t count_diagnostics(const typevec_t *langs)
165 {
166  size_t count = 0;
167 
168  size_t len = typevec_len(langs);
169  for (size_t i = 0; i < len; i++)
170  {
171  const language_t *lang = typevec_offset(langs, i);
172  module_info_t info = lang->info;
173  count += info.diagnostics.count;
174  }
175 
176  return count;
177 }
178 
179 // TODO: this should all be part of the support library
180 
181 static void print_lang_info(io_t *io, const language_t *lang)
182 {
183  module_info_t info = lang->info;
184  diagnostic_list_t diagnostics = info.diagnostics;
185  version_info_t version = info.version;
186 
187  int major = CT_VERSION_MAJOR(version.version);
188  int minor = CT_VERSION_MINOR(version.version);
189  int patch = CT_VERSION_PATCH(version.version);
190 
191  io_printf(io, "%s:\n", info.name);
192  io_printf(io, " id: %s\n", info.id);
193  io_printf(io, " desc: %s\n", version.desc);
194  io_printf(io, " author: %s\n", version.author);
195  io_printf(io, " license: %s\n", version.license);
196  io_printf(io, " version: %d.%d.%d\n", major, minor, patch);
197 
198  io_printf(io, " %zu diagnostics\n", diagnostics.count);
199 }
200 
201 static void print_all_langs(io_t *io, typevec_t *langs)
202 {
203  size_t len = typevec_len(langs);
204  io_printf(io, "%zu available languages:\n", len);
205  for (size_t i = 0; i < len; i++)
206  {
207  const language_t *lang = typevec_offset(langs, i);
208  print_lang_info(io, lang);
209  }
210 }
211 
212 static void print_diagnostic(io_t *io, const diagnostic_t *diag)
213 {
214  io_printf(io, "%s: %s\n", diag->id, severity_string(diag->severity));
215  io_printf(io, "brief: %s\n", diag->brief);
216  io_printf(io, "description: %s\n", diag->description);
217 }
218 
219 int main(int argc, const char **argv)
220 {
221  setup_default(NULL);
222  arena_t *arena = get_global_arena();
223  io_t *io = io_stdout();
224 
225  broker_t *broker = broker_new(&kFrontendInfo, arena);
226  loader_t *loader = loader_new(arena);
227  support_t *support = support_new(broker, loader, arena);
229 
230  typevec_t *mods = support_get_modules(support);
231 
232  size_t len = typevec_len(mods);
233  typevec_t *langs = typevec_new(sizeof(language_t), len, arena);
234  for (size_t i = 0; i < len; i++)
235  {
236  const loaded_module_t *mod = typevec_offset(mods, i);
237  if (mod->type & eModLanguage)
238  {
239  typevec_push(langs, mod->lang);
240  }
241  }
242 
243  tool_t tool = make_config(langs, arena);
244 
245  setup_init_t init = setup_parse(argc, argv, tool.options);
246 
247  if (setup_should_exit(&init))
248  return setup_exit_code(&init);
249 
253 
255  {
256  print_all_langs(io, langs);
257  return CT_EXIT_OK;
258  }
259 
263 
264  size_t lang_index = cfg_enum_value(tool.print_one_lang);
265  if (lang_index != 0)
266  {
267  const language_t *lang = typevec_offset(langs, lang_index - 1);
268  print_lang_info(io, lang);
269  return CT_EXIT_OK;
270  }
271 
275 
277 
278  size_t count = count_diagnostics(langs) + common.count;
279 
280  diag_search_t ctx = {
281  .ids = map_optimal(count, kTypeInfoString, arena),
282  .diagnostics = typevec_new(sizeof(diagnostic_t), count, arena),
283  };
284 
285  add_diagnostics(&ctx, common);
286 
287  size_t lang_count = typevec_len(langs);
288  for (size_t i = 0; i < lang_count; i++)
289  {
290  const language_t *lang = typevec_offset(langs, i);
291  module_info_t info = lang->info;
292  add_diagnostics(&ctx, info.diagnostics);
293  }
294 
298 
300  {
301  size_t diag_count = typevec_len(ctx.diagnostics);
302  io_printf(io, "%zu diagnostics:\n", diag_count);
303  for (size_t i = 0; i < diag_count; i++)
304  {
305  const diagnostic_t *diag = typevec_offset(ctx.diagnostics, i);
306  print_diagnostic(io, diag);
307 
308  if (i + 1 < diag_count)
309  {
310  io_printf(io, "\n");
311  }
312  }
313 
314  return CT_EXIT_OK;
315  }
316 
320 
321  size_t lang_diag_index = cfg_enum_value(tool.print_one_diag);
322  if (lang_diag_index != 0)
323  {
324  const language_t *lang = typevec_offset(langs, lang_diag_index - 1);
325 
326  module_info_t info = lang->info;
327  size_t diag_count = info.diagnostics.count;
328  io_printf(io, "%zu diagnostics for %s:\n", diag_count, info.name);
329 
330  for (size_t i = 0; i < diag_count; i++)
331  {
332  const diagnostic_t *diag = info.diagnostics.diagnostics[i];
333  print_diagnostic(io, diag);
334 
335  if (i + 1 < diag_count)
336  {
337  io_printf(io, "\n");
338  }
339  }
340  }
341 
345 
346  vector_t *posargs = init.posargs;
347  size_t posarg_count = vector_len(posargs);
348  for (size_t i = 0; i < posarg_count; i++)
349  {
350  const char *arg = vector_get(posargs, i);
351  const diagnostic_t *diag = map_get(ctx.ids, arg);
352  if (diag == NULL)
353  {
354  io_printf(io, "unknown diagnostic: %s\n", arg);
355  }
356  else
357  {
358  print_diagnostic(io, diag);
359 
360  if (i + 1 < posarg_count)
361  {
362  io_printf(io, "\n");
363  }
364  }
365  }
366 
367  io_close(io);
368 }
int main(int argc, const char **argv)
Definition: main.c:168
CT_BROKER_API broker_t * broker_new(const frontend_t *frontend, arena_t *arena)
Definition: broker.c:130
CT_CONFIG_API cfg_field_t * config_enum(cfg_group_t *group, const cfg_info_t *info, cfg_enum_t cfg)
add a new choice field to a configuration group
Definition: config.c:162
CT_CONFIG_API cfg_field_t * config_bool(cfg_group_t *group, const cfg_info_t *info, bool initial)
add a new yes/no field to a configuration group
Definition: config.c:126
CT_PUREFN CT_CONFIG_API bool cfg_bool_value(const cfg_field_t *field)
get the current boolean value of a configuration field
Definition: reflect.c:143
CT_PUREFN CT_CONFIG_API size_t cfg_enum_value(const cfg_field_t *field)
get the current enum value of a configuration field
Definition: reflect.c:167
#define CT_ARGS(it)
Definition: config.h:57
#define CT_ARG_LONG(name)
Definition: config.h:55
CT_CONFIG_API cfg_group_t * config_root(const cfg_info_t *info, arena_t *arena)
create a new configuration group
Definition: config.c:97
#define CT_VERSION_MAJOR(version)
returns the major version of version
Definition: version_def.h:37
#define CT_VERSION_MINOR(version)
returns the minor version of version
Definition: version_def.h:38
#define CT_NEW_VERSION(major, minor, patch)
creates a new ctu_version_t from major, minor and patch
Definition: version_def.h:20
#define CT_VERSION_PATCH(version)
returns the patch version of version
Definition: version_def.h:39
#define CT_EXIT_OK
no user errors or internal errors
Definition: macros.h:91
CT_NODISCARD CT_CONSTFN CT_EVENTS_API diagnostic_list_t get_common_diagnostics(void)
get all common diagnostics
Definition: events.c:22
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
Definition: memory.c:16
CT_NODISCARD CT_STD_API map_t * map_optimal(size_t size, hash_info_t info, arena_t *arena)
create a new map with an optimal size
Definition: optimal.c:85
CT_STD_API void map_set(map_t *map, const void *key, void *value)
set a key-value pair in a map
Definition: map.c:294
CT_NODISCARD CT_PUREFN CT_STD_API void * map_get(const map_t *map, const void *key)
get a value from a map
Definition: map.c:324
CT_IO_API os_error_t io_close(INOUT_NOTNULL io_t *io)
destroy an IO object
CT_IO_API io_t * io_stdout(void)
get the global stdout IO object
Definition: console.c:60
CT_IO_API size_t io_printf(io_t *io, STA_FORMAT_STRING const char *fmt,...)
printf to an io object
CT_SUPPORT_API void support_load_default_modules(support_t *support)
load all default modules
Definition: support.c:139
CT_SUPPORT_API typevec_t * support_get_modules(support_t *support)
Definition: support.c:168
CT_SUPPORT_API support_t * support_new(broker_t *broker, loader_t *loader, arena_t *arena)
create a support instance from an existing loader and broker configures the broker with the modules i...
Definition: support.c:113
#define ARENA_MALLOC(size, name, parent, arena)
allocate memory from a custom allocator
Definition: arena.h:392
STA_RET_STRING CT_CONSTFN CT_NOTIFY_API const char * severity_string(severity_t severity)
get the name of a severity
Definition: notify.c:216
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
Definition: panic.h:116
CT_SETUP_API setup_init_t setup_parse(int argc, const char **argv, setup_options_t setup)
parse the command line
Definition: setup.c:366
CT_PUREFN CT_SETUP_API bool setup_should_exit(const setup_init_t *init)
accessor functions
Definition: setup.c:434
CT_SETUP_API void setup_default(arena_t *arena)
initialise the runtime with default options
Definition: setup.c:188
CT_SETUP_API setup_options_t setup_options(version_info_t info, cfg_group_t *root)
setup default options
Definition: setup.c:215
CT_PUREFN CT_SETUP_API int setup_exit_code(const setup_init_t *init)
get the exit code
Definition: setup.c:442
CT_STD_API const hash_info_t kTypeInfoString
type information for a c style string
Definition: typeinfo.c:35
CT_STD_API void * typevec_push(typevec_t *vec, const void *src)
push a value onto the vector
Definition: vector.c:156
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_STD_API typevec_t * typevec_new(size_t width, size_t len, arena_t *arena)
create a new typed vector on the heap
Definition: vector.c:77
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_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
Definition: vector.c:134
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
Definition: vector.c:152
CT_SUPPORT_API loader_t * loader_new(arena_t *arena)
Definition: loader.c:41
an allocator object
Definition: arena.h:86
a choice in a set of options
Definition: config.h:97
STA_FIELD_STRING const char * text
the name of this choice
Definition: config.h:99
a choice from a set of options
Definition: config.h:107
information about a configuration field
Definition: config.h:69
STA_FIELD_STRING const char * name
the name of this field
Definition: config.h:71
map_t * ids
Definition: main.c:142
typevec_t * diagnostics
Definition: main.c:144
a list of diagnostics
Definition: diagnostic.h:48
size_t count
the number of diagnostics in the list
Definition: diagnostic.h:54
const diagnostic_t *const * diagnostics
the list of diagnostics
Definition: diagnostic.h:51
a diagnostic
Definition: diagnostic.h:27
const char * brief
a brief description of the diagnostic a single line description of the diagnostic
Definition: diagnostic.h:38
const char * id
the id of the diagnostic should be in the format [A-Z]{2,3}[0-9]{4} e.g. CLI0001 this is not enforced...
Definition: diagnostic.h:34
severity_t severity
the severity of the diagnostic
Definition: diagnostic.h:29
const char * description
a description of the diagnostic a more involved description of the diagnostic this is optional
Definition: diagnostic.h:43
the frontend running the mediator
Definition: broker.h:251
module_info_t info
information about the frontend
Definition: broker.h:253
io object implementation
Definition: impl.h:122
a language driver support capabilities
Definition: broker.h:143
module_info_t info
common information about the language
Definition: broker.h:145
module_type_t type
Definition: loader.h:49
const language_t * lang
Definition: loader.h:51
Definition: common.h:8
an unordered hash map
Definition: map.h:38
common information about anything the broker supports
Definition: broker.h:99
version_info_t version
the version of the module
Definition: broker.h:107
diagnostic_list_t diagnostics
all diagnostics associated with this module
Definition: broker.h:110
const char * id
unique id for the module
Definition: broker.h:101
const char * name
the human readable name for the module
Definition: broker.h:104
the result of parsing the command line
Definition: setup.h:69
vector_t * posargs
the parsed position arguments
Definition: setup.h:79
default options shared by all tools
Definition: setup.h:31
Definition: cmd.h:14
cfg_field_t * print_all_langs
Definition: main.c:76
cfg_field_t * print_one_lang
Definition: main.c:77
cfg_field_t * print_one_diag
Definition: main.c:80
setup_options_t options
Definition: cmd.h:31
cfg_group_t * root
Definition: main.c:44
cfg_field_t * print_all_diags
Definition: main.c:79
A vector with a fixed type size.
Definition: vector.h:24
a generic vector of pointers
Definition: vector.c:16
version information for a driver/interface/plugin
Definition: version_def.h:48
const char * license
the license of this component
Definition: version_def.h:49
const char * author
the author of this component
Definition: version_def.h:51
const char * desc
a short description of this component
Definition: version_def.h:50
ctu_version_t version
the version info for this component
Definition: version_def.h:52