Cthulhu  0.2.10
Cthulhu compiler collection
common.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 
3 #include "common.h"
4 
5 #include "base/panic.h"
6 #include "config/config.h"
7 #include "core/macros.h"
8 
9 #include "arena/arena.h"
10 
11 #include "scan/scan.h"
12 #include "std/map.h"
13 #include "std/vector.h"
14 #include "std/str.h"
15 
16 typedef struct where_t where_t;
17 
18 // internals
19 
20 static void apply_callbacks(scan_t *scan, const cfg_field_t *param, const void *value, vector_t *all)
21 {
22  CTASSERT(scan != NULL);
23  CTASSERT(all != NULL);
24  CTASSERT(value != NULL);
25 
26  ap_t *self = scan_get_context(scan);
27  size_t len = vector_len(all);
28 
29  for (size_t i = 0; i < len; i++)
30  {
31  ap_callback_t *cb = vector_get(all, i);
32  if (cb->callback(self, param, value, cb->data))
33  return;
34  }
35 }
36 
37 void ap_add_error(ap_t *self, const char *fmt, ...)
38 {
39  va_list args;
40  va_start(args, fmt);
41  char *error = str_vformat(self->arena, fmt, args);
42  va_end(args);
43 
44  vector_push(&self->errors, error);
45 }
46 
47 // flex + bison callbacks
48 
49 static void update_flags(cfg_field_t *param, const char *value, ap_t *self)
50 {
51  // first split `value` by `,`
52  const char *start = value;
53  const char *end = value;
54 
55  while (*end != '\0')
56  {
57  if (*end == ',')
58  {
59  size_t len = end - start;
60  char *flag = arena_strndup(start, len, self->arena);
61 
62  // if the flag starts with `-` then it's a negative flag
63  // otherwise it's a positive flag
64  bool negate = *flag == '-';
65  if (negate)
66  flag++;
67 
68  if (!cfg_set_flag(param, flag, !negate))
69  {
70  ap_add_error(self, "unknown flag value: %s", flag);
71  }
72 
73  start = end + 1;
74  }
75 
76  end++;
77  }
78 
79  // handle the last flag
80  bool negate = *start == '-';
81  if (negate)
82  start++;
83 
84  if (!cfg_set_flag(param, start, !negate))
85  {
86  ap_add_error(self, "unknown flag value: %s", start);
87  }
88 }
89 
90 void ap_on_string(scan_t *scan, cfg_field_t *param, char *value)
91 {
92  ap_t *self = scan_get_context(scan);
93  vector_t *callbacks = map_get(self->event_lookup, param);
94 
95  if (callbacks)
96  apply_callbacks(scan, param, value, callbacks);
97 
98  cfg_type_t type = cfg_get_type(param);
99  switch (type) {
100  case eConfigString:
101  cfg_set_string(param, arena_strdup(value, self->arena));
102  break;
103 
104  case eConfigVector:
105  cfg_vector_push(param, arena_strdup(value, self->arena));
106  break;
107 
108  case eConfigEnum:
109  // TODO: handle failure
110  cfg_set_enum(param, value);
111  break;
112 
113  case eConfigFlags:
114  update_flags(param, value, self);
115  break;
116 
117  default:
118  CT_NEVER("unknown config type %d", type);
119  }
120 }
121 
122 void ap_on_bool(scan_t *scan, cfg_field_t *param, bool value)
123 {
124  ap_t *self = scan_get_context(scan);
125  vector_t *callbacks = map_get(self->event_lookup, param);
126 
127  if (callbacks)
128  apply_callbacks(scan, param, &value, callbacks);
129 
130  cfg_set_bool(param, value);
131 }
132 
133 void ap_on_int(scan_t *scan, cfg_field_t *param, mpz_t value)
134 {
135  ap_t *self = scan_get_context(scan);
136 
137  vector_t *callbacks = map_get(self->event_lookup, param);
138 
139  if (callbacks)
140  apply_callbacks(scan, param, value, callbacks);
141 
142  int v = mpz_get_si(value);
143 
144  if (!cfg_set_int(param, v))
145  {
146  ap_add_error(self, "value out of range: %d", v);
147  }
148 }
149 
150 void ap_on_posarg(scan_t *scan, char *value)
151 {
152  ap_t *self = scan_get_context(scan);
153  apply_callbacks(scan, NULL, value, self->posarg_callbacks);
154  vector_push(&self->posargs, (char*)value);
155 }
156 
157 void ap_on_invalid(scan_t *scan, char *value)
158 {
159  ap_t *self = scan_get_context(scan);
160 
161  ap_add_error(self, "invalid ascii character: `%s`", value);
162 }
163 
164 void aperror(where_t *where, void *state, scan_t *scan, const char *msg)
165 {
166  CT_UNUSED(state);
167  CT_UNUSED(where);
168 
169  ap_t *self = scan_get_context(scan);
170 
171  ap_add_error(self, "%s", msg);
172 }
CT_NODISCARD CT_PUREFN CT_SCAN_API void * scan_get_context(const scan_t *scan)
get the context of a scanner
Definition: scan.c:88
CT_PUREFN CT_CONFIG_API cfg_type_t cfg_get_type(const cfg_field_t *field)
get the type of a configuration field
Definition: reflect.c:6
CT_CONFIG_API void cfg_vector_push(cfg_field_t *field, char *value)
push a new value onto an array field
Definition: update.c:43
CT_NODISCARD CT_CONFIG_API bool cfg_set_int(cfg_field_t *field, int value)
set the current value of an int field
Definition: update.c:9
CT_NODISCARD CT_CONFIG_API bool cfg_set_flag(cfg_field_t *field, const char *choice, bool set)
set the current value of a flags field set the value via a string name
Definition: update.c:112
CT_CONFIG_API void cfg_set_string(cfg_field_t *field, char *value)
set the current value of a string field
Definition: update.c:35
CT_CONFIG_API bool cfg_set_enum(cfg_field_t *field, const char *choice)
set the current value of an enum field set the value via a string name
Definition: update.c:51
CT_CONFIG_API void cfg_set_bool(cfg_field_t *field, bool value)
set the current value of a bool field
Definition: update.c:27
cfg_type_t
the type of a configuration field
Definition: config.h:27
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
#define CT_UNUSED(x)
mark a variable as unused
Definition: macros.h:46
CT_NODISCARD CT_ARENA_API char * arena_strdup(const char *str, arena_t *arena)
allocate a copy of a string from a custom allocator
Definition: arena.c:95
CT_NODISCARD CT_ARENA_API char * arena_strndup(STA_READS(len) const char *str, size_t len, arena_t *arena)
allocate a copy of a string with a maximum length from a custom allocator
#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 STA_FORMAT_STRING const char * fmt
Definition: str.h:68
CT_NODISCARD STA_FORMAT_STRING const char CT_NODISCARD CT_STD_API char * str_vformat(arena_t *arena, const char *fmt, va_list args)
format a string
Definition: str.c:110
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_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
Definition: vector.c:108
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
void * data
Definition: common.h:21
ap_event_t callback
Definition: common.h:20
argparse instance
Definition: common.h:26
a source file scanner
Definition: scan.h:24
a generic vector of pointers
Definition: vector.c:16
a location inside a scanner locations are inclusive and 0-based
Definition: where.h:23
void ap_on_bool(scan_t *scan, cfg_field_t *param, bool value)
Definition: common.c:122
void ap_on_string(scan_t *scan, cfg_field_t *param, char *value)
Definition: common.c:90
void ap_add_error(ap_t *self, const char *fmt,...)
Definition: common.c:37
void ap_on_int(scan_t *scan, cfg_field_t *param, mpz_t value)
Definition: common.c:133
void ap_on_invalid(scan_t *scan, char *value)
Definition: common.c:157
void aperror(where_t *where, void *state, scan_t *scan, const char *msg)
Definition: common.c:164
void ap_on_posarg(scan_t *scan, char *value)
Definition: common.c:150