aboutsummaryrefslogtreecommitdiff
path: root/src/MoonP/moon_compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/MoonP/moon_compiler.cpp')
-rw-r--r--src/MoonP/moon_compiler.cpp198
1 files changed, 160 insertions, 38 deletions
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp
index debc43a..f24441f 100644
--- a/src/MoonP/moon_compiler.cpp
+++ b/src/MoonP/moon_compiler.cpp
@@ -53,7 +53,7 @@ inline std::string s(std::string_view sv) {
53 return std::string(sv); 53 return std::string(sv);
54} 54}
55 55
56const std::string_view version = "0.4.18"sv; 56const std::string_view version = "0.4.19"sv;
57const std::string_view extension = "mp"sv; 57const std::string_view extension = "mp"sv;
58 58
59class MoonCompilerImpl { 59class MoonCompilerImpl {
@@ -89,10 +89,17 @@ public:
89 } 89 }
90#endif // MOONP_NO_MACRO 90#endif // MOONP_NO_MACRO
91 91
92 std::tuple<std::string,std::string,GlobalVars> compile(std::string_view codes, const MoonConfig& config) { 92 CompileInfo compile(std::string_view codes, const MoonConfig& config) {
93 _config = config; 93 _config = config;
94#ifndef MOONP_NO_MACRO
95 if (L) passOptions();
96#endif // MOONP_NO_MACRO
94 _info = _parser.parse<File_t>(codes); 97 _info = _parser.parse<File_t>(codes);
95 GlobalVars globals; 98 std::unique_ptr<GlobalVars> globals;
99 std::unique_ptr<Options> options;
100 if (!config.options.empty()) {
101 options = std::make_unique<Options>(config.options);
102 }
96 DEFER(clear()); 103 DEFER(clear());
97 if (_info.node) { 104 if (_info.node) {
98 try { 105 try {
@@ -104,19 +111,39 @@ public:
104 nullptr, true); 111 nullptr, true);
105 popScope(); 112 popScope();
106 if (config.lintGlobalVariable) { 113 if (config.lintGlobalVariable) {
107 globals = std::make_unique<std::list<GlobalVar>>(); 114 globals = std::make_unique<GlobalVars>();
108 for (const auto& var : _globals) { 115 for (const auto& var : _globals) {
109 int line,col; 116 int line,col;
110 std::tie(line,col) = var.second; 117 std::tie(line,col) = var.second;
111 globals->push_back({var.first, line, col}); 118 globals->push_back({var.first, line, col});
112 } 119 }
113 } 120 }
114 return {std::move(out.back()), Empty, std::move(globals)}; 121#ifndef MOONP_NO_MACRO
122 if (L) {
123 int top = lua_gettop(L);
124 DEFER(lua_settop(L, top));
125 if (!options) {
126 options = std::make_unique<Options>();
127 }
128 pushMoonp("options"sv);
129 lua_pushnil(L); // options startKey
130 while (lua_next(L, -2) != 0) { // options key value
131 size_t len = 0;
132 auto pstr = lua_tolstring(L, -2, &len);
133 std::string key{pstr, len};
134 pstr = lua_tolstring(L, -1, &len);
135 std::string value{pstr, len};
136 (*options)[key] = value;
137 lua_pop(L, 1); // options key
138 }
139 }
140#endif // MOONP_NO_MACRO
141 return {std::move(out.back()), Empty, std::move(globals), std::move(options)};
115 } catch (const std::logic_error& error) { 142 } catch (const std::logic_error& error) {
116 return {Empty, error.what(), std::move(globals)}; 143 return {Empty, error.what(), std::move(globals), std::move(options)};
117 } 144 }
118 } else { 145 } else {
119 return {Empty, std::move(_info.error), std::move(globals)}; 146 return {Empty, std::move(_info.error), std::move(globals), std::move(options)};
120 } 147 }
121 } 148 }
122 149
@@ -2150,6 +2177,17 @@ private:
2150 } 2177 }
2151 2178
2152#ifndef MOONP_NO_MACRO 2179#ifndef MOONP_NO_MACRO
2180 void passOptions() {
2181 if (!_config.options.empty()) {
2182 pushMoonp("options"sv); // options
2183 for (const auto& option : _config.options) {
2184 lua_pushlstring(L, option.second.c_str(), option.second.size());
2185 lua_setfield(L, -2, option.first.c_str());
2186 }
2187 lua_pop(L, 1);
2188 }
2189 }
2190
2153 void pushCurrentModule() { 2191 void pushCurrentModule() {
2154 if (_useModule) { 2192 if (_useModule) {
2155 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE 2193 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
@@ -2165,6 +2203,7 @@ private:
2165 if (_luaOpen) { 2203 if (_luaOpen) {
2166 _luaOpen(static_cast<void*>(L)); 2204 _luaOpen(static_cast<void*>(L));
2167 } 2205 }
2206 passOptions();
2168 _stateOwner = true; 2207 _stateOwner = true;
2169 } 2208 }
2170 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE 2209 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
@@ -2314,7 +2353,7 @@ private:
2314 out.push_back(Empty); 2353 out.push_back(Empty);
2315 } 2354 }
2316#else 2355#else
2317 void transformMacro(Macro_t* macro, str_list& out, bool exporting) { 2356 void transformMacro(Macro_t* macro, str_list&, bool) {
2318 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, macro)); 2357 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, macro));
2319 } 2358 }
2320#endif // MOONP_NO_MACRO 2359#endif // MOONP_NO_MACRO
@@ -3023,16 +3062,67 @@ private:
3023 } 3062 }
3024 3063
3025#ifndef MOONP_NO_MACRO 3064#ifndef MOONP_NO_MACRO
3026 std::pair<std::string,std::string> expandMacroStr(ChainValue_t* chainValue) { 3065 std::tuple<std::string,std::string,str_list> expandMacroStr(ChainValue_t* chainValue) {
3027 const auto& chainList = chainValue->items.objects(); 3066 const auto& chainList = chainValue->items.objects();
3028 auto x = ast_to<Callable_t>(chainList.front())->item.to<MacroName_t>(); 3067 auto x = ast_to<Callable_t>(chainList.front())->item.to<MacroName_t>();
3029 auto macroName = _parser.toString(x->name); 3068 auto macroName = x->name ? _parser.toString(x->name) : Empty;
3030 if (!_useModule) { 3069 if (!macroName.empty() && !_useModule) {
3031 throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); 3070 throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x));
3032 } 3071 }
3033 pushCurrentModule(); // cur 3072 pushCurrentModule(); // cur
3034 int top = lua_gettop(L) - 1; 3073 int top = lua_gettop(L) - 1;
3035 DEFER(lua_settop(L, top)); 3074 DEFER(lua_settop(L, top));
3075 if (macroName.empty()) {
3076 lua_pop(L, 1); // empty
3077 auto item = *(++chainList.begin());
3078 const node_container* args = nullptr;
3079 if (auto invoke = ast_cast<Invoke_t>(item)) {
3080 args = &invoke->args.objects();
3081 } else {
3082 args = &ast_to<InvokeArgs_t>(item)->args.objects();
3083 }
3084 if (args->size() != 1) {
3085 throw std::logic_error(_info.errorMessage("in-place macro must be followed by a compile time function"sv, x));
3086 }
3087 auto fcodes = _parser.toString(args->back());
3088 Utils::trim(fcodes);
3089 pushMoonp("loadstring"sv); // loadstring
3090 lua_pushlstring(L, fcodes.c_str(), fcodes.size()); // loadstring codes
3091 lua_pushliteral(L, "=(macro in-place)"); // loadstring codes chunk
3092 pushOptions(args->back()->m_begin.m_line - 1); // loadstring codes chunk options
3093 if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), f err
3094 std::string err = lua_tostring(L, -1);
3095 throw std::logic_error(_info.errorMessage(s("fail to load macro codes\n"sv) + err, x));
3096 } // f err
3097 if (lua_isnil(L, -2) != 0) { // f == nil, f err
3098 std::string err = lua_tostring(L, -1);
3099 throw std::logic_error(_info.errorMessage(s("fail to load macro codes, at (macro in-place): "sv) + err, x));
3100 }
3101 lua_pop(L, 1); // f
3102 pushMoonp("pcall"sv); // f pcall
3103 lua_insert(L, -2); // pcall f
3104 if (lua_pcall(L, 1, 2, 0) != 0) { // f(), success macroFunc
3105 std::string err = lua_tostring(L, -1);
3106 throw std::logic_error(_info.errorMessage(s("fail to generate macro function\n"sv) + err, x));
3107 } // success res
3108 if (lua_toboolean(L, -2) == 0) {
3109 std::string err = lua_tostring(L, -1);
3110 throw std::logic_error(_info.errorMessage(s("fail to generate macro function\n"sv) + err, x));
3111 } // true macroFunc
3112 lua_remove(L, -2); // macroFunc
3113 pushMoonp("pcall"sv); // macroFunc pcall
3114 lua_insert(L, -2); // pcall macroFunc
3115 bool success = lua_pcall(L, 1, 2, 0) == 0;
3116 if (!success) { // err
3117 std::string err = lua_tostring(L, -1);
3118 throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x));
3119 } // success err
3120 if (lua_toboolean(L, -2) == 0) {
3121 std::string err = lua_tostring(L, -1);
3122 throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x));
3123 }
3124 return {s("block"sv), Empty, {}};
3125 }
3036 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName 3126 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName
3037 lua_rawget(L, -2); // cur[macroName], cur macro 3127 lua_rawget(L, -2); // cur[macroName], cur macro
3038 if (lua_istable(L, -1) == 0) { 3128 if (lua_istable(L, -1) == 0) {
@@ -3060,9 +3150,7 @@ private:
3060 BREAK_IF(!chainValue); 3150 BREAK_IF(!chainValue);
3061 BREAK_IF(!isMacroChain(chainValue)); 3151 BREAK_IF(!isMacroChain(chainValue));
3062 BREAK_IF(chainValue->items.size() != 2); 3152 BREAK_IF(chainValue->items.size() != 2);
3063 std::string type, codes; 3153 str = std::get<1>(expandMacroStr(chainValue));
3064 std::tie(type, codes) = expandMacroStr(chainValue);
3065 str = codes;
3066 BLOCK_END 3154 BLOCK_END
3067 if (str.empty()) { 3155 if (str.empty()) {
3068 // exp is reassembled due to backcall expressions 3156 // exp is reassembled due to backcall expressions
@@ -3092,30 +3180,55 @@ private:
3092 Utils::replace(str, "\r\n"sv, "\n"sv); 3180 Utils::replace(str, "\r\n"sv, "\n"sv);
3093 lua_pushlstring(L, str.c_str(), str.size()); 3181 lua_pushlstring(L, str.c_str(), str.size());
3094 } // cur macro pcall func args... 3182 } // cur macro pcall func args...
3095 bool success = lua_pcall(L, static_cast<int>(args->size()) + 1, 2, 0) == 0; 3183 bool success = lua_pcall(L, static_cast<int>(args->size()) + 1, 3, 0) == 0;
3096 if (!success) { // cur macro err 3184 if (!success) { // cur macro err
3097 std::string err = lua_tostring(L, -1); 3185 std::string err = lua_tostring(L, -1);
3098 throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x)); 3186 throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x));
3099 } // cur macro success res 3187 } // cur macro success res option
3100 if (lua_toboolean(L, -2) == 0) { 3188 if (lua_toboolean(L, -3) == 0) {
3101 std::string err = lua_tostring(L, -1); 3189 std::string err = lua_tostring(L, -2);
3102 throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x)); 3190 throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x));
3103 } 3191 }
3104 lua_remove(L, -2); // cur macro res 3192 lua_remove(L, -3); // cur macro res option
3105 if (lua_isstring(L, -1) == 0) { 3193 if (lua_isstring(L, -2) == 0) {
3106 throw std::logic_error(_info.errorMessage(s("macro function must return string with expanded codes"sv), x)); 3194 throw std::logic_error(_info.errorMessage(s("macro function must return string with expanded codes"sv), x));
3107 } // cur macro codes 3195 } // cur macro codes option
3108 lua_rawgeti(L, -2, 2); // cur macro codes type 3196 lua_rawgeti(L, -3, 2); // cur macro codes option type
3109 std::string type = lua_tostring(L, -1); 3197 std::string type = lua_tostring(L, -1);
3198 lua_pop(L, 1); // cur macro codes option
3199 str_list localVars;
3200 if (lua_isnil(L, -1) == 0) {
3201 if (lua_istable(L, -1) == 0) {
3202 throw std::logic_error(_info.errorMessage(s("macro function must return expanded codes followed by a config table"sv), x));
3203 }
3204 if (type == "expr"sv || type == "block"sv) {
3205 throw std::logic_error(_info.errorMessage(s("expr or block macro is not accepting config table"sv), x));
3206 }
3207 for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) {
3208 lua_rawgeti(L, -1, i + 1); // cur macro codes option item
3209 size_t len = 0;
3210 if (lua_isstring(L, -1) == 0) {
3211 throw std::logic_error(_info.errorMessage(s("macro config table must contains strings"sv), x));
3212 }
3213 auto name = lua_tolstring(L, -1, &len);
3214 if (_parser.match<Variable_t>({name, len})) {
3215 localVars.push_back(std::string(name, len));
3216 } else {
3217 throw std::logic_error(_info.errorMessage(s("macro config table must contains names for local variables, got \""sv) + std::string(name, len) + '"', x));
3218 }
3219 lua_pop(L, 1);
3220 }
3221 } // cur macro codes option
3110 std::string codes = lua_tostring(L, -2); 3222 std::string codes = lua_tostring(L, -2);
3111 return {type, codes}; 3223 return {type, codes, std::move(localVars)};
3112 } 3224 }
3113 3225
3114 std::tuple<ast_ptr<false,ast_node>, std::unique_ptr<input>, std::string> expandMacro(ChainValue_t* chainValue, ExpUsage usage, bool allowBlockMacroReturn) { 3226 std::tuple<ast_ptr<false,ast_node>, std::unique_ptr<input>, std::string, str_list> expandMacro(ChainValue_t* chainValue, ExpUsage usage, bool allowBlockMacroReturn) {
3115 auto x = ast_to<Callable_t>(chainValue->items.front())->item.to<MacroName_t>(); 3227 auto x = ast_to<Callable_t>(chainValue->items.front())->item.to<MacroName_t>();
3116 const auto& chainList = chainValue->items.objects(); 3228 const auto& chainList = chainValue->items.objects();
3117 std::string type, codes; 3229 std::string type, codes;
3118 std::tie(type, codes) = expandMacroStr(chainValue); 3230 str_list localVars;
3231 std::tie(type, codes, localVars) = expandMacroStr(chainValue);
3119 std::string targetType(usage != ExpUsage::Common || chainList.size() > 2 ? "expr"sv : "block"sv); 3232 std::string targetType(usage != ExpUsage::Common || chainList.size() > 2 ? "expr"sv : "block"sv);
3120 if (type == "lua"sv) { 3233 if (type == "lua"sv) {
3121 if (!allowBlockMacroReturn && targetType != "block"sv) { 3234 if (!allowBlockMacroReturn && targetType != "block"sv) {
@@ -3128,19 +3241,19 @@ private:
3128 std::string err = lua_tostring(L, -1); 3241 std::string err = lua_tostring(L, -1);
3129 throw std::logic_error(_info.errorMessage(err, x)); 3242 throw std::logic_error(_info.errorMessage(err, x));
3130 } 3243 }
3131 return {nullptr, nullptr, std::move(codes)}; 3244 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
3132 } else if (type == "text"sv) { 3245 } else if (type == "text"sv) {
3133 if (!allowBlockMacroReturn && targetType != "block"sv) { 3246 if (!allowBlockMacroReturn && targetType != "block"sv) {
3134 throw std::logic_error(_info.errorMessage("text macro can only be placed where block macro is allowed"sv, x)); 3247 throw std::logic_error(_info.errorMessage("text macro can only be placed where block macro is allowed"sv, x));
3135 } 3248 }
3136 return {nullptr, nullptr, std::move(codes)}; 3249 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
3137 } else if (!allowBlockMacroReturn && type != targetType) { 3250 } else if (!allowBlockMacroReturn && type != targetType) {
3138 throw std::logic_error(_info.errorMessage(s("macro type mismatch, "sv) + targetType + s(" expected, got "sv) + type, x)); 3251 throw std::logic_error(_info.errorMessage(s("macro type mismatch, "sv) + targetType + s(" expected, got "sv) + type, x));
3139 } 3252 }
3140 ParseInfo info; 3253 ParseInfo info;
3141 if (usage == ExpUsage::Common) { 3254 if (usage == ExpUsage::Common) {
3142 if (codes.empty()) { 3255 if (codes.empty()) {
3143 return {x->new_ptr<Block_t>().get(), std::move(info.codes), Empty}; 3256 return {x->new_ptr<Block_t>().get(), std::move(info.codes), Empty, std::move(localVars)};
3144 } 3257 }
3145 if (type == "expr"sv) { 3258 if (type == "expr"sv) {
3146 info = _parser.parse<Exp_t>(codes); 3259 info = _parser.parse<Exp_t>(codes);
@@ -3202,7 +3315,7 @@ private:
3202 info.node.set(exp); 3315 info.node.set(exp);
3203 } 3316 }
3204 } 3317 }
3205 return {info.node, std::move(info.codes), Empty}; 3318 return {info.node, std::move(info.codes), Empty, std::move(localVars)};
3206 } 3319 }
3207#endif // MOONP_NO_MACRO 3320#endif // MOONP_NO_MACRO
3208 3321
@@ -3212,10 +3325,11 @@ private:
3212 ast_ptr<false,ast_node> node; 3325 ast_ptr<false,ast_node> node;
3213 std::unique_ptr<input> codes; 3326 std::unique_ptr<input> codes;
3214 std::string luaCodes; 3327 std::string luaCodes;
3215 std::tie(node, codes, luaCodes) = expandMacro(chainValue, usage, allowBlockMacroReturn); 3328 str_list localVars;
3329 std::tie(node, codes, luaCodes, localVars) = expandMacro(chainValue, usage, allowBlockMacroReturn);
3216 Utils::replace(luaCodes, "\r\n"sv, "\n"sv); 3330 Utils::replace(luaCodes, "\r\n"sv, "\n"sv);
3217 Utils::trim(luaCodes); 3331 Utils::trim(luaCodes);
3218 if (!node && !codes) { 3332 if (!node) {
3219 if (!luaCodes.empty()) { 3333 if (!luaCodes.empty()) {
3220 if (_config.reserveLineNumber) { 3334 if (_config.reserveLineNumber) {
3221 luaCodes.insert(0, nll(chainValue).substr(1)); 3335 luaCodes.insert(0, nll(chainValue).substr(1));
@@ -3223,6 +3337,11 @@ private:
3223 luaCodes.append(nlr(chainValue)); 3337 luaCodes.append(nlr(chainValue));
3224 } 3338 }
3225 out.push_back(luaCodes); 3339 out.push_back(luaCodes);
3340 if (!localVars.empty()) {
3341 for (const auto& var : localVars) {
3342 addToScope(var);
3343 }
3344 }
3226 return; 3345 return;
3227 } 3346 }
3228 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) { 3347 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) {
@@ -3254,6 +3373,7 @@ private:
3254 } 3373 }
3255 return; 3374 return;
3256#else 3375#else
3376 (void)allowBlockMacroReturn;
3257 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, chainValue)); 3377 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, chainValue));
3258#endif // MOONP_NO_MACRO 3378#endif // MOONP_NO_MACRO
3259 } 3379 }
@@ -4983,11 +5103,9 @@ private:
4983 config.lintGlobalVariable = false; 5103 config.lintGlobalVariable = false;
4984 config.reserveLineNumber = false; 5104 config.reserveLineNumber = false;
4985 config.implicitReturnRoot = _config.implicitReturnRoot; 5105 config.implicitReturnRoot = _config.implicitReturnRoot;
4986 std::string codes, err; 5106 auto result = compiler.compile(text, config);
4987 GlobalVars globals; 5107 if (result.codes.empty() && !result.error.empty()) {
4988 std::tie(codes, err, globals) = compiler.compile(text, config); 5108 throw std::logic_error(_info.errorMessage(s("fail to compile module '"sv) + moduleName + s("\': "sv) + result.error, x));
4989 if (codes.empty() && !err.empty()) {
4990 throw std::logic_error(_info.errorMessage(s("fail to compile module '"sv) + moduleName + s("\': "sv) + err, x));
4991 } 5109 }
4992 lua_pop(L, 1); // cur 5110 lua_pop(L, 1); // cur
4993 } 5111 }
@@ -5325,12 +5443,16 @@ MoonCompiler::MoonCompiler(void* sharedState,
5325#ifndef MOONP_NO_MACRO 5443#ifndef MOONP_NO_MACRO
5326_compiler(std::make_unique<MoonCompilerImpl>(static_cast<lua_State*>(sharedState), luaOpen, sameModule)) {} 5444_compiler(std::make_unique<MoonCompilerImpl>(static_cast<lua_State*>(sharedState), luaOpen, sameModule)) {}
5327#else 5445#else
5328_compiler(std::make_unique<MoonCompilerImpl>()) {} 5446_compiler(std::make_unique<MoonCompilerImpl>()) {
5447 (void)sharedState;
5448 (void)luaOpen;
5449 (void)sameModule;
5450}
5329#endif // MOONP_NO_MACRO 5451#endif // MOONP_NO_MACRO
5330 5452
5331MoonCompiler::~MoonCompiler() {} 5453MoonCompiler::~MoonCompiler() {}
5332 5454
5333std::tuple<std::string,std::string,GlobalVars> MoonCompiler::compile(std::string_view codes, const MoonConfig& config) { 5455CompileInfo MoonCompiler::compile(std::string_view codes, const MoonConfig& config) {
5334 return _compiler->compile(codes, config); 5456 return _compiler->compile(codes, config);
5335} 5457}
5336 5458