Coverage Report

Created: 2026-01-17 06:38

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