diff options
Diffstat (limited to 'src/yue.cpp')
| -rw-r--r-- | src/yue.cpp | 208 |
1 files changed, 144 insertions, 64 deletions
diff --git a/src/yue.cpp b/src/yue.cpp index 2722c55..26f581e 100644 --- a/src/yue.cpp +++ b/src/yue.cpp | |||
| @@ -131,12 +131,10 @@ void pushOptions(lua_State* L, int lineOffset) { | |||
| 131 | #endif // YUE_NO_MACRO | 131 | #endif // YUE_NO_MACRO |
| 132 | 132 | ||
| 133 | #ifndef YUE_COMPILER_ONLY | 133 | #ifndef YUE_COMPILER_ONLY |
| 134 | static const char luaminifyCodes[] = | 134 | #include "luaminify_lua.h" |
| 135 | #include "LuaMinify.h" | ||
| 136 | ; | ||
| 137 | 135 | ||
| 138 | static void pushLuaminify(lua_State* L) { | 136 | static void pushLuaminify(lua_State* L) { |
| 139 | if (luaL_loadbuffer(L, luaminifyCodes, sizeof(luaminifyCodes) / sizeof(luaminifyCodes[0]) - 1, "=(luaminify)") != 0) { | 137 | if (luaL_loadbuffer(L, luaminify_lua, sizeof(luaminify_lua) / sizeof(luaminify_lua[0]), "=(luaminify)") != 0) { |
| 140 | std::string err = "failed to load luaminify module.\n"s + lua_tostring(L, -1); | 138 | std::string err = "failed to load luaminify module.\n"s + lua_tostring(L, -1); |
| 141 | luaL_error(L, err.c_str()); | 139 | luaL_error(L, err.c_str()); |
| 142 | } else if (lua_pcall(L, 0, 1, 0) != 0) { | 140 | } else if (lua_pcall(L, 0, 1, 0) != 0) { |
| @@ -317,32 +315,56 @@ public: | |||
| 317 | 315 | ||
| 318 | int main(int narg, const char** args) { | 316 | int main(int narg, const char** args) { |
| 319 | const char* help = | 317 | const char* help = |
| 320 | "Usage: yue [options|files|directories] ...\n\n" | 318 | "Usage: yue\n" |
| 321 | " -h Print this message\n" | 319 | " [options] [<file/directory>] ...\n" |
| 322 | #ifndef YUE_COMPILER_ONLY | 320 | #ifndef YUE_COMPILER_ONLY |
| 323 | " -e str Execute a file or raw codes\n" | 321 | " yue -e <code_or_file> [args...]\n" |
| 324 | " -m Generate minified codes\n" | ||
| 325 | " -r Rewrite output to match original line numbers\n" | ||
| 326 | #endif // YUE_COMPILER_ONLY | 322 | #endif // YUE_COMPILER_ONLY |
| 327 | " -t path Specify where to place compiled files\n" | ||
| 328 | " -o file Write output to file\n" | ||
| 329 | " -s Use spaces in generated codes instead of tabs\n" | ||
| 330 | " -p Write output to standard out\n" | ||
| 331 | " -b Dump compile time (doesn't write output)\n" | ||
| 332 | " -g Dump global variables used in NAME LINE COLUMN\n" | ||
| 333 | " -l Write line numbers from source codes\n" | ||
| 334 | " -j Disable implicit return at end of file\n" | ||
| 335 | " -c Reserve comments before statement from source codes\n" | ||
| 336 | #ifndef YUE_NO_WATCHER | 323 | #ifndef YUE_NO_WATCHER |
| 337 | " -w path Watch changes and compile every file under directory\n" | 324 | " yue -w [<directory>] [options]\n" |
| 338 | #endif // YUE_NO_WATCHER | 325 | #endif // YUE_NO_WATCHER |
| 339 | " -v Print version\n" | 326 | " yue -\n\n" |
| 327 | "Notes:\n" | ||
| 328 | " - '-' / '--' must be the first and only argument.\n" | ||
| 329 | " - '-o/--output' can not be used with multiple input files.\n" | ||
| 330 | #ifndef YUE_NO_WATCHER | ||
| 331 | " - '-w/--watch' can not be used with file input (directory only).\n" | ||
| 332 | #endif // YUE_NO_WATCHER | ||
| 333 | #ifndef YUE_COMPILER_ONLY | ||
| 334 | " - with '-e/--execute', remaining tokens are treated as script args.\n\n" | ||
| 335 | #else | ||
| 336 | "\n" | ||
| 337 | #endif // YUE_COMPILER_ONLY | ||
| 338 | "Options:\n" | ||
| 339 | " -h, --help Show this help message and exit.\n" | ||
| 340 | #ifndef YUE_COMPILER_ONLY | 340 | #ifndef YUE_COMPILER_ONLY |
| 341 | " -- Read from standard in, print to standard out\n" | 341 | " -e <str>, --execute <str> Execute a file or raw codes\n" |
| 342 | " (Must be first and only argument)\n\n" | 342 | " -m, --minify Generate minified codes\n" |
| 343 | " --target=version Specify the Lua version that codes will be generated to\n" | 343 | " -r, --rewrite Rewrite output to match original line numbers\n" |
| 344 | " (version can only be 5.1 to 5.5)\n" | 344 | #endif // YUE_COMPILER_ONLY |
| 345 | " --path=path_str Append an extra Lua search path string to package.path\n\n" | 345 | " -t <output_to>, --output-to <output_to>\n" |
| 346 | " Specify where to place compiled files\n" | ||
| 347 | " -o <file>, --output <file> Write output to file\n" | ||
| 348 | " -p, --print Write output to standard out\n" | ||
| 349 | " -b, --benchmark Dump compile time (doesn't write output)\n" | ||
| 350 | " -g, --globals Dump global variables used in NAME LINE COLUMN\n" | ||
| 351 | " -s, --spaces Use spaces in generated codes instead of tabs\n" | ||
| 352 | " -l, --line-numbers Write line numbers from source codes\n" | ||
| 353 | " -j, --no-implicit-return Disable implicit return at end of file\n" | ||
| 354 | " -c, --reserve-comments Reserve comments before statement from source codes\n" | ||
| 355 | #ifndef YUE_NO_WATCHER | ||
| 356 | " -w [<dir>], --watch [<dir>]\n" | ||
| 357 | " Watch changes and compile every file under directory\n" | ||
| 358 | #endif // YUE_NO_WATCHER | ||
| 359 | " -v, --version Print version\n" | ||
| 360 | #ifndef YUE_COMPILER_ONLY | ||
| 361 | " - Read from standard in, print to standard out\n" | ||
| 362 | " (Must be first and only argument)\n" | ||
| 363 | " -- Same as '-' (kept for backward compatibility)\n\n" | ||
| 364 | " --target <version> Specify the Lua version that codes will be generated to\n" | ||
| 365 | " (version can only be 5.1 to 5.5)\n" | ||
| 366 | " --path <path_str> Append an extra Lua search path string to package.path\n" | ||
| 367 | " --<key>=<value> Pass compiler option in key=value form (existing behavior)\n\n" | ||
| 346 | " Execute without options to enter REPL, type symbol '$'\n" | 368 | " Execute without options to enter REPL, type symbol '$'\n" |
| 347 | " in a single line to start/stop multi-line mode\n" | 369 | " in a single line to start/stop multi-line mode\n" |
| 348 | #endif // YUE_COMPILER_ONLY | 370 | #endif // YUE_COMPILER_ONLY |
| @@ -446,11 +468,6 @@ int main(int narg, const char** args) { | |||
| 446 | if (err.substr(0, modName.size()) == modName) { | 468 | if (err.substr(0, modName.size()) == modName) { |
| 447 | err = err.substr(modName.size()); | 469 | err = err.substr(modName.size()); |
| 448 | } | 470 | } |
| 449 | auto pos = err.find(':'); | ||
| 450 | if (pos != std::string::npos) { | ||
| 451 | int lineNum = std::stoi(err.substr(0, pos)); | ||
| 452 | err = std::to_string(lineNum - 1) + err.substr(pos); | ||
| 453 | } | ||
| 454 | std::cout << Err << err << Stop; | 471 | std::cout << Err << err << Stop; |
| 455 | continue; | 472 | continue; |
| 456 | } | 473 | } |
| @@ -502,13 +519,35 @@ int main(int narg, const char** args) { | |||
| 502 | std::string resultFile; | 519 | std::string resultFile; |
| 503 | std::string workPath; | 520 | std::string workPath; |
| 504 | std::list<std::pair<std::string, std::string>> files; | 521 | std::list<std::pair<std::string, std::string>> files; |
| 522 | |||
| 523 | auto isOptionToken = [](std::string_view s) { | ||
| 524 | return !s.empty() && (s[0] == '-' || (s.size() >= 2 && s.substr(0, 2) == "--"sv)); | ||
| 525 | }; | ||
| 526 | auto takeValue = [&](int& i, std::string_view arg, std::string_view optName) -> std::string { | ||
| 527 | // supports: --opt=value, --opt value, -o value, -t value, etc. | ||
| 528 | if (auto eq = arg.find('='); eq != std::string_view::npos) { | ||
| 529 | return std::string(arg.substr(eq + 1)); | ||
| 530 | } | ||
| 531 | if (i + 1 < narg) { | ||
| 532 | ++i; | ||
| 533 | return std::string(args[i]); | ||
| 534 | } | ||
| 535 | std::cout << help; | ||
| 536 | (void)optName; | ||
| 537 | return std::string(); | ||
| 538 | }; | ||
| 539 | |||
| 505 | for (int i = 1; i < narg; ++i) { | 540 | for (int i = 1; i < narg; ++i) { |
| 506 | std::string arg = args[i]; | 541 | std::string arg = args[i]; |
| 507 | if (arg == "--"sv) { | 542 | if (arg == "-"sv || arg == "--"sv) { |
| 508 | if (i != 1) { | 543 | if (i != 1) { |
| 509 | std::cout << help; | 544 | std::cout << help; |
| 510 | return 1; | 545 | return 1; |
| 511 | } | 546 | } |
| 547 | if (narg != 2) { | ||
| 548 | std::cout << help; | ||
| 549 | return 1; | ||
| 550 | } | ||
| 512 | char ch; | 551 | char ch; |
| 513 | std::string codes; | 552 | std::string codes; |
| 514 | while ((ch = std::cin.get()) && !std::cin.eof()) { | 553 | while ((ch = std::cin.get()) && !std::cin.eof()) { |
| @@ -529,9 +568,9 @@ int main(int narg, const char** args) { | |||
| 529 | return 1; | 568 | return 1; |
| 530 | } | 569 | } |
| 531 | #ifndef YUE_COMPILER_ONLY | 570 | #ifndef YUE_COMPILER_ONLY |
| 532 | } else if (arg == "-e"sv) { | 571 | } else if (arg == "-e"sv || arg == "--execute"sv || arg.rfind("--execute="sv, 0) == 0) { |
| 533 | ++i; | 572 | auto evalStr = takeValue(i, arg, "execute"sv); |
| 534 | if (i < narg) { | 573 | if (!evalStr.empty()) { |
| 535 | lua_State* L = luaL_newstate(); | 574 | lua_State* L = luaL_newstate(); |
| 536 | openlibs(L); | 575 | openlibs(L); |
| 537 | DEFER(lua_close(L)); | 576 | DEFER(lua_close(L)); |
| @@ -540,7 +579,6 @@ int main(int narg, const char** args) { | |||
| 540 | std::cout << lua_tostring(L, -1) << '\n'; | 579 | std::cout << lua_tostring(L, -1) << '\n'; |
| 541 | return 1; | 580 | return 1; |
| 542 | } | 581 | } |
| 543 | std::string evalStr = args[i]; | ||
| 544 | lua_newtable(L); | 582 | lua_newtable(L); |
| 545 | i++; | 583 | i++; |
| 546 | for (int j = i, index = 1; j < narg; j++) { | 584 | for (int j = i, index = 1; j < narg; j++) { |
| @@ -623,58 +661,100 @@ int main(int narg, const char** args) { | |||
| 623 | } | 661 | } |
| 624 | return 0; | 662 | return 0; |
| 625 | } else { | 663 | } else { |
| 626 | std::cout << help; | ||
| 627 | return 1; | 664 | return 1; |
| 628 | } | 665 | } |
| 629 | } else if (arg == "-m"sv) { | 666 | } else if (arg == "-m"sv || arg == "--minify"sv) { |
| 630 | minify = true; | 667 | minify = true; |
| 631 | } else if (arg == "-r"sv) { | 668 | } else if (arg == "-r"sv || arg == "--rewrite"sv) { |
| 632 | rewrite = true; | 669 | rewrite = true; |
| 633 | #endif // YUE_COMPILER_ONLY | 670 | #endif // YUE_COMPILER_ONLY |
| 634 | } else if (arg == "-s"sv) { | 671 | } else if (arg == "-s"sv || arg == "--spaces"sv) { |
| 635 | config.useSpaceOverTab = true; | 672 | config.useSpaceOverTab = true; |
| 636 | } else if (arg == "-l"sv) { | 673 | } else if (arg == "-l"sv || arg == "--line-numbers"sv) { |
| 637 | config.reserveLineNumber = true; | 674 | config.reserveLineNumber = true; |
| 638 | } else if (arg == "-c"sv) { | 675 | } else if (arg == "-c"sv || arg == "--reserve-comments"sv) { |
| 639 | config.reserveComment = true; | 676 | config.reserveComment = true; |
| 640 | } else if (arg == "-j"sv) { | 677 | } else if (arg == "-j"sv || arg == "--no-implicit-return"sv) { |
| 641 | config.implicitReturnRoot = false; | 678 | config.implicitReturnRoot = false; |
| 642 | } else if (arg == "-p"sv) { | 679 | } else if (arg == "-p"sv || arg == "--print"sv) { |
| 643 | writeToFile = false; | 680 | writeToFile = false; |
| 644 | } else if (arg == "-g"sv) { | 681 | } else if (arg == "-g"sv || arg == "--globals"sv) { |
| 645 | writeToFile = false; | 682 | writeToFile = false; |
| 646 | lintGlobal = true; | 683 | lintGlobal = true; |
| 647 | } else if (arg == "-t"sv) { | 684 | } else if (arg == "-t"sv || arg == "--output-to"sv || arg.rfind("--output-to="sv, 0) == 0) { |
| 648 | ++i; | 685 | targetPath = takeValue(i, arg, "output-to"sv); |
| 649 | if (i < narg) { | 686 | if (targetPath.empty()) return 1; |
| 650 | targetPath = args[i]; | 687 | } else if (arg == "-b"sv || arg == "--benchmark"sv) { |
| 651 | } else { | ||
| 652 | std::cout << help; | ||
| 653 | return 1; | ||
| 654 | } | ||
| 655 | } else if (arg == "-b"sv) { | ||
| 656 | dumpCompileTime = true; | 688 | dumpCompileTime = true; |
| 657 | } else if (arg == "-h"sv) { | 689 | } else if (arg == "-h"sv || arg == "--help"sv) { |
| 658 | std::cout << help; | 690 | std::cout << help; |
| 659 | return 0; | 691 | return 0; |
| 660 | } else if (arg == "-v"sv) { | 692 | } else if (arg == "-v"sv || arg == "--version"sv) { |
| 661 | std::cout << "Yuescript version: "sv << yue::version << '\n'; | 693 | std::cout << "Yuescript version: "sv << yue::version << '\n'; |
| 662 | return 0; | 694 | return 0; |
| 663 | } else if (arg == "-o"sv) { | 695 | } else if (arg == "-o"sv || arg == "--output"sv || arg.rfind("--output="sv, 0) == 0) { |
| 664 | ++i; | 696 | resultFile = takeValue(i, arg, "output"sv); |
| 665 | if (i < narg) { | 697 | if (resultFile.empty()) return 1; |
| 666 | resultFile = args[i]; | 698 | } else if (arg == "-w"sv || arg == "--watch"sv || arg.rfind("--watch="sv, 0) == 0) { |
| 667 | } else { | ||
| 668 | std::cout << help; | ||
| 669 | return 1; | ||
| 670 | } | ||
| 671 | } else if (arg == "-w"sv) { | ||
| 672 | #ifndef YUE_NO_WATCHER | 699 | #ifndef YUE_NO_WATCHER |
| 673 | watchFiles = true; | 700 | watchFiles = true; |
| 701 | // accept optional directory value: -w <dir> / --watch <dir> / --watch=<dir> | ||
| 702 | if (arg != "-w"sv) { | ||
| 703 | auto watchDir = takeValue(i, arg, "watch"sv); | ||
| 704 | if (watchDir.empty()) return 1; | ||
| 705 | arg = watchDir; | ||
| 706 | // fall through to directory/file handling below by re-processing as positional | ||
| 707 | if (fs::is_directory(arg)) { | ||
| 708 | workPath = arg; | ||
| 709 | for (auto item : fs::recursive_directory_iterator(arg)) { | ||
| 710 | if (!item.is_directory()) { | ||
| 711 | auto ext = item.path().extension().string(); | ||
| 712 | for (char& ch : ext) ch = std::tolower(ch); | ||
| 713 | if (!ext.empty() && ext.substr(1) == yue::extension) { | ||
| 714 | files.emplace_back(item.path().string(), item.path().lexically_relative(arg).string()); | ||
| 715 | } | ||
| 716 | } | ||
| 717 | } | ||
| 718 | } else if (!arg.empty()) { | ||
| 719 | std::cout << help; | ||
| 720 | return 1; | ||
| 721 | } | ||
| 722 | continue; | ||
| 723 | } else if (i + 1 < narg && !isOptionToken(args[i + 1])) { | ||
| 724 | // support -w <dir> while keeping old "-w <dir as positional>" behavior | ||
| 725 | auto watchDir = takeValue(i, arg, "watch"sv); | ||
| 726 | if (!watchDir.empty()) { | ||
| 727 | arg = watchDir; | ||
| 728 | if (fs::is_directory(arg)) { | ||
| 729 | workPath = arg; | ||
| 730 | for (auto item : fs::recursive_directory_iterator(arg)) { | ||
| 731 | if (!item.is_directory()) { | ||
| 732 | auto ext = item.path().extension().string(); | ||
| 733 | for (char& ch : ext) ch = std::tolower(ch); | ||
| 734 | if (!ext.empty() && ext.substr(1) == yue::extension) { | ||
| 735 | files.emplace_back(item.path().string(), item.path().lexically_relative(arg).string()); | ||
| 736 | } | ||
| 737 | } | ||
| 738 | } | ||
| 739 | } else { | ||
| 740 | std::cout << help; | ||
| 741 | return 1; | ||
| 742 | } | ||
| 743 | continue; | ||
| 744 | } | ||
| 745 | } | ||
| 674 | #else | 746 | #else |
| 675 | std::cout << "Error: -w is not supported\n"sv; | 747 | std::cout << "Error: -w is not supported\n"sv; |
| 676 | return 1; | 748 | return 1; |
| 677 | #endif // YUE_NO_WATCHER | 749 | #endif // YUE_NO_WATCHER |
| 750 | } else if (arg == "--target"sv || arg.rfind("--target="sv, 0) == 0) { | ||
| 751 | auto v = takeValue(i, arg, "target"sv); | ||
| 752 | if (v.empty()) return 1; | ||
| 753 | config.options["target"s] = v; | ||
| 754 | } else if (arg == "--path"sv || arg.rfind("--path="sv, 0) == 0) { | ||
| 755 | auto v = takeValue(i, arg, "path"sv); | ||
| 756 | if (v.empty()) return 1; | ||
| 757 | config.options["path"s] = v; | ||
| 678 | } else if (arg.size() > 2 && arg.substr(0, 2) == "--"sv && arg.substr(2, 1) != "-"sv) { | 758 | } else if (arg.size() > 2 && arg.substr(0, 2) == "--"sv && arg.substr(2, 1) != "-"sv) { |
| 679 | auto argStr = arg.substr(2); | 759 | auto argStr = arg.substr(2); |
| 680 | yue::Utils::trim(argStr); | 760 | yue::Utils::trim(argStr); |
