diff options
author | Li Jin <dragon-fly@qq.com> | 2025-07-17 18:02:39 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2025-07-17 18:02:39 +0800 |
commit | c03bf36db11bcd90034b0e67bd1f5c8c0765eb7f (patch) | |
tree | 18d18739cb2b99600f0d93fb9d8e7097a8584a7e /src | |
parent | 281149d74af1d218cc43fe57b1d68d3759ce6d0c (diff) | |
download | yuescript-c03bf36db11bcd90034b0e67bd1f5c8c0765eb7f.tar.gz yuescript-c03bf36db11bcd90034b0e67bd1f5c8c0765eb7f.tar.bz2 yuescript-c03bf36db11bcd90034b0e67bd1f5c8c0765eb7f.zip |
Added YAML multiline string and macro argument checking.
Diffstat (limited to 'src')
-rw-r--r-- | src/yuescript/yue_ast.cpp | 24 | ||||
-rw-r--r-- | src/yuescript/yue_ast.h | 28 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 142 | ||||
-rw-r--r-- | src/yuescript/yue_parser.cpp | 34 | ||||
-rw-r--r-- | src/yuescript/yue_parser.h | 5 |
5 files changed, 221 insertions, 12 deletions
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index da99d07..bacdc01 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp | |||
@@ -962,6 +962,30 @@ std::string DoubleString_t::to_string(void* ud) const { | |||
962 | } | 962 | } |
963 | return '"' + join(temp) + '"'; | 963 | return '"' + join(temp) + '"'; |
964 | } | 964 | } |
965 | std::string YAMLLineInner_t::to_string(void* ud) const { | ||
966 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
967 | return info->convert(this); | ||
968 | } | ||
969 | std::string YAMLLineContent_t::to_string(void* ud) const { | ||
970 | if (content.is<Exp_t>()) { | ||
971 | return "#{"s + content->to_string(ud) + '}'; | ||
972 | } | ||
973 | return content->to_string(ud); | ||
974 | } | ||
975 | std::string YAMLLine_t::to_string(void* ud) const { | ||
976 | str_list temp; | ||
977 | for (auto seg : segments.objects()) { | ||
978 | temp.emplace_back(seg->to_string(ud)); | ||
979 | } | ||
980 | return join(temp); | ||
981 | } | ||
982 | std::string YAMLMultiline_t::to_string(void* ud) const { | ||
983 | str_list temp; | ||
984 | for (auto seg : lines.objects()) { | ||
985 | temp.emplace_back(seg->to_string(ud)); | ||
986 | } | ||
987 | return "|\n" + join(temp, "\n"sv); | ||
988 | } | ||
965 | std::string String_t::to_string(void* ud) const { | 989 | std::string String_t::to_string(void* ud) const { |
966 | return str->to_string(ud); | 990 | return str->to_string(ud); |
967 | } | 991 | } |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index d396d82..c529f34 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -591,8 +591,28 @@ AST_NODE(DoubleString) | |||
591 | AST_MEMBER(DoubleString, &sep, &segments) | 591 | AST_MEMBER(DoubleString, &sep, &segments) |
592 | AST_END(DoubleString) | 592 | AST_END(DoubleString) |
593 | 593 | ||
594 | AST_LEAF(YAMLLineInner) | ||
595 | AST_END(YAMLLineInner) | ||
596 | |||
597 | AST_NODE(YAMLLineContent) | ||
598 | ast_sel<true, YAMLLineInner_t, Exp_t> content; | ||
599 | AST_MEMBER(YAMLLineContent, &content) | ||
600 | AST_END(YAMLLineContent) | ||
601 | |||
602 | AST_NODE(YAMLLine) | ||
603 | ast_ptr<true, Seperator_t> sep; | ||
604 | ast_list<false, YAMLLineContent_t> segments; | ||
605 | AST_MEMBER(YAMLLine, &sep, &segments) | ||
606 | AST_END(YAMLLine) | ||
607 | |||
608 | AST_NODE(YAMLMultiline) | ||
609 | ast_ptr<true, Seperator_t> sep; | ||
610 | ast_list<true, YAMLLine_t> lines; | ||
611 | AST_MEMBER(YAMLMultiline, &sep, &lines) | ||
612 | AST_END(YAMLMultiline) | ||
613 | |||
594 | AST_NODE(String) | 614 | AST_NODE(String) |
595 | ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; | 615 | ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str; |
596 | AST_MEMBER(String, &str) | 616 | AST_MEMBER(String, &str) |
597 | AST_END(String) | 617 | AST_END(String) |
598 | 618 | ||
@@ -752,15 +772,17 @@ AST_END(Export) | |||
752 | AST_NODE(FnArgDef) | 772 | AST_NODE(FnArgDef) |
753 | ast_sel<true, Variable_t, SelfItem_t> name; | 773 | ast_sel<true, Variable_t, SelfItem_t> name; |
754 | ast_ptr<false, ExistentialOp_t> op; | 774 | ast_ptr<false, ExistentialOp_t> op; |
775 | ast_ptr<false, Name_t> label; | ||
755 | ast_ptr<false, Exp_t> defaultValue; | 776 | ast_ptr<false, Exp_t> defaultValue; |
756 | AST_MEMBER(FnArgDef, &name, &op, &defaultValue) | 777 | AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue) |
757 | AST_END(FnArgDef) | 778 | AST_END(FnArgDef) |
758 | 779 | ||
759 | AST_NODE(FnArgDefList) | 780 | AST_NODE(FnArgDefList) |
760 | ast_ptr<true, Seperator_t> sep; | 781 | ast_ptr<true, Seperator_t> sep; |
761 | ast_list<false, FnArgDef_t> definitions; | 782 | ast_list<false, FnArgDef_t> definitions; |
762 | ast_ptr<false, VarArg_t> varArg; | 783 | ast_ptr<false, VarArg_t> varArg; |
763 | AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) | 784 | ast_ptr<false, Name_t> label; |
785 | AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label) | ||
764 | AST_END(FnArgDefList) | 786 | AST_END(FnArgDefList) |
765 | 787 | ||
766 | AST_NODE(OuterVarShadow) | 788 | AST_NODE(OuterVarShadow) |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 9f5a41e..35d99bd 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
78 | "close"s // Lua 5.4 | 78 | "close"s // Lua 5.4 |
79 | }; | 79 | }; |
80 | 80 | ||
81 | const std::string_view version = "0.29.0"sv; | 81 | const std::string_view version = "0.29.1"sv; |
82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
83 | 83 | ||
84 | class CompileError : public std::logic_error { | 84 | class CompileError : public std::logic_error { |
@@ -5418,18 +5418,29 @@ private: | |||
5418 | auto macroLit = macro->decl.to<MacroLit_t>(); | 5418 | auto macroLit = macro->decl.to<MacroLit_t>(); |
5419 | auto argsDef = macroLit->argsDef.get(); | 5419 | auto argsDef = macroLit->argsDef.get(); |
5420 | str_list newArgs; | 5420 | str_list newArgs; |
5421 | str_list argChecks; | ||
5422 | bool hasCheck = false; | ||
5421 | if (argsDef) { | 5423 | if (argsDef) { |
5422 | for (auto def_ : argsDef->definitions.objects()) { | 5424 | for (auto def_ : argsDef->definitions.objects()) { |
5423 | auto def = static_cast<FnArgDef_t*>(def_); | 5425 | auto def = static_cast<FnArgDef_t*>(def_); |
5424 | if (def->name.is<SelfItem_t>()) { | 5426 | if (def->name.is<SelfItem_t>()) { |
5425 | throw CompileError("self name is not supported for macro function argument"sv, def->name); | 5427 | throw CompileError("self name is not supported for macro function argument"sv, def->name); |
5426 | } else { | 5428 | } else { |
5429 | if (def->op) throw CompileError("invalid existence checking"sv, def->op); | ||
5430 | if (def->label) { | ||
5431 | hasCheck = true; | ||
5432 | const auto& astName = argChecks.emplace_back(_parser.toString(def->label)); | ||
5433 | if (!_parser.hasAST(astName)) { | ||
5434 | throw CompileError("invalid AST name"sv, def->label); | ||
5435 | } | ||
5436 | } else { | ||
5437 | argChecks.emplace_back(); | ||
5438 | } | ||
5427 | std::string defVal; | 5439 | std::string defVal; |
5428 | if (def->defaultValue) { | 5440 | if (def->defaultValue) { |
5429 | defVal = _parser.toString(def->defaultValue); | 5441 | defVal = _parser.toString(def->defaultValue); |
5430 | Utils::trim(defVal); | 5442 | Utils::trim(defVal); |
5431 | defVal.insert(0, "=[==========["sv); | 5443 | defVal = '=' + Utils::toLuaString(defVal); |
5432 | defVal.append("]==========]"sv); | ||
5433 | } | 5444 | } |
5434 | newArgs.emplace_back(_parser.toString(def->name) + defVal); | 5445 | newArgs.emplace_back(_parser.toString(def->name) + defVal); |
5435 | } | 5446 | } |
@@ -5438,6 +5449,14 @@ private: | |||
5438 | newArgs.emplace_back(_parser.toString(argsDef->varArg)); | 5449 | newArgs.emplace_back(_parser.toString(argsDef->varArg)); |
5439 | } | 5450 | } |
5440 | } | 5451 | } |
5452 | if (argsDef->label) { | ||
5453 | hasCheck = true; | ||
5454 | const auto& astName = _parser.toString(argsDef->label); | ||
5455 | if (!_parser.hasAST(astName)) { | ||
5456 | throw CompileError("invalid AST name"sv, argsDef->label); | ||
5457 | } | ||
5458 | argChecks.emplace_back("..."s + astName); | ||
5459 | } | ||
5441 | std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); | 5460 | std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); |
5442 | auto chunkName = "=(macro "s + macroName + ')'; | 5461 | auto chunkName = "=(macro "s + macroName + ')'; |
5443 | pushCurrentModule(); // cur | 5462 | pushCurrentModule(); // cur |
@@ -5467,6 +5486,24 @@ private: | |||
5467 | throw CompileError("failed to generate macro function\n"s + err, macroLit); | 5486 | throw CompileError("failed to generate macro function\n"s + err, macroLit); |
5468 | } // cur true macro | 5487 | } // cur true macro |
5469 | lua_remove(L, -2); // cur macro | 5488 | lua_remove(L, -2); // cur macro |
5489 | if (hasCheck) { | ||
5490 | lua_createtable(L, 0, 0); // cur macro checks | ||
5491 | int i = 1; | ||
5492 | for (const auto& check : argChecks) { | ||
5493 | if (check.empty()) { | ||
5494 | lua_pushboolean(L, 0); | ||
5495 | lua_rawseti(L, -2, i); | ||
5496 | } else { | ||
5497 | lua_pushlstring(L, check.c_str(), check.size()); | ||
5498 | lua_rawseti(L, -2, i); | ||
5499 | } | ||
5500 | i++; | ||
5501 | } | ||
5502 | lua_createtable(L, 2, 0); // cur macro checks macrotab | ||
5503 | lua_insert(L, -3); // cur macrotab macro checks | ||
5504 | lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro | ||
5505 | lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab | ||
5506 | } // cur macro | ||
5470 | if (exporting && _config.exporting && !_config.module.empty()) { | 5507 | if (exporting && _config.exporting && !_config.module.empty()) { |
5471 | pushModuleTable(_config.module); // cur macro module | 5508 | pushModuleTable(_config.module); // cur macro module |
5472 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name | 5509 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name |
@@ -5624,7 +5661,11 @@ private: | |||
5624 | auto def = static_cast<FnArgDef_t*>(_def); | 5661 | auto def = static_cast<FnArgDef_t*>(_def); |
5625 | auto& arg = argItems.emplace_back(); | 5662 | auto& arg = argItems.emplace_back(); |
5626 | switch (def->name->get_id()) { | 5663 | switch (def->name->get_id()) { |
5627 | case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; | 5664 | case id<Variable_t>(): { |
5665 | if (def->op) throw CompileError("invalid existence checking"sv, def->op); | ||
5666 | arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); | ||
5667 | break; | ||
5668 | } | ||
5628 | case id<SelfItem_t>(): { | 5669 | case id<SelfItem_t>(): { |
5629 | assignSelf = true; | 5670 | assignSelf = true; |
5630 | if (def->op) { | 5671 | if (def->op) { |
@@ -6748,7 +6789,25 @@ private: | |||
6748 | break; | 6789 | break; |
6749 | } | 6790 | } |
6750 | } | 6791 | } |
6751 | if (!lua_isfunction(L, -1)) { | 6792 | str_list checks; |
6793 | if (lua_istable(L, -1)) { | ||
6794 | lua_rawgeti(L, -1, 1); // cur macrotab checks | ||
6795 | int len = lua_objlen(L, -1); | ||
6796 | for (int i = 1; i <= len; i++) { | ||
6797 | lua_rawgeti(L, -1, i); | ||
6798 | if (lua_toboolean(L, -1) == 0) { | ||
6799 | checks.emplace_back(); | ||
6800 | } else { | ||
6801 | size_t str_len = 0; | ||
6802 | auto str = lua_tolstring(L, -1, &str_len); | ||
6803 | checks.emplace_back(std::string{str, str_len}); | ||
6804 | } | ||
6805 | lua_pop(L, 1); | ||
6806 | } | ||
6807 | lua_pop(L, 1); | ||
6808 | lua_rawgeti(L, -1, 2); // cur macrotab macroFunc | ||
6809 | lua_remove(L, -2); // cur macroFunc | ||
6810 | } else if (!lua_isfunction(L, -1)) { | ||
6752 | auto code = expandBuiltinMacro(macroName, x); | 6811 | auto code = expandBuiltinMacro(macroName, x); |
6753 | if (!code.empty()) return code; | 6812 | if (!code.empty()) return code; |
6754 | if (macroName == "is_ast"sv) { | 6813 | if (macroName == "is_ast"sv) { |
@@ -6796,8 +6855,31 @@ private: | |||
6796 | if (!lua_checkstack(L, argStrs.size())) { | 6855 | if (!lua_checkstack(L, argStrs.size())) { |
6797 | throw CompileError("too much macro params"s, x); | 6856 | throw CompileError("too much macro params"s, x); |
6798 | } | 6857 | } |
6858 | auto checkIt = checks.begin(); | ||
6859 | node_container::const_iterator argIt; | ||
6860 | if (args) { | ||
6861 | argIt = args->begin(); | ||
6862 | } | ||
6799 | for (const auto& arg : argStrs) { | 6863 | for (const auto& arg : argStrs) { |
6864 | if (checkIt != checks.end()) { | ||
6865 | if (checkIt->empty()) { | ||
6866 | ++checkIt; | ||
6867 | } else { | ||
6868 | if ((*checkIt)[0] == '.') { | ||
6869 | auto astName = checkIt->substr(3); | ||
6870 | if (!_parser.match(astName, arg)) { | ||
6871 | throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt); | ||
6872 | } | ||
6873 | } else { | ||
6874 | if (!_parser.match(*checkIt, arg)) { | ||
6875 | throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt); | ||
6876 | } | ||
6877 | ++checkIt; | ||
6878 | } | ||
6879 | } | ||
6880 | } | ||
6800 | lua_pushlstring(L, arg.c_str(), arg.size()); | 6881 | lua_pushlstring(L, arg.c_str(), arg.size()); |
6882 | ++argIt; | ||
6801 | } // cur pcall macroFunc args... | 6883 | } // cur pcall macroFunc args... |
6802 | bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; | 6884 | bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; |
6803 | if (!success) { // cur err | 6885 | if (!success) { // cur err |
@@ -9096,12 +9178,62 @@ private: | |||
9096 | out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); | 9178 | out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); |
9097 | } | 9179 | } |
9098 | 9180 | ||
9181 | void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) { | ||
9182 | std::optional<std::string_view> indent; | ||
9183 | str_list temp; | ||
9184 | for (auto line_ : multiline->lines.objects()) { | ||
9185 | auto line = static_cast<YAMLLine_t*>(line_); | ||
9186 | if (!line->segments.empty()) { | ||
9187 | str_list segs; | ||
9188 | for (auto seg_ : line->segments.objects()) { | ||
9189 | auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get(); | ||
9190 | switch (content->get_id()) { | ||
9191 | case id<YAMLLineInner_t>(): { | ||
9192 | auto str = _parser.toString(content); | ||
9193 | Utils::replace(str, "\r\n"sv, "\n"sv); | ||
9194 | Utils::replace(str, "\n"sv, "\\n"sv); | ||
9195 | Utils::replace(str, "\\#"sv, "#"sv); | ||
9196 | segs.push_back('\"' + str + '\"'); | ||
9197 | break; | ||
9198 | } | ||
9199 | case id<Exp_t>(): { | ||
9200 | transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure); | ||
9201 | segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')'; | ||
9202 | break; | ||
9203 | } | ||
9204 | default: YUEE("AST node mismatch", content); break; | ||
9205 | } | ||
9206 | } | ||
9207 | auto lineStr = join(segs, " .. "sv); | ||
9208 | if (!indent) { | ||
9209 | auto pos = lineStr.find_first_not_of("\t "sv, 1); | ||
9210 | if (pos == std::string::npos) { | ||
9211 | throw CompileError("expecting first line indent"sv, line); | ||
9212 | } | ||
9213 | indent = std::string_view{lineStr.c_str(), pos}; | ||
9214 | } else { | ||
9215 | if (std::string_view{lineStr}.substr(0, indent.value().size()) != indent.value()) { | ||
9216 | throw CompileError("inconsistent indent"sv, line); | ||
9217 | } | ||
9218 | } | ||
9219 | lineStr = '"' + lineStr.substr(indent.value().size()); | ||
9220 | temp.push_back(lineStr); | ||
9221 | } | ||
9222 | } | ||
9223 | auto str = join(temp, " .. '\\n' .. "sv); | ||
9224 | Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv); | ||
9225 | Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv); | ||
9226 | Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv); | ||
9227 | out.push_back(str); | ||
9228 | } | ||
9229 | |||
9099 | void transformString(String_t* string, str_list& out) { | 9230 | void transformString(String_t* string, str_list& out) { |
9100 | auto str = string->str.get(); | 9231 | auto str = string->str.get(); |
9101 | switch (str->get_id()) { | 9232 | switch (str->get_id()) { |
9102 | case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; | 9233 | case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; |
9103 | case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; | 9234 | case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; |
9104 | case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; | 9235 | case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; |
9236 | case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break; | ||
9105 | default: YUEE("AST node mismatch", str); break; | 9237 | default: YUEE("AST node mismatch", str); break; |
9106 | } | 9238 | } |
9107 | } | 9239 | } |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 1011a49..eebc676 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
@@ -639,7 +639,15 @@ YueParser::YueParser() { | |||
639 | DoubleStringInner = +(not_("#{") >> double_string_plain); | 639 | DoubleStringInner = +(not_("#{") >> double_string_plain); |
640 | DoubleStringContent = DoubleStringInner | interp; | 640 | DoubleStringContent = DoubleStringInner | interp; |
641 | DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; | 641 | DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; |
642 | String = DoubleString | SingleString | LuaString; | 642 | |
643 | YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char); | ||
644 | YAMLLineContent = YAMLLineInner | interp; | ||
645 | YAMLLine = check_indent_match >> Seperator >> +YAMLLineContent | | ||
646 | advance_match >> Seperator >> ensure(+YAMLLineContent, pop_indent) | | ||
647 | Seperator >> *set(" \t") >> and_(line_break); | ||
648 | YAMLMultiline = '|' >> Seperator >> +space_break >> advance_match >> ensure(YAMLLine >> *(*set(" \t") >> line_break >> YAMLLine), pop_indent); | ||
649 | |||
650 | String = DoubleString | SingleString | LuaString | YAMLMultiline; | ||
643 | 651 | ||
644 | lua_string_open = '[' >> *expr('=') >> '['; | 652 | lua_string_open = '[' >> *expr('=') >> '['; |
645 | lua_string_close = ']' >> *expr('=') >> ']'; | 653 | lua_string_close = ']' >> *expr('=') >> ']'; |
@@ -883,11 +891,11 @@ YueParser::YueParser() { | |||
883 | 891 | ||
884 | fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); | 892 | fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); |
885 | 893 | ||
886 | FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); | 894 | FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp); |
887 | 895 | ||
888 | FnArgDefList = Seperator >> ( | 896 | FnArgDefList = Seperator >> ( |
889 | fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) | | 897 | fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg >> -(space >> '`' >> space >> Name)) | |
890 | white >> VarArg | 898 | white >> VarArg >> -(space >> '`' >> space >> Name) |
891 | ); | 899 | ); |
892 | 900 | ||
893 | OuterVarShadow = key("using") >> space >> (NameList | key("nil")); | 901 | OuterVarShadow = key("using") >> space >> (NameList | key("nil")); |
@@ -1176,6 +1184,24 @@ void trim(std::string& str) { | |||
1176 | str.erase(0, str.find_first_not_of(" \t\r\n")); | 1184 | str.erase(0, str.find_first_not_of(" \t\r\n")); |
1177 | str.erase(str.find_last_not_of(" \t\r\n") + 1); | 1185 | str.erase(str.find_last_not_of(" \t\r\n") + 1); |
1178 | } | 1186 | } |
1187 | |||
1188 | std::string toLuaString(const std::string& input) { | ||
1189 | std::string luaStr = "\""; | ||
1190 | for (char c : input) { | ||
1191 | switch (c) { | ||
1192 | case '\"': luaStr += "\\\""; break; | ||
1193 | case '\\': luaStr += "\\\\"; break; | ||
1194 | case '\n': luaStr += "\\n"; break; | ||
1195 | case '\r': luaStr += "\\r"; break; | ||
1196 | case '\t': luaStr += "\\t"; break; | ||
1197 | default: | ||
1198 | luaStr += c; | ||
1199 | break; | ||
1200 | } | ||
1201 | } | ||
1202 | luaStr += "\""; | ||
1203 | return luaStr; | ||
1204 | } | ||
1179 | } // namespace Utils | 1205 | } // namespace Utils |
1180 | 1206 | ||
1181 | std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { | 1207 | std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 1057626..15f9277 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
@@ -378,6 +378,10 @@ private: | |||
378 | AST_RULE(DoubleStringInner); | 378 | AST_RULE(DoubleStringInner); |
379 | AST_RULE(DoubleStringContent); | 379 | AST_RULE(DoubleStringContent); |
380 | AST_RULE(DoubleString); | 380 | AST_RULE(DoubleString); |
381 | AST_RULE(YAMLLineInner); | ||
382 | AST_RULE(YAMLLineContent); | ||
383 | AST_RULE(YAMLLine); | ||
384 | AST_RULE(YAMLMultiline); | ||
381 | AST_RULE(String); | 385 | AST_RULE(String); |
382 | AST_RULE(Parens); | 386 | AST_RULE(Parens); |
383 | AST_RULE(DotChainItem); | 387 | AST_RULE(DotChainItem); |
@@ -453,6 +457,7 @@ private: | |||
453 | namespace Utils { | 457 | namespace Utils { |
454 | void replace(std::string& str, std::string_view from, std::string_view to); | 458 | void replace(std::string& str, std::string_view from, std::string_view to); |
455 | void trim(std::string& str); | 459 | void trim(std::string& str); |
460 | std::string toLuaString(const std::string& input); | ||
456 | } // namespace Utils | 461 | } // namespace Utils |
457 | 462 | ||
458 | } // namespace yue | 463 | } // namespace yue |