GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/import/checker.c Lines: 183 209 87.6 %
Date: 2020-08-07 19:15:19 Branches: 94 126 74.6 %

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
563184
ANN static Symbol gwisym(const Gwi gwi, const m_str str) {
20
563184
  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
27
ANN static Array_Sub mk_array(MemPool mp, struct AC *ac) {
36
27
  const Array_Sub array = new_array_sub(mp, ac->base);
37
27
  array->depth = ac->depth;
38
27
  array->exp = ac->base;
39
27
  return array;
40
}
41
42
43
563191
ANN static Symbol __str2sym(const Gwi gwi, struct td_checker *tdc) {
44
563191
  char buf[strlen(tdc->str) + 1];
45
563191
  m_str tmp = buf;
46
563191
  if(*tdc->str == '@')
47
64970
    *tmp++ = *tdc->str++;
48
3528800
  while(*tdc->str) {
49
2403221
    const char c = *tdc->str;
50

2403221
    if(!isalnum(c) && c != '_')
51
803
      break;
52
2402418
    *tmp++ = *tdc->str++;
53
  }
54
563191
  if(tmp == buf)
55
7
    GWI_ERR_O("empty symbol");
56
563184
  *tmp = '\0';
57
563184
  return gwisym(gwi, buf);
58
}
59
60
70926
ANN static inline Symbol _str2sym(const Gwi gwi, struct td_checker *tdc, const m_str path) {
61
70926
  const Symbol sym = __str2sym(gwi, tdc);
62
70926
  if(*tdc->str)
63
5
    GWI_ERR_O(_("illegal character '%c' in path '%s'."), *tdc->str, path)
64
70921
  return sym;
65
}
66
67
/** convert a string to a symbol, with error checking **/
68
14656
ANN Symbol str2sym(const Gwi gwi, const m_str path) {
69
14656
  struct td_checker tdc = { .str=path };
70
14656
  return _str2sym(gwi, &tdc, path);
71
}
72
73
// only in enum.c
74
1503
ANN ID_List str2symlist(const Gwi gwi, const m_str path) {
75
1503
  DECL_OO(const Symbol, sym, = str2sym(gwi, path))
76
1503
  return new_id_list(gwi->gwion->mp, sym, loc(gwi));
77
}
78
79
46795
ANN Var_Decl str2var(const Gwi gwi, const m_str path) {
80
46795
  struct td_checker tdc = { .str=path };
81
46795
  DECL_OO(const Symbol, sym, = __str2sym(gwi, &tdc))
82
46793
  struct AC ac = { .str = tdc.str };
83
46793
  CHECK_BO(ac_run(gwi, &ac))
84
93582
  const Array_Sub array = ac.depth ?
85
46791
    mk_array(gwi->gwion->mp, &ac) : NULL;
86
46791
  return new_var_decl(gwi->gwion->mp, sym, array, loc(gwi));
87
}
88
89
// only in udef.c
90
22669
ANN Var_Decl_List str2varlist(const Gwi gwi, const m_str path) {
91
22669
  DECL_OO(const Var_Decl, var, = str2var(gwi, path))
92
22666
  return new_var_decl_list(gwi->gwion->mp, var, NULL);
93
}
94
95
751
ANN static ID_List _tmpl_list(const Gwi gwi, struct td_checker *tdc) {
96
751
  DECL_OO(const Symbol, sym, = __str2sym(gwi, tdc))
97
751
  ID_List next = NULL;
98
751
  if(*tdc->str == ',') {
99
5
    ++tdc->str;
100

5
    if(!(next = _tmpl_list(gwi, tdc)) || next == (ID_List)GW_ERROR)
101
      return (ID_List)GW_ERROR;
102
  }
103
751
  const ID_List list = new_id_list(gwi->gwion->mp, sym, loc(gwi));
104
751
  list->next = next;
105
751
  return list;
106
}
107
108
56270
ANN static ID_List __tmpl_list(const Gwi gwi, struct td_checker *tdc) {
109
56270
  if(tdc->str[0] != '<')
110
55524
    return NULL;
111
746
  if(tdc->str[1] != '~')
112
    return (ID_List)GW_ERROR;
113
746
  tdc->str += 2;
114
746
  const ID_List list =  _tmpl_list(gwi, tdc);
115
746
  if(list == (ID_List)GW_ERROR)
116
    return (ID_List)GW_ERROR;
117

746
  if(tdc->str[0] != '~' || tdc->str[1] != '>') {
118
// unfinished template
119
    if(list)
120
      free_id_list(gwi->gwion->mp, list);
121
    return (ID_List)GW_ERROR;
122
  }
123
746
  tdc->str += 2;
124
746
  return list;
125
}
126
127
56270
ANN m_bool check_typename_def(const Gwi gwi, ImportCK *ck) {
128
56270
  struct td_checker tdc = { .str= ck->name };
129
56270
  ID_List il = __tmpl_list(gwi, &tdc);
130
56270
  if(il == (ID_List)GW_ERROR)
131
    return GW_ERROR;
132
56270
  if(!(ck->sym = _str2sym(gwi, &tdc, tdc.str))) {
133
    if(il)
134
      free_id_list(gwi->gwion->mp, il);
135
    return GW_ERROR;
136
  }
137
56270
  ck->tmpl = il;
138
56270
  ck->name = s_name(ck->sym);
139
56270
  return GW_OK;
140
141
}
142
143
67236
ANN m_bool ck_ini(const Gwi gwi, const enum importck_type t) {
144
67236
  if(gwi->ck) // TODO: improve error message
145
4
    GWI_ERR_B(_("already importing"))
146
67232
  gwi->ck = mp_calloc2(gwi->gwion->mp, sizeof(ImportCK));
147
67232
  gwi->ck->type = t;
148
67232
  return GW_OK;
149
}
150
151
92868
ANN m_bool ck_ok(const Gwi gwi, const enum importck_type t) {
152
92868
  if(!gwi->ck)
153
1
    GWI_ERR_B(_("import not started"))
154
92867
  if(gwi->ck->type == t)
155
92866
    return GW_OK;
156
  // TODO: improve error message
157
1
  GWI_ERR_B(_("already importing"))
158
}
159
160
66472
ANN void ck_end(const Gwi gwi) {
161
66472
  mp_free2(gwi->gwion->mp, sizeof(ImportCK), gwi->ck);
162
66472
  gwi->ck = NULL;
163
66472
}
164
165
typedef void (*cleaner) (MemPool, ImportCK*);
166
static cleaner cleaners[] =
167
{
168
  ck_clean_edef,
169
  ck_clean_udef,
170
  ck_clean_tdef,
171
NULL,//  ck_clean_oper,
172
  ck_clean_item,
173
  ck_clean_fdef
174
};
175
176
23
ANN void ck_clean(const Gwi gwi) {
177
23
  cleaners[gwi->ck->type](gwi->gwion->mp, gwi->ck);
178
23
  memset(gwi->ck, 0, sizeof(ImportCK));
179
23
}
180
181
ANN Type_Decl* _str2decl(const Gwi gwi, struct td_checker *tdc);
182
7
ANN Type_List __str2tl(const Gwi gwi, struct td_checker *tdc) {
183
7
  Type_Decl *td = _str2decl(gwi, tdc);
184
7
  if(!td)
185
    GWI_ERR_O("invalid types");
186
7
  Type_List next = NULL;
187
7
  if(*tdc->str == ',') {
188
1
    ++tdc->str;
189
1
    if(!(next = __str2tl(gwi, tdc))) {
190
      free_type_decl(gwi->gwion->mp, td);
191
      return NULL;
192
    }
193
  }
194
7
  return new_type_list(gwi->gwion->mp, td, next);
195
}
196
197
444720
ANN Type_List td_tmpl(const Gwi gwi, struct td_checker *tdc) {
198
444720
  if(*tdc->str != '<')
199
444714
    return NULL; // GW_PASS
200
6
  ++tdc->str;
201
6
  if(*tdc->str != '~') {
202
    GWI_ERR("invalid character");
203
    return (Type_List)GW_ERROR;
204
  }
205
6
  ++tdc->str;
206
6
  Type_List tl = __str2tl(gwi, tdc);
207
6
  if(!tl)
208
    return (Type_List)GW_ERROR;
209

6
  if(tdc->str[0] != '~' || tdc->str[1] != '>') {
210
1
    free_type_list(gwi->gwion->mp, tl);
211
1
    GWI_ERR("unfinished template");
212
1
    return (Type_List)GW_ERROR;
213
  }
214
5
  tdc->str += 2;
215
5
  return tl;
216
}
217
218
5
ANN static void ac_add_exp(struct AC *ac, const Exp exp) {
219
5
  if(ac->exp)
220
2
    ac->exp = (ac->exp->next = exp);
221
  else
222
3
    ac->base = ac->exp = exp;
223
5
}
224
225
226
444720
ANN Type_Decl* _str2decl(const Gwi gwi, struct td_checker *tdc) {
227
444720
  Type_List tl = td_tmpl(gwi, tdc);
228
444720
  if(tl == (Type_List)GW_ERROR)
229
1
    return NULL;
230
444719
  Type_Decl *next = NULL;
231
444719
  const Symbol sym = __str2sym(gwi, tdc);
232
444719
  if(!sym) {
233
4
    if(tl)
234
      free_type_list(gwi->gwion->mp, tl);
235
4
    return NULL;
236
  }
237
444715
  struct AC ac = { .str = tdc->str };
238
444715
  if(ac_run(gwi, &ac) < 0) {
239
    if(tl)free_type_list(gwi->gwion->mp, tl);
240
    return NULL;
241
  }
242
444715
  tdc->str = ac.str;
243
444715
  if(*tdc->str == '.') {
244
2
    ++tdc->str;
245
2
    if(!(next =  _str2decl(gwi, tdc))) {
246
      if(tl)
247
        free_type_list(gwi->gwion->mp, tl);
248
      if(ac.base)
249
        free_exp(gwi->gwion->mp, ac.base);
250
      return NULL;
251
    }
252
  }
253
444715
  Type_Decl *td = new_type_decl(gwi->gwion->mp, sym, loc(gwi));
254
444715
  td->next = next;
255
444715
  td->types = tl;
256
444715
  if(ac.depth)
257
20
    td->array = mk_array(gwi->gwion->mp, &ac);
258
444715
  return td;
259
}
260
261
444711
ANN Type_Decl* str2decl(const Gwi gwi, const m_str str) {
262
444711
  const ae_flag flag = strncmp(str, "nonnull ", 8) ? ae_flag_none : ae_flag_nonnull;
263
444711
  struct td_checker tdc = { .str=str };
264
444711
  if(flag == ae_flag_nonnull)
265
17520
    tdc.str += 8;
266
444711
  DECL_OO(Type_Decl *, td, = _str2decl(gwi, &tdc))
267
444706
  if(*tdc.str) {
268
4
    free_type_decl(gwi->gwion->mp, td);
269
4
    GWI_ERR_O("excedental character '%c'", *tdc.str);
270
  }
271
444702
  td->flag |= flag;
272
444702
  return td;
273
}
274
275
40
ANN static inline m_bool ac_finish(const Gwi gwi, struct AC *ac) {
276
40
  if(*ac->str == ']')
277
39
    return GW_OK;
278
1
  GWI_ERR_B("unfinished array");
279
}
280
281
5
ANN static inline m_bool ac_num(const Gwi gwi, const m_int num) {
282
5
  if(num >= 0)
283
5
    return GW_OK;
284
  GWI_ERR_B("negative array dimension")
285
}
286
287
5
ANN static inline m_bool ac_exp(const Gwi gwi, struct AC *ac) {
288

5
  if(!ac->depth || ac->base)
289
5
    return GW_OK;
290
  GWI_ERR_B("malformed array [][...]")
291
}
292
293
34
ANN static inline m_bool ac_noexp(const Gwi gwi, struct AC *ac) {
294
34
  if(!ac->exp)
295
33
    return GW_OK;
296
1
  GWI_ERR_B("malformed array [...][]")
297
}
298
299
40
ANN static m_bool _ac_run(const Gwi gwi, struct AC *ac) {
300
40
  const m_str str = ac->str;
301
40
  const m_int num = strtol(str, &ac->str, 10);
302
40
  CHECK_BB(ac_finish(gwi, ac))
303
39
  if(str != ac->str) {
304
5
    CHECK_BB(ac_num(gwi, num))
305
5
    CHECK_BB(ac_exp(gwi, ac))
306
5
    const Exp exp = new_prim_int(gwi->gwion->mp, num, loc(gwi));
307
5
    ac_add_exp(ac, exp);
308
  } else
309
34
    CHECK_BB(ac_noexp(gwi, ac))
310
38
  ++ac->str;
311
38
  return GW_OK;
312
}
313
314
491508
ANN static m_bool ac_run(const Gwi gwi, struct AC *ac) {
315
983054
  while(*ac->str) {
316
53
    if(*ac->str != '[')
317
13
      break;
318
40
    ++ac->str;
319
40
    CHECK_BB(_ac_run(gwi, ac))
320
38
    ++ac->depth;
321
  }
322
491506
  return GW_OK;
323
}