GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/import/import_checker.c Lines: 178 201 88.6 %
Date: 2020-09-22 13:02:15 Branches: 93 118 78.8 %

Line Branch Exec Source
1
/** @file: checker.c                                   *
2
 *  \brief: functions to check names in import module  *
3
 *                                                     */
4
#include <ctype.h>
5
#include "gwion_util.h"
6
#include "gwion_ast.h"
7
#include "gwion_env.h"
8
#include "vm.h"
9
#include "traverse.h"
10
#include "instr.h"
11
#include "object.h"
12
#include "emit.h"
13
#include "gwion.h"
14
#include "operator.h"
15
#include "import.h"
16
#include "gwi.h"
17
18
__attribute__((returns_nonnull))
19
553550
ANN static Symbol gwisym(const Gwi gwi, const m_str str) {
20
553550
  return insert_symbol(gwi->gwion->st, str);
21
}
22
23
struct td_checker {
24
  m_str str;
25
};
26
27
struct AC {
28
  m_str str;
29
  Exp base;
30
  Exp exp;
31
  m_uint depth;
32
};
33
34
ANN static m_bool ac_run(const Gwi gwi, struct AC *ac);
35
23
ANN static Array_Sub mk_array(MemPool mp, struct AC *ac) {
36
23
  const Array_Sub array = new_array_sub(mp, ac->base);
37
23
  array->depth = ac->depth;
38
23
  array->exp = ac->base;
39
23
  return array;
40
}
41
42
43
553560
ANN static Symbol __str2sym(const Gwi gwi, struct td_checker *tdc) {
44
553560
  char buf[strlen(tdc->str) + 1];
45
553560
  m_str tmp = buf;
46
553560
  if(*tdc->str == '@')
47
64080
    *tmp++ = *tdc->str++;
48
3468747
  while(*tdc->str) {
49
2364554
    const char c = *tdc->str;
50

2364554
    if(!isalnum(c) && c != '_')
51
2927
      break;
52
2361627
    *tmp++ = *tdc->str++;
53
  }
54
553560
  if(tmp == buf)
55
10
    GWI_ERR_O("empty symbol");
56
553550
  *tmp = '\0';
57
553550
  return gwisym(gwi, buf);
58
}
59
60
69890
ANN static inline Symbol _str2sym(const Gwi gwi, struct td_checker *tdc, const m_str path) {
61
69890
  const Symbol sym = __str2sym(gwi, tdc);
62

69890
  if(*tdc->str && *tdc->str != ':')
63
4
    GWI_ERR_O(_("illegal character '%c' in path '%s'."), *tdc->str, path)
64
69886
  return sym;
65
}
66
67
/** convert a string to a symbol, with error checking **/
68
14296
ANN Symbol str2sym(const Gwi gwi, const m_str path) {
69
14296
  struct td_checker tdc = { .str=path };
70
14296
  return _str2sym(gwi, &tdc, path);
71
}
72
73
// only in enum.c
74
1467
ANN ID_List str2symlist(const Gwi gwi, const m_str path) {
75
1467
  DECL_OO(const Symbol, sym, = str2sym(gwi, path))
76
1467
  return new_id_list(gwi->gwion->mp, sym, loc(gwi));
77
}
78
79
45638
ANN Var_Decl str2var(const Gwi gwi, const m_str path) {
80
45638
  struct td_checker tdc = { .str=path };
81
45638
  DECL_OO(const Symbol, sym, = __str2sym(gwi, &tdc))
82
45636
  struct AC ac = { .str = tdc.str };
83
45636
  CHECK_BO(ac_run(gwi, &ac))
84
91268
  const Array_Sub array = ac.depth ?
85
45634
    mk_array(gwi->gwion->mp, &ac) : NULL;
86
45634
  return new_var_decl(gwi->gwion->mp, sym, array, loc(gwi));
87
}
88
89
// only in udef.c
90
22108
ANN Var_Decl_List str2varlist(const Gwi gwi, const m_str path) {
91
22108
  DECL_OO(const Var_Decl, var, = str2var(gwi, path))
92
22105
  return new_var_decl_list(gwi->gwion->mp, var, NULL);
93
}
94
95
1439
ANN static ID_List _tmpl_list(const Gwi gwi, struct td_checker *tdc) {
96
1439
  DECL_OO(const Symbol, sym, = __str2sym(gwi, tdc))
97
1439
  ID_List next = NULL;
98
1439
  if(*tdc->str == ',') {
99
2
    ++tdc->str;
100

2
    if(!(next = _tmpl_list(gwi, tdc)) || next == (ID_List)GW_ERROR)
101
      return (ID_List)GW_ERROR;
102
  }
103
1439
  const ID_List list = new_id_list(gwi->gwion->mp, sym, loc(gwi));
104
1439
  list->next = next;
105
1439
  return list;
106
}
107
108
55592
ANN static ID_List __tmpl_list(const Gwi gwi, struct td_checker *tdc) {
109
55592
  if(tdc->str[0] != ':')
110
54155
    return NULL;
111
1437
  if(tdc->str[1] != '[')
112
    return (ID_List)GW_ERROR;
113
1437
  tdc->str += 2;
114
1437
  const ID_List list =  _tmpl_list(gwi, tdc);
115
1437
  if(list == (ID_List)GW_ERROR)
116
    return (ID_List)GW_ERROR;
117
1437
  if(tdc->str[0] != ']') {
118
// unfinished template
119
    if(list)
120
      free_id_list(gwi->gwion->mp, list);
121
    return (ID_List)GW_ERROR;
122
  }
123
1437
  ++tdc->str;
124
1437
  return list;
125
}
126
127
55594
ANN m_bool check_typename_def(const Gwi gwi, ImportCK *ck) {
128
55594
  struct td_checker tdc = { .str= ck->name };
129
55594
  if(!(ck->sym = _str2sym(gwi, &tdc, tdc.str)))
130
2
    return GW_ERROR;
131
55592
  ID_List il = __tmpl_list(gwi, &tdc);
132
55592
  if(il == (ID_List)GW_ERROR)
133
    return GW_ERROR;
134
55592
  ck->tmpl = il;
135
55592
  ck->name = s_name(ck->sym);
136
55592
  return GW_OK;
137
138
}
139
140
65575
ANN m_bool ck_ini(const Gwi gwi, const enum importck_type t) {
141
65575
  if(gwi->ck) // TODO: improve error message
142
4
    GWI_ERR_B(_("already importing"))
143
65571
  gwi->ck = mp_calloc2(gwi->gwion->mp, sizeof(ImportCK));
144
65571
  gwi->ck->type = t;
145
65571
  return GW_OK;
146
}
147
148
90574
ANN m_bool ck_ok(const Gwi gwi, const enum importck_type t) {
149
90574
  if(!gwi->ck)
150
1
    GWI_ERR_B(_("import not started"))
151
90573
  if(gwi->ck->type == t)
152
90572
    return GW_OK;
153
  // TODO: improve error message
154
1
  GWI_ERR_B(_("already importing"))
155
}
156
157
64119
ANN void ck_end(const Gwi gwi) {
158
64119
  mp_free2(gwi->gwion->mp, sizeof(ImportCK), gwi->ck);
159
64119
  gwi->ck = NULL;
160
64119
}
161
162
typedef void (*cleaner) (MemPool, ImportCK*);
163
static cleaner cleaners[] =
164
{
165
  ck_clean_edef,
166
  ck_clean_udef,
167
  ck_clean_tdef,
168
NULL,//  ck_clean_oper,
169
  ck_clean_item,
170
  ck_clean_fdef
171
};
172
173
23
ANN void ck_clean(const Gwi gwi) {
174
23
  cleaners[gwi->ck->type](gwi->gwion->mp, gwi->ck);
175
23
  memset(gwi->ck, 0, sizeof(ImportCK));
176
23
}
177
178
ANN Type_Decl* _str2decl(const Gwi gwi, struct td_checker *tdc);
179
3
ANN Type_List __str2tl(const Gwi gwi, struct td_checker *tdc) {
180
3
  Type_Decl *td = _str2decl(gwi, tdc);
181
3
  if(!td)
182
1
    GWI_ERR_O("invalid types");
183
2
  Type_List next = NULL;
184
2
  if(*tdc->str == ',') {
185
    ++tdc->str;
186
    if(!(next = __str2tl(gwi, tdc))) {
187
      free_type_decl(gwi->gwion->mp, td);
188
      return NULL;
189
    }
190
  }
191
2
  return new_type_list(gwi->gwion->mp, td, next);
192
}
193
194
436587
ANN static Type_List td_tmpl(const Gwi gwi, struct td_checker *tdc) {
195
436587
  if(*tdc->str != ':')
196
436584
    return NULL; // GW_PASS
197
3
  ++tdc->str;
198
3
  if(*tdc->str != '[') {
199
    GWI_ERR("invalid character");
200
    return (Type_List)GW_ERROR;
201
  }
202
3
  ++tdc->str;
203
3
  Type_List tl = __str2tl(gwi, tdc);
204
3
  if(!tl)
205
1
    return (Type_List)GW_ERROR;
206
2
  if(tdc->str[0] != ']') {
207
    free_type_list(gwi->gwion->mp, tl);
208
    GWI_ERR("unfinished template");
209
    return (Type_List)GW_ERROR;
210
  }
211
2
  ++tdc->str;
212
2
  return tl;
213
}
214
215
5
ANN static void ac_add_exp(struct AC *ac, const Exp exp) {
216
5
  if(ac->exp)
217
2
    ac->exp = (ac->exp->next = exp);
218
  else
219
3
    ac->base = ac->exp = exp;
220
5
}
221
222
223
436593
ANN Type_Decl* _str2decl(const Gwi gwi, struct td_checker *tdc) {
224
436593
  DECL_OO(const Symbol, sym, = __str2sym(gwi, tdc))
225
436587
  struct AC ac = { .str = tdc->str };
226
436587
  CHECK_BO(ac_run(gwi, &ac))
227
436587
  tdc->str = ac.str;
228
436587
  Type_List tl = td_tmpl(gwi, tdc);
229
436587
  if(tl == (Type_List)GW_ERROR)
230
1
    return NULL;
231
436586
  Type_Decl *next = NULL;
232
436586
  if(*tdc->str == '.') {
233
2
    ++tdc->str;
234
2
    if(!(next =  _str2decl(gwi, tdc))) {
235
      if(tl)
236
        free_type_list(gwi->gwion->mp, tl);
237
      if(ac.base)
238
        free_exp(gwi->gwion->mp, ac.base);
239
      return NULL;
240
    }
241
  }
242
436586
  Type_Decl *td = new_type_decl(gwi->gwion->mp, sym, loc(gwi));
243
436586
  td->next = next;
244
436586
  td->types = tl;
245
436586
  if(ac.depth)
246
17
    td->array = mk_array(gwi->gwion->mp, &ac);
247
436586
  return td;
248
}
249
250
436588
ANN Type_Decl* str2decl(const Gwi gwi, const m_str str) {
251
436588
  const ae_flag flag = strncmp(str, "nonnull ", 8) ? ae_flag_none : ae_flag_nonnull;
252
436588
  struct td_checker tdc = { .str=str };
253
436588
  if(flag == ae_flag_nonnull)
254
17800
    tdc.str += 8;
255
436588
  DECL_OO(Type_Decl *, td, = _str2decl(gwi, &tdc))
256
436582
  if(*tdc.str) {
257
4
    free_type_decl(gwi->gwion->mp, td);
258
4
    GWI_ERR_O("excedental character '%c'", *tdc.str);
259
  }
260
436578
  td->flag |= flag;
261
436578
  return td;
262
}
263
264
35
ANN static inline m_bool ac_finish(const Gwi gwi, struct AC *ac) {
265
35
  if(*ac->str == ']')
266
34
    return GW_OK;
267
1
  GWI_ERR_B("unfinished array");
268
}
269
270
5
ANN static inline m_bool ac_num(const Gwi gwi, const m_int num) {
271
5
  if(num >= 0)
272
5
    return GW_OK;
273
  GWI_ERR_B("negative array dimension")
274
}
275
276
5
ANN static inline m_bool ac_exp(const Gwi gwi, struct AC *ac) {
277

5
  if(!ac->depth || ac->base)
278
5
    return GW_OK;
279
  GWI_ERR_B("malformed array [][...]")
280
}
281
282
29
ANN static inline m_bool ac_noexp(const Gwi gwi, struct AC *ac) {
283
29
  if(!ac->exp)
284
28
    return GW_OK;
285
1
  GWI_ERR_B("malformed array [...][]")
286
}
287
288
35
ANN static m_bool _ac_run(const Gwi gwi, struct AC *ac) {
289
35
  const m_str str = ac->str;
290
35
  const m_int num = strtol(str, &ac->str, 10);
291
35
  CHECK_BB(ac_finish(gwi, ac))
292
34
  if(str != ac->str) {
293
5
    CHECK_BB(ac_num(gwi, num))
294
5
    CHECK_BB(ac_exp(gwi, ac))
295
5
    const Exp exp = new_prim_int(gwi->gwion->mp, num, loc(gwi));
296
5
    ac_add_exp(ac, exp);
297
  } else
298
29
    CHECK_BB(ac_noexp(gwi, ac))
299
33
  ++ac->str;
300
33
  return GW_OK;
301
}
302
303
482223
ANN static m_bool ac_run(const Gwi gwi, struct AC *ac) {
304
964479
  while(*ac->str) {
305
46
    if(*ac->str != '[')
306
11
      break;
307
35
    ++ac->str;
308
35
    CHECK_BB(_ac_run(gwi, ac))
309
33
    ++ac->depth;
310
  }
311
482221
  return GW_OK;
312
}