GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/string.c Lines: 179 426 42.0 %
Date: 2020-09-14 00:22:58 Branches: 49 178 27.5 %

Line Branch Exec Source
1
#include <stdlib.h>
2
#include <string.h>
3
#include <math.h>
4
#include "gwion_util.h"
5
#include "gwion_ast.h"
6
#include "gwion_env.h"
7
#include "vm.h"
8
#include "instr.h"
9
#include "object.h"
10
#include "gwion.h"
11
#include "operator.h"
12
#include "import.h"
13
#include "emit.h"
14
#include "specialid.h"
15
#include "gwi.h"
16
#include "gack.h"
17
18
10
ANN static void push_string(const VM_Shred shred, const M_Object obj, const m_str c) {
19
10
  STRING(obj) = s_name(insert_symbol(shred->info->vm->gwion->st, c));
20
10
  *(M_Object*)REG(-SZ_INT) = (M_Object)obj;
21
10
  _release(obj, shred);
22
10
}
23
24
#define describe_string_logical(name, action)    \
25
static INSTR(String_##name) {                    \
26
  POP_REG(shred, SZ_INT);                        \
27
  const M_Object lhs = *(M_Object*)REG(-SZ_INT); \
28
  const M_Object rhs = *(M_Object*)REG(0);       \
29
  *(m_int*)REG(-SZ_INT) = action;                \
30
  release(lhs, shred);                           \
31
  release(rhs, shred);                           \
32
}
33


5
describe_string_logical(eq, (lhs && rhs && STRING(lhs) == STRING(rhs)) || (!lhs && !rhs))
34


2
describe_string_logical(neq, !(lhs && rhs && STRING(lhs) == STRING(rhs)) || (!lhs && !rhs))
35
36
10
static INSTR(String_Assign) {
37
10
  POP_REG(shred, SZ_INT);
38
10
  const M_Object lhs = *(M_Object*)REG(-SZ_INT);
39
10
  const M_Object rhs = *(M_Object*)REG(0);
40
10
  release(lhs, shred);
41
10
  push_string(shred, rhs, lhs ? STRING(lhs) : "");
42
10
}
43
44
13
static CTOR(string_ctor) {
45
13
  STRING(o) = "";
46
13
}
47
48
64
ID_CHECK(check_funcpp) {
49
64
  ((Exp_Primary*)prim)->prim_type = ae_prim_str;
50
74
  ((Exp_Primary*)prim)->d.str = env->func ? env->func->name : env->class_def ?
51
10
    env->class_def->name : env->name;
52
64
  ((Exp_Primary*)prim)->value = global_string(env, prim->d.str);
53
64
  return prim->value->type;
54
}
55
56
453
static GACK(gack_string) {
57
453
  const M_Object obj = *(M_Object*)VALUE;
58
453
  INTERP_PRINTF("%s", obj ? STRING(obj) : "(null string)");
59
453
}
60
61
5
static inline m_bool bounds(const m_str str, const m_int i) {
62
5
  CHECK_BB(i)
63
4
  return (m_uint)i < strlen(str) ? GW_OK : GW_ERROR;
64
}
65
66
3
static INSTR(StringSlice) {
67
3
  shred->reg -= SZ_INT *2;
68
3
  const M_Object obj = *(M_Object*)REG(-SZ_INT);
69
3
  m_str str = STRING(obj);
70
3
  const m_int start = *(m_uint*)REG(0);
71
3
  const size_t strsz = strlen(str);
72
3
  m_int end   = *(m_uint*)REG(SZ_INT);
73
3
  if(end < 0)
74
2
    end = strsz + end;
75

3
  if(bounds(str, start) < 0 || bounds(str, end) < 0)
76
1
    Except(shred, "OutOfBoundsStringSlice");
77
2
  const m_int op    = start < end ? 1 : -1;
78
2
  const m_uint sz    = op > 0 ? end - start : start - end;
79
2
  char c[sz + 1];
80
11
  for(m_int i = start, j = 0; i != end; i += op, ++j)
81
9
    c[j] = str[i];
82
2
  c[sz] = '\0';
83
2
  *(M_Object*)REG(-SZ_INT) = new_string(shred->info->vm->gwion->mp, shred, c);
84
}
85
86
static MFUN(string_len) {
87
  *(m_uint*)RETURN = strlen(STRING(o));
88
}
89
90
static MFUN(string_upper) {
91
  char c[strlen(STRING(o)) + 1];
92
  strcpy(c, STRING(o));
93
  for(m_uint i = 0; i < strlen(c); i++)
94
    if(c[i]  >= 'a' && c[i] <= 'z')
95
      c[i] += 'A' - 'a';
96
  *(M_Object*)RETURN = new_string(shred->info->vm->gwion->mp, shred, c);
97
}
98
99
static MFUN(string_lower) {
100
  char c[strlen(STRING(o)) + 1];
101
  strcpy(c, STRING(o));
102
  for(m_uint i = 0; i < strlen(c); i++)
103
    if(c[i]  >= 'A' && c[i] <= 'Z')
104
      c[i] -= 'A' - 'a';
105
  *(M_Object*)RETURN = new_string(shred->info->vm->gwion->mp, shred, c);
106
}
107
108
static MFUN(string_ltrim) {
109
  m_uint i = 0;
110
  const m_str str = STRING(o);
111
  while(str[i] == ' ')
112
    i++;
113
  char c[strlen(str) - i + 1];
114
  strcpy(c, STRING(o) + i);
115
  *(M_Object*)RETURN = new_string(shred->info->vm->gwion->mp, shred, c);
116
}
117
118
static MFUN(string_rtrim) {
119
  const m_str str = STRING(o);
120
  m_uint len = strlen(str) - 1;
121
  while(str[len] == ' ')
122
    len--;
123
  char c[len + 2];
124
  strncpy(c, str, len + 1);
125
  c[len + 1] = '\0';
126
  *(M_Object*)RETURN = new_string(shred->info->vm->gwion->mp, shred, c);
127
}
128
129
1
static MFUN(string_trim) {
130
1
  const m_str str = STRING(o);
131
1
  m_int i, start = 0, end = 0, len = 0;
132
2
  while(str[len] != '\0')
133
    len++;
134
1
  for(i = 0; i < len; i++) {
135
    if(str[i] == ' ')
136
      start++;
137
    else break;
138
  }
139
1
  for(i = len - 1; i >= 0; i--) {
140
    if(str[i] == ' ')
141
      end++;
142
    else break;
143
  }
144
1
  if(len - start - end <= 0) {
145
1
    *(m_uint*)RETURN = 0;
146
1
    return;
147
  }
148
  char c[len - start - end + 1];
149
  for(i = start; i < len - end; i++)
150
    c[i - start] = str[i];
151
  c[len - start - end ] = '\0';
152
  *(M_Object*)RETURN = new_string(shred->info->vm->gwion->mp, shred, c);
153
}
154
155
static MFUN(string_charAt) {
156
  const m_str str = STRING(o);
157
  const m_int i = *(m_int*)MEM(SZ_INT);
158
  const m_uint len = strlen(str);
159
  if(i < 0 || (m_uint)i >= len)
160
    *(m_uint*)RETURN = -1;
161
  else
162
    *(m_uint*)RETURN = str[i];
163
}
164
165
static MFUN(string_setCharAt) {
166
  const m_str str = STRING(o);
167
  const m_int i = *(m_int*)MEM(SZ_INT);
168
  const m_int c = *(m_int*)MEM(SZ_INT * 2);
169
  const m_uint len = strlen(str);
170
  if(i < 0 || (m_uint)i >= len)
171
    *(m_uint*)RETURN = -1;
172
  else {
173
    str[i] = c;
174
    STRING(o) = s_name(insert_symbol(shred->info->vm->gwion->st, str));
175
    *(m_uint*)RETURN = c;
176
  }
177
}
178
179
static MFUN(string_insert) {
180
  char str[strlen(STRING(o)) + 1];
181
  strcpy(str, STRING(o));
182
  m_int i, len_insert = 0, index = *(m_int*)MEM(SZ_INT);
183
  const M_Object arg = *(M_Object*)MEM(SZ_INT * 2);
184
185
  if(!arg) {
186
    *(M_Object*)RETURN = NULL;
187
    return;
188
  }
189
  char insert[strlen(STRING(arg)) + 1];
190
  strcpy(insert, STRING(arg));
191
  const m_uint len = strlen(str);
192
  len_insert =  strlen(insert);
193
  char c[len + len_insert + 1];
194
  for(i = 0; i < index; i++)
195
    c[i] = str[i];
196
  for(i = 0; i < len_insert; i++)
197
    c[i + index] = insert[i];
198
  for(i = index; i < (m_int)len; i++)
199
    c[i + len_insert] = str[i];
200
  c[len + len_insert] = '\0';
201
  release(arg, shred);
202
  *(M_Object*)RETURN = new_string(shred->info->vm->gwion->mp, shred, c);;
203
}
204
205
static MFUN(string_replace) {
206
  char str[strlen(STRING(o)) + 1];
207
  strcpy(str, STRING(o));
208
  m_int i, len_insert = 0, index = *(m_int*)MEM(SZ_INT);
209
  const M_Object arg = *(M_Object*)MEM(SZ_INT * 2);
210
  if(!arg) {
211
    *(M_Object*)RETURN = o;
212
    return;
213
  }
214
  char insert[strlen(STRING(arg)) + 1];
215
  strcpy(insert, STRING(arg));
216
  const m_uint len = strlen(str);
217
  len_insert =  strlen(insert);
218
  if(index >= (m_int)len  || index < 0 || (index + len_insert + 1) <= 0) {
219
    release(arg, shred);
220
    *(M_Object*)RETURN = NULL;
221
    return;
222
  }
223
  char c[index + len_insert + 1];
224
  for(i = 0; i < index; i++)
225
    c[i] = str[i];
226
  for(i = 0; i < len_insert; i++)
227
    c[i + index] = insert[i];
228
  c[index + len_insert] = '\0';
229
  release(arg, shred);
230
  *(M_Object*)RETURN = new_string(shred->info->vm->gwion->mp, shred, c);;
231
}
232
233
1
static MFUN(string_replaceN) {
234
1
  char str[strlen(STRING(o)) + 1];
235
1
  strcpy(str, STRING(o));
236
1
  m_int i, index = *(m_int*)MEM(SZ_INT);
237
1
  const M_Object arg = *(M_Object*)MEM(SZ_INT * 3);
238
1
  const m_int _len = *(m_int*)MEM(SZ_INT * 2);
239

1
  if(!arg || index > (m_int)strlen(STRING(o)) || _len > (m_int)strlen(STRING(arg))) {
240
    *(M_Object*)RETURN = NULL;
241
    return;
242
  }
243
1
  char insert[strlen(STRING(arg)) + 1];
244
1
  const m_uint len = strlen(str);
245
1
  memset(insert, 0, len + 1);
246
1
  strcpy(insert, STRING(arg));
247
1
  str[len] = '\0';
248
1
  if(index > (m_int)len)
249
    index = len - 1;
250
1
  char c[len + _len];
251
1
  memset(c, 0, len + _len);
252
3
  for(i = 0; i < index; i++)
253
2
    c[i] = str[i];
254
4
  for(i = 0; i < _len; i++)
255
3
    c[i + index] = insert[i];
256
3
  for(i = index + _len; i < (m_int)len; i++)
257
2
    c[i] = str[i];
258
1
  c[len + _len - 1] = '\0';
259
1
  release(arg, shred);
260
1
  *(M_Object*)RETURN = new_string(shred->info->vm->gwion->mp, shred, c);;
261
}
262
263
static MFUN(string_find) {
264
  const m_str str = STRING(o);
265
  m_int i = 0, ret = -1;
266
  char arg = *(m_int*)MEM(SZ_INT);
267
  while(str[i] != '\0') {
268
    if(str[i] == arg) {
269
      ret = i;
270
      break;
271
    }
272
    i++;
273
  }
274
  *(m_uint*)RETURN = ret;
275
}
276
277
static MFUN(string_findStart) {
278
  const m_str str = STRING(o);
279
  const char pos = *(m_int*)MEM(SZ_INT);
280
  const char arg = *(m_int*)MEM(SZ_INT * 2);
281
  m_int i = pos, ret = -1;
282
  if(!strlen(str)) {
283
    *(M_Object*)RETURN = NULL;
284
    return;
285
  }
286
  while(str[i] != '\0') {
287
    if(str[i] == arg) {
288
      ret = i;
289
      break;
290
    }
291
    i++;
292
  }
293
  *(m_uint*)RETURN = ret;
294
}
295
296
static MFUN(string_findStr) {
297
  if(!strlen(STRING(o))) {
298
    *(M_Object*)RETURN = NULL;
299
    return;
300
  }
301
  char str[strlen(STRING(o)) + 1];
302
  strcpy(str, STRING(o));
303
  m_int ret = -1;
304
  const M_Object obj = *(M_Object*)MEM(SZ_INT);
305
  if(!obj) {
306
    *(m_uint*)RETURN = 0;
307
    return;
308
  }
309
  const m_str arg = STRING(obj);
310
  const m_int len  = strlen(str);
311
  m_int i = 0;
312
  const m_int arg_len = strlen(arg);
313
  while(i < len) {
314
    if(!strncmp(str + i, arg, arg_len)) {
315
      ret = i;
316
      break;
317
    }
318
    i++;
319
  }
320
  release(obj, shred);
321
  *(m_uint*)RETURN = ret;
322
}
323
324
static MFUN(string_findStrStart) {
325
  if(!strlen(STRING(o))) {
326
    *(M_Object*)RETURN = NULL;
327
    return;
328
  }
329
  char str[strlen(STRING(o)) + 1];
330
  strcpy(str, STRING(o));
331
  m_int ret = -1;
332
  const m_int start = *(m_int*)MEM(SZ_INT);
333
  const M_Object obj = *(M_Object*)MEM(SZ_INT * 2);
334
  if(!obj) {
335
    *(M_Object*)RETURN = NULL;
336
    return;
337
  }
338
  const m_str arg = STRING(obj);
339
  const m_int len  = strlen(str);
340
  m_int i = start;
341
  const m_int arg_len = strlen(arg);
342
  while(i < len) {
343
    if(!strncmp(str + i, arg, arg_len)) {
344
      ret = i;
345
      break;
346
    }
347
    i++;
348
  }
349
  release(obj, shred);
350
  *(m_uint*)RETURN = ret;
351
}
352
353
static MFUN(string_rfind) {
354
  const m_str str = STRING(o);
355
  m_int i = strlen(str) - 1, ret = -1;
356
  const char arg = *(m_int*)MEM(SZ_INT);
357
  while(i > -1 && str[i] != '\0') {
358
    if(str[i] == arg) {
359
      ret = i;
360
      break;
361
    }
362
    i--;
363
  }
364
  *(m_uint*)RETURN = ret;
365
}
366
367
static MFUN(string_rfindStart) {
368
  if(!strlen(STRING(o))) {
369
    *(M_Object*)RETURN = NULL;
370
    return;
371
  }
372
  char str[strlen(STRING(o)) + 1];
373
  strcpy(str, STRING(o));
374
  const char pos = *(m_int*)MEM(SZ_INT);
375
  const char arg = *(m_int*)MEM(SZ_INT * 2);
376
  m_int i = pos, ret = -1;
377
  while(i > 0 && str[i] != '\0') {
378
    if(str[i] == arg) {
379
      ret = i;
380
      break;
381
    }
382
    i--;
383
  }
384
  *(m_uint*)RETURN = ret;
385
}
386
387
static MFUN(string_rfindStr) {
388
  if(!strlen(STRING(o))) {
389
    *(M_Object*)RETURN = NULL;
390
    return;
391
  }
392
  char str[strlen(STRING(o)) + 1];
393
  strcpy(str, STRING(o));
394
  m_int ret = -1;
395
  const M_Object obj = *(M_Object*)MEM(SZ_INT);
396
  const m_str arg = STRING(o);
397
  const m_int len  = strlen(str);
398
  m_int i = len - 1;
399
  const m_int arg_len = strlen(arg);
400
  while(i) {
401
    if(!strncmp(str + i, arg, arg_len)) {
402
      ret = i;
403
      break;
404
    }
405
    i--;
406
  }
407
  release(obj, shred);
408
  *(m_uint*)RETURN = ret;
409
}
410
411
static MFUN(string_rfindStrStart) {
412
  if(!strlen(STRING(o))) {
413
    *(M_Object*)RETURN = NULL;
414
    return;
415
  }
416
  char str[strlen(STRING(o)) + 1];
417
  strcpy(str, STRING(o));
418
  m_int ret = -1;
419
  m_int start = *(m_int*)MEM(SZ_INT);
420
  const M_Object obj = *(M_Object*)MEM(SZ_INT * 2);
421
  if(!obj) {
422
    *(m_uint*)RETURN = 0;
423
    return;
424
  }
425
  m_str arg = STRING(obj);
426
427
  m_int i = start;
428
  const m_int arg_len = strlen(arg);
429
  while(i > -1) {
430
    if(!strncmp(str + i, arg, arg_len)) {
431
      ret = i;
432
      break;
433
    }
434
    i--;
435
  }
436
  release(obj, shred);
437
  *(m_uint*)RETURN = ret;
438
}
439
440
3
static MFUN(string_erase) {
441
3
  const m_str str = STRING(o);
442
3
  const m_int start = *(m_int*)MEM(SZ_INT);
443
3
  const m_int rem = *(m_int*)MEM(SZ_INT * 2);
444
3
  const m_int len = strlen(str);
445
3
  const m_int size = len - rem + 1;
446

3
  if(start >= len || size <= 0) {
447
1
    *(M_Object*)RETURN = NULL;
448
1
    return;
449
  }
450
2
  char c[size];
451
2
  c[size - 1] = '\0';
452
2
  for(m_int i = 0; i < start; i++)
453
    c[i] = str[i];
454
22
  for(m_int i = start + rem; i < len; i++)
455
20
    c[i - rem] = str[i];
456
2
  STRING(o) = s_name(insert_symbol(shred->info->vm->gwion->st, c));
457
}
458
459
711
GWION_IMPORT(string) {
460
711
  const Type t_string = gwi_class_ini(gwi, "string", NULL);
461
711
  gwi_class_xtor(gwi, string_ctor, NULL);
462
711
  GWI_BB(gwi_gack(gwi, t_string, gack_string))
463
711
  gwi->gwion->type[et_string] = t_string; // use func
464
465
711
  gwi_item_ini(gwi, "@internal", "@data");
466
711
  GWI_BB(gwi_item_end(gwi,   ae_flag_const, NULL))
467
468
711
  gwi_func_ini(gwi, "int", "size");
469
711
  GWI_BB(gwi_func_end(gwi, string_len, ae_flag_none))
470
471
711
  gwi_func_ini(gwi, "string", "upper");
472
711
  GWI_BB(gwi_func_end(gwi, string_upper, ae_flag_none))
473
474
711
  gwi_func_ini(gwi, "string", "lower");
475
711
  GWI_BB(gwi_func_end(gwi, string_lower, ae_flag_none))
476
477
711
  gwi_func_ini(gwi, "string", "ltrim");
478
711
  GWI_BB(gwi_func_end(gwi, string_ltrim, ae_flag_none))
479
480
711
  gwi_func_ini(gwi, "string", "rtrim");
481
711
  GWI_BB(gwi_func_end(gwi, string_rtrim, ae_flag_none))
482
483
711
  gwi_func_ini(gwi, "string", "trim");
484
711
  GWI_BB(gwi_func_end(gwi, string_trim, ae_flag_none))
485
486
711
  gwi_func_ini(gwi, "int", "charAt");
487
711
  gwi_func_arg(gwi, "int", "pos");
488
711
  GWI_BB(gwi_func_end(gwi, string_charAt, ae_flag_none))
489
490
711
  gwi_func_ini(gwi, "int", "charAt");
491
711
  gwi_func_arg(gwi, "int", "pos");
492
711
  gwi_func_arg(gwi, "char", "c");
493
711
  GWI_BB(gwi_func_end(gwi, string_setCharAt, ae_flag_none))
494
495
711
  gwi_func_ini(gwi, "string", "insert");
496
711
  gwi_func_arg(gwi, "int", "pos");
497
711
  gwi_func_arg(gwi, "string", "str");
498
711
  GWI_BB(gwi_func_end(gwi, string_insert, ae_flag_none))
499
500
711
  gwi_func_ini(gwi, "string", "replace");
501
711
  gwi_func_arg(gwi, "int", "pos");
502
711
  gwi_func_arg(gwi, "string", "str");
503
711
  GWI_BB(gwi_func_end(gwi, string_replace, ae_flag_none))
504
505
711
  gwi_func_ini(gwi, "string", "replace");
506
711
  gwi_func_arg(gwi, "int", "pos");
507
711
  gwi_func_arg(gwi, "int", "n");
508
711
  gwi_func_arg(gwi, "string", "str");
509
711
  GWI_BB(gwi_func_end(gwi, string_replaceN, ae_flag_none))
510
511
711
  gwi_func_ini(gwi, "int", "find");
512
711
  gwi_func_arg(gwi, "char", "c");
513
711
  GWI_BB(gwi_func_end(gwi, string_find, ae_flag_none))
514
515
711
  gwi_func_ini(gwi, "int", "find");
516
711
  gwi_func_arg(gwi, "int", "pos");
517
711
  gwi_func_arg(gwi, "char", "c");
518
711
  GWI_BB(gwi_func_end(gwi, string_findStart, ae_flag_none))
519
520
711
  gwi_func_ini(gwi, "int", "find");
521
711
  gwi_func_arg(gwi, "string", "str");
522
711
  GWI_BB(gwi_func_end(gwi, string_findStr, ae_flag_none))
523
524
711
  gwi_func_ini(gwi, "int", "find");
525
711
  gwi_func_arg(gwi, "int", "pos");
526
711
  gwi_func_arg(gwi, "string", "str");
527
711
  GWI_BB(gwi_func_end(gwi, string_findStrStart, ae_flag_none))
528
529
711
  gwi_func_ini(gwi, "int", "rfind");
530
711
  gwi_func_arg(gwi, "char", "c");
531
711
  GWI_BB(gwi_func_end(gwi, string_rfind, ae_flag_none))
532
533
711
  gwi_func_ini(gwi, "int", "rfind");
534
711
  gwi_func_arg(gwi, "int", "pos");
535
711
  gwi_func_arg(gwi, "char", "c");
536
711
  GWI_BB(gwi_func_end(gwi, string_rfindStart, ae_flag_none))
537
538
711
  gwi_func_ini(gwi, "int", "rfind");
539
711
  gwi_func_arg(gwi, "string", "str");
540
711
  GWI_BB(gwi_func_end(gwi, string_rfindStr, ae_flag_none))
541
542
711
  gwi_func_ini(gwi, "int", "rfind");
543
711
  gwi_func_arg(gwi, "int", "pos");
544
711
  gwi_func_arg(gwi, "string", "str");
545
711
  GWI_BB(gwi_func_end(gwi, string_rfindStrStart, ae_flag_none))
546
547
711
  gwi_func_ini(gwi, "void", "erase");
548
711
  gwi_func_arg(gwi, "int", "start");
549
711
  gwi_func_arg(gwi, "int", "length");
550
711
  GWI_BB(gwi_func_end(gwi, string_erase, ae_flag_none))
551
552
711
  GWI_BB(gwi_class_end(gwi))
553
554
711
  GWI_BB(gwi_oper_ini(gwi, "string",  "nonnull string", "nonnull string"))
555
711
  GWI_BB(gwi_oper_add(gwi, opck_const_rhs))
556
711
  GWI_BB(gwi_oper_end(gwi, "=>",      String_Assign))
557
558
711
  GWI_BB(gwi_oper_ini(gwi, "string",  "string", "bool"))
559
711
  GWI_BB(gwi_oper_end(gwi, "==",       String_eq))
560
711
  GWI_BB(gwi_oper_end(gwi, "!=",       String_neq))
561
562
711
  GWI_BB(gwi_oper_ini(gwi, "int", "nonnull string", "nonnull string"))
563
711
  GWI_BB(gwi_oper_end(gwi, "@slice", StringSlice))
564
565
711
  struct SpecialId_ spid = { .ck=check_funcpp, .exec=RegPushMe, .is_const=1 };
566
711
  gwi_specialid(gwi, "__func__", &spid);
567
711
  return GW_OK;
568
}