js.hpp (2570B)
1 #ifndef GUARD_SHIRTILY_SUBCORNEAL_ISOPROPYLTHIOGALACTOSIDE_DECULTURALIZES_7789 2 #define GUARD_SHIRTILY_SUBCORNEAL_ISOPROPYLTHIOGALACTOSIDE_DECULTURALIZES_7789 3 #pragma once 4 5 #include <libshit/except.hpp> 6 #include <libshit/random.hpp> 7 8 #include <libshit/assert.hpp> 9 #include <libshit/nonowning_string.hpp> 10 #include <libshit/utils.hpp> 11 #include <libshit/wtf8.hpp> 12 13 #include <csetjmp> 14 #include <stdexcept> 15 #include <string> 16 17 struct js_State; 18 19 namespace Scraps 20 { 21 22 LIBSHIT_GEN_EXCEPTION_TYPE(JsError, std::runtime_error); 23 24 #if LIBSHIT_HAS_ASSERT 25 # define SCRAPS_JS_GETTOP(vm, name) auto name = js_gettop(vm) 26 # define SCRAPS_JS_CHECKTOP(vm, val) LIBSHIT_ASSERT(js_gettop(vm) == (val)) 27 #else 28 # define SCRAPS_JS_GETTOP(vm, name) ((void) 0) 29 # define SCRAPS_JS_CHECKTOP(vm, val) ((void) 0) 30 #endif 31 32 class JsRef 33 { 34 public: 35 constexpr JsRef(js_State* vm) noexcept : vm{vm} {} 36 constexpr operator js_State*() noexcept { return vm; } 37 38 void EvalToString(std::string& out, Libshit::StringView src); 39 std::string EvalToString(Libshit::StringView src) 40 { std::string res; EvalToString(res, src); return res; } 41 42 void PushEval(Libshit::StringView src); 43 44 template <typename T, typename U = js_State*> 45 void Catch(T fun, U vm_ = nullptr) 46 { 47 // I do not want to include mujs.h here, so abuse templates 48 vm_ = vm; 49 auto top = js_gettop(vm_); 50 // because mujs has to use braindead CESU8 and return void* instead of 51 // jmp_buf which automatically decays to void* then inplicitly convertible 52 // back to jmp_buf on most C compilers, because usually jmp_buf is typedefd 53 // to something[1], but it's actually `typedef /* unspecified */ jmp_buf;` 54 // according to the C standard, so it doesn't have to work even on C, and 55 // it's completely broken on C++. why must everyone be a fucking idiot?! 56 if (setjmp(*reinterpret_cast<jmp_buf*>(js_savetry(vm_)))) 57 { 58 auto s = Libshit::Cesu8ToWtf8(js_tostring(vm_, -1)); 59 js_pop(vm_, js_gettop(vm_) - top); 60 LIBSHIT_THROW(JsError, Libshit::Move(s)); 61 } 62 63 // can't use AtScopeExit here because longjmping over a variable with 64 // non-trivial destructor is UB 65 try { fun(); } catch (...) { js_endtry(vm_); throw; } 66 js_endtry(vm_); 67 } 68 69 protected: 70 js_State* vm; 71 }; 72 73 class JsState final : public JsRef 74 { 75 JsState(int dummy); 76 public: 77 JsState(Libshit::Xoshiro256p& random); 78 ~JsState() noexcept; 79 JsState(const JsState&) = delete; 80 void operator=(const JsState&) = delete; 81 82 }; 83 84 } 85 86 #endif