├── .gitignore ├── Build └── .gitkeep ├── Dependencies ├── luau │ ├── include │ │ ├── Luau │ │ │ ├── Ast.h │ │ │ ├── Bytecode.h │ │ │ ├── BytecodeBuilder.h │ │ │ ├── BytecodeUtils.h │ │ │ ├── Common.h │ │ │ ├── Compiler.h │ │ │ ├── Confusables.h │ │ │ ├── DenseHash.h │ │ │ ├── ExperimentalFlags.h │ │ │ ├── Lexer.h │ │ │ ├── Location.h │ │ │ ├── ParseOptions.h │ │ │ ├── ParseResult.h │ │ │ ├── Parser.h │ │ │ ├── StringUtils.h │ │ │ └── TimeTrace.h │ │ └── luacode.h │ └── lib │ │ ├── luau_static.lib │ │ └── luau_static.pdb └── zstd │ ├── include │ ├── xxhash.h │ └── zstd.h │ └── lib │ ├── libzstd_static.lib │ └── libzstd_static.pdb ├── README.md ├── UWP_Executor.sln └── UWP_Executor ├── Execution.cpp ├── Execution.hpp ├── Main.cpp ├── Roblox.hpp ├── Scheduler.cpp ├── Scheduler.hpp ├── UWP_Executor.vcxproj └── UWP_Executor.vcxproj.filters /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | Build/ 3 | UWP_Executor/Release/ 4 | *.user 5 | -------------------------------------------------------------------------------- /Build/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/Ast.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Location.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace Luau 14 | { 15 | 16 | struct AstName 17 | { 18 | const char* value; 19 | 20 | AstName() 21 | : value(nullptr) 22 | { 23 | } 24 | 25 | explicit AstName(const char* value) 26 | : value(value) 27 | { 28 | } 29 | 30 | bool operator==(const AstName& rhs) const 31 | { 32 | return value == rhs.value; 33 | } 34 | 35 | bool operator!=(const AstName& rhs) const 36 | { 37 | return value != rhs.value; 38 | } 39 | 40 | bool operator==(const char* rhs) const 41 | { 42 | return value && strcmp(value, rhs) == 0; 43 | } 44 | 45 | bool operator!=(const char* rhs) const 46 | { 47 | return !value || strcmp(value, rhs) != 0; 48 | } 49 | 50 | bool operator<(const AstName& rhs) const 51 | { 52 | return (value && rhs.value) ? strcmp(value, rhs.value) < 0 : value < rhs.value; 53 | } 54 | }; 55 | 56 | class AstType; 57 | class AstVisitor; 58 | class AstStat; 59 | class AstStatBlock; 60 | class AstExpr; 61 | class AstTypePack; 62 | 63 | struct AstLocal 64 | { 65 | AstName name; 66 | Location location; 67 | AstLocal* shadow; 68 | size_t functionDepth; 69 | size_t loopDepth; 70 | 71 | AstType* annotation; 72 | 73 | AstLocal(const AstName& name, const Location& location, AstLocal* shadow, size_t functionDepth, size_t loopDepth, AstType* annotation) 74 | : name(name) 75 | , location(location) 76 | , shadow(shadow) 77 | , functionDepth(functionDepth) 78 | , loopDepth(loopDepth) 79 | , annotation(annotation) 80 | { 81 | } 82 | }; 83 | 84 | template 85 | struct AstArray 86 | { 87 | T* data; 88 | size_t size; 89 | 90 | const T* begin() const 91 | { 92 | return data; 93 | } 94 | const T* end() const 95 | { 96 | return data + size; 97 | } 98 | }; 99 | 100 | struct AstTypeList 101 | { 102 | AstArray types; 103 | // Null indicates no tail, not an untyped tail. 104 | AstTypePack* tailType = nullptr; 105 | }; 106 | 107 | using AstArgumentName = std::pair; // TODO: remove and replace when we get a common struct for this pair instead of AstName 108 | 109 | struct AstGenericType 110 | { 111 | AstName name; 112 | Location location; 113 | AstType* defaultValue = nullptr; 114 | }; 115 | 116 | struct AstGenericTypePack 117 | { 118 | AstName name; 119 | Location location; 120 | AstTypePack* defaultValue = nullptr; 121 | }; 122 | 123 | extern int gAstRttiIndex; 124 | 125 | template 126 | struct AstRtti 127 | { 128 | static const int value; 129 | }; 130 | 131 | template 132 | const int AstRtti::value = ++gAstRttiIndex; 133 | 134 | #define LUAU_RTTI(Class) \ 135 | static int ClassIndex() \ 136 | { \ 137 | return AstRtti::value; \ 138 | } 139 | 140 | class AstNode 141 | { 142 | public: 143 | explicit AstNode(int classIndex, const Location& location) 144 | : classIndex(classIndex) 145 | , location(location) 146 | { 147 | } 148 | 149 | virtual void visit(AstVisitor* visitor) = 0; 150 | 151 | virtual AstExpr* asExpr() 152 | { 153 | return nullptr; 154 | } 155 | virtual AstStat* asStat() 156 | { 157 | return nullptr; 158 | } 159 | virtual AstType* asType() 160 | { 161 | return nullptr; 162 | } 163 | 164 | template 165 | bool is() const 166 | { 167 | return classIndex == T::ClassIndex(); 168 | } 169 | template 170 | T* as() 171 | { 172 | return classIndex == T::ClassIndex() ? static_cast(this) : nullptr; 173 | } 174 | template 175 | const T* as() const 176 | { 177 | return classIndex == T::ClassIndex() ? static_cast(this) : nullptr; 178 | } 179 | 180 | const int classIndex; 181 | Location location; 182 | }; 183 | 184 | class AstExpr : public AstNode 185 | { 186 | public: 187 | explicit AstExpr(int classIndex, const Location& location) 188 | : AstNode(classIndex, location) 189 | { 190 | } 191 | 192 | AstExpr* asExpr() override 193 | { 194 | return this; 195 | } 196 | }; 197 | 198 | class AstStat : public AstNode 199 | { 200 | public: 201 | explicit AstStat(int classIndex, const Location& location) 202 | : AstNode(classIndex, location) 203 | , hasSemicolon(false) 204 | { 205 | } 206 | 207 | AstStat* asStat() override 208 | { 209 | return this; 210 | } 211 | 212 | bool hasSemicolon; 213 | }; 214 | 215 | class AstExprGroup : public AstExpr 216 | { 217 | public: 218 | LUAU_RTTI(AstExprGroup) 219 | 220 | explicit AstExprGroup(const Location& location, AstExpr* expr); 221 | 222 | void visit(AstVisitor* visitor) override; 223 | 224 | AstExpr* expr; 225 | }; 226 | 227 | class AstExprConstantNil : public AstExpr 228 | { 229 | public: 230 | LUAU_RTTI(AstExprConstantNil) 231 | 232 | explicit AstExprConstantNil(const Location& location); 233 | 234 | void visit(AstVisitor* visitor) override; 235 | }; 236 | 237 | class AstExprConstantBool : public AstExpr 238 | { 239 | public: 240 | LUAU_RTTI(AstExprConstantBool) 241 | 242 | AstExprConstantBool(const Location& location, bool value); 243 | 244 | void visit(AstVisitor* visitor) override; 245 | 246 | bool value; 247 | }; 248 | 249 | enum class ConstantNumberParseResult 250 | { 251 | Ok, 252 | Malformed, 253 | BinOverflow, 254 | HexOverflow, 255 | }; 256 | 257 | class AstExprConstantNumber : public AstExpr 258 | { 259 | public: 260 | LUAU_RTTI(AstExprConstantNumber) 261 | 262 | AstExprConstantNumber(const Location& location, double value, ConstantNumberParseResult parseResult = ConstantNumberParseResult::Ok); 263 | 264 | void visit(AstVisitor* visitor) override; 265 | 266 | double value; 267 | ConstantNumberParseResult parseResult; 268 | }; 269 | 270 | class AstExprConstantString : public AstExpr 271 | { 272 | public: 273 | LUAU_RTTI(AstExprConstantString) 274 | 275 | enum QuoteStyle 276 | { 277 | Quoted, 278 | Unquoted 279 | }; 280 | 281 | AstExprConstantString(const Location& location, const AstArray& value, QuoteStyle quoteStyle = Quoted); 282 | 283 | void visit(AstVisitor* visitor) override; 284 | 285 | AstArray value; 286 | QuoteStyle quoteStyle = Quoted; 287 | }; 288 | 289 | class AstExprLocal : public AstExpr 290 | { 291 | public: 292 | LUAU_RTTI(AstExprLocal) 293 | 294 | AstExprLocal(const Location& location, AstLocal* local, bool upvalue); 295 | 296 | void visit(AstVisitor* visitor) override; 297 | 298 | AstLocal* local; 299 | bool upvalue; 300 | }; 301 | 302 | class AstExprGlobal : public AstExpr 303 | { 304 | public: 305 | LUAU_RTTI(AstExprGlobal) 306 | 307 | AstExprGlobal(const Location& location, const AstName& name); 308 | 309 | void visit(AstVisitor* visitor) override; 310 | 311 | AstName name; 312 | }; 313 | 314 | class AstExprVarargs : public AstExpr 315 | { 316 | public: 317 | LUAU_RTTI(AstExprVarargs) 318 | 319 | AstExprVarargs(const Location& location); 320 | 321 | void visit(AstVisitor* visitor) override; 322 | }; 323 | 324 | class AstExprCall : public AstExpr 325 | { 326 | public: 327 | LUAU_RTTI(AstExprCall) 328 | 329 | AstExprCall(const Location& location, AstExpr* func, const AstArray& args, bool self, const Location& argLocation); 330 | 331 | void visit(AstVisitor* visitor) override; 332 | 333 | AstExpr* func; 334 | AstArray args; 335 | bool self; 336 | Location argLocation; 337 | }; 338 | 339 | class AstExprIndexName : public AstExpr 340 | { 341 | public: 342 | LUAU_RTTI(AstExprIndexName) 343 | 344 | AstExprIndexName( 345 | const Location& location, AstExpr* expr, const AstName& index, const Location& indexLocation, const Position& opPosition, char op); 346 | 347 | void visit(AstVisitor* visitor) override; 348 | 349 | AstExpr* expr; 350 | AstName index; 351 | Location indexLocation; 352 | Position opPosition; 353 | char op = '.'; 354 | }; 355 | 356 | class AstExprIndexExpr : public AstExpr 357 | { 358 | public: 359 | LUAU_RTTI(AstExprIndexExpr) 360 | 361 | AstExprIndexExpr(const Location& location, AstExpr* expr, AstExpr* index); 362 | 363 | void visit(AstVisitor* visitor) override; 364 | 365 | AstExpr* expr; 366 | AstExpr* index; 367 | }; 368 | 369 | class AstExprFunction : public AstExpr 370 | { 371 | public: 372 | LUAU_RTTI(AstExprFunction) 373 | 374 | AstExprFunction(const Location& location, const AstArray& generics, const AstArray& genericPacks, 375 | AstLocal* self, const AstArray& args, bool vararg, const Location& varargLocation, AstStatBlock* body, size_t functionDepth, 376 | const AstName& debugname, const std::optional& returnAnnotation = {}, AstTypePack* varargAnnotation = nullptr, 377 | bool hasEnd = false, const std::optional& argLocation = std::nullopt); 378 | 379 | void visit(AstVisitor* visitor) override; 380 | 381 | AstArray generics; 382 | AstArray genericPacks; 383 | AstLocal* self; 384 | AstArray args; 385 | std::optional returnAnnotation; 386 | bool vararg = false; 387 | Location varargLocation; 388 | AstTypePack* varargAnnotation; 389 | 390 | AstStatBlock* body; 391 | 392 | size_t functionDepth; 393 | 394 | AstName debugname; 395 | 396 | bool hasEnd = false; 397 | std::optional argLocation; 398 | }; 399 | 400 | class AstExprTable : public AstExpr 401 | { 402 | public: 403 | LUAU_RTTI(AstExprTable) 404 | 405 | struct Item 406 | { 407 | enum Kind 408 | { 409 | List, // foo, in which case key is a nullptr 410 | Record, // foo=bar, in which case key is a AstExprConstantString 411 | General, // [foo]=bar 412 | }; 413 | 414 | Kind kind; 415 | 416 | AstExpr* key; // can be nullptr! 417 | AstExpr* value; 418 | }; 419 | 420 | AstExprTable(const Location& location, const AstArray& items); 421 | 422 | void visit(AstVisitor* visitor) override; 423 | 424 | AstArray items; 425 | }; 426 | 427 | class AstExprUnary : public AstExpr 428 | { 429 | public: 430 | LUAU_RTTI(AstExprUnary) 431 | 432 | enum Op 433 | { 434 | Not, 435 | Minus, 436 | Len 437 | }; 438 | 439 | AstExprUnary(const Location& location, Op op, AstExpr* expr); 440 | 441 | void visit(AstVisitor* visitor) override; 442 | 443 | Op op; 444 | AstExpr* expr; 445 | }; 446 | 447 | std::string toString(AstExprUnary::Op op); 448 | 449 | class AstExprBinary : public AstExpr 450 | { 451 | public: 452 | LUAU_RTTI(AstExprBinary) 453 | 454 | enum Op 455 | { 456 | Add, 457 | Sub, 458 | Mul, 459 | Div, 460 | FloorDiv, 461 | Mod, 462 | Pow, 463 | Concat, 464 | CompareNe, 465 | CompareEq, 466 | CompareLt, 467 | CompareLe, 468 | CompareGt, 469 | CompareGe, 470 | And, 471 | Or, 472 | 473 | Op__Count 474 | }; 475 | 476 | AstExprBinary(const Location& location, Op op, AstExpr* left, AstExpr* right); 477 | 478 | void visit(AstVisitor* visitor) override; 479 | 480 | Op op; 481 | AstExpr* left; 482 | AstExpr* right; 483 | }; 484 | 485 | std::string toString(AstExprBinary::Op op); 486 | 487 | class AstExprTypeAssertion : public AstExpr 488 | { 489 | public: 490 | LUAU_RTTI(AstExprTypeAssertion) 491 | 492 | AstExprTypeAssertion(const Location& location, AstExpr* expr, AstType* annotation); 493 | 494 | void visit(AstVisitor* visitor) override; 495 | 496 | AstExpr* expr; 497 | AstType* annotation; 498 | }; 499 | 500 | class AstExprIfElse : public AstExpr 501 | { 502 | public: 503 | LUAU_RTTI(AstExprIfElse) 504 | 505 | AstExprIfElse(const Location& location, AstExpr* condition, bool hasThen, AstExpr* trueExpr, bool hasElse, AstExpr* falseExpr); 506 | 507 | void visit(AstVisitor* visitor) override; 508 | 509 | AstExpr* condition; 510 | bool hasThen; 511 | AstExpr* trueExpr; 512 | bool hasElse; 513 | AstExpr* falseExpr; 514 | }; 515 | 516 | class AstExprInterpString : public AstExpr 517 | { 518 | public: 519 | LUAU_RTTI(AstExprInterpString) 520 | 521 | AstExprInterpString(const Location& location, const AstArray>& strings, const AstArray& expressions); 522 | 523 | void visit(AstVisitor* visitor) override; 524 | 525 | /// An interpolated string such as `foo{bar}baz` is represented as 526 | /// an array of strings for "foo" and "bar", and an array of expressions for "baz". 527 | /// `strings` will always have one more element than `expressions`. 528 | AstArray> strings; 529 | AstArray expressions; 530 | }; 531 | 532 | class AstStatBlock : public AstStat 533 | { 534 | public: 535 | LUAU_RTTI(AstStatBlock) 536 | 537 | AstStatBlock(const Location& location, const AstArray& body, bool hasEnd=true); 538 | 539 | void visit(AstVisitor* visitor) override; 540 | 541 | AstArray body; 542 | bool hasEnd = false; 543 | }; 544 | 545 | class AstStatIf : public AstStat 546 | { 547 | public: 548 | LUAU_RTTI(AstStatIf) 549 | 550 | AstStatIf(const Location& location, AstExpr* condition, AstStatBlock* thenbody, AstStat* elsebody, const std::optional& thenLocation, 551 | const std::optional& elseLocation, bool hasEnd); 552 | 553 | void visit(AstVisitor* visitor) override; 554 | 555 | AstExpr* condition; 556 | AstStatBlock* thenbody; 557 | AstStat* elsebody; 558 | 559 | std::optional thenLocation; 560 | 561 | // Active for 'elseif' as well 562 | std::optional elseLocation; 563 | 564 | bool hasEnd = false; 565 | }; 566 | 567 | class AstStatWhile : public AstStat 568 | { 569 | public: 570 | LUAU_RTTI(AstStatWhile) 571 | 572 | AstStatWhile(const Location& location, AstExpr* condition, AstStatBlock* body, bool hasDo, const Location& doLocation, bool hasEnd); 573 | 574 | void visit(AstVisitor* visitor) override; 575 | 576 | AstExpr* condition; 577 | AstStatBlock* body; 578 | 579 | bool hasDo = false; 580 | Location doLocation; 581 | 582 | bool hasEnd = false; 583 | }; 584 | 585 | class AstStatRepeat : public AstStat 586 | { 587 | public: 588 | LUAU_RTTI(AstStatRepeat) 589 | 590 | AstStatRepeat(const Location& location, AstExpr* condition, AstStatBlock* body, bool hasUntil); 591 | 592 | void visit(AstVisitor* visitor) override; 593 | 594 | AstExpr* condition; 595 | AstStatBlock* body; 596 | 597 | bool hasUntil = false; 598 | }; 599 | 600 | class AstStatBreak : public AstStat 601 | { 602 | public: 603 | LUAU_RTTI(AstStatBreak) 604 | 605 | AstStatBreak(const Location& location); 606 | 607 | void visit(AstVisitor* visitor) override; 608 | }; 609 | 610 | class AstStatContinue : public AstStat 611 | { 612 | public: 613 | LUAU_RTTI(AstStatContinue) 614 | 615 | AstStatContinue(const Location& location); 616 | 617 | void visit(AstVisitor* visitor) override; 618 | }; 619 | 620 | class AstStatReturn : public AstStat 621 | { 622 | public: 623 | LUAU_RTTI(AstStatReturn) 624 | 625 | AstStatReturn(const Location& location, const AstArray& list); 626 | 627 | void visit(AstVisitor* visitor) override; 628 | 629 | AstArray list; 630 | }; 631 | 632 | class AstStatExpr : public AstStat 633 | { 634 | public: 635 | LUAU_RTTI(AstStatExpr) 636 | 637 | AstStatExpr(const Location& location, AstExpr* expr); 638 | 639 | void visit(AstVisitor* visitor) override; 640 | 641 | AstExpr* expr; 642 | }; 643 | 644 | class AstStatLocal : public AstStat 645 | { 646 | public: 647 | LUAU_RTTI(AstStatLocal) 648 | 649 | AstStatLocal(const Location& location, const AstArray& vars, const AstArray& values, 650 | const std::optional& equalsSignLocation); 651 | 652 | void visit(AstVisitor* visitor) override; 653 | 654 | AstArray vars; 655 | AstArray values; 656 | 657 | std::optional equalsSignLocation; 658 | }; 659 | 660 | class AstStatFor : public AstStat 661 | { 662 | public: 663 | LUAU_RTTI(AstStatFor) 664 | 665 | AstStatFor(const Location& location, AstLocal* var, AstExpr* from, AstExpr* to, AstExpr* step, AstStatBlock* body, bool hasDo, 666 | const Location& doLocation, bool hasEnd); 667 | 668 | void visit(AstVisitor* visitor) override; 669 | 670 | AstLocal* var; 671 | AstExpr* from; 672 | AstExpr* to; 673 | AstExpr* step; 674 | AstStatBlock* body; 675 | 676 | bool hasDo = false; 677 | Location doLocation; 678 | 679 | bool hasEnd = false; 680 | }; 681 | 682 | class AstStatForIn : public AstStat 683 | { 684 | public: 685 | LUAU_RTTI(AstStatForIn) 686 | 687 | AstStatForIn(const Location& location, const AstArray& vars, const AstArray& values, AstStatBlock* body, bool hasIn, 688 | const Location& inLocation, bool hasDo, const Location& doLocation, bool hasEnd); 689 | 690 | void visit(AstVisitor* visitor) override; 691 | 692 | AstArray vars; 693 | AstArray values; 694 | AstStatBlock* body; 695 | 696 | bool hasIn = false; 697 | Location inLocation; 698 | 699 | bool hasDo = false; 700 | Location doLocation; 701 | 702 | bool hasEnd = false; 703 | }; 704 | 705 | class AstStatAssign : public AstStat 706 | { 707 | public: 708 | LUAU_RTTI(AstStatAssign) 709 | 710 | AstStatAssign(const Location& location, const AstArray& vars, const AstArray& values); 711 | 712 | void visit(AstVisitor* visitor) override; 713 | 714 | AstArray vars; 715 | AstArray values; 716 | }; 717 | 718 | class AstStatCompoundAssign : public AstStat 719 | { 720 | public: 721 | LUAU_RTTI(AstStatCompoundAssign) 722 | 723 | AstStatCompoundAssign(const Location& location, AstExprBinary::Op op, AstExpr* var, AstExpr* value); 724 | 725 | void visit(AstVisitor* visitor) override; 726 | 727 | AstExprBinary::Op op; 728 | AstExpr* var; 729 | AstExpr* value; 730 | }; 731 | 732 | class AstStatFunction : public AstStat 733 | { 734 | public: 735 | LUAU_RTTI(AstStatFunction) 736 | 737 | AstStatFunction(const Location& location, AstExpr* name, AstExprFunction* func); 738 | 739 | void visit(AstVisitor* visitor) override; 740 | 741 | AstExpr* name; 742 | AstExprFunction* func; 743 | }; 744 | 745 | class AstStatLocalFunction : public AstStat 746 | { 747 | public: 748 | LUAU_RTTI(AstStatLocalFunction) 749 | 750 | AstStatLocalFunction(const Location& location, AstLocal* name, AstExprFunction* func); 751 | 752 | void visit(AstVisitor* visitor) override; 753 | 754 | AstLocal* name; 755 | AstExprFunction* func; 756 | }; 757 | 758 | class AstStatTypeAlias : public AstStat 759 | { 760 | public: 761 | LUAU_RTTI(AstStatTypeAlias) 762 | 763 | AstStatTypeAlias(const Location& location, const AstName& name, const Location& nameLocation, const AstArray& generics, 764 | const AstArray& genericPacks, AstType* type, bool exported); 765 | 766 | void visit(AstVisitor* visitor) override; 767 | 768 | AstName name; 769 | Location nameLocation; 770 | AstArray generics; 771 | AstArray genericPacks; 772 | AstType* type; 773 | bool exported; 774 | }; 775 | 776 | class AstStatDeclareGlobal : public AstStat 777 | { 778 | public: 779 | LUAU_RTTI(AstStatDeclareGlobal) 780 | 781 | AstStatDeclareGlobal(const Location& location, const AstName& name, AstType* type); 782 | 783 | void visit(AstVisitor* visitor) override; 784 | 785 | AstName name; 786 | AstType* type; 787 | }; 788 | 789 | class AstStatDeclareFunction : public AstStat 790 | { 791 | public: 792 | LUAU_RTTI(AstStatDeclareFunction) 793 | 794 | AstStatDeclareFunction(const Location& location, const AstName& name, const AstArray& generics, 795 | const AstArray& genericPacks, const AstTypeList& params, const AstArray& paramNames, 796 | const AstTypeList& retTypes); 797 | 798 | void visit(AstVisitor* visitor) override; 799 | 800 | AstName name; 801 | AstArray generics; 802 | AstArray genericPacks; 803 | AstTypeList params; 804 | AstArray paramNames; 805 | AstTypeList retTypes; 806 | }; 807 | 808 | struct AstDeclaredClassProp 809 | { 810 | AstName name; 811 | AstType* ty = nullptr; 812 | bool isMethod = false; 813 | }; 814 | 815 | struct AstTableIndexer 816 | { 817 | AstType* indexType; 818 | AstType* resultType; 819 | Location location; 820 | }; 821 | 822 | class AstStatDeclareClass : public AstStat 823 | { 824 | public: 825 | LUAU_RTTI(AstStatDeclareClass) 826 | 827 | AstStatDeclareClass(const Location& location, const AstName& name, std::optional superName, const AstArray& props, 828 | AstTableIndexer* indexer = nullptr); 829 | 830 | void visit(AstVisitor* visitor) override; 831 | 832 | AstName name; 833 | std::optional superName; 834 | 835 | AstArray props; 836 | AstTableIndexer* indexer; 837 | }; 838 | 839 | class AstType : public AstNode 840 | { 841 | public: 842 | AstType(int classIndex, const Location& location) 843 | : AstNode(classIndex, location) 844 | { 845 | } 846 | 847 | AstType* asType() override 848 | { 849 | return this; 850 | } 851 | }; 852 | 853 | // Don't have Luau::Variant available, it's a bit of an overhead, but a plain struct is nice to use 854 | struct AstTypeOrPack 855 | { 856 | AstType* type = nullptr; 857 | AstTypePack* typePack = nullptr; 858 | }; 859 | 860 | class AstTypeReference : public AstType 861 | { 862 | public: 863 | LUAU_RTTI(AstTypeReference) 864 | 865 | AstTypeReference(const Location& location, std::optional prefix, AstName name, std::optional prefixLocation, 866 | const Location& nameLocation, bool hasParameterList = false, const AstArray& parameters = {}); 867 | 868 | void visit(AstVisitor* visitor) override; 869 | 870 | bool hasParameterList; 871 | std::optional prefix; 872 | std::optional prefixLocation; 873 | AstName name; 874 | Location nameLocation; 875 | AstArray parameters; 876 | }; 877 | 878 | struct AstTableProp 879 | { 880 | AstName name; 881 | Location location; 882 | AstType* type; 883 | }; 884 | 885 | class AstTypeTable : public AstType 886 | { 887 | public: 888 | LUAU_RTTI(AstTypeTable) 889 | 890 | AstTypeTable(const Location& location, const AstArray& props, AstTableIndexer* indexer = nullptr); 891 | 892 | void visit(AstVisitor* visitor) override; 893 | 894 | AstArray props; 895 | AstTableIndexer* indexer; 896 | }; 897 | 898 | class AstTypeFunction : public AstType 899 | { 900 | public: 901 | LUAU_RTTI(AstTypeFunction) 902 | 903 | AstTypeFunction(const Location& location, const AstArray& generics, const AstArray& genericPacks, 904 | const AstTypeList& argTypes, const AstArray>& argNames, const AstTypeList& returnTypes); 905 | 906 | void visit(AstVisitor* visitor) override; 907 | 908 | AstArray generics; 909 | AstArray genericPacks; 910 | AstTypeList argTypes; 911 | AstArray> argNames; 912 | AstTypeList returnTypes; 913 | }; 914 | 915 | class AstTypeTypeof : public AstType 916 | { 917 | public: 918 | LUAU_RTTI(AstTypeTypeof) 919 | 920 | AstTypeTypeof(const Location& location, AstExpr* expr); 921 | 922 | void visit(AstVisitor* visitor) override; 923 | 924 | AstExpr* expr; 925 | }; 926 | 927 | class AstTypeUnion : public AstType 928 | { 929 | public: 930 | LUAU_RTTI(AstTypeUnion) 931 | 932 | AstTypeUnion(const Location& location, const AstArray& types); 933 | 934 | void visit(AstVisitor* visitor) override; 935 | 936 | AstArray types; 937 | }; 938 | 939 | class AstTypeIntersection : public AstType 940 | { 941 | public: 942 | LUAU_RTTI(AstTypeIntersection) 943 | 944 | AstTypeIntersection(const Location& location, const AstArray& types); 945 | 946 | void visit(AstVisitor* visitor) override; 947 | 948 | AstArray types; 949 | }; 950 | 951 | class AstExprError : public AstExpr 952 | { 953 | public: 954 | LUAU_RTTI(AstExprError) 955 | 956 | AstExprError(const Location& location, const AstArray& expressions, unsigned messageIndex); 957 | 958 | void visit(AstVisitor* visitor) override; 959 | 960 | AstArray expressions; 961 | unsigned messageIndex; 962 | }; 963 | 964 | class AstStatError : public AstStat 965 | { 966 | public: 967 | LUAU_RTTI(AstStatError) 968 | 969 | AstStatError(const Location& location, const AstArray& expressions, const AstArray& statements, unsigned messageIndex); 970 | 971 | void visit(AstVisitor* visitor) override; 972 | 973 | AstArray expressions; 974 | AstArray statements; 975 | unsigned messageIndex; 976 | }; 977 | 978 | class AstTypeError : public AstType 979 | { 980 | public: 981 | LUAU_RTTI(AstTypeError) 982 | 983 | AstTypeError(const Location& location, const AstArray& types, bool isMissing, unsigned messageIndex); 984 | 985 | void visit(AstVisitor* visitor) override; 986 | 987 | AstArray types; 988 | bool isMissing; 989 | unsigned messageIndex; 990 | }; 991 | 992 | class AstTypeSingletonBool : public AstType 993 | { 994 | public: 995 | LUAU_RTTI(AstTypeSingletonBool) 996 | 997 | AstTypeSingletonBool(const Location& location, bool value); 998 | 999 | void visit(AstVisitor* visitor) override; 1000 | 1001 | bool value; 1002 | }; 1003 | 1004 | class AstTypeSingletonString : public AstType 1005 | { 1006 | public: 1007 | LUAU_RTTI(AstTypeSingletonString) 1008 | 1009 | AstTypeSingletonString(const Location& location, const AstArray& value); 1010 | 1011 | void visit(AstVisitor* visitor) override; 1012 | 1013 | const AstArray value; 1014 | }; 1015 | 1016 | class AstTypePack : public AstNode 1017 | { 1018 | public: 1019 | AstTypePack(int classIndex, const Location& location) 1020 | : AstNode(classIndex, location) 1021 | { 1022 | } 1023 | }; 1024 | 1025 | class AstTypePackExplicit : public AstTypePack 1026 | { 1027 | public: 1028 | LUAU_RTTI(AstTypePackExplicit) 1029 | 1030 | AstTypePackExplicit(const Location& location, AstTypeList typeList); 1031 | 1032 | void visit(AstVisitor* visitor) override; 1033 | 1034 | AstTypeList typeList; 1035 | }; 1036 | 1037 | class AstTypePackVariadic : public AstTypePack 1038 | { 1039 | public: 1040 | LUAU_RTTI(AstTypePackVariadic) 1041 | 1042 | AstTypePackVariadic(const Location& location, AstType* variadicType); 1043 | 1044 | void visit(AstVisitor* visitor) override; 1045 | 1046 | AstType* variadicType; 1047 | }; 1048 | 1049 | class AstTypePackGeneric : public AstTypePack 1050 | { 1051 | public: 1052 | LUAU_RTTI(AstTypePackGeneric) 1053 | 1054 | AstTypePackGeneric(const Location& location, AstName name); 1055 | 1056 | void visit(AstVisitor* visitor) override; 1057 | 1058 | AstName genericName; 1059 | }; 1060 | 1061 | class AstVisitor 1062 | { 1063 | public: 1064 | virtual ~AstVisitor() {} 1065 | 1066 | virtual bool visit(class AstNode*) 1067 | { 1068 | return true; 1069 | } 1070 | 1071 | virtual bool visit(class AstExpr* node) 1072 | { 1073 | return visit(static_cast(node)); 1074 | } 1075 | 1076 | virtual bool visit(class AstExprGroup* node) 1077 | { 1078 | return visit(static_cast(node)); 1079 | } 1080 | virtual bool visit(class AstExprConstantNil* node) 1081 | { 1082 | return visit(static_cast(node)); 1083 | } 1084 | virtual bool visit(class AstExprConstantBool* node) 1085 | { 1086 | return visit(static_cast(node)); 1087 | } 1088 | virtual bool visit(class AstExprConstantNumber* node) 1089 | { 1090 | return visit(static_cast(node)); 1091 | } 1092 | virtual bool visit(class AstExprConstantString* node) 1093 | { 1094 | return visit(static_cast(node)); 1095 | } 1096 | virtual bool visit(class AstExprLocal* node) 1097 | { 1098 | return visit(static_cast(node)); 1099 | } 1100 | virtual bool visit(class AstExprGlobal* node) 1101 | { 1102 | return visit(static_cast(node)); 1103 | } 1104 | virtual bool visit(class AstExprVarargs* node) 1105 | { 1106 | return visit(static_cast(node)); 1107 | } 1108 | virtual bool visit(class AstExprCall* node) 1109 | { 1110 | return visit(static_cast(node)); 1111 | } 1112 | virtual bool visit(class AstExprIndexName* node) 1113 | { 1114 | return visit(static_cast(node)); 1115 | } 1116 | virtual bool visit(class AstExprIndexExpr* node) 1117 | { 1118 | return visit(static_cast(node)); 1119 | } 1120 | virtual bool visit(class AstExprFunction* node) 1121 | { 1122 | return visit(static_cast(node)); 1123 | } 1124 | virtual bool visit(class AstExprTable* node) 1125 | { 1126 | return visit(static_cast(node)); 1127 | } 1128 | virtual bool visit(class AstExprUnary* node) 1129 | { 1130 | return visit(static_cast(node)); 1131 | } 1132 | virtual bool visit(class AstExprBinary* node) 1133 | { 1134 | return visit(static_cast(node)); 1135 | } 1136 | virtual bool visit(class AstExprTypeAssertion* node) 1137 | { 1138 | return visit(static_cast(node)); 1139 | } 1140 | virtual bool visit(class AstExprIfElse* node) 1141 | { 1142 | return visit(static_cast(node)); 1143 | } 1144 | virtual bool visit(class AstExprInterpString* node) 1145 | { 1146 | return visit(static_cast(node)); 1147 | } 1148 | virtual bool visit(class AstExprError* node) 1149 | { 1150 | return visit(static_cast(node)); 1151 | } 1152 | 1153 | virtual bool visit(class AstStat* node) 1154 | { 1155 | return visit(static_cast(node)); 1156 | } 1157 | 1158 | virtual bool visit(class AstStatBlock* node) 1159 | { 1160 | return visit(static_cast(node)); 1161 | } 1162 | virtual bool visit(class AstStatIf* node) 1163 | { 1164 | return visit(static_cast(node)); 1165 | } 1166 | virtual bool visit(class AstStatWhile* node) 1167 | { 1168 | return visit(static_cast(node)); 1169 | } 1170 | virtual bool visit(class AstStatRepeat* node) 1171 | { 1172 | return visit(static_cast(node)); 1173 | } 1174 | virtual bool visit(class AstStatBreak* node) 1175 | { 1176 | return visit(static_cast(node)); 1177 | } 1178 | virtual bool visit(class AstStatContinue* node) 1179 | { 1180 | return visit(static_cast(node)); 1181 | } 1182 | virtual bool visit(class AstStatReturn* node) 1183 | { 1184 | return visit(static_cast(node)); 1185 | } 1186 | virtual bool visit(class AstStatExpr* node) 1187 | { 1188 | return visit(static_cast(node)); 1189 | } 1190 | virtual bool visit(class AstStatLocal* node) 1191 | { 1192 | return visit(static_cast(node)); 1193 | } 1194 | virtual bool visit(class AstStatFor* node) 1195 | { 1196 | return visit(static_cast(node)); 1197 | } 1198 | virtual bool visit(class AstStatForIn* node) 1199 | { 1200 | return visit(static_cast(node)); 1201 | } 1202 | virtual bool visit(class AstStatAssign* node) 1203 | { 1204 | return visit(static_cast(node)); 1205 | } 1206 | virtual bool visit(class AstStatCompoundAssign* node) 1207 | { 1208 | return visit(static_cast(node)); 1209 | } 1210 | virtual bool visit(class AstStatFunction* node) 1211 | { 1212 | return visit(static_cast(node)); 1213 | } 1214 | virtual bool visit(class AstStatLocalFunction* node) 1215 | { 1216 | return visit(static_cast(node)); 1217 | } 1218 | virtual bool visit(class AstStatTypeAlias* node) 1219 | { 1220 | return visit(static_cast(node)); 1221 | } 1222 | virtual bool visit(class AstStatDeclareFunction* node) 1223 | { 1224 | return visit(static_cast(node)); 1225 | } 1226 | virtual bool visit(class AstStatDeclareGlobal* node) 1227 | { 1228 | return visit(static_cast(node)); 1229 | } 1230 | virtual bool visit(class AstStatDeclareClass* node) 1231 | { 1232 | return visit(static_cast(node)); 1233 | } 1234 | virtual bool visit(class AstStatError* node) 1235 | { 1236 | return visit(static_cast(node)); 1237 | } 1238 | 1239 | // By default visiting type annotations is disabled; override this in your visitor if you need to! 1240 | virtual bool visit(class AstType* node) 1241 | { 1242 | return false; 1243 | } 1244 | 1245 | virtual bool visit(class AstTypeReference* node) 1246 | { 1247 | return visit(static_cast(node)); 1248 | } 1249 | virtual bool visit(class AstTypeTable* node) 1250 | { 1251 | return visit(static_cast(node)); 1252 | } 1253 | virtual bool visit(class AstTypeFunction* node) 1254 | { 1255 | return visit(static_cast(node)); 1256 | } 1257 | virtual bool visit(class AstTypeTypeof* node) 1258 | { 1259 | return visit(static_cast(node)); 1260 | } 1261 | virtual bool visit(class AstTypeUnion* node) 1262 | { 1263 | return visit(static_cast(node)); 1264 | } 1265 | virtual bool visit(class AstTypeIntersection* node) 1266 | { 1267 | return visit(static_cast(node)); 1268 | } 1269 | virtual bool visit(class AstTypeSingletonBool* node) 1270 | { 1271 | return visit(static_cast(node)); 1272 | } 1273 | virtual bool visit(class AstTypeSingletonString* node) 1274 | { 1275 | return visit(static_cast(node)); 1276 | } 1277 | virtual bool visit(class AstTypeError* node) 1278 | { 1279 | return visit(static_cast(node)); 1280 | } 1281 | 1282 | virtual bool visit(class AstTypePack* node) 1283 | { 1284 | return false; 1285 | } 1286 | virtual bool visit(class AstTypePackExplicit* node) 1287 | { 1288 | return visit(static_cast(node)); 1289 | } 1290 | virtual bool visit(class AstTypePackVariadic* node) 1291 | { 1292 | return visit(static_cast(node)); 1293 | } 1294 | virtual bool visit(class AstTypePackGeneric* node) 1295 | { 1296 | return visit(static_cast(node)); 1297 | } 1298 | }; 1299 | 1300 | AstName getIdentifier(AstExpr*); 1301 | Location getLocation(const AstTypeList& typeList); 1302 | 1303 | template // AstNode, AstExpr, AstLocal, etc 1304 | Location getLocation(AstArray array) 1305 | { 1306 | if (0 == array.size) 1307 | return {}; 1308 | 1309 | return Location{array.data[0]->location.begin, array.data[array.size - 1]->location.end}; 1310 | } 1311 | 1312 | #undef LUAU_RTTI 1313 | 1314 | } // namespace Luau 1315 | 1316 | namespace std 1317 | { 1318 | 1319 | template<> 1320 | struct hash 1321 | { 1322 | size_t operator()(const Luau::AstName& value) const 1323 | { 1324 | // note: since operator== uses pointer identity, hashing function uses it as well 1325 | // the hasher is the same as DenseHashPointer (DenseHash.h) 1326 | return (uintptr_t(value.value) >> 4) ^ (uintptr_t(value.value) >> 9); 1327 | } 1328 | }; 1329 | 1330 | } // namespace std 1331 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/Bytecode.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | // clang-format off 5 | 6 | // This header contains the bytecode definition for Luau interpreter 7 | // Creating the bytecode is outside the scope of this file and is handled by bytecode builder (BytecodeBuilder.h) and bytecode compiler (Compiler.h) 8 | // Note that ALL enums declared in this file are order-sensitive since the values are baked into bytecode that needs to be processed by legacy clients. 9 | 10 | // # Bytecode definitions 11 | // Bytecode instructions are using "word code" - each instruction is one or many 32-bit words. 12 | // The first word in the instruction is always the instruction header, and *must* contain the opcode (enum below) in the least significant byte. 13 | // 14 | // Instruction word can be encoded using one of the following encodings: 15 | // ABC - least-significant byte for the opcode, followed by three bytes, A, B and C; each byte declares a register index, small index into some other table or an unsigned integral value 16 | // AD - least-significant byte for the opcode, followed by A byte, followed by D half-word (16-bit integer). D is a signed integer that commonly specifies constant table index or jump offset 17 | // E - least-significant byte for the opcode, followed by E (24-bit integer). E is a signed integer that commonly specifies a jump offset 18 | // 19 | // Instruction word is sometimes followed by one extra word, indicated as AUX - this is just a 32-bit word and is decoded according to the specification for each opcode. 20 | // For each opcode the encoding is *static* - that is, based on the opcode you know a-priory how large the instruction is, with the exception of NEWCLOSURE 21 | 22 | // # Bytecode indices 23 | // Bytecode instructions commonly refer to integer values that define offsets or indices for various entities. For each type, there's a maximum encodable value. 24 | // Note that in some cases, the compiler will set a lower limit than the maximum encodable value is to prevent fragile code into bumping against the limits whenever we change the compilation details. 25 | // Additionally, in some specific instructions such as ANDK, the limit on the encoded value is smaller; this means that if a value is larger, a different instruction must be selected. 26 | // 27 | // Registers: 0-254. Registers refer to the values on the function's stack frame, including arguments. 28 | // Upvalues: 0-199. Upvalues refer to the values stored in the closure object. 29 | // Constants: 0-2^23-1. Constants are stored in a table allocated with each proto; to allow for future bytecode tweaks the encodable value is limited to 23 bits. 30 | // Closures: 0-2^15-1. Closures are created from child protos via a child index; the limit is for the number of closures immediately referenced in each function. 31 | // Jumps: -2^23..2^23. Jump offsets are specified in word increments, so jumping over an instruction may sometimes require an offset of 2 or more. Note that for jump instructions with AUX, the AUX word is included as part of the jump offset. 32 | 33 | // # Bytecode versions 34 | // Bytecode serialized format embeds a version number, that dictates both the serialized form as well as the allowed instructions. As long as the bytecode version falls into supported 35 | // range (indicated by LBC_BYTECODE_MIN / LBC_BYTECODE_MAX) and was produced by Luau compiler, it should load and execute correctly. 36 | // 37 | // Note that Luau runtime doesn't provide indefinite bytecode compatibility: support for older versions gets removed over time. As such, bytecode isn't a durable storage format and it's expected 38 | // that Luau users can recompile bytecode from source on Luau version upgrades if necessary. 39 | 40 | // # Bytecode version history 41 | // 42 | // Note: due to limitations of the versioning scheme, some bytecode blobs that carry version 2 are using features from version 3. Starting from version 3, version should be sufficient to indicate bytecode compatibility. 43 | // 44 | // Version 1: Baseline version for the open-source release. Supported until 0.521. 45 | // Version 2: Adds Proto::linedefined. Supported until 0.544. 46 | // Version 3: Adds FORGPREP/JUMPXEQK* and enhances AUX encoding for FORGLOOP. Removes FORGLOOP_NEXT/INEXT and JUMPIFEQK/JUMPIFNOTEQK. Currently supported. 47 | // Version 4: Adds Proto::flags, typeinfo, and floor division opcodes IDIV/IDIVK. Currently supported. 48 | 49 | // Bytecode opcode, part of the instruction header 50 | enum LuauOpcode 51 | { 52 | // NOP: noop 53 | LOP_NOP, 54 | 55 | // BREAK: debugger break 56 | LOP_BREAK, 57 | 58 | // LOADNIL: sets register to nil 59 | // A: target register 60 | LOP_LOADNIL, 61 | 62 | // LOADB: sets register to boolean and jumps to a given short offset (used to compile comparison results into a boolean) 63 | // A: target register 64 | // B: value (0/1) 65 | // C: jump offset 66 | LOP_LOADB, 67 | 68 | // LOADN: sets register to a number literal 69 | // A: target register 70 | // D: value (-32768..32767) 71 | LOP_LOADN, 72 | 73 | // LOADK: sets register to an entry from the constant table from the proto (number/string) 74 | // A: target register 75 | // D: constant table index (0..32767) 76 | LOP_LOADK, 77 | 78 | // MOVE: move (copy) value from one register to another 79 | // A: target register 80 | // B: source register 81 | LOP_MOVE, 82 | 83 | // GETGLOBAL: load value from global table using constant string as a key 84 | // A: target register 85 | // C: predicted slot index (based on hash) 86 | // AUX: constant table index 87 | LOP_GETGLOBAL, 88 | 89 | // SETGLOBAL: set value in global table using constant string as a key 90 | // A: source register 91 | // C: predicted slot index (based on hash) 92 | // AUX: constant table index 93 | LOP_SETGLOBAL, 94 | 95 | // GETUPVAL: load upvalue from the upvalue table for the current function 96 | // A: target register 97 | // B: upvalue index 98 | LOP_GETUPVAL, 99 | 100 | // SETUPVAL: store value into the upvalue table for the current function 101 | // A: target register 102 | // B: upvalue index 103 | LOP_SETUPVAL, 104 | 105 | // CLOSEUPVALS: close (migrate to heap) all upvalues that were captured for registers >= target 106 | // A: target register 107 | LOP_CLOSEUPVALS, 108 | 109 | // GETIMPORT: load imported global table global from the constant table 110 | // A: target register 111 | // D: constant table index (0..32767); we assume that imports are loaded into the constant table 112 | // AUX: 3 10-bit indices of constant strings that, combined, constitute an import path; length of the path is set by the top 2 bits (1,2,3) 113 | LOP_GETIMPORT, 114 | 115 | // GETTABLE: load value from table into target register using key from register 116 | // A: target register 117 | // B: table register 118 | // C: index register 119 | LOP_GETTABLE, 120 | 121 | // SETTABLE: store source register into table using key from register 122 | // A: source register 123 | // B: table register 124 | // C: index register 125 | LOP_SETTABLE, 126 | 127 | // GETTABLEKS: load value from table into target register using constant string as a key 128 | // A: target register 129 | // B: table register 130 | // C: predicted slot index (based on hash) 131 | // AUX: constant table index 132 | LOP_GETTABLEKS, 133 | 134 | // SETTABLEKS: store source register into table using constant string as a key 135 | // A: source register 136 | // B: table register 137 | // C: predicted slot index (based on hash) 138 | // AUX: constant table index 139 | LOP_SETTABLEKS, 140 | 141 | // GETTABLEN: load value from table into target register using small integer index as a key 142 | // A: target register 143 | // B: table register 144 | // C: index-1 (index is 1..256) 145 | LOP_GETTABLEN, 146 | 147 | // SETTABLEN: store source register into table using small integer index as a key 148 | // A: source register 149 | // B: table register 150 | // C: index-1 (index is 1..256) 151 | LOP_SETTABLEN, 152 | 153 | // NEWCLOSURE: create closure from a child proto; followed by a CAPTURE instruction for each upvalue 154 | // A: target register 155 | // D: child proto index (0..32767) 156 | LOP_NEWCLOSURE, 157 | 158 | // NAMECALL: prepare to call specified method by name by loading function from source register using constant index into target register and copying source register into target register + 1 159 | // A: target register 160 | // B: source register 161 | // C: predicted slot index (based on hash) 162 | // AUX: constant table index 163 | // Note that this instruction must be followed directly by CALL; it prepares the arguments 164 | // This instruction is roughly equivalent to GETTABLEKS + MOVE pair, but we need a special instruction to support custom __namecall metamethod 165 | LOP_NAMECALL, 166 | 167 | // CALL: call specified function 168 | // A: register where the function object lives, followed by arguments; results are placed starting from the same register 169 | // B: argument count + 1, or 0 to preserve all arguments up to top (MULTRET) 170 | // C: result count + 1, or 0 to preserve all values and adjust top (MULTRET) 171 | LOP_CALL, 172 | 173 | // RETURN: returns specified values from the function 174 | // A: register where the returned values start 175 | // B: number of returned values + 1, or 0 to return all values up to top (MULTRET) 176 | LOP_RETURN, 177 | 178 | // JUMP: jumps to target offset 179 | // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") 180 | LOP_JUMP, 181 | 182 | // JUMPBACK: jumps to target offset; this is equivalent to JUMP but is used as a safepoint to be able to interrupt while/repeat loops 183 | // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") 184 | LOP_JUMPBACK, 185 | 186 | // JUMPIF: jumps to target offset if register is not nil/false 187 | // A: source register 188 | // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") 189 | LOP_JUMPIF, 190 | 191 | // JUMPIFNOT: jumps to target offset if register is nil/false 192 | // A: source register 193 | // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") 194 | LOP_JUMPIFNOT, 195 | 196 | // JUMPIFEQ, JUMPIFLE, JUMPIFLT, JUMPIFNOTEQ, JUMPIFNOTLE, JUMPIFNOTLT: jumps to target offset if the comparison is true (or false, for NOT variants) 197 | // A: source register 1 198 | // D: jump offset (-32768..32767; 1 means "next instruction" aka "don't jump") 199 | // AUX: source register 2 200 | LOP_JUMPIFEQ, 201 | LOP_JUMPIFLE, 202 | LOP_JUMPIFLT, 203 | LOP_JUMPIFNOTEQ, 204 | LOP_JUMPIFNOTLE, 205 | LOP_JUMPIFNOTLT, 206 | 207 | // ADD, SUB, MUL, DIV, MOD, POW: compute arithmetic operation between two source registers and put the result into target register 208 | // A: target register 209 | // B: source register 1 210 | // C: source register 2 211 | LOP_ADD, 212 | LOP_SUB, 213 | LOP_MUL, 214 | LOP_DIV, 215 | LOP_MOD, 216 | LOP_POW, 217 | 218 | // ADDK, SUBK, MULK, DIVK, MODK, POWK: compute arithmetic operation between the source register and a constant and put the result into target register 219 | // A: target register 220 | // B: source register 221 | // C: constant table index (0..255) 222 | LOP_ADDK, 223 | LOP_SUBK, 224 | LOP_MULK, 225 | LOP_DIVK, 226 | LOP_MODK, 227 | LOP_POWK, 228 | 229 | // AND, OR: perform `and` or `or` operation (selecting first or second register based on whether the first one is truthy) and put the result into target register 230 | // A: target register 231 | // B: source register 1 232 | // C: source register 2 233 | LOP_AND, 234 | LOP_OR, 235 | 236 | // ANDK, ORK: perform `and` or `or` operation (selecting source register or constant based on whether the source register is truthy) and put the result into target register 237 | // A: target register 238 | // B: source register 239 | // C: constant table index (0..255) 240 | LOP_ANDK, 241 | LOP_ORK, 242 | 243 | // CONCAT: concatenate all strings between B and C (inclusive) and put the result into A 244 | // A: target register 245 | // B: source register start 246 | // C: source register end 247 | LOP_CONCAT, 248 | 249 | // NOT, MINUS, LENGTH: compute unary operation for source register and put the result into target register 250 | // A: target register 251 | // B: source register 252 | LOP_NOT, 253 | LOP_MINUS, 254 | LOP_LENGTH, 255 | 256 | // NEWTABLE: create table in target register 257 | // A: target register 258 | // B: table size, stored as 0 for v=0 and ceil(log2(v))+1 for v!=0 259 | // AUX: array size 260 | LOP_NEWTABLE, 261 | 262 | // DUPTABLE: duplicate table using the constant table template to target register 263 | // A: target register 264 | // D: constant table index (0..32767) 265 | LOP_DUPTABLE, 266 | 267 | // SETLIST: set a list of values to table in target register 268 | // A: target register 269 | // B: source register start 270 | // C: value count + 1, or 0 to use all values up to top (MULTRET) 271 | // AUX: table index to start from 272 | LOP_SETLIST, 273 | 274 | // FORNPREP: prepare a numeric for loop, jump over the loop if first iteration doesn't need to run 275 | // A: target register; numeric for loops assume a register layout [limit, step, index, variable] 276 | // D: jump offset (-32768..32767) 277 | // limit/step are immutable, index isn't visible to user code since it's copied into variable 278 | LOP_FORNPREP, 279 | 280 | // FORNLOOP: adjust loop variables for one iteration, jump back to the loop header if loop needs to continue 281 | // A: target register; see FORNPREP for register layout 282 | // D: jump offset (-32768..32767) 283 | LOP_FORNLOOP, 284 | 285 | // FORGLOOP: adjust loop variables for one iteration of a generic for loop, jump back to the loop header if loop needs to continue 286 | // A: target register; generic for loops assume a register layout [generator, state, index, variables...] 287 | // D: jump offset (-32768..32767) 288 | // AUX: variable count (1..255) in the low 8 bits, high bit indicates whether to use ipairs-style traversal in the fast path 289 | // loop variables are adjusted by calling generator(state, index) and expecting it to return a tuple that's copied to the user variables 290 | // the first variable is then copied into index; generator/state are immutable, index isn't visible to user code 291 | LOP_FORGLOOP, 292 | 293 | // FORGPREP_INEXT: prepare FORGLOOP with 2 output variables (no AUX encoding), assuming generator is luaB_inext, and jump to FORGLOOP 294 | // A: target register (see FORGLOOP for register layout) 295 | LOP_FORGPREP_INEXT, 296 | 297 | // removed in v3 298 | LOP_DEP_FORGLOOP_INEXT, 299 | 300 | // FORGPREP_NEXT: prepare FORGLOOP with 2 output variables (no AUX encoding), assuming generator is luaB_next, and jump to FORGLOOP 301 | // A: target register (see FORGLOOP for register layout) 302 | LOP_FORGPREP_NEXT, 303 | 304 | // NATIVECALL: start executing new function in native code 305 | // this is a pseudo-instruction that is never emitted by bytecode compiler, but can be constructed at runtime to accelerate native code dispatch 306 | LOP_NATIVECALL, 307 | 308 | // GETVARARGS: copy variables into the target register from vararg storage for current function 309 | // A: target register 310 | // B: variable count + 1, or 0 to copy all variables and adjust top (MULTRET) 311 | LOP_GETVARARGS, 312 | 313 | // DUPCLOSURE: create closure from a pre-created function object (reusing it unless environments diverge) 314 | // A: target register 315 | // D: constant table index (0..32767) 316 | LOP_DUPCLOSURE, 317 | 318 | // PREPVARARGS: prepare stack for variadic functions so that GETVARARGS works correctly 319 | // A: number of fixed arguments 320 | LOP_PREPVARARGS, 321 | 322 | // LOADKX: sets register to an entry from the constant table from the proto (number/string) 323 | // A: target register 324 | // AUX: constant table index 325 | LOP_LOADKX, 326 | 327 | // JUMPX: jumps to the target offset; like JUMPBACK, supports interruption 328 | // E: jump offset (-2^23..2^23; 0 means "next instruction" aka "don't jump") 329 | LOP_JUMPX, 330 | 331 | // FASTCALL: perform a fast call of a built-in function 332 | // A: builtin function id (see LuauBuiltinFunction) 333 | // C: jump offset to get to following CALL 334 | // FASTCALL is followed by one of (GETIMPORT, MOVE, GETUPVAL) instructions and by CALL instruction 335 | // This is necessary so that if FASTCALL can't perform the call inline, it can continue normal execution 336 | // If FASTCALL *can* perform the call, it jumps over the instructions *and* over the next CALL 337 | // Note that FASTCALL will read the actual call arguments, such as argument/result registers and counts, from the CALL instruction 338 | LOP_FASTCALL, 339 | 340 | // COVERAGE: update coverage information stored in the instruction 341 | // E: hit count for the instruction (0..2^23-1) 342 | // The hit count is incremented by VM every time the instruction is executed, and saturates at 2^23-1 343 | LOP_COVERAGE, 344 | 345 | // CAPTURE: capture a local or an upvalue as an upvalue into a newly created closure; only valid after NEWCLOSURE 346 | // A: capture type, see LuauCaptureType 347 | // B: source register (for VAL/REF) or upvalue index (for UPVAL/UPREF) 348 | LOP_CAPTURE, 349 | 350 | // removed in v3 351 | LOP_DEP_JUMPIFEQK, 352 | LOP_DEP_JUMPIFNOTEQK, 353 | 354 | // FASTCALL1: perform a fast call of a built-in function using 1 register argument 355 | // A: builtin function id (see LuauBuiltinFunction) 356 | // B: source argument register 357 | // C: jump offset to get to following CALL 358 | LOP_FASTCALL1, 359 | 360 | // FASTCALL2: perform a fast call of a built-in function using 2 register arguments 361 | // A: builtin function id (see LuauBuiltinFunction) 362 | // B: source argument register 363 | // C: jump offset to get to following CALL 364 | // AUX: source register 2 in least-significant byte 365 | LOP_FASTCALL2, 366 | 367 | // FASTCALL2K: perform a fast call of a built-in function using 1 register argument and 1 constant argument 368 | // A: builtin function id (see LuauBuiltinFunction) 369 | // B: source argument register 370 | // C: jump offset to get to following CALL 371 | // AUX: constant index 372 | LOP_FASTCALL2K, 373 | 374 | // FORGPREP: prepare loop variables for a generic for loop, jump to the loop backedge unconditionally 375 | // A: target register; generic for loops assume a register layout [generator, state, index, variables...] 376 | // D: jump offset (-32768..32767) 377 | LOP_FORGPREP, 378 | 379 | // JUMPXEQKNIL, JUMPXEQKB: jumps to target offset if the comparison with constant is true (or false, see AUX) 380 | // A: source register 1 381 | // D: jump offset (-32768..32767; 1 means "next instruction" aka "don't jump") 382 | // AUX: constant value (for boolean) in low bit, NOT flag (that flips comparison result) in high bit 383 | LOP_JUMPXEQKNIL, 384 | LOP_JUMPXEQKB, 385 | 386 | // JUMPXEQKN, JUMPXEQKS: jumps to target offset if the comparison with constant is true (or false, see AUX) 387 | // A: source register 1 388 | // D: jump offset (-32768..32767; 1 means "next instruction" aka "don't jump") 389 | // AUX: constant table index in low 24 bits, NOT flag (that flips comparison result) in high bit 390 | LOP_JUMPXEQKN, 391 | LOP_JUMPXEQKS, 392 | 393 | // IDIV: compute floor division between two source registers and put the result into target register 394 | // A: target register 395 | // B: source register 1 396 | // C: source register 2 397 | LOP_IDIV, 398 | 399 | // IDIVK compute floor division between the source register and a constant and put the result into target register 400 | // A: target register 401 | // B: source register 402 | // C: constant table index (0..255) 403 | LOP_IDIVK, 404 | 405 | // Enum entry for number of opcodes, not a valid opcode by itself! 406 | LOP__COUNT 407 | }; 408 | 409 | // Bytecode instruction header: it's always a 32-bit integer, with low byte (first byte in little endian) containing the opcode 410 | // Some instruction types require more data and have more 32-bit integers following the header 411 | #define LUAU_INSN_OP(insn) ((insn) & 0xff) 412 | 413 | // ABC encoding: three 8-bit values, containing registers or small numbers 414 | #define LUAU_INSN_A(insn) (((insn) >> 8) & 0xff) 415 | #define LUAU_INSN_B(insn) (((insn) >> 16) & 0xff) 416 | #define LUAU_INSN_C(insn) (((insn) >> 24) & 0xff) 417 | 418 | // AD encoding: one 8-bit value, one signed 16-bit value 419 | #define LUAU_INSN_D(insn) (int32_t(insn) >> 16) 420 | 421 | // E encoding: one signed 24-bit value 422 | #define LUAU_INSN_E(insn) (int32_t(insn) >> 8) 423 | 424 | // Bytecode tags, used internally for bytecode encoded as a string 425 | enum LuauBytecodeTag 426 | { 427 | // Bytecode version; runtime supports [MIN, MAX], compiler emits TARGET by default but may emit a higher version when flags are enabled 428 | LBC_VERSION_MIN = 3, 429 | LBC_VERSION_MAX = 4, 430 | LBC_VERSION_TARGET = 3, 431 | // Type encoding version 432 | LBC_TYPE_VERSION = 1, 433 | // Types of constant table entries 434 | LBC_CONSTANT_NIL = 0, 435 | LBC_CONSTANT_BOOLEAN, 436 | LBC_CONSTANT_NUMBER, 437 | LBC_CONSTANT_STRING, 438 | LBC_CONSTANT_IMPORT, 439 | LBC_CONSTANT_TABLE, 440 | LBC_CONSTANT_CLOSURE, 441 | }; 442 | 443 | // Type table tags 444 | enum LuauBytecodeType 445 | { 446 | LBC_TYPE_NIL = 0, 447 | LBC_TYPE_BOOLEAN, 448 | LBC_TYPE_NUMBER, 449 | LBC_TYPE_STRING, 450 | LBC_TYPE_TABLE, 451 | LBC_TYPE_FUNCTION, 452 | LBC_TYPE_THREAD, 453 | LBC_TYPE_USERDATA, 454 | LBC_TYPE_VECTOR, 455 | 456 | LBC_TYPE_ANY = 15, 457 | LBC_TYPE_OPTIONAL_BIT = 1 << 7, 458 | 459 | LBC_TYPE_INVALID = 256, 460 | }; 461 | 462 | // Builtin function ids, used in LOP_FASTCALL 463 | enum LuauBuiltinFunction 464 | { 465 | LBF_NONE = 0, 466 | 467 | // assert() 468 | LBF_ASSERT, 469 | 470 | // math. 471 | LBF_MATH_ABS, 472 | LBF_MATH_ACOS, 473 | LBF_MATH_ASIN, 474 | LBF_MATH_ATAN2, 475 | LBF_MATH_ATAN, 476 | LBF_MATH_CEIL, 477 | LBF_MATH_COSH, 478 | LBF_MATH_COS, 479 | LBF_MATH_DEG, 480 | LBF_MATH_EXP, 481 | LBF_MATH_FLOOR, 482 | LBF_MATH_FMOD, 483 | LBF_MATH_FREXP, 484 | LBF_MATH_LDEXP, 485 | LBF_MATH_LOG10, 486 | LBF_MATH_LOG, 487 | LBF_MATH_MAX, 488 | LBF_MATH_MIN, 489 | LBF_MATH_MODF, 490 | LBF_MATH_POW, 491 | LBF_MATH_RAD, 492 | LBF_MATH_SINH, 493 | LBF_MATH_SIN, 494 | LBF_MATH_SQRT, 495 | LBF_MATH_TANH, 496 | LBF_MATH_TAN, 497 | 498 | // bit32. 499 | LBF_BIT32_ARSHIFT, 500 | LBF_BIT32_BAND, 501 | LBF_BIT32_BNOT, 502 | LBF_BIT32_BOR, 503 | LBF_BIT32_BXOR, 504 | LBF_BIT32_BTEST, 505 | LBF_BIT32_EXTRACT, 506 | LBF_BIT32_LROTATE, 507 | LBF_BIT32_LSHIFT, 508 | LBF_BIT32_REPLACE, 509 | LBF_BIT32_RROTATE, 510 | LBF_BIT32_RSHIFT, 511 | 512 | // type() 513 | LBF_TYPE, 514 | 515 | // string. 516 | LBF_STRING_BYTE, 517 | LBF_STRING_CHAR, 518 | LBF_STRING_LEN, 519 | 520 | // typeof() 521 | LBF_TYPEOF, 522 | 523 | // string. 524 | LBF_STRING_SUB, 525 | 526 | // math. 527 | LBF_MATH_CLAMP, 528 | LBF_MATH_SIGN, 529 | LBF_MATH_ROUND, 530 | 531 | // raw* 532 | LBF_RAWSET, 533 | LBF_RAWGET, 534 | LBF_RAWEQUAL, 535 | 536 | // table. 537 | LBF_TABLE_INSERT, 538 | LBF_TABLE_UNPACK, 539 | 540 | // vector ctor 541 | LBF_VECTOR, 542 | 543 | // bit32.count 544 | LBF_BIT32_COUNTLZ, 545 | LBF_BIT32_COUNTRZ, 546 | 547 | // select(_, ...) 548 | LBF_SELECT_VARARG, 549 | 550 | // rawlen 551 | LBF_RAWLEN, 552 | 553 | // bit32.extract(_, k, k) 554 | LBF_BIT32_EXTRACTK, 555 | 556 | // get/setmetatable 557 | LBF_GETMETATABLE, 558 | LBF_SETMETATABLE, 559 | 560 | // tonumber/tostring 561 | LBF_TONUMBER, 562 | LBF_TOSTRING, 563 | }; 564 | 565 | // Capture type, used in LOP_CAPTURE 566 | enum LuauCaptureType 567 | { 568 | LCT_VAL = 0, 569 | LCT_REF, 570 | LCT_UPVAL, 571 | }; 572 | 573 | // Proto flag bitmask, stored in Proto::flags 574 | enum LuauProtoFlag 575 | { 576 | // used to tag main proto for modules with --!native 577 | LPF_NATIVE_MODULE = 1 << 0, 578 | }; 579 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/BytecodeBuilder.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Bytecode.h" 5 | #include "Luau/DenseHash.h" 6 | #include "Luau/StringUtils.h" 7 | 8 | #include 9 | 10 | namespace Luau 11 | { 12 | 13 | class BytecodeEncoder 14 | { 15 | public: 16 | virtual ~BytecodeEncoder() {} 17 | 18 | virtual void encode(uint32_t* data, size_t count) = 0; 19 | }; 20 | 21 | class BytecodeBuilder 22 | { 23 | public: 24 | // BytecodeBuilder does *not* copy the data passed via StringRef; instead, it keeps the ref around until finalize() 25 | // Please be careful with the lifetime of the data that's being passed because of this. 26 | // The safe and correct pattern is to only build StringRefs out of pieces of AST (AstName or AstArray<>) that are backed by AstAllocator. 27 | // Note that you must finalize() the builder before the Allocator backing the Ast is destroyed. 28 | struct StringRef 29 | { 30 | // To construct a StringRef, use sref() from Compiler.cpp. 31 | const char* data = nullptr; 32 | size_t length = 0; 33 | 34 | bool operator==(const StringRef& other) const; 35 | }; 36 | 37 | struct TableShape 38 | { 39 | static const unsigned int kMaxLength = 32; 40 | 41 | int32_t keys[kMaxLength]; 42 | unsigned int length = 0; 43 | 44 | bool operator==(const TableShape& other) const; 45 | }; 46 | 47 | BytecodeBuilder(BytecodeEncoder* encoder = 0); 48 | 49 | uint32_t beginFunction(uint8_t numparams, bool isvararg = false); 50 | void endFunction(uint8_t maxstacksize, uint8_t numupvalues, uint8_t flags = 0); 51 | 52 | void setMainFunction(uint32_t fid); 53 | 54 | int32_t addConstantNil(); 55 | int32_t addConstantBoolean(bool value); 56 | int32_t addConstantNumber(double value); 57 | int32_t addConstantString(StringRef value); 58 | int32_t addImport(uint32_t iid); 59 | int32_t addConstantTable(const TableShape& shape); 60 | int32_t addConstantClosure(uint32_t fid); 61 | 62 | int16_t addChildFunction(uint32_t fid); 63 | 64 | void emitABC(LuauOpcode op, uint8_t a, uint8_t b, uint8_t c); 65 | void emitAD(LuauOpcode op, uint8_t a, int16_t d); 66 | void emitE(LuauOpcode op, int32_t e); 67 | void emitAux(uint32_t aux); 68 | 69 | size_t emitLabel(); 70 | 71 | [[nodiscard]] bool patchJumpD(size_t jumpLabel, size_t targetLabel); 72 | [[nodiscard]] bool patchSkipC(size_t jumpLabel, size_t targetLabel); 73 | 74 | void foldJumps(); 75 | void expandJumps(); 76 | 77 | void setFunctionTypeInfo(std::string value); 78 | 79 | void setDebugFunctionName(StringRef name); 80 | void setDebugFunctionLineDefined(int line); 81 | void setDebugLine(int line); 82 | void pushDebugLocal(StringRef name, uint8_t reg, uint32_t startpc, uint32_t endpc); 83 | void pushDebugUpval(StringRef name); 84 | 85 | size_t getInstructionCount() const; 86 | uint32_t getDebugPC() const; 87 | 88 | void addDebugRemark(const char* format, ...) LUAU_PRINTF_ATTR(2, 3); 89 | 90 | void finalize(); 91 | 92 | enum DumpFlags 93 | { 94 | Dump_Code = 1 << 0, 95 | Dump_Lines = 1 << 1, 96 | Dump_Source = 1 << 2, 97 | Dump_Locals = 1 << 3, 98 | Dump_Remarks = 1 << 4, 99 | }; 100 | 101 | void setDumpFlags(uint32_t flags) 102 | { 103 | dumpFlags = flags; 104 | dumpFunctionPtr = &BytecodeBuilder::dumpCurrentFunction; 105 | } 106 | 107 | void setDumpSource(const std::string& source); 108 | 109 | bool needsDebugRemarks() const 110 | { 111 | return (dumpFlags & Dump_Remarks) != 0; 112 | } 113 | 114 | const std::string& getBytecode() const 115 | { 116 | LUAU_ASSERT(!bytecode.empty()); // did you forget to call finalize? 117 | return bytecode; 118 | } 119 | 120 | std::string dumpFunction(uint32_t id) const; 121 | std::string dumpEverything() const; 122 | std::string dumpSourceRemarks() const; 123 | std::string dumpTypeInfo() const; 124 | 125 | void annotateInstruction(std::string& result, uint32_t fid, uint32_t instpos) const; 126 | 127 | static uint32_t getImportId(int32_t id0); 128 | static uint32_t getImportId(int32_t id0, int32_t id1); 129 | static uint32_t getImportId(int32_t id0, int32_t id1, int32_t id2); 130 | 131 | static int decomposeImportId(uint32_t ids, int32_t& id0, int32_t& id1, int32_t& id2); 132 | 133 | static uint32_t getStringHash(StringRef key); 134 | 135 | static std::string getError(const std::string& message); 136 | 137 | static uint8_t getVersion(); 138 | static uint8_t getTypeEncodingVersion(); 139 | 140 | private: 141 | struct Constant 142 | { 143 | enum Type 144 | { 145 | Type_Nil, 146 | Type_Boolean, 147 | Type_Number, 148 | Type_String, 149 | Type_Import, 150 | Type_Table, 151 | Type_Closure, 152 | }; 153 | 154 | Type type; 155 | union 156 | { 157 | bool valueBoolean; 158 | double valueNumber; 159 | unsigned int valueString; // index into string table 160 | uint32_t valueImport; // 10-10-10-2 encoded import id 161 | uint32_t valueTable; // index into tableShapes[] 162 | uint32_t valueClosure; // index of function in global list 163 | }; 164 | }; 165 | 166 | struct ConstantKey 167 | { 168 | Constant::Type type; 169 | // Note: this stores value* from Constant; when type is Number_Double, this stores the same bits as double does but in uint64_t. 170 | uint64_t value; 171 | 172 | bool operator==(const ConstantKey& key) const 173 | { 174 | return type == key.type && value == key.value; 175 | } 176 | }; 177 | 178 | struct Function 179 | { 180 | std::string data; 181 | 182 | uint8_t maxstacksize = 0; 183 | uint8_t numparams = 0; 184 | uint8_t numupvalues = 0; 185 | bool isvararg = false; 186 | 187 | unsigned int debugname = 0; 188 | int debuglinedefined = 0; 189 | 190 | std::string dump; 191 | std::string dumpname; 192 | std::vector dumpinstoffs; 193 | std::string typeinfo; 194 | }; 195 | 196 | struct DebugLocal 197 | { 198 | unsigned int name; 199 | 200 | uint8_t reg; 201 | uint32_t startpc; 202 | uint32_t endpc; 203 | }; 204 | 205 | struct DebugUpval 206 | { 207 | unsigned int name; 208 | }; 209 | 210 | struct Jump 211 | { 212 | uint32_t source; 213 | uint32_t target; 214 | }; 215 | 216 | struct StringRefHash 217 | { 218 | size_t operator()(const StringRef& v) const; 219 | }; 220 | 221 | struct ConstantKeyHash 222 | { 223 | size_t operator()(const ConstantKey& key) const; 224 | }; 225 | 226 | struct TableShapeHash 227 | { 228 | size_t operator()(const TableShape& v) const; 229 | }; 230 | 231 | std::vector functions; 232 | uint32_t currentFunction = ~0u; 233 | uint32_t mainFunction = ~0u; 234 | 235 | std::vector insns; 236 | std::vector lines; 237 | std::vector constants; 238 | std::vector protos; 239 | std::vector jumps; 240 | 241 | std::vector tableShapes; 242 | 243 | bool hasLongJumps = false; 244 | 245 | DenseHashMap constantMap; 246 | DenseHashMap tableShapeMap; 247 | DenseHashMap protoMap; 248 | 249 | int debugLine = 0; 250 | 251 | std::vector debugLocals; 252 | std::vector debugUpvals; 253 | 254 | DenseHashMap stringTable; 255 | std::vector debugStrings; 256 | 257 | std::vector> debugRemarks; 258 | std::string debugRemarkBuffer; 259 | 260 | BytecodeEncoder* encoder = nullptr; 261 | std::string bytecode; 262 | 263 | uint32_t dumpFlags = 0; 264 | std::vector dumpSource; 265 | std::vector> dumpRemarks; 266 | 267 | std::string (BytecodeBuilder::*dumpFunctionPtr)(std::vector&) const = nullptr; 268 | 269 | void validate() const; 270 | void validateInstructions() const; 271 | void validateVariadic() const; 272 | 273 | std::string dumpCurrentFunction(std::vector& dumpinstoffs) const; 274 | void dumpConstant(std::string& result, int k) const; 275 | void dumpInstruction(const uint32_t* opcode, std::string& output, int targetLabel) const; 276 | 277 | void writeFunction(std::string& ss, uint32_t id, uint8_t flags) const; 278 | void writeLineInfo(std::string& ss) const; 279 | void writeStringTable(std::string& ss) const; 280 | 281 | int32_t addConstant(const ConstantKey& key, const Constant& value); 282 | unsigned int addStringTableEntry(StringRef value); 283 | }; 284 | 285 | } // namespace Luau 286 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/BytecodeUtils.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Bytecode.h" 5 | 6 | namespace Luau 7 | { 8 | 9 | inline int getOpLength(LuauOpcode op) 10 | { 11 | switch (op) 12 | { 13 | case LOP_GETGLOBAL: 14 | case LOP_SETGLOBAL: 15 | case LOP_GETIMPORT: 16 | case LOP_GETTABLEKS: 17 | case LOP_SETTABLEKS: 18 | case LOP_NAMECALL: 19 | case LOP_JUMPIFEQ: 20 | case LOP_JUMPIFLE: 21 | case LOP_JUMPIFLT: 22 | case LOP_JUMPIFNOTEQ: 23 | case LOP_JUMPIFNOTLE: 24 | case LOP_JUMPIFNOTLT: 25 | case LOP_NEWTABLE: 26 | case LOP_SETLIST: 27 | case LOP_FORGLOOP: 28 | case LOP_LOADKX: 29 | case LOP_FASTCALL2: 30 | case LOP_FASTCALL2K: 31 | case LOP_JUMPXEQKNIL: 32 | case LOP_JUMPXEQKB: 33 | case LOP_JUMPXEQKN: 34 | case LOP_JUMPXEQKS: 35 | return 2; 36 | 37 | default: 38 | return 1; 39 | } 40 | } 41 | 42 | } // namespace Luau 43 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/Common.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | // Compiler codegen control macros 5 | #ifdef _MSC_VER 6 | #define LUAU_NORETURN __declspec(noreturn) 7 | #define LUAU_NOINLINE __declspec(noinline) 8 | #define LUAU_FORCEINLINE __forceinline 9 | #define LUAU_LIKELY(x) x 10 | #define LUAU_UNLIKELY(x) x 11 | #define LUAU_UNREACHABLE() __assume(false) 12 | #define LUAU_DEBUGBREAK() __debugbreak() 13 | #else 14 | #define LUAU_NORETURN __attribute__((__noreturn__)) 15 | #define LUAU_NOINLINE __attribute__((noinline)) 16 | #define LUAU_FORCEINLINE inline __attribute__((always_inline)) 17 | #define LUAU_LIKELY(x) __builtin_expect(x, 1) 18 | #define LUAU_UNLIKELY(x) __builtin_expect(x, 0) 19 | #define LUAU_UNREACHABLE() __builtin_unreachable() 20 | #define LUAU_DEBUGBREAK() __builtin_trap() 21 | #endif 22 | 23 | #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 24 | #define LUAU_BIG_ENDIAN 25 | #endif 26 | 27 | namespace Luau 28 | { 29 | 30 | using AssertHandler = int (*)(const char* expression, const char* file, int line, const char* function); 31 | 32 | inline AssertHandler& assertHandler() 33 | { 34 | static AssertHandler handler = nullptr; 35 | return handler; 36 | } 37 | 38 | // We want 'inline' to correctly link this function declared in the header 39 | // But we also want to prevent compiler from inlining this function when optimization and assertions are enabled together 40 | // Reason for that is that compilation times can increase significantly in such a configuration 41 | LUAU_NOINLINE inline int assertCallHandler(const char* expression, const char* file, int line, const char* function) 42 | { 43 | if (AssertHandler handler = assertHandler()) 44 | return handler(expression, file, line, function); 45 | 46 | return 1; 47 | } 48 | 49 | } // namespace Luau 50 | 51 | #if !defined(NDEBUG) || defined(LUAU_ENABLE_ASSERT) 52 | #define LUAU_ASSERT(expr) ((void)(!!(expr) || (Luau::assertCallHandler(#expr, __FILE__, __LINE__, __FUNCTION__) && (LUAU_DEBUGBREAK(), 0)))) 53 | #define LUAU_ASSERTENABLED 54 | #else 55 | #define LUAU_ASSERT(expr) (void)sizeof(!!(expr)) 56 | #endif 57 | 58 | namespace Luau 59 | { 60 | 61 | template 62 | struct FValue 63 | { 64 | static FValue* list; 65 | 66 | T value; 67 | bool dynamic; 68 | const char* name; 69 | FValue* next; 70 | 71 | FValue(const char* name, T def, bool dynamic) 72 | : value(def) 73 | , dynamic(dynamic) 74 | , name(name) 75 | , next(list) 76 | { 77 | list = this; 78 | } 79 | 80 | operator T() const 81 | { 82 | return value; 83 | } 84 | }; 85 | 86 | template 87 | FValue* FValue::list = nullptr; 88 | 89 | } // namespace Luau 90 | 91 | #define LUAU_FASTFLAG(flag) \ 92 | namespace FFlag \ 93 | { \ 94 | extern Luau::FValue flag; \ 95 | } 96 | #define LUAU_FASTFLAGVARIABLE(flag, def) \ 97 | namespace FFlag \ 98 | { \ 99 | Luau::FValue flag(#flag, def, false); \ 100 | } 101 | #define LUAU_FASTINT(flag) \ 102 | namespace FInt \ 103 | { \ 104 | extern Luau::FValue flag; \ 105 | } 106 | #define LUAU_FASTINTVARIABLE(flag, def) \ 107 | namespace FInt \ 108 | { \ 109 | Luau::FValue flag(#flag, def, false); \ 110 | } 111 | 112 | #define LUAU_DYNAMIC_FASTFLAG(flag) \ 113 | namespace DFFlag \ 114 | { \ 115 | extern Luau::FValue flag; \ 116 | } 117 | #define LUAU_DYNAMIC_FASTFLAGVARIABLE(flag, def) \ 118 | namespace DFFlag \ 119 | { \ 120 | Luau::FValue flag(#flag, def, true); \ 121 | } 122 | #define LUAU_DYNAMIC_FASTINT(flag) \ 123 | namespace DFInt \ 124 | { \ 125 | extern Luau::FValue flag; \ 126 | } 127 | #define LUAU_DYNAMIC_FASTINTVARIABLE(flag, def) \ 128 | namespace DFInt \ 129 | { \ 130 | Luau::FValue flag(#flag, def, true); \ 131 | } 132 | 133 | #if defined(__GNUC__) 134 | #define LUAU_PRINTF_ATTR(fmt, arg) __attribute__((format(printf, fmt, arg))) 135 | #else 136 | #define LUAU_PRINTF_ATTR(fmt, arg) 137 | #endif 138 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/Compiler.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/ParseOptions.h" 5 | #include "Luau/Location.h" 6 | #include "Luau/StringUtils.h" 7 | #include "Luau/Common.h" 8 | 9 | namespace Luau 10 | { 11 | class AstNameTable; 12 | struct ParseResult; 13 | class BytecodeBuilder; 14 | class BytecodeEncoder; 15 | 16 | // Note: this structure is duplicated in luacode.h, don't forget to change these in sync! 17 | struct CompileOptions 18 | { 19 | // 0 - no optimization 20 | // 1 - baseline optimization level that doesn't prevent debuggability 21 | // 2 - includes optimizations that harm debuggability such as inlining 22 | int optimizationLevel = 1; 23 | 24 | // 0 - no debugging support 25 | // 1 - line info & function names only; sufficient for backtraces 26 | // 2 - full debug info with local & upvalue names; necessary for debugger 27 | int debugLevel = 1; 28 | 29 | // 0 - no code coverage support 30 | // 1 - statement coverage 31 | // 2 - statement and expression coverage (verbose) 32 | int coverageLevel = 0; 33 | 34 | // global builtin to construct vectors; disabled by default 35 | const char* vectorLib = nullptr; 36 | const char* vectorCtor = nullptr; 37 | 38 | // vector type name for type tables; disabled by default 39 | const char* vectorType = nullptr; 40 | 41 | // null-terminated array of globals that are mutable; disables the import optimization for fields accessed through these 42 | const char* const* mutableGlobals = nullptr; 43 | }; 44 | 45 | class CompileError : public std::exception 46 | { 47 | public: 48 | CompileError(const Location& location, const std::string& message); 49 | 50 | virtual ~CompileError() throw(); 51 | 52 | virtual const char* what() const throw(); 53 | 54 | const Location& getLocation() const; 55 | 56 | static LUAU_NORETURN void raise(const Location& location, const char* format, ...) LUAU_PRINTF_ATTR(2, 3); 57 | 58 | private: 59 | Location location; 60 | std::string message; 61 | }; 62 | 63 | // compiles bytecode into bytecode builder using either a pre-parsed AST or parsing it from source; throws on errors 64 | void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, const AstNameTable& names, const CompileOptions& options = {}); 65 | void compileOrThrow(BytecodeBuilder& bytecode, const std::string& source, const CompileOptions& options = {}, const ParseOptions& parseOptions = {}); 66 | 67 | // compiles bytecode into a bytecode blob, that either contains the valid bytecode or an encoded error that luau_load can decode 68 | std::string compile( 69 | const std::string& source, const CompileOptions& options = {}, const ParseOptions& parseOptions = {}, BytecodeEncoder* encoder = nullptr); 70 | 71 | } // namespace Luau 72 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/Confusables.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include 5 | 6 | namespace Luau 7 | { 8 | const char* findConfusable(uint32_t codepoint); 9 | } 10 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/DenseHash.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Common.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace Luau 12 | { 13 | 14 | struct DenseHashPointer 15 | { 16 | size_t operator()(const void* key) const 17 | { 18 | return (uintptr_t(key) >> 4) ^ (uintptr_t(key) >> 9); 19 | } 20 | }; 21 | 22 | // Internal implementation of DenseHashSet and DenseHashMap 23 | namespace detail 24 | { 25 | 26 | template 27 | using DenseHashDefault = std::conditional_t, DenseHashPointer, std::hash>; 28 | 29 | template 30 | class DenseHashTable 31 | { 32 | public: 33 | class const_iterator; 34 | class iterator; 35 | 36 | explicit DenseHashTable(const Key& empty_key, size_t buckets = 0) 37 | : data(nullptr) 38 | , capacity(0) 39 | , count(0) 40 | , empty_key(empty_key) 41 | { 42 | // validate that equality operator is at least somewhat functional 43 | LUAU_ASSERT(eq(empty_key, empty_key)); 44 | // buckets has to be power-of-two or zero 45 | LUAU_ASSERT((buckets & (buckets - 1)) == 0); 46 | 47 | if (buckets) 48 | { 49 | data = static_cast(::operator new(sizeof(Item) * buckets)); 50 | capacity = buckets; 51 | 52 | ItemInterface::fill(data, buckets, empty_key); 53 | } 54 | } 55 | 56 | ~DenseHashTable() 57 | { 58 | if (data) 59 | destroy(); 60 | } 61 | 62 | DenseHashTable(const DenseHashTable& other) 63 | : data(nullptr) 64 | , capacity(0) 65 | , count(other.count) 66 | , empty_key(other.empty_key) 67 | { 68 | if (other.capacity) 69 | { 70 | data = static_cast(::operator new(sizeof(Item) * other.capacity)); 71 | 72 | for (size_t i = 0; i < other.capacity; ++i) 73 | { 74 | new (&data[i]) Item(other.data[i]); 75 | capacity = i + 1; // if Item copy throws, capacity will note the number of initialized objects for destroy() to clean up 76 | } 77 | } 78 | } 79 | 80 | DenseHashTable(DenseHashTable&& other) 81 | : data(other.data) 82 | , capacity(other.capacity) 83 | , count(other.count) 84 | , empty_key(other.empty_key) 85 | { 86 | other.data = nullptr; 87 | other.capacity = 0; 88 | other.count = 0; 89 | } 90 | 91 | DenseHashTable& operator=(DenseHashTable&& other) 92 | { 93 | if (this != &other) 94 | { 95 | if (data) 96 | destroy(); 97 | 98 | data = other.data; 99 | capacity = other.capacity; 100 | count = other.count; 101 | empty_key = other.empty_key; 102 | 103 | other.data = nullptr; 104 | other.capacity = 0; 105 | other.count = 0; 106 | } 107 | 108 | return *this; 109 | } 110 | 111 | DenseHashTable& operator=(const DenseHashTable& other) 112 | { 113 | if (this != &other) 114 | { 115 | DenseHashTable copy(other); 116 | *this = std::move(copy); 117 | } 118 | 119 | return *this; 120 | } 121 | 122 | void clear() 123 | { 124 | if (count == 0) 125 | return; 126 | 127 | if (capacity > 32) 128 | { 129 | destroy(); 130 | } 131 | else 132 | { 133 | ItemInterface::destroy(data, capacity); 134 | ItemInterface::fill(data, capacity, empty_key); 135 | } 136 | 137 | count = 0; 138 | } 139 | 140 | void destroy() 141 | { 142 | ItemInterface::destroy(data, capacity); 143 | 144 | ::operator delete(data); 145 | data = nullptr; 146 | 147 | capacity = 0; 148 | } 149 | 150 | Item* insert_unsafe(const Key& key) 151 | { 152 | // It is invalid to insert empty_key into the table since it acts as a "entry does not exist" marker 153 | LUAU_ASSERT(!eq(key, empty_key)); 154 | 155 | size_t hashmod = capacity - 1; 156 | size_t bucket = hasher(key) & hashmod; 157 | 158 | for (size_t probe = 0; probe <= hashmod; ++probe) 159 | { 160 | Item& probe_item = data[bucket]; 161 | 162 | // Element does not exist, insert here 163 | if (eq(ItemInterface::getKey(probe_item), empty_key)) 164 | { 165 | ItemInterface::setKey(probe_item, key); 166 | count++; 167 | return &probe_item; 168 | } 169 | 170 | // Element already exists 171 | if (eq(ItemInterface::getKey(probe_item), key)) 172 | { 173 | return &probe_item; 174 | } 175 | 176 | // Hash collision, quadratic probing 177 | bucket = (bucket + probe + 1) & hashmod; 178 | } 179 | 180 | // Hash table is full - this should not happen 181 | LUAU_ASSERT(false); 182 | return NULL; 183 | } 184 | 185 | const Item* find(const Key& key) const 186 | { 187 | if (count == 0) 188 | return 0; 189 | if (eq(key, empty_key)) 190 | return 0; 191 | 192 | size_t hashmod = capacity - 1; 193 | size_t bucket = hasher(key) & hashmod; 194 | 195 | for (size_t probe = 0; probe <= hashmod; ++probe) 196 | { 197 | const Item& probe_item = data[bucket]; 198 | 199 | // Element exists 200 | if (eq(ItemInterface::getKey(probe_item), key)) 201 | return &probe_item; 202 | 203 | // Element does not exist 204 | if (eq(ItemInterface::getKey(probe_item), empty_key)) 205 | return NULL; 206 | 207 | // Hash collision, quadratic probing 208 | bucket = (bucket + probe + 1) & hashmod; 209 | } 210 | 211 | // Hash table is full - this should not happen 212 | LUAU_ASSERT(false); 213 | return NULL; 214 | } 215 | 216 | void rehash() 217 | { 218 | size_t newsize = capacity == 0 ? 16 : capacity * 2; 219 | 220 | DenseHashTable newtable(empty_key, newsize); 221 | 222 | for (size_t i = 0; i < capacity; ++i) 223 | { 224 | const Key& key = ItemInterface::getKey(data[i]); 225 | 226 | if (!eq(key, empty_key)) 227 | { 228 | Item* item = newtable.insert_unsafe(key); 229 | *item = std::move(data[i]); 230 | } 231 | } 232 | 233 | LUAU_ASSERT(count == newtable.count); 234 | 235 | std::swap(data, newtable.data); 236 | std::swap(capacity, newtable.capacity); 237 | } 238 | 239 | void rehash_if_full(const Key& key) 240 | { 241 | if (count >= capacity * 3 / 4 && !find(key)) 242 | { 243 | rehash(); 244 | } 245 | } 246 | 247 | const_iterator begin() const 248 | { 249 | size_t start = 0; 250 | 251 | while (start < capacity && eq(ItemInterface::getKey(data[start]), empty_key)) 252 | start++; 253 | 254 | return const_iterator(this, start); 255 | } 256 | 257 | const_iterator end() const 258 | { 259 | return const_iterator(this, capacity); 260 | } 261 | 262 | iterator begin() 263 | { 264 | size_t start = 0; 265 | 266 | while (start < capacity && eq(ItemInterface::getKey(data[start]), empty_key)) 267 | start++; 268 | 269 | return iterator(this, start); 270 | } 271 | 272 | iterator end() 273 | { 274 | return iterator(this, capacity); 275 | } 276 | 277 | size_t size() const 278 | { 279 | return count; 280 | } 281 | 282 | class const_iterator 283 | { 284 | public: 285 | using value_type = Item; 286 | using reference = Item&; 287 | using pointer = Item*; 288 | using iterator = pointer; 289 | using difference_type = size_t; 290 | using iterator_category = std::input_iterator_tag; 291 | 292 | const_iterator() 293 | : set(0) 294 | , index(0) 295 | { 296 | } 297 | 298 | const_iterator(const DenseHashTable* set, size_t index) 299 | : set(set) 300 | , index(index) 301 | { 302 | } 303 | 304 | const Item& operator*() const 305 | { 306 | return set->data[index]; 307 | } 308 | 309 | const Item* operator->() const 310 | { 311 | return &set->data[index]; 312 | } 313 | 314 | bool operator==(const const_iterator& other) const 315 | { 316 | return set == other.set && index == other.index; 317 | } 318 | 319 | bool operator!=(const const_iterator& other) const 320 | { 321 | return set != other.set || index != other.index; 322 | } 323 | 324 | const_iterator& operator++() 325 | { 326 | size_t size = set->capacity; 327 | 328 | do 329 | { 330 | index++; 331 | } while (index < size && set->eq(ItemInterface::getKey(set->data[index]), set->empty_key)); 332 | 333 | return *this; 334 | } 335 | 336 | const_iterator operator++(int) 337 | { 338 | const_iterator res = *this; 339 | ++*this; 340 | return res; 341 | } 342 | 343 | private: 344 | const DenseHashTable* set; 345 | size_t index; 346 | }; 347 | 348 | class iterator 349 | { 350 | public: 351 | iterator() 352 | : set(0) 353 | , index(0) 354 | { 355 | } 356 | 357 | iterator(DenseHashTable* set, size_t index) 358 | : set(set) 359 | , index(index) 360 | { 361 | } 362 | 363 | MutableItem& operator*() const 364 | { 365 | return *reinterpret_cast(&set->data[index]); 366 | } 367 | 368 | MutableItem* operator->() const 369 | { 370 | return reinterpret_cast(&set->data[index]); 371 | } 372 | 373 | bool operator==(const iterator& other) const 374 | { 375 | return set == other.set && index == other.index; 376 | } 377 | 378 | bool operator!=(const iterator& other) const 379 | { 380 | return set != other.set || index != other.index; 381 | } 382 | 383 | iterator& operator++() 384 | { 385 | size_t size = set->capacity; 386 | 387 | do 388 | { 389 | index++; 390 | } while (index < size && set->eq(ItemInterface::getKey(set->data[index]), set->empty_key)); 391 | 392 | return *this; 393 | } 394 | 395 | iterator operator++(int) 396 | { 397 | iterator res = *this; 398 | ++*this; 399 | return res; 400 | } 401 | 402 | private: 403 | DenseHashTable* set; 404 | size_t index; 405 | }; 406 | 407 | private: 408 | Item* data; 409 | size_t capacity; 410 | size_t count; 411 | Key empty_key; 412 | Hash hasher; 413 | Eq eq; 414 | }; 415 | 416 | template 417 | struct ItemInterfaceSet 418 | { 419 | static const Key& getKey(const Key& item) 420 | { 421 | return item; 422 | } 423 | 424 | static void setKey(Key& item, const Key& key) 425 | { 426 | item = key; 427 | } 428 | 429 | static void fill(Key* data, size_t count, const Key& key) 430 | { 431 | for (size_t i = 0; i < count; ++i) 432 | new (&data[i]) Key(key); 433 | } 434 | 435 | static void destroy(Key* data, size_t count) 436 | { 437 | for (size_t i = 0; i < count; ++i) 438 | data[i].~Key(); 439 | } 440 | }; 441 | 442 | template 443 | struct ItemInterfaceMap 444 | { 445 | static const Key& getKey(const std::pair& item) 446 | { 447 | return item.first; 448 | } 449 | 450 | static void setKey(std::pair& item, const Key& key) 451 | { 452 | item.first = key; 453 | } 454 | 455 | static void fill(std::pair* data, size_t count, const Key& key) 456 | { 457 | for (size_t i = 0; i < count; ++i) 458 | { 459 | new (&data[i].first) Key(key); 460 | new (&data[i].second) Value(); 461 | } 462 | } 463 | 464 | static void destroy(std::pair* data, size_t count) 465 | { 466 | for (size_t i = 0; i < count; ++i) 467 | { 468 | data[i].first.~Key(); 469 | data[i].second.~Value(); 470 | } 471 | } 472 | }; 473 | 474 | } // namespace detail 475 | 476 | // This is a faster alternative of unordered_set, but it does not implement the same interface (i.e. it does not support erasing) 477 | template, typename Eq = std::equal_to> 478 | class DenseHashSet 479 | { 480 | typedef detail::DenseHashTable, Hash, Eq> Impl; 481 | Impl impl; 482 | 483 | public: 484 | typedef typename Impl::const_iterator const_iterator; 485 | typedef typename Impl::iterator iterator; 486 | 487 | explicit DenseHashSet(const Key& empty_key, size_t buckets = 0) 488 | : impl(empty_key, buckets) 489 | { 490 | } 491 | 492 | void clear() 493 | { 494 | impl.clear(); 495 | } 496 | 497 | const Key& insert(const Key& key) 498 | { 499 | impl.rehash_if_full(key); 500 | return *impl.insert_unsafe(key); 501 | } 502 | 503 | const Key* find(const Key& key) const 504 | { 505 | return impl.find(key); 506 | } 507 | 508 | bool contains(const Key& key) const 509 | { 510 | return impl.find(key) != 0; 511 | } 512 | 513 | size_t size() const 514 | { 515 | return impl.size(); 516 | } 517 | 518 | bool empty() const 519 | { 520 | return impl.size() == 0; 521 | } 522 | 523 | const_iterator begin() const 524 | { 525 | return impl.begin(); 526 | } 527 | 528 | const_iterator end() const 529 | { 530 | return impl.end(); 531 | } 532 | 533 | iterator begin() 534 | { 535 | return impl.begin(); 536 | } 537 | 538 | iterator end() 539 | { 540 | return impl.end(); 541 | } 542 | }; 543 | 544 | // This is a faster alternative of unordered_map, but it does not implement the same interface (i.e. it does not support erasing and has 545 | // contains() instead of find()) 546 | template, typename Eq = std::equal_to> 547 | class DenseHashMap 548 | { 549 | typedef detail::DenseHashTable, std::pair, detail::ItemInterfaceMap, Hash, Eq> Impl; 550 | Impl impl; 551 | 552 | public: 553 | typedef typename Impl::const_iterator const_iterator; 554 | typedef typename Impl::iterator iterator; 555 | 556 | explicit DenseHashMap(const Key& empty_key, size_t buckets = 0) 557 | : impl(empty_key, buckets) 558 | { 559 | } 560 | 561 | void clear() 562 | { 563 | impl.clear(); 564 | } 565 | 566 | // Note: this reference is invalidated by any insert operation (i.e. operator[]) 567 | Value& operator[](const Key& key) 568 | { 569 | impl.rehash_if_full(key); 570 | return impl.insert_unsafe(key)->second; 571 | } 572 | 573 | // Note: this pointer is invalidated by any insert operation (i.e. operator[]) 574 | const Value* find(const Key& key) const 575 | { 576 | const std::pair* result = impl.find(key); 577 | 578 | return result ? &result->second : NULL; 579 | } 580 | 581 | // Note: this pointer is invalidated by any insert operation (i.e. operator[]) 582 | Value* find(const Key& key) 583 | { 584 | const std::pair* result = impl.find(key); 585 | 586 | return result ? const_cast(&result->second) : NULL; 587 | } 588 | 589 | bool contains(const Key& key) const 590 | { 591 | return impl.find(key) != 0; 592 | } 593 | 594 | std::pair try_insert(const Key& key, const Value& value) 595 | { 596 | impl.rehash_if_full(key); 597 | 598 | size_t before = impl.size(); 599 | std::pair* slot = impl.insert_unsafe(key); 600 | 601 | // Value is fresh if container count has increased 602 | bool fresh = impl.size() > before; 603 | 604 | if (fresh) 605 | slot->second = value; 606 | 607 | return std::make_pair(std::ref(slot->second), fresh); 608 | } 609 | 610 | size_t size() const 611 | { 612 | return impl.size(); 613 | } 614 | 615 | bool empty() const 616 | { 617 | return impl.size() == 0; 618 | } 619 | 620 | const_iterator begin() const 621 | { 622 | return impl.begin(); 623 | } 624 | 625 | const_iterator end() const 626 | { 627 | return impl.end(); 628 | } 629 | 630 | iterator begin() 631 | { 632 | return impl.begin(); 633 | } 634 | 635 | iterator end() 636 | { 637 | return impl.end(); 638 | } 639 | }; 640 | 641 | } // namespace Luau 642 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/ExperimentalFlags.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include 5 | 6 | namespace Luau 7 | { 8 | 9 | inline bool isFlagExperimental(const char* flag) 10 | { 11 | // Flags in this list are disabled by default in various command-line tools. They may have behavior that is not fully final, 12 | // or critical bugs that are found after the code has been submitted. 13 | static const char* const kList[] = { 14 | "LuauInstantiateInSubtyping", // requires some fixes to lua-apps code 15 | "LuauTinyControlFlowAnalysis", // waiting for updates to packages depended by internal builtin plugins 16 | // makes sure we always have at least one entry 17 | nullptr, 18 | }; 19 | 20 | for (const char* item : kList) 21 | if (item && strcmp(item, flag) == 0) 22 | return true; 23 | 24 | return false; 25 | } 26 | 27 | } // namespace Luau 28 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/Lexer.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Ast.h" 5 | #include "Luau/Location.h" 6 | #include "Luau/DenseHash.h" 7 | #include "Luau/Common.h" 8 | 9 | #include 10 | 11 | namespace Luau 12 | { 13 | 14 | class Allocator 15 | { 16 | public: 17 | Allocator(); 18 | Allocator(Allocator&&); 19 | 20 | Allocator& operator=(Allocator&&) = delete; 21 | 22 | ~Allocator(); 23 | 24 | void* allocate(size_t size); 25 | 26 | template 27 | T* alloc(Args&&... args) 28 | { 29 | static_assert(std::is_trivially_destructible::value, "Objects allocated with this allocator will never have their destructors run!"); 30 | 31 | T* t = static_cast(allocate(sizeof(T))); 32 | new (t) T(std::forward(args)...); 33 | return t; 34 | } 35 | 36 | private: 37 | struct Page 38 | { 39 | Page* next; 40 | 41 | char data[8192]; 42 | }; 43 | 44 | Page* root; 45 | size_t offset; 46 | }; 47 | 48 | struct Lexeme 49 | { 50 | enum Type 51 | { 52 | Eof = 0, 53 | 54 | // 1..255 means actual character values 55 | Char_END = 256, 56 | 57 | Equal, 58 | LessEqual, 59 | GreaterEqual, 60 | NotEqual, 61 | Dot2, 62 | Dot3, 63 | SkinnyArrow, 64 | DoubleColon, 65 | FloorDiv, 66 | 67 | InterpStringBegin, 68 | InterpStringMid, 69 | InterpStringEnd, 70 | // An interpolated string with no expressions (like `x`) 71 | InterpStringSimple, 72 | 73 | AddAssign, 74 | SubAssign, 75 | MulAssign, 76 | DivAssign, 77 | FloorDivAssign, 78 | ModAssign, 79 | PowAssign, 80 | ConcatAssign, 81 | 82 | RawString, 83 | QuotedString, 84 | Number, 85 | Name, 86 | 87 | Comment, 88 | BlockComment, 89 | 90 | BrokenString, 91 | BrokenComment, 92 | BrokenUnicode, 93 | BrokenInterpDoubleBrace, 94 | 95 | Error, 96 | 97 | Reserved_BEGIN, 98 | ReservedAnd = Reserved_BEGIN, 99 | ReservedBreak, 100 | ReservedDo, 101 | ReservedElse, 102 | ReservedElseif, 103 | ReservedEnd, 104 | ReservedFalse, 105 | ReservedFor, 106 | ReservedFunction, 107 | ReservedIf, 108 | ReservedIn, 109 | ReservedLocal, 110 | ReservedNil, 111 | ReservedNot, 112 | ReservedOr, 113 | ReservedRepeat, 114 | ReservedReturn, 115 | ReservedThen, 116 | ReservedTrue, 117 | ReservedUntil, 118 | ReservedWhile, 119 | Reserved_END 120 | }; 121 | 122 | Type type; 123 | Location location; 124 | unsigned int length; 125 | 126 | union 127 | { 128 | const char* data; // String, Number, Comment 129 | const char* name; // Name 130 | unsigned int codepoint; // BrokenUnicode 131 | }; 132 | 133 | Lexeme(const Location& location, Type type); 134 | Lexeme(const Location& location, char character); 135 | Lexeme(const Location& location, Type type, const char* data, size_t size); 136 | Lexeme(const Location& location, Type type, const char* name); 137 | 138 | std::string toString() const; 139 | }; 140 | 141 | class AstNameTable 142 | { 143 | public: 144 | AstNameTable(Allocator& allocator); 145 | 146 | AstName addStatic(const char* name, Lexeme::Type type = Lexeme::Name); 147 | 148 | std::pair getOrAddWithType(const char* name, size_t length); 149 | std::pair getWithType(const char* name, size_t length) const; 150 | 151 | AstName getOrAdd(const char* name); 152 | AstName get(const char* name) const; 153 | 154 | private: 155 | struct Entry 156 | { 157 | AstName value; 158 | uint32_t length; 159 | Lexeme::Type type; 160 | 161 | bool operator==(const Entry& other) const; 162 | }; 163 | 164 | struct EntryHash 165 | { 166 | size_t operator()(const Entry& e) const; 167 | }; 168 | 169 | DenseHashSet data; 170 | 171 | Allocator& allocator; 172 | }; 173 | 174 | class Lexer 175 | { 176 | public: 177 | Lexer(const char* buffer, std::size_t bufferSize, AstNameTable& names); 178 | 179 | void setSkipComments(bool skip); 180 | void setReadNames(bool read); 181 | 182 | const Location& previousLocation() const 183 | { 184 | return prevLocation; 185 | } 186 | 187 | const Lexeme& next(); 188 | const Lexeme& next(bool skipComments, bool updatePrevLocation); 189 | void nextline(); 190 | 191 | Lexeme lookahead(); 192 | 193 | const Lexeme& current() const 194 | { 195 | return lexeme; 196 | } 197 | 198 | static bool isReserved(const std::string& word); 199 | 200 | static bool fixupQuotedString(std::string& data); 201 | static void fixupMultilineString(std::string& data); 202 | 203 | private: 204 | char peekch() const; 205 | char peekch(unsigned int lookahead) const; 206 | 207 | Position position() const; 208 | 209 | // consume() assumes current character is not a newline for performance; when that is not known, consumeAny() should be used instead. 210 | void consume(); 211 | void consumeAny(); 212 | 213 | Lexeme readCommentBody(); 214 | 215 | // Given a sequence [===[ or ]===], returns: 216 | // 1. number of equal signs (or 0 if none present) between the brackets 217 | // 2. -1 if this is not a long comment/string separator 218 | // 3. -N if this is a malformed separator 219 | // Does *not* consume the closing brace. 220 | int skipLongSeparator(); 221 | 222 | Lexeme readLongString(const Position& start, int sep, Lexeme::Type ok, Lexeme::Type broken); 223 | Lexeme readQuotedString(); 224 | 225 | Lexeme readInterpolatedStringBegin(); 226 | Lexeme readInterpolatedStringSection(Position start, Lexeme::Type formatType, Lexeme::Type endType); 227 | 228 | void readBackslashInString(); 229 | 230 | std::pair readName(); 231 | 232 | Lexeme readNumber(const Position& start, unsigned int startOffset); 233 | 234 | Lexeme readUtf8Error(); 235 | Lexeme readNext(); 236 | 237 | const char* buffer; 238 | std::size_t bufferSize; 239 | 240 | unsigned int offset; 241 | 242 | unsigned int line; 243 | unsigned int lineOffset; 244 | 245 | Lexeme lexeme; 246 | 247 | Location prevLocation; 248 | 249 | AstNameTable& names; 250 | 251 | bool skipComments; 252 | bool readNames; 253 | 254 | enum class BraceType 255 | { 256 | InterpolatedString, 257 | Normal 258 | }; 259 | 260 | std::vector braceStack; 261 | }; 262 | 263 | inline bool isSpace(char ch) 264 | { 265 | return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\v' || ch == '\f'; 266 | } 267 | 268 | } // namespace Luau 269 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/Location.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include 5 | namespace Luau 6 | { 7 | 8 | struct Position 9 | { 10 | unsigned int line, column; 11 | 12 | Position(unsigned int line, unsigned int column); 13 | 14 | bool operator==(const Position& rhs) const; 15 | bool operator!=(const Position& rhs) const; 16 | bool operator<(const Position& rhs) const; 17 | bool operator>(const Position& rhs) const; 18 | bool operator<=(const Position& rhs) const; 19 | bool operator>=(const Position& rhs) const; 20 | 21 | void shift(const Position& start, const Position& oldEnd, const Position& newEnd); 22 | }; 23 | 24 | struct Location 25 | { 26 | Position begin, end; 27 | 28 | Location(); 29 | Location(const Position& begin, const Position& end); 30 | Location(const Position& begin, unsigned int length); 31 | Location(const Location& begin, const Location& end); 32 | 33 | bool operator==(const Location& rhs) const; 34 | bool operator!=(const Location& rhs) const; 35 | 36 | bool encloses(const Location& l) const; 37 | bool overlaps(const Location& l) const; 38 | bool contains(const Position& p) const; 39 | bool containsClosed(const Position& p) const; 40 | void extend(const Location& other); 41 | void shift(const Position& start, const Position& oldEnd, const Position& newEnd); 42 | }; 43 | 44 | } // namespace Luau 45 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/ParseOptions.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | namespace Luau 5 | { 6 | 7 | enum class Mode 8 | { 9 | NoCheck, // Do not perform any inference 10 | Nonstrict, // Unannotated symbols are any 11 | Strict, // Unannotated symbols are inferred 12 | Definition, // Type definition module, has special parsing rules 13 | }; 14 | 15 | struct ParseOptions 16 | { 17 | bool allowDeclarationSyntax = false; 18 | bool captureComments = false; 19 | }; 20 | 21 | } // namespace Luau 22 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/ParseResult.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Common.h" 5 | #include "Luau/Location.h" 6 | #include "Luau/Lexer.h" 7 | #include "Luau/StringUtils.h" 8 | 9 | namespace Luau 10 | { 11 | 12 | class AstStatBlock; 13 | 14 | class ParseError : public std::exception 15 | { 16 | public: 17 | ParseError(const Location& location, const std::string& message); 18 | 19 | virtual const char* what() const throw(); 20 | 21 | const Location& getLocation() const; 22 | const std::string& getMessage() const; 23 | 24 | static LUAU_NORETURN void raise(const Location& location, const char* format, ...) LUAU_PRINTF_ATTR(2, 3); 25 | 26 | private: 27 | Location location; 28 | std::string message; 29 | }; 30 | 31 | class ParseErrors : public std::exception 32 | { 33 | public: 34 | ParseErrors(std::vector errors); 35 | 36 | virtual const char* what() const throw(); 37 | 38 | const std::vector& getErrors() const; 39 | 40 | private: 41 | std::vector errors; 42 | std::string message; 43 | }; 44 | 45 | struct HotComment 46 | { 47 | bool header; 48 | Location location; 49 | std::string content; 50 | }; 51 | 52 | struct Comment 53 | { 54 | Lexeme::Type type; // Comment, BlockComment, or BrokenComment 55 | Location location; 56 | }; 57 | 58 | struct ParseResult 59 | { 60 | AstStatBlock* root; 61 | size_t lines = 0; 62 | 63 | std::vector hotcomments; 64 | std::vector errors; 65 | 66 | std::vector commentLocations; 67 | }; 68 | 69 | static constexpr const char* kParseNameError = "%error-id%"; 70 | 71 | } // namespace Luau 72 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/Parser.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Ast.h" 5 | #include "Luau/Lexer.h" 6 | #include "Luau/ParseOptions.h" 7 | #include "Luau/ParseResult.h" 8 | #include "Luau/StringUtils.h" 9 | #include "Luau/DenseHash.h" 10 | #include "Luau/Common.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace Luau 17 | { 18 | 19 | template 20 | class TempVector 21 | { 22 | public: 23 | explicit TempVector(std::vector& storage); 24 | 25 | ~TempVector(); 26 | 27 | const T& operator[](std::size_t index) const; 28 | 29 | const T& front() const; 30 | 31 | const T& back() const; 32 | 33 | bool empty() const; 34 | 35 | std::size_t size() const; 36 | 37 | void push_back(const T& item); 38 | 39 | typename std::vector::const_iterator begin() const 40 | { 41 | return storage.begin() + offset; 42 | } 43 | typename std::vector::const_iterator end() const 44 | { 45 | return storage.begin() + offset + size_; 46 | } 47 | 48 | private: 49 | std::vector& storage; 50 | size_t offset; 51 | size_t size_; 52 | }; 53 | 54 | class Parser 55 | { 56 | public: 57 | static ParseResult parse( 58 | const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, ParseOptions options = ParseOptions()); 59 | 60 | private: 61 | struct Name; 62 | struct Binding; 63 | 64 | Parser(const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, const ParseOptions& options); 65 | 66 | bool blockFollow(const Lexeme& l); 67 | 68 | AstStatBlock* parseChunk(); 69 | 70 | // chunk ::= {stat [`;']} [laststat [`;']] 71 | // block ::= chunk 72 | AstStatBlock* parseBlock(); 73 | 74 | AstStatBlock* parseBlockNoScope(); 75 | 76 | // stat ::= 77 | // varlist `=' explist | 78 | // functioncall | 79 | // do block end | 80 | // while exp do block end | 81 | // repeat block until exp | 82 | // if exp then block {elseif exp then block} [else block] end | 83 | // for Name `=' exp `,' exp [`,' exp] do block end | 84 | // for namelist in explist do block end | 85 | // function funcname funcbody | 86 | // local function Name funcbody | 87 | // local namelist [`=' explist] 88 | // laststat ::= return [explist] | break 89 | AstStat* parseStat(); 90 | 91 | // if exp then block {elseif exp then block} [else block] end 92 | AstStat* parseIf(); 93 | 94 | // while exp do block end 95 | AstStat* parseWhile(); 96 | 97 | // repeat block until exp 98 | AstStat* parseRepeat(); 99 | 100 | // do block end 101 | AstStat* parseDo(); 102 | 103 | // break 104 | AstStat* parseBreak(); 105 | 106 | // continue 107 | AstStat* parseContinue(const Location& start); 108 | 109 | // for Name `=' exp `,' exp [`,' exp] do block end | 110 | // for namelist in explist do block end | 111 | AstStat* parseFor(); 112 | 113 | // funcname ::= Name {`.' Name} [`:' Name] 114 | AstExpr* parseFunctionName(Location start, bool& hasself, AstName& debugname); 115 | 116 | // function funcname funcbody 117 | AstStat* parseFunctionStat(); 118 | 119 | // local function Name funcbody | 120 | // local namelist [`=' explist] 121 | AstStat* parseLocal(); 122 | 123 | // return [explist] 124 | AstStat* parseReturn(); 125 | 126 | // type Name `=' Type 127 | AstStat* parseTypeAlias(const Location& start, bool exported); 128 | 129 | AstDeclaredClassProp parseDeclaredClassMethod(); 130 | 131 | // `declare global' Name: Type | 132 | // `declare function' Name`(' [parlist] `)' [`:` Type] 133 | AstStat* parseDeclaration(const Location& start); 134 | 135 | // varlist `=' explist 136 | AstStat* parseAssignment(AstExpr* initial); 137 | 138 | // var [`+=' | `-=' | `*=' | `/=' | `%=' | `^=' | `..='] exp 139 | AstStat* parseCompoundAssignment(AstExpr* initial, AstExprBinary::Op op); 140 | 141 | std::pair> prepareFunctionArguments(const Location& start, bool hasself, const TempVector& args); 142 | 143 | // funcbodyhead ::= `(' [namelist [`,' `...'] | `...'] `)' [`:` Type] 144 | // funcbody ::= funcbodyhead block end 145 | std::pair parseFunctionBody( 146 | bool hasself, const Lexeme& matchFunction, const AstName& debugname, const Name* localName); 147 | 148 | // explist ::= {exp `,'} exp 149 | void parseExprList(TempVector& result); 150 | 151 | // binding ::= Name [`:` Type] 152 | Binding parseBinding(); 153 | 154 | // bindinglist ::= (binding | `...') {`,' bindinglist} 155 | // Returns the location of the vararg ..., or std::nullopt if the function is not vararg. 156 | std::tuple parseBindingList(TempVector& result, bool allowDot3 = false); 157 | 158 | AstType* parseOptionalType(); 159 | 160 | // TypeList ::= Type [`,' TypeList] 161 | // ReturnType ::= Type | `(' TypeList `)' 162 | // TableProp ::= Name `:' Type 163 | // TableIndexer ::= `[' Type `]' `:' Type 164 | // PropList ::= (TableProp | TableIndexer) [`,' PropList] 165 | // Type 166 | // ::= Name 167 | // | `nil` 168 | // | `{' [PropList] `}' 169 | // | `(' [TypeList] `)' `->` ReturnType 170 | 171 | // Returns the variadic annotation, if it exists. 172 | AstTypePack* parseTypeList(TempVector& result, TempVector>& resultNames); 173 | 174 | std::optional parseOptionalReturnType(); 175 | std::pair parseReturnType(); 176 | 177 | AstTableIndexer* parseTableIndexer(); 178 | 179 | AstTypeOrPack parseFunctionType(bool allowPack); 180 | AstType* parseFunctionTypeTail(const Lexeme& begin, AstArray generics, AstArray genericPacks, 181 | AstArray params, AstArray> paramNames, AstTypePack* varargAnnotation); 182 | 183 | AstType* parseTableType(); 184 | AstTypeOrPack parseSimpleType(bool allowPack); 185 | 186 | AstTypeOrPack parseTypeOrPack(); 187 | AstType* parseType(); 188 | 189 | AstTypePack* parseTypePack(); 190 | AstTypePack* parseVariadicArgumentTypePack(); 191 | 192 | AstType* parseTypeSuffix(AstType* type, const Location& begin); 193 | 194 | static std::optional parseUnaryOp(const Lexeme& l); 195 | static std::optional parseBinaryOp(const Lexeme& l); 196 | static std::optional parseCompoundOp(const Lexeme& l); 197 | 198 | struct BinaryOpPriority 199 | { 200 | unsigned char left, right; 201 | }; 202 | 203 | std::optional checkUnaryConfusables(); 204 | std::optional checkBinaryConfusables(const BinaryOpPriority binaryPriority[], unsigned int limit); 205 | 206 | // subexpr -> (asexp | unop subexpr) { binop subexpr } 207 | // where `binop' is any binary operator with a priority higher than `limit' 208 | AstExpr* parseExpr(unsigned int limit = 0); 209 | 210 | // NAME 211 | AstExpr* parseNameExpr(const char* context = nullptr); 212 | 213 | // prefixexp -> NAME | '(' expr ')' 214 | AstExpr* parsePrefixExpr(); 215 | 216 | // primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } 217 | AstExpr* parsePrimaryExpr(bool asStatement); 218 | 219 | // asexp -> simpleexp [`::' Type] 220 | AstExpr* parseAssertionExpr(); 221 | 222 | // simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp 223 | AstExpr* parseSimpleExpr(); 224 | 225 | // args ::= `(' [explist] `)' | tableconstructor | String 226 | AstExpr* parseFunctionArgs(AstExpr* func, bool self); 227 | 228 | // tableconstructor ::= `{' [fieldlist] `}' 229 | // fieldlist ::= field {fieldsep field} [fieldsep] 230 | // field ::= `[' exp `]' `=' exp | Name `=' exp | exp 231 | // fieldsep ::= `,' | `;' 232 | AstExpr* parseTableConstructor(); 233 | 234 | // TODO: Add grammar rules here? 235 | AstExpr* parseIfElseExpr(); 236 | 237 | // stringinterp ::= exp { exp} 238 | AstExpr* parseInterpString(); 239 | 240 | // Name 241 | std::optional parseNameOpt(const char* context = nullptr); 242 | Name parseName(const char* context = nullptr); 243 | Name parseIndexName(const char* context, const Position& previous); 244 | 245 | // `<' namelist `>' 246 | std::pair, AstArray> parseGenericTypeList(bool withDefaultValues); 247 | 248 | // `<' Type[, ...] `>' 249 | AstArray parseTypeParams(); 250 | 251 | std::optional> parseCharArray(); 252 | AstExpr* parseString(); 253 | AstExpr* parseNumber(); 254 | 255 | AstLocal* pushLocal(const Binding& binding); 256 | 257 | unsigned int saveLocals(); 258 | 259 | void restoreLocals(unsigned int offset); 260 | 261 | // check that parser is at lexeme/symbol, move to next lexeme/symbol on success, report failure and continue on failure 262 | bool expectAndConsume(char value, const char* context = nullptr); 263 | bool expectAndConsume(Lexeme::Type type, const char* context = nullptr); 264 | void expectAndConsumeFail(Lexeme::Type type, const char* context); 265 | 266 | struct MatchLexeme 267 | { 268 | MatchLexeme(const Lexeme& l) 269 | : type(l.type) 270 | , position(l.location.begin) 271 | { 272 | } 273 | 274 | Lexeme::Type type; 275 | Position position; 276 | }; 277 | 278 | bool expectMatchAndConsume(char value, const MatchLexeme& begin, bool searchForMissing = false); 279 | void expectMatchAndConsumeFail(Lexeme::Type type, const MatchLexeme& begin, const char* extra = nullptr); 280 | bool expectMatchAndConsumeRecover(char value, const MatchLexeme& begin, bool searchForMissing); 281 | 282 | bool expectMatchEndAndConsume(Lexeme::Type type, const MatchLexeme& begin); 283 | void expectMatchEndAndConsumeFail(Lexeme::Type type, const MatchLexeme& begin); 284 | 285 | template 286 | AstArray copy(const T* data, std::size_t size); 287 | 288 | template 289 | AstArray copy(const TempVector& data); 290 | 291 | template 292 | AstArray copy(std::initializer_list data); 293 | 294 | AstArray copy(const std::string& data); 295 | 296 | void incrementRecursionCounter(const char* context); 297 | 298 | void report(const Location& location, const char* format, va_list args); 299 | void report(const Location& location, const char* format, ...) LUAU_PRINTF_ATTR(3, 4); 300 | 301 | void reportNameError(const char* context); 302 | 303 | AstStatError* reportStatError(const Location& location, const AstArray& expressions, const AstArray& statements, 304 | const char* format, ...) LUAU_PRINTF_ATTR(5, 6); 305 | AstExprError* reportExprError(const Location& location, const AstArray& expressions, const char* format, ...) LUAU_PRINTF_ATTR(4, 5); 306 | AstTypeError* reportTypeError(const Location& location, const AstArray& types, const char* format, ...) LUAU_PRINTF_ATTR(4, 5); 307 | // `parseErrorLocation` is associated with the parser error 308 | // `astErrorLocation` is associated with the AstTypeError created 309 | // It can be useful to have different error locations so that the parse error can include the next lexeme, while the AstTypeError can precisely 310 | // define the location (possibly of zero size) where a type annotation is expected. 311 | AstTypeError* reportMissingTypeError(const Location& parseErrorLocation, const Location& astErrorLocation, const char* format, ...) 312 | LUAU_PRINTF_ATTR(4, 5); 313 | 314 | AstExpr* reportFunctionArgsError(AstExpr* func, bool self); 315 | void reportAmbiguousCallError(); 316 | 317 | void nextLexeme(); 318 | 319 | struct Function 320 | { 321 | bool vararg; 322 | unsigned int loopDepth; 323 | 324 | Function() 325 | : vararg(false) 326 | , loopDepth(0) 327 | { 328 | } 329 | }; 330 | 331 | struct Local 332 | { 333 | AstLocal* local; 334 | unsigned int offset; 335 | 336 | Local() 337 | : local(nullptr) 338 | , offset(0) 339 | { 340 | } 341 | }; 342 | 343 | struct Name 344 | { 345 | AstName name; 346 | Location location; 347 | 348 | Name(const AstName& name, const Location& location) 349 | : name(name) 350 | , location(location) 351 | { 352 | } 353 | }; 354 | 355 | struct Binding 356 | { 357 | Name name; 358 | AstType* annotation; 359 | 360 | explicit Binding(const Name& name, AstType* annotation = nullptr) 361 | : name(name) 362 | , annotation(annotation) 363 | { 364 | } 365 | }; 366 | 367 | ParseOptions options; 368 | 369 | Lexer lexer; 370 | Allocator& allocator; 371 | 372 | std::vector commentLocations; 373 | std::vector hotcomments; 374 | 375 | bool hotcommentHeader = true; 376 | 377 | unsigned int recursionCounter; 378 | 379 | AstName nameSelf; 380 | AstName nameNumber; 381 | AstName nameError; 382 | AstName nameNil; 383 | 384 | MatchLexeme endMismatchSuspect; 385 | 386 | std::vector functionStack; 387 | 388 | DenseHashMap localMap; 389 | std::vector localStack; 390 | 391 | std::vector parseErrors; 392 | 393 | std::vector matchRecoveryStopOnToken; 394 | 395 | std::vector scratchStat; 396 | std::vector> scratchString; 397 | std::vector scratchExpr; 398 | std::vector scratchExprAux; 399 | std::vector scratchName; 400 | std::vector scratchPackName; 401 | std::vector scratchBinding; 402 | std::vector scratchLocal; 403 | std::vector scratchTableTypeProps; 404 | std::vector scratchType; 405 | std::vector scratchTypeOrPack; 406 | std::vector scratchDeclaredClassProps; 407 | std::vector scratchItem; 408 | std::vector scratchArgName; 409 | std::vector scratchGenericTypes; 410 | std::vector scratchGenericTypePacks; 411 | std::vector> scratchOptArgName; 412 | std::string scratchData; 413 | }; 414 | 415 | } // namespace Luau 416 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/StringUtils.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Common.h" 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace Luau 12 | { 13 | 14 | std::string format(const char* fmt, ...) LUAU_PRINTF_ATTR(1, 2); 15 | std::string vformat(const char* fmt, va_list args); 16 | 17 | void formatAppend(std::string& str, const char* fmt, ...) LUAU_PRINTF_ATTR(2, 3); 18 | void vformatAppend(std::string& ret, const char* fmt, va_list args); 19 | 20 | std::string join(const std::vector& segments, std::string_view delimiter); 21 | std::string join(const std::vector& segments, std::string_view delimiter); 22 | 23 | std::vector split(std::string_view s, char delimiter); 24 | 25 | // Computes the Damerau-Levenshtein distance of A and B. 26 | // https://en.wikipedia.org/wiki/Damerau-Levenshtein_distance#Distance_with_adjacent_transpositions 27 | size_t editDistance(std::string_view a, std::string_view b); 28 | 29 | bool startsWith(std::string_view lhs, std::string_view rhs); 30 | bool equalsLower(std::string_view lhs, std::string_view rhs); 31 | 32 | size_t hashRange(const char* data, size_t size); 33 | 34 | std::string escape(std::string_view s, bool escapeForInterpString = false); 35 | bool isIdentifier(std::string_view s); 36 | } // namespace Luau 37 | -------------------------------------------------------------------------------- /Dependencies/luau/include/Luau/TimeTrace.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include "Luau/Common.h" 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | LUAU_FASTFLAG(DebugLuauTimeTracing) 12 | 13 | namespace Luau 14 | { 15 | namespace TimeTrace 16 | { 17 | double getClock(); 18 | uint32_t getClockMicroseconds(); 19 | } // namespace TimeTrace 20 | } // namespace Luau 21 | 22 | #if defined(LUAU_ENABLE_TIME_TRACE) 23 | 24 | namespace Luau 25 | { 26 | namespace TimeTrace 27 | { 28 | struct Token 29 | { 30 | const char* name; 31 | const char* category; 32 | }; 33 | 34 | enum class EventType : uint8_t 35 | { 36 | Enter, 37 | Leave, 38 | 39 | ArgName, 40 | ArgValue, 41 | }; 42 | 43 | struct Event 44 | { 45 | EventType type; 46 | uint16_t token; 47 | 48 | union 49 | { 50 | uint32_t microsec; // 1 hour trace limit 51 | uint32_t dataPos; 52 | } data; 53 | }; 54 | 55 | struct GlobalContext; 56 | struct ThreadContext; 57 | 58 | std::shared_ptr getGlobalContext(); 59 | 60 | uint16_t createToken(GlobalContext& context, const char* name, const char* category); 61 | uint32_t createThread(GlobalContext& context, ThreadContext* threadContext); 62 | void releaseThread(GlobalContext& context, ThreadContext* threadContext); 63 | void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector& events, const std::vector& data); 64 | 65 | struct ThreadContext 66 | { 67 | ThreadContext() 68 | : globalContext(getGlobalContext()) 69 | { 70 | threadId = createThread(*globalContext, this); 71 | } 72 | 73 | ~ThreadContext() 74 | { 75 | if (!events.empty()) 76 | flushEvents(); 77 | 78 | releaseThread(*globalContext, this); 79 | } 80 | 81 | void flushEvents() 82 | { 83 | static uint16_t flushToken = createToken(*globalContext, "flushEvents", "TimeTrace"); 84 | 85 | events.push_back({EventType::Enter, flushToken, {getClockMicroseconds()}}); 86 | 87 | TimeTrace::flushEvents(*globalContext, threadId, events, data); 88 | 89 | events.clear(); 90 | data.clear(); 91 | 92 | events.push_back({EventType::Leave, 0, {getClockMicroseconds()}}); 93 | } 94 | 95 | void eventEnter(uint16_t token) 96 | { 97 | eventEnter(token, getClockMicroseconds()); 98 | } 99 | 100 | void eventEnter(uint16_t token, uint32_t microsec) 101 | { 102 | events.push_back({EventType::Enter, token, {microsec}}); 103 | } 104 | 105 | void eventLeave() 106 | { 107 | eventLeave(getClockMicroseconds()); 108 | } 109 | 110 | void eventLeave(uint32_t microsec) 111 | { 112 | events.push_back({EventType::Leave, 0, {microsec}}); 113 | 114 | if (events.size() > kEventFlushLimit) 115 | flushEvents(); 116 | } 117 | 118 | void eventArgument(const char* name, const char* value) 119 | { 120 | uint32_t pos = uint32_t(data.size()); 121 | data.insert(data.end(), name, name + strlen(name) + 1); 122 | events.push_back({EventType::ArgName, 0, {pos}}); 123 | 124 | pos = uint32_t(data.size()); 125 | data.insert(data.end(), value, value + strlen(value) + 1); 126 | events.push_back({EventType::ArgValue, 0, {pos}}); 127 | } 128 | 129 | std::shared_ptr globalContext; 130 | uint32_t threadId; 131 | std::vector events; 132 | std::vector data; 133 | 134 | static constexpr size_t kEventFlushLimit = 8192; 135 | }; 136 | 137 | ThreadContext& getThreadContext(); 138 | 139 | struct Scope 140 | { 141 | explicit Scope(uint16_t token) 142 | : context(getThreadContext()) 143 | { 144 | if (!FFlag::DebugLuauTimeTracing) 145 | return; 146 | 147 | context.eventEnter(token); 148 | } 149 | 150 | ~Scope() 151 | { 152 | if (!FFlag::DebugLuauTimeTracing) 153 | return; 154 | 155 | context.eventLeave(); 156 | } 157 | 158 | ThreadContext& context; 159 | }; 160 | 161 | struct OptionalTailScope 162 | { 163 | explicit OptionalTailScope(uint16_t token, uint32_t threshold) 164 | : context(getThreadContext()) 165 | , token(token) 166 | , threshold(threshold) 167 | { 168 | if (!FFlag::DebugLuauTimeTracing) 169 | return; 170 | 171 | pos = uint32_t(context.events.size()); 172 | microsec = getClockMicroseconds(); 173 | } 174 | 175 | ~OptionalTailScope() 176 | { 177 | if (!FFlag::DebugLuauTimeTracing) 178 | return; 179 | 180 | if (pos == context.events.size()) 181 | { 182 | uint32_t curr = getClockMicroseconds(); 183 | 184 | if (curr - microsec > threshold) 185 | { 186 | context.eventEnter(token, microsec); 187 | context.eventLeave(curr); 188 | } 189 | } 190 | } 191 | 192 | ThreadContext& context; 193 | uint16_t token; 194 | uint32_t threshold; 195 | uint32_t microsec; 196 | uint32_t pos; 197 | }; 198 | 199 | LUAU_NOINLINE uint16_t createScopeData(const char* name, const char* category); 200 | 201 | } // namespace TimeTrace 202 | } // namespace Luau 203 | 204 | // Regular scope 205 | #define LUAU_TIMETRACE_SCOPE(name, category) \ 206 | static uint16_t lttScopeStatic = Luau::TimeTrace::createScopeData(name, category); \ 207 | Luau::TimeTrace::Scope lttScope(lttScopeStatic) 208 | 209 | // A scope without nested scopes that may be skipped if the time it took is less than the threshold 210 | #define LUAU_TIMETRACE_OPTIONAL_TAIL_SCOPE(name, category, microsec) \ 211 | static uint16_t lttScopeStaticOptTail = Luau::TimeTrace::createScopeData(name, category); \ 212 | Luau::TimeTrace::OptionalTailScope lttScope(lttScopeStaticOptTail, microsec) 213 | 214 | // Extra key/value data can be added to regular scopes 215 | #define LUAU_TIMETRACE_ARGUMENT(name, value) \ 216 | do \ 217 | { \ 218 | if (FFlag::DebugLuauTimeTracing) \ 219 | lttScope.context.eventArgument(name, value); \ 220 | } while (false) 221 | 222 | #else 223 | 224 | #define LUAU_TIMETRACE_SCOPE(name, category) 225 | #define LUAU_TIMETRACE_OPTIONAL_TAIL_SCOPE(name, category, microsec) 226 | #define LUAU_TIMETRACE_ARGUMENT(name, value) \ 227 | do \ 228 | { \ 229 | } while (false) 230 | 231 | #endif 232 | -------------------------------------------------------------------------------- /Dependencies/luau/include/luacode.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details 2 | #pragma once 3 | 4 | #include 5 | 6 | // Can be used to reconfigure visibility/exports for public APIs 7 | #ifndef LUACODE_API 8 | #define LUACODE_API extern 9 | #endif 10 | 11 | typedef struct lua_CompileOptions lua_CompileOptions; 12 | 13 | struct lua_CompileOptions 14 | { 15 | // 0 - no optimization 16 | // 1 - baseline optimization level that doesn't prevent debuggability 17 | // 2 - includes optimizations that harm debuggability such as inlining 18 | int optimizationLevel; // default=1 19 | 20 | // 0 - no debugging support 21 | // 1 - line info & function names only; sufficient for backtraces 22 | // 2 - full debug info with local & upvalue names; necessary for debugger 23 | int debugLevel; // default=1 24 | 25 | // 0 - no code coverage support 26 | // 1 - statement coverage 27 | // 2 - statement and expression coverage (verbose) 28 | int coverageLevel; // default=0 29 | 30 | // global builtin to construct vectors; disabled by default 31 | const char* vectorLib; 32 | const char* vectorCtor; 33 | 34 | // vector type name for type tables; disabled by default 35 | const char* vectorType; 36 | 37 | // null-terminated array of globals that are mutable; disables the import optimization for fields accessed through these 38 | const char* const* mutableGlobals; 39 | }; 40 | 41 | // compile source to bytecode; when source compilation fails, the resulting bytecode contains the encoded error. use free() to destroy 42 | LUACODE_API char* luau_compile(const char* source, size_t size, lua_CompileOptions* options, size_t* outsize); 43 | -------------------------------------------------------------------------------- /Dependencies/luau/lib/luau_static.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spoorloos/uwp_executor/032f81b22175e9be8bb644f2e15af6e464098990/Dependencies/luau/lib/luau_static.lib -------------------------------------------------------------------------------- /Dependencies/luau/lib/luau_static.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spoorloos/uwp_executor/032f81b22175e9be8bb644f2e15af6e464098990/Dependencies/luau/lib/luau_static.pdb -------------------------------------------------------------------------------- /Dependencies/zstd/lib/libzstd_static.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spoorloos/uwp_executor/032f81b22175e9be8bb644f2e15af6e464098990/Dependencies/zstd/lib/libzstd_static.lib -------------------------------------------------------------------------------- /Dependencies/zstd/lib/libzstd_static.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spoorloos/uwp_executor/032f81b22175e9be8bb644f2e15af6e464098990/Dependencies/zstd/lib/libzstd_static.pdb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!WARNING] 2 | > As of September 2023 this is permanently patched and unusable! 3 | 4 | # UWP Executor 5 | 6 | A simple script executor for the microsoft store version of Roblox. 7 | 8 | ## Installation 9 | 10 | The project and its libraries were all intended (and compiled) with the v143 platform toolset; you will need to install the latest version of Visual Studio 2022 to compile the project. 11 | 12 | ## Usage 13 | 14 | To inject the DLL you can use [Extreme Injector](https://github.com/master131/ExtremeInjector) (or any other injection tool) with a manual map injection method. Keep in mind that the offsets change weekly and you'll have to update them yourself in [Roblox.hpp](UWP_Executor/Roblox.hpp), you can use [UWP Roblox Dumper](https://github.com/Spoorloos/uwp_roblox_dumper) or find them yourself. 15 | 16 | ## Credits 17 | 18 | Credits to [EpixScripts/rbxcompile](https://github.com/EpixScripts/rbxcompile) for the compression method. 19 | 20 | -------------------------------------------------------------------------------- /UWP_Executor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33815.320 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UWP_Executor", "UWP_Executor\UWP_Executor.vcxproj", "{CC25D15D-C50A-4F64-B65D-C58881B98489}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x86 = Release|x86 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {CC25D15D-C50A-4F64-B65D-C58881B98489}.Release|x86.ActiveCfg = Release|Win32 14 | {CC25D15D-C50A-4F64-B65D-C58881B98489}.Release|x86.Build.0 = Release|Win32 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | SolutionGuid = {2600DA75-8AEB-4C7C-A158-A4A386B97736} 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /UWP_Executor/Execution.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Execution.hpp" 5 | #include "Roblox.hpp" 6 | #include "Scheduler.hpp" 7 | 8 | #include "zstd.h" 9 | #include "xxhash.h" 10 | 11 | #include "Luau/Compiler.h" 12 | #include "Luau/BytecodeBuilder.h" 13 | #include "Luau/BytecodeUtils.h" 14 | 15 | const uint32_t identity = 8u, script = NULL; 16 | 17 | class bytecode_encoder_t : public Luau::BytecodeEncoder { 18 | inline void encode(uint32_t* data, size_t count) override { 19 | // Loop through the instructions. 20 | for (auto i = 0u; i < count;) { 21 | // Get the opcode (which is the first byte of the instruction). 22 | auto& opcode = *reinterpret_cast(data + i); 23 | 24 | // Add the instruction length (which could be multiple 32-bit integers). 25 | i += Luau::getOpLength(LuauOpcode(opcode)); 26 | 27 | // Encode the opcode. 28 | opcode *= 227; 29 | } 30 | } 31 | }; 32 | 33 | std::string compress_bytecode(std::string_view bytecode) { 34 | // Create a buffer. 35 | const auto data_size = bytecode.size(); 36 | const auto max_size = ZSTD_compressBound(data_size); 37 | auto buffer = std::vector(max_size + 8); 38 | 39 | // Copy RSB1 and data size into the buffer. 40 | strcpy_s(&buffer[0], buffer.capacity(), "RSB1"); 41 | memcpy_s(&buffer[4], buffer.capacity(), &data_size, sizeof(data_size)); 42 | 43 | // Copy compressed bytecode into the buffer. 44 | const auto compressed_size = ZSTD_compress(&buffer[8], max_size, bytecode.data(), data_size, ZSTD_maxCLevel()); 45 | if (ZSTD_isError(compressed_size)) 46 | throw std::runtime_error("Failed to compress the bytecode."); 47 | 48 | // Encrypt the buffer. 49 | const auto size = compressed_size + 8; 50 | const auto key = XXH32(buffer.data(), size, 42u); 51 | const auto bytes = reinterpret_cast(&key); 52 | 53 | for (auto i = 0u; i < size; ++i) 54 | buffer[i] ^= bytes[i % 4] + i * 41u; 55 | 56 | // Create and return output. 57 | return std::string(buffer.data(), size); 58 | } 59 | 60 | void Execution::execute_bytecode(std::string_view bytecode) { 61 | // Compress and load the bytecode. 62 | auto compressed = compress_bytecode(bytecode); 63 | const auto state = Roblox::get_state(Scheduler::get_script_context(), &identity, &script); 64 | 65 | if (Roblox::luavm_load(state, &compressed, "", 0)) 66 | throw std::runtime_error("Unexpected error during execution."); 67 | 68 | // Set the identity, spawn the script closure and pop it off the stack. 69 | Roblox::set_identity(state, identity); 70 | Roblox::task_spawn(state); 71 | Roblox::pop_stack(state, 1); 72 | } 73 | 74 | void Execution::execute_script(const std::string& source) { 75 | // If the script is empty, return. 76 | if (source.length() == 0) 77 | return; 78 | 79 | // Compile the script. 80 | static auto encoder = bytecode_encoder_t(); 81 | const auto bytecode = Luau::compile("task.wait()" + source, {}, {}, &encoder); 82 | 83 | // Print out the compiler error or execute the bytecode. 84 | if (bytecode[0] == '\0') 85 | Roblox::print(2, bytecode.c_str() + 1); 86 | else 87 | Execution::execute_bytecode(bytecode); 88 | } 89 | -------------------------------------------------------------------------------- /UWP_Executor/Execution.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Execution { 6 | void execute_bytecode(std::string_view bytecode); 7 | 8 | void execute_script(const std::string& source); 9 | } 10 | -------------------------------------------------------------------------------- /UWP_Executor/Main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Roblox.hpp" 5 | #include "Execution.hpp" 6 | 7 | void entry() noexcept { 8 | try { 9 | // Execute script(s). 10 | Execution::execute_script("printidentity()"); 11 | } catch (const std::exception& error) { 12 | // Caught an exception, print it to the console. 13 | Roblox::print(3, "The executor has caught an exception: %s", error.what()); 14 | } 15 | } 16 | 17 | bool __stdcall DllMain(HMODULE h_module, DWORD reason, LPVOID) { 18 | if (reason == DLL_PROCESS_ATTACH) { 19 | DisableThreadLibraryCalls(h_module); 20 | std::thread(entry).detach(); 21 | } 22 | return true; 23 | } 24 | -------------------------------------------------------------------------------- /UWP_Executor/Roblox.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Offsets { // Version: 2.592.586.0 7 | // Base offsets: 8 | constexpr uintptr_t get_scheduler = 0x7AAAA0; 9 | constexpr uintptr_t get_state = 0x4555F0; 10 | constexpr uintptr_t luavm_load = 0x554E90; 11 | constexpr uintptr_t task_spawn = 0x554030; 12 | constexpr uintptr_t print = 0xD71B20; 13 | 14 | // Other offsets: 15 | constexpr ptrdiff_t top = 12/*, base = 16*/; 16 | constexpr ptrdiff_t extra_space = 72, identity = 24; 17 | } 18 | 19 | namespace Types { 20 | using get_scheduler = uintptr_t(__cdecl*)(); 21 | using get_state = uintptr_t(__thiscall*)(uintptr_t script_context, const uint32_t* identity, const uintptr_t* script); 22 | using luavm_load = int32_t(__fastcall*)(uintptr_t state, std::string* source, const char* chunk_name, int32_t env); 23 | using task_spawn = int32_t(__cdecl*)(uintptr_t state); 24 | using print = int32_t(__cdecl*)(int32_t type, const char* message, ...); 25 | } 26 | 27 | namespace Roblox { 28 | // Get the base address which all the function offsets are relative to. 29 | const auto base = reinterpret_cast(GetModuleHandle(nullptr)); 30 | 31 | // Roblox functions: 32 | const auto get_scheduler = reinterpret_cast(base + Offsets::get_scheduler); 33 | const auto get_state = reinterpret_cast(base + Offsets::get_state); 34 | const auto luavm_load = reinterpret_cast(base + Offsets::luavm_load); 35 | const auto task_spawn = reinterpret_cast(base + Offsets::task_spawn); 36 | const auto print = reinterpret_cast(base + Offsets::print); 37 | 38 | // Custom functions: 39 | inline void set_identity(uintptr_t state, uint32_t identity) noexcept { 40 | *reinterpret_cast(*reinterpret_cast(state + Offsets::extra_space) + Offsets::identity) = identity; 41 | } 42 | 43 | inline void pop_stack(uintptr_t state, uint8_t amount) noexcept { 44 | *reinterpret_cast(state + Offsets::top) -= 0x10 * amount; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /UWP_Executor/Scheduler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Scheduler.hpp" 5 | #include "Roblox.hpp" 6 | 7 | uintptr_t Scheduler::get_job(const char* job_name) noexcept { 8 | // Get the scheduler. 9 | static auto scheduler = uintptr_t(); 10 | if (!scheduler) 11 | scheduler = Roblox::get_scheduler(); 12 | 13 | // Get the start and end address of the job-vector. 14 | auto jobs_start = *reinterpret_cast(scheduler + 0x134); 15 | const auto jobs_end = *reinterpret_cast(scheduler + 0x138); 16 | 17 | // Loop through the job pointers (each 8 bytes long as they're shared_ptrs). 18 | auto result = uintptr_t(); 19 | for (; jobs_start < jobs_end; jobs_start += 8u) { 20 | const auto job = *reinterpret_cast(jobs_start); 21 | 22 | // If the name matches, set return to job. 23 | if (*reinterpret_cast(job + 0x80) == job_name) 24 | result = job; 25 | } 26 | return result; 27 | } 28 | 29 | uintptr_t Scheduler::get_script_context() { 30 | // Get the WaitingHybridScriptsJob and make sure it was found. 31 | if (const auto job = Scheduler::get_job("WaitingHybridScriptsJob")) 32 | // Return the script context. 33 | return *reinterpret_cast(job + 0x1A8); 34 | else 35 | // If it couldn't find the job, throw an exception. 36 | throw std::runtime_error("Couldn't find WaitingHybridScriptsJob"); 37 | } 38 | -------------------------------------------------------------------------------- /UWP_Executor/Scheduler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Scheduler { 4 | uintptr_t get_job(const char* job_name) noexcept; 5 | 6 | uintptr_t get_script_context(); 7 | }; 8 | -------------------------------------------------------------------------------- /UWP_Executor/UWP_Executor.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Release 6 | Win32 7 | 8 | 9 | 10 | 16.0 11 | Win32Proj 12 | {cc25d15d-c50a-4f64-b65d-c58881b98489} 13 | UWPExecutor 14 | 10.0 15 | 16 | 17 | 18 | DynamicLibrary 19 | false 20 | v143 21 | true 22 | Unicode 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | $(SolutionDir)Build\ 35 | 36 | 37 | 38 | Level3 39 | true 40 | true 41 | true 42 | WIN32;NDEBUG;UWPEXECUTOR_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 43 | true 44 | NotUsing 45 | 46 | 47 | stdcpplatest 48 | $(SolutionDir)Dependencies\zstd\include;$(SolutionDir)Dependencies\luau\include;%(AdditionalIncludeDirectories) 49 | 50 | 51 | Windows 52 | true 53 | true 54 | true 55 | false 56 | $(SolutionDir)Dependencies\zstd\lib;$(SolutionDir)Dependencies\luau\lib 57 | libzstd_static.lib;luau_static.lib;%(AdditionalDependencies) 58 | /NODEFAULTLIB:LIBCMT %(AdditionalOptions) 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /UWP_Executor/UWP_Executor.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Scheduler 7 | 8 | 9 | Execution 10 | 11 | 12 | 13 | 14 | {84c063d0-b89d-4063-9a26-c4ea6b849a3a} 15 | 16 | 17 | {494c74d0-6866-4df9-90a5-4e045e546c14} 18 | 19 | 20 | {ff474c05-2153-4a99-8b23-abdfea3afdf3} 21 | 22 | 23 | 24 | 25 | Scheduler 26 | 27 | 28 | Execution 29 | 30 | 31 | Roblox 32 | 33 | 34 | 35 | --------------------------------------------------------------------------------