GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/import/import_checker.c Lines: 178 201 88.6 %
Date: 2020-10-03 09:50:08 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
554331
ANN static Symbol gwisym(const Gwi gwi, const m_str str) {
20
554331
  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
554341
ANN static Symbol __str2sym(const Gwi gwi, struct td_checker *tdc) {
44
554341
  char buf[strlen(tdc->str) + 1];
45
554341
  m_str tmp = buf;
46
554341
  if(*tdc->str == '@')
47
64170
    *tmp++ = *tdc->str++;
48
3473636
  while(*tdc->str) {
49
2367889
    const char c = *tdc->str;
50

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

69989
  if(*tdc->str && *tdc->str != ':')
63
4
    GWI_ERR_O(_("illegal character '%c' in path '%s'."), *tdc->str, path)
64
69985
  return sym;
65
}
66
67
/** convert a string to a symbol, with error checking **/
68
14316
ANN Symbol str2sym(const Gwi gwi, const m_str path) {
69
14316
  struct td_checker tdc = { .str=path };
70
14316
  return _str2sym(gwi, &tdc, path);
71
}
72
73
// only in enum.c
74
1469
ANN ID_List str2symlist(const Gwi gwi, const m_str path) {
75
1469
  DECL_OO(const Symbol, sym, = str2sym(gwi, path))
76
1469
  return new_id_list(gwi->gwion->mp, sym, loc(gwi));
77
}
78
79
45702
ANN Var_Decl str2var(const Gwi gwi, const m_str path) {
80
45702
  struct td_checker tdc = { .str=path };
81
45702
  DECL_OO(const Symbol, sym, = __str2sym(gwi, &tdc))
82
45700
  struct AC ac = { .str = tdc.str };
83
45700
  CHECK_BO(ac_run(gwi, &ac))
84
91396
  const Array_Sub array = ac.depth ?
85
45698
    mk_array(gwi->gwion->mp, &ac) : NULL;
86
45698
  return new_var_decl(gwi->gwion->mp, sym, array, loc(gwi));
87
}
88
89
// only in udef.c
90
22139
ANN Var_Decl_List str2varlist(const Gwi gwi, const m_str path) {
91
22139
  DECL_OO(const Var_Decl, var, = str2var(gwi, path))
92
22136
  return new_var_decl_list(gwi->gwion->mp, var, NULL);
93
}
94
95
1442
ANN static ID_List _tmpl_list(const Gwi gwi, struct td_checker *tdc) {
96
1442
  DECL_OO(const Symbol, sym, = __str2sym(gwi, tdc))
97
1442
  ID_List next = NULL;
98
1442
  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
1442
  const ID_List list = new_id_list(gwi->gwion->mp, sym, loc(gwi));
104
1442
  list->next = next;
105
1442
  return list;
106
}
107
108
55671
ANN static ID_List __tmpl_list(const Gwi gwi, struct td_checker *tdc) {
109
55671
  if(tdc->str[0] != ':')
110
54231
    return NULL;
111
1440
  if(tdc->str[1] != '[')
112
    return (ID_List)GW_ERROR;
113
1440
  tdc->str += 2;
114
1440
  const ID_List list =  _tmpl_list(gwi, tdc);
115
1440
  if(list == (ID_List)GW_ERROR)
116
    return (ID_List)GW_ERROR;
117
1440
  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
1440
  ++tdc->str;
124
1440
  return list;
125
}
126
127
55673
ANN m_bool check_typename_def(const Gwi gwi, ImportCK *ck) {
128
55673
  struct td_checker tdc = { .str= ck->name };
129
55673
  if(!(ck->sym = _str2sym(gwi, &tdc, tdc.str)))
130
2
    return GW_ERROR;
131
55671
  ID_List il = __tmpl_list(gwi, &tdc);
132
55671
  if(il == (ID_List)GW_ERROR)
133
    return GW_ERROR;
134
55671
  ck->tmpl = il;
135
55671
  ck->name = s_name(ck->sym);
136
55671
  return GW_OK;
137
138
}
139
140
65668
ANN m_bool ck_ini(const Gwi gwi, const enum importck_type t) {
141
65668
  if(gwi->ck) // TODO: improve error message
142
4
    GWI_ERR_B(_("already importing"))
143
65664
  gwi->ck = mp_calloc2(gwi->gwion->mp, sizeof(ImportCK));
144
65664
  gwi->ck->type = t;
145
65664
  return GW_OK;
146
}
147
148
90702
ANN m_bool ck_ok(const Gwi gwi, const enum importck_type t) {
149
90702
  if(!gwi->ck)
150
1
    GWI_ERR_B(_("import not started"))
151
90701
  if(gwi->ck->type == t)
152
90700
    return GW_OK;
153
  // TODO: improve error message
154
1
  GWI_ERR_B(_("already importing"))
155
}
156
157
64210
ANN void ck_end(const Gwi gwi) {
158
64210
  mp_free2(gwi->gwion->mp, sizeof(ImportCK), gwi->ck);
159
64210
  gwi->ck = NULL;
160
64210
}
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
4
ANN Type_List __str2tl(const Gwi gwi, struct td_checker *tdc) {
180
4
  Type_Decl *td = _str2decl(gwi, tdc);
181
4
  if(!td)
182
1
    GWI_ERR_O("invalid types");
183
3
  Type_List next = NULL;
184
3
  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
3
  return new_type_list(gwi->gwion->mp, td, next);
192
}
193
194
437202
ANN static Type_List td_tmpl(const Gwi gwi, struct td_checker *tdc) {
195
437202
  if(*tdc->str != ':')
196
437198
    return NULL; // GW_PASS
197
4
  ++tdc->str;
198
4
  if(*tdc->str != '[') {
199
    GWI_ERR("invalid character");
200
    return (Type_List)GW_ERROR;
201
  }
202
4
  ++tdc->str;
203
4
  Type_List tl = __str2tl(gwi, tdc);
204
4
  if(!tl)
205
1
    return (Type_List)GW_ERROR;
206
3
  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
3
  ++tdc->str;
212
3
  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
437208
ANN Type_Decl* _str2decl(const Gwi gwi, struct td_checker *tdc) {
224
437208
  DECL_OO(const Symbol, sym, = __str2sym(gwi, tdc))
225
437202
  struct AC ac = { .str = tdc->str };
226
437202
  CHECK_BO(ac_run(gwi, &ac))
227
437202
  tdc->str = ac.str;
228
437202
  Type_List tl = td_tmpl(gwi, tdc);
229
437202
  if(tl == (Type_List)GW_ERROR)
230
1
    return NULL;
231
437201
  Type_Decl *next = NULL;
232
437201
  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
437201
  Type_Decl *td = new_type_decl(gwi->gwion->mp, sym, loc(gwi));
243
437201
  td->next = next;
244
437201
  td->types = tl;
245
437201
  if(ac.depth)
246
17
    td->array = mk_array(gwi->gwion->mp, &ac);
247
437201
  return td;
248
}
249
250
437202
ANN Type_Decl* str2decl(const Gwi gwi, const m_str str) {
251
437202
  const ae_flag flag = strncmp(str, "nonnull ", 8) ? ae_flag_none : ae_flag_nonnull;
252
437202
  struct td_checker tdc = { .str=str };
253
437202
  if(flag == ae_flag_nonnull)
254
17825
    tdc.str += 8;
255
437202
  DECL_OO(Type_Decl *, td, = _str2decl(gwi, &tdc))
256
437196
  if(*tdc.str) {
257
4
    free_type_decl(gwi->gwion->mp, td);
258
4
    GWI_ERR_O("excedental character '%c'", *tdc.str);
259
  }
260
437192
  td->flag |= flag;
261
437192
  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
482902
ANN static m_bool ac_run(const Gwi gwi, struct AC *ac) {
304
965837
  while(*ac->str) {
305
48
    if(*ac->str != '[')
306
13
      break;
307
35
    ++ac->str;
308
35
    CHECK_BB(_ac_run(gwi, ac))
309
33
    ++ac->depth;
310
  }
311
482900
  return GW_OK;
312
}