Coverage Report

Created: 2026-01-25 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/testdir/tests/capi/luaL_loadbuffer_proto/serializer.cc
Line
Count
Source
1
/*
2
 * SPDX-License-Identifier: BSD-2-Clause
3
 *
4
 * Copyright 2023-2026, Sergey Bronnikov.
5
 * Copyright 2022, Tarantool AUTHORS, please see AUTHORS file.
6
 */
7
#include "serializer.h"
8
9
#include <stack>
10
#include <string>
11
12
/**
13
* If control flow reaches the point of the unreachable(), the program is
14
* undefined. It is useful in situations where the compiler cannot deduce
15
* the unreachability of the code.
16
*/
17
#if __has_builtin(__builtin_unreachable) || defined(__GNUC__)
18
0
#  define unreachable() (assert(0), __builtin_unreachable())
19
#else
20
#  define unreachable() (assert(0))
21
#endif
22
23
using namespace lua_grammar;
24
25
extern char preamble_lua[];
26
27
#define PROTO_TOSTRING(TYPE, VAR_NAME) \
28
  std::string TYPE##ToString(const TYPE & (VAR_NAME))
29
30
/* PROTO_TOSTRING version for nested (depth=2) protobuf messages. */
31
#define NESTED_PROTO_TOSTRING(TYPE, VAR_NAME, PARENT_MESSAGE) \
32
  std::string TYPE##ToString \
33
  (const PARENT_MESSAGE::TYPE & (VAR_NAME))
34
35
namespace luajit_fuzzer {
36
namespace {
37
38
/*
39
 * The following keywords are reserved and cannot be used as names,
40
 * see Lua 5.1 Reference Manual, 2.1 – Lexical Conventions.
41
 */
42
const std::set<std::string> KReservedLuaKeywords {
43
  "and",
44
  "break",
45
  "do",
46
  "else",
47
  "elseif",
48
  "end",
49
  "false",
50
  "for",
51
  "function",
52
  "if",
53
  "in",
54
  "local",
55
  "nil",
56
  "not",
57
  "or",
58
  "repeat",
59
  "return",
60
  "then",
61
  "true",
62
  "until",
63
  "while",
64
};
65
66
const std::string kCounterNamePrefix = "counter_";
67
const std::string kNumberWrapperName = "always_number";
68
const std::string kBinOpWrapperName = "only_numbers_cmp";
69
const std::string kNotNaNAndNilWrapperName = "not_nan_and_nil";
70
71
PROTO_TOSTRING(Block, block);
72
PROTO_TOSTRING(Chunk, chunk);
73
74
PROTO_TOSTRING(Statement, stat);
75
76
/** LastStatement and nested types. */
77
PROTO_TOSTRING(LastStatement, laststat);
78
NESTED_PROTO_TOSTRING(ReturnOptionalExpressionList, explist, LastStatement);
79
80
/**
81
 * Statement options.
82
 */
83
84
/** AssignmentList and nested types. */
85
PROTO_TOSTRING(AssignmentList, assignmentlist);
86
NESTED_PROTO_TOSTRING(VariableList, varlist, AssignmentList);
87
88
/** FunctionCall and nested types. */
89
PROTO_TOSTRING(FunctionCall, call);
90
NESTED_PROTO_TOSTRING(Args, args, FunctionCall);
91
NESTED_PROTO_TOSTRING(PrefixArgs, prefixargs, FunctionCall);
92
NESTED_PROTO_TOSTRING(PrefixNamedArgs, prefixnamedargs, FunctionCall);
93
94
/** DoBlock, WhileCycle and RepeatCycle clauses. */
95
PROTO_TOSTRING(DoBlock, block);
96
PROTO_TOSTRING(WhileCycle, whilecycle);
97
PROTO_TOSTRING(RepeatCycle, repeatcycle);
98
99
/** IfStatement and nested types. */
100
PROTO_TOSTRING(IfStatement, statement);
101
NESTED_PROTO_TOSTRING(ElseIfBlock, elseifblock, IfStatement);
102
103
/** ForCycleName and ForCycleList clauses. */
104
PROTO_TOSTRING(ForCycleName, forcyclename);
105
PROTO_TOSTRING(ForCycleList, forcyclelist);
106
107
/** Function and nested types. */
108
PROTO_TOSTRING(Function, func);
109
NESTED_PROTO_TOSTRING(FuncName, funcname, Function);
110
111
PROTO_TOSTRING(NameList, namelist);
112
NESTED_PROTO_TOSTRING(NameListWithEllipsis, namelist, FuncBody);
113
NESTED_PROTO_TOSTRING(ParList, parlist, FuncBody);
114
115
/** LocalFunc and LocalNames clauses. */
116
PROTO_TOSTRING(LocalFunc, localfunc);
117
PROTO_TOSTRING(LocalNames, localnames);
118
119
/**
120
 * Expressions and variables.
121
 */
122
123
/** Expressions clauses. */
124
PROTO_TOSTRING(ExpressionList, explist);
125
PROTO_TOSTRING(OptionalExpressionList, explist);
126
PROTO_TOSTRING(PrefixExpression, prefExpr);
127
128
/* Variable and nested types. */
129
PROTO_TOSTRING(Variable, var);
130
NESTED_PROTO_TOSTRING(IndexWithExpression, indexexpr, Variable);
131
NESTED_PROTO_TOSTRING(IndexWithName, indexname, Variable);
132
133
/** Expression and nested types. */
134
PROTO_TOSTRING(Expression, expr);
135
NESTED_PROTO_TOSTRING(AnonFunc, function, Expression);
136
NESTED_PROTO_TOSTRING(ExpBinaryOpExp, binary, Expression);
137
NESTED_PROTO_TOSTRING(UnaryOpExp, unary, Expression);
138
139
/**
140
 * Tables and fields.
141
 */
142
PROTO_TOSTRING(TableConstructor, table);
143
PROTO_TOSTRING(FieldList, fieldlist);
144
NESTED_PROTO_TOSTRING(FieldWithFieldSep, field, FieldList);
145
146
/** Field and nested types. */
147
PROTO_TOSTRING(Field, field);
148
NESTED_PROTO_TOSTRING(ExpressionAssignment, assignment, Field);
149
NESTED_PROTO_TOSTRING(NameAssignment, assignment, Field);
150
PROTO_TOSTRING(FieldSep, sep);
151
152
/** Operators. */
153
PROTO_TOSTRING(BinaryOperator, op);
154
PROTO_TOSTRING(UnaryOperator, op);
155
156
/** Identifier (Name). */
157
PROTO_TOSTRING(Name, name);
158
159
std::string
160
NumberWrappedExpressionToString(const Expression &expr)
161
12.4k
{
162
12.4k
  std::string retval;
163
12.4k
  retval += kNumberWrapperName;
164
12.4k
  retval += "(";
165
12.4k
  retval += ExpressionToString(expr);
166
12.4k
  retval += ")";
167
168
12.4k
  return retval;
169
12.4k
}
170
171
std::string
172
AllowedIndexExpressionToString(const Expression &expr)
173
5.00k
{
174
5.00k
  std::string retval;
175
5.00k
  retval += kNotNaNAndNilWrapperName;
176
5.00k
  retval += "(";
177
5.00k
  retval += ExpressionToString(expr);
178
5.00k
  retval += ")";
179
5.00k
  return retval;
180
5.00k
}
181
182
/**
183
 * Class that controls id creation for counters. Basically, a
184
 * variable wrapper that guarantees variable to be incremented.
185
 */
186
class CounterIdProvider {
187
public:
188
  /** Returns number of id provided. */
189
  std::size_t count()
190
125k
  {
191
125k
    return id_;
192
125k
  }
193
194
  /** Returns a new id that was not used after last clean(). */
195
  std::size_t next()
196
123k
  {
197
123k
    return id_++;
198
123k
  }
199
200
  /**
201
   * Cleans history. Should be used to make fuzzer starts
202
   * independent.
203
   */
204
  void clean()
205
1.88k
  {
206
1.88k
    id_ = 0;
207
1.88k
  }
208
209
private:
210
  std::size_t id_ = 0;
211
};
212
213
/** A singleton for counter id provider. */
214
CounterIdProvider&
215
GetCounterIdProvider()
216
250k
{
217
250k
  static CounterIdProvider provider;
218
250k
  return provider;
219
250k
}
220
221
std::string
222
GetCounterName(std::size_t id)
223
247k
{
224
247k
  return kCounterNamePrefix + std::to_string(id);
225
247k
}
226
227
/** Returns `<counter_name> = <counter_name> + 1`. */
228
std::string
229
GetCounterIncrement(const std::string &counter_name)
230
123k
{
231
123k
  std::string retval = counter_name;
232
123k
  retval += " = ";
233
123k
  retval += counter_name;
234
123k
  retval += " + 1;\n";
235
123k
  return retval;
236
123k
}
237
238
/**
239
 * Returns `if <counter_name> > kMaxCounterValue then
240
 * <then_block> end`.
241
 */
242
std::string
243
GetCondition(const std::string &counter_name, const std::string &then_block)
244
123k
{
245
123k
  std::string retval = "if ";
246
123k
  retval += counter_name;
247
123k
  retval += " > ";
248
123k
  retval += std::to_string(kMaxCounterValue);
249
123k
  retval += " then ";
250
123k
  retval += then_block;
251
123k
  retval += " end\n";
252
123k
  return retval;
253
123k
}
254
255
/**
256
 * Class that registers and provides context during code
257
 * generation.
258
 * Used to generate correct Lua code.
259
 */
260
class Context {
261
public:
262
  enum class BlockType {
263
    kReturnable,
264
    kBreakable,
265
    kReturnableWithVararg,
266
  };
267
268
  void step_in(BlockType type)
269
123k
  {
270
123k
    block_stack_.push(type);
271
123k
    if (block_type_is_returnable_(type)) {
272
47.5k
      returnable_stack_.push(type);
273
47.5k
    }
274
123k
  }
275
276
  void step_out()
277
123k
  {
278
123k
    assert(!block_stack_.empty());
279
123k
    if (block_type_is_returnable_(block_stack_.top())) {
280
47.5k
      assert(!returnable_stack_.empty());
281
47.5k
      returnable_stack_.pop();
282
47.5k
    }
283
123k
    block_stack_.pop();
284
123k
  }
285
286
  std::string get_next_block_setup()
287
123k
  {
288
123k
    std::size_t id = GetCounterIdProvider().next();
289
123k
    std::string counter_name = GetCounterName(id);
290
291
123k
    return GetCondition(counter_name, get_exit_statement_()) +
292
123k
           GetCounterIncrement(counter_name);
293
123k
  }
294
295
  bool break_is_possible()
296
3.19k
  {
297
3.19k
    return !block_stack_.empty() &&
298
2.66k
           block_stack_.top() == BlockType::kBreakable;
299
3.19k
  }
300
301
  bool return_is_possible()
302
12.7k
  {
303
12.7k
    return !returnable_stack_.empty();
304
12.7k
  }
305
306
  bool vararg_is_possible()
307
5.36k
  {
308
5.36k
    return (returnable_stack_.empty() ||
309
1.53k
      (!returnable_stack_.empty() &&
310
1.53k
       returnable_stack_.top() ==
311
1.53k
        BlockType::kReturnableWithVararg));
312
5.36k
  }
313
314
private:
315
316
  bool block_type_is_returnable_(BlockType type)
317
247k
  {
318
247k
    switch (type) {
319
151k
    case BlockType::kBreakable:
320
151k
      return false;
321
90.8k
    case BlockType::kReturnable:
322
95.1k
    case BlockType::kReturnableWithVararg:
323
95.1k
      return true;
324
247k
    }
325
0
    unreachable();
326
0
  }
327
328
  std::string get_exit_statement_()
329
123k
  {
330
123k
    assert(!block_stack_.empty());
331
123k
    switch (block_stack_.top()) {
332
75.9k
    case BlockType::kBreakable:
333
75.9k
      return "break";
334
45.4k
    case BlockType::kReturnable:
335
47.5k
    case BlockType::kReturnableWithVararg:
336
47.5k
      return "return";
337
123k
    }
338
0
    unreachable();
339
0
  }
340
341
  std::stack<BlockType> block_stack_;
342
  /*
343
   * The returnable block can be exited with return from
344
   * the breakable block within it, but the breakable block
345
   * cannot be exited with break from the returnable block within
346
   * it.
347
   * Valid code:
348
   * `function foo() while true do return end end`
349
   * Erroneous code:
350
   * `while true do function foo() break end end`
351
   * This stack is used to check if `return` is possible.
352
   */
353
  std::stack<BlockType> returnable_stack_;
354
};
355
356
Context&
357
GetContext()
358
392k
{
359
392k
  static Context context;
360
392k
  return context;
361
392k
}
362
363
/**
364
 * Block may be placed not only in a cycle, so specially for cycles
365
 * there is a function that will add a break condition and a
366
 * counter increment.
367
 */
368
std::string
369
BlockToStringCycleProtected(const Block &block)
370
75.9k
{
371
75.9k
  std::string retval = GetContext().get_next_block_setup();
372
75.9k
  retval += ChunkToString(block.chunk());
373
75.9k
  return retval;
374
75.9k
}
375
376
/**
377
 * DoBlock may be placed not only in a cycle, so specially for
378
 * cycles there is a function that will call
379
 * BlockToStringCycleProtected().
380
 */
381
std::string
382
DoBlockToStringCycleProtected(const DoBlock &block)
383
26.6k
{
384
26.6k
  std::string retval = "do\n";
385
26.6k
  retval += BlockToStringCycleProtected(block.block());
386
26.6k
  retval += "end\n";
387
26.6k
  return retval;
388
26.6k
}
389
390
/**
391
 * FuncBody may contain recursive calls, so for all function bodies,
392
 * there is a function that adds a return condition and a counter
393
 * increment.
394
 */
395
std::string
396
FuncBodyToStringReqProtected(const FuncBody &body)
397
47.5k
{
398
47.5k
  std::string body_str = "( ";
399
47.5k
  if (body.has_parlist()) {
400
8.37k
    body_str += ParListToString(body.parlist());
401
8.37k
  }
402
47.5k
  body_str += " )\n\t";
403
404
47.5k
  body_str += GetContext().get_next_block_setup();
405
406
47.5k
  body_str += BlockToString(body.block());
407
47.5k
  body_str += "end\n";
408
47.5k
  return body_str;
409
47.5k
}
410
411
bool
412
FuncBodyHasVararg(const FuncBody &body)
413
47.5k
{
414
47.5k
  if (!body.has_parlist()) {
415
39.1k
    return false;
416
39.1k
  }
417
8.37k
  const FuncBody::ParList &parlist = body.parlist();
418
8.37k
  switch (parlist.parlist_oneof_case()) {
419
1.33k
  case FuncBody::ParList::ParlistOneofCase::kNamelist:
420
1.33k
    return parlist.namelist().has_ellipsis();
421
1.28k
  case FuncBody::ParList::ParlistOneofCase::kEllipsis:
422
1.28k
    return true;
423
5.75k
  default:
424
5.75k
    return parlist.namelist().has_ellipsis();
425
8.37k
  }
426
8.37k
}
427
428
Context::BlockType
429
GetFuncBodyType(const FuncBody &body)
430
47.5k
{
431
47.5k
  return FuncBodyHasVararg(body) ?
432
2.12k
    Context::BlockType::kReturnableWithVararg :
433
47.5k
    Context::BlockType::kReturnable;
434
47.5k
}
435
436
std::string
437
ClearIdentifier(const std::string &identifier)
438
257k
{
439
257k
  std::string cleared;
440
441
257k
  bool has_first_not_digit = false;
442
257k
  for (char c : identifier) {
443
136k
    if (has_first_not_digit && (std::iswalnum(c) || c == '_')) {
444
74.7k
      cleared += c;
445
74.7k
    } else if (std::isalpha(c) || c == '_') {
446
10.8k
      has_first_not_digit = true;
447
10.8k
      cleared += c;
448
51.3k
    } else {
449
51.3k
      cleared += '_';
450
51.3k
    }
451
136k
  }
452
257k
  return cleared;
453
257k
}
454
455
/** Drop any special symbols to avoid parser errors. */
456
std::string
457
ClearString(const std::string &str)
458
172k
{
459
172k
  std::string escaped;
460
172k
  int nbackslash = 0;
461
172k
  for (char c : str) {
462
88.9k
    if (c == '\\') {
463
1.89k
      nbackslash++;
464
87.1k
    } else {
465
87.1k
      if (!std::isprint(c))
466
8.31k
        continue;
467
78.7k
      nbackslash = 0;
468
78.7k
      if (c == '\'' || c == '\n')
469
6.86k
        escaped += '\\';
470
78.7k
    }
471
80.6k
    escaped += c;
472
80.6k
  }
473
  /* Avoid escaping the ending quote. */
474
172k
  if (nbackslash & 1)
475
93
    escaped += '\\';
476
172k
  return escaped;
477
172k
}
478
479
inline std::string
480
clamp(std::string s, size_t maxSize = kMaxStrLength)
481
430k
{
482
430k
  if (s.size() > maxSize)
483
4.70k
    s.resize(maxSize);
484
430k
  return s;
485
430k
}
486
487
inline double
488
clamp(double number, double upper, double lower)
489
16.1k
{
490
16.1k
  return number <= lower ? lower :
491
16.1k
         number >= upper ? upper : number;
492
16.1k
}
493
494
/**
495
 * Function to sanitize strings or identifiers. For identifiers,
496
 * sanitization is more stringent.
497
 */
498
inline std::string
499
ConvertToStringDefault(const std::string &s, bool is_identifier = false)
500
430k
{
501
430k
  std::string str = clamp(s);
502
430k
  if (is_identifier)
503
257k
    str = ClearIdentifier(str);
504
172k
  else
505
172k
    str = ClearString(str);
506
430k
  if (is_identifier && str.empty())
507
239k
    str = std::string(kDefaultIdent);
508
430k
  return str;
509
430k
}
510
511
PROTO_TOSTRING(Block, block)
512
71.2k
{
513
71.2k
  return ChunkToString(block.chunk());
514
71.2k
}
515
516
PROTO_TOSTRING(Chunk, chunk)
517
147k
{
518
147k
  std::string chunk_str;
519
354k
  for (int i = 0; i < chunk.stat_size(); ++i)
520
207k
    chunk_str += StatementToString(chunk.stat(i)) + "\n";
521
522
147k
  if (chunk.has_laststat())
523
15.9k
    chunk_str += LastStatementToString(chunk.laststat()) + "\n";
524
525
147k
  return chunk_str;
526
147k
}
527
528
/**
529
 * LastStatement and nested types.
530
 */
531
PROTO_TOSTRING(LastStatement, laststat)
532
15.9k
{
533
15.9k
  std::string laststat_str;
534
15.9k
  using LastStatType = LastStatement::LastOneofCase;
535
15.9k
  switch (laststat.last_oneof_case()) {
536
5.26k
  case LastStatType::kExplist:
537
5.26k
    laststat_str = ReturnOptionalExpressionListToString(
538
5.26k
      laststat.explist());
539
5.26k
    break;
540
3.19k
  case LastStatType::kBreak:
541
3.19k
    if (GetContext().break_is_possible()) {
542
1.50k
      laststat_str = "break";
543
1.50k
    }
544
3.19k
    break;
545
7.51k
  default:
546
    /* Chosen as default in order to decrease number of 'break's. */
547
7.51k
    laststat_str = ReturnOptionalExpressionListToString(
548
7.51k
      laststat.explist());
549
7.51k
    break;
550
15.9k
  }
551
552
  /*
553
   * Add a semicolon when last statement is not empty
554
   * to avoid errors like:
555
   *
556
   * <preamble.lua>
557
   * (nil):Name0()
558
   * (nil)() -- ambiguous syntax (function call x new statement) near '('
559
   */
560
15.9k
  if (!laststat_str.empty())
561
9.81k
    laststat_str += "; ";
562
563
15.9k
  return laststat_str;
564
15.9k
}
565
566
NESTED_PROTO_TOSTRING(ReturnOptionalExpressionList, explist, LastStatement)
567
12.7k
{
568
12.7k
  if (!GetContext().return_is_possible()) {
569
4.47k
    return "";
570
4.47k
  }
571
572
8.30k
  std::string explist_str = "return";
573
8.30k
  if (explist.has_explist()) {
574
4.08k
    explist_str += " " + ExpressionListToString(explist.explist());
575
4.08k
    explist_str += " ";
576
4.08k
  }
577
8.30k
  return explist_str;
578
12.7k
}
579
580
/**
581
 * Statement and statement options.
582
 */
583
PROTO_TOSTRING(Statement, stat)
584
207k
{
585
207k
  std::string stat_str;
586
207k
  using StatType = Statement::StatOneofCase;
587
207k
  switch (stat.stat_oneof_case()) {
588
12.1k
  case StatType::kList:
589
12.1k
    stat_str = AssignmentListToString(stat.list());
590
12.1k
    break;
591
47.8k
  case StatType::kCall:
592
47.8k
    stat_str = FunctionCallToString(stat.call());
593
47.8k
    break;
594
2.21k
  case StatType::kBlock:
595
2.21k
    stat_str = DoBlockToString(stat.block());
596
2.21k
    break;
597
4.92k
  case StatType::kWhilecycle:
598
4.92k
    stat_str = WhileCycleToString(stat.whilecycle());
599
4.92k
    break;
600
49.3k
  case StatType::kRepeatcycle:
601
49.3k
    stat_str = RepeatCycleToString(stat.repeatcycle());
602
49.3k
    break;
603
9.48k
  case StatType::kIfstat:
604
9.48k
    stat_str = IfStatementToString(stat.ifstat());
605
9.48k
    break;
606
4.87k
  case StatType::kForcyclename:
607
4.87k
    stat_str = ForCycleNameToString(stat.forcyclename());
608
4.87k
    break;
609
16.8k
  case StatType::kForcyclelist:
610
16.8k
    stat_str = ForCycleListToString(stat.forcyclelist());
611
16.8k
    break;
612
6.14k
  case StatType::kFunc:
613
6.14k
    stat_str = FunctionToString(stat.func());
614
6.14k
    break;
615
10.1k
  case StatType::kLocalfunc:
616
10.1k
    stat_str = LocalFuncToString(stat.localfunc());
617
10.1k
    break;
618
10.3k
  case StatType::kLocalnames:
619
10.3k
    stat_str = LocalNamesToString(stat.localnames());
620
10.3k
    break;
621
33.0k
  default:
622
    /**
623
     * Chosen arbitrarily more for simplicity.
624
     * TODO: Choose "more interesting" defaults.
625
     */
626
33.0k
    stat_str = AssignmentListToString(stat.list());
627
33.0k
    break;
628
207k
  }
629
630
  /*
631
   * Always add a semicolon regardless of grammar
632
   * to avoid errors like:
633
   *
634
   * <preamble.lua>
635
   * (nil):Name0()
636
   * (nil)() -- ambiguous syntax (function call x new statement) near '('
637
   */
638
207k
  stat_str += "; ";
639
640
207k
  return stat_str;
641
207k
}
642
643
/**
644
 * AssignmentList and nested types.
645
 */
646
PROTO_TOSTRING(AssignmentList, assignmentlist)
647
45.2k
{
648
45.2k
  std::string list_str = VariableListToString(assignmentlist.varlist());
649
45.2k
  list_str += " = " + ExpressionListToString(assignmentlist.explist());
650
45.2k
  return list_str;
651
45.2k
}
652
653
NESTED_PROTO_TOSTRING(VariableList, varlist, AssignmentList)
654
45.2k
{
655
45.2k
  std::string varlist_str = VariableToString(varlist.var());
656
59.6k
  for (int i = 0; i < varlist.vars_size(); ++i) {
657
14.4k
    varlist_str += ", " + VariableToString(varlist.vars(i));
658
14.4k
    varlist_str += " ";
659
14.4k
  }
660
45.2k
  return varlist_str;
661
45.2k
}
662
663
/**
664
 * FunctionCall and nested types.
665
 */
666
PROTO_TOSTRING(FunctionCall, call)
667
59.7k
{
668
59.7k
  using FuncCallType = FunctionCall::CallOneofCase;
669
59.7k
  switch (call.call_oneof_case()) {
670
8.41k
  case FuncCallType::kPrefArgs:
671
8.41k
    return PrefixArgsToString(call.prefargs());
672
4.52k
  case FuncCallType::kNamedArgs:
673
4.52k
    return PrefixNamedArgsToString(call.namedargs());
674
46.7k
  default:
675
    /* Chosen for more variability of generated programs. */
676
46.7k
    return PrefixNamedArgsToString(call.namedargs());
677
59.7k
  }
678
59.7k
}
679
680
NESTED_PROTO_TOSTRING(Args, args, FunctionCall)
681
59.7k
{
682
59.7k
  using ArgsType = FunctionCall::Args::ArgsOneofCase;
683
59.7k
  switch (args.args_oneof_case()) {
684
3.71k
  case ArgsType::kExplist:
685
3.71k
    return "(" + OptionalExpressionListToString(args.explist()) +
686
3.71k
           ")";
687
1.14k
  case ArgsType::kTableconstructor:
688
1.14k
    return TableConstructorToString(args.tableconstructor());
689
2.13k
  case ArgsType::kStr:
690
2.13k
    return "'" + ConvertToStringDefault(args.str()) + "'";
691
52.7k
  default:
692
    /* For more variability. */
693
52.7k
    return TableConstructorToString(args.tableconstructor());
694
59.7k
  }
695
59.7k
}
696
697
NESTED_PROTO_TOSTRING(PrefixArgs, prefixargs, FunctionCall)
698
8.41k
{
699
8.41k
  std::string prefixargs_str = PrefixExpressionToString(
700
8.41k
    prefixargs.prefixexp());
701
8.41k
  prefixargs_str += " " + ArgsToString(prefixargs.args());
702
8.41k
  return prefixargs_str;
703
8.41k
}
704
705
NESTED_PROTO_TOSTRING(PrefixNamedArgs, prefixnamedargs, FunctionCall)
706
51.3k
{
707
51.3k
  std::string predixnamedargs_str = PrefixExpressionToString(
708
51.3k
    prefixnamedargs.prefixexp());
709
51.3k
  predixnamedargs_str += ":" + NameToString(prefixnamedargs.name());
710
51.3k
  predixnamedargs_str += " " + ArgsToString(prefixnamedargs.args());
711
51.3k
  return predixnamedargs_str;
712
51.3k
}
713
714
/**
715
 * DoBlock clause.
716
 */
717
PROTO_TOSTRING(DoBlock, block)
718
2.21k
{
719
2.21k
  return "do\n" + BlockToString(block.block()) + "end\n";
720
2.21k
}
721
722
/**
723
 * WhileCycle clause.
724
 */
725
PROTO_TOSTRING(WhileCycle, whilecycle)
726
4.92k
{
727
4.92k
  GetContext().step_in(Context::BlockType::kBreakable);
728
729
4.92k
  std::string whilecycle_str = "while ";
730
4.92k
  whilecycle_str += ExpressionToString(whilecycle.condition());
731
4.92k
  whilecycle_str += " ";
732
4.92k
  whilecycle_str += DoBlockToStringCycleProtected(whilecycle.doblock());
733
734
4.92k
  GetContext().step_out();
735
4.92k
  return whilecycle_str;
736
4.92k
}
737
738
/**
739
 * RepeatCycle clause.
740
 */
741
PROTO_TOSTRING(RepeatCycle, repeatcycle)
742
49.3k
{
743
49.3k
  GetContext().step_in(Context::BlockType::kBreakable);
744
745
49.3k
  std::string repeatcycle_str = "repeat\n";
746
49.3k
  repeatcycle_str += BlockToStringCycleProtected(repeatcycle.block());
747
49.3k
  repeatcycle_str += "until ";
748
49.3k
  repeatcycle_str += ExpressionToString(repeatcycle.condition());
749
750
49.3k
  GetContext().step_out();
751
49.3k
  return repeatcycle_str;
752
49.3k
}
753
754
/**
755
 * IfStatement and nested types.
756
 */
757
PROTO_TOSTRING(IfStatement, statement)
758
9.48k
{
759
9.48k
  std::string statement_str = "if " +
760
9.48k
    ExpressionToString(statement.condition());
761
9.48k
  statement_str += " then\n\t" + BlockToString(statement.first());
762
763
15.2k
  for (int i = 0; i < statement.clauses_size(); ++i)
764
5.77k
    statement_str += ElseIfBlockToString(statement.clauses(i));
765
766
9.48k
  if (statement.has_last())
767
4.29k
    statement_str += "else\n\t" + BlockToString(statement.last());
768
769
9.48k
  statement_str += "end\n";
770
9.48k
  return statement_str;
771
9.48k
}
772
773
NESTED_PROTO_TOSTRING(ElseIfBlock, elseifblock, IfStatement)
774
5.77k
{
775
5.77k
  std::string elseifblock_str = "elseif ";
776
5.77k
  elseifblock_str += ExpressionToString(elseifblock.condition());
777
5.77k
  elseifblock_str += " then\n\t";
778
5.77k
  elseifblock_str += BlockToString(elseifblock.block());
779
5.77k
  return elseifblock_str;
780
5.77k
}
781
782
/**
783
 * ForCycleName clause.
784
 * TODO: In 'for i = start, stop, step' construction start, stop, step
785
 * should be numbers. So results of the corresponding expressions
786
 * should be number.
787
 */
788
PROTO_TOSTRING(ForCycleName, forcyclename)
789
4.87k
{
790
4.87k
  GetContext().step_in(Context::BlockType::kBreakable);
791
792
4.87k
  std::string forcyclename_str = "for ";
793
4.87k
  forcyclename_str += NameToString(forcyclename.name());
794
4.87k
  forcyclename_str += " = ";
795
4.87k
  forcyclename_str += NumberWrappedExpressionToString(
796
4.87k
    forcyclename.startexp());
797
4.87k
  forcyclename_str += ", ";
798
4.87k
  forcyclename_str += NumberWrappedExpressionToString(
799
4.87k
    forcyclename.stopexp());
800
801
4.87k
  if (forcyclename.has_stepexp())
802
2.66k
    forcyclename_str += ", " + NumberWrappedExpressionToString(
803
2.66k
      forcyclename.stepexp());
804
805
4.87k
  forcyclename_str += " ";
806
4.87k
  forcyclename_str += DoBlockToStringCycleProtected(
807
4.87k
    forcyclename.doblock());
808
809
4.87k
  GetContext().step_out();
810
4.87k
  return forcyclename_str;
811
4.87k
}
812
813
/**
814
 * ForCycleList clause.
815
 */
816
PROTO_TOSTRING(ForCycleList, forcyclelist)
817
16.8k
{
818
16.8k
  GetContext().step_in(Context::BlockType::kBreakable);
819
820
16.8k
  std::string forcyclelist_str = "for ";
821
16.8k
  forcyclelist_str += NameListToString(forcyclelist.names());
822
16.8k
  forcyclelist_str += " in ";
823
16.8k
  forcyclelist_str += ExpressionListToString(forcyclelist.expressions());
824
16.8k
  forcyclelist_str += " ";
825
16.8k
  forcyclelist_str += DoBlockToStringCycleProtected(
826
16.8k
    forcyclelist.doblock());
827
828
16.8k
  GetContext().step_out();
829
16.8k
  return forcyclelist_str;
830
16.8k
}
831
832
/**
833
 * Function and nested types.
834
 */
835
PROTO_TOSTRING(Function, func)
836
6.14k
{
837
6.14k
  GetContext().step_in(GetFuncBodyType(func.body()));
838
839
6.14k
  std::string func_str = "function ";
840
6.14k
  func_str += FuncNameToString(func.name());
841
6.14k
  func_str += FuncBodyToStringReqProtected(func.body());
842
843
6.14k
  GetContext().step_out();
844
6.14k
  return func_str;
845
6.14k
}
846
847
NESTED_PROTO_TOSTRING(FuncName, funcname, Function)
848
6.14k
{
849
6.14k
  std::string funcname_str = NameToString(funcname.firstname());
850
851
7.15k
  for (int i = 0; i < funcname.names_size(); ++i)
852
1.01k
    funcname_str += "." + NameToString(funcname.names(i));
853
854
6.14k
  if (funcname.has_lastname())
855
516
    funcname_str += ":" + NameToString(funcname.lastname());
856
857
6.14k
  return funcname_str;
858
6.14k
}
859
860
PROTO_TOSTRING(NameList, namelist)
861
34.2k
{
862
34.2k
  std::string namelist_str = NameToString(namelist.firstname());
863
44.9k
  for (int i = 0; i < namelist.names_size(); ++i)
864
10.6k
    namelist_str += ", " + NameToString(namelist.names(i));
865
34.2k
  return namelist_str;
866
34.2k
}
867
868
NESTED_PROTO_TOSTRING(NameListWithEllipsis, namelist, FuncBody)
869
7.08k
{
870
7.08k
  std::string namelist_str = NameListToString(namelist.namelist());
871
7.08k
  if (namelist.has_ellipsis())
872
835
    namelist_str += ", ...";
873
7.08k
  return namelist_str;
874
7.08k
}
875
876
NESTED_PROTO_TOSTRING(ParList, parlist, FuncBody)
877
8.37k
{
878
8.37k
  using ParListType = FuncBody::ParList::ParlistOneofCase;
879
8.37k
  switch (parlist.parlist_oneof_case()) {
880
1.33k
  case ParListType::kNamelist:
881
1.33k
    return NameListWithEllipsisToString(parlist.namelist());
882
1.28k
  case ParListType::kEllipsis:
883
1.28k
    return "...";
884
5.75k
  default:
885
    /* Chosen as default in order to decrease number of ellipses. */
886
5.75k
    return NameListWithEllipsisToString(parlist.namelist());
887
8.37k
  }
888
8.37k
}
889
890
/**
891
 * LocalFunc clause.
892
 */
893
PROTO_TOSTRING(LocalFunc, localfunc)
894
10.1k
{
895
10.1k
  GetContext().step_in(GetFuncBodyType(localfunc.funcbody()));
896
897
10.1k
  std::string localfunc_str = "local function ";
898
10.1k
  localfunc_str += NameToString(localfunc.name());
899
10.1k
  localfunc_str += " ";
900
10.1k
  localfunc_str += FuncBodyToStringReqProtected(localfunc.funcbody());
901
902
10.1k
  GetContext().step_out();
903
10.1k
  return localfunc_str;
904
10.1k
}
905
906
/**
907
 * LocalNames clause.
908
 */
909
PROTO_TOSTRING(LocalNames, localnames)
910
10.3k
{
911
10.3k
  std::string localnames_str = "local ";
912
10.3k
  localnames_str += NameListToString(localnames.namelist());
913
914
10.3k
  if (localnames.has_explist())
915
8.31k
    localnames_str += " = " + ExpressionListToString(
916
8.31k
      localnames.explist());
917
10.3k
  return localnames_str;
918
10.3k
}
919
920
/**
921
 * Expressions and variables.
922
 */
923
924
/**
925
 * Expressions clauses.
926
 */
927
PROTO_TOSTRING(ExpressionList, explist)
928
78.0k
{
929
78.0k
  std::string explist_str;
930
119k
  for (int i = 0; i < explist.expressions_size(); ++i)
931
41.5k
    explist_str += ExpressionToString(explist.expressions(i)) +
932
41.5k
        ", ";
933
78.0k
  explist_str += ExpressionToString(explist.explast()) + " ";
934
78.0k
  return explist_str;
935
78.0k
}
936
937
PROTO_TOSTRING(OptionalExpressionList, explist)
938
3.71k
{
939
3.71k
  if (explist.has_explist())
940
3.51k
    return ExpressionListToString(explist.explist());
941
205
  return "";
942
3.71k
}
943
944
PROTO_TOSTRING(PrefixExpression, prefixexp)
945
92.5k
{
946
92.5k
  using PrefExprType = PrefixExpression::PrefixOneofCase;
947
92.5k
  switch (prefixexp.prefix_oneof_case()) {
948
7.25k
  case PrefExprType::kVar:
949
7.25k
    return VariableToString(prefixexp.var());
950
11.9k
  case PrefExprType::kFunctioncall:
951
11.9k
    return FunctionCallToString(prefixexp.functioncall());
952
6.58k
  case PrefExprType::kExp:
953
6.58k
    return "(" + ExpressionToString(prefixexp.exp()) + ")";
954
66.7k
  default:
955
    /*
956
     * Can be generated too nested expressions with other options,
957
     * though they can be enabled for more variable fuzzing.
958
     */
959
66.7k
    return VariableToString(prefixexp.var());
960
92.5k
  }
961
92.5k
}
962
963
/**
964
 * Variable and nested types.
965
 */
966
PROTO_TOSTRING(Variable, var)
967
133k
{
968
133k
  using VarType = Variable::VarOneofCase;
969
133k
  switch (var.var_oneof_case()) {
970
7.25k
  case VarType::kName:
971
7.25k
    return NameToString(var.name());
972
5.33k
  case VarType::kIndexexpr:
973
5.33k
    return IndexWithExpressionToString(var.indexexpr());
974
3.35k
  case VarType::kIndexname:
975
3.35k
    return IndexWithNameToString(var.indexname());
976
117k
  default:
977
    /*
978
     * Can be generated too nested expressions with other options,
979
     * though they can be enabled for more variable fuzzing.
980
     */
981
117k
    return NameToString(var.name());
982
133k
  }
983
133k
}
984
985
NESTED_PROTO_TOSTRING(IndexWithExpression, indexexpr, Variable)
986
5.33k
{
987
5.33k
  std::string indexexpr_str = PrefixExpressionToString(
988
5.33k
    indexexpr.prefixexp());
989
5.33k
  indexexpr_str += "[" + ExpressionToString(indexexpr.exp()) + "]";
990
5.33k
  return indexexpr_str;
991
5.33k
}
992
993
NESTED_PROTO_TOSTRING(IndexWithName, indexname, Variable)
994
3.35k
{
995
3.35k
  std::string indexname_str = PrefixExpressionToString(
996
3.35k
    indexname.prefixexp());
997
3.35k
  std::string idx_str = ConvertToStringDefault(indexname.name(), true);
998
  /* Prevent using reserved keywords as indices. */
999
3.35k
  if (KReservedLuaKeywords.find(idx_str) != KReservedLuaKeywords.end()) {
1000
33
    idx_str += "_1";
1001
33
  }
1002
3.35k
  indexname_str += "." + idx_str;
1003
3.35k
  return indexname_str;
1004
3.35k
}
1005
1006
/**
1007
 * Expression and nested types.
1008
 */
1009
PROTO_TOSTRING(Expression, expr)
1010
332k
{
1011
332k
  using ExprType = Expression::ExprOneofCase;
1012
332k
  switch (expr.expr_oneof_case()) {
1013
16.4k
  case ExprType::kNil:
1014
16.4k
    return "nil";
1015
4.26k
  case ExprType::kFalse:
1016
4.26k
    return "false";
1017
4.76k
  case ExprType::kTrue:
1018
4.76k
    return "true";
1019
16.1k
  case ExprType::kNumber: {
1020
    /* Clamp number between given boundaries. */
1021
16.1k
    double number = clamp(expr.number(), kMaxNumber, kMinNumber);
1022
16.1k
    return std::to_string(number);
1023
0
  }
1024
7.13k
  case ExprType::kStr:
1025
7.13k
    return "'" + ConvertToStringDefault(expr.str()) + "'";
1026
5.36k
  case ExprType::kEllipsis:
1027
5.36k
    if (GetContext().vararg_is_possible()) {
1028
4.40k
      return " ... ";
1029
4.40k
    } else {
1030
957
      return " nil";
1031
957
    }
1032
31.3k
  case ExprType::kFunction:
1033
31.3k
    return AnonFuncToString(expr.function());
1034
24.1k
  case ExprType::kPrefixexp:
1035
24.1k
    return PrefixExpressionToString(expr.prefixexp());
1036
8.82k
  case ExprType::kTableconstructor:
1037
8.82k
    return TableConstructorToString(expr.tableconstructor());
1038
44.6k
  case ExprType::kBinary:
1039
44.6k
    return ExpBinaryOpExpToString(expr.binary());
1040
5.86k
  case ExprType::kUnary:
1041
5.86k
    return UnaryOpExpToString(expr.unary());
1042
163k
  default:
1043
    /**
1044
     * Arbitrary choice.
1045
     * TODO: Choose "more interesting" defaults.
1046
     */
1047
163k
    return "'" + ConvertToStringDefault(expr.str()) + "'";
1048
332k
  }
1049
332k
}
1050
1051
NESTED_PROTO_TOSTRING(AnonFunc, func, Expression)
1052
31.3k
{
1053
31.3k
  GetContext().step_in(GetFuncBodyType(func.body()));
1054
1055
31.3k
  std::string retval = "function ";
1056
31.3k
  retval += FuncBodyToStringReqProtected(func.body());
1057
1058
31.3k
  GetContext().step_out();
1059
31.3k
  return retval;
1060
31.3k
}
1061
1062
NESTED_PROTO_TOSTRING(ExpBinaryOpExp, binary, Expression)
1063
44.6k
{
1064
44.6k
  std::string leftexp_str = ExpressionToString(binary.leftexp());
1065
44.6k
  std::string binop_str = BinaryOperatorToString(binary.binop());
1066
44.6k
  std::string rightexp_str = ExpressionToString(binary.rightexp());
1067
1068
44.6k
  std::string binary_str;
1069
44.6k
  if (binop_str == "<" ||
1070
41.8k
      binop_str == ">" ||
1071
41.4k
      binop_str == "<=" ||
1072
41.2k
      binop_str == ">=") {
1073
3.74k
    binary_str = kBinOpWrapperName;
1074
3.74k
    binary_str += "(" + leftexp_str;
1075
3.74k
    binary_str += ", '" + binop_str + "', ";
1076
3.74k
    binary_str += rightexp_str + ")";
1077
3.74k
    return binary_str;
1078
3.74k
  }
1079
1080
40.8k
  binary_str = leftexp_str;
1081
40.8k
  binary_str += " " + binop_str + " ";
1082
40.8k
  binary_str += rightexp_str;
1083
1084
40.8k
  return binary_str;
1085
44.6k
}
1086
1087
NESTED_PROTO_TOSTRING(UnaryOpExp, unary, Expression)
1088
5.86k
{
1089
5.86k
  std::string unary_str = UnaryOperatorToString(unary.unop());
1090
  /*
1091
   * Add a whitespace before an expression with unary minus,
1092
   * otherwise double hyphen comments the following code
1093
   * and it breaks generated programs syntactically.
1094
   */
1095
5.86k
  unary_str += " " + ExpressionToString(unary.exp());
1096
5.86k
  return unary_str;
1097
5.86k
}
1098
1099
/**
1100
 * Tables and fields.
1101
 */
1102
PROTO_TOSTRING(TableConstructor, table)
1103
62.7k
{
1104
62.7k
  std::string table_str = " (setmetatable({ ";
1105
62.7k
  if (table.has_fieldlist())
1106
6.94k
    table_str += FieldListToString(table.fieldlist());
1107
62.7k
  table_str += " }, table_mt))()";
1108
62.7k
  return table_str;
1109
62.7k
}
1110
1111
PROTO_TOSTRING(FieldList, fieldlist)
1112
6.94k
{
1113
6.94k
  std::string fieldlist_str = FieldToString(fieldlist.firstfield());
1114
19.0k
  for (int i = 0; i < fieldlist.fields_size(); ++i)
1115
12.1k
    fieldlist_str += FieldWithFieldSepToString(fieldlist.fields(i));
1116
6.94k
  if (fieldlist.has_lastsep())
1117
1.58k
    fieldlist_str += FieldSepToString(fieldlist.lastsep());
1118
6.94k
  return fieldlist_str;
1119
6.94k
}
1120
1121
NESTED_PROTO_TOSTRING(FieldWithFieldSep, field, FieldList)
1122
12.1k
{
1123
12.1k
  std::string field_str = FieldSepToString(field.sep());
1124
12.1k
  field_str += " " + FieldToString(field.field());
1125
12.1k
  return field_str;
1126
12.1k
}
1127
1128
/**
1129
 * Field and nested types.
1130
 */
1131
PROTO_TOSTRING(Field, field)
1132
19.0k
{
1133
19.0k
  using FieldType = Field::FieldOneofCase;
1134
19.0k
  switch (field.field_oneof_case()) {
1135
5.00k
  case FieldType::kExprassign:
1136
5.00k
    return ExpressionAssignmentToString(field.exprassign());
1137
568
  case FieldType::kNamedassign:
1138
568
    return NameAssignmentToString(field.namedassign());
1139
4.04k
  case FieldType::kExpression:
1140
4.04k
    return ExpressionToString(field.expression());
1141
9.44k
  default:
1142
    /* More common case of using fields. */
1143
9.44k
    return NameAssignmentToString(field.namedassign());
1144
19.0k
  }
1145
19.0k
}
1146
1147
NESTED_PROTO_TOSTRING(ExpressionAssignment, assignment, Field)
1148
5.00k
{
1149
  /* Prevent error 'table index is nil' and 'table index is NaN'. */
1150
5.00k
  std::string assignment_str = "[ " +
1151
5.00k
    AllowedIndexExpressionToString(assignment.key()) + " ]";
1152
5.00k
  assignment_str += " = " + ExpressionToString(assignment.value());
1153
5.00k
  return assignment_str;
1154
5.00k
}
1155
1156
NESTED_PROTO_TOSTRING(NameAssignment, assignment, Field)
1157
10.0k
{
1158
10.0k
  std::string assignment_str = NameToString(assignment.name());
1159
10.0k
  assignment_str += " = " + ExpressionToString(assignment.value());
1160
10.0k
  return assignment_str;
1161
10.0k
}
1162
1163
PROTO_TOSTRING(FieldSep, sep)
1164
13.6k
{
1165
13.6k
  using FieldSepType = FieldSep::SepOneofCase;
1166
13.6k
  switch (sep.sep_oneof_case()) {
1167
4.02k
  case FieldSepType::kComma:
1168
4.02k
    return ",";
1169
1.24k
  case FieldSepType::kSemicolon:
1170
1.24k
    return ";";
1171
8.42k
  default:
1172
8.42k
    return ",";
1173
13.6k
  }
1174
13.6k
}
1175
1176
/**
1177
 * Operators.
1178
 */
1179
PROTO_TOSTRING(BinaryOperator, op)
1180
44.6k
{
1181
44.6k
  using BinopType = BinaryOperator::BinaryOneofCase;
1182
44.6k
  switch (op.binary_oneof_case()) {
1183
3.24k
  case BinopType::kAdd:
1184
3.24k
    return "+";
1185
1.53k
  case BinopType::kSub:
1186
1.53k
    return "-";
1187
3.70k
  case BinopType::kMult:
1188
3.70k
    return "*";
1189
1.05k
  case BinopType::kDiv:
1190
1.05k
    return "/";
1191
#if LUA_VERSION_NUM >= 503
1192
  case BinopType::kIDiv:
1193
    return "//";
1194
#endif
1195
827
  case BinopType::kExp:
1196
827
    return "^";
1197
1.24k
  case BinopType::kMod:
1198
1.24k
    return "%";
1199
1200
10.4k
  case BinopType::kConcat:
1201
10.4k
    return "..";
1202
1203
2.75k
  case BinopType::kLess:
1204
2.75k
    return "<";
1205
133
  case BinopType::kLessEqual:
1206
133
    return "<=";
1207
471
  case BinopType::kGreater:
1208
471
    return ">";
1209
385
  case BinopType::kGreaterEqual:
1210
385
    return ">=";
1211
206
  case BinopType::kEqual:
1212
206
    return "==";
1213
220
  case BinopType::kNotEqual:
1214
220
    return "~=";
1215
1.02k
  case BinopType::kAnd:
1216
1.02k
    return "and";
1217
6.69k
  case BinopType::kOr:
1218
6.69k
    return "or";
1219
1220
#if LUA_VERSION_NUM >= 503
1221
  case BinopType::kBAnd:
1222
    return "&";
1223
  case BinopType::kBOr:
1224
    return "|";
1225
  case BinopType::kBXor:
1226
    return "~";
1227
  case BinopType::kBShl:
1228
    return "<<";
1229
  case BinopType::kBShr:
1230
    return ">>";
1231
#endif
1232
10.6k
  default:
1233
    /* Works in most cases. */
1234
10.6k
    return "==";
1235
44.6k
  }
1236
44.6k
}
1237
1238
PROTO_TOSTRING(UnaryOperator, op)
1239
5.86k
{
1240
5.86k
  using UnaryopType = UnaryOperator::UnaryOneofCase;
1241
5.86k
  switch (op.unary_oneof_case()) {
1242
1.85k
  case UnaryopType::kNegate:
1243
1.85k
    return "-";
1244
394
  case UnaryopType::kNot:
1245
394
    return "not ";
1246
646
  case UnaryopType::kLength:
1247
646
    return "#";
1248
#if LUA_VERSION_NUM >= 503
1249
  case UnaryopType::kBNot:
1250
    return "~";
1251
#endif
1252
2.96k
  default:
1253
    /* Works in most cases. */
1254
2.96k
    return "not ";
1255
5.86k
  }
1256
5.86k
}
1257
1258
/**
1259
 * Identifier (Name).
1260
 */
1261
PROTO_TOSTRING(Name, name)
1262
253k
{
1263
253k
  std::string ident = ConvertToStringDefault(name.name(), true);
1264
  /* Prevent using reserved keywords as identifiers. */
1265
253k
  if (KReservedLuaKeywords.find(ident) != KReservedLuaKeywords.end()) {
1266
173
    ident += "_1";
1267
173
  }
1268
  /* Identifier has default name, add an index. */
1269
253k
  if (!ident.compare(kDefaultIdent)) {
1270
237k
    ident += std::to_string(name.num() % kMaxIdentifiers);
1271
237k
  }
1272
253k
  return ident;
1273
253k
}
1274
1275
} /* namespace */
1276
1277
std::string
1278
MainBlockToString(const Block &block)
1279
1.88k
{
1280
1.88k
  GetCounterIdProvider().clean();
1281
1282
1.88k
  std::string block_str = BlockToString(block);
1283
1.88k
  std::string retval = preamble_lua;
1284
1285
125k
  for (size_t i = 0; i < GetCounterIdProvider().count(); ++i) {
1286
123k
    retval += GetCounterName(i);
1287
123k
    retval += " = 0\n";
1288
123k
  }
1289
1.88k
  retval += block_str;
1290
1291
1.88k
  return retval;
1292
1.88k
}
1293
1294
} /* namespace luajit_fuzzer */