1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "luaengine.h"
#include "luatr.h"
#include <utils/macroexpander.h>
using namespace Utils;
namespace Lua::Internal {
void setNext(
MacroExpander *expander,
sol::state &lua,
auto &table,
const QByteArray &key,
QList<QByteArray>::const_iterator it,
QList<QByteArray>::const_iterator end)
{
if (it + 1 == end) {
if (expander->isPrefixVariable(key)) {
table.set_function(it->toStdString(), [key, expander](const QString &s) -> QString {
return expander->value(key + s.toUtf8());
});
} else {
table.set(it->toStdString(), expander->value(key));
}
} else {
auto existingTable = table.template get<sol::optional<sol::table>>(it->toStdString());
if (existingTable) {
setNext(expander, lua, *existingTable, key, it + 1, end);
} else {
sol::table newTable = lua.create_table();
setNext(expander, lua, newTable, key, it + 1, end);
table.set(it->toStdString(), newTable);
}
}
};
sol::protected_function_result run(sol::state &lua, QString statement, MacroExpander *expander)
{
return runFunction(lua, statement, "Statement", [expander](sol::state &lua) {
sol::global_table &t = lua.globals();
for (QByteArray key : expander->visibleVariables()) {
if (key != "Lua:<value>") {
if (key.endsWith(":<value>"))
key = key.chopped(7);
QList<QByteArray> parts = key.split(':');
parts.removeIf([](const QByteArray &part) { return part.isEmpty(); });
setNext(expander, lua, t, key, parts.cbegin(), parts.cend());
}
}
});
}
Result<QString> tryRun(const QString statement, MacroExpander *expander)
{
sol::state lua;
auto result = run(lua, statement, expander);
if (!result.valid()) {
sol::error err = result;
return make_unexpected(QString::fromStdString(err.what()));
}
QStringList results;
for (int i = 1; i <= result.return_count(); i++) {
size_t l;
const char *s = luaL_tolstring(result.lua_state(), int(i), &l);
results.append(QString::fromUtf8(s, int(l)));
}
return results.join(QLatin1Char(' '));
}
void setupLuaExpander(MacroExpander *expander)
{
expander->registerPrefix(
"Lua",
Tr::tr("Evaluate simple Lua statements.<br>"
"Literal '}' characters must be escaped as \"\\}\", "
"'\\' characters must be escaped as \"\\\\\", "
"'#' characters must be escaped as \"\\#\", "
"and \"%{\" must be escaped as \"%\\{\"."),
[expander](const QString &statement) -> QString {
if (statement.isEmpty())
return Tr::tr("No Lua statement to evaluate.");
Result<QString> result = tryRun("return " + statement, expander);
if (result)
return *result;
result = tryRun(statement, expander);
if (!result)
return result.error();
return *result;
});
}
} // namespace Lua::Internal
|