instruction.cpp (20949B)
1 #include "instruction.hpp" 2 3 #include "../cstring_item.hpp" 4 #include "../raw_item.hpp" 5 #include "../../sink.hpp" 6 7 #include <libshit/lua/static_class.hpp> 8 #include <libshit/lua/user_type.hpp> 9 10 #include <boost/mp11/algorithm.hpp> 11 #include <boost/mp11/bind.hpp> 12 #include <boost/mp11/list.hpp> 13 14 #include <iomanip> 15 16 namespace Neptools::Stsc 17 { 18 19 // helpers for generic CreateAndInsert 20 namespace 21 { 22 using CreateType = Libshit::NotNull<Libshit::SmartPtr<InstructionBase>> 23 (*)(Context&, const Source&); 24 25 template <Flavor F, uint8_t I> 26 Libshit::NotNull<Libshit::SmartPtr<InstructionBase>> 27 CreateAdapt(Context& ctx, const Source& src) 28 { return ctx.Create<InstructionItem<F, I>>(I, src); } 29 30 31 namespace mp = boost::mp11; 32 #define NEPTOOLS_GEN(x,y) , Flavor::x 33 using Flavors = mp::mp_list_c< 34 Flavor NEPTOOLS_GEN_STSC_FLAVOR(NEPTOOLS_GEN,)>; 35 #undef NEPTOOLS_GEN 36 37 template <typename F> 38 using MakeMap = mp::mp_transform_q< 39 mp::mp_bind<std::pair, F, mp::_1>, 40 mp::mp_from_sequence<std::make_integer_sequence<std::uint32_t, 256>>>; 41 using AllOpcodes = mp::mp_flatten< 42 mp::mp_transform_q<mp::mp_bind<MakeMap, mp::_1>, Flavors>>; 43 44 template <typename List> struct CreateMapImpl; 45 template <typename... X> 46 struct CreateMapImpl<mp::mp_list<X...>> 47 { 48 #pragma GCC diagnostic push 49 #pragma GCC diagnostic ignored "-Wmissing-braces" 50 static inline const constexpr CreateType 51 MAP[mp::mp_size<Flavors>::value][256] = 52 { CreateAdapt<X::first_type::value, X::second_type::value>... }; 53 #pragma GCC diagnostic pop 54 }; 55 56 using CreateMap = CreateMapImpl<AllOpcodes>; 57 } 58 59 // base 60 InstructionBase& InstructionBase::CreateAndInsert(ItemPointer ptr, Flavor f) 61 { 62 auto x = RawItem::GetSource(ptr, -1); 63 x.src.CheckSize(1); 64 uint8_t opcode = x.src.ReadLittleUint8(); 65 auto ctx = x.ritem.GetContext(); 66 auto& ret = x.ritem.Split( 67 ptr.offset, CreateMap::MAP[static_cast<size_t>(f)][opcode](*ctx, x.src)); 68 69 ret.PostInsert(f); 70 return ret; 71 } 72 73 void InstructionBase::InstrDump(Sink& sink) const 74 { 75 sink.WriteLittleUint8(opcode); 76 } 77 78 std::ostream& InstructionBase::InstrInspect( 79 std::ostream& os, unsigned indent) const 80 { 81 Item::Inspect_(os, indent); 82 auto flags = os.flags(); 83 os << "instruction(0x" << std::setw(2) << std::setfill('0') << std::hex 84 << unsigned(opcode); 85 os.flags(flags); 86 return os; 87 } 88 89 90 // generic implementation 91 namespace 92 { 93 94 template <typename... Args> struct PODTuple; 95 96 template <typename Head, typename... Args> 97 struct PODTuple<Head, Args...> 98 { 99 Head head; 100 PODTuple<Args...> tail; 101 }; 102 103 template <typename T> struct PODTuple<T> { T head; }; 104 template<> struct PODTuple<> {}; 105 106 template <size_t I> struct PODTupleGet 107 { 108 template <typename T> static auto& Get(T& tuple) 109 { return PODTupleGet<I-1>::Get(tuple.tail); } 110 }; 111 template<> struct PODTupleGet<0> 112 { 113 template <typename T> static auto& Get(T& tuple) 114 { return tuple.head; } 115 }; 116 117 template <size_t I, typename T> inline auto& Get(T& tuple) 118 { return PODTupleGet<I>::Get(tuple); } 119 120 121 template <typename T> struct EndianMap; 122 template<> struct EndianMap<uint8_t> 123 { using Type = boost::endian::little_uint8_t; }; 124 template<> struct EndianMap<uint16_t> 125 { using Type = boost::endian::little_uint16_t; }; 126 template<> struct EndianMap<uint32_t> 127 { using Type = boost::endian::little_uint32_t; }; 128 129 template <typename T> using ToVoid = void; 130 131 132 template <typename T, typename Enable = void> struct Traits; 133 134 template <typename T> 135 struct Traits<T, ToVoid<typename EndianMap<T>::Type>> 136 { 137 using RawType = typename EndianMap<T>::Type; 138 static constexpr const size_t SIZE = sizeof(T); 139 140 static void Validate(RawType, FilePosition) {} 141 static T Parse(RawType r, Context&) { return r; } 142 static RawType Dump(T r) { return r; } 143 static void Inspect(std::ostream& os, T t) { os << uint32_t(t); } 144 static void PostInsert(T, Flavor) {} 145 }; 146 147 template<> struct Traits<float> 148 { 149 using RawType = boost::endian::little_uint32_t; 150 static constexpr const size_t SIZE = 4; 151 152 static void Validate(RawType, FilePosition) {} 153 static float Parse(RawType r, Context&) 154 { 155 uint32_t num = r; 156 float ret; 157 memcpy(&ret, &num, sizeof(ret)); 158 return ret; 159 } 160 161 static RawType Dump(float f) 162 { 163 uint32_t ret; 164 memcpy(&ret, &f, sizeof(ret)); 165 return ret; 166 } 167 168 static void Inspect(std::ostream& os, float v) { os << v; } 169 static void PostInsert(float, Flavor) {} 170 }; 171 172 template<> struct Traits<void*> 173 { 174 using RawType = boost::endian::little_uint32_t; 175 static constexpr const size_t SIZE = 4; 176 177 static void Validate(uint32_t r, FilePosition size) 178 { LIBSHIT_VALIDATE_FIELD("Stsc::Instruction", r <= size); } 179 180 static LabelPtr Parse(uint32_t r, Context& ctx) 181 { return r ? ctx.GetLabelTo(r) : LabelPtr{}; } 182 183 static RawType Dump(const LabelPtr& l) 184 { return l ? ToFilePos(l->GetPtr()) : 0; } 185 186 static void Inspect(std::ostream& os, const LabelPtr& l) 187 { os << PrintLabel(l); } 188 189 static void PostInsert(const LabelPtr&, Flavor) {} 190 }; 191 192 template<> struct Traits<std::string> : public Traits<void*> 193 { 194 static LabelPtr Parse(uint32_t r, Context& ctx) 195 { 196 if (!r) return {}; 197 if (auto ptr = ctx.GetPointer(r); ptr.Maybe<RawItem>()) 198 { 199 auto x = RawItem::GetSource(ptr, -1); 200 return ctx.GetLabelTo( 201 r, CStringItem::GetLabelName(x.src.PreadCString(0))); 202 } 203 else 204 return ctx.GetLabelTo(r); 205 } 206 207 static void PostInsert(const LabelPtr& lbl, Flavor) 208 { if (lbl) MaybeCreate<CStringItem>(lbl->GetPtr()); } 209 }; 210 211 template<> struct Traits<Code*> : public Traits<void*> 212 { 213 static void PostInsert(const LabelPtr& lbl, Flavor f) 214 { if (lbl) MaybeCreateUnchecked<InstructionBase>(lbl->GetPtr(), f); } 215 }; 216 217 template <typename T, typename... Args> struct OperationsImpl; 218 template <typename... T, size_t... I> 219 struct OperationsImpl<std::index_sequence<I...>, T...> 220 { 221 #define FORALL(...) ((__VA_ARGS__), ...) 222 223 template <typename Tuple> 224 static void Validate(const Tuple& tuple, FilePosition size) 225 { 226 (void) size; // shut up, retarded gcc 227 FORALL(Traits<T>::Validate(Get<I>(tuple), size)); 228 } 229 230 template <typename Dst, typename Src> 231 static void Parse(Dst& dst, const Src& src, Context& ctx) 232 { 233 (void) ctx; // shut up, retarded gcc 234 FORALL(std::get<I>(dst) = Traits<T>::Parse(Get<I>(src), ctx)); 235 } 236 237 template <typename Dst, typename Src> 238 static void Dump(Dst& dst, const Src& src) 239 { FORALL(Get<I>(dst) = Traits<T>::Dump(std::get<I>(src))); } 240 241 template <typename Tuple> 242 static void Inspect(std::ostream& os, const Tuple& tuple) 243 { 244 FORALL( 245 os << ", ", 246 Traits<T>::Inspect(os, std::get<I>(tuple))); 247 } 248 249 template <typename Tuple> 250 static void PostInsert(const Tuple& tuple, Flavor f) 251 { 252 (void) f; // shut up, retarded gcc 253 FORALL(Traits<T>::PostInsert(std::get<I>(tuple), f)); 254 } 255 256 static constexpr size_t Size() 257 { 258 size_t sum = 0; 259 FORALL(sum += Traits<T>::SIZE); 260 return sum; 261 } 262 #undef FORALL 263 }; 264 265 template <typename... Args> 266 using Operations = OperationsImpl<std::index_sequence_for<Args...>, Args...>; 267 268 } 269 270 template <bool NoReturn, typename... Args> 271 const FilePosition SimpleInstruction<NoReturn, Args...>::SIZE = 272 Operations<Args...>::Size() + 1; 273 274 template <bool NoReturn, typename... Args> 275 SimpleInstruction<NoReturn, Args...>::SimpleInstruction( 276 Key k, Context& ctx, uint8_t opcode, Source src) 277 : InstructionBase{k, ctx, opcode} 278 { 279 ADD_SOURCE(Parse_(ctx, src), src); 280 } 281 282 template <bool NoReturn, typename... Args> 283 void SimpleInstruction<NoReturn, Args...>::Parse_(Context& ctx, Source& src) 284 { 285 src.CheckSize(SIZE); 286 using Tuple = PODTuple<typename Traits<Args>::RawType...>; 287 static_assert(std::is_pod_v<Tuple>); 288 static_assert(Libshit::EmptySizeof<Tuple> == Operations<Args...>::Size()); 289 290 auto raw = src.ReadGen<Tuple>(); 291 292 Operations<Args...>::Validate(raw, ctx.GetSize()); 293 Operations<Args...>::Parse(args, raw, ctx); 294 } 295 296 template <bool NoReturn, typename... Args> 297 void SimpleInstruction<NoReturn, Args...>::Dump_(Sink& sink) const 298 { 299 InstrDump(sink); 300 301 using Tuple = PODTuple<typename Traits<Args>::RawType...>; 302 Tuple t; 303 Operations<Args...>::Dump(t, args); 304 sink.WriteGen(t); 305 } 306 307 template <bool NoReturn, typename... Args> 308 void SimpleInstruction<NoReturn, Args...>::Inspect_( 309 std::ostream& os, unsigned indent) const 310 { 311 InstrInspect(os, indent); 312 Operations<Args...>::Inspect(os, args); 313 os << ')'; 314 } 315 316 template <bool NoReturn, typename... Args> 317 void SimpleInstruction<NoReturn, Args...>::PostInsert(Flavor f) 318 { 319 Operations<Args...>::PostInsert(args, f); 320 if (!NoReturn) MaybeCreateUnchecked<InstructionBase>(&*++Iterator(), f); 321 } 322 323 // ------------------------------------------------------------------------ 324 // specific instruction implementations 325 InstructionRndJumpItem::InstructionRndJumpItem( 326 Key k, Context& ctx, uint8_t opcode, Source src) 327 : InstructionBase{k, ctx, opcode} 328 { 329 ADD_SOURCE(Parse_(ctx, src), src); 330 } 331 332 void InstructionRndJumpItem::Parse_(Context& ctx, Source& src) 333 { 334 src.CheckRemainingSize(1); 335 uint8_t n = src.ReadLittleUint8(); 336 src.CheckRemainingSize(4*n); 337 338 tgts.reserve(n); 339 340 for (size_t i = 0; i < n; ++i) 341 { 342 uint32_t t = src.ReadLittleUint32(); 343 LIBSHIT_VALIDATE_FIELD( 344 "Stsc::InstructionRndJumpItem", t < ctx.GetSize()); 345 tgts.push_back(ctx.GetLabelTo(t)); 346 } 347 } 348 349 void InstructionRndJumpItem::Dump_(Sink& sink) const 350 { 351 InstrDump(sink); 352 sink.WriteLittleUint8(tgts.size()); 353 for (const auto& l : tgts) 354 sink.WriteLittleUint32(ToFilePos(l->GetPtr())); 355 } 356 357 void InstructionRndJumpItem::Inspect_(std::ostream& os, unsigned indent) const 358 { 359 InstrInspect(os, indent); 360 bool first = true; 361 for (const auto& l : tgts) 362 { 363 if (!first) os << ", "; 364 first = false; 365 os << PrintLabel(l); 366 } 367 os << ')'; 368 } 369 370 void InstructionRndJumpItem::PostInsert(Flavor f) 371 { 372 for (const auto& l : tgts) 373 MaybeCreateUnchecked<InstructionBase>(l->GetPtr(), f); 374 MaybeCreateUnchecked<InstructionBase>(&*++Iterator(), f); 375 } 376 377 // ------------------------------------------------------------------------ 378 379 void InstructionJumpIfItem::FixParams::Validate( 380 FilePosition rem_size, FilePosition size) 381 { 382 #define VALIDATE(x) \ 383 LIBSHIT_VALIDATE_FIELD("Stsc::InstructionJumpIfItem::FixParams", x) 384 VALIDATE(this->size * sizeof(NodeParams) <= rem_size); 385 VALIDATE(tgt < size); 386 #undef VALIDATE 387 } 388 389 void InstructionJumpIfItem::NodeParams::Validate(uint16_t size) 390 { 391 #define VALIDATE(x) \ 392 LIBSHIT_VALIDATE_FIELD("Stsc::InstructionJumpIfItem::NodeParams", x) 393 VALIDATE(left <= size); 394 VALIDATE(right <= size); 395 #undef VALIDATE 396 } 397 398 InstructionJumpIfItem::InstructionJumpIfItem( 399 Key k, Context& ctx, uint8_t opcode, Source src) 400 : InstructionBase{k, ctx, opcode}, tgt{Libshit::EmptyNotNull{}} 401 { 402 ADD_SOURCE(Parse_(ctx, src), src); 403 } 404 405 #if LIBSHIT_WITH_LUA 406 static size_t ParseTree( 407 Libshit::Lua::StateRef vm, std::vector<InstructionJumpIfItem::Node>& tree, 408 Libshit::Lua::Any lua_tree, int type) 409 { 410 if (type == LUA_TNIL) return 0; 411 412 lua_checkstack(vm, 5); 413 414 auto i = tree.size(); 415 tree.emplace_back(); 416 417 lua_rawgeti(vm, lua_tree, 1); // +1 418 tree[i].operation = vm.Check<uint8_t>(-1); 419 lua_rawgeti(vm, lua_tree, 2); // +2 420 tree[i].value = vm.Check<uint32_t>(-1); 421 lua_pop(vm, 2); // 0 422 423 type = lua_rawgeti(vm, lua_tree, 3); // +1 424 tree[i].left = ParseTree(vm, tree, lua_gettop(vm), type); 425 lua_pop(vm, 1); // 0 426 427 type = lua_rawgeti(vm, lua_tree, 4); // +1 428 tree[i].right = ParseTree(vm, tree, lua_gettop(vm), type); 429 lua_pop(vm, 1); // 0 430 return i+1; 431 } 432 433 InstructionJumpIfItem::InstructionJumpIfItem( 434 Key k, Context& ctx, Libshit::Lua::StateRef vm, uint8_t opcode, 435 Libshit::NotNull<LabelPtr> tgt, Libshit::Lua::RawTable lua_tree) 436 : InstructionBase{k, ctx, opcode}, tgt{tgt} 437 { ParseTree(vm, tree, lua_tree, LUA_TTABLE); } 438 #endif 439 440 void InstructionJumpIfItem::Dispose() noexcept 441 { 442 tree.clear(); 443 InstructionBase::Dispose(); 444 } 445 446 void InstructionJumpIfItem::Parse_(Context& ctx, Source& src) 447 { 448 src.CheckRemainingSize(sizeof(FixParams)); 449 auto fp = src.ReadGen<FixParams>(); 450 fp.Validate(src.GetRemainingSize(), ctx.GetSize()); 451 tgt = ctx.GetLabelTo(fp.tgt); 452 453 uint16_t n = fp.size; 454 src.CheckRemainingSize(n * sizeof(NodeParams)); 455 tree.reserve(n); 456 for (uint16_t i = 0; i < n; ++i) 457 { 458 auto nd = src.ReadGen<NodeParams>(); 459 nd.Validate(n); 460 tree.push_back({nd.operation, nd.value, nd.left, nd.right}); 461 } 462 } 463 464 void InstructionJumpIfItem::Dump_(Sink& sink) const 465 { 466 InstrDump(sink); 467 sink.WriteGen(FixParams{tree.size(), ToFilePos(tgt->GetPtr())}); 468 for (auto& n : tree) 469 sink.WriteGen(NodeParams{n.operation, n.value, n.left, n.right}); 470 } 471 472 void InstructionJumpIfItem::Inspect_(std::ostream& os, unsigned indent) const 473 { 474 InstrInspect(os, indent) << ", " << PrintLabel(tgt) << ", "; 475 InspectNode(os, 0); 476 os << ')'; 477 } 478 479 void InstructionJumpIfItem::InspectNode(std::ostream& os, size_t i) const 480 { 481 if (i >= tree.size()) 482 { 483 os << "nil"; 484 return; 485 } 486 487 auto& n = tree[i]; 488 os << '{' << unsigned(n.operation) << ", " << n.value << ", "; 489 InspectNode(os, n.left - 1); 490 os << ", "; 491 InspectNode(os, n.right - 1); 492 os << '}'; 493 } 494 495 void InstructionJumpIfItem::PostInsert(Flavor f) 496 { 497 MaybeCreateUnchecked<InstructionBase>(tgt->GetPtr(), f); 498 MaybeCreateUnchecked<InstructionBase>(&*++Iterator(), f); 499 } 500 501 // ------------------------------------------------------------------------ 502 503 void InstructionJumpSwitchItemNoire::FixParams::Validate(FilePosition rem_size) 504 { 505 LIBSHIT_VALIDATE_FIELD("Stsc::InstructionJumpSwitchItemNoire::FixParams", 506 size * sizeof(ExpressionParams) <= rem_size); 507 } 508 509 void InstructionJumpSwitchItemNoire::ExpressionParams::Validate( 510 FilePosition size) 511 { 512 LIBSHIT_VALIDATE_FIELD( 513 "Stsc::InstructionJumpSwitchItemNoire::ExpressionParams", tgt < size); 514 } 515 516 InstructionJumpSwitchItemNoire::InstructionJumpSwitchItemNoire( 517 Key k, Context& ctx, uint8_t opcode, Source src) 518 : InstructionBase{k, ctx, opcode} 519 { 520 ADD_SOURCE(Parse_(ctx, src), src); 521 } 522 523 InstructionJumpSwitchItemPotbb::InstructionJumpSwitchItemPotbb( 524 Key k, Context& ctx, uint8_t opcode, Source src) 525 : InstructionJumpSwitchItemNoire{k, ctx, opcode} 526 { 527 ADD_SOURCE(Parse_(ctx, src), src); 528 } 529 530 void InstructionJumpSwitchItemNoire::Dispose() noexcept 531 { 532 expressions.clear(); 533 InstructionBase::Dispose(); 534 } 535 536 void InstructionJumpSwitchItemNoire::Parse_(Context& ctx, Source& src) 537 { 538 src.CheckRemainingSize(sizeof(FixParams)); 539 auto fp = src.ReadGen<FixParams>(); 540 fp.Validate(src.GetRemainingSize()); 541 542 expected_val = fp.expected_val; 543 last_is_default = fp.size & 0x8000; 544 auto size = last_is_default ? fp.size & 0x7ff : uint16_t(fp.size); 545 546 expressions.reserve(size); 547 for (uint16_t i = 0; i < size; ++i) 548 { 549 auto exp = src.ReadGen<ExpressionParams>(); 550 exp.Validate(ctx.GetSize()); 551 expressions.emplace_back( 552 exp.expression, ctx.GetLabelTo(exp.tgt)); 553 } 554 } 555 556 void InstructionJumpSwitchItemPotbb::Parse_(Context& ctx, Source& src) 557 { 558 InstructionJumpSwitchItemNoire::Parse_(ctx, src); 559 src.CheckRemainingSize(1); 560 trailing_byte = src.ReadLittleUint8(); 561 } 562 563 void InstructionJumpSwitchItemNoire::Dump_(Sink& sink) const 564 { 565 InstrDump(sink); 566 sink.WriteGen(FixParams{expected_val, 567 (last_is_default << 15) | expressions.size()}); 568 for (auto& e : expressions) 569 sink.WriteGen(ExpressionParams{ 570 e.expression, ToFilePos(e.target->GetPtr())}); 571 } 572 573 void InstructionJumpSwitchItemPotbb::Dump_(Sink& sink) const 574 { 575 InstructionJumpSwitchItemNoire::Dump_(sink); 576 sink.WriteLittleUint8(trailing_byte); 577 } 578 579 void InstructionJumpSwitchItemNoire::InspectBase( 580 std::ostream& os, unsigned indent) const 581 { 582 InstrInspect(os, indent) << ", " << expected_val << ", " 583 << last_is_default << ", {"; 584 bool first = true; 585 for (auto& e : expressions) 586 { 587 if (!first) os << ", "; 588 first = false; 589 os << '{' << e.expression << ", " << PrintLabel(e.target) << '}'; 590 } 591 os << '}'; 592 } 593 594 void InstructionJumpSwitchItemNoire::Inspect_( 595 std::ostream& os, unsigned indent) const 596 { 597 InspectBase(os, indent); 598 os << ')'; 599 } 600 601 void InstructionJumpSwitchItemPotbb::Inspect_( 602 std::ostream& os, unsigned indent) const 603 { 604 InspectBase(os, indent); 605 os << ", " << int(trailing_byte) << ')'; 606 } 607 608 void InstructionJumpSwitchItemNoire::PostInsert(Flavor f) 609 { 610 for (const auto& e : expressions) 611 MaybeCreate<InstructionBase>(e.target->GetPtr(), f); 612 if (!last_is_default) 613 MaybeCreateUnchecked<InstructionBase>(&*++Iterator(), f); 614 } 615 616 } 617 618 #if LIBSHIT_WITH_LUA 619 namespace Libshit::Lua 620 { 621 622 template <bool NoReturn, typename... Args> 623 struct TypeRegisterTraits<Neptools::Stsc::SimpleInstruction<NoReturn, Args...>> 624 { 625 using T = Neptools::Stsc::SimpleInstruction<NoReturn, Args...>; 626 627 template <size_t I> 628 static RetNum Get0(StateRef vm, T& instr, int idx) 629 { 630 if constexpr (I == sizeof...(Args)) 631 lua_pushnil(vm); 632 else if (idx == I) 633 vm.Push(std::get<I>(instr.args)); 634 else 635 return Get0<I+1>(vm, instr, idx); 636 return 1; 637 } 638 static void Get1(const T&, Libshit::Lua::VarArg) noexcept {} 639 640 641 template <size_t I> 642 static void Set(StateRef vm, T& instr, int idx, Skip val) 643 { 644 (void) val; 645 if constexpr (I == sizeof...(Args)) 646 luaL_error(vm, "trying to set invalid index"); 647 else if (idx == I) 648 std::get<I>(instr.args) = vm.Check<std::tuple_element_t< 649 I, typename T::ArgsT>>(3); 650 else 651 Set<I+1>(vm, instr, idx, {}); 652 } 653 654 static void Register(TypeBuilder& bld) 655 { 656 bld.Inherit<T, Neptools::Stsc::InstructionBase>(); 657 658 // that tuple constructors can blow up exponentially, disable overload 659 // check (tuple constructors can't take source, so it should be ok) 660 bld.AddFunction< 661 TypeTraits<T>::template Make< 662 Neptools::Context::Key, Neptools::Context&, uint8_t, Neptools::Source&>, 663 TypeTraits<T>::template Make< 664 Neptools::Context::Key, Neptools::Context&, uint8_t, 665 LuaGetRef<Neptools::Stsc::TupleTypeMapT<Args>>...> 666 >("new"); 667 668 bld.AddFunction<&Get0<0>, &Get1>("get"); 669 bld.AddFunction<&Set<0>>("set"); 670 } 671 }; 672 673 namespace 674 { 675 struct LIBSHIT_NOLUA InstructionItem : StaticClass 676 { 677 constexpr static char TYPE_NAME[] = "neptools.stsc.instruction_item"; 678 }; 679 680 template <typename T> struct InstructionReg; 681 template <typename... X> struct InstructionReg<boost::mp11::mp_list<X...>> 682 { 683 static void GetTab(Lua::StateRef vm, int i, int& prev) 684 { 685 if (i == prev) return; 686 if (prev != -1) lua_pop(vm, 1); 687 prev = i; 688 lua_createtable(vm, 255, 0); 689 lua_pushvalue(vm, -1); 690 lua_rawseti(vm, -4, i); 691 } 692 693 static void Register(TypeBuilder& bld) 694 { 695 static_assert(sizeof...(X) > 0); 696 auto vm = bld.GetVm(); 697 int prev = -1; 698 ((GetTab(vm, static_cast<int>(X::first_type::value), prev), 699 TypeRegister::Register<Neptools::Stsc::InstructionItem< 700 X::first_type::value, X::second_type::value>>(vm), 701 lua_rawseti(vm, -2, X::second_type::value)), ...); 702 lua_pop(vm, 1); 703 } 704 }; 705 706 } 707 708 template<> struct TypeRegisterTraits<InstructionItem> 709 : InstructionReg<Neptools::Stsc::AllOpcodes> {}; 710 711 static TypeRegister::StateRegister<InstructionItem> reg; 712 713 } 714 715 #include <libshit/container/vector.lua.hpp> 716 LIBSHIT_STD_VECTOR_LUAGEN( 717 label, Libshit::NotNull<Neptools::LabelPtr>); 718 LIBSHIT_STD_VECTOR_LUAGEN( 719 stsc_instruction_jump_if_item_node, 720 Neptools::Stsc::InstructionJumpIfItem::Node); 721 LIBSHIT_STD_VECTOR_LUAGEN( 722 stsc_instruction_jump_switch_item_noire_expression, 723 Neptools::Stsc::InstructionJumpSwitchItemNoire::Expression); 724 #include "instruction.binding.hpp" 725 726 #endif