summaryrefslogtreecommitdiff
path: root/src/yue.cpp
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2026-01-21 10:05:19 +0800
committerLi Jin <dragon-fly@qq.com>2026-01-21 10:05:19 +0800
commit604a8e5e53cdc7391a502fcabf07e8f1cc2a778c (patch)
tree18dca1f8314fe918d6173ed4acbdc84c5b541752 /src/yue.cpp
parentc6229c02564024d8c02c2d438b2fc180ce4c6bcf (diff)
downloadyuescript-0.32.3.tar.gz
yuescript-0.32.3.tar.bz2
yuescript-0.32.3.zip
Diffstat (limited to '')
-rw-r--r--src/yue.cpp208
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
134static const char luaminifyCodes[] = 134#include "luaminify_lua.h"
135#include "LuaMinify.h"
136 ;
137 135
138static void pushLuaminify(lua_State* L) { 136static 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
318int main(int narg, const char** args) { 316int 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);