You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

417 lines
12 KiB

  1. #include "UserScript.h"
  2. #include "UserScriptRequire.h"
  3. #include <algorithm>
  4. #include <span>
  5. #include <utility>
  6. using interpreter = decltype(scripting::prepare_interpreter({}));
  7. using namespace scripting;
  8. struct fn_array final : public scripting::function_impl {
  9. const int32_t size_limit;
  10. const bool can_contain_arrays;
  11. fn_array(int32_t _size_limit, bool _can_contain_arrays)
  12. : size_limit(_size_limit)
  13. , can_contain_arrays(_can_contain_arrays)
  14. {}
  15. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  16. array ary;
  17. if(not can_contain_arrays && details::NoArrays<0>{}.verify(self, n)) {
  18. error = script_error{
  19. .message = "/array: arrays cannot contain other arrays"
  20. };
  21. return std::nullopt;
  22. }
  23. if(n.size() > std::max<int32_t>(0, size_limit)) {
  24. error = script_error{
  25. .message = "/array: arrays exceeds max size"
  26. };
  27. return std::nullopt;
  28. }
  29. std::transform(n.rbegin(), n.rend(), std::back_inserter(ary.value), [&](argument& arg){
  30. if(std::holds_alternative<scripting::script_value>(arg)) {
  31. return std::get<scripting::script_value>(arg);
  32. } else {
  33. return self->resolve(std::get<scripting::script_variable>(arg).name);
  34. }
  35. });
  36. return ary;
  37. }
  38. ~fn_array() final = default;
  39. };
  40. struct fn_array_reverse final : public scripting::function_impl {
  41. fn_array_reverse() = default;
  42. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  43. using verifier = Verify<details::TypeVerifier<0, array>>;
  44. if(verifier{}.verify(self, n)) {
  45. error = script_error{
  46. .message = "/array_reverse takes exactly 1 argument of type array"
  47. };
  48. return std::nullopt;
  49. }
  50. auto& arg = n.front();
  51. script_value target;
  52. if(std::holds_alternative<scripting::script_value>(arg)) {
  53. target = std::get<scripting::script_value>(arg);
  54. } else {
  55. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  56. }
  57. auto& ary = std::get<array>(target);
  58. std::reverse(ary.value.begin(), ary.value.end());
  59. return target;
  60. }
  61. ~fn_array_reverse() final = default;
  62. };
  63. struct fn_array_append final : public scripting::function_impl {
  64. const std::string name;
  65. const int32_t size_limit;
  66. const bool can_contain_arrays;
  67. fn_array_append(std::string _name, int32_t _size_limit, bool _can_contain_arrays)
  68. : name(std::move(_name))
  69. , size_limit(_size_limit)
  70. , can_contain_arrays(_can_contain_arrays)
  71. {}
  72. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  73. using verifier = Verify<
  74. details::TypeVerifier<0, array>,
  75. details::VariableVerifier<0>,
  76. details::SizeAtLeast<1>
  77. >;
  78. if(verifier{}.verify(self, n) && can_contain_arrays || details::NoArrays<1>{}.verify(self, n)) {
  79. error = script_error{
  80. .message = "/array_append: must provide an array variable as first argument"
  81. };
  82. return std::nullopt;
  83. }
  84. auto target = self->getValue(std::get<script_variable>(n.back()).name);
  85. n.pop_back();
  86. auto& ary = std::get<array>(target.value().get()).value;
  87. if(n.size() + ary.size() > std::max<int32_t>(0, size_limit)) {
  88. error = script_error{
  89. .message = "/array_append: array would exceed size limit"
  90. };
  91. return script_value{0};
  92. }
  93. std::transform(n.rbegin(), n.rend(), std::back_inserter(ary), [&](argument& arg){
  94. if(std::holds_alternative<scripting::script_value>(arg)) {
  95. return std::get<scripting::script_value>(arg);
  96. } else {
  97. return self->resolve(std::get<scripting::script_variable>(arg).name);
  98. }
  99. });
  100. return script_value{1};
  101. }
  102. ~fn_array_append() final = default;
  103. };
  104. struct fn_array_prepend final : public scripting::function_impl {
  105. const std::string name;
  106. const int32_t size_limit;
  107. const bool can_contain_arrays;
  108. fn_array_prepend(std::string _name, int32_t _size_limit, bool _can_contain_arrays)
  109. : name(std::move(_name))
  110. , size_limit(_size_limit)
  111. , can_contain_arrays(_can_contain_arrays)
  112. {}
  113. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  114. using verifier = Verify<
  115. details::TypeVerifier<0, array>,
  116. details::VariableVerifier<0>,
  117. details::SizeEquals<2>
  118. >;
  119. if((verifier{}.verify(self, n)) && (can_contain_arrays || details::NoArrays<1>{}.verify(self, n))) {
  120. error = script_error{
  121. .message = "/array_append: must provide an array variable as first argument"
  122. };
  123. return std::nullopt;
  124. }
  125. auto target = self->getValue(std::get<script_variable>(n.back()).name);
  126. n.pop_back();
  127. auto& ary = std::get<array>(target.value().get()).value;
  128. if(n.size() + ary.size() > std::max<int32_t>(0, size_limit)) {
  129. error = script_error{
  130. .message = name + ": array would exceed size limit"
  131. };
  132. return script_value{0};
  133. }
  134. if(std::holds_alternative<scripting::script_value>(n.front())) {
  135. ary.push_front(std::get<scripting::script_value>(n.front()));
  136. } else {
  137. ary.push_front(self->resolve(std::get<scripting::script_variable>(n.front()).name));
  138. }
  139. return script_value{1};
  140. }
  141. ~fn_array_prepend() final = default;
  142. };
  143. struct fn_array_pop final : public scripting::function_impl {
  144. std::string name;
  145. fn_array_pop(std::string _name) : name(std::move(_name)) {}
  146. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  147. using verifier = Verify<
  148. details::TypeVerifier<0, array>,
  149. details::VariableVerifier<0>,
  150. details::SizeEquals<1>
  151. >;
  152. if(verifier{}.verify(self, n)) {
  153. error = script_error{
  154. .message = name + " takes exactly 1 argument of type array"
  155. };
  156. return std::nullopt;
  157. }
  158. auto& arg = n.front();
  159. script_value target;
  160. if(std::holds_alternative<scripting::script_value>(arg)) {
  161. target = std::get<scripting::script_value>(arg);
  162. } else {
  163. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  164. }
  165. auto& ary = std::get<array>(target);
  166. if(ary.value.empty()) {
  167. return {null{}};
  168. }
  169. auto value = ary.value.back();
  170. ary.value.pop_back();
  171. return value;
  172. }
  173. ~fn_array_pop() final = default;
  174. };
  175. struct fn_array_size final : public scripting::function_impl {
  176. fn_array_size() = default;
  177. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {using verifier = Verify<
  178. details::TypeVerifier<0, array>,
  179. details::VariableVerifier<0>,
  180. details::SizeEquals<1>
  181. >;
  182. if(verifier{}.verify(self, n)) {
  183. error = script_error{
  184. .message = "/array_size takes exactly 1 argument of type array"
  185. };
  186. return std::nullopt;
  187. }
  188. auto& arg = n.front();
  189. script_value target;
  190. if(std::holds_alternative<scripting::script_value>(arg)) {
  191. target = std::get<scripting::script_value>(arg);
  192. } else {
  193. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  194. }
  195. return static_cast<int32_t>(std::get<array>(target).value.size());
  196. }
  197. ~fn_array_size() final = default;
  198. };
  199. struct fn_array_index final : public scripting::function_impl {
  200. fn_array_index() = default;
  201. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  202. if(n.size() != 2) {
  203. error = script_error{
  204. .message = "/array_size takes exactly 2 argument of type (array, integer)"
  205. };
  206. return std::nullopt;
  207. }
  208. using verifier = Verify<
  209. details::TypeVerifier<0, array>,
  210. details::VariableVerifier<0>,
  211. details::TypeVerifier<1, int32_t>
  212. >;
  213. if(verifier{}.verify(self, n)) {
  214. error = script_error{
  215. .message = "/array_index takes exactly 2 argument of type (array, integer)"
  216. };
  217. return std::nullopt;
  218. }
  219. auto& arg = n.back();
  220. script_value target;
  221. if(std::holds_alternative<scripting::script_value>(arg)) {
  222. target = std::get<scripting::script_value>(arg);
  223. } else {
  224. target = self->resolve(std::get<scripting::script_variable>(arg).name);
  225. }
  226. auto& idx_arg = n.front();
  227. script_value idx;
  228. if(std::holds_alternative<scripting::script_value>(idx_arg)) {
  229. idx = std::get<scripting::script_value>(idx_arg);
  230. } else {
  231. idx = self->resolve(std::get<scripting::script_variable>(idx_arg).name);
  232. }
  233. if(static_cast<int32_t>(std::get<array>(target).value.size()) <= std::get<int32_t>(idx)) {
  234. error = script_error{
  235. .message = "/array_index index must be smaller that the array size, the first element of the array has index 0"
  236. };
  237. return std::nullopt;
  238. }
  239. if(std::get<int32_t>(idx) < 0) {
  240. error = script_error{
  241. .message = "/array_index index must be 0 or more"
  242. };
  243. return std::nullopt;
  244. }
  245. return std::get<array>(target).value.at(static_cast<size_t>(std::get<int32_t>(idx)));
  246. }
  247. ~fn_array_index() final = default;
  248. };
  249. struct fn_array_set final : public scripting::function_impl {
  250. fn_array_set() = default;
  251. std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
  252. if(n.size() != 3) {
  253. error = script_error{
  254. .message = "/array_set takes exactly 3 argument of type (array, integer, value), provided a different amount"
  255. };
  256. return std::nullopt;
  257. }
  258. auto& arg = n.back();
  259. if(std::holds_alternative<scripting::script_value>(arg)) {
  260. error = script_error{
  261. .message = "/array_set takes exactly 3 argument of type (array, integer, value), the array needs to be a variable"
  262. };
  263. return std::nullopt;
  264. }
  265. auto target = self->getValue(std::get<scripting::script_variable>(arg).name);
  266. if(not target) {
  267. error = script_error{
  268. .message = "/array_set takes exactly 3 argument of type (array, integer, value), provided array variable is undefined"
  269. };
  270. return std::nullopt;
  271. }
  272. if(not std::holds_alternative<array>(target.value().get())) {
  273. error = script_error{
  274. .message = "/array_set takes exactly 1 argument of type array followed by an integer, argument 1 is not an array"
  275. };
  276. return std::nullopt;
  277. }
  278. auto& concrete_target = std::get<array>(target.value().get());
  279. auto& idx_arg = n[1];
  280. script_value idx;
  281. if(std::holds_alternative<scripting::script_value>(idx_arg)) {
  282. idx = std::get<scripting::script_value>(idx_arg);
  283. } else {
  284. idx = self->resolve(std::get<scripting::script_variable>(idx_arg).name);
  285. }
  286. if(not std::holds_alternative<int32_t>(idx)) {
  287. error = script_error{
  288. .message = "/array_set takes exactly 1 argument of type array followed by an integer, argument 2 is not an integer"
  289. };
  290. return std::nullopt;
  291. }
  292. if(static_cast<int32_t>(concrete_target.value.size()) <= std::get<int32_t>(idx)) {
  293. error = script_error{
  294. .message = "/array_set index must be smaller that the array size, the first element of the array has index 0"
  295. };
  296. return std::nullopt;
  297. }
  298. if(std::get<int32_t>(idx) < 0) {
  299. error = script_error{
  300. .message = "/array_set index must be 0 or more"
  301. };
  302. return std::nullopt;
  303. }
  304. auto& value_arg = n.front();
  305. script_value value;
  306. if(std::holds_alternative<scripting::script_value>(value_arg)) {
  307. value = std::get<scripting::script_value>(value_arg);
  308. } else {
  309. value = self->resolve(std::get<scripting::script_variable>(value_arg).name);
  310. }
  311. concrete_target.value.at(std::get<int32_t>(idx)) = value;
  312. return concrete_target.value[std::get<int32_t>(idx)];
  313. }
  314. ~fn_array_set() final = default;
  315. };
  316. namespace scripting {
  317. interpreter register_array_lib(interpreter target, bool recursive_arrays, int32_t size_limit) {
  318. target->registerFunction("array", std::make_unique<fn_array>(size_limit, recursive_arrays));
  319. target->registerFunction("array_reverse", std::make_unique<fn_array_reverse>());
  320. target->registerFunction("array_append", std::make_unique<fn_array_append>("array_append", size_limit, recursive_arrays));
  321. target->registerFunction("array_push", std::make_unique<fn_array_append>("array_push", size_limit, recursive_arrays));
  322. target->registerFunction("array_pop", std::make_unique<fn_array_pop>("array_pop"));
  323. target->registerFunction("array_size", std::make_unique<fn_array_size>());
  324. target->registerFunction("array_index", std::make_unique<fn_array_index>());
  325. target->registerFunction("array_set", std::make_unique<fn_array_set>());
  326. target->registerFunction("queue_enqueue", std::make_unique<fn_array_prepend>("queue_enqueue", size_limit, recursive_arrays));
  327. target->registerFunction("queue_dequeue", std::make_unique<fn_array_pop>("queue_dequeue"));
  328. return std::move(target);
  329. }
  330. }