Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/fuzz/protoprint.cpp
2723 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "luau.pb.h"
3
4
static const std::string kNames[] = {
5
"_G",
6
"_VERSION",
7
"__add",
8
"__call",
9
"__concat",
10
"__div",
11
"__eq",
12
"__idiv",
13
"__index",
14
"__iter",
15
"__le",
16
"__len",
17
"__lt",
18
"__mod",
19
"__mode",
20
"__mul",
21
"__namecall",
22
"__newindex",
23
"__pow",
24
"__sub",
25
"__type",
26
"__unm",
27
"abs",
28
"acos",
29
"arshift",
30
"asin",
31
"assert",
32
"atan",
33
"atan2",
34
"band",
35
"bit32",
36
"bnot",
37
"boolean",
38
"bor",
39
"btest",
40
"buffer",
41
"bxor",
42
"byte",
43
"ceil",
44
"char",
45
"charpattern",
46
"clamp",
47
"clear",
48
"clock",
49
"clone",
50
"close",
51
"codepoint",
52
"codes",
53
"collectgarbage",
54
"concat",
55
"copy",
56
"coroutine",
57
"cos",
58
"cosh",
59
"countlz",
60
"countrz",
61
"create",
62
"date",
63
"debug",
64
"deg",
65
"difftime",
66
"error",
67
"exp",
68
"extract",
69
"fill",
70
"find",
71
"floor",
72
"fmod",
73
"foreach",
74
"foreachi",
75
"format",
76
"freeze",
77
"frexp",
78
"fromstring",
79
"function",
80
"gcinfo",
81
"getfenv",
82
"getmetatable",
83
"getn",
84
"gmatch",
85
"gsub",
86
"huge",
87
"info",
88
"insert",
89
"ipairs",
90
"isfrozen",
91
"isyieldable",
92
"ldexp",
93
"len",
94
"loadstring",
95
"log",
96
"log10",
97
"lower",
98
"lrotate",
99
"lshift",
100
"match",
101
"math",
102
"max",
103
"maxn",
104
"min",
105
"modf",
106
"move",
107
"newproxy",
108
"next",
109
"nil",
110
"noise",
111
"number",
112
"offset",
113
"os",
114
"pack",
115
"packsize",
116
"pairs",
117
"pcall",
118
"pi",
119
"pow",
120
"print",
121
"rad",
122
"random",
123
"randomseed",
124
"rawequal",
125
"rawget",
126
"rawlen",
127
"rawset",
128
"readf32",
129
"readf64",
130
"readi16",
131
"readi32",
132
"readi8",
133
"readstring",
134
"readu16",
135
"readu32",
136
"readu8",
137
"remove",
138
"rep",
139
"replace",
140
"require",
141
"resume",
142
"reverse",
143
"round",
144
"rrotate",
145
"rshift",
146
"running",
147
"select",
148
"setfenv",
149
"setmetatable",
150
"sign",
151
"sin",
152
"sinh",
153
"sort",
154
"split",
155
"sqrt",
156
"status",
157
"string",
158
"sub",
159
"table",
160
"tan",
161
"tanh",
162
"thread",
163
"time",
164
"tonumber",
165
"tostring",
166
"tostring",
167
"traceback",
168
"type",
169
"typeof",
170
"unpack",
171
"upper",
172
"userdata",
173
"utf8",
174
"vector",
175
"wrap",
176
"writef32",
177
"writef64",
178
"writei16",
179
"writei32",
180
"writei8",
181
"writestring",
182
"writeu16",
183
"writeu32",
184
"writeu8",
185
"xpcall",
186
"yield",
187
"types",
188
"unknown",
189
"never",
190
"any",
191
"singleton",
192
"optional",
193
"generic",
194
"negationof",
195
"unionof",
196
"intersectionof",
197
"newtable",
198
"newfunction",
199
"integer",
200
"neg",
201
"add",
202
"sub",
203
"mul",
204
"div",
205
"rem",
206
"idiv",
207
"mod",
208
"udiv",
209
"urem",
210
"lt",
211
"le",
212
"gt",
213
"ge",
214
"ult",
215
"ule",
216
"ugt",
217
"uge",
218
"readinteger",
219
"writeinteger",
220
"mininteger",
221
"maxinteger",
222
};
223
224
static const std::string kTypes[] = {
225
"any",
226
"boolean",
227
"buffer",
228
"nil",
229
"number",
230
"integer",
231
"string",
232
"thread",
233
"vector",
234
"unknown",
235
"never",
236
};
237
238
static const std::string kExternTypes[] = {
239
"Vector3",
240
"Instance",
241
"Part",
242
};
243
244
static const std::string kBuiltinTypes[] = {
245
"len", "unm", "add", "sub", "mul", "div", "idiv", "pow", "mod", "concat",
246
"lt", "le", "eq", "keyof", "rawkeyof", "index", "rawget", "setmetatable", "getmetatable",
247
};
248
249
struct ProtoToLuau
250
{
251
struct Function
252
{
253
int loops = 0;
254
bool vararg = false;
255
};
256
257
std::string source;
258
std::vector<Function> functions;
259
bool types = false;
260
261
ProtoToLuau()
262
{
263
Function top = {};
264
top.vararg = true;
265
functions.push_back(top);
266
}
267
268
std::string displayName(const luau::Name& name)
269
{
270
if (name.has_builtin())
271
{
272
size_t index = size_t(name.builtin()) % std::size(kNames);
273
return kNames[index];
274
}
275
else if (name.has_custom())
276
{
277
return 'n' + std::to_string(name.custom() & 0xff);
278
}
279
else
280
{
281
return "_";
282
}
283
}
284
285
void ident(const luau::Name& name)
286
{
287
source += displayName(name);
288
}
289
290
void ident(const luau::RegularTypeName& name)
291
{
292
source += 't';
293
source += std::to_string(name.index() & 0xff);
294
}
295
296
void ident(const luau::GenericTypeName& name)
297
{
298
source += char('A' + (name.index() % 26));
299
}
300
301
void ident(const luau::BuiltinTypeName& name)
302
{
303
size_t index = size_t(name.index()) % std::size(kBuiltinTypes);
304
source += kBuiltinTypes[index];
305
}
306
307
void ident(const luau::TypeName& name)
308
{
309
if (name.has_regular())
310
ident(name.regular());
311
else if (name.has_generic())
312
ident(name.generic());
313
else if (name.has_builtin())
314
ident(name.builtin());
315
else
316
source += "any";
317
}
318
319
template<typename T>
320
void genericidents(const T& node)
321
{
322
if (node.generics_size() || node.genericpacks_size())
323
{
324
source += '<';
325
bool first = true;
326
327
for (size_t i = 0; i < node.generics_size(); ++i)
328
{
329
if (!first)
330
source += ',';
331
first = false;
332
ident(node.generics(i));
333
}
334
335
for (size_t i = 0; i < node.genericpacks_size(); ++i)
336
{
337
if (!first)
338
source += ',';
339
first = false;
340
ident(node.genericpacks(i));
341
source += "...";
342
}
343
344
source += '>';
345
}
346
}
347
348
void print(const luau::Expr& expr)
349
{
350
if (expr.has_group())
351
print(expr.group());
352
else if (expr.has_nil())
353
print(expr.nil());
354
else if (expr.has_bool_())
355
print(expr.bool_());
356
else if (expr.has_number())
357
print(expr.number());
358
else if (expr.has_integer())
359
print(expr.integer());
360
else if (expr.has_string())
361
print(expr.string());
362
else if (expr.has_local())
363
print(expr.local());
364
else if (expr.has_global())
365
print(expr.global());
366
else if (expr.has_varargs())
367
print(expr.varargs());
368
else if (expr.has_call())
369
print(expr.call());
370
else if (expr.has_index_name())
371
print(expr.index_name());
372
else if (expr.has_index_expr())
373
print(expr.index_expr());
374
else if (expr.has_function())
375
print(expr.function());
376
else if (expr.has_table())
377
print(expr.table());
378
else if (expr.has_unary())
379
print(expr.unary());
380
else if (expr.has_binary())
381
print(expr.binary());
382
else if (expr.has_ifelse())
383
print(expr.ifelse());
384
else if (expr.has_interpstring())
385
print(expr.interpstring());
386
else
387
source += "_";
388
}
389
390
void print(const luau::ExprPrefix& expr)
391
{
392
if (expr.has_group())
393
print(expr.group());
394
else if (expr.has_local())
395
print(expr.local());
396
else if (expr.has_global())
397
print(expr.global());
398
else if (expr.has_call())
399
print(expr.call());
400
else if (expr.has_index_name())
401
print(expr.index_name());
402
else if (expr.has_index_expr())
403
print(expr.index_expr());
404
else
405
source += "_";
406
}
407
408
void print(const luau::ExprGroup& expr)
409
{
410
source += '(';
411
print(expr.expr());
412
source += ')';
413
}
414
415
void print(const luau::ExprConstantNil& expr)
416
{
417
source += "nil";
418
}
419
420
void print(const luau::ExprConstantBool& expr)
421
{
422
source += expr.val() ? "true" : "false";
423
}
424
425
void print(const luau::ExprConstantNumber& expr)
426
{
427
source += std::to_string(expr.val());
428
}
429
430
void print(const luau::ExprConstantInteger& expr)
431
{
432
source += std::to_string(expr.val()) + "i";
433
}
434
435
void print(const luau::ExprConstantString& expr)
436
{
437
source += '"';
438
for (char ch : expr.val())
439
if (isalpha(ch))
440
source += ch;
441
source += '"';
442
}
443
444
void print(const luau::Local& var)
445
{
446
source += 'l';
447
source += std::to_string(var.name() & 0xff);
448
}
449
450
void print(const luau::ExprLocal& expr)
451
{
452
print(expr.var());
453
}
454
455
void print(const luau::ExprGlobal& expr)
456
{
457
ident(expr.name());
458
}
459
460
void print(const luau::ExprVarargs& expr)
461
{
462
if (functions.back().vararg)
463
source += "...";
464
else
465
source += "_";
466
}
467
468
void print(const luau::ExprCall& expr)
469
{
470
if (expr.func().has_index_name())
471
print(expr.func().index_name(), expr.self());
472
else
473
print(expr.func());
474
source += '(';
475
for (int i = 0; i < expr.args_size(); ++i)
476
{
477
if (i != 0)
478
source += ',';
479
print(expr.args(i));
480
}
481
source += ')';
482
}
483
484
void print(const luau::ExprIndexName& expr, bool self = false)
485
{
486
print(expr.expr());
487
source += self ? ':' : '.';
488
ident(expr.index());
489
}
490
491
void print(const luau::ExprIndexExpr& expr)
492
{
493
print(expr.expr());
494
source += '[';
495
print(expr.index());
496
source += ']';
497
}
498
499
void function(const luau::ExprFunction& expr)
500
{
501
genericidents(expr);
502
source += "(";
503
for (int i = 0; i < expr.args_size(); ++i)
504
{
505
if (i != 0)
506
source += ',';
507
print(expr.args(i));
508
509
if (types && i < expr.types_size())
510
{
511
source += ':';
512
print(expr.types(i));
513
}
514
}
515
if (expr.vararg())
516
{
517
if (expr.args_size())
518
source += ',';
519
source += "...";
520
}
521
source += ')';
522
if (types && expr.rettypes_size())
523
{
524
source += ':';
525
if (expr.rettypes_size() > 1)
526
source += '(';
527
for (size_t i = 0; i < expr.rettypes_size(); ++i)
528
{
529
if (i != 0)
530
source += ',';
531
print(expr.rettypes(i));
532
}
533
if (expr.rettypes_size() > 1)
534
source += ')';
535
}
536
source += '\n';
537
538
Function func = {};
539
func.vararg = expr.vararg();
540
functions.push_back(func);
541
542
print(expr.body());
543
544
functions.pop_back();
545
546
source += "end";
547
}
548
549
void print(const luau::ExprFunction& expr)
550
{
551
for (size_t i = 0; i < expr.attributes_size(); ++i)
552
{
553
print(expr.attributes(i));
554
source += "\n";
555
}
556
source += "function";
557
function(expr);
558
}
559
560
void print(const luau::ExprTable& expr)
561
{
562
source += '{';
563
for (int i = 0; i < expr.items_size(); ++i)
564
{
565
if (expr.items(i).has_key_name())
566
{
567
ident(expr.items(i).key_name());
568
source += '=';
569
}
570
else if (expr.items(i).has_key_expr())
571
{
572
source += "[";
573
print(expr.items(i).key_expr());
574
source += "]=";
575
}
576
577
print(expr.items(i).value());
578
source += ',';
579
}
580
source += '}';
581
}
582
583
void print(const luau::ExprUnary& expr)
584
{
585
if (expr.op() == luau::ExprUnary::Not)
586
source += "not ";
587
else if (expr.op() == luau::ExprUnary::Minus)
588
source += "- ";
589
else if (expr.op() == luau::ExprUnary::Len)
590
source += "# ";
591
592
print(expr.expr());
593
}
594
595
void print(const luau::ExprBinary& expr)
596
{
597
print(expr.left());
598
599
if (expr.op() == luau::ExprBinary::Add)
600
source += " + ";
601
else if (expr.op() == luau::ExprBinary::Sub)
602
source += " - ";
603
else if (expr.op() == luau::ExprBinary::Mul)
604
source += " * ";
605
else if (expr.op() == luau::ExprBinary::Div)
606
source += " / ";
607
else if (expr.op() == luau::ExprBinary::FloorDiv)
608
source += " // ";
609
else if (expr.op() == luau::ExprBinary::Mod)
610
source += " % ";
611
else if (expr.op() == luau::ExprBinary::Pow)
612
source += " ^ ";
613
else if (expr.op() == luau::ExprBinary::Concat)
614
source += " .. ";
615
else if (expr.op() == luau::ExprBinary::CompareNe)
616
source += " ~= ";
617
else if (expr.op() == luau::ExprBinary::CompareEq)
618
source += " == ";
619
else if (expr.op() == luau::ExprBinary::CompareLt)
620
source += " < ";
621
else if (expr.op() == luau::ExprBinary::CompareLe)
622
source += " <= ";
623
else if (expr.op() == luau::ExprBinary::CompareGt)
624
source += " > ";
625
else if (expr.op() == luau::ExprBinary::CompareGe)
626
source += " >= ";
627
else if (expr.op() == luau::ExprBinary::And)
628
source += " and ";
629
else if (expr.op() == luau::ExprBinary::Or)
630
source += " or ";
631
632
print(expr.right());
633
}
634
635
void print(const luau::ExprIfElse& expr)
636
{
637
source += "if ";
638
print(expr.cond());
639
source += " then ";
640
print(expr.then());
641
642
if (expr.has_else_())
643
{
644
source += " else ";
645
print(expr.else_());
646
}
647
else if (expr.has_elseif())
648
{
649
source += " else";
650
print(expr.elseif());
651
}
652
}
653
654
void print(const luau::ExprInterpString& expr)
655
{
656
source += "`";
657
658
for (int i = 0; i < expr.parts_size(); ++i)
659
{
660
if (expr.parts(i).has_string())
661
{
662
// String literal is added surrounded with "", but that's ok
663
print(expr.parts(i));
664
}
665
else
666
{
667
source += "{";
668
print(expr.parts(i));
669
source += "}";
670
}
671
}
672
673
source += "`";
674
}
675
676
void print(const luau::LValue& expr)
677
{
678
if (expr.has_local())
679
print(expr.local());
680
else if (expr.has_global())
681
print(expr.global());
682
else if (expr.has_index_name())
683
print(expr.index_name());
684
else if (expr.has_index_expr())
685
print(expr.index_expr());
686
else
687
source += "_";
688
}
689
690
void print(const luau::Stat& stat)
691
{
692
if (stat.has_block())
693
print(stat.block());
694
else if (stat.has_if_())
695
print(stat.if_());
696
else if (stat.has_while_())
697
print(stat.while_());
698
else if (stat.has_repeat())
699
print(stat.repeat());
700
else if (stat.has_break_())
701
print(stat.break_());
702
else if (stat.has_continue_())
703
print(stat.continue_());
704
else if (stat.has_return_())
705
print(stat.return_());
706
else if (stat.has_call())
707
print(stat.call());
708
else if (stat.has_local())
709
print(stat.local());
710
else if (stat.has_for_())
711
print(stat.for_());
712
else if (stat.has_for_in())
713
print(stat.for_in());
714
else if (stat.has_assign())
715
print(stat.assign());
716
else if (stat.has_compound_assign())
717
print(stat.compound_assign());
718
else if (stat.has_function())
719
print(stat.function());
720
else if (stat.has_local_function())
721
print(stat.local_function());
722
else if (stat.has_type_alias())
723
print(stat.type_alias());
724
else if (stat.has_require_into_local())
725
print(stat.require_into_local());
726
else if (stat.has_type_function())
727
print(stat.type_function());
728
else
729
source += "do end\n";
730
}
731
732
void print(const luau::StatBlock& stat)
733
{
734
for (int i = 0; i < stat.body_size(); ++i)
735
{
736
if (stat.body(i).has_block())
737
{
738
source += "do\n";
739
print(stat.body(i));
740
source += "end\n";
741
}
742
else
743
{
744
print(stat.body(i));
745
746
// parser will reject code with break/continue/return being non-trailing statements in a block
747
if (stat.body(i).has_break_() || stat.body(i).has_continue_() || stat.body(i).has_return_())
748
break;
749
}
750
}
751
}
752
753
void print(const luau::StatIf& stat)
754
{
755
source += "if ";
756
print(stat.cond());
757
source += " then\n";
758
print(stat.then());
759
760
if (stat.has_else_())
761
{
762
source += "else\n";
763
print(stat.else_());
764
source += "end\n";
765
}
766
else if (stat.has_elseif())
767
{
768
source += "else";
769
print(stat.elseif());
770
}
771
else
772
{
773
source += "end\n";
774
}
775
}
776
777
void print(const luau::StatWhile& stat)
778
{
779
source += "while ";
780
print(stat.cond());
781
source += " do\n";
782
783
functions.back().loops++;
784
print(stat.body());
785
functions.back().loops--;
786
787
source += "end\n";
788
}
789
790
void print(const luau::StatRepeat& stat)
791
{
792
source += "repeat\n";
793
794
functions.back().loops++;
795
print(stat.body());
796
functions.back().loops--;
797
798
source += "until ";
799
print(stat.cond());
800
source += "\n";
801
}
802
803
void print(const luau::StatBreak& stat)
804
{
805
if (functions.back().loops)
806
source += "break\n";
807
else
808
source += "do end\n";
809
}
810
811
void print(const luau::StatContinue& stat)
812
{
813
if (functions.back().loops)
814
source += "continue\n";
815
else
816
source += "do end\n";
817
}
818
819
void print(const luau::StatReturn& stat)
820
{
821
source += "return ";
822
for (int i = 0; i < stat.list_size(); ++i)
823
{
824
if (i != 0)
825
source += ',';
826
print(stat.list(i));
827
}
828
source += "\n";
829
}
830
831
void print(const luau::StatCall& stat)
832
{
833
print(stat.expr());
834
source += '\n';
835
}
836
837
void print(const luau::StatLocal& stat)
838
{
839
source += "local ";
840
841
if (stat.vars_size() == 0)
842
source += '_';
843
844
for (int i = 0; i < stat.vars_size(); ++i)
845
{
846
if (i != 0)
847
source += ',';
848
print(stat.vars(i));
849
850
if (types && i < stat.types_size())
851
{
852
source += ':';
853
print(stat.types(i));
854
}
855
}
856
857
if (stat.values_size() != 0)
858
source += " = ";
859
860
for (int i = 0; i < stat.values_size(); ++i)
861
{
862
if (i != 0)
863
source += ',';
864
print(stat.values(i));
865
}
866
source += '\n';
867
}
868
869
void print(const luau::StatFor& stat)
870
{
871
source += "for ";
872
print(stat.var());
873
source += '=';
874
print(stat.from());
875
source += ',';
876
print(stat.to());
877
if (stat.has_step())
878
{
879
source += ',';
880
print(stat.step());
881
}
882
source += " do\n";
883
884
functions.back().loops++;
885
print(stat.body());
886
functions.back().loops--;
887
888
source += "end\n";
889
}
890
891
void print(const luau::StatForIn& stat)
892
{
893
source += "for ";
894
895
if (stat.vars_size() == 0)
896
source += '_';
897
898
for (int i = 0; i < stat.vars_size(); ++i)
899
{
900
if (i != 0)
901
source += ',';
902
print(stat.vars(i));
903
}
904
905
source += " in ";
906
907
if (stat.values_size() == 0)
908
source += "...";
909
910
for (int i = 0; i < stat.values_size(); ++i)
911
{
912
if (i != 0)
913
source += ',';
914
print(stat.values(i));
915
}
916
917
source += " do\n";
918
919
functions.back().loops++;
920
print(stat.body());
921
functions.back().loops--;
922
923
source += "end\n";
924
}
925
926
void print(const luau::StatAssign& stat)
927
{
928
if (stat.vars_size() == 0)
929
source += '_';
930
931
for (int i = 0; i < stat.vars_size(); ++i)
932
{
933
if (i != 0)
934
source += ',';
935
print(stat.vars(i));
936
}
937
938
source += " = ";
939
940
if (stat.values_size() == 0)
941
source += "nil";
942
943
for (int i = 0; i < stat.values_size(); ++i)
944
{
945
if (i != 0)
946
source += ',';
947
print(stat.values(i));
948
}
949
source += '\n';
950
}
951
952
void print(const luau::StatCompoundAssign& stat)
953
{
954
print(stat.var());
955
956
if (stat.op() == luau::StatCompoundAssign::Add)
957
source += " += ";
958
else if (stat.op() == luau::StatCompoundAssign::Sub)
959
source += " -= ";
960
else if (stat.op() == luau::StatCompoundAssign::Mul)
961
source += " *= ";
962
else if (stat.op() == luau::StatCompoundAssign::Div)
963
source += " /= ";
964
else if (stat.op() == luau::StatCompoundAssign::Mod)
965
source += " %= ";
966
else if (stat.op() == luau::StatCompoundAssign::Pow)
967
source += " ^= ";
968
else if (stat.op() == luau::StatCompoundAssign::Concat)
969
source += " ..= ";
970
971
print(stat.value());
972
source += '\n';
973
}
974
975
void print(const luau::StatFunction& stat)
976
{
977
source += "function ";
978
if (stat.var().has_index_name())
979
print(stat.var().index_name(), stat.self());
980
else if (stat.var().has_index_expr())
981
source += '_'; // function foo[bar]() is invalid syntax
982
else
983
print(stat.var());
984
function(stat.func());
985
source += '\n';
986
}
987
988
void print(const luau::StatLocalFunction& stat)
989
{
990
source += "local function ";
991
print(stat.var());
992
function(stat.func());
993
source += '\n';
994
}
995
996
void print(const luau::StatTypeAlias& stat)
997
{
998
if (stat.export_())
999
source += "export ";
1000
1001
source += "type ";
1002
ident(stat.name());
1003
genericidents(stat);
1004
source += " = ";
1005
print(stat.type());
1006
source += '\n';
1007
}
1008
1009
void print(const luau::StatRequireIntoLocalHelper& stat)
1010
{
1011
source += "local ";
1012
print(stat.var());
1013
source += " = require(module" + std::to_string(stat.modulenum() % 2) + ")\n";
1014
}
1015
1016
void print(const luau::StatTypeFunction& stat)
1017
{
1018
for (size_t i = 0; i < stat.func().attributes_size(); ++i)
1019
{
1020
print(stat.func().attributes(i));
1021
source += "\n";
1022
}
1023
1024
if (stat.export_())
1025
source += "export ";
1026
1027
source += "type function ";
1028
ident(stat.name());
1029
function(stat.func());
1030
source += '\n';
1031
}
1032
1033
void print(const luau::Type& type)
1034
{
1035
if (type.has_primitive())
1036
print(type.primitive());
1037
else if (type.has_literal())
1038
print(type.literal());
1039
else if (type.has_table())
1040
print(type.table());
1041
else if (type.has_function())
1042
print(type.function());
1043
else if (type.has_typeof())
1044
print(type.typeof());
1045
else if (type.has_union_())
1046
print(type.union_());
1047
else if (type.has_intersection())
1048
print(type.intersection());
1049
else if (type.has_extern_())
1050
print(type.extern_());
1051
else if (type.has_ref())
1052
print(type.ref());
1053
else if (type.has_boolean())
1054
print(type.boolean());
1055
else if (type.has_string())
1056
print(type.string());
1057
else
1058
source += "any";
1059
}
1060
1061
void print(const luau::TypePrimitive& type)
1062
{
1063
size_t index = size_t(type.kind()) % std::size(kTypes);
1064
source += kTypes[index];
1065
}
1066
1067
void print(const luau::TypeLiteral& type)
1068
{
1069
ident(type.name());
1070
1071
if (type.generics_size() || type.genericpacks_size())
1072
{
1073
source += '<';
1074
bool first = true;
1075
1076
for (size_t i = 0; i < type.generics_size(); ++i)
1077
{
1078
if (!first)
1079
source += ',';
1080
first = false;
1081
print(type.generics(i));
1082
}
1083
1084
for (size_t i = 0; i < type.genericpacks_size(); ++i)
1085
{
1086
if (!first)
1087
source += ',';
1088
first = false;
1089
ident(type.genericpacks(i));
1090
source += "...";
1091
}
1092
1093
source += '>';
1094
}
1095
}
1096
1097
void print(const luau::TableFieldAccess& expr)
1098
{
1099
if (expr == luau::TableFieldAccess::Read)
1100
source += "read";
1101
else if (expr == luau::TableFieldAccess::Write)
1102
source += "write";
1103
}
1104
1105
void print(const luau::TypeTable& type)
1106
{
1107
source += '{';
1108
for (size_t i = 0; i < type.items_size(); ++i)
1109
{
1110
auto& item = type.items(i);
1111
1112
if (item.has_access())
1113
{
1114
print(item.access());
1115
source += ' ';
1116
}
1117
1118
ident(item.key());
1119
source += ':';
1120
print(item.type());
1121
source += ',';
1122
}
1123
if (type.has_indexer())
1124
{
1125
auto& indexer = type.indexer();
1126
1127
if (indexer.has_access())
1128
{
1129
print(indexer.access());
1130
source += ' ';
1131
}
1132
1133
source += '[';
1134
print(indexer.key());
1135
source += "]:";
1136
print(indexer.value());
1137
}
1138
source += '}';
1139
}
1140
1141
void print(const luau::TypeFunction& type)
1142
{
1143
genericidents(type);
1144
source += '(';
1145
for (size_t i = 0; i < type.args_size(); ++i)
1146
{
1147
if (i != 0)
1148
source += ',';
1149
print(type.args(i));
1150
}
1151
source += ")->";
1152
if (type.rets_size() != 1)
1153
source += '(';
1154
for (size_t i = 0; i < type.rets_size(); ++i)
1155
{
1156
if (i != 0)
1157
source += ',';
1158
print(type.rets(i));
1159
}
1160
if (type.rets_size() != 1)
1161
source += ')';
1162
}
1163
1164
void print(const luau::TypeTypeof& type)
1165
{
1166
source += "typeof(";
1167
print(type.expr());
1168
source += ')';
1169
}
1170
1171
void print(const luau::TypeUnion& type)
1172
{
1173
source += '(';
1174
print(type.left());
1175
source += ")|(";
1176
print(type.right());
1177
source += ')';
1178
}
1179
1180
void print(const luau::TypeIntersection& type)
1181
{
1182
source += '(';
1183
print(type.left());
1184
source += ")&(";
1185
print(type.right());
1186
source += ')';
1187
}
1188
1189
void print(const luau::TypeExtern& type)
1190
{
1191
size_t index = size_t(type.kind()) % std::size(kExternTypes);
1192
source += kExternTypes[index];
1193
}
1194
1195
void print(const luau::TypeRef& type)
1196
{
1197
print(type.prefix());
1198
source += '.';
1199
ident(type.index());
1200
}
1201
1202
void print(const luau::TypeBoolean& type)
1203
{
1204
source += type.val() ? "true" : "false";
1205
}
1206
1207
void print(const luau::TypeString& type)
1208
{
1209
source += '"';
1210
for (char ch : type.val())
1211
if (isgraph(ch))
1212
source += ch;
1213
source += '"';
1214
}
1215
1216
void print(const luau::ExprLiteralTable& table)
1217
{
1218
source += '{';
1219
for (int i = 0; i < table.items_size(); ++i)
1220
{
1221
ident(table.items(i).key_name());
1222
source += '=';
1223
1224
print(table.items(i).value());
1225
source += ',';
1226
}
1227
source += '}';
1228
}
1229
1230
void print(const luau::ExprLiteral& lit)
1231
{
1232
if (lit.has_table())
1233
print(lit.table());
1234
else if (lit.has_nil())
1235
print(lit.nil());
1236
else if (lit.has_bool_())
1237
print(lit.bool_());
1238
else if (lit.has_number())
1239
print(lit.number());
1240
else if (lit.has_integer())
1241
print(lit.integer());
1242
else if (lit.has_string())
1243
print(lit.string());
1244
}
1245
1246
void print(const luau::ExprAttr& attr)
1247
{
1248
std::string name;
1249
if (attr.type() == luau::AttrType::Checked)
1250
name = "checked";
1251
if (attr.type() == luau::AttrType::Native)
1252
name = "native";
1253
if (attr.type() == luau::AttrType::Deprecated)
1254
name = "deprecated";
1255
else
1256
name = displayName(attr.name());
1257
1258
if (attr.braced())
1259
{
1260
source += "@[" + name;
1261
if (attr.args_size() == 1)
1262
{
1263
source += " ";
1264
print(attr.args(0));
1265
}
1266
else if (attr.args_size() > 1)
1267
{
1268
source += "(";
1269
for (int i = 0; i < attr.args_size(); ++i)
1270
{
1271
if (i != 0)
1272
source += ',';
1273
print(attr.args(i));
1274
}
1275
source += ")";
1276
}
1277
source += "]";
1278
}
1279
else
1280
{
1281
source += "@" + name;
1282
}
1283
}
1284
};
1285
1286
std::vector<std::string> protoprint(const luau::ModuleSet& stat, bool types)
1287
{
1288
std::vector<std::string> result;
1289
1290
if (stat.has_module())
1291
{
1292
ProtoToLuau printer;
1293
printer.types = types;
1294
printer.print(stat.module());
1295
result.push_back(printer.source);
1296
}
1297
1298
ProtoToLuau printer;
1299
printer.types = types;
1300
printer.print(stat.program());
1301
result.push_back(printer.source);
1302
1303
return result;
1304
}
1305
1306