| 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 |  |  | } |