Coverage Report

Created: 2023-08-27 06:20

/src/testdir/tests/luaL_loadbuffer_proto/serializer.cc
Line
Count
Source (jump to first uncovered line)
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
using namespace lua_grammar;
12
13
#define PROTO_TOSTRING(TYPE, VAR_NAME) \
14
  std::string TYPE##ToString(const TYPE & (VAR_NAME))
15
16
/* PROTO_TOSTRING version for nested (depth=2) protobuf messages. */
17
#define NESTED_PROTO_TOSTRING(TYPE, VAR_NAME, PARENT_MESSAGE) \
18
  std::string TYPE##ToString \
19
  (const PARENT_MESSAGE::TYPE & (VAR_NAME))
20
21
namespace luajit_fuzzer {
22
namespace {
23
24
const std::string kCounterNamePrefix = "counter_";
25
26
PROTO_TOSTRING(Block, block);
27
PROTO_TOSTRING(Chunk, chunk);
28
29
PROTO_TOSTRING(Statement, stat);
30
31
/** LastStatement and nested types. */
32
PROTO_TOSTRING(LastStatement, laststat);
33
NESTED_PROTO_TOSTRING(ReturnOptionalExpressionList, explist, LastStatement);
34
35
/**
36
 * Statement options.
37
 */
38
39
/** AssignmentList and nested types. */
40
PROTO_TOSTRING(AssignmentList, assignmentlist);
41
NESTED_PROTO_TOSTRING(VariableList, varlist, AssignmentList);
42
43
/** FunctionCall and nested types. */
44
PROTO_TOSTRING(FunctionCall, call);
45
NESTED_PROTO_TOSTRING(Args, args, FunctionCall);
46
NESTED_PROTO_TOSTRING(PrefixArgs, prefixargs, FunctionCall);
47
NESTED_PROTO_TOSTRING(PrefixNamedArgs, prefixnamedargs, FunctionCall);
48
49
/** DoBlock, WhileCycle and RepeatCycle clauses. */
50
PROTO_TOSTRING(DoBlock, block);
51
PROTO_TOSTRING(WhileCycle, whilecycle);
52
PROTO_TOSTRING(RepeatCycle, repeatcycle);
53
54
/** IfStatement and nested types. */
55
PROTO_TOSTRING(IfStatement, statement);
56
NESTED_PROTO_TOSTRING(ElseIfBlock, elseifblock, IfStatement);
57
58
/** ForCycleName and ForCycleList clauses. */
59
PROTO_TOSTRING(ForCycleName, forcyclename);
60
PROTO_TOSTRING(ForCycleList, forcyclelist);
61
62
/** Function and nested types. */
63
PROTO_TOSTRING(Function, func);
64
NESTED_PROTO_TOSTRING(FuncName, funcname, Function);
65
66
PROTO_TOSTRING(NameList, namelist);
67
NESTED_PROTO_TOSTRING(NameListWithEllipsis, namelist, FuncBody);
68
NESTED_PROTO_TOSTRING(ParList, parlist, FuncBody);
69
70
/** LocalFunc and LocalNames clauses. */
71
PROTO_TOSTRING(LocalFunc, localfunc);
72
PROTO_TOSTRING(LocalNames, localnames);
73
74
/**
75
 * Expressions and variables.
76
 */
77
78
/** Expressions clauses. */
79
PROTO_TOSTRING(ExpressionList, explist);
80
PROTO_TOSTRING(OptionalExpressionList, explist);
81
PROTO_TOSTRING(PrefixExpression, prefExpr);
82
83
/* Variable and nested types. */
84
PROTO_TOSTRING(Variable, var);
85
NESTED_PROTO_TOSTRING(IndexWithExpression, indexexpr, Variable);
86
NESTED_PROTO_TOSTRING(IndexWithName, indexname, Variable);
87
88
/** Expression and nested types. */
89
PROTO_TOSTRING(Expression, expr);
90
NESTED_PROTO_TOSTRING(AnonFunc, function, Expression);
91
NESTED_PROTO_TOSTRING(ExpBinaryOpExp, binary, Expression);
92
NESTED_PROTO_TOSTRING(UnaryOpExp, unary, Expression);
93
94
/**
95
 * Tables and fields.
96
 */
97
PROTO_TOSTRING(TableConstructor, table);
98
PROTO_TOSTRING(FieldList, fieldlist);
99
NESTED_PROTO_TOSTRING(FieldWithFieldSep, field, FieldList);
100
101
/** Field and nested types. */
102
PROTO_TOSTRING(Field, field);
103
NESTED_PROTO_TOSTRING(ExpressionAssignment, assignment, Field);
104
NESTED_PROTO_TOSTRING(NameAssignment, assignment, Field);
105
PROTO_TOSTRING(FieldSep, sep);
106
107
/** Operators. */
108
PROTO_TOSTRING(BinaryOperator, op);
109
PROTO_TOSTRING(UnaryOperator, op);
110
111
/** Identifier (Name). */
112
PROTO_TOSTRING(Name, name);
113
114
/**
115
 * Class that controls id creation for counters. Basically, a
116
 * variable wrapper that guarantees variable to be incremented.
117
 */
118
class CounterIdProvider {
119
public:
120
  /** Returns number of id provided. */
121
  std::size_t count()
122
80.3k
  {
123
80.3k
    return id_;
124
80.3k
  }
125
126
  /** Returns a new id that was not used after last clean(). */
127
  std::size_t next()
128
77.7k
  {
129
77.7k
    return id_++;
130
77.7k
  }
131
132
  /**
133
   * Cleans history. Should be used to make fuzzer starts
134
   * independent.
135
   */
136
  void clean()
137
2.58k
  {
138
2.58k
    id_ = 0;
139
2.58k
  }
140
141
private:
142
  std::size_t id_ = 0;
143
};
144
145
/** A singleton for counter id provider. */
146
CounterIdProvider&
147
GetCounterIdProvider()
148
160k
{
149
160k
  static CounterIdProvider provider;
150
160k
  return provider;
151
160k
}
152
153
std::string
154
GetCounterName(std::size_t id)
155
155k
{
156
155k
  return kCounterNamePrefix + std::to_string(id);
157
155k
}
158
159
/** Returns `<counter_name> = <counter_name> + 1`. */
160
std::string
161
GetCounterIncrement(const std::string &counter_name)
162
77.7k
{
163
77.7k
  std::string retval = counter_name;
164
77.7k
  retval += " = ";
165
77.7k
  retval += counter_name;
166
77.7k
  retval += " + 1\n";
167
77.7k
  return retval;
168
77.7k
}
169
170
/**
171
 * Returns `if <counter_name> > kMaxCounterValue then
172
 * <then_block> end`.
173
 */
174
std::string
175
GetCondition(const std::string &counter_name, const std::string &then_block)
176
77.7k
{
177
77.7k
  std::string retval = "if ";
178
77.7k
  retval += counter_name;
179
77.7k
  retval += " > ";
180
77.7k
  retval += std::to_string(kMaxCounterValue);
181
77.7k
  retval += " then ";
182
77.7k
  retval += then_block;
183
77.7k
  retval += " end\n";
184
77.7k
  return retval;
185
77.7k
}
186
187
/**
188
 * Block may be placed not only in a cycle, so specially for cycles
189
 * there is a function that will add a break condition and a
190
 * counter increment.
191
 */
192
std::string
193
BlockToStringCycleProtected(const Block &block, const std::string &counter_name)
194
53.5k
{
195
53.5k
  std::string retval = GetCondition(counter_name, "break");
196
53.5k
  retval += GetCounterIncrement(counter_name);
197
53.5k
  retval += ChunkToString(block.chunk());
198
53.5k
  return retval;
199
53.5k
}
200
201
/**
202
 * DoBlock may be placed not only in a cycle, so specially for
203
 * cycles there is a function that will call
204
 * BlockToStringCycleProtected().
205
 */
206
std::string
207
DoBlockToStringCycleProtected(const DoBlock &block,
208
            const std::string &counter_name)
209
47.2k
{
210
47.2k
  std::string retval = "do\n";
211
47.2k
  retval += BlockToStringCycleProtected(block.block(), counter_name);
212
47.2k
  retval += "end\n";
213
47.2k
  return retval;
214
47.2k
}
215
216
/**
217
 * FuncBody may contain recursive calls, so for all function bodies,
218
 * there is a function that adds a return condition and a counter
219
 * increment.
220
 */
221
std::string
222
FuncBodyToStringReqProtected(const FuncBody &body,
223
           const std::string &counter_name)
224
24.2k
{
225
24.2k
  std::string body_str = "( ";
226
24.2k
  if (body.has_parlist()) {
227
3.51k
    body_str += ParListToString(body.parlist());
228
3.51k
  }
229
24.2k
  body_str += " )\n\t";
230
231
24.2k
  body_str += GetCondition(counter_name, "return");
232
24.2k
  body_str += GetCounterIncrement(counter_name);
233
234
24.2k
  body_str += BlockToString(body.block());
235
24.2k
  body_str += "end\n";
236
24.2k
  return body_str;
237
24.2k
}
238
239
std::string
240
ClearIdentifier(const std::string &identifier)
241
286k
{
242
286k
  std::string cleared;
243
244
286k
  bool has_first_not_digit = false;
245
582k
  for (char c : identifier) {
246
582k
    if (has_first_not_digit && (std::iswalnum(c) || c == '_')) {
247
296k
      cleared += c;
248
296k
    } else if (std::isalpha(c) || c == '_') {
249
16.4k
      has_first_not_digit = true;
250
16.4k
      cleared += c;
251
16.4k
    }
252
582k
  }
253
286k
  return cleared;
254
286k
}
255
256
inline std::string
257
clamp(std::string s, size_t maxSize = kMaxStrLength)
258
286k
{
259
286k
  if (s.size() > maxSize)
260
1.43k
    s.resize(maxSize);
261
286k
  return s;
262
286k
}
263
264
inline double
265
clamp(double number, double upper, double lower)
266
25.8k
{
267
25.8k
  return number <= lower ? lower :
268
25.8k
         number >= upper ? upper : number;
269
25.8k
}
270
271
inline std::string
272
ConvertToStringDefault(const std::string &s)
273
286k
{
274
286k
  std::string ident = ClearIdentifier(s);
275
286k
  ident = clamp(ident);
276
286k
  if (ident.empty())
277
270k
    return std::string(kDefaultIdent);
278
16.4k
  return ident;
279
286k
}
280
281
PROTO_TOSTRING(Block, block)
282
36.7k
{
283
36.7k
  return ChunkToString(block.chunk());
284
36.7k
}
285
286
PROTO_TOSTRING(Chunk, chunk)
287
90.2k
{
288
90.2k
  std::string chunk_str;
289
195k
  for (int i = 0; i < chunk.stat_size(); ++i)
290
104k
    chunk_str += StatementToString(chunk.stat(i)) + "\n";
291
292
90.2k
  if (chunk.has_laststat())
293
9.08k
    chunk_str += LastStatementToString(chunk.laststat()) + "\n";
294
295
90.2k
  return chunk_str;
296
90.2k
}
297
298
/**
299
 * LastStatement and nested types.
300
 */
301
PROTO_TOSTRING(LastStatement, laststat)
302
9.08k
{
303
9.08k
  std::string laststat_str;
304
9.08k
  using LastStatType = LastStatement::LastOneofCase;
305
9.08k
  switch (laststat.last_oneof_case()) {
306
4.58k
  case LastStatType::kExplist:
307
4.58k
    laststat_str = ReturnOptionalExpressionListToString(
308
4.58k
      laststat.explist());
309
4.58k
    break;
310
1.98k
  case LastStatType::kBreak:
311
1.98k
    laststat_str = "break";
312
1.98k
    break;
313
2.51k
  default:
314
    /* Chosen as default in order to decrease number of 'break's. */
315
2.51k
    laststat_str = ReturnOptionalExpressionListToString(
316
2.51k
      laststat.explist());
317
2.51k
    break;
318
9.08k
  }
319
320
9.08k
  if (laststat.has_semicolon())
321
2.58k
    laststat_str += "; ";
322
323
9.08k
  return laststat_str;
324
9.08k
}
325
326
NESTED_PROTO_TOSTRING(ReturnOptionalExpressionList, explist, LastStatement)
327
7.10k
{
328
7.10k
  std::string explist_str = "return";
329
7.10k
  if (explist.has_explist()) {
330
4.31k
    explist_str += " " + ExpressionListToString(explist.explist());
331
4.31k
    explist_str += " ";
332
4.31k
  }
333
7.10k
  return explist_str;
334
7.10k
}
335
336
/**
337
 * Statement and statement options.
338
 */
339
PROTO_TOSTRING(Statement, stat)
340
104k
{
341
104k
  std::string stat_str;
342
104k
  using StatType = Statement::StatOneofCase;
343
104k
  switch (stat.stat_oneof_case()) {
344
8.49k
  case StatType::kList:
345
8.49k
    stat_str = AssignmentListToString(stat.list());
346
8.49k
    break;
347
7.34k
  case StatType::kCall:
348
7.34k
    stat_str = FunctionCallToString(stat.call());
349
7.34k
    break;
350
1.63k
  case StatType::kBlock:
351
1.63k
    stat_str = DoBlockToString(stat.block());
352
1.63k
    break;
353
8.70k
  case StatType::kWhilecycle:
354
8.70k
    stat_str = WhileCycleToString(stat.whilecycle());
355
8.70k
    break;
356
6.25k
  case StatType::kRepeatcycle:
357
6.25k
    stat_str = RepeatCycleToString(stat.repeatcycle());
358
6.25k
    break;
359
4.52k
  case StatType::kIfstat:
360
4.52k
    stat_str = IfStatementToString(stat.ifstat());
361
4.52k
    break;
362
2.02k
  case StatType::kForcyclename:
363
2.02k
    stat_str = ForCycleNameToString(stat.forcyclename());
364
2.02k
    break;
365
36.5k
  case StatType::kForcyclelist:
366
36.5k
    stat_str = ForCycleListToString(stat.forcyclelist());
367
36.5k
    break;
368
3.78k
  case StatType::kFunc:
369
3.78k
    stat_str = FunctionToString(stat.func());
370
3.78k
    break;
371
2.48k
  case StatType::kLocalfunc:
372
2.48k
    stat_str = LocalFuncToString(stat.localfunc());
373
2.48k
    break;
374
2.58k
  case StatType::kLocalnames:
375
2.58k
    stat_str = LocalNamesToString(stat.localnames());
376
2.58k
    break;
377
20.5k
  default:
378
    /**
379
     * Chosen arbitrarily more for simplicity.
380
     * TODO: Choose "more interesting" defaults.
381
     */
382
20.5k
    stat_str = AssignmentListToString(stat.list());
383
20.5k
    break;
384
104k
  }
385
386
104k
  if (stat.has_semicolon())
387
53.9k
    stat_str += "; ";
388
389
104k
  return stat_str;
390
104k
}
391
392
/**
393
 * AssignmentList and nested types.
394
 */
395
PROTO_TOSTRING(AssignmentList, assignmentlist)
396
29.0k
{
397
29.0k
  std::string list_str = VariableListToString(assignmentlist.varlist());
398
29.0k
  list_str += " = " + ExpressionListToString(assignmentlist.explist());
399
29.0k
  return list_str;
400
29.0k
}
401
402
NESTED_PROTO_TOSTRING(VariableList, varlist, AssignmentList)
403
29.0k
{
404
29.0k
  std::string varlist_str = VariableToString(varlist.var());
405
43.6k
  for (int i = 0; i < varlist.vars_size(); ++i) {
406
14.5k
    varlist_str += ", " + VariableToString(varlist.vars(i));
407
14.5k
    varlist_str += " ";
408
14.5k
  }
409
29.0k
  return varlist_str;
410
29.0k
}
411
412
/**
413
 * FunctionCall and nested types.
414
 */
415
PROTO_TOSTRING(FunctionCall, call)
416
19.8k
{
417
19.8k
  using FuncCallType = FunctionCall::CallOneofCase;
418
19.8k
  switch (call.call_oneof_case()) {
419
8.63k
  case FuncCallType::kPrefArgs:
420
8.63k
    return PrefixArgsToString(call.prefargs());
421
3.86k
  case FuncCallType::kNamedArgs:
422
3.86k
    return PrefixNamedArgsToString(call.namedargs());
423
7.34k
  default:
424
    /* Chosen for more variability of generated programs. */
425
7.34k
    return PrefixNamedArgsToString(call.namedargs());
426
19.8k
  }
427
19.8k
}
428
429
NESTED_PROTO_TOSTRING(Args, args, FunctionCall)
430
19.8k
{
431
19.8k
  using ArgsType = FunctionCall::Args::ArgsOneofCase;
432
19.8k
  switch (args.args_oneof_case()) {
433
6.72k
  case ArgsType::kExplist:
434
6.72k
    return "(" + OptionalExpressionListToString(args.explist()) +
435
6.72k
           ")";
436
771
  case ArgsType::kTableconstructor:
437
771
    return TableConstructorToString(args.tableconstructor());
438
958
  case ArgsType::kStr:
439
958
    return "'" + ConvertToStringDefault(args.str()) + "'";
440
11.3k
  default:
441
    /* For more variability. */
442
11.3k
    return TableConstructorToString(args.tableconstructor());
443
19.8k
  }
444
19.8k
}
445
446
NESTED_PROTO_TOSTRING(PrefixArgs, prefixargs, FunctionCall)
447
8.63k
{
448
8.63k
  std::string prefixargs_str = PrefixExpressionToString(
449
8.63k
    prefixargs.prefixexp());
450
8.63k
  prefixargs_str += " " + ArgsToString(prefixargs.args());
451
8.63k
  return prefixargs_str;
452
8.63k
}
453
454
NESTED_PROTO_TOSTRING(PrefixNamedArgs, prefixnamedargs, FunctionCall)
455
11.2k
{
456
11.2k
  std::string predixnamedargs_str = PrefixExpressionToString(
457
11.2k
    prefixnamedargs.prefixexp());
458
11.2k
  predixnamedargs_str += ":" + NameToString(prefixnamedargs.name());
459
11.2k
  predixnamedargs_str += " " + ArgsToString(prefixnamedargs.args());
460
11.2k
  return predixnamedargs_str;
461
11.2k
}
462
463
/**
464
 * DoBlock clause.
465
 */
466
PROTO_TOSTRING(DoBlock, block)
467
1.63k
{
468
1.63k
  return "do\n" + BlockToString(block.block()) + "end\n";
469
1.63k
}
470
471
/**
472
 * WhileCycle clause.
473
 */
474
PROTO_TOSTRING(WhileCycle, whilecycle)
475
8.70k
{
476
8.70k
  const auto id = GetCounterIdProvider().next();
477
8.70k
  auto counter_name = GetCounterName(id);
478
479
8.70k
  std::string whilecycle_str = "while ";
480
8.70k
  whilecycle_str += ExpressionToString(whilecycle.condition());
481
8.70k
  whilecycle_str += " ";
482
8.70k
  whilecycle_str += DoBlockToStringCycleProtected(whilecycle.doblock(),
483
8.70k
              counter_name);
484
485
8.70k
  return whilecycle_str;
486
8.70k
}
487
488
/**
489
 * RepeatCycle clause.
490
 */
491
PROTO_TOSTRING(RepeatCycle, repeatcycle)
492
6.25k
{
493
6.25k
  const auto id = GetCounterIdProvider().next();
494
6.25k
  auto counter_name = GetCounterName(id);
495
496
6.25k
  std::string repeatcycle_str = "repeat\n";
497
6.25k
  repeatcycle_str += BlockToStringCycleProtected(repeatcycle.block(),
498
6.25k
                   counter_name);
499
6.25k
  repeatcycle_str += "until ";
500
6.25k
  repeatcycle_str += ExpressionToString(repeatcycle.condition());
501
502
6.25k
  return repeatcycle_str;
503
6.25k
}
504
505
/**
506
 * IfStatement and nested types.
507
 */
508
PROTO_TOSTRING(IfStatement, statement)
509
4.52k
{
510
4.52k
  std::string statement_str = "if " +
511
4.52k
    ExpressionToString(statement.condition());
512
4.52k
  statement_str += " then\n\t" + BlockToString(statement.first());
513
514
6.13k
  for (int i = 0; i < statement.clauses_size(); ++i)
515
1.60k
    statement_str += ElseIfBlockToString(statement.clauses(i));
516
517
4.52k
  if (statement.has_last())
518
2.17k
    statement_str += "else\n\t" + BlockToString(statement.last());
519
520
4.52k
  statement_str += "end\n";
521
4.52k
  return statement_str;
522
4.52k
}
523
524
NESTED_PROTO_TOSTRING(ElseIfBlock, elseifblock, IfStatement)
525
1.60k
{
526
1.60k
  std::string elseifblock_str = "else if ";
527
1.60k
  elseifblock_str += ExpressionToString(elseifblock.condition());
528
1.60k
  elseifblock_str += " then\n\t";
529
1.60k
  elseifblock_str += BlockToString(elseifblock.block());
530
1.60k
  return elseifblock_str;
531
1.60k
}
532
533
/**
534
 * ForCycleName clause.
535
 * TODO: In 'for i = start, stop, step' construction start, stop, step
536
 * should be numbers. So results of the corresponding expressions
537
 * should be number.
538
 */
539
PROTO_TOSTRING(ForCycleName, forcyclename)
540
2.02k
{
541
2.02k
  const auto id = GetCounterIdProvider().next();
542
2.02k
  auto counter_name = GetCounterName(id);
543
544
2.02k
  std::string forcyclename_str = "for ";
545
2.02k
  forcyclename_str += NameToString(forcyclename.name());
546
2.02k
  forcyclename_str += " = ";
547
2.02k
  forcyclename_str += ExpressionToString(forcyclename.startexp());
548
2.02k
  forcyclename_str += ", ";
549
2.02k
  forcyclename_str += ExpressionToString(forcyclename.stopexp());
550
551
2.02k
  if (forcyclename.has_stepexp())
552
1.02k
    forcyclename_str += ", " + ExpressionToString(
553
1.02k
      forcyclename.stepexp());
554
555
2.02k
  forcyclename_str += " ";
556
2.02k
  forcyclename_str += DoBlockToStringCycleProtected(
557
2.02k
    forcyclename.doblock(), counter_name);
558
2.02k
  return forcyclename_str;
559
2.02k
}
560
561
/**
562
 * ForCycleList clause.
563
 */
564
PROTO_TOSTRING(ForCycleList, forcyclelist)
565
36.5k
{
566
36.5k
  const auto id = GetCounterIdProvider().next();
567
36.5k
  auto counter_name = GetCounterName(id);
568
569
36.5k
  std::string forcyclelist_str = "for ";
570
36.5k
  forcyclelist_str += NameListToString(forcyclelist.names());
571
36.5k
  forcyclelist_str += " in ";
572
36.5k
  forcyclelist_str += ExpressionListToString(forcyclelist.expressions());
573
36.5k
  forcyclelist_str += " ";
574
36.5k
  forcyclelist_str += DoBlockToStringCycleProtected(
575
36.5k
    forcyclelist.doblock(), counter_name);
576
36.5k
  return forcyclelist_str;
577
36.5k
}
578
579
/**
580
 * Function and nested types.
581
 */
582
PROTO_TOSTRING(Function, func)
583
3.78k
{
584
3.78k
  const auto id = GetCounterIdProvider().next();
585
3.78k
  auto counter_name = GetCounterName(id);
586
587
3.78k
  std::string func_str = "function ";
588
3.78k
  func_str += FuncNameToString(func.name());
589
3.78k
  func_str += FuncBodyToStringReqProtected(func.body(), counter_name);
590
591
3.78k
  return func_str;
592
3.78k
}
593
594
NESTED_PROTO_TOSTRING(FuncName, funcname, Function)
595
3.78k
{
596
3.78k
  std::string funcname_str = NameToString(funcname.firstname());
597
598
4.87k
  for (int i = 0; i < funcname.names_size(); ++i)
599
1.09k
    funcname_str += "." + NameToString(funcname.names(i));
600
601
3.78k
  if (funcname.has_lastname())
602
231
    funcname_str += ":" + NameToString(funcname.lastname());
603
604
3.78k
  return funcname_str;
605
3.78k
}
606
607
PROTO_TOSTRING(NameList, namelist)
608
41.0k
{
609
41.0k
  std::string namelist_str = NameToString(namelist.firstname());
610
54.8k
  for (int i = 0; i < namelist.names_size(); ++i)
611
13.8k
    namelist_str += ", " + NameToString(namelist.names(i));
612
41.0k
  return namelist_str;
613
41.0k
}
614
615
NESTED_PROTO_TOSTRING(NameListWithEllipsis, namelist, FuncBody)
616
1.93k
{
617
1.93k
  std::string namelist_str = NameListToString(namelist.namelist());
618
1.93k
  if (namelist.has_ellipsis())
619
374
    namelist_str += ", ...";
620
1.93k
  return namelist_str;
621
1.93k
}
622
623
NESTED_PROTO_TOSTRING(ParList, parlist, FuncBody)
624
3.51k
{
625
3.51k
  using ParListType = FuncBody::ParList::ParlistOneofCase;
626
3.51k
  switch (parlist.parlist_oneof_case()) {
627
742
  case ParListType::kNamelist:
628
742
    return NameListWithEllipsisToString(parlist.namelist());
629
1.58k
  case ParListType::kEllipsis:
630
1.58k
    return "...";
631
1.19k
  default:
632
    /* Chosen as default in order to decrease number of ellipses. */
633
1.19k
    return NameListWithEllipsisToString(parlist.namelist());
634
3.51k
  }
635
3.51k
}
636
637
/**
638
 * LocalFunc clause.
639
 */
640
PROTO_TOSTRING(LocalFunc, localfunc)
641
2.48k
{
642
2.48k
  const auto id = GetCounterIdProvider().next();
643
2.48k
  auto counter_name = GetCounterName(id);
644
645
2.48k
  std::string localfunc_str = "local function ";
646
2.48k
  localfunc_str += NameToString(localfunc.name());
647
2.48k
  localfunc_str += " ";
648
2.48k
  localfunc_str += FuncBodyToStringReqProtected(localfunc.funcbody(),
649
2.48k
                  counter_name);
650
651
2.48k
  return localfunc_str;
652
2.48k
}
653
654
/**
655
 * LocalNames clause.
656
 */
657
PROTO_TOSTRING(LocalNames, localnames)
658
2.58k
{
659
2.58k
  std::string localnames_str = "local ";
660
2.58k
  localnames_str += NameListToString(localnames.namelist());
661
662
2.58k
  if (localnames.has_explist())
663
954
    localnames_str += " = " + ExpressionListToString(
664
954
      localnames.explist());
665
2.58k
  return localnames_str;
666
2.58k
}
667
668
/**
669
 * Expressions and variables.
670
 */
671
672
/**
673
 * Expressions clauses.
674
 */
675
PROTO_TOSTRING(ExpressionList, explist)
676
77.4k
{
677
77.4k
  std::string explist_str;
678
124k
  for (int i = 0; i < explist.expressions_size(); ++i)
679
46.8k
    explist_str += ExpressionToString(explist.expressions(i)) +
680
46.8k
        ", ";
681
77.4k
  explist_str += ExpressionToString(explist.explast()) + " ";
682
77.4k
  return explist_str;
683
77.4k
}
684
685
PROTO_TOSTRING(OptionalExpressionList, explist)
686
6.72k
{
687
6.72k
  if (explist.has_explist())
688
6.57k
    return ExpressionListToString(explist.explist());
689
150
  return "";
690
6.72k
}
691
692
PROTO_TOSTRING(PrefixExpression, prefixexp)
693
61.2k
{
694
61.2k
  using PrefExprType = PrefixExpression::PrefixOneofCase;
695
61.2k
  switch (prefixexp.prefix_oneof_case()) {
696
8.38k
  case PrefExprType::kVar:
697
8.38k
    return VariableToString(prefixexp.var());
698
12.5k
  case PrefExprType::kFunctioncall:
699
12.5k
    return FunctionCallToString(prefixexp.functioncall());
700
6.86k
  case PrefExprType::kExp:
701
6.86k
    return "(" + ExpressionToString(prefixexp.exp()) + ")";
702
33.4k
  default:
703
    /*
704
     * Can be generated too nested expressions with other options,
705
     * though they can be enabled for more variable fuzzing.
706
     */
707
33.4k
    return VariableToString(prefixexp.var());
708
61.2k
  }
709
61.2k
}
710
711
/**
712
 * Variable and nested types.
713
 */
714
PROTO_TOSTRING(Variable, var)
715
85.4k
{
716
85.4k
  using VarType = Variable::VarOneofCase;
717
85.4k
  switch (var.var_oneof_case()) {
718
2.13k
  case VarType::kName:
719
2.13k
    return NameToString(var.name());
720
6.96k
  case VarType::kIndexexpr:
721
6.96k
    return IndexWithExpressionToString(var.indexexpr());
722
7.94k
  case VarType::kIndexname:
723
7.94k
    return IndexWithNameToString(var.indexname());
724
68.4k
  default:
725
    /*
726
     * Can be generated too nested expressions with other options,
727
     * though they can be enabled for more variable fuzzing.
728
     */
729
68.4k
    return NameToString(var.name());
730
85.4k
  }
731
85.4k
}
732
733
NESTED_PROTO_TOSTRING(IndexWithExpression, indexexpr, Variable)
734
6.96k
{
735
6.96k
  std::string indexexpr_str = PrefixExpressionToString(
736
6.96k
    indexexpr.prefixexp());
737
6.96k
  indexexpr_str += "[" + ExpressionToString(indexexpr.exp()) + "]";
738
6.96k
  return indexexpr_str;
739
6.96k
}
740
741
NESTED_PROTO_TOSTRING(IndexWithName, indexname, Variable)
742
7.94k
{
743
7.94k
  std::string indexname_str = PrefixExpressionToString(
744
7.94k
    indexname.prefixexp());
745
7.94k
  indexname_str += "." + ConvertToStringDefault(indexname.name());
746
7.94k
  return indexname_str;
747
7.94k
}
748
749
/**
750
 * Expression and nested types.
751
 */
752
PROTO_TOSTRING(Expression, expr)
753
269k
{
754
269k
  using ExprType = Expression::ExprOneofCase;
755
269k
  switch (expr.expr_oneof_case()) {
756
6.10k
  case ExprType::kNil:
757
6.10k
    return "nil";
758
3.04k
  case ExprType::kFalse:
759
3.04k
    return "false";
760
4.45k
  case ExprType::kTrue:
761
4.45k
    return "true";
762
25.8k
  case ExprType::kNumber: {
763
    /* Clamp number between given boundaries. */
764
25.8k
    double number = clamp(expr.number(), kMaxNumber, kMinNumber);
765
25.8k
    return std::to_string(number);
766
0
  }
767
6.10k
  case ExprType::kStr:
768
6.10k
    return "'" + ConvertToStringDefault(expr.str()) + "'";
769
4.91k
  case ExprType::kEllipsis:
770
4.91k
    return " ... ";
771
17.9k
  case ExprType::kFunction:
772
17.9k
    return AnonFuncToString(expr.function());
773
26.4k
  case ExprType::kPrefixexp:
774
26.4k
    return PrefixExpressionToString(expr.prefixexp());
775
11.0k
  case ExprType::kTableconstructor:
776
11.0k
    return TableConstructorToString(expr.tableconstructor());
777
36.4k
  case ExprType::kBinary:
778
36.4k
    return ExpBinaryOpExpToString(expr.binary());
779
8.96k
  case ExprType::kUnary:
780
8.96k
    return UnaryOpExpToString(expr.unary());
781
118k
  default:
782
    /**
783
     * Arbitrary choice.
784
     * TODO: Choose "more interesting" defaults.
785
     */
786
118k
    return "'" + ConvertToStringDefault(expr.str()) + "'";
787
269k
  }
788
269k
}
789
790
NESTED_PROTO_TOSTRING(AnonFunc, func, Expression)
791
17.9k
{
792
17.9k
  const auto id = GetCounterIdProvider().next();
793
17.9k
  auto counter_name = GetCounterName(id);
794
795
17.9k
  std::string retval = "function ";
796
17.9k
  retval += FuncBodyToStringReqProtected(func.body(), counter_name);
797
798
17.9k
  return retval;
799
17.9k
}
800
801
NESTED_PROTO_TOSTRING(ExpBinaryOpExp, binary, Expression)
802
36.4k
{
803
36.4k
  std::string binary_str = ExpressionToString(binary.leftexp());
804
36.4k
  binary_str += " " + BinaryOperatorToString(binary.binop()) + " ";
805
36.4k
  binary_str += ExpressionToString(binary.rightexp());
806
36.4k
  return binary_str;
807
36.4k
}
808
809
NESTED_PROTO_TOSTRING(UnaryOpExp, unary, Expression)
810
8.96k
{
811
8.96k
  std::string unary_str = UnaryOperatorToString(unary.unop());
812
8.96k
  unary_str += ExpressionToString(unary.exp());
813
8.96k
  return unary_str;
814
8.96k
}
815
816
/**
817
 * Tables and fields.
818
 */
819
PROTO_TOSTRING(TableConstructor, table)
820
23.2k
{
821
23.2k
  std::string table_str = "{ ";
822
23.2k
  if (table.has_fieldlist())
823
9.38k
    table_str += FieldListToString(table.fieldlist());
824
23.2k
  table_str += " }";
825
23.2k
  return table_str;
826
23.2k
}
827
828
PROTO_TOSTRING(FieldList, fieldlist)
829
9.38k
{
830
9.38k
  std::string fieldlist_str = FieldToString(fieldlist.firstfield());
831
18.3k
  for (int i = 0; i < fieldlist.fields_size(); ++i)
832
8.93k
    fieldlist_str += FieldWithFieldSepToString(fieldlist.fields(i));
833
9.38k
  if (fieldlist.has_lastsep())
834
1.90k
    fieldlist_str += FieldSepToString(fieldlist.lastsep());
835
9.38k
  return fieldlist_str;
836
9.38k
}
837
838
NESTED_PROTO_TOSTRING(FieldWithFieldSep, field, FieldList)
839
8.93k
{
840
8.93k
  std::string field_str = FieldSepToString(field.sep());
841
8.93k
  field_str += " " + FieldToString(field.field());
842
8.93k
  return field_str;
843
8.93k
}
844
845
/**
846
 * Field and nested types.
847
 */
848
PROTO_TOSTRING(Field, field)
849
18.3k
{
850
18.3k
  using FieldType = Field::FieldOneofCase;
851
18.3k
  switch (field.field_oneof_case()) {
852
5.47k
  case FieldType::kExprassign:
853
5.47k
    return ExpressionAssignmentToString(field.exprassign());
854
783
  case FieldType::kNamedassign:
855
783
    return NameAssignmentToString(field.namedassign());
856
5.70k
  case FieldType::kExpression:
857
5.70k
    return ExpressionToString(field.expression());
858
6.36k
  default:
859
    /* More common case of using fields. */
860
6.36k
    return NameAssignmentToString(field.namedassign());
861
18.3k
  }
862
18.3k
}
863
864
NESTED_PROTO_TOSTRING(ExpressionAssignment, assignment, Field)
865
5.47k
{
866
5.47k
  std::string assignment_str = "[ " +
867
5.47k
    ExpressionToString(assignment.key()) + " ]";
868
5.47k
  assignment_str += " = " + ExpressionToString(assignment.value());
869
5.47k
  return assignment_str;
870
5.47k
}
871
872
NESTED_PROTO_TOSTRING(NameAssignment, assignment, Field)
873
7.14k
{
874
7.14k
  std::string assignment_str = NameToString(assignment.name());
875
7.14k
  assignment_str += " = " + ExpressionToString(assignment.value());
876
7.14k
  return assignment_str;
877
7.14k
}
878
879
PROTO_TOSTRING(FieldSep, sep)
880
10.8k
{
881
10.8k
  using FieldSepType = FieldSep::SepOneofCase;
882
10.8k
  switch (sep.sep_oneof_case()) {
883
2.26k
  case FieldSepType::kComma:
884
2.26k
    return ",";
885
1.38k
  case FieldSepType::kSemicolon:
886
1.38k
    return ";";
887
7.18k
  default:
888
7.18k
    return ",";
889
10.8k
  }
890
10.8k
}
891
892
/**
893
 * Operators.
894
 */
895
PROTO_TOSTRING(BinaryOperator, op)
896
36.4k
{
897
36.4k
  using BinopType = BinaryOperator::BinaryOneofCase;
898
36.4k
  switch (op.binary_oneof_case()) {
899
1.17k
  case BinopType::kAdd:
900
1.17k
    return "+";
901
2.33k
  case BinopType::kSub:
902
2.33k
    return "-";
903
8.97k
  case BinopType::kMult:
904
8.97k
    return "*";
905
1.26k
  case BinopType::kDiv:
906
1.26k
    return "/";
907
873
  case BinopType::kExp:
908
873
    return "^";
909
1.44k
  case BinopType::kMod:
910
1.44k
    return "%";
911
912
3.35k
  case BinopType::kConcat:
913
3.35k
    return "..";
914
915
905
  case BinopType::kLess:
916
905
    return "<";
917
752
  case BinopType::kLessEqual:
918
752
    return "<=";
919
762
  case BinopType::kGreater:
920
762
    return ">";
921
927
  case BinopType::kGreaterEqual:
922
927
    return ">=";
923
784
  case BinopType::kEqual:
924
784
    return "==";
925
622
  case BinopType::kNotEqual:
926
622
    return "~=";
927
2.08k
  case BinopType::kAnd:
928
2.08k
    return "and";
929
4.08k
  case BinopType::kOr:
930
4.08k
    return "or";
931
6.07k
  default:
932
    /* Works in most cases. */
933
6.07k
    return "==";
934
36.4k
  }
935
36.4k
}
936
937
PROTO_TOSTRING(UnaryOperator, op)
938
8.96k
{
939
8.96k
  using UnaryopType = UnaryOperator::UnaryOneofCase;
940
8.96k
  switch (op.unary_oneof_case()) {
941
1.32k
  case UnaryopType::kNegate:
942
1.32k
    return "-";
943
435
  case UnaryopType::kNot:
944
435
    return "not ";
945
4.72k
  case UnaryopType::kLength:
946
4.72k
    return "#";
947
2.48k
  default:
948
    /* Works in most cases. */
949
2.48k
    return "not ";
950
8.96k
  }
951
8.96k
}
952
953
/**
954
 * Identifier (Name).
955
 */
956
PROTO_TOSTRING(Name, name)
957
153k
{
958
153k
  std::string ident = ConvertToStringDefault(name.name());
959
153k
  return ident + std::to_string(name.num() % kMaxIdentifiers);
960
153k
}
961
962
} /* namespace */
963
964
std::string
965
MainBlockToString(const Block &block)
966
2.58k
{
967
2.58k
  GetCounterIdProvider().clean();
968
969
2.58k
  std::string block_str = BlockToString(block);
970
2.58k
  std::string retval;
971
972
80.3k
  for (size_t i = 0; i < GetCounterIdProvider().count(); ++i) {
973
77.7k
    retval += GetCounterName(i);
974
77.7k
    retval += " = 0\n";
975
77.7k
  }
976
2.58k
  retval += block_str;
977
978
2.58k
  return retval;
979
2.58k
}
980
981
} /* namespace luajit_fuzzer */