GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/import/checker.c Lines: 180 201 89.6 %
Date: 2020-09-14 00:22:58 Branches: 96 122 78.7 %

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
552062
ANN static Symbol gwisym(const Gwi gwi, const m_str str) {
20
552062
  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
552072
ANN static Symbol __str2sym(const Gwi gwi, struct td_checker *tdc) {
44
552072
  char buf[strlen(tdc->str) + 1];
45
552072
  m_str tmp = buf;
46
552072
  if(*tdc->str == '@')
47
63279
    *tmp++ = *tdc->str++;
48
3458901
  while(*tdc->str) {
49
2357680
    const char c = *tdc->str;
50

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

69792
  if(*tdc->str && *tdc->str != '<')
63
3
    GWI_ERR_O(_("illegal character '%c' in path '%s'."), *tdc->str, path)
64
69789
  return sym;
65
}
66
67
/** convert a string to a symbol, with error checking **/
68
14276
ANN Symbol str2sym(const Gwi gwi, const m_str path) {
69
14276
  struct td_checker tdc = { .str=path };
70
14276
  return _str2sym(gwi, &tdc, path);
71
}
72
73
// only in enum.c
74
1465
ANN ID_List str2symlist(const Gwi gwi, const m_str path) {
75
1465
  DECL_OO(const Symbol, sym, = str2sym(gwi, path))
76
1465
  return new_id_list(gwi->gwion->mp, sym, loc(gwi));
77
}
78
79
45574
ANN Var_Decl str2var(const Gwi gwi, const m_str path) {
80
45574
  struct td_checker tdc = { .str=path };
81
45574
  DECL_OO(const Symbol, sym, = __str2sym(gwi, &tdc))
82
45572
  struct AC ac = { .str = tdc.str };
83
45572
  CHECK_BO(ac_run(gwi, &ac))
84
91140
  const Array_Sub array = ac.depth ?
85
45570
    mk_array(gwi->gwion->mp, &ac) : NULL;
86
45570
  return new_var_decl(gwi->gwion->mp, sym, array, loc(gwi));
87
}
88
89
// only in udef.c
90
22077
ANN Var_Decl_List str2varlist(const Gwi gwi, const m_str path) {
91
22077
  DECL_OO(const Var_Decl, var, = str2var(gwi, path))
92
22074
  return new_var_decl_list(gwi->gwion->mp, var, NULL);
93
}
94
95
1437
ANN static ID_List _tmpl_list(const Gwi gwi, struct td_checker *tdc) {
96
1437
  DECL_OO(const Symbol, sym, = __str2sym(gwi, tdc))
97
1437
  ID_List next = NULL;
98
1437
  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
1437
  const ID_List list = new_id_list(gwi->gwion->mp, sym, loc(gwi));
104
1437
  list->next = next;
105
1437
  return list;
106
}
107
108
55514
ANN static ID_List __tmpl_list(const Gwi gwi, struct td_checker *tdc) {
109
55514
  if(tdc->str[0] != '<')
110
54079
    return NULL;
111
1435
  if(tdc->str[1] != '~')
112
    return (ID_List)GW_ERROR;
113
1435
  tdc->str += 2;
114
1435
  const ID_List list =  _tmpl_list(gwi, tdc);
115
1435
  if(list == (ID_List)GW_ERROR)
116
    return (ID_List)GW_ERROR;
117

1435
  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
1435
  tdc->str += 2;
124
1435
  return list;
125
}
126
127
55516
ANN m_bool check_typename_def(const Gwi gwi, ImportCK *ck) {
128
55516
  struct td_checker tdc = { .str= ck->name };
129
55516
  if(!(ck->sym = _str2sym(gwi, &tdc, tdc.str)))
130
2
    return GW_ERROR;
131
55514
  ID_List il = __tmpl_list(gwi, &tdc);
132
55514
  if(il == (ID_List)GW_ERROR)
133
    return GW_ERROR;
134
55514
  ck->tmpl = il;
135
55514
  ck->name = s_name(ck->sym);
136
55514
  return GW_OK;
137
138
}
139
140
65483
ANN m_bool ck_ini(const Gwi gwi, const enum importck_type t) {
141
65483
  if(gwi->ck) // TODO: improve error message
142
4
    GWI_ERR_B(_("already importing"))
143
65479
  gwi->ck = mp_calloc2(gwi->gwion->mp, sizeof(ImportCK));
144
65479
  gwi->ck->type = t;
145
65479
  return GW_OK;
146
}
147
148
90447
ANN m_bool ck_ok(const Gwi gwi, const enum importck_type t) {
149
90447
  if(!gwi->ck)
150
1
    GWI_ERR_B(_("import not started"))
151
90446
  if(gwi->ck->type == t)
152
90445
    return GW_OK;
153
  // TODO: improve error message
154
1
  GWI_ERR_B(_("already importing"))
155
}
156
157
64029
ANN void ck_end(const Gwi gwi) {
158
64029
  mp_free2(gwi->gwion->mp, sizeof(ImportCK), gwi->ck);
159
64029
  gwi->ck = NULL;
160
64029
}
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
435263
ANN static Type_List td_tmpl(const Gwi gwi, struct td_checker *tdc) {
195
435263
  if(*tdc->str != '<')
196
435259
    return NULL; // GW_PASS
197
4
  ++tdc->str;
198
4
  if(*tdc->str != '~') {
199
1
    GWI_ERR("invalid character");
200
1
    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] != '~' || tdc->str[1] != '>') {
207
    free_type_list(gwi->gwion->mp, tl);
208
    GWI_ERR("unfinished template");
209
    return (Type_List)GW_ERROR;
210
  }
211
2
  tdc->str += 2;
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
435269
ANN Type_Decl* _str2decl(const Gwi gwi, struct td_checker *tdc) {
224
435269
  DECL_OO(const Symbol, sym, = __str2sym(gwi, tdc))
225
435263
  struct AC ac = { .str = tdc->str };
226
435263
  CHECK_BO(ac_run(gwi, &ac))
227
435263
  tdc->str = ac.str;
228
435263
  Type_List tl = td_tmpl(gwi, tdc);
229
435263
  if(tl == (Type_List)GW_ERROR)
230
2
    return NULL;
231
435261
  Type_Decl *next = NULL;
232
435261
  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
435261
  Type_Decl *td = new_type_decl(gwi->gwion->mp, sym, loc(gwi));
243
435261
  td->next = next;
244
435261
  td->types = tl;
245
435261
  if(ac.depth)
246
17
    td->array = mk_array(gwi->gwion->mp, &ac);
247
435261
  return td;
248
}
249
250
435264
ANN Type_Decl* str2decl(const Gwi gwi, const m_str str) {
251
435264
  const ae_flag flag = strncmp(str, "nonnull ", 8) ? ae_flag_none : ae_flag_nonnull;
252
435264
  struct td_checker tdc = { .str=str };
253
435264
  if(flag == ae_flag_nonnull)
254
17064
    tdc.str += 8;
255
435264
  DECL_OO(Type_Decl *, td, = _str2decl(gwi, &tdc))
256
435257
  if(*tdc.str) {
257
3
    free_type_decl(gwi->gwion->mp, td);
258
3
    GWI_ERR_O("excedental character '%c'", *tdc.str);
259
  }
260
435254
  td->flag |= flag;
261
435254
  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
480835
ANN static m_bool ac_run(const Gwi gwi, struct AC *ac) {
304
961703
  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
480833
  return GW_OK;
312
}