diff --git a/.gitignore b/.gitignore index 1576c988..1dbd30dc 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ tulip/macos/dist tulip/macos/lextab.py tulip/macos/yacctab.py tulip/linux/build-standard +tulip/web/build-standard tulip/linux/dev tulip/ios/build-standard tulip/esp32s3/managed_components diff --git a/amy b/amy index 66d31441..8af2ce83 160000 --- a/amy +++ b/amy @@ -1 +1 @@ -Subproject commit 66d31441ed50f61a0fc4873c6c27c8de937606e0 +Subproject commit 8af2ce834066ad5d5428154fa95cfa2b8b554a02 diff --git a/tulip/fs/ex/xanadu.py b/tulip/fs/ex/xanadu.py index 485fbbce..eaa30629 100644 --- a/tulip/fs/ex/xanadu.py +++ b/tulip/fs/ex/xanadu.py @@ -160,9 +160,9 @@ def broken_chord(base_pitch, intervals, start_time, **kwargs): wait_for(53000) # Crude fade-out. -for i in range(10): - amy.volume(1 - i / 10) - time.sleep(0.1) +#for i in range(10): +# amy.send(volume=1 - i / 10) +# time.sleep(0.1) midi.Synth.reset() diff --git a/tulip/release.sh b/tulip/release.sh index 92fb8cc9..fa9e589b 100755 --- a/tulip/release.sh +++ b/tulip/release.sh @@ -1,6 +1,6 @@ #!/bin/bash # This script cleans, builds and uploads binaries for the 4 supported Tulip CC versions -# It also does this for Tulip Desktop macOS. +# It also does this for Tulip Desktop macOS and Tulip Web. # call it like ./release.sh v-jan-2024 upload , where v-jan-2024 is a github release tag # and upload is one of [sys, upload, test] @@ -65,6 +65,14 @@ if [ "$TYPE" == "upload" ]; then fi cd .. +# Now do web +cd ../web +make clean +./build.sh +if [ "$TYPE" == "upload" ]; then + git commit -a -m "deploying Tulip Web"; git push -u origin HEAD; gh pr create -f; gh pr merge -m +fi +cd .. diff --git a/tulip/shared/alles.c b/tulip/shared/alles.c index a71ba537..41499dfa 100644 --- a/tulip/shared/alles.c +++ b/tulip/shared/alles.c @@ -222,8 +222,6 @@ void run_alles() { esp_amy_init(); amy_reset_oscs(); - // Schedule a "turning on" sound - bleep(); // // Spin this core until the power off button is pressed, parsing events and making sounds //while(status & RUNNING) { @@ -238,9 +236,6 @@ void * alles_start(void *vargs) { alles_local_ip[0] = 0; unix_amy_init(); amy_reset_oscs(); - // Schedule a "turning on" sound - // We don't do this by default on tulip desktop as all threads start at once and it makes the bleep sound bad - bleep(); // Spin this core until the power off button is pressed, parsing events and making sounds while(status & RUNNING) { delay_ms(10); diff --git a/tulip/shared/desktop/unix_display.c b/tulip/shared/desktop/unix_display.c index 442156b1..6ed85b8e 100644 --- a/tulip/shared/desktop/unix_display.c +++ b/tulip/shared/desktop/unix_display.c @@ -162,7 +162,6 @@ int8_t compute_viewport(uint16_t tw, uint16_t th, int8_t resize_tulip) { viewport.w = (int)((float)tulip_rect.w * w_ratio); viewport.h = (int)((float)tulip_rect.h * h_ratio); viewport.x = (sw - viewport.w) / 2; - return 1; // ok } @@ -173,6 +172,7 @@ int unix_display_draw() { frame_ticks = get_ticks_ms(); + uint8_t *pixels; int pitch; @@ -200,14 +200,15 @@ int unix_display_draw() { SDL_UnlockTexture(framebuffer); +#ifndef __EMSCRIPTEN__ SDL_RenderPresent(default_renderer); - +#endif // Clean up and show SDL_UpdateWindowSurface(window); display_frame_done_generic(); - + // Are we restarting the display for a mode change, or quitting if(unix_display_flag < 0) { destroy_window(); @@ -219,6 +220,9 @@ int unix_display_draw() { } } + + + return get_ticks_ms() - frame_ticks; } @@ -244,6 +248,12 @@ void init_window() { // If this is not set it prevents sleep on a mac (at least) SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1"); SDL_SetWindowTitle(window, "Tulip Desktop"); + +#ifdef __EMSCRIPTEN__ // Tulip web deskop + const int simulate_infinite_loop = 0; // call the function repeatedly + const int fps = 0; // call the function as fast as the browser wants to render (typically 60fps) +// emscripten_set_main_loop(show_frame, NULL, fps, simulate_infinite_loop); +#endif } diff --git a/tulip/shared/display.c b/tulip/shared/display.c index e9dea382..f6ac2b4b 100644 --- a/tulip/shared/display.c +++ b/tulip/shared/display.c @@ -901,7 +901,7 @@ void display_tfb_str(unsigned char*str, uint16_t len, uint8_t format, uint8_t fg } -extern float unix_display_set_clock(uint8_t mhz); +extern void unix_display_set_clock(uint8_t mhz); void display_set_clock(uint8_t mhz) { if(mhz > 1 && mhz < 50) { #ifdef ESP_PLATFORM diff --git a/tulip/shared/midi.c b/tulip/shared/midi.c index e506b945..9fd95a4e 100644 --- a/tulip/shared/midi.c +++ b/tulip/shared/midi.c @@ -38,7 +38,7 @@ void callback_midi_message_received(uint8_t *data, size_t len) { if (midi_queue_tail == midi_queue_head) { // Queue wrap, drop oldest item. midi_queue_head = (midi_queue_head + 1) % MIDI_QUEUE_DEPTH; - fprintf(stderr, "dropped midi message\n"); + //fprintf(stderr, "dropped midi message\n"); } // We tell Python that a MIDI message has been received @@ -125,6 +125,11 @@ void convert_midi_bytes_to_messages(uint8_t * data, size_t len, uint8_t usb) { } } +void process_single_midi_byte(uint8_t byte) { + uint8_t data[1]; + data[0] = byte; + convert_midi_bytes_to_messages(data, 1, 1); +} void midi_local(uint8_t * bytes, uint16_t len) { @@ -210,9 +215,17 @@ void run_midi() { // defined in virtualmidi.m #else -// This is MIDI out on tulip desktop that is NOT macos... not supported +// This is MIDI out on tulip desktop that is NOT macos... web or linux void midi_out(uint8_t * bytes, uint16_t len) { - // nothing yet + #ifdef __EMSCRIPTEN__ + EM_ASM( + if(midiOutputDevice != null) { + midiOutputDevice.send(HEAPU8.subarray($0, $0 + $1)); + }, bytes, len + ); + #else + // nothing yet for linux + #endif } #endif diff --git a/tulip/shared/midi.h b/tulip/shared/midi.h index 5cbd74ea..b4540356 100644 --- a/tulip/shared/midi.h +++ b/tulip/shared/midi.h @@ -1,6 +1,6 @@ // midi.h -#include "alles.h" #ifdef ESP_PLATFORM +#include "alles.h" #include "soc/uart_reg.h" extern QueueHandle_t uart_queue; #else @@ -10,6 +10,7 @@ extern QueueHandle_t uart_queue; #include "py/mphal.h" #include "py/runtime.h" void convert_midi_bytes_to_messages(uint8_t * data, size_t len, uint8_t usb); +void process_single_midi_byte(uint8_t byte); extern mp_obj_t midi_callback; diff --git a/tulip/shared/modtulip.c b/tulip/shared/modtulip.c index ba60a953..b0d2c3c5 100644 --- a/tulip/shared/modtulip.c +++ b/tulip/shared/modtulip.c @@ -10,10 +10,12 @@ #include "bresenham.h" #include "extmod/vfs.h" #include "py/stream.h" +#ifndef __EMSCRIPTEN__ #include "alles.h" +#endif #include "midi.h" -#include "ui.h" #include "tsequencer.h" +#include "ui.h" #include "keyscan.h" #include "genhdr/mpversion.h" @@ -27,7 +29,7 @@ // tulip.display_clock(18) // clock = tulip.display_clock() -extern float unix_display_set_clock(); +extern void unix_display_set_clock(uint8_t); extern void display_start(); extern void display_stop(); extern void save_tfb(); @@ -394,6 +396,8 @@ STATIC mp_obj_t tulip_board(size_t n_args, const mp_obj_t *args) { return mp_obj_new_str("N32R8", strlen("N32R8")); #elif defined TULIP_DESKTOP return mp_obj_new_str("DESKTOP", strlen("DESKTOP")); +#elif defined TULIP_WEB + return mp_obj_new_str("WEB", strlen("WEB")); #else return mp_obj_new_str("OTHER", strlen("OTHER")); #endif @@ -461,7 +465,8 @@ STATIC mp_obj_t tulip_defer(size_t n_args, const mp_obj_t *args) { if(index>=0) { defer_callbacks[index] = args[0]; defer_args[index] = args[1]; - defer_sysclock[index] = amy_sysclock() + mp_obj_get_int(args[2]); + defer_sysclock[index] = get_ticks_ms() + mp_obj_get_int(args[2]); + } else { mp_raise_ValueError(MP_ERROR_TEXT("No more defer slots available")); } @@ -856,7 +861,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(tulip_int_screenshot_obj, 1, 1, tulip extern void mcast_send(char*, uint16_t len); - +#ifndef __EMSCRIPTEN__ STATIC mp_obj_t tulip_alles_send(size_t n_args, const mp_obj_t *args) { if(n_args > 1) { if(mp_obj_get_int(args[1])) { // mesh @@ -913,6 +918,8 @@ STATIC mp_obj_t tulip_set_quartet(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(tulip_set_quartet_obj, 1, 1, tulip_set_quartet); +#endif + STATIC mp_obj_t tulip_brightness(size_t n_args, const mp_obj_t *args) { if(n_args > 0) { @@ -1075,6 +1082,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(tulip_cpu_obj, 0, 1, tulip_cpu); #ifndef ESP_PLATFORM #ifndef __linux__ +#ifndef __EMSCRIPTEN__ extern char* get_tulip_home_path(); STATIC mp_obj_t tulip_app_path(size_t n_args, const mp_obj_t *args) { char * path = get_tulip_home_path(); @@ -1084,6 +1092,7 @@ STATIC mp_obj_t tulip_app_path(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(tulip_app_path_obj, 0, 0, tulip_app_path); #endif #endif +#endif STATIC mp_obj_t tulip_bg_bezier(size_t n_args, const mp_obj_t *args) { uint16_t x0 = mp_obj_get_int(args[0]); @@ -1303,12 +1312,14 @@ STATIC const mp_rom_map_elem_t tulip_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_key_editor), MP_ROM_PTR(&tulip_key_editor_obj) }, { MP_ROM_QSTR(MP_QSTR_activate_editor), MP_ROM_PTR(&tulip_activate_editor_obj) }, { MP_ROM_QSTR(MP_QSTR_int_screenshot), MP_ROM_PTR(&tulip_int_screenshot_obj) }, +#ifndef __EMSCRIPTEN__ { MP_ROM_QSTR(MP_QSTR_multicast_start), MP_ROM_PTR(&tulip_multicast_start_obj) }, { MP_ROM_QSTR(MP_QSTR_alles_send), MP_ROM_PTR(&tulip_alles_send_obj) }, { MP_ROM_QSTR(MP_QSTR_alles_map), MP_ROM_PTR(&tulip_alles_map_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_quartet), MP_ROM_PTR(&tulip_set_quartet_obj) }, +#endif { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&tulip_brightness_obj) }, { MP_ROM_QSTR(MP_QSTR_rgb332_565), MP_ROM_PTR(&tulip_rgb332_565_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_quartet), MP_ROM_PTR(&tulip_set_quartet_obj) }, { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&tulip_keys_obj) }, { MP_ROM_QSTR(MP_QSTR_touch), MP_ROM_PTR(&tulip_touch_obj) }, { MP_ROM_QSTR(MP_QSTR_touch_delta), MP_ROM_PTR(&tulip_touch_delta_obj) }, @@ -1340,9 +1351,11 @@ STATIC const mp_rom_map_elem_t tulip_module_globals_table[] = { // Special platform specific things #ifndef ESP_PLATFORM #ifndef __linux__ +#ifndef __EMSCRIPTEN__ { MP_ROM_QSTR(MP_QSTR_app_path), MP_ROM_PTR(&tulip_app_path_obj) }, #endif #endif +#endif }; diff --git a/tulip/shared/polyfills.c b/tulip/shared/polyfills.c index a67aa94e..3e4f557c 100644 --- a/tulip/shared/polyfills.c +++ b/tulip/shared/polyfills.c @@ -5,6 +5,17 @@ // free(?) // thread / xtaskCreate +#ifdef AMY_IS_EXTERNAL +void * malloc_caps(uint32_t size, uint32_t flags) { +#ifdef ESP_PLATFORM + //fprintf(stderr, "allocing size %ld flags %ld\n", size, flags); + return heap_caps_malloc(size, flags); +#else + // ignore flags + return malloc(size); +#endif +} +#endif #ifndef ESP_PLATFORM @@ -45,7 +56,11 @@ void delay_ms(uint32_t ms) { #ifdef ESP_PLATFORM vTaskDelay(ms / portTICK_PERIOD_MS); #else + #ifndef __EMSCRIPTEN__ usleep(ms * 1000); + #else + // nothing + #endif #endif } @@ -68,7 +83,11 @@ int64_t get_time_ms() { return mp_hal_ticks_ms(); // a large number } int32_t get_ticks_ms() { +#ifndef __EMSCRIPTEN__ return amy_sysclock(); // based on audio driver +#else + return mp_hal_ticks_ms(); +#endif } void *calloc_caps(uint32_t align, uint32_t count, uint32_t size, uint32_t flags) { diff --git a/tulip/shared/polyfills.h b/tulip/shared/polyfills.h index 358b5f60..429babe6 100644 --- a/tulip/shared/polyfills.h +++ b/tulip/shared/polyfills.h @@ -2,7 +2,9 @@ #include #include "py/mphal.h" +#ifndef __EMSCRIPTEN__ #include "amy.h" +#endif #ifdef ESP_PLATFORM // not sure, maybe esp includes? extern void esp32s3_display_start(); diff --git a/tulip/shared/py/_boot.py b/tulip/shared/py/_boot.py index 66ce9cce..b7cd6858 100644 --- a/tulip/shared/py/_boot.py +++ b/tulip/shared/py/_boot.py @@ -1,10 +1,12 @@ import gc import uos -import tulip, world, sys, midi, amy, alles - +import tulip, sys, midi, amy, alles, world from upysh import * from tulip import edit, run + # This _boot runs both desktop and esp32s3 + + try: from esp32 import Partition try: @@ -24,40 +26,48 @@ except OSError: # this is you booting a non-OTA esp32 device. it's ok! pass - + + except ImportError: - # Tulip Desktop + # Not a hardware Tulip try: tulipcc = tulip.root_dir() - try: + if(not tulip.exists(tulipcc)): mkdir(tulipcc) - except OSError: - # already exists, that's fine - pass - + # On Desktop, we can put sys in sys/ and user in user/ - try: - mkdir(tulipcc+"sys") - tulip.desktop_copy_sys(tulipcc+"sys") - except OSError: - # already exists, do nothing - pass - - try: - mkdir(tulipcc+"user") - except OSError: - # Already exists, don't do anything - pass + if(tulip.board()=='DESKTOP'): + try: + mkdir(tulipcc+"sys") + tulip.desktop_copy_sys(tulipcc+"sys") + except OSError: + # already exists, do nothing + pass + + try: + mkdir(tulipcc+"user") + except OSError: + # Already exists, don't do anything + pass cd(tulip.root_dir()+"user") + tulip.add_to_bootpy("# boot.py\n# Put anything here you want to run on Tulip startup\n", only_first_create=True) sys.path.append("../sys/ex") - except: + except Exception as e: + sys.print_exception(e) # Probably iOS cd(tulip.app_path()) gc.collect() -# Override amy's send to work with tulip -amy.override_send = lambda x: tulip.alles_send(x, alles.mesh_flag) -midi.setup() + +# Set up audio/midi. +if(tulip.board() == "WEB"): + midi.setup() + # Override send & bleep are done from JS on web because of click-to-start audio. +else: + # Override amy's send to work with tulip + amy.override_send = lambda x: tulip.alles_send(x, alles.mesh_flag) + midi.setup() + midi.startup_bleep() diff --git a/tulip/shared/py/drums.py b/tulip/shared/py/drums.py index 172d24df..860ae07c 100644 --- a/tulip/shared/py/drums.py +++ b/tulip/shared/py/drums.py @@ -263,7 +263,6 @@ def run(screen): app.add(app.leds, direction=lv.ALIGN.OUT_BOTTOM_LEFT, pad_y=0) app.rows = [DrumRow([x[1] for x in drumkit], i, midi_note=i) for i in range(7)] app.add(app.rows, direction=lv.ALIGN.OUT_BOTTOM_LEFT) - for i,row in enumerate(app.rows): row.set_preset([1, 2, 0, 6, 7, 9, 10][i]) row.set_vel(.5) diff --git a/tulip/shared/py/midi.py b/tulip/shared/py/midi.py index d8865c24..033dbee4 100644 --- a/tulip/shared/py/midi.py +++ b/tulip/shared/py/midi.py @@ -33,6 +33,8 @@ def add_synth_object(self, channel, synth_object): def add_synth(self, channel=1, patch_number=0, num_voices=6): if channel == 10: synth_object = DrumSynth(num_voices=num_voices) + elif channel == 16: + synth_object = OscSynth(num_voices=1) # the "system bleep" synth else: synth_object = Synth(num_voices=num_voices, patch_number=patch_number) self.add_synth_object(channel, synth_object) @@ -485,8 +487,9 @@ def ensure_midi_config(): if not config: # Tulip defaults, 6 note polyphony on channel 1 # drum machine always on channel 10 + # utility sine wave bleeper on channel 16 config = MidiConfig( - voices_per_channel={1: 6, 10: 10}, + voices_per_channel={1: 6, 10: 10, 16: 1}, patch_per_channel={1: 0}, show_warnings=True, ) @@ -665,6 +668,14 @@ def c_fired_midi_event(x): m = tulip.midi_in() +# Resets AMY timebase and plays the bleep +def startup_bleep(): + amy.send(reset=amy.RESET_TIMEBASE) + if 16 in config.synth_per_channel: + config.synth_per_channel[16].note_on(57, 1, time=0) + config.synth_per_channel[16].note_on(69, 1, time=150) + config.synth_per_channel[16].note_off(69, time=300) + def deferred_midi_config(t): setup_midi_codes() @@ -674,6 +685,7 @@ def deferred_midi_config(t): ensure_midi_config() def setup(): + deferred_midi_config(None) # we can't setup on boot right away as we need to get the bleep going and the alles setup done, so wait on a defer - tulip.defer(deferred_midi_config, None, 500) + #tulip.defer(deferred_midi_config, None, 500) diff --git a/tulip/shared/py/tulip.py b/tulip/shared/py/tulip.py index 1265da40..f0872c53 100644 --- a/tulip/shared/py/tulip.py +++ b/tulip/shared/py/tulip.py @@ -1,29 +1,10 @@ # tulip.py - # Bring in all c-defined tulip functions from _tulip import * -import world from upysh import cd, pwd import amy -def root_dir(): - try: - import uos - - root_directory = "/" - if board() == "DESKTOP": - xdg_data_directory = uos.getenv("HOME") + "/.local/share" - - if (exists(xdg_data_directory)): - root_directory = xdg_data_directory + "/tulipcc/" - else: - # fall back to ~/Documents if XDG base directory spec is not supported - root_directory = uos.getenv("HOME") + "/Documents/tulipcc/" - - return root_directory - except: - return "/" def sys(): return root_dir()+"sys/" @@ -240,15 +221,20 @@ def prompt(prompt): return # Add a string to the users' boot.py -- used by some utlities -def add_to_bootpy(s): +# if only_first_create is set, will only write if the file doesn't exist yet +def add_to_bootpy(s, only_first_create=False): + first = False try: bootpy = open(tulip.root_dir()+"user/boot.py","r").read() except OSError: + first = True bootpy = "" # file doesn't exist yet + bootpy = bootpy + "\n" + s + "\n" - w = open(tulip.root_dir()+'user/boot.py','w') - w.write(bootpy) - w.close() + if((only_first_create and first) or (not only_first_create)): + w = open(tulip.root_dir()+'user/boot.py','w') + w.write(bootpy) + w.close() # Wrapper around AMY tempo to store it amy_bpm = 108 @@ -300,7 +286,8 @@ def root_dir(): else: # fall back to ~/Documents if XDG base directory spec is not supported root_directory = uos.getenv("HOME") + "/Documents/tulipcc/" - + elif board() == "WEB": + root_directory = "/tulip4/" return root_directory except: return "/" @@ -613,6 +600,7 @@ def url_put(url, filename, headers={"User-Agent":"TulipCC/4.0"}): f.close() def screenshot(filename=None): + import world from upysh import rm if(filename is not None): int_screenshot(filename) diff --git a/tulip/shared/py/webrequests.py b/tulip/shared/py/webrequests.py new file mode 100644 index 00000000..bd32ce8b --- /dev/null +++ b/tulip/shared/py/webrequests.py @@ -0,0 +1,142 @@ +# webrequests.py +# javascript version (as much as we can) of urequests.py + + +import json +import js + +def as_bytearray(buffer): + """ + Given a JavaScript ArrayBuffer, convert it to a Python bytearray in a + MicroPython friendly manner. + """ + ui8a = js.Uint8Array.new(buffer) + size = ui8a.length + ba = bytearray(size) + for i in range(0, size): + ba[i] = ui8a[i] + return ba + +### wrap the response to grant Pythonic results +class _Response: + def __init__(self, response): + self._response = response + + # grant access to response.ok and other fields + def __getattr__(self, attr): + return getattr(self._response, attr) + + # exposed methods with Pythonic results + async def arrayBuffer(self): + buffer = await self._response.arrayBuffer() + # works in Pyodide + if hasattr(buffer, "to_py"): + return buffer.to_py() + # shims in MicroPython + return memoryview(as_bytearray(buffer)) + + async def blob(self): + return await self._response.blob() + + async def bytearray(self): + buffer = await self._response.arrayBuffer() + return as_bytearray(buffer) + + async def json(self): + return json.loads(await self.text()) + + async def text(self): + return await self._response.text() + + +### allow direct await to _Response methods +class _DirectResponse: + @staticmethod + def setup(promise, response): + promise._response = _Response(response) + return promise._response + + def __init__(self, promise): + self._promise = promise + promise._response = None + promise.arrayBuffer = self.arrayBuffer + promise.blob = self.blob + promise.bytearray = self.bytearray + promise.json = self.json + promise.text = self.text + + async def _response(self): + if not self._promise._response: + await self._promise + return self._promise._response + + async def arrayBuffer(self): + response = await self._response() + return await response.arrayBuffer() + + async def blob(self): + response = await self._response() + return await response.blob() + + async def bytearray(self): + response = await self._response() + return await response.bytearray() + + async def json(self): + response = await self._response() + return await response.json() + + async def text(self): + response = await self._response() + return await response.text() + + +def fetch(url, **kw): + # workaround Pyodide / MicroPython dict <-> js conversion + options = js.JSON.parse(json.dumps(kw)) + awaited = lambda response, *args: _DirectResponse.setup(promise, response) + promise = js.fetch(url, options).then(awaited) + _DirectResponse(promise) + return promise + + +""" +def get(url): + import js + print(f"fetching {url}...") + res = await js.fetch(url) + json = await res.json() + for i in dir(json): + print(f"{i}: {json[i]}") + return json + + + + +#def get(url, headers = {}): +# return await js.fetch(url, method='GET', headers=headers) + + json = await res.json() + + response = requests.get(base_url+"messages?limit=%d" % (chunk_size), headers = headers) + response = requests.get(base_url+"messages?limit=%d&before=%s" % (chunk_size, oldest_id), headers=headers) + api_response = requests.post( + files_base_url+"attachments", + headers=headers, + json={"files": [{"filename": filename, "file_size": filesize, "id": 1}]}, + ) + + put_response = requests.put( + put_url, + headers={ + "Authorization": headers['Authorization'], + "User-Agent": headers['User-Agent'], + "Content-Length": str(filesize), + "Content-Type": "application/octet-stream", + }, + data=f, + ) + + r = requests.post(files_base_url+"messages", headers = headers, data = json.dumps(payload)) + r = requests.post(text_base_url+"messages", headers = headers, data = json.dumps ( {"content":u + " ### " + message} )) +""" diff --git a/tulip/shared/py/world.py b/tulip/shared/py/world.py index 34c2e467..841207b0 100644 --- a/tulip/shared/py/world.py +++ b/tulip/shared/py/world.py @@ -1,10 +1,13 @@ # T U L I P ~ W O R L D # a Tulip only chat room and file transfer service -import urequests as requests import json import os import tulip +if(tulip.board()=="WEB"): + import webrequests as requests +else: + import urequests as requests MAX_DESCRIPTION_SIZE=50 MAX_USERNAME_SIZE=10 diff --git a/tulip/shared/tsequencer.c b/tulip/shared/tsequencer.c index 7acc35b5..49895352 100644 --- a/tulip/shared/tsequencer.c +++ b/tulip/shared/tsequencer.c @@ -1,16 +1,24 @@ #include "tsequencer.h" +#include + mp_obj_t sequencer_callbacks[SEQUENCER_SLOTS]; uint8_t sequencer_dividers[SEQUENCER_SLOTS]; mp_obj_t defer_callbacks[DEFER_SLOTS]; mp_obj_t defer_args[DEFER_SLOTS]; uint32_t defer_sysclock[DEFER_SLOTS]; +#ifdef AMY_IS_EXTERNAL +uint32_t sequencer_tick_count = 0; +#endif void tulip_amy_sequencer_hook(uint32_t tick_count) { + #ifdef AMY_IS_EXTERNAL + sequencer_tick_count = tick_count; + #endif for(uint8_t i=0;i defer_sysclock[i]) { - //fprintf(stderr, "calling defer with sysclock %" PRIu32 " and actual %" PRIu32"\n", defer_sysclock[i], amy_sysclock() ); + if(defer_callbacks[i] != NULL && get_ticks_ms() > defer_sysclock[i]) { + //fprintf(stderr, "calling defer with sysclock %" PRIu32 " and actual %" PRIu32"\n", defer_sysclock[i], get_ticks_ms() ); mp_sched_schedule(defer_callbacks[i], defer_args[i]); defer_callbacks[i] = NULL; defer_sysclock[i] = 0; defer_args[i] = NULL; } @@ -30,6 +38,7 @@ void tulip_amy_sequencer_hook(uint32_t tick_count) { void tsequencer_init() { for(uint8_t i=0;i #include "polyfills.h" +#ifndef AMY_IS_EXTERNAL #include "sequencer.h" +#else +extern uint32_t sequencer_tick_count; +#define AMY_SEQUENCER_PPQ 48 +#endif extern mp_obj_t sequencer_callbacks[SEQUENCER_SLOTS]; extern uint8_t sequencer_dividers[SEQUENCER_SLOTS]; @@ -18,5 +23,6 @@ extern mp_obj_t defer_args[DEFER_SLOTS]; void tsequencer_init(); +void tulip_amy_sequencer_hook(uint32_t tick_count); #endif \ No newline at end of file diff --git a/tulip/shared/tulip_helpers.c b/tulip/shared/tulip_helpers.c index 49d48663..017fb9c7 100644 --- a/tulip/shared/tulip_helpers.c +++ b/tulip/shared/tulip_helpers.c @@ -4,10 +4,15 @@ #include "ui.h" extern uint8_t keyboard_send_keys_to_micropython; extern int8_t keyboard_grab_ui_focus; - +#ifdef __EMSCRIPTEN__ +extern int mp_js_repl_process_char(int); +#endif void tx_char(int c) { if(keyboard_send_keys_to_micropython) { ringbuf_put(&stdin_ringbuf, c); + #ifdef __EMSCRIPTEN__ + mp_js_repl_process_char(c); + #endif } } @@ -106,7 +111,11 @@ uint32_t tulip_fread(mp_obj_t file, uint8_t * buf, uint32_t len) { } uint32_t tulip_fseek(mp_obj_t file, uint32_t seekpoint, int32_t whence) { + #ifdef __EMSCRIPTEN__ + return 0; + #else return mp_stream_posix_lseek(file, seekpoint, whence); + #endif } int32_t tulip_getline(char * line, uint32_t * len, mp_obj_t file ) { diff --git a/tulip/web/Makefile b/tulip/web/Makefile new file mode 100644 index 00000000..276b645d --- /dev/null +++ b/tulip/web/Makefile @@ -0,0 +1,234 @@ +################################################################################ +# Initial setup of Makefile environment. + +TOP = ../../micropython + +# Set parallel flag to # of CPUs +CPUS ?= $(shell sysctl -n hw.ncpu || echo 1) +MAKEFLAGS += --jobs=$(CPUS) + +# Select the variant to build for: +ifdef VARIANT_DIR +# Custom variant path - remove trailing slash and get the final component of +# the path as the variant name. +VARIANT ?= $(notdir $(VARIANT_DIR:/=)) +else +# If not given on the command line, then default to standard. +VARIANT ?= standard +VARIANT_DIR ?= variants/$(VARIANT) +endif + + +ifeq ($(wildcard $(VARIANT_DIR)/.),) +$(error Invalid VARIANT specified: $(VARIANT_DIR)) +endif + +# If the build directory is not given, make it reflect the variant name. +BUILD ?= build-$(VARIANT)/tulip/obj + +include $(TOP)/py/mkenv.mk +include $(VARIANT_DIR)/mpconfigvariant.mk + +# Use the default frozen manifest, variants may override this. +FROZEN_MANIFEST ?= variants/manifest.py + +# Qstr definitions (must come before including py.mk). +QSTR_DEFS = qstrdefsport.h + +# Include py core make definitions. +include $(TOP)/py/py.mk +include $(TOP)/extmod/extmod.mk + +################################################################################ +# Project specific settings and compiler/linker flags. + + +# LVGL stuff +LVGL_BINDING_DIR = $(TOP)/../lv_binding_micropython_tulip +LVGL_DIR = $(LVGL_BINDING_DIR)/lvgl +LVGL_GENERIC_DRV_DIR = $(LVGL_BINDING_DIR)/driver/generic +INC += -I$(LVGL_BINDING_DIR) -I. +ALL_LVGL_SRC = $(shell find $(LVGL_DIR) -type f) +LVGL_PP = $(BUILD)/lvgl/lvgl.pp.c +LVGL_MPY = $(BUILD)/lvgl/lv_mpy.c +LVGL_MPY_METADATA = $(BUILD)/lvgl/lv_mpy.json +QSTR_GLOBAL_DEPENDENCIES += $(LVGL_MPY) +CFLAGS_MOD += $(LV_CFLAGS) +SRC_C += $(shell find $(LVGL_DIR)/src -type f -name '*.c') +CFLAGS += -DLV_CONF_INCLUDE_SIMPLE + +# This is for the lvgl stuff that uses STATIC +CFLAGS += -DSTATIC=static + +$(LVGL_MPY): $(ALL_LVGL_SRC) $(LVGL_BINDING_DIR)/gen/gen_mpy.py + $(ECHO) "LVGL-GEN $@" + $(Q)mkdir -p $(dir $@) + $(Q)$(CPP) $(LV_CFLAGS) -DLVGL_PREPROCESS -I $(LVGL_BINDING_DIR)/pycparser/utils/fake_libc_include $(INC) $(LVGL_DIR)/lvgl.h > $(LVGL_PP) + $(Q)$(PYTHON) $(LVGL_BINDING_DIR)/gen/gen_mpy.py -M lvgl -MP lv -MD $(LVGL_MPY_METADATA) -E $(LVGL_PP) $(LVGL_DIR)/lvgl.h > $@ + + +CC = emcc +LD = emcc +NODE ?= node +TERSER ?= npx terser + +INC += -I. +INC += -I../shared/ +INC += -I../shared/desktop/ +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(VARIANT_DIR) +INC += -I$(TOP)/../lv_binding_micropython_tulip/lvgl/src +INC += -I$(TOP)/../lv_binding_micropython_tulip/lvgl/src/libs/lodepng + +CFLAGS += -Wall -Werror -Wdouble-promotion -Wfloat-conversion -DSTATIC=static -Wno-unused-variable -Wno-unused-function +CFLAGS += -O3 -DNDEBUG +CWARN += -Wextra -Wno-unused-parameter -Wno-unused-but-set-parameter -Wpointer-arith -Wno-double-promotion -Wfloat-conversion -Wno-missing-declarations -Wno-unused-but-set-variable -Wno-sign-compare -Wno-gnu-variable-sized-type-not-at-end -Wno-undefined-internal +CFLAGS += $(INC) $(CWARN) +CFLAGS += -DTULIP_WEB -DMA_ENABLE_AUDIO_WORKLETS -sUSE_SDL=2 -DAMY_IS_EXTERNAL + +EXPORTED_FUNCTIONS_EXTRA += ,\ + _mp_js_do_exec,\ + _mp_js_do_exec_async,\ + _mp_js_frozen_exec,\ + _mp_js_do_import,\ + _mp_js_register_js_module,\ + _proxy_c_free_obj,\ + _proxy_c_init,\ + _proxy_c_to_js_call,\ + _proxy_c_to_js_delete_attr,\ + _proxy_c_to_js_dir,\ + _proxy_c_to_js_get_array,\ + _proxy_c_to_js_get_dict,\ + _proxy_c_to_js_get_iter,\ + _proxy_c_to_js_get_type,\ + _proxy_c_to_js_has_attr,\ + _proxy_c_to_js_iternext,\ + _proxy_c_to_js_lookup_attr,\ + _proxy_c_to_js_resume,\ + _proxy_c_to_js_store_attr,\ + _proxy_convert_mp_to_js_obj_cside,\ + _tulip_tick + +EXPORTED_RUNTIME_METHODS_EXTRA += ,\ + PATH,\ + PATH_FS,\ + UTF8ToString,\ + getValue,\ + lengthBytesUTF8,\ + setValue,\ + stringToUTF8 + +JSFLAGS += \ + -lidbfs.js \ + -s USE_SDL=2 \ + -s ASYNCIFY \ + -s ASYNCIFY_STACK_SIZE=16000 \ + -s ASSERTIONS \ + -s EXPORTED_FUNCTIONS="\ + _free,\ + _malloc,\ + _mp_js_init,\ + _mp_js_repl_init,\ + _mp_js_repl_process_char,\ + _mp_hal_get_interrupt_char,\ + _mp_handle_pending,\ + _process_single_midi_byte,\ + _mp_sched_keyboard_interrupt$(EXPORTED_FUNCTIONS_EXTRA)" +JSFLAGS += -s EXPORTED_RUNTIME_METHODS="\ + ccall,\ + cwrap,\ + FS$(EXPORTED_RUNTIME_METHODS_EXTRA)" +JSFLAGS += --js-library library.js +JSFLAGS += -s SUPPORT_LONGJMP=emscripten +JSFLAGS += -s MODULARIZE -s EXPORT_NAME=_createMicroPythonModule +JSFLAGS += -s INITIAL_MEMORY=128mb -s TOTAL_STACK=64mb -s ALLOW_MEMORY_GROWTH=1 +JSFLAGS += --preload-file ../fs@tulip4/sys + +################################################################################ +# Source files and libraries. + +SRC_SHARED = $(addprefix shared/,\ + runtime/interrupt_char.c \ + runtime/stdout_helpers.c \ + runtime/pyexec.c \ + readline/readline.c \ + timeutils/timeutils.c \ + ) + +SRC_C += \ + lexer_dedent.c \ + main.c \ + modjs.c \ + modjsffi.c \ + mphalport.c \ + objjsproxy.c \ + proxy_c.c \ + $(LVGL_MPY) + + +TULIP_EXTMOD_DIR = ../shared +EXTMOD_SRC_C += $(addprefix $(TULIP_EXTMOD_DIR)/, \ + modtulip.c \ + polyfills.c \ + smallfont.c \ + display.c \ + u8g2_fonts.c \ + u8fontdata.c \ + bresenham.c \ + ui.c \ + help.c \ + tulip_helpers.c \ + editor.c \ + keyscan.c \ + lodepng.c \ + lvgl_u8g2.c \ + tsequencer.c \ + midi.c \ + desktop/unix_display.c \ + ) + +# List of sources for qstr extraction. +SRC_QSTR += $(SRC_C) $(SRC_SHARED) $(EXTMOD_SRC_C) + +SRC_JS += \ + api.js \ + objpyproxy.js \ + proxy_js.js \ + +OBJ += $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) + + +################################################################################ +# Main targets. + +.PHONY: all repl min test test_min + +all: $(BUILD)/micropython.mjs + +$(BUILD)/micropython.mjs: $(OBJ) library.js $(SRC_JS) + $(ECHO) "LINK $@" + $(Q)emcc $(LDFLAGS) -o $@ $(OBJ) $(JSFLAGS) + $(Q)cat $(SRC_JS) >> $@ + +$(BUILD)/micropython.min.mjs: $(BUILD)/micropython.mjs + $(TERSER) $< --compress --module -o $@ + +repl: $(BUILD)/micropython.mjs + $(NODE) $< + +min: $(BUILD)/micropython.min.mjs + +test: $(BUILD)/micropython.mjs $(TOP)/tests/run-tests.py + cd $(TOP)/tests && MICROPY_MICROPYTHON_MJS=../ports/webassembly/$< ./run-tests.py -t webassembly + +test_min: $(BUILD)/micropython.min.mjs $(TOP)/tests/run-tests.py + cd $(TOP)/tests && MICROPY_MICROPYTHON_MJS=../ports/webassembly/$< ./run-tests.py -t webassembly + +################################################################################ +# Remaining make rules. + +include $(TOP)/py/mkrules.mk diff --git a/tulip/web/README.md b/tulip/web/README.md new file mode 100644 index 00000000..fa6694dd --- /dev/null +++ b/tulip/web/README.md @@ -0,0 +1,59 @@ +# Tulip web port + +this is a very work in progress port of Tulip Desktop to the web. + +Our _goal_ is to have this be the official tulip desktop experience, if we can get it there. you can still run "native" tulip desktop on linux/mac by compiling it if you'd rather. + +This will help us lessen our support load and also expose Tulip to people on other platforms (windows!) without having to download anything. + +## Build + +``` +./build.sh +python3 server.py +# go to localhost:8000 +``` + +## Use + +I test on Chrome right now. I don't think safari supports webmidi. + +The tulip "sys" files will load into `/tulip4/sys`. `/tulip4/user` is there for your files. Unlike other tulip ports, `/tulip4/sys` is "read only" in the sense that it resets back to our shipped FS default every page load. `/tulip4/user` will persist in your browser as an IndexedDB localstorage thing. + + +## what works + - python REPL + - tulip BG functions, graphics layer, TFB, sprites etc + - LVGL + - AMY (loaded as a separate audioworklet), including sequencer + - keyboard & mouse via SDL + - persistent filesystem in localstorage, including `sys` examples folder + - MIDI input & output w/ selectable devices + +## what doesn't (yet) + - tulip world + - urequests + - time.sleep() + +## TODO + - ~~T-sequencer running too slowly to hit every tick #, so % dividers get missed (see LEDs in drums)~~ + - ~~FS needs examples loaded on boot~~ + - ~~FS needs to persist to localstorage~~ + - ~~MIDI output~~ + - ~~MIDI device selector dropdown~~ + - ~~audio device dropdown if possible?~~ - [seems not fully supported yet](https://developer.mozilla.org/en-US/docs/Web/API/Audio_Output_Devices_API#browser_compatibility) + - ~~restart tulip button~~ + - ~~delete storage button~~ + - ~~get working on safari / iOS safari minus webmidi~~ + - ~~start LVGL before onclick for audio so it's not a black screen on launch~~ + - ~~sync my AMY changes to main AMY~~ + - ~~build in release.sh~~ + - ~~speed of LVGL object creation(?) (try `run('drums')`)~~ + - ~~startup bleep (and fix the juno bleep on macos desktop!)~~ + - ~~test changes on tulip desktop mac / linux and tulip cc~~ + - "sockets"/web requests - tulip world etc + - some solution for `time.sleep` / `sleep_ms` -- see `parallax`, `bunny_bounce`, `xanadu` + - test github hosting on tulip.computer/ + - resizeable/responsive SDL canvas + - maybe some simple intro HOWTO on the page + diff --git a/tulip/web/api.js b/tulip/web/api.js new file mode 100644 index 00000000..70fe164f --- /dev/null +++ b/tulip/web/api.js @@ -0,0 +1,328 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Options: +// - pystack: size in words of the MicroPython Python stack. +// - heapsize: size in bytes of the MicroPython GC heap. +// - url: location to load `micropython.mjs`. +// - stdin: function to return input characters. +// - stdout: function that takes one argument, and is passed lines of stdout +// output as they are produced. By default this is handled by Emscripten +// and in a browser goes to console, in node goes to process.stdout.write. +// - stderr: same behaviour as stdout but for error output. +// - linebuffer: whether to buffer line-by-line to stdout/stderr. +export async function loadMicroPython(options) { + const { pystack, heapsize, url, stdin, stdout, stderr, linebuffer } = + Object.assign( + { pystack: 2 * 1024, heapsize: 1024 * 1024, linebuffer: true }, + options, + ); + let Module = {}; + Module.locateFile = (path, scriptDirectory) => + url || scriptDirectory + path; + Module._textDecoder = new TextDecoder(); + if (stdin !== undefined) { + Module.stdin = stdin; + } + if (stdout !== undefined) { + if (linebuffer) { + Module._stdoutBuffer = []; + Module.stdout = (c) => { + if (c === 10) { + stdout( + Module._textDecoder.decode( + new Uint8Array(Module._stdoutBuffer), + ), + ); + Module._stdoutBuffer = []; + } else { + Module._stdoutBuffer.push(c); + } + }; + } else { + Module.stdout = (c) => stdout(new Uint8Array([c])); + } + } + if (stderr !== undefined) { + if (linebuffer) { + Module._stderrBuffer = []; + Module.stderr = (c) => { + if (c === 10) { + stderr( + Module._textDecoder.decode( + new Uint8Array(Module._stderrBuffer), + ), + ); + Module._stderrBuffer = []; + } else { + Module._stderrBuffer.push(c); + } + }; + } else { + Module.stderr = (c) => stderr(new Uint8Array([c])); + } + } + Module = await _createMicroPythonModule(Module); + Module.canvas = (function() { return document.getElementById('canvas'); })(); + + globalThis.Module = Module; + proxy_js_init(); + const pyimport = (name) => { + const value = Module._malloc(3 * 4); + Module.ccall( + "mp_js_do_import", + "null", + ["string", "pointer"], + [name, value], + ); + return proxy_convert_mp_to_js_obj_jsside_with_free(value); + }; + Module.ccall( + "mp_js_init", + "null", + ["number", "number"], + [pystack, heapsize], + ); + Module.ccall("proxy_c_init", "null", [], []); + return { + _module: Module, + PyProxy: PyProxy, + FS: Module.FS, + globals: { + __dict__: pyimport("__main__").__dict__, + get(key) { + return this.__dict__[key]; + }, + set(key, value) { + this.__dict__[key] = value; + }, + delete(key) { + delete this.__dict__[key]; + }, + }, + registerJsModule(name, module) { + const value = Module._malloc(3 * 4); + proxy_convert_js_to_mp_obj_jsside(module, value); + Module.ccall( + "mp_js_register_js_module", + "null", + ["string", "pointer"], + [name, value], + ); + Module._free(value); + }, + pyimport: pyimport, + runPython(code) { + const len = Module.lengthBytesUTF8(code); + const buf = Module._malloc(len + 1); + Module.stringToUTF8(code, buf, len + 1); + const value = Module._malloc(3 * 4); + Module.ccall( + "mp_js_do_exec", + "number", + ["pointer", "number", "pointer"], + [buf, len, value], + ); + Module._free(buf); + return proxy_convert_mp_to_js_obj_jsside_with_free(value); + }, + runPythonAsync(code) { + const len = Module.lengthBytesUTF8(code); + const buf = Module._malloc(len + 1); + Module.stringToUTF8(code, buf, len + 1); + const value = Module._malloc(3 * 4); + Module.ccall( + "mp_js_do_exec_async", + "number", + ["pointer", "number", "pointer"], + [buf, len, value], + { async: true }, + ); + Module._free(buf); + const ret = proxy_convert_mp_to_js_obj_jsside_with_free(value); + if (ret instanceof PyProxyThenable) { + return Promise.resolve(ret); + } + return ret; + }, + handlePending() { + return Module.ccall( + "mp_handle_pending", "null", ["boolean"], [true] + ); + }, + runFrozenAsync(module) { + const len = Module.lengthBytesUTF8(module); + const buf = Module._malloc(len + 1); + Module.stringToUTF8(module, buf, len + 1); + Module.ccall( + "mp_js_frozen_exec", + "number", + ["pointer"], + [buf], + { async: true }, + ); + Module._free(buf); + }, + replInit() { + Module.ccall("mp_js_repl_init", "null", ["null"], {async: true}); + }, + replProcessChar(chr) { + return Module.ccall( + "mp_js_repl_process_char", + "number", + ["number"], + [chr], + ); + }, + tulipTick(tick) { + return Module.ccall( + "tulip_tick", "null", ["number"], [tick], {async:true} + ); + }, + midiByte(byte) { + return Module.ccall( + "process_single_midi_byte", "null", ["number"], [byte], {async:true} + ); + }, + // Needed if the GC/asyncify is enabled. + async replProcessCharWithAsyncify(chr) { + return Module.ccall( + "mp_js_repl_process_char", + "number", + ["number"], + [chr], + { async: true }, + ); + }, + }; +} + +globalThis.loadMicroPython = loadMicroPython; + +async function runCLI() { + const fs = await import("fs"); + let heap_size = 128 * 1024; + let contents = ""; + let repl = true; + + for (let i = 2; i < process.argv.length; i++) { + if (process.argv[i] === "-X" && i < process.argv.length - 1) { + if (process.argv[i + 1].includes("heapsize=")) { + heap_size = parseInt(process.argv[i + 1].split("heapsize=")[1]); + const suffix = process.argv[i + 1].substr(-1).toLowerCase(); + if (suffix === "k") { + heap_size *= 1024; + } else if (suffix === "m") { + heap_size *= 1024 * 1024; + } + ++i; + } + } else { + contents += fs.readFileSync(process.argv[i], "utf8"); + repl = false; + } + } + + if (process.stdin.isTTY === false) { + contents = fs.readFileSync(0, "utf8"); + repl = false; + } + + const mp = await loadMicroPython({ + heapsize: heap_size, + stdout: (data) => process.stdout.write(data), + linebuffer: false, + }); + + if (repl) { + mp.replInit(); + process.stdin.setRawMode(true); + process.stdin.on("data", (data) => { + for (let i = 0; i < data.length; i++) { + mp.replProcessCharWithAsyncify(data[i]).then((result) => { + if (result) { + process.exit(); + } + }); + } + }); + } else { + // If the script to run ends with a running of the asyncio main loop, then inject + // a simple `asyncio.run` hook that starts the main task. This is primarily to + // support running the standard asyncio tests. + if (contents.endsWith("asyncio.run(main())\n")) { + const asyncio = mp.pyimport("asyncio"); + asyncio.run = async (task) => { + await asyncio.create_task(task); + }; + } + + try { + mp.runPython(contents); + } catch (error) { + if (error.name === "PythonError") { + if (error.type === "SystemExit") { + // SystemExit, this is a valid exception to successfully end a script. + } else { + // An unhandled Python exception, print in out. + console.error(error.message); + } + } else { + // A non-Python exception. Re-raise it. + throw error; + } + } + } +} + +// Check if Node is running (equivalent to ENVIRONMENT_IS_NODE). +if ( + typeof process === "object" && + typeof process.versions === "object" && + typeof process.versions.node === "string" +) { + // Check if this module is run from the command line via `node micropython.mjs`. + // + // See https://stackoverflow.com/questions/6398196/detect-if-called-through-require-or-directly-by-command-line/66309132#66309132 + // + // Note: + // - `resolve()` is used to handle symlinks + // - `includes()` is used to handle cases where the file extension was omitted when passed to node + + if (process.argv.length > 1) { + const path = await import("path"); + const url = await import("url"); + + const pathToThisFile = path.resolve(url.fileURLToPath(import.meta.url)); + const pathPassedToNode = path.resolve(process.argv[1]); + const isThisFileBeingRunViaCLI = + pathToThisFile.includes(pathPassedToNode); + + if (isThisFileBeingRunViaCLI) { + runCLI(); + } + } +} diff --git a/tulip/web/asyncio/__init__.py b/tulip/web/asyncio/__init__.py new file mode 100644 index 00000000..ba1ca635 --- /dev/null +++ b/tulip/web/asyncio/__init__.py @@ -0,0 +1,9 @@ +# MicroPython asyncio module, for use with webassembly port +# MIT license; Copyright (c) 2024 Damien P. George + +from .core import * +from .funcs import wait_for, wait_for_ms, gather +from .event import Event +from .lock import Lock + +__version__ = (3, 0, 0) diff --git a/tulip/web/asyncio/core.py b/tulip/web/asyncio/core.py new file mode 100644 index 00000000..47846fc2 --- /dev/null +++ b/tulip/web/asyncio/core.py @@ -0,0 +1,258 @@ +# MicroPython asyncio module, for use with webassembly port +# MIT license; Copyright (c) 2019-2024 Damien P. George + +from time import ticks_ms as ticks, ticks_diff, ticks_add +import sys, js, jsffi + +# Import TaskQueue and Task from built-in C code. +from _asyncio import TaskQueue, Task + + +################################################################################ +# Exceptions + + +class CancelledError(BaseException): + pass + + +class TimeoutError(Exception): + pass + + +# Used when calling Loop.call_exception_handler. +_exc_context = {"message": "Task exception wasn't retrieved", "exception": None, "future": None} + + +################################################################################ +# Sleep functions + + +# "Yield" once, then raise StopIteration +class SingletonGenerator: + def __init__(self): + self.state = None + self.exc = StopIteration() + + def __iter__(self): + return self + + def __next__(self): + if self.state is not None: + _task_queue.push(cur_task, self.state) + self.state = None + return None + else: + self.exc.__traceback__ = None + raise self.exc + + +# Pause task execution for the given time (integer in milliseconds, uPy extension) +# Use a SingletonGenerator to do it without allocating on the heap +def sleep_ms(t, sgen=SingletonGenerator()): + assert sgen.state is None + sgen.state = ticks_add(ticks(), max(0, t)) + return sgen + + +# Pause task execution for the given time (in seconds) +def sleep(t): + return sleep_ms(int(t * 1000)) + + +################################################################################ +# Main run loop + +asyncio_timer = None + + +class TopLevelCoro: + @staticmethod + def set(resolve, reject): + TopLevelCoro.resolve = resolve + TopLevelCoro.reject = reject + + @staticmethod + def send(value): + TopLevelCoro.resolve() + + +class ThenableEvent: + def __init__(self, thenable): + self.result = None # Result of the thenable + self.waiting = None # Task waiting on completion of this thenable + thenable.then(self.set) + + def set(self, value=None): + # Thenable/Promise is fulfilled, set result and schedule any waiting task. + self.result = value + if self.waiting: + _task_queue.push(self.waiting) + self.waiting = None + + def remove(self, task): + self.waiting = None + + # async + def wait(self): + # Set the calling task as the task waiting on this thenable. + self.waiting = cur_task + # Set calling task's data to this object so it can be removed if needed. + cur_task.data = self + # Wait for the thenable to fulfill. + yield + # Return the result of the thenable. + return self.result + + +# Ensure the awaitable is a task +def _promote_to_task(aw): + return aw if isinstance(aw, Task) else create_task(aw) + + +def _schedule_run_iter(dt): + global asyncio_timer + if asyncio_timer is not None: + js.clearTimeout(asyncio_timer) + asyncio_timer = js.setTimeout(_run_iter, dt) + + +def _run_iter(): + global cur_task + excs_all = (CancelledError, Exception) # To prevent heap allocation in loop + excs_stop = (CancelledError, StopIteration) # To prevent heap allocation in loop + while True: + # Wait until the head of _task_queue is ready to run + t = _task_queue.peek() + if t: + # A task waiting on _task_queue; "ph_key" is time to schedule task at + dt = max(0, ticks_diff(t.ph_key, ticks())) + else: + # No tasks can be woken so finished running + cur_task = _top_level_task + return + + if dt > 0: + # schedule to call again later + cur_task = _top_level_task + _schedule_run_iter(dt) + return + + # Get next task to run and continue it + t = _task_queue.pop() + cur_task = t + try: + # Continue running the coroutine, it's responsible for rescheduling itself + exc = t.data + if not exc: + t.coro.send(None) + else: + # If the task is finished and on the run queue and gets here, then it + # had an exception and was not await'ed on. Throwing into it now will + # raise StopIteration and the code below will catch this and run the + # call_exception_handler function. + t.data = None + t.coro.throw(exc) + except excs_all as er: + # Check the task is not on any event queue + assert t.data is None + # This task is done. + if t.state: + # Task was running but is now finished. + waiting = False + if t.state is True: + # "None" indicates that the task is complete and not await'ed on (yet). + t.state = None + elif callable(t.state): + # The task has a callback registered to be called on completion. + t.state(t, er) + t.state = False + waiting = True + else: + # Schedule any other tasks waiting on the completion of this task. + while t.state.peek(): + _task_queue.push(t.state.pop()) + waiting = True + # "False" indicates that the task is complete and has been await'ed on. + t.state = False + if not waiting and not isinstance(er, excs_stop): + # An exception ended this detached task, so queue it for later + # execution to handle the uncaught exception if no other task retrieves + # the exception in the meantime (this is handled by Task.throw). + _task_queue.push(t) + # Save return value of coro to pass up to caller. + t.data = er + elif t.state is None: + # Task is already finished and nothing await'ed on the task, + # so call the exception handler. + + # Save exception raised by the coro for later use. + t.data = exc + + # Create exception context and call the exception handler. + _exc_context["exception"] = exc + _exc_context["future"] = t + Loop.call_exception_handler(_exc_context) + + +# Create and schedule a new task from a coroutine. +def create_task(coro): + if not hasattr(coro, "send"): + raise TypeError("coroutine expected") + t = Task(coro, globals()) + _task_queue.push(t) + return t + + +# Task used to suspend and resume top-level await. +_top_level_task = Task(TopLevelCoro, globals()) + +################################################################################ +# Event loop wrapper + + +cur_task = _top_level_task + + +class Loop: + _exc_handler = None + + def create_task(coro): + return create_task(coro) + + def close(): + pass + + def set_exception_handler(handler): + Loop._exc_handler = handler + + def get_exception_handler(): + return Loop._exc_handler + + def default_exception_handler(loop, context): + print(context["message"], file=sys.stderr) + print("future:", context["future"], "coro=", context["future"].coro, file=sys.stderr) + sys.print_exception(context["exception"], sys.stderr) + + def call_exception_handler(context): + (Loop._exc_handler or Loop.default_exception_handler)(Loop, context) + + +def get_event_loop(): + return Loop + + +def current_task(): + if cur_task is None: + raise RuntimeError("no running event loop") + return cur_task + + +def new_event_loop(): + global _task_queue + _task_queue = TaskQueue(_schedule_run_iter) # TaskQueue of Task instances. + return Loop + + +# Initialise default event loop. +new_event_loop() diff --git a/tulip/web/build.sh b/tulip/web/build.sh new file mode 100755 index 00000000..7dcc7654 --- /dev/null +++ b/tulip/web/build.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# build.sh +# Just builds web version locally +set -e + +source ../shared/grab_submodules.sh + +cd ../../amy +make docs/amy.js +cd ../tulip/web +cp ../../amy/docs/amy.js ../../www/run/ +cp ../../amy/docs/amy.wasm ../../www/run/ +cp ../../amy/docs/amy.aw.js ../../www/run/ + +make +cp build-standard/tulip/obj/micropython.wasm ../../www/run/ +cp build-standard/tulip/obj/micropython.mjs ../../www/run/ +cp build-standard/tulip/obj/micropython.data ../../www/run/ + diff --git a/tulip/web/lexer_dedent.c b/tulip/web/lexer_dedent.c new file mode 100644 index 00000000..555caea8 --- /dev/null +++ b/tulip/web/lexer_dedent.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "lexer_dedent.h" + +typedef struct _mp_reader_mem_dedent_t { + size_t free_len; // if >0 mem is freed on close by: m_free(beg, free_len) + const byte *beg; + const byte *cur; + const byte *end; + size_t dedent_prefix; +} mp_reader_mem_dedent_t; + +// Work out the amount of common whitespace among all non-empty lines. +static size_t dedent(const byte *text, size_t len) { + size_t min_prefix = -1; + size_t cur_prefix = 0; + bool start_of_line = true; + for (const byte *t = text; t < text + len; ++t) { + if (*t == '\n') { + start_of_line = true; + cur_prefix = 0; + } else if (start_of_line) { + if (unichar_isspace(*t)) { + ++cur_prefix; + } else { + if (cur_prefix < min_prefix) { + min_prefix = cur_prefix; + if (min_prefix == 0) { + return min_prefix; + } + } + start_of_line = false; + } + } + } + return min_prefix; +} + +static mp_uint_t mp_reader_mem_dedent_readbyte(void *data) { + mp_reader_mem_dedent_t *reader = (mp_reader_mem_dedent_t *)data; + if (reader->cur < reader->end) { + byte c = *reader->cur++; + if (c == '\n') { + for (size_t i = 0; i < reader->dedent_prefix; ++i) { + if (*reader->cur == '\n') { + break; + } + ++reader->cur; + } + } + return c; + } else { + return MP_READER_EOF; + } +} + +static void mp_reader_mem_dedent_close(void *data) { + mp_reader_mem_dedent_t *reader = (mp_reader_mem_dedent_t *)data; + if (reader->free_len > 0) { + m_del(char, (char *)reader->beg, reader->free_len); + } + m_del_obj(mp_reader_mem_dedent_t, reader); +} + +static void mp_reader_new_mem_dedent(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len) { + mp_reader_mem_dedent_t *rm = m_new_obj(mp_reader_mem_dedent_t); + rm->free_len = free_len; + rm->beg = buf; + rm->cur = buf; + rm->end = buf + len; + rm->dedent_prefix = dedent(buf, len); + reader->data = rm; + reader->readbyte = mp_reader_mem_dedent_readbyte; + reader->close = mp_reader_mem_dedent_close; +} + +mp_lexer_t *mp_lexer_new_from_str_len_dedent(qstr src_name, const char *str, size_t len, size_t free_len) { + mp_reader_t reader; + mp_reader_new_mem_dedent(&reader, (const byte *)str, len, free_len); + return mp_lexer_new(src_name, reader); +} diff --git a/tulip/web/lexer_dedent.h b/tulip/web/lexer_dedent.h new file mode 100644 index 00000000..a8cc2526 --- /dev/null +++ b/tulip/web/lexer_dedent.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_WEBASSEMBLY_LEXER_DEDENT_H +#define MICROPY_INCLUDED_WEBASSEMBLY_LEXER_DEDENT_H + +#include "py/lexer.h" + +// This function creates a new "dedenting lexer" which automatically dedents the input +// source code if every non-empty line in that source starts with a common whitespace +// prefix. It does this dedenting inplace as the memory is read. +mp_lexer_t *mp_lexer_new_from_str_len_dedent(qstr src_name, const char *str, size_t len, size_t free_len); + +#endif // MICROPY_INCLUDED_WEBASSEMBLY_LEXER_DEDENT_H diff --git a/tulip/web/lextab.py b/tulip/web/lextab.py new file mode 100644 index 00000000..aeb5c152 --- /dev/null +++ b/tulip/web/lextab.py @@ -0,0 +1,10 @@ +# lextab.py. This file automatically created by PLY (version 3.10). Don't edit! +_tabversion = '3.10' +_lextokens = set(('AND', 'ANDEQUAL', 'ARROW', 'AUTO', 'BREAK', 'CASE', 'CHAR', 'CHAR_CONST', 'COLON', 'COMMA', 'CONDOP', 'CONST', 'CONTINUE', 'DEFAULT', 'DIVEQUAL', 'DIVIDE', 'DO', 'DOUBLE', 'ELLIPSIS', 'ELSE', 'ENUM', 'EQ', 'EQUALS', 'EXTERN', 'FLOAT', 'FLOAT_CONST', 'FOR', 'GE', 'GOTO', 'GT', 'HEX_FLOAT_CONST', 'ID', 'IF', 'INLINE', 'INT', 'INT_CONST_BIN', 'INT_CONST_CHAR', 'INT_CONST_DEC', 'INT_CONST_HEX', 'INT_CONST_OCT', 'LAND', 'LBRACE', 'LBRACKET', 'LE', 'LNOT', 'LONG', 'LOR', 'LPAREN', 'LSHIFT', 'LSHIFTEQUAL', 'LT', 'MINUS', 'MINUSEQUAL', 'MINUSMINUS', 'MOD', 'MODEQUAL', 'NE', 'NOT', 'OFFSETOF', 'OR', 'OREQUAL', 'PERIOD', 'PLUS', 'PLUSEQUAL', 'PLUSPLUS', 'PPHASH', 'PPPRAGMA', 'PPPRAGMASTR', 'RBRACE', 'RBRACKET', 'REGISTER', 'RESTRICT', 'RETURN', 'RPAREN', 'RSHIFT', 'RSHIFTEQUAL', 'SEMI', 'SHORT', 'SIGNED', 'SIZEOF', 'STATIC', 'STRING_LITERAL', 'STRUCT', 'SWITCH', 'TIMES', 'TIMESEQUAL', 'TYPEDEF', 'TYPEID', 'U16CHAR_CONST', 'U16STRING_LITERAL', 'U32CHAR_CONST', 'U32STRING_LITERAL', 'U8CHAR_CONST', 'U8STRING_LITERAL', 'UNION', 'UNSIGNED', 'VOID', 'VOLATILE', 'WCHAR_CONST', 'WHILE', 'WSTRING_LITERAL', 'XOR', 'XOREQUAL', '_ALIGNAS', '_ALIGNOF', '_ATOMIC', '_BOOL', '_COMPLEX', '_NORETURN', '_PRAGMA', '_STATIC_ASSERT', '_THREAD_LOCAL', '__INT128')) +_lexreflags = 64 +_lexliterals = '' +_lexstateinfo = {'INITIAL': 'inclusive', 'ppline': 'exclusive', 'pppragma': 'exclusive'} +_lexstatere = {'INITIAL': [('(?P[ \\t]*\\#)|(?P\\n+)|(?P\\{)|(?P\\})|(?P((((([0-9]*\\.[0-9]+)|([0-9]+\\.))([eE][-+]?[0-9]+)?)|([0-9]+([eE][-+]?[0-9]+)))[FfLl]?))|(?P(0[xX]([0-9a-fA-F]+|((([0-9a-fA-F]+)?\\.[0-9a-fA-F]+)|([0-9a-fA-F]+\\.)))([pP][+-]?[0-9]+)[FfLl]?))|(?P0[xX][0-9a-fA-F]+(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|(?P0[bB][01]+(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|(?P0[0-7]*[89])|(?P0[0-7]*(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|(?P(0(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|([1-9][0-9]*(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?))|(?P\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F])))){2,4}\')|(?P\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?PL\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?Pu8\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?Pu\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?PU\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))\')|(?P(\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))*\\n)|(\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))*$))|(?P(\'([^\'\\\\\\n]|(\\\\(([a-wyzA-Z._~!=&\\^\\-\\\\?\'"]|x(?![0-9a-fA-F]))|(\\d+)(?!\\d)|(x[0-9a-fA-F]+)(?![0-9a-fA-F]))))[^\'\n]+\')|(\'\')|(\'([\\\\][^a-zA-Z._~^!=&\\^\\-\\\\?\'"x0-9])[^\'\\n]*\'))|(?PL"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?Pu8"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?Pu"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?PU"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*([\\\\][^a-zA-Z._~^!=&\\^\\-\\\\?\'"x0-9])([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P[a-zA-Z_$][0-9a-zA-Z_$]*)|(?P"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P\\.\\.\\.)|(?P\\|\\|)|(?P\\+\\+)|(?P<<=)|(?P\\|=)|(?P\\+=)|(?P>>=)|(?P\\*=)|(?P\\^=)|(?P&=)|(?P->)|(?P\\?)|(?P/=)|(?P==)|(?P>=)|(?P&&)|(?P\\[)|(?P<=)|(?P\\()|(?P<<)|(?P-=)|(?P--)|(?P%=)|(?P!=)|(?P\\|)|(?P\\.)|(?P\\+)|(?P\\])|(?P\\))|(?P>>)|(?P\\*)|(?P\\^)|(?P&)|(?P:)|(?P,)|(?P/)|(?P=)|(?P>)|(?P!)|(?P<)|(?P-)|(?P%)|(?P~)|(?P;)', [None, ('t_PPHASH', 'PPHASH'), ('t_NEWLINE', 'NEWLINE'), ('t_LBRACE', 'LBRACE'), ('t_RBRACE', 'RBRACE'), ('t_FLOAT_CONST', 'FLOAT_CONST'), None, None, None, None, None, None, None, None, None, ('t_HEX_FLOAT_CONST', 'HEX_FLOAT_CONST'), None, None, None, None, None, None, None, ('t_INT_CONST_HEX', 'INT_CONST_HEX'), None, None, None, None, None, None, None, ('t_INT_CONST_BIN', 'INT_CONST_BIN'), None, None, None, None, None, None, None, ('t_BAD_CONST_OCT', 'BAD_CONST_OCT'), ('t_INT_CONST_OCT', 'INT_CONST_OCT'), None, None, None, None, None, None, None, ('t_INT_CONST_DEC', 'INT_CONST_DEC'), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_INT_CONST_CHAR', 'INT_CONST_CHAR'), None, None, None, None, None, None, ('t_CHAR_CONST', 'CHAR_CONST'), None, None, None, None, None, None, ('t_WCHAR_CONST', 'WCHAR_CONST'), None, None, None, None, None, None, ('t_U8CHAR_CONST', 'U8CHAR_CONST'), None, None, None, None, None, None, ('t_U16CHAR_CONST', 'U16CHAR_CONST'), None, None, None, None, None, None, ('t_U32CHAR_CONST', 'U32CHAR_CONST'), None, None, None, None, None, None, ('t_UNMATCHED_QUOTE', 'UNMATCHED_QUOTE'), None, None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_BAD_CHAR_CONST', 'BAD_CHAR_CONST'), None, None, None, None, None, None, None, None, None, None, ('t_WSTRING_LITERAL', 'WSTRING_LITERAL'), None, None, ('t_U8STRING_LITERAL', 'U8STRING_LITERAL'), None, None, ('t_U16STRING_LITERAL', 'U16STRING_LITERAL'), None, None, ('t_U32STRING_LITERAL', 'U32STRING_LITERAL'), None, None, ('t_BAD_STRING_LITERAL', 'BAD_STRING_LITERAL'), None, None, None, None, None, ('t_ID', 'ID'), (None, 'STRING_LITERAL'), None, None, (None, 'ELLIPSIS'), (None, 'LOR'), (None, 'PLUSPLUS'), (None, 'LSHIFTEQUAL'), (None, 'OREQUAL'), (None, 'PLUSEQUAL'), (None, 'RSHIFTEQUAL'), (None, 'TIMESEQUAL'), (None, 'XOREQUAL'), (None, 'ANDEQUAL'), (None, 'ARROW'), (None, 'CONDOP'), (None, 'DIVEQUAL'), (None, 'EQ'), (None, 'GE'), (None, 'LAND'), (None, 'LBRACKET'), (None, 'LE'), (None, 'LPAREN'), (None, 'LSHIFT'), (None, 'MINUSEQUAL'), (None, 'MINUSMINUS'), (None, 'MODEQUAL'), (None, 'NE'), (None, 'OR'), (None, 'PERIOD'), (None, 'PLUS'), (None, 'RBRACKET'), (None, 'RPAREN'), (None, 'RSHIFT'), (None, 'TIMES'), (None, 'XOR'), (None, 'AND'), (None, 'COLON'), (None, 'COMMA'), (None, 'DIVIDE'), (None, 'EQUALS'), (None, 'GT'), (None, 'LNOT'), (None, 'LT'), (None, 'MINUS'), (None, 'MOD'), (None, 'NOT'), (None, 'SEMI')])], 'ppline': [('(?P"([^"\\\\\\n]|(\\\\[0-9a-zA-Z._~!=&\\^\\-\\\\?\'"]))*")|(?P(0(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?)|([1-9][0-9]*(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?))|(?P\\n)|(?Pline)', [None, ('t_ppline_FILENAME', 'FILENAME'), None, None, ('t_ppline_LINE_NUMBER', 'LINE_NUMBER'), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_ppline_NEWLINE', 'NEWLINE'), ('t_ppline_PPLINE', 'PPLINE')])], 'pppragma': [('(?P\\n)|(?Ppragma)|(?P.+)', [None, ('t_pppragma_NEWLINE', 'NEWLINE'), ('t_pppragma_PPPRAGMA', 'PPPRAGMA'), ('t_pppragma_STR', 'STR')])]} +_lexstateignore = {'INITIAL': ' \t', 'ppline': ' \t', 'pppragma': ' \t'} +_lexstateerrorf = {'INITIAL': 't_error', 'ppline': 't_ppline_error', 'pppragma': 't_pppragma_error'} +_lexstateeoff = {} diff --git a/tulip/web/library.h b/tulip/web/library.h new file mode 100644 index 00000000..04b408d7 --- /dev/null +++ b/tulip/web/library.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Rami Ali + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +extern void mp_js_write(const char *str, mp_uint_t len); +extern int mp_js_ticks_ms(void); +extern void mp_js_hook(void); +extern double mp_js_time_ms(void); +extern uint32_t mp_js_random_u32(void); diff --git a/tulip/web/library.js b/tulip/web/library.js new file mode 100644 index 00000000..3f6c9cb6 --- /dev/null +++ b/tulip/web/library.js @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Rami Ali + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +mergeInto(LibraryManager.library, { + // This string will be emitted directly into the output file by Emscripten. + mp_js_ticks_ms__postset: "var MP_JS_EPOCH = Date.now()", + + mp_js_ticks_ms: () => Date.now() - MP_JS_EPOCH, + + mp_js_hook: () => { + if (ENVIRONMENT_IS_NODE) { + const mp_interrupt_char = Module.ccall( + "mp_hal_get_interrupt_char", + "number", + ["number"], + ["null"], + ); + const fs = require("fs"); + + const buf = Buffer.alloc(1); + try { + const n = fs.readSync(process.stdin.fd, buf, 0, 1); + if (n > 0) { + if (buf[0] === mp_interrupt_char) { + Module.ccall( + "mp_sched_keyboard_interrupt", + "null", + ["null"], + ["null"], + ); + } else { + process.stdout.write(String.fromCharCode(buf[0])); + } + } + } catch (e) { + if (e.code === "EAGAIN") { + } else { + throw e; + } + } + } + }, + + mp_js_time_ms: () => Date.now(), + + // Node prior to v19 did not expose "crypto" as a global, so make sure it exists. + mp_js_random_u32__postset: + "if (globalThis.crypto === undefined) { globalThis.crypto = require('crypto'); }", + + mp_js_random_u32: () => + globalThis.crypto.getRandomValues(new Uint32Array(1))[0], +}); diff --git a/tulip/web/main.c b/tulip/web/main.c new file mode 100644 index 00000000..f32fd4f1 --- /dev/null +++ b/tulip/web/main.c @@ -0,0 +1,305 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Damien P. George and 2017, 2018 Rami Ali + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/builtin.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" +#include "extmod/vfs_posix.h" +#include "shared/runtime/pyexec.h" + +#include "emscripten.h" +#include "lexer_dedent.h" +#include "library.h" +#include "proxy_c.h" +#include "py/ringbuf.h" + +#include "tsequencer.h" + +extern void setup_lvgl(); +void tulip_start(); + + +STATIC uint8_t stdin_ringbuf_array[260]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; + + +// This counter tracks the current depth of calls into C code that originated +// externally, ie from JavaScript. When the counter is 0 that corresponds to +// the top-level call into C. +static size_t external_call_depth = 0; + +#if MICROPY_GC_SPLIT_HEAP_AUTO +static void gc_collect_top_level(void); +#endif + +void external_call_depth_inc(void) { + ++external_call_depth; + #if MICROPY_GC_SPLIT_HEAP_AUTO + if (external_call_depth == 1) { + gc_collect_top_level(); + } + #endif +} + +void external_call_depth_dec(void) { + --external_call_depth; +} + +extern void unix_display_init(); +extern int unix_display_draw(); +uint8_t tulip_ready = 0; + +void main_loop__tulip() { + if(tulip_ready) { + unix_display_draw(); + mp_handle_pending(true); + } +} + +void tulip_tick(uint32_t tick) { + if(tulip_ready) tulip_amy_sequencer_hook(tick); +} + +void setup_fs() { + EM_ASM( + try { + FS.mkdir('/tulip4/user'); + } catch (err) { + console.log('tulip4/user already exist'); + } + // Then mount with IDBFS type + FS.mount(IDBFS, {autoPersist:true}, '/tulip4/user'); + // Then sync + FS.syncfs(true, function (err) { + // Error + }); + ); +} +extern void unix_display_init(); + +void mp_js_init(int pystack_size, int heap_size) { + + setup_fs(); + emscripten_set_main_loop(main_loop__tulip, 0, 0); + + #if MICROPY_ENABLE_PYSTACK + mp_obj_t *pystack = (mp_obj_t *)malloc(pystack_size * sizeof(mp_obj_t)); + mp_pystack_init(pystack, pystack + pystack_size); + #endif + + #if MICROPY_ENABLE_GC + char *heap = (char *)malloc(heap_size * sizeof(char)); + gc_init(heap, heap + heap_size); + #endif + + #if MICROPY_GC_SPLIT_HEAP_AUTO + // When MICROPY_GC_SPLIT_HEAP_AUTO is enabled, set the GC threshold to a low + // value so that a collection is triggered before the heap fills up. The actual + // garbage collection will happen later when control returns to the top-level, + // via the `gc_collect_pending` flag and `gc_collect_top_level()`. + MP_STATE_MEM(gc_alloc_threshold) = 16 * 1024 / MICROPY_BYTES_PER_GC_BLOCK; + #endif + + mp_init(); + + #if MICROPY_VFS_POSIX + { + // Mount the host FS at the root of our internal VFS + mp_obj_t args[2] = { + MP_OBJ_TYPE_GET_SLOT(&mp_type_vfs_posix, make_new)(&mp_type_vfs_posix, 0, 0, NULL), + MP_OBJ_NEW_QSTR(qstr_from_str("/")), + }; + mp_vfs_mount(2, args, (mp_map_t *)&mp_const_empty_map); + MP_STATE_VM(vfs_cur) = MP_STATE_VM(vfs_mount_table); + } + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); + #endif + tsequencer_init(); + unix_display_init(); + setup_lvgl(); + tulip_ready = 1; +} + +void mp_js_register_js_module(const char *name, uint32_t *value) { + mp_obj_t module_name = MP_OBJ_NEW_QSTR(qstr_from_str(name)); + mp_obj_t module = proxy_convert_js_to_mp_obj_cside(value); + mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; + mp_map_lookup(mp_loaded_modules_map, module_name, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; +} + +void mp_js_do_import(const char *name, uint32_t *out) { + external_call_depth_inc(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t ret = mp_import_name(qstr_from_str(name), mp_const_none, MP_OBJ_NEW_SMALL_INT(0)); + // Return the leaf of the import, eg for "a.b.c" return "c". + const char *m = name; + const char *n = name; + for (;; ++n) { + if (*n == '\0' || *n == '.') { + if (m != name) { + ret = mp_load_attr(ret, qstr_from_strn(m, n - m)); + } + m = n + 1; + if (*n == '\0') { + break; + } + } + } + nlr_pop(); + external_call_depth_dec(); + proxy_convert_mp_to_js_obj_cside(ret, out); + } else { + // uncaught exception + external_call_depth_dec(); + proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); + } +} + +void mp_js_do_exec(const char *src, size_t len, uint32_t *out) { + external_call_depth_inc(); + mp_parse_input_kind_t input_kind = MP_PARSE_FILE_INPUT; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len_dedent(MP_QSTR__lt_stdin_gt_, src, len, 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); + mp_obj_t ret = mp_call_function_0(module_fun); + nlr_pop(); + external_call_depth_dec(); + proxy_convert_mp_to_js_obj_cside(ret, out); + } else { + // uncaught exception + external_call_depth_dec(); + proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); + } +} +#include "py/frozenmod.h" + +void mp_js_frozen_exec(const char *name) { + pyexec_file_if_exists(name); +} + +void mp_js_do_exec_async(const char *src, size_t len, uint32_t *out) { + mp_compile_allow_top_level_await = true; + mp_js_do_exec(src, len, out); + mp_compile_allow_top_level_await = false; +} + +void mp_js_repl_init(void) { + pyexec_event_repl_init(); +} + +int mp_js_repl_process_char(int c) { + mp_compile_allow_top_level_await = true; + external_call_depth_inc(); + int ret = pyexec_event_repl_process_char(c); + external_call_depth_dec(); + mp_compile_allow_top_level_await = false; + return ret; +} + +#if MICROPY_GC_SPLIT_HEAP_AUTO + +static bool gc_collect_pending = false; + +// The largest new region that is available to become Python heap. +size_t gc_get_max_new_split(void) { + return 128 * 1024 * 1024; +} + +// Don't collect anything. Instead require the heap to grow. +void gc_collect(void) { + gc_collect_pending = true; +} + +// Collect at the top-level, where there are no root pointers from stack/registers. +static void gc_collect_top_level(void) { + if (gc_collect_pending) { + gc_collect_pending = false; + gc_collect_start(); + gc_collect_end(); + } +} + +#else + +static void gc_scan_func(void *begin, void *end) { + gc_collect_root((void **)begin, (void **)end - (void **)begin + 1); +} + +void gc_collect(void) { + gc_collect_start(); + emscripten_scan_stack(gc_scan_func); + emscripten_scan_registers(gc_scan_func); + gc_collect_end(); +} + +#endif + +#if !MICROPY_VFS +mp_lexer_t *mp_lexer_new_from_file(qstr filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); +#endif + +void nlr_jump_fail(void *val) { + while (1) { + ; + } +} + +void NORETURN __fatal_error(const char *msg) { + while (1) { + ; + } +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif diff --git a/tulip/web/modjs.c b/tulip/web/modjs.c new file mode 100644 index 00000000..bed09086 --- /dev/null +++ b/tulip/web/modjs.c @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objmodule.h" +#include "py/runtime.h" +#include "proxy_c.h" + +#if MICROPY_PY_JS + +/******************************************************************************/ +// js module + +void mp_module_js_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_jsproxy_t global_this; + global_this.ref = 0; + mp_obj_jsproxy_attr(MP_OBJ_FROM_PTR(&global_this), attr, dest); +} + +static const mp_rom_map_elem_t mp_module_js_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_js) }, +}; +static MP_DEFINE_CONST_DICT(mp_module_js_globals, mp_module_js_globals_table); + +const mp_obj_module_t mp_module_js = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mp_module_js_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_js, mp_module_js); +MP_REGISTER_MODULE_DELEGATION(mp_module_js, mp_module_js_attr); + +#endif // MICROPY_PY_JS diff --git a/tulip/web/modjsffi.c b/tulip/web/modjsffi.c new file mode 100644 index 00000000..ac3d8602 --- /dev/null +++ b/tulip/web/modjsffi.c @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "emscripten.h" +#include "py/gc.h" +#include "py/objmodule.h" +#include "py/runtime.h" +#include "proxy_c.h" + +#if MICROPY_PY_JSFFI + +/******************************************************************************/ +// jsffi module + +EM_JS(void, proxy_convert_mp_to_js_then_js_to_mp_obj_jsside, (uint32_t * out), { + const ret = proxy_convert_mp_to_js_obj_jsside(out); + proxy_convert_js_to_mp_obj_jsside_force_double_proxy(ret, out); +}); + +static mp_obj_t mp_jsffi_create_proxy(mp_obj_t arg) { + uint32_t out[3]; + proxy_convert_mp_to_js_obj_cside(arg, out); + proxy_convert_mp_to_js_then_js_to_mp_obj_jsside(out); + return proxy_convert_js_to_mp_obj_cside(out); +} +static MP_DEFINE_CONST_FUN_OBJ_1(mp_jsffi_create_proxy_obj, mp_jsffi_create_proxy); + +EM_JS(void, proxy_convert_mp_to_js_then_js_to_js_then_js_to_mp_obj_jsside, (uint32_t * out), { + const ret = proxy_convert_mp_to_js_obj_jsside(out); + const js_obj = PyProxy.toJs(ret); + proxy_convert_js_to_mp_obj_jsside(js_obj, out); +}); + +static mp_obj_t mp_jsffi_to_js(mp_obj_t arg) { + uint32_t out[3]; + proxy_convert_mp_to_js_obj_cside(arg, out); + proxy_convert_mp_to_js_then_js_to_js_then_js_to_mp_obj_jsside(out); + return proxy_convert_js_to_mp_obj_cside(out); +} +static MP_DEFINE_CONST_FUN_OBJ_1(mp_jsffi_to_js_obj, mp_jsffi_to_js); + +// *FORMAT-OFF* +EM_JS(void, js_get_proxy_js_ref_info, (uint32_t * out), { + let used = 0; + for (const elem of proxy_js_ref) { + if (elem !== undefined) { + ++used; + } + } + Module.setValue(out, proxy_js_ref.length, "i32"); + Module.setValue(out + 4, used, "i32"); +}); +// *FORMAT-ON* + +static mp_obj_t mp_jsffi_mem_info(void) { + mp_obj_list_t *l = (mp_obj_list_t *)MP_OBJ_TO_PTR(MP_STATE_PORT(proxy_c_ref)); + mp_int_t used = 0; + for (size_t i = 0; i < l->len; ++i) { + if (l->items[i] != MP_OBJ_NULL) { + ++used; + } + } + uint32_t proxy_js_ref_info[2]; + js_get_proxy_js_ref_info(proxy_js_ref_info); + gc_info_t info; + gc_info(&info); + mp_obj_t elems[] = { + MP_OBJ_NEW_SMALL_INT(info.total), // GC heap total bytes + MP_OBJ_NEW_SMALL_INT(info.used), // GC heap used bytes + MP_OBJ_NEW_SMALL_INT(info.free), // GC heap free bytes + MP_OBJ_NEW_SMALL_INT(l->len), // proxy_c_ref allocated size + MP_OBJ_NEW_SMALL_INT(used), // proxy_c_ref used + MP_OBJ_NEW_SMALL_INT(proxy_js_ref_info[0]), // proxy_js_ref allocated size + MP_OBJ_NEW_SMALL_INT(proxy_js_ref_info[1]), // proxy_js_ref used + }; + return mp_obj_new_tuple(MP_ARRAY_SIZE(elems), elems); +} +static MP_DEFINE_CONST_FUN_OBJ_0(mp_jsffi_mem_info_obj, mp_jsffi_mem_info); + +static const mp_rom_map_elem_t mp_module_jsffi_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_jsffi) }, + + { MP_ROM_QSTR(MP_QSTR_JsProxy), MP_ROM_PTR(&mp_type_jsproxy) }, + { MP_ROM_QSTR(MP_QSTR_JsException), MP_ROM_PTR(&mp_type_JsException) }, + { MP_ROM_QSTR(MP_QSTR_create_proxy), MP_ROM_PTR(&mp_jsffi_create_proxy_obj) }, + { MP_ROM_QSTR(MP_QSTR_to_js), MP_ROM_PTR(&mp_jsffi_to_js_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_jsffi_mem_info_obj) }, +}; +static MP_DEFINE_CONST_DICT(mp_module_jsffi_globals, mp_module_jsffi_globals_table); + +const mp_obj_module_t mp_module_jsffi = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mp_module_jsffi_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_jsffi, mp_module_jsffi); + +#endif // MICROPY_PY_JSFFI diff --git a/tulip/web/modtime.c b/tulip/web/modtime.c new file mode 100644 index 00000000..1b1e63d4 --- /dev/null +++ b/tulip/web/modtime.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "shared/timeutils/timeutils.h" +#include "library.h" + +// Return the localtime as an 8-tuple. +static mp_obj_t mp_time_localtime_get(void) { + timeutils_struct_time_t tm; + timeutils_seconds_since_epoch_to_struct_time(mp_hal_time_ms() / 1000, &tm); + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); +} + +// Returns the number of seconds, as a float, since the Epoch. +static mp_obj_t mp_time_time_get(void) { + return mp_obj_new_float((mp_float_t)mp_hal_time_ms() / 1000); +} diff --git a/tulip/web/mpconfigport.h b/tulip/web/mpconfigport.h new file mode 100644 index 00000000..db5bde83 --- /dev/null +++ b/tulip/web/mpconfigport.h @@ -0,0 +1,131 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2022 Damien P. George + * Copyright (c) 2017, 2018 Rami Ali + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Options to control how MicroPython is built for this port, overriding +// defaults in py/mpconfig.h. + +#include +#include // for malloc, for MICROPY_GC_SPLIT_HEAP_AUTO + +// Variant-specific definitions. +#include "mpconfigvariant.h" +#include "emscripten.h" +#ifndef MICROPY_CONFIG_ROM_LEVEL +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) +#endif + +#define MICROPY_PY_SYS_STDFILES (0) +#define MICROPY_PY_BUILTINS_HELP_TEXT tulip_desktop_help_text + +#define MICROPY_ALLOC_PATH_MAX (256) +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_COMP_ALLOW_TOP_LEVEL_AWAIT (1) +#define MICROPY_READER_VFS (MICROPY_VFS) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_PYSTACK (1) +#define MICROPY_STACK_CHECK (0) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_REPL_EVENT_DRIVEN (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_ENABLE_DOC_STRING (1) +#define MICROPY_WARNINGS (1) +#define MICROPY_ERROR_PRINTER (&mp_stderr_print) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) + +#define MICROPY_EPOCH_IS_1970 (1) +#define MICROPY_PY_ASYNCIO_TASK_QUEUE_PUSH_CALLBACK (1) +#define MICROPY_PY_RANDOM_SEED_INIT_FUNC (mp_js_random_u32()) +#define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1) +#define MICROPY_PY_TIME_TIME_TIME_NS (1) +#define MICROPY_PY_TIME_INCLUDEFILE "ports/webassembly/modtime.c" +#ifndef MICROPY_VFS +#define MICROPY_VFS (1) +#endif +#define MICROPY_VFS_POSIX (MICROPY_VFS) +#define MICROPY_PY_SYS_PLATFORM "webassembly" + +#ifndef MICROPY_PY_JS +#define MICROPY_PY_JS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + +#ifndef MICROPY_PY_JSFFI +#define MICROPY_PY_JSFFI (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(bool); \ + mp_handle_pending(true); \ + } while (0); + +// Whether the VM will periodically call mp_js_hook(), which checks for +// interrupt characters on stdin (or equivalent input). +#ifndef MICROPY_VARIANT_ENABLE_JS_HOOK +#define MICROPY_VARIANT_ENABLE_JS_HOOK (0) +#endif + +#if MICROPY_VARIANT_ENABLE_JS_HOOK +#define MICROPY_VM_HOOK_COUNT (10) +#define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT; +#define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \ + vm_hook_divisor = MICROPY_VM_HOOK_COUNT; \ + extern void mp_js_hook(void); \ + mp_js_hook(); \ +} +#define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL +#define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL +#endif + +// type definitions for the specific machine + +#define MP_SSIZE_MAX (0x7fffffff) + +// This port is intended to be 32-bit, but unfortunately, int32_t for +// different targets may be defined in different ways - either as int +// or as long. This requires different printf formatting specifiers +// to print such value. So, we avoid int32_t and use int directly. +#define UINT_FMT "%u" +#define INT_FMT "%d" +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MICROPY_HW_BOARD_NAME "Tulip" +#define MICROPY_HW_MCU_NAME "Emscripten" + +#define MP_STATE_PORT MP_STATE_VM + +#if MICROPY_VFS +// _GNU_SOURCE must be defined to get definitions of DT_xxx symbols from dirent.h. +#define _GNU_SOURCE +#endif + +extern const struct _mp_print_t mp_stderr_print; + +uint32_t mp_js_random_u32(void); diff --git a/tulip/web/mphalport.c b/tulip/web/mphalport.c new file mode 100644 index 00000000..ce0d0ddd --- /dev/null +++ b/tulip/web/mphalport.c @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/mphal.h" +#include "library.h" +#include "mphalport.h" +#include "display.h" + + +static void stderr_print_strn(void *env, const char *str, size_t len) { + if(len) { + display_tfb_str((unsigned char*)str, len, 0, tfb_fg_pal_color, tfb_bg_pal_color); + } + (void)env; + write(2, str, len); +} + +const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; + +mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) { + if(len) { + display_tfb_str((unsigned char*)str, len, 0, tfb_fg_pal_color, tfb_bg_pal_color); + } + return write(1, str, len); +} + +void mp_hal_delay_ms(mp_uint_t ms) { + uint32_t start = mp_hal_ticks_ms(); + while (mp_hal_ticks_ms() - start < ms) { + } +} + +void mp_hal_delay_us(mp_uint_t us) { + uint32_t start = mp_hal_ticks_us(); + while (mp_hal_ticks_us() - start < us) { + } +} + +mp_uint_t mp_hal_ticks_us(void) { + return mp_js_ticks_ms() * 1000; +} + +mp_uint_t mp_hal_ticks_ms(void) { + return mp_js_ticks_ms(); +} + +mp_uint_t mp_hal_ticks_cpu(void) { + return 0; +} + +uint64_t mp_hal_time_ms(void) { + double mm = mp_js_time_ms(); + return (uint64_t)mm; +} + +uint64_t mp_hal_time_ns(void) { + return mp_hal_time_ms() * 1000000ULL; +} + +extern int mp_interrupt_char; + +int mp_hal_get_interrupt_char(int c) { + return mp_interrupt_char; +} diff --git a/tulip/web/mphalport.h b/tulip/web/mphalport.h new file mode 100644 index 00000000..1a8e50bf --- /dev/null +++ b/tulip/web/mphalport.h @@ -0,0 +1,63 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "shared/runtime/interrupt_char.h" + +#define mp_hal_stdin_rx_chr() (0) +mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len); + +void mp_hal_delay_ms(mp_uint_t ms); +void mp_hal_delay_us(mp_uint_t us); +mp_uint_t mp_hal_ticks_ms(void); +mp_uint_t mp_hal_ticks_us(void); +mp_uint_t mp_hal_ticks_cpu(void); +uint64_t mp_hal_time_ms(void); + +int mp_hal_get_interrupt_char(int); + +#if MICROPY_VFS_POSIX + +#include + +// This macro is used to implement PEP 475 to retry specified syscalls on EINTR +#define MP_HAL_RETRY_SYSCALL(ret, syscall, raise) \ + { \ + for (;;) { \ + ret = syscall; \ + if (ret == -1) { \ + int err = errno; \ + if (err == EINTR) { \ + mp_handle_pending(true); \ + continue; \ + } \ + raise; \ + } \ + break; \ + } \ + } + +#endif diff --git a/tulip/web/node_run.sh b/tulip/web/node_run.sh new file mode 100755 index 00000000..466ffe39 --- /dev/null +++ b/tulip/web/node_run.sh @@ -0,0 +1,2 @@ +#!/bin/sh +node $(dirname $0)/build/micropython.js "$@" diff --git a/tulip/web/objjsproxy.c b/tulip/web/objjsproxy.c new file mode 100644 index 00000000..167d4382 --- /dev/null +++ b/tulip/web/objjsproxy.c @@ -0,0 +1,550 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "emscripten.h" +#include "py/objmodule.h" +#include "py/runtime.h" +#include "proxy_c.h" + +EM_JS(bool, has_attr, (int jsref, const char *str), { + const base = proxy_js_ref[jsref]; + const attr = UTF8ToString(str); + if (attr in base) { + return true; + } else { + return false; + } +}); + +// *FORMAT-OFF* +EM_JS(bool, lookup_attr, (int jsref, const char *str, uint32_t * out), { + const base = proxy_js_ref[jsref]; + const attr = UTF8ToString(str); + + // Attempt to lookup the requested attribute from the base object: + // - If the value is not `undefined` then the attribute exists with that value. + // - Otherwise if the value is `undefined` and the `in` operator returns true, then + // that attribute does exist and is intended to have a value of `undefined`. + // - Otherwise, the attribute does not exist. + let value = base[attr]; + if (value !== undefined || attr in base) { + if (typeof value === "function") { + if (base !== globalThis) { + if ("_ref" in value) { + // This is a proxy of a Python function, it doesn't need + // binding. And not binding it means if it's passed back + // to Python then it can be extracted from the proxy as a + // true Python function. + } else { + // A function that is not a Python function. Bind it. + value = value.bind(base); + } + } + } + proxy_convert_js_to_mp_obj_jsside(value, out); + return true; + } else { + return false; + } +}); +// *FORMAT-ON* + +EM_JS(void, store_attr, (int jsref, const char *attr_ptr, uint32_t * value_ref), { + const attr = UTF8ToString(attr_ptr); + const value = proxy_convert_mp_to_js_obj_jsside(value_ref); + proxy_js_ref[jsref][attr] = value; +}); + +EM_JS(void, call0, (int f_ref, uint32_t * out), { + // Because of JavaScript "this" semantics, we must extract the target function + // to a variable before calling it, so "this" is bound to the correct value. + // + // In detail: + // In JavaScript, proxy_js_ref[f_ref] acts like a function call + // proxy_js_ref.at(f_ref), and "this" will be bound to proxy_js_ref if + // there is a chain of calls, such as proxy_js_ref.at(f_ref)(). + // But proxy_js_ref is not "this" in the context of the call, so we + // must extract the function to an independent variable and then call + // that variable, so that "this" is correct (it will be "undefined"). + + const f = proxy_js_ref[f_ref]; + const ret = f(); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(int, call1, (int f_ref, uint32_t * a0, uint32_t * out), { + const a0_js = proxy_convert_mp_to_js_obj_jsside(a0); + const f = proxy_js_ref[f_ref]; + const ret = f(a0_js); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(int, call2, (int f_ref, uint32_t * a0, uint32_t * a1, uint32_t * out), { + const a0_js = proxy_convert_mp_to_js_obj_jsside(a0); + const a1_js = proxy_convert_mp_to_js_obj_jsside(a1); + const f = proxy_js_ref[f_ref]; + const ret = f(a0_js, a1_js); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(int, calln, (int f_ref, uint32_t n_args, uint32_t * value, uint32_t * out), { + const f = proxy_js_ref[f_ref]; + const a = []; + for (let i = 0; i < n_args; ++i) { + const v = proxy_convert_mp_to_js_obj_jsside(value + i * 3 * 4); + a.push(v); + } + const ret = f(... a); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(void, call0_kwarg, (int f_ref, uint32_t n_kw, uint32_t * key, uint32_t * value, uint32_t * out), { + const f = proxy_js_ref[f_ref]; + const a = {}; + for (let i = 0; i < n_kw; ++i) { + const k = UTF8ToString(getValue(key + i * 4, "i32")); + const v = proxy_convert_mp_to_js_obj_jsside(value + i * 3 * 4); + a[k] = v; + } + const ret = f(a); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(void, call1_kwarg, (int f_ref, uint32_t * arg0, uint32_t n_kw, uint32_t * key, uint32_t * value, uint32_t * out), { + const f = proxy_js_ref[f_ref]; + const a0 = proxy_convert_mp_to_js_obj_jsside(arg0); + const a = {}; + for (let i = 0; i < n_kw; ++i) { + const k = UTF8ToString(getValue(key + i * 4, "i32")); + const v = proxy_convert_mp_to_js_obj_jsside(value + i * 3 * 4); + a[k] = v; + } + const ret = f(a0, a); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(void, js_reflect_construct, (int f_ref, uint32_t n_args, uint32_t * args, uint32_t * out), { + const f = proxy_js_ref[f_ref]; + const as = []; + for (let i = 0; i < n_args; ++i) { + as.push(proxy_convert_mp_to_js_obj_jsside(args + i * 3 * 4)); + } + const ret = Reflect.construct(f, as); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(void, js_get_iter, (int f_ref, uint32_t * out), { + const f = proxy_js_ref[f_ref]; + const ret = f[Symbol.iterator](); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(bool, js_iter_next, (int f_ref, uint32_t * out), { + const f = proxy_js_ref[f_ref]; + const ret = f.next(); + if (ret.done) { + return false; + } else { + proxy_convert_js_to_mp_obj_jsside(ret.value, out); + return true; + } +}); + +EM_JS(void, js_subscr_load, (int f_ref, uint32_t * index_ref, uint32_t * out), { + const target = proxy_js_ref[f_ref]; + const index = python_index_semantics(target, proxy_convert_mp_to_js_obj_jsside(index_ref)); + const ret = target[index]; + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); + +EM_JS(void, js_subscr_store, (int f_ref, uint32_t * idx, uint32_t * value), { + const f = proxy_js_ref[f_ref]; + f[proxy_convert_mp_to_js_obj_jsside(idx)] = proxy_convert_mp_to_js_obj_jsside(value); +}); + +static void jsproxy_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->ref); +} + +static mp_obj_t jsproxy_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in); + + if (n_kw == 0) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false); + } else { + mp_arg_check_num(n_args, n_kw, 0, 1, true); + uint32_t key[n_kw]; + uint32_t value[PVN * n_kw]; + for (int i = 0; i < n_kw; ++i) { + key[i] = (uintptr_t)mp_obj_str_get_str(args[n_args + i * 2]); + proxy_convert_mp_to_js_obj_cside(args[n_args + i * 2 + 1], &value[i * PVN]); + } + uint32_t out[3]; + if (n_args == 0) { + call0_kwarg(self->ref, n_kw, key, value, out); + } else { + // n_args == 1 + uint32_t arg0[PVN]; + proxy_convert_mp_to_js_obj_cside(args[0], arg0); + call1_kwarg(self->ref, arg0, n_kw, key, value, out); + } + return proxy_convert_js_to_mp_obj_cside(out); + } + + if (n_args == 0) { + uint32_t out[3]; + call0(self->ref, out); + return proxy_convert_js_to_mp_obj_cside(out); + } else if (n_args == 1) { + uint32_t arg0[PVN]; + uint32_t out[PVN]; + proxy_convert_mp_to_js_obj_cside(args[0], arg0); + call1(self->ref, arg0, out); + return proxy_convert_js_to_mp_obj_cside(out); + } else if (n_args == 2) { + uint32_t arg0[PVN]; + proxy_convert_mp_to_js_obj_cside(args[0], arg0); + uint32_t arg1[PVN]; + proxy_convert_mp_to_js_obj_cside(args[1], arg1); + uint32_t out[3]; + call2(self->ref, arg0, arg1, out); + return proxy_convert_js_to_mp_obj_cside(out); + } else { + uint32_t value[PVN * n_args]; + for (int i = 0; i < n_args; ++i) { + proxy_convert_mp_to_js_obj_cside(args[i], &value[i * PVN]); + } + uint32_t out[3]; + calln(self->ref, n_args, value, out); + return proxy_convert_js_to_mp_obj_cside(out); + } +} + +EM_JS(void, proxy_js_free_obj, (int js_ref), { + if (js_ref >= PROXY_JS_REF_NUM_STATIC) { + proxy_js_ref[js_ref] = undefined; + if (js_ref < proxy_js_ref_next) { + proxy_js_ref_next = js_ref; + } + } +}); + +static mp_obj_t jsproxy___del__(mp_obj_t self_in) { + mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in); + proxy_js_free_obj(self->ref); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(jsproxy___del___obj, jsproxy___del__); + +static mp_obj_t jsproxy_reflect_construct(size_t n_args, const mp_obj_t *args) { + int arg0 = mp_obj_jsproxy_get_ref(args[0]); + n_args -= 1; + args += 1; + uint32_t args_conv[n_args]; + for (unsigned int i = 0; i < n_args; ++i) { + proxy_convert_mp_to_js_obj_cside(args[i], &args_conv[i * PVN]); + } + uint32_t out[PVN]; + js_reflect_construct(arg0, n_args, args_conv, out); + return proxy_convert_js_to_mp_obj_cside(out); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR(jsproxy_reflect_construct_obj, 1, jsproxy_reflect_construct); + +static mp_obj_t jsproxy_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in); + if (value == MP_OBJ_SENTINEL) { + // Load subscript. + uint32_t idx[PVN], out[PVN]; + proxy_convert_mp_to_js_obj_cside(index, idx); + js_subscr_load(self->ref, idx, out); + return proxy_convert_js_to_mp_obj_cside(out); + } else if (value == MP_OBJ_NULL) { + // Delete subscript. + return MP_OBJ_NULL; // not supported + } else { + // Store subscript. + uint32_t idx[PVN], val[PVN]; + proxy_convert_mp_to_js_obj_cside(index, idx); + proxy_convert_mp_to_js_obj_cside(value, val); + js_subscr_store(self->ref, idx, val); + return mp_const_none; + } +} + +void mp_obj_jsproxy_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in); + if (dest[0] == MP_OBJ_NULL) { + // Load attribute. + uint32_t out[PVN]; + if (attr == MP_QSTR___del__) { + // For finaliser. + dest[0] = MP_OBJ_FROM_PTR(&jsproxy___del___obj); + dest[1] = self_in; + } else if (lookup_attr(self->ref, qstr_str(attr), out)) { + dest[0] = proxy_convert_js_to_mp_obj_cside(out); + } else if (attr == MP_QSTR_new) { + // Special case to handle construction of JS objects. + // JS objects don't have a ".new" attribute, doing "Obj.new" is a Pyodide idiom for "new Obj". + // It translates to the JavaScript "Reflect.construct(Obj, Array(...args))". + dest[0] = MP_OBJ_FROM_PTR(&jsproxy_reflect_construct_obj); + dest[1] = self_in; + } + } else if (dest[1] == MP_OBJ_NULL) { + // Delete attribute. + } else { + // Store attribute. + uint32_t value[PVN]; + proxy_convert_mp_to_js_obj_cside(dest[1], value); + store_attr(self->ref, qstr_str(attr), value); + dest[0] = MP_OBJ_NULL; + } +} + +/******************************************************************************/ +// jsproxy iterator + +typedef struct _jsproxy_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_jsproxy_t *iter; +} jsproxy_it_t; + +static mp_obj_t jsproxy_it_iternext(mp_obj_t self_in) { + jsproxy_it_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t out[3]; + if (js_iter_next(self->iter->ref, out)) { + return proxy_convert_js_to_mp_obj_cside(out); + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +static mp_obj_t jsproxy_new_it(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(jsproxy_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in); + jsproxy_it_t *o = (jsproxy_it_t *)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = jsproxy_it_iternext; + uint32_t out[3]; + js_get_iter(self->ref, out); + o->iter = proxy_convert_js_to_mp_obj_cside(out); + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ +// jsproxy generator + +enum { + JSOBJ_GEN_STATE_WAITING, + JSOBJ_GEN_STATE_COMPLETED, + JSOBJ_GEN_STATE_EXHAUSTED, +}; + +typedef struct _jsproxy_gen_t { + mp_obj_base_t base; + mp_obj_t thenable; + int state; +} jsproxy_gen_t; + +mp_vm_return_kind_t jsproxy_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { + jsproxy_gen_t *self = MP_OBJ_TO_PTR(self_in); + + if (throw_value) { + *ret_val = throw_value; + return MP_VM_RETURN_EXCEPTION; + } + + switch (self->state) { + case JSOBJ_GEN_STATE_WAITING: + self->state = JSOBJ_GEN_STATE_COMPLETED; + *ret_val = self->thenable; + return MP_VM_RETURN_YIELD; + + case JSOBJ_GEN_STATE_COMPLETED: + self->state = JSOBJ_GEN_STATE_EXHAUSTED; + *ret_val = send_value; + return MP_VM_RETURN_NORMAL; + + case JSOBJ_GEN_STATE_EXHAUSTED: + default: + // Trying to resume an already stopped generator. + // This is an optimised "raise StopIteration(None)". + *ret_val = mp_const_none; + return MP_VM_RETURN_NORMAL; + } +} + +static mp_obj_t jsproxy_gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, bool raise_stop_iteration) { + mp_obj_t ret; + switch (jsproxy_gen_resume(self_in, send_value, throw_value, &ret)) { + case MP_VM_RETURN_NORMAL: + default: + // A normal return is a StopIteration, either raise it or return + // MP_OBJ_STOP_ITERATION as an optimisation. + if (ret == mp_const_none) { + ret = MP_OBJ_NULL; + } + if (raise_stop_iteration) { + mp_raise_StopIteration(ret); + } else { + return mp_make_stop_iteration(ret); + } + + case MP_VM_RETURN_YIELD: + return ret; + + case MP_VM_RETURN_EXCEPTION: + nlr_raise(ret); + } +} + +static mp_obj_t jsproxy_gen_instance_iternext(mp_obj_t self_in) { + return jsproxy_gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL, false); +} + +static mp_obj_t jsproxy_gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { + return jsproxy_gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL, true); +} +static MP_DEFINE_CONST_FUN_OBJ_2(jsproxy_gen_instance_send_obj, jsproxy_gen_instance_send); + +static mp_obj_t jsproxy_gen_instance_throw(size_t n_args, const mp_obj_t *args) { + // The signature of this function is: throw(type[, value[, traceback]]) + // CPython will pass all given arguments through the call chain and process them + // at the point they are used (native generators will handle them differently to + // user-defined generators with a throw() method). To save passing multiple + // values, MicroPython instead does partial processing here to reduce it down to + // one argument and passes that through: + // - if only args[1] is given, or args[2] is given but is None, args[1] is + // passed through (in the standard case it is an exception class or instance) + // - if args[2] is given and not None it is passed through (in the standard + // case it would be an exception instance and args[1] its corresponding class) + // - args[3] is always ignored + + mp_obj_t exc = args[1]; + if (n_args > 2 && args[2] != mp_const_none) { + exc = args[2]; + } + + return jsproxy_gen_resume_and_raise(args[0], mp_const_none, exc, true); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(jsproxy_gen_instance_throw_obj, 2, 4, jsproxy_gen_instance_throw); + +static mp_obj_t jsproxy_gen_instance_close(mp_obj_t self_in) { + mp_obj_t ret; + switch (jsproxy_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) { + case MP_VM_RETURN_YIELD: + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("generator ignored GeneratorExit")); + + // Swallow GeneratorExit (== successful close), and re-raise any other + case MP_VM_RETURN_EXCEPTION: + // ret should always be an instance of an exception class + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(ret)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { + return mp_const_none; + } + nlr_raise(ret); + + default: + // The only choice left is MP_VM_RETURN_NORMAL which is successful close + return mp_const_none; + } +} +static MP_DEFINE_CONST_FUN_OBJ_1(jsproxy_gen_instance_close_obj, jsproxy_gen_instance_close); + +static const mp_rom_map_elem_t jsproxy_gen_instance_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&jsproxy_gen_instance_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&jsproxy_gen_instance_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&jsproxy_gen_instance_throw_obj) }, +}; +static MP_DEFINE_CONST_DICT(jsproxy_gen_instance_locals_dict, jsproxy_gen_instance_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mp_type_jsproxy_gen, + MP_QSTR_generator, + MP_TYPE_FLAG_ITER_IS_ITERNEXT, + iter, jsproxy_gen_instance_iternext, + locals_dict, &jsproxy_gen_instance_locals_dict + ); + +static mp_obj_t jsproxy_new_gen(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(jsproxy_gen_t) <= sizeof(mp_obj_iter_buf_t)); + jsproxy_gen_t *o = (jsproxy_gen_t *)iter_buf; + o->base.type = &mp_type_jsproxy_gen; + o->thenable = self_in; + o->state = JSOBJ_GEN_STATE_WAITING; + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ + +#if MICROPY_PY_ASYNCIO +extern mp_obj_t mp_asyncio_context; +#endif + +static mp_obj_t jsproxy_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in); + if (has_attr(self->ref, "then")) { + #if MICROPY_PY_ASYNCIO + // When asyncio is running and the caller here is a task, wrap the JavaScript + // thenable in a ThenableEvent, and get the task to wait on that event. This + // decouples the task from the thenable and allows cancelling the task. + if (mp_asyncio_context != MP_OBJ_NULL) { + mp_obj_t cur_task = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task)); + if (cur_task != mp_const_none) { + mp_obj_t thenable_event_class = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_ThenableEvent)); + mp_obj_t thenable_event = mp_call_function_1(thenable_event_class, self_in); + mp_obj_t dest[2]; + mp_load_method(thenable_event, MP_QSTR_wait, dest); + mp_obj_t wait_gen = mp_call_method_n_kw(0, 0, dest); + return mp_getiter(wait_gen, iter_buf); + } + } + #endif + return jsproxy_new_gen(self_in, iter_buf); + } else { + return jsproxy_new_it(self_in, iter_buf); + } +} + +MP_DEFINE_CONST_OBJ_TYPE( + mp_type_jsproxy, + MP_QSTR_JsProxy, + MP_TYPE_FLAG_ITER_IS_GETITER, + print, jsproxy_print, + call, jsproxy_call, + attr, mp_obj_jsproxy_attr, + subscr, jsproxy_subscr, + iter, jsproxy_getiter + ); + +mp_obj_t mp_obj_new_jsproxy(int ref) { + mp_obj_jsproxy_t *o = mp_obj_malloc_with_finaliser(mp_obj_jsproxy_t, &mp_type_jsproxy); + o->ref = ref; + return MP_OBJ_FROM_PTR(o); +} diff --git a/tulip/web/objpyproxy.js b/tulip/web/objpyproxy.js new file mode 100644 index 00000000..3b94f8aa --- /dev/null +++ b/tulip/web/objpyproxy.js @@ -0,0 +1,241 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +class PyProxy { + constructor(ref) { + this._ref = ref; + } + + // Convert js_obj -- which is possibly a PyProxy -- to a JavaScript object. + static toJs(js_obj) { + if (!(js_obj instanceof PyProxy)) { + return js_obj; + } + + const type = Module.ccall( + "proxy_c_to_js_get_type", + "number", + ["number"], + [js_obj._ref], + ); + + if (type === 1 || type === 2) { + // List or tuple. + const array_ref = Module._malloc(2 * 4); + const item = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_get_array", + "null", + ["number", "pointer"], + [js_obj._ref, array_ref], + ); + const len = Module.getValue(array_ref, "i32"); + const items_ptr = Module.getValue(array_ref + 4, "i32"); + const js_array = []; + for (let i = 0; i < len; ++i) { + Module.ccall( + "proxy_convert_mp_to_js_obj_cside", + "null", + ["pointer", "pointer"], + [Module.getValue(items_ptr + i * 4, "i32"), item], + ); + const js_item = proxy_convert_mp_to_js_obj_jsside(item); + js_array.push(PyProxy.toJs(js_item)); + } + Module._free(array_ref); + Module._free(item); + return js_array; + } + + if (type === 3) { + // Dict. + const map_ref = Module._malloc(2 * 4); + const item = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_get_dict", + "null", + ["number", "pointer"], + [js_obj._ref, map_ref], + ); + const alloc = Module.getValue(map_ref, "i32"); + const table_ptr = Module.getValue(map_ref + 4, "i32"); + const js_dict = {}; + for (let i = 0; i < alloc; ++i) { + const mp_key = Module.getValue(table_ptr + i * 8, "i32"); + if (mp_key > 8) { + // Convert key to JS object. + Module.ccall( + "proxy_convert_mp_to_js_obj_cside", + "null", + ["pointer", "pointer"], + [mp_key, item], + ); + const js_key = proxy_convert_mp_to_js_obj_jsside(item); + + // Convert value to JS object. + const mp_value = Module.getValue( + table_ptr + i * 8 + 4, + "i32", + ); + Module.ccall( + "proxy_convert_mp_to_js_obj_cside", + "null", + ["pointer", "pointer"], + [mp_value, item], + ); + const js_value = proxy_convert_mp_to_js_obj_jsside(item); + + // Populate JS dict. + js_dict[js_key] = PyProxy.toJs(js_value); + } + } + Module._free(map_ref); + Module._free(item); + return js_dict; + } + + // Cannot convert to JS, leave as a PyProxy. + return js_obj; + } +} + +// This handler's goal is to allow minimal introspection +// of Python references from the JS world/utilities. +const py_proxy_handler = { + isExtensible() { + return true; + }, + ownKeys(target) { + const value = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_dir", + "null", + ["number", "pointer"], + [target._ref, value], + ); + const dir = proxy_convert_mp_to_js_obj_jsside_with_free(value); + return PyProxy.toJs(dir).filter((attr) => !attr.startsWith("__")); + }, + getOwnPropertyDescriptor(target, prop) { + return { + value: target[prop], + enumerable: true, + writable: true, + configurable: true, + }; + }, + has(target, prop) { + return Module.ccall( + "proxy_c_to_js_has_attr", + "number", + ["number", "string"], + [target._ref, prop], + ); + }, + get(target, prop) { + if (prop === "_ref") { + return target._ref; + } + if (prop === "then") { + return null; + } + + if (prop === Symbol.iterator) { + // Get the Python object iterator, and return a JavaScript generator. + const iter_ref = Module.ccall( + "proxy_c_to_js_get_iter", + "number", + ["number"], + [target._ref], + ); + return function* () { + const value = Module._malloc(3 * 4); + while (true) { + const valid = Module.ccall( + "proxy_c_to_js_iternext", + "number", + ["number", "pointer"], + [iter_ref, value], + ); + if (!valid) { + break; + } + yield proxy_convert_mp_to_js_obj_jsside(value); + } + Module._free(value); + }; + } + + const value = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_lookup_attr", + "null", + ["number", "string", "pointer"], + [target._ref, prop, value], + ); + return proxy_convert_mp_to_js_obj_jsside_with_free(value); + }, + set(target, prop, value) { + const value_conv = Module._malloc(3 * 4); + proxy_convert_js_to_mp_obj_jsside(value, value_conv); + const ret = Module.ccall( + "proxy_c_to_js_store_attr", + "number", + ["number", "string", "number"], + [target._ref, prop, value_conv], + ); + Module._free(value_conv); + return ret; + }, + deleteProperty(target, prop) { + return Module.ccall( + "proxy_c_to_js_delete_attr", + "number", + ["number", "string"], + [target._ref, prop], + ); + }, +}; + +// PyProxy of a Python generator, that implements the thenable interface. +class PyProxyThenable { + constructor(ref) { + this._ref = ref; + } + + then(resolve, reject) { + const values = Module._malloc(3 * 3 * 4); + proxy_convert_js_to_mp_obj_jsside(resolve, values + 3 * 4); + proxy_convert_js_to_mp_obj_jsside(reject, values + 2 * 3 * 4); + Module.ccall( + "proxy_c_to_js_resume", + "null", + ["number", "pointer"], + [this._ref, values], + ); + return proxy_convert_mp_to_js_obj_jsside_with_free(values); + } +} diff --git a/tulip/web/package-lock.json b/tulip/web/package-lock.json new file mode 100644 index 00000000..05eb06e5 --- /dev/null +++ b/tulip/web/package-lock.json @@ -0,0 +1,17 @@ +{ + "name": "webassembly", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@xterm/xterm": "^5.5.0" + } + }, + "node_modules/@xterm/xterm": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", + "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==" + } + } +} diff --git a/tulip/web/package.json b/tulip/web/package.json new file mode 100644 index 00000000..00609aef --- /dev/null +++ b/tulip/web/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@xterm/xterm": "^5.5.0" + } +} diff --git a/tulip/web/proxy_c.c b/tulip/web/proxy_c.c new file mode 100644 index 00000000..00abc43b --- /dev/null +++ b/tulip/web/proxy_c.c @@ -0,0 +1,615 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "emscripten.h" +#include "py/builtin.h" +#include "py/runtime.h" +#include "proxy_c.h" + +// Number of static entries at the start of proxy_c_ref. +#define PROXY_C_REF_NUM_STATIC (1) + +// These constants should match the constants in proxy_js.js. + +enum { + PROXY_KIND_MP_EXCEPTION = -1, + PROXY_KIND_MP_NULL = 0, + PROXY_KIND_MP_NONE = 1, + PROXY_KIND_MP_BOOL = 2, + PROXY_KIND_MP_INT = 3, + PROXY_KIND_MP_FLOAT = 4, + PROXY_KIND_MP_STR = 5, + PROXY_KIND_MP_CALLABLE = 6, + PROXY_KIND_MP_GENERATOR = 7, + PROXY_KIND_MP_OBJECT = 8, + PROXY_KIND_MP_JSPROXY = 9, + PROXY_KIND_MP_EXISTING = 10, +}; + +enum { + PROXY_KIND_JS_UNDEFINED = 0, + PROXY_KIND_JS_NULL = 1, + PROXY_KIND_JS_BOOLEAN = 2, + PROXY_KIND_JS_INTEGER = 3, + PROXY_KIND_JS_DOUBLE = 4, + PROXY_KIND_JS_STRING = 5, + PROXY_KIND_JS_OBJECT = 6, + PROXY_KIND_JS_PYPROXY = 7, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + mp_type_undefined, + MP_QSTR_undefined, + MP_TYPE_FLAG_NONE + ); + +static const mp_obj_base_t mp_const_undefined_obj = {&mp_type_undefined}; + +#define mp_const_undefined (MP_OBJ_FROM_PTR(&mp_const_undefined_obj)) + +MP_DEFINE_EXCEPTION(JsException, Exception) + +// Index to start searching for the next available slot in proxy_c_ref. +static size_t proxy_c_ref_next; + +void proxy_c_init(void) { + MP_STATE_PORT(proxy_c_ref) = mp_obj_new_list(0, NULL); + MP_STATE_PORT(proxy_c_dict) = mp_obj_new_dict(0); + mp_obj_list_append(MP_STATE_PORT(proxy_c_ref), MP_OBJ_NULL); + proxy_c_ref_next = PROXY_C_REF_NUM_STATIC; +} + +MP_REGISTER_ROOT_POINTER(mp_obj_t proxy_c_ref); +MP_REGISTER_ROOT_POINTER(mp_obj_t proxy_c_dict); + +// obj cannot be MP_OBJ_NULL. +static inline size_t proxy_c_add_obj(mp_obj_t obj) { + // Search for the first free slot in proxy_c_ref. + size_t id = 0; + mp_obj_list_t *l = (mp_obj_list_t *)MP_OBJ_TO_PTR(MP_STATE_PORT(proxy_c_ref)); + while (proxy_c_ref_next < l->len) { + if (l->items[proxy_c_ref_next] == MP_OBJ_NULL) { + // Free slot found, reuse it. + id = proxy_c_ref_next; + ++proxy_c_ref_next; + l->items[id] = obj; + break; + } + ++proxy_c_ref_next; + } + + if (id == 0) { + // No free slots, so grow proxy_c_ref by one (append at the end of the list). + id = l->len; + mp_obj_list_append(MP_STATE_PORT(proxy_c_ref), obj); + proxy_c_ref_next = l->len; + } + + // Add the object to proxy_c_dict, keyed by the object pointer, with value the object id. + mp_obj_t obj_key = mp_obj_new_int_from_uint((uintptr_t)obj); + mp_map_elem_t *elem = mp_map_lookup(mp_obj_dict_get_map(MP_STATE_PORT(proxy_c_dict)), obj_key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + elem->value = mp_obj_new_int_from_uint(id); + + return id; +} + +EM_JS(int, js_check_existing, (int c_ref), { + return proxy_js_check_existing(c_ref); +}); + +// obj cannot be MP_OBJ_NULL. +static inline int proxy_c_check_existing(mp_obj_t obj) { + mp_obj_t obj_key = mp_obj_new_int_from_uint((uintptr_t)obj); + mp_map_elem_t *elem = mp_map_lookup(mp_obj_dict_get_map(MP_STATE_PORT(proxy_c_dict)), obj_key, MP_MAP_LOOKUP); + if (elem == NULL) { + return -1; + } + uint32_t c_ref = mp_obj_int_get_truncated(elem->value); + return js_check_existing(c_ref); +} + +static inline mp_obj_t proxy_c_get_obj(uint32_t c_ref) { + return ((mp_obj_list_t *)MP_OBJ_TO_PTR(MP_STATE_PORT(proxy_c_ref)))->items[c_ref]; +} + +void proxy_c_free_obj(uint32_t c_ref) { + if (c_ref >= PROXY_C_REF_NUM_STATIC) { + // Remove the object from proxy_c_dict if the c_ref in that dict corresponds to this object. + // (It may be that this object exists in the dict but with a different c_ref from a more + // recent proxy of this object.) + mp_obj_t obj_key = mp_obj_new_int_from_uint((uintptr_t)proxy_c_get_obj(c_ref)); + mp_map_elem_t *elem = mp_map_lookup(mp_obj_dict_get_map(MP_STATE_PORT(proxy_c_dict)), obj_key, MP_MAP_LOOKUP); + if (elem != NULL && mp_obj_int_get_truncated(elem->value) == c_ref) { + mp_map_lookup(mp_obj_dict_get_map(MP_STATE_PORT(proxy_c_dict)), obj_key, MP_MAP_LOOKUP_REMOVE_IF_FOUND); + } + + // Clear the slot in proxy_c_ref used by this object, so the GC can reclaim the object. + ((mp_obj_list_t *)MP_OBJ_TO_PTR(MP_STATE_PORT(proxy_c_ref)))->items[c_ref] = MP_OBJ_NULL; + proxy_c_ref_next = MIN(proxy_c_ref_next, c_ref); + } +} + +mp_obj_t proxy_convert_js_to_mp_obj_cside(uint32_t *value) { + if (value[0] == PROXY_KIND_JS_UNDEFINED) { + return mp_const_undefined; + } else if (value[0] == PROXY_KIND_JS_NULL) { + return mp_const_none; + } else if (value[0] == PROXY_KIND_JS_BOOLEAN) { + return mp_obj_new_bool(value[1]); + } else if (value[0] == PROXY_KIND_JS_INTEGER) { + return mp_obj_new_int(value[1]); + } else if (value[0] == PROXY_KIND_JS_DOUBLE) { + return mp_obj_new_float_from_d(*(double *)&value[1]); + } else if (value[0] == PROXY_KIND_JS_STRING) { + mp_obj_t s = mp_obj_new_str((void *)value[2], value[1]); + free((void *)value[2]); + return s; + } else if (value[0] == PROXY_KIND_JS_PYPROXY) { + return proxy_c_get_obj(value[1]); + } else { + // PROXY_KIND_JS_OBJECT + return mp_obj_new_jsproxy(value[1]); + } +} + +void proxy_convert_mp_to_js_obj_cside(mp_obj_t obj, uint32_t *out) { + uint32_t kind; + int js_ref; + if (obj == MP_OBJ_NULL) { + kind = PROXY_KIND_MP_NULL; + } else if (obj == mp_const_none) { + kind = PROXY_KIND_MP_NONE; + } else if (mp_obj_is_bool(obj)) { + kind = PROXY_KIND_MP_BOOL; + out[1] = mp_obj_is_true(obj); + } else if (mp_obj_is_int(obj)) { + kind = PROXY_KIND_MP_INT; + out[1] = mp_obj_get_int_truncated(obj); // TODO support big int + } else if (mp_obj_is_float(obj)) { + kind = PROXY_KIND_MP_FLOAT; + *(double *)&out[1] = mp_obj_get_float(obj); + } else if (mp_obj_is_str(obj)) { + kind = PROXY_KIND_MP_STR; + size_t len; + const char *str = mp_obj_str_get_data(obj, &len); + out[1] = len; + out[2] = (uintptr_t)str; + } else if (obj == mp_const_undefined) { + kind = PROXY_KIND_MP_JSPROXY; + out[1] = 1; + } else if (mp_obj_is_jsproxy(obj)) { + kind = PROXY_KIND_MP_JSPROXY; + out[1] = mp_obj_jsproxy_get_ref(obj); + } else if ((js_ref = proxy_c_check_existing(obj)) >= 0) { + kind = PROXY_KIND_MP_EXISTING; + out[1] = js_ref; + } else if (mp_obj_get_type(obj) == &mp_type_JsException) { + mp_obj_exception_t *exc = MP_OBJ_TO_PTR(obj); + if (exc->args->len > 0 && mp_obj_is_jsproxy(exc->args->items[0])) { + kind = PROXY_KIND_MP_JSPROXY; + out[1] = mp_obj_jsproxy_get_ref(exc->args->items[0]); + } else { + kind = PROXY_KIND_MP_OBJECT; + out[1] = proxy_c_add_obj(obj); + } + } else { + if (mp_obj_is_callable(obj)) { + kind = PROXY_KIND_MP_CALLABLE; + } else if (mp_obj_is_type(obj, &mp_type_gen_instance)) { + kind = PROXY_KIND_MP_GENERATOR; + } else { + kind = PROXY_KIND_MP_OBJECT; + } + out[1] = proxy_c_add_obj(obj); + } + out[0] = kind; +} + +void proxy_convert_mp_to_js_exc_cside(void *exc, uint32_t *out) { + out[0] = PROXY_KIND_MP_EXCEPTION; + vstr_t vstr; + mp_print_t print; + vstr_init_print(&vstr, 64, &print); + vstr_add_str(&vstr, qstr_str(mp_obj_get_type(MP_OBJ_FROM_PTR(exc))->name)); + vstr_add_char(&vstr, '\x04'); + mp_obj_print_exception(&print, MP_OBJ_FROM_PTR(exc)); + char *s = malloc(vstr_len(&vstr) + 1); + memcpy(s, vstr_str(&vstr), vstr_len(&vstr)); + out[1] = vstr_len(&vstr); + out[2] = (uintptr_t)s; + vstr_clear(&vstr); +} + +void proxy_c_to_js_call(uint32_t c_ref, uint32_t n_args, uint32_t *args_value, uint32_t *out) { + external_call_depth_inc(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t args[n_args]; + for (size_t i = 0; i < n_args; ++i) { + args[i] = proxy_convert_js_to_mp_obj_cside(args_value + i * 3); + } + mp_obj_t obj = proxy_c_get_obj(c_ref); + mp_obj_t member = mp_call_function_n_kw(obj, n_args, 0, args); + nlr_pop(); + external_call_depth_dec(); + proxy_convert_mp_to_js_obj_cside(member, out); + } else { + // uncaught exception + external_call_depth_dec(); + proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); + } +} + +void proxy_c_to_js_dir(uint32_t c_ref, uint32_t *out) { + external_call_depth_inc(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + mp_obj_t dir; + if (mp_obj_is_dict_or_ordereddict(obj)) { + mp_map_t *map = mp_obj_dict_get_map(obj); + dir = mp_obj_new_list(0, NULL); + for (size_t i = 0; i < map->alloc; i++) { + if (mp_map_slot_is_filled(map, i)) { + mp_obj_list_append(dir, map->table[i].key); + } + } + } else { + mp_obj_t args[1] = { obj }; + dir = mp_builtin_dir_obj.fun.var(1, args); + } + nlr_pop(); + external_call_depth_dec(); + proxy_convert_mp_to_js_obj_cside(dir, out); + } else { + // uncaught exception + external_call_depth_dec(); + proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); + } +} + +bool proxy_c_to_js_has_attr(uint32_t c_ref, const char *attr_in) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + qstr attr = qstr_from_str(attr_in); + if (mp_obj_is_dict_or_ordereddict(obj)) { + mp_map_t *map = mp_obj_dict_get_map(obj); + mp_map_elem_t *elem = mp_map_lookup(map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); + return elem != NULL; + } else { + mp_obj_t dest[2]; + mp_load_method_protected(obj, attr, dest, true); + if (dest[0] != MP_OBJ_NULL) { + return true; + } + } + return false; +} + +void proxy_c_to_js_lookup_attr(uint32_t c_ref, const char *attr_in, uint32_t *out) { + external_call_depth_inc(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + qstr attr = qstr_from_str(attr_in); + mp_obj_t member; + if (mp_obj_is_dict_or_ordereddict(obj)) { + // Lookup the requested attribute as a key in the target dict, and + // return `undefined` if not found (instead of raising `KeyError`). + mp_obj_dict_t *self = MP_OBJ_TO_PTR(obj); + mp_map_elem_t *elem = mp_map_lookup(&self->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); + if (elem == NULL) { + member = mp_const_undefined; + } else { + member = elem->value; + } + } else { + // Lookup the requested attribute as a member/method of the target object. + member = mp_load_attr(obj, attr); + } + nlr_pop(); + external_call_depth_dec(); + proxy_convert_mp_to_js_obj_cside(member, out); + } else { + // uncaught exception + external_call_depth_dec(); + proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); + } +} + +static bool proxy_c_to_js_store_helper(uint32_t c_ref, const char *attr_in, uint32_t *value_in) { + external_call_depth_inc(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + qstr attr = qstr_from_str(attr_in); + + mp_obj_t value = MP_OBJ_NULL; + if (value_in != NULL) { + value = proxy_convert_js_to_mp_obj_cside(value_in); + } + + if (mp_obj_is_dict_or_ordereddict(obj)) { + if (value == MP_OBJ_NULL) { + mp_obj_dict_delete(obj, MP_OBJ_NEW_QSTR(attr)); + } else { + mp_obj_dict_store(obj, MP_OBJ_NEW_QSTR(attr), value); + } + } else { + mp_store_attr(obj, attr, value); + } + nlr_pop(); + external_call_depth_dec(); + return true; + } else { + // uncaught exception + external_call_depth_dec(); + return false; + } +} + +bool proxy_c_to_js_store_attr(uint32_t c_ref, const char *attr_in, uint32_t *value_in) { + return proxy_c_to_js_store_helper(c_ref, attr_in, value_in); +} + +bool proxy_c_to_js_delete_attr(uint32_t c_ref, const char *attr_in) { + return proxy_c_to_js_store_helper(c_ref, attr_in, NULL); +} + +uint32_t proxy_c_to_js_get_type(uint32_t c_ref) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + const mp_obj_type_t *type = mp_obj_get_type(obj); + if (type == &mp_type_tuple) { + return 1; + } else if (type == &mp_type_list) { + return 2; + } else if (type == &mp_type_dict) { + return 3; + } else { + return 4; + } +} + +void proxy_c_to_js_get_array(uint32_t c_ref, uint32_t *out) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + size_t len; + mp_obj_t *items; + mp_obj_get_array(obj, &len, &items); + out[0] = len; + out[1] = (uintptr_t)items; +} + +void proxy_c_to_js_get_dict(uint32_t c_ref, uint32_t *out) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + mp_map_t *map = mp_obj_dict_get_map(obj); + out[0] = map->alloc; + out[1] = (uintptr_t)map->table; +} + +EM_JS(void, js_get_error_info, (int jsref, uint32_t * out_name, uint32_t * out_message), { + const error = proxy_js_ref[jsref]; + proxy_convert_js_to_mp_obj_jsside(error.name, out_name); + proxy_convert_js_to_mp_obj_jsside(error.message, out_message); +}); + +mp_obj_t mp_obj_jsproxy_make_js_exception(mp_obj_t error) { + uint32_t out_name[PVN]; + uint32_t out_message[PVN]; + js_get_error_info(mp_obj_jsproxy_get_ref(error), out_name, out_message); + mp_obj_t args[3] = { + error, + proxy_convert_js_to_mp_obj_cside(out_name), + proxy_convert_js_to_mp_obj_cside(out_message), + }; + return mp_obj_new_exception_args(&mp_type_JsException, MP_ARRAY_SIZE(args), args); +} + +/******************************************************************************/ +// Bridge Python iterator to JavaScript iterator protocol. + +uint32_t proxy_c_to_js_get_iter(uint32_t c_ref) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + mp_obj_t iter = mp_getiter(obj, NULL); + return proxy_c_add_obj(iter); +} + +bool proxy_c_to_js_iternext(uint32_t c_ref, uint32_t *out) { + external_call_depth_inc(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + mp_obj_t iter = mp_iternext_allow_raise(obj); + if (iter == MP_OBJ_STOP_ITERATION) { + external_call_depth_dec(); + nlr_pop(); + return false; + } + nlr_pop(); + external_call_depth_dec(); + proxy_convert_mp_to_js_obj_cside(iter, out); + return true; + } else { + external_call_depth_dec(); + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + return false; + } else { + // uncaught exception + proxy_convert_mp_to_js_exc_cside(nlr.ret_val, out); + return true; + } + } +} + +/******************************************************************************/ +// Bridge Python generator to JavaScript thenable. + +static const mp_obj_fun_builtin_var_t resume_obj; + +EM_JS(void, js_then_resolve, (uint32_t * ret_value, uint32_t * resolve), { + const ret_value_js = proxy_convert_mp_to_js_obj_jsside(ret_value); + const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve); + resolve_js(ret_value_js); +}); + +EM_JS(void, js_then_reject, (uint32_t * ret_value, uint32_t * reject), { + // The ret_value object should be a Python exception. Convert it to a + // JavaScript PythonError and pass it as the reason to reject the promise. + let ret_value_js; + try { + ret_value_js = proxy_convert_mp_to_js_obj_jsside(ret_value); + } catch(error) { + ret_value_js = error; + } + const reject_js = proxy_convert_mp_to_js_obj_jsside(reject); + reject_js(ret_value_js); +}); + +// *FORMAT-OFF* +EM_JS(void, js_then_continue, (int jsref, uint32_t * py_resume, uint32_t * resolve, uint32_t * reject, uint32_t * out), { + const py_resume_js = proxy_convert_mp_to_js_obj_jsside(py_resume); + const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve); + const reject_js = proxy_convert_mp_to_js_obj_jsside(reject); + const ret = proxy_js_ref[jsref].then( + (result) => { + // The Promise is fulfilled on the JavaScript side. Take the result and + // send it to the encapsulating generator on the Python side, so it + // becomes the result of the "yield from" that deferred to this Promise. + py_resume_js(result, null, resolve_js, reject_js); + }, + (reason) => { + // The Promise is rejected on the JavaScript side. Take the reason and + // throw it into the encapsulating generator on the Python side. + py_resume_js(null, reason, resolve_js, reject_js); + }, + ); + proxy_convert_js_to_mp_obj_jsside(ret, out); +}); +// *FORMAT-ON* + +EM_JS(void, create_promise, (uint32_t * out_set, uint32_t * out_promise), { + const out_set_js = proxy_convert_mp_to_js_obj_jsside(out_set); + const promise = new Promise(out_set_js); + proxy_convert_js_to_mp_obj_jsside(promise, out_promise); +}); + +static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t resolve, mp_obj_t reject) { + if (throw_value != MP_OBJ_NULL && throw_value != mp_const_none) { + if (send_value == mp_const_none) { + send_value = MP_OBJ_NULL; + } + // Ensure that the `throw_value` is a proper Python exception instance. + if (mp_obj_is_jsproxy(throw_value)) { + throw_value = mp_obj_jsproxy_make_js_exception(throw_value); + } else { + throw_value = mp_make_raise_obj(throw_value); + } + } else { + throw_value = MP_OBJ_NULL; + if (send_value == mp_const_undefined) { + send_value = mp_const_none; + } + } + + mp_obj_t ret_value; + mp_vm_return_kind_t ret_kind = mp_resume(self_in, send_value, throw_value, &ret_value); + + if (ret_kind == MP_VM_RETURN_NORMAL) { + uint32_t out_ret_value[PVN]; + uint32_t out_resolve[PVN]; + proxy_convert_mp_to_js_obj_cside(ret_value, out_ret_value); + proxy_convert_mp_to_js_obj_cside(resolve, out_resolve); + js_then_resolve(out_ret_value, out_resolve); + return mp_const_none; + } else if (ret_kind == MP_VM_RETURN_YIELD) { + // If ret_value is None then there has been a top-level await of an asyncio primitive. + // Otherwise, ret_value should be a JS thenable. + + if (ret_value == mp_const_none) { + // Waiting on an asyncio primitive to complete, eg a Task or Event. + // + // Completion of this primitive will occur when the asyncio.core._top_level_task + // Task is made runable and its coroutine's send() method is called. Need to + // construct a Promise that resolves when that send() method is called, because + // that will resume the top-level await from the JavaScript side. + // + // This is accomplished via the asyncio.core.TopLevelCoro class and its methods. + mp_obj_t asyncio = mp_import_name(MP_QSTR_asyncio_dot_core, mp_const_none, MP_OBJ_NEW_SMALL_INT(0)); + mp_obj_t asyncio_core = mp_load_attr(asyncio, MP_QSTR_core); + mp_obj_t top_level_coro = mp_load_attr(asyncio_core, MP_QSTR_TopLevelCoro); + mp_obj_t top_level_coro_set = mp_load_attr(top_level_coro, MP_QSTR_set); + uint32_t out_set[PVN]; + proxy_convert_mp_to_js_obj_cside(top_level_coro_set, out_set); + uint32_t out_promise[PVN]; + create_promise(out_set, out_promise); + ret_value = proxy_convert_js_to_mp_obj_cside(out_promise); + } + + mp_obj_t py_resume = mp_obj_new_bound_meth(MP_OBJ_FROM_PTR(&resume_obj), self_in); + int ref = mp_obj_jsproxy_get_ref(ret_value); + uint32_t out_py_resume[PVN]; + uint32_t out_resolve[PVN]; + uint32_t out_reject[PVN]; + proxy_convert_mp_to_js_obj_cside(py_resume, out_py_resume); + proxy_convert_mp_to_js_obj_cside(resolve, out_resolve); + proxy_convert_mp_to_js_obj_cside(reject, out_reject); + uint32_t out[PVN]; + js_then_continue(ref, out_py_resume, out_resolve, out_reject, out); + return proxy_convert_js_to_mp_obj_cside(out); + } else { // ret_kind == MP_VM_RETURN_EXCEPTION; + // Pass the exception through as an object to reject the promise (don't raise/throw it). + uint32_t out_ret_value[PVN]; + uint32_t out_reject[PVN]; + proxy_convert_mp_to_js_exc_cside(ret_value, out_ret_value); + proxy_convert_mp_to_js_obj_cside(reject, out_reject); + js_then_reject(out_ret_value, out_reject); + return mp_const_none; + } +} + +static mp_obj_t resume_fun(size_t n_args, const mp_obj_t *args) { + return proxy_resume_execute(args[0], args[1], args[2], args[3], args[4]); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(resume_obj, 5, 5, resume_fun); + +void proxy_c_to_js_resume(uint32_t c_ref, uint32_t *args) { + external_call_depth_inc(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t obj = proxy_c_get_obj(c_ref); + mp_obj_t resolve = proxy_convert_js_to_mp_obj_cside(args + 1 * 3); + mp_obj_t reject = proxy_convert_js_to_mp_obj_cside(args + 2 * 3); + mp_obj_t ret = proxy_resume_execute(obj, mp_const_none, mp_const_none, resolve, reject); + nlr_pop(); + external_call_depth_dec(); + proxy_convert_mp_to_js_obj_cside(ret, args); + } else { + // uncaught exception + external_call_depth_dec(); + proxy_convert_mp_to_js_exc_cside(nlr.ret_val, args); + } +} diff --git a/tulip/web/proxy_c.h b/tulip/web/proxy_c.h new file mode 100644 index 00000000..d3567c19 --- /dev/null +++ b/tulip/web/proxy_c.h @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_WEBASSEMBLY_PROXY_C_H +#define MICROPY_INCLUDED_WEBASSEMBLY_PROXY_C_H + +#include "py/obj.h" + +// proxy value number of items +#define PVN (3) + +typedef struct _mp_obj_jsproxy_t { + mp_obj_base_t base; + int ref; +} mp_obj_jsproxy_t; + +extern const mp_obj_type_t mp_type_jsproxy; +extern const mp_obj_type_t mp_type_JsException; + +void external_call_depth_inc(void); +void external_call_depth_dec(void); + +void proxy_c_init(void); +mp_obj_t proxy_convert_js_to_mp_obj_cside(uint32_t *value); +void proxy_convert_mp_to_js_obj_cside(mp_obj_t obj, uint32_t *out); +void proxy_convert_mp_to_js_exc_cside(void *exc, uint32_t *out); + +mp_obj_t mp_obj_new_jsproxy(int ref); +void mp_obj_jsproxy_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); + +static inline bool mp_obj_is_jsproxy(mp_obj_t o) { + return mp_obj_get_type(o) == &mp_type_jsproxy; +} + +static inline int mp_obj_jsproxy_get_ref(mp_obj_t o) { + mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(o); + return self->ref; +} + +#endif // MICROPY_INCLUDED_WEBASSEMBLY_PROXY_C_H diff --git a/tulip/web/proxy_js.js b/tulip/web/proxy_js.js new file mode 100644 index 00000000..f4d1377a --- /dev/null +++ b/tulip/web/proxy_js.js @@ -0,0 +1,314 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Number of static entries at the start of proxy_js_ref. +const PROXY_JS_REF_NUM_STATIC = 2; + +// These constants should match the constants in proxy_c.c. + +const PROXY_KIND_MP_EXCEPTION = -1; +const PROXY_KIND_MP_NULL = 0; +const PROXY_KIND_MP_NONE = 1; +const PROXY_KIND_MP_BOOL = 2; +const PROXY_KIND_MP_INT = 3; +const PROXY_KIND_MP_FLOAT = 4; +const PROXY_KIND_MP_STR = 5; +const PROXY_KIND_MP_CALLABLE = 6; +const PROXY_KIND_MP_GENERATOR = 7; +const PROXY_KIND_MP_OBJECT = 8; +const PROXY_KIND_MP_JSPROXY = 9; +const PROXY_KIND_MP_EXISTING = 10; + +const PROXY_KIND_JS_UNDEFINED = 0; +const PROXY_KIND_JS_NULL = 1; +const PROXY_KIND_JS_BOOLEAN = 2; +const PROXY_KIND_JS_INTEGER = 3; +const PROXY_KIND_JS_DOUBLE = 4; +const PROXY_KIND_JS_STRING = 5; +const PROXY_KIND_JS_OBJECT = 6; +const PROXY_KIND_JS_PYPROXY = 7; + +class PythonError extends Error { + constructor(exc_type, exc_details) { + super(exc_details); + this.name = "PythonError"; + this.type = exc_type; + } +} + +function proxy_js_init() { + globalThis.proxy_js_ref = [globalThis, undefined]; + globalThis.proxy_js_ref_next = PROXY_JS_REF_NUM_STATIC; + globalThis.proxy_js_map = new Map(); + globalThis.proxy_js_existing = [undefined]; + globalThis.pyProxyFinalizationRegistry = new FinalizationRegistry( + (cRef) => { + globalThis.proxy_js_map.delete(cRef); + Module.ccall("proxy_c_free_obj", "null", ["number"], [cRef]); + }, + ); +} + +// Check if the c_ref (Python proxy index) has a corresponding JavaScript-side PyProxy +// associated with it. If so, take a concrete reference to this PyProxy from the WeakRef +// and put it in proxy_js_existing, to be referenced and reused by PROXY_KIND_MP_EXISTING. +function proxy_js_check_existing(c_ref) { + const existing_obj = globalThis.proxy_js_map.get(c_ref)?.deref(); + if (existing_obj === undefined) { + return -1; + } + + // Search for a free slot in proxy_js_existing. + for (let i = 0; i < globalThis.proxy_js_existing.length; ++i) { + if (globalThis.proxy_js_existing[i] === undefined) { + // Free slot found, put existing_obj here and return the index. + globalThis.proxy_js_existing[i] = existing_obj; + return i; + } + } + + // No free slot, so append to proxy_js_existing and return the new index. + globalThis.proxy_js_existing.push(existing_obj); + return globalThis.proxy_js_existing.length - 1; +} + +// js_obj cannot be undefined +function proxy_js_add_obj(js_obj) { + // Search for the first free slot in proxy_js_ref. + while (proxy_js_ref_next < proxy_js_ref.length) { + if (proxy_js_ref[proxy_js_ref_next] === undefined) { + // Free slot found, reuse it. + const id = proxy_js_ref_next; + ++proxy_js_ref_next; + proxy_js_ref[id] = js_obj; + return id; + } + ++proxy_js_ref_next; + } + + // No free slots, so grow proxy_js_ref by one (append at the end of the array). + const id = proxy_js_ref.length; + proxy_js_ref[id] = js_obj; + proxy_js_ref_next = proxy_js_ref.length; + return id; +} + +function proxy_call_python(target, argumentsList) { + let args = 0; + + // Strip trailing "undefined" arguments. + while ( + argumentsList.length > 0 && + argumentsList[argumentsList.length - 1] === undefined + ) { + argumentsList.pop(); + } + + if (argumentsList.length > 0) { + // TODO use stackAlloc/stackRestore? + args = Module._malloc(argumentsList.length * 3 * 4); + for (const i in argumentsList) { + proxy_convert_js_to_mp_obj_jsside( + argumentsList[i], + args + i * 3 * 4, + ); + } + } + const value = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_call", + "null", + ["number", "number", "number", "pointer"], + [target, argumentsList.length, args, value], + {async:true}, + ); + if (argumentsList.length > 0) { + Module._free(args); + } + const ret = proxy_convert_mp_to_js_obj_jsside_with_free(value); + if (ret instanceof PyProxyThenable) { + // In Python when an async function is called it creates the + // corresponding "generator", which must then be executed at + // the top level by an asyncio-like scheduler. In JavaScript + // the semantics for async functions is that they are started + // immediately (their non-async prefix code is executed immediately) + // and only if they await do they return a Promise to delay the + // execution of the remainder of the function. + // + // Emulate the JavaScript behaviour here by resolving the Python + // async function. We assume that the caller who gets this + // return is JavaScript. + return Promise.resolve(ret); + } + return ret; +} + +function proxy_convert_js_to_mp_obj_jsside(js_obj, out) { + let kind; + if (js_obj === undefined) { + kind = PROXY_KIND_JS_UNDEFINED; + } else if (js_obj === null) { + kind = PROXY_KIND_JS_NULL; + } else if (typeof js_obj === "boolean") { + kind = PROXY_KIND_JS_BOOLEAN; + Module.setValue(out + 4, js_obj, "i32"); + } else if (typeof js_obj === "number") { + if (Number.isInteger(js_obj)) { + kind = PROXY_KIND_JS_INTEGER; + Module.setValue(out + 4, js_obj, "i32"); + } else { + kind = PROXY_KIND_JS_DOUBLE; + // double must be stored to an address that's a multiple of 8 + const temp = (out + 4) & ~7; + Module.setValue(temp, js_obj, "double"); + const double_lo = Module.getValue(temp, "i32"); + const double_hi = Module.getValue(temp + 4, "i32"); + Module.setValue(out + 4, double_lo, "i32"); + Module.setValue(out + 8, double_hi, "i32"); + } + } else if (typeof js_obj === "string") { + kind = PROXY_KIND_JS_STRING; + const len = Module.lengthBytesUTF8(js_obj); + const buf = Module._malloc(len + 1); + Module.stringToUTF8(js_obj, buf, len + 1); + Module.setValue(out + 4, len, "i32"); + Module.setValue(out + 8, buf, "i32"); + } else if ( + js_obj instanceof PyProxy || + (typeof js_obj === "function" && "_ref" in js_obj) || + js_obj instanceof PyProxyThenable + ) { + kind = PROXY_KIND_JS_PYPROXY; + Module.setValue(out + 4, js_obj._ref, "i32"); + } else { + kind = PROXY_KIND_JS_OBJECT; + const id = proxy_js_add_obj(js_obj); + Module.setValue(out + 4, id, "i32"); + } + Module.setValue(out + 0, kind, "i32"); +} + +function proxy_convert_js_to_mp_obj_jsside_force_double_proxy(js_obj, out) { + if ( + js_obj instanceof PyProxy || + (typeof js_obj === "function" && "_ref" in js_obj) || + js_obj instanceof PyProxyThenable + ) { + const kind = PROXY_KIND_JS_OBJECT; + const id = proxy_js_add_obj(js_obj); + Module.setValue(out + 4, id, "i32"); + Module.setValue(out + 0, kind, "i32"); + } else { + proxy_convert_js_to_mp_obj_jsside(js_obj, out); + } +} + +function proxy_convert_mp_to_js_obj_jsside(value) { + const kind = Module.getValue(value, "i32"); + let obj; + if (kind === PROXY_KIND_MP_EXCEPTION) { + // Exception + const str_len = Module.getValue(value + 4, "i32"); + const str_ptr = Module.getValue(value + 8, "i32"); + const str = Module.UTF8ToString(str_ptr, str_len); + Module._free(str_ptr); + const str_split = str.split("\x04"); + throw new PythonError(str_split[0], str_split[1]); + } + if (kind === PROXY_KIND_MP_NULL) { + // MP_OBJ_NULL + throw new Error("NULL object"); + } + if (kind === PROXY_KIND_MP_NONE) { + // None + obj = null; + } else if (kind === PROXY_KIND_MP_BOOL) { + // bool + obj = Module.getValue(value + 4, "i32") ? true : false; + } else if (kind === PROXY_KIND_MP_INT) { + // int + obj = Module.getValue(value + 4, "i32"); + } else if (kind === PROXY_KIND_MP_FLOAT) { + // float + // double must be loaded from an address that's a multiple of 8 + const temp = (value + 4) & ~7; + const double_lo = Module.getValue(value + 4, "i32"); + const double_hi = Module.getValue(value + 8, "i32"); + Module.setValue(temp, double_lo, "i32"); + Module.setValue(temp + 4, double_hi, "i32"); + obj = Module.getValue(temp, "double"); + } else if (kind === PROXY_KIND_MP_STR) { + // str + const str_len = Module.getValue(value + 4, "i32"); + const str_ptr = Module.getValue(value + 8, "i32"); + obj = Module.UTF8ToString(str_ptr, str_len); + } else if (kind === PROXY_KIND_MP_JSPROXY) { + // js proxy + const id = Module.getValue(value + 4, "i32"); + obj = proxy_js_ref[id]; + } else if (kind === PROXY_KIND_MP_EXISTING) { + const id = Module.getValue(value + 4, "i32"); + obj = globalThis.proxy_js_existing[id]; + globalThis.proxy_js_existing[id] = undefined; + } else { + // obj + const id = Module.getValue(value + 4, "i32"); + if (kind === PROXY_KIND_MP_CALLABLE) { + obj = (...args) => { + return proxy_call_python(id, args); + }; + obj._ref = id; + } else if (kind === PROXY_KIND_MP_GENERATOR) { + obj = new PyProxyThenable(id); + } else { + // PROXY_KIND_MP_OBJECT + const target = new PyProxy(id); + obj = new Proxy(target, py_proxy_handler); + } + globalThis.pyProxyFinalizationRegistry.register(obj, id); + globalThis.proxy_js_map.set(id, new WeakRef(obj)); + } + return obj; +} + +function proxy_convert_mp_to_js_obj_jsside_with_free(value) { + const ret = proxy_convert_mp_to_js_obj_jsside(value); + Module._free(value); + return ret; +} + +function python_index_semantics(target, index_in) { + let index = index_in; + if (typeof index === "number") { + if (index < 0) { + index += target.length; + } + if (index < 0 || index >= target.length) { + throw new PythonError("IndexError", "index out of range"); + } + } + return index; +} diff --git a/tulip/web/qstrdefsport.h b/tulip/web/qstrdefsport.h new file mode 100644 index 00000000..421344bd --- /dev/null +++ b/tulip/web/qstrdefsport.h @@ -0,0 +1,4 @@ +// qstrs specific to this port +// *FORMAT-OFF* +Q(/lib) +Q(asyncio.core) diff --git a/tulip/web/server.py b/tulip/web/server.py new file mode 100644 index 00000000..16aa04b7 --- /dev/null +++ b/tulip/web/server.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +# Attribution: https://stackoverflow.com/questions/21956683/enable-access-control-on-simple-http-server + +try: + # Python 3 + from http.server import HTTPServer, SimpleHTTPRequestHandler, test as test_orig + import sys + def test (*args): + test_orig(*args, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000) +except ImportError: # Python 2 + from BaseHTTPServer import HTTPServer, test + from SimpleHTTPServer import SimpleHTTPRequestHandler + +class CORSRequestHandler (SimpleHTTPRequestHandler): + def end_headers (self): + self.send_header('Access-Control-Allow-Origin', '*') + self.send_header('Cross-Origin-Embedder-Policy', 'require-corp') + self.send_header('Cross-Origin-Opener-Policy', 'same-origin') + SimpleHTTPRequestHandler.end_headers(self) + +if __name__ == '__main__': + import os + os.chdir("../../www/run") + test(CORSRequestHandler, HTTPServer) + + diff --git a/tulip/web/variants/manifest.py b/tulip/web/variants/manifest.py new file mode 100644 index 00000000..cc84dd1e --- /dev/null +++ b/tulip/web/variants/manifest.py @@ -0,0 +1,29 @@ +# The asyncio package is built from the standard implementation but with the +# core scheduler replaced with a custom scheduler that uses the JavaScript +# runtime (with setTimeout an Promise's) to contrtol the scheduling. + +freeze("../../shared/py") +freeze("../../../amy", "amy.py") +freeze("../../../amy", "juno.py") + + +package( + "asyncio", + ( + "event.py", + "funcs.py", + "lock.py", + ), + base_path="$(MPY_DIR)/extmod", + opt=3, +) + +package( + "asyncio", + ( + "__init__.py", + "core.py", + ), + base_path="$(PORT_DIR)", + opt=3, +) diff --git a/tulip/web/variants/pyscript/manifest.py b/tulip/web/variants/pyscript/manifest.py new file mode 100644 index 00000000..db088e70 --- /dev/null +++ b/tulip/web/variants/pyscript/manifest.py @@ -0,0 +1,29 @@ +include("$(PORT_DIR)/variants/manifest.py") + +require("abc") +require("base64") +require("collections") +require("collections-defaultdict") +require("copy") +require("datetime") +require("fnmatch") +require("functools") +require("gzip") +require("hmac") +require("html") +require("inspect") +require("io") +require("itertools") +require("locale") +require("logging") +require("operator") +require("os") +require("os-path") +require("pathlib") +require("stat") +require("tarfile") +require("tarfile-write") +require("time") +require("unittest") +require("uu") +require("zlib") diff --git a/tulip/web/variants/pyscript/mpconfigvariant.h b/tulip/web/variants/pyscript/mpconfigvariant.h new file mode 100644 index 00000000..ed8e8128 --- /dev/null +++ b/tulip/web/variants/pyscript/mpconfigvariant.h @@ -0,0 +1,3 @@ +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES) +#define MICROPY_GC_SPLIT_HEAP (1) +#define MICROPY_GC_SPLIT_HEAP_AUTO (1) diff --git a/tulip/web/variants/pyscript/mpconfigvariant.mk b/tulip/web/variants/pyscript/mpconfigvariant.mk new file mode 100644 index 00000000..016b96a9 --- /dev/null +++ b/tulip/web/variants/pyscript/mpconfigvariant.mk @@ -0,0 +1,3 @@ +JSFLAGS += -s ALLOW_MEMORY_GROWTH + +FROZEN_MANIFEST ?= variants/pyscript/manifest.py diff --git a/tulip/web/variants/standard/mpconfigvariant.h b/tulip/web/variants/standard/mpconfigvariant.h new file mode 100644 index 00000000..7be62ea7 --- /dev/null +++ b/tulip/web/variants/standard/mpconfigvariant.h @@ -0,0 +1 @@ +#define MICROPY_VARIANT_ENABLE_JS_HOOK (1) diff --git a/tulip/web/variants/standard/mpconfigvariant.mk b/tulip/web/variants/standard/mpconfigvariant.mk new file mode 100644 index 00000000..62ee1619 --- /dev/null +++ b/tulip/web/variants/standard/mpconfigvariant.mk @@ -0,0 +1 @@ +JSFLAGS += -s ASYNCIFY diff --git a/tulip/web/yacctab.py b/tulip/web/yacctab.py new file mode 100644 index 00000000..68b14660 --- /dev/null +++ b/tulip/web/yacctab.py @@ -0,0 +1,369 @@ + +# yacctab.py +# This file is automatically generated. Do not edit. +_tabversion = '3.10' + +_lr_method = 'LALR' + +_lr_signature = 'translation_unit_or_emptyleftLORleftLANDleftORleftXORleftANDleftEQNEleftGTGELTLEleftRSHIFTLSHIFTleftPLUSMINUSleftTIMESDIVIDEMODAUTO BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER OFFSETOF RESTRICT RETURN SHORT SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE WHILE __INT128 _BOOL _COMPLEX _NORETURN _THREAD_LOCAL _STATIC_ASSERT _ATOMIC _ALIGNOF _ALIGNAS _PRAGMA ID TYPEID INT_CONST_DEC INT_CONST_OCT INT_CONST_HEX INT_CONST_BIN INT_CONST_CHAR FLOAT_CONST HEX_FLOAT_CONST CHAR_CONST WCHAR_CONST U8CHAR_CONST U16CHAR_CONST U32CHAR_CONST STRING_LITERAL WSTRING_LITERAL U8STRING_LITERAL U16STRING_LITERAL U32STRING_LITERAL PLUS MINUS TIMES DIVIDE MOD OR AND NOT XOR LSHIFT RSHIFT LOR LAND LNOT LT LE GT GE EQ NE EQUALS TIMESEQUAL DIVEQUAL MODEQUAL PLUSEQUAL MINUSEQUAL LSHIFTEQUAL RSHIFTEQUAL ANDEQUAL XOREQUAL OREQUAL PLUSPLUS MINUSMINUS ARROW CONDOP LPAREN RPAREN LBRACKET RBRACKET LBRACE RBRACE COMMA PERIOD SEMI COLON ELLIPSIS PPHASH PPPRAGMA PPPRAGMASTRabstract_declarator_opt : empty\n| abstract_declaratorassignment_expression_opt : empty\n| assignment_expressionblock_item_list_opt : empty\n| block_item_listdeclaration_list_opt : empty\n| declaration_listdeclaration_specifiers_no_type_opt : empty\n| declaration_specifiers_no_typedesignation_opt : empty\n| designationexpression_opt : empty\n| expressionid_init_declarator_list_opt : empty\n| id_init_declarator_listidentifier_list_opt : empty\n| identifier_listinit_declarator_list_opt : empty\n| init_declarator_listinitializer_list_opt : empty\n| initializer_listparameter_type_list_opt : empty\n| parameter_type_liststruct_declarator_list_opt : empty\n| struct_declarator_listtype_qualifier_list_opt : empty\n| type_qualifier_list direct_id_declarator : ID\n direct_id_declarator : LPAREN id_declarator RPAREN\n direct_id_declarator : direct_id_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET\n direct_id_declarator : direct_id_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET\n | direct_id_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET\n direct_id_declarator : direct_id_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET\n direct_id_declarator : direct_id_declarator LPAREN parameter_type_list RPAREN\n | direct_id_declarator LPAREN identifier_list_opt RPAREN\n direct_typeid_declarator : TYPEID\n direct_typeid_declarator : LPAREN typeid_declarator RPAREN\n direct_typeid_declarator : direct_typeid_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET\n direct_typeid_declarator : direct_typeid_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET\n | direct_typeid_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET\n direct_typeid_declarator : direct_typeid_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET\n direct_typeid_declarator : direct_typeid_declarator LPAREN parameter_type_list RPAREN\n | direct_typeid_declarator LPAREN identifier_list_opt RPAREN\n direct_typeid_noparen_declarator : TYPEID\n direct_typeid_noparen_declarator : direct_typeid_noparen_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET\n direct_typeid_noparen_declarator : direct_typeid_noparen_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET\n | direct_typeid_noparen_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET\n direct_typeid_noparen_declarator : direct_typeid_noparen_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET\n direct_typeid_noparen_declarator : direct_typeid_noparen_declarator LPAREN parameter_type_list RPAREN\n | direct_typeid_noparen_declarator LPAREN identifier_list_opt RPAREN\n id_declarator : direct_id_declarator\n id_declarator : pointer direct_id_declarator\n typeid_declarator : direct_typeid_declarator\n typeid_declarator : pointer direct_typeid_declarator\n typeid_noparen_declarator : direct_typeid_noparen_declarator\n typeid_noparen_declarator : pointer direct_typeid_noparen_declarator\n translation_unit_or_empty : translation_unit\n | empty\n translation_unit : external_declaration\n translation_unit : translation_unit external_declaration\n external_declaration : function_definition\n external_declaration : declaration\n external_declaration : pp_directive\n | pppragma_directive\n external_declaration : SEMI\n external_declaration : static_assert\n static_assert : _STATIC_ASSERT LPAREN constant_expression COMMA unified_string_literal RPAREN\n | _STATIC_ASSERT LPAREN constant_expression RPAREN\n pp_directive : PPHASH\n pppragma_directive : PPPRAGMA\n | PPPRAGMA PPPRAGMASTR\n | _PRAGMA LPAREN unified_string_literal RPAREN\n pppragma_directive_list : pppragma_directive\n | pppragma_directive_list pppragma_directive\n function_definition : id_declarator declaration_list_opt compound_statement\n function_definition : declaration_specifiers id_declarator declaration_list_opt compound_statement\n statement : labeled_statement\n | expression_statement\n | compound_statement\n | selection_statement\n | iteration_statement\n | jump_statement\n | pppragma_directive\n | static_assert\n pragmacomp_or_statement : pppragma_directive_list statement\n | statement\n decl_body : declaration_specifiers init_declarator_list_opt\n | declaration_specifiers_no_type id_init_declarator_list_opt\n declaration : decl_body SEMI\n declaration_list : declaration\n | declaration_list declaration\n declaration_specifiers_no_type : type_qualifier declaration_specifiers_no_type_opt\n declaration_specifiers_no_type : storage_class_specifier declaration_specifiers_no_type_opt\n declaration_specifiers_no_type : function_specifier declaration_specifiers_no_type_opt\n declaration_specifiers_no_type : atomic_specifier declaration_specifiers_no_type_opt\n declaration_specifiers_no_type : alignment_specifier declaration_specifiers_no_type_opt\n declaration_specifiers : declaration_specifiers type_qualifier\n declaration_specifiers : declaration_specifiers storage_class_specifier\n declaration_specifiers : declaration_specifiers function_specifier\n declaration_specifiers : declaration_specifiers type_specifier_no_typeid\n declaration_specifiers : type_specifier\n declaration_specifiers : declaration_specifiers_no_type type_specifier\n declaration_specifiers : declaration_specifiers alignment_specifier\n storage_class_specifier : AUTO\n | REGISTER\n | STATIC\n | EXTERN\n | TYPEDEF\n | _THREAD_LOCAL\n function_specifier : INLINE\n | _NORETURN\n type_specifier_no_typeid : VOID\n | _BOOL\n | CHAR\n | SHORT\n | INT\n | LONG\n | FLOAT\n | DOUBLE\n | _COMPLEX\n | SIGNED\n | UNSIGNED\n | __INT128\n type_specifier : typedef_name\n | enum_specifier\n | struct_or_union_specifier\n | type_specifier_no_typeid\n | atomic_specifier\n atomic_specifier : _ATOMIC LPAREN type_name RPAREN\n type_qualifier : CONST\n | RESTRICT\n | VOLATILE\n | _ATOMIC\n init_declarator_list : init_declarator\n | init_declarator_list COMMA init_declarator\n init_declarator : declarator\n | declarator EQUALS initializer\n id_init_declarator_list : id_init_declarator\n | id_init_declarator_list COMMA init_declarator\n id_init_declarator : id_declarator\n | id_declarator EQUALS initializer\n specifier_qualifier_list : specifier_qualifier_list type_specifier_no_typeid\n specifier_qualifier_list : specifier_qualifier_list type_qualifier\n specifier_qualifier_list : type_specifier\n specifier_qualifier_list : type_qualifier_list type_specifier\n specifier_qualifier_list : alignment_specifier\n specifier_qualifier_list : specifier_qualifier_list alignment_specifier\n struct_or_union_specifier : struct_or_union ID\n | struct_or_union TYPEID\n struct_or_union_specifier : struct_or_union brace_open struct_declaration_list brace_close\n | struct_or_union brace_open brace_close\n struct_or_union_specifier : struct_or_union ID brace_open struct_declaration_list brace_close\n | struct_or_union ID brace_open brace_close\n | struct_or_union TYPEID brace_open struct_declaration_list brace_close\n | struct_or_union TYPEID brace_open brace_close\n struct_or_union : STRUCT\n | UNION\n struct_declaration_list : struct_declaration\n | struct_declaration_list struct_declaration\n struct_declaration : specifier_qualifier_list struct_declarator_list_opt SEMI\n struct_declaration : SEMI\n struct_declaration : pppragma_directive\n struct_declarator_list : struct_declarator\n | struct_declarator_list COMMA struct_declarator\n struct_declarator : declarator\n struct_declarator : declarator COLON constant_expression\n | COLON constant_expression\n enum_specifier : ENUM ID\n | ENUM TYPEID\n enum_specifier : ENUM brace_open enumerator_list brace_close\n enum_specifier : ENUM ID brace_open enumerator_list brace_close\n | ENUM TYPEID brace_open enumerator_list brace_close\n enumerator_list : enumerator\n | enumerator_list COMMA\n | enumerator_list COMMA enumerator\n alignment_specifier : _ALIGNAS LPAREN type_name RPAREN\n | _ALIGNAS LPAREN constant_expression RPAREN\n enumerator : ID\n | ID EQUALS constant_expression\n declarator : id_declarator\n | typeid_declarator\n pointer : TIMES type_qualifier_list_opt\n | TIMES type_qualifier_list_opt pointer\n type_qualifier_list : type_qualifier\n | type_qualifier_list type_qualifier\n parameter_type_list : parameter_list\n | parameter_list COMMA ELLIPSIS\n parameter_list : parameter_declaration\n | parameter_list COMMA parameter_declaration\n parameter_declaration : declaration_specifiers id_declarator\n | declaration_specifiers typeid_noparen_declarator\n parameter_declaration : declaration_specifiers abstract_declarator_opt\n identifier_list : identifier\n | identifier_list COMMA identifier\n initializer : assignment_expression\n initializer : brace_open initializer_list_opt brace_close\n | brace_open initializer_list COMMA brace_close\n initializer_list : designation_opt initializer\n | initializer_list COMMA designation_opt initializer\n designation : designator_list EQUALS\n designator_list : designator\n | designator_list designator\n designator : LBRACKET constant_expression RBRACKET\n | PERIOD identifier\n type_name : specifier_qualifier_list abstract_declarator_opt\n abstract_declarator : pointer\n abstract_declarator : pointer direct_abstract_declarator\n abstract_declarator : direct_abstract_declarator\n direct_abstract_declarator : LPAREN abstract_declarator RPAREN direct_abstract_declarator : direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET\n direct_abstract_declarator : LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET\n direct_abstract_declarator : direct_abstract_declarator LBRACKET TIMES RBRACKET\n direct_abstract_declarator : LBRACKET TIMES RBRACKET\n direct_abstract_declarator : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN\n direct_abstract_declarator : LPAREN parameter_type_list_opt RPAREN\n block_item : declaration\n | statement\n block_item_list : block_item\n | block_item_list block_item\n compound_statement : brace_open block_item_list_opt brace_close labeled_statement : ID COLON pragmacomp_or_statement labeled_statement : CASE constant_expression COLON pragmacomp_or_statement labeled_statement : DEFAULT COLON pragmacomp_or_statement selection_statement : IF LPAREN expression RPAREN pragmacomp_or_statement selection_statement : IF LPAREN expression RPAREN statement ELSE pragmacomp_or_statement selection_statement : SWITCH LPAREN expression RPAREN pragmacomp_or_statement iteration_statement : WHILE LPAREN expression RPAREN pragmacomp_or_statement iteration_statement : DO pragmacomp_or_statement WHILE LPAREN expression RPAREN SEMI iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement iteration_statement : FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement jump_statement : GOTO ID SEMI jump_statement : BREAK SEMI jump_statement : CONTINUE SEMI jump_statement : RETURN expression SEMI\n | RETURN SEMI\n expression_statement : expression_opt SEMI expression : assignment_expression\n | expression COMMA assignment_expression\n assignment_expression : LPAREN compound_statement RPAREN typedef_name : TYPEID assignment_expression : conditional_expression\n | unary_expression assignment_operator assignment_expression\n assignment_operator : EQUALS\n | XOREQUAL\n | TIMESEQUAL\n | DIVEQUAL\n | MODEQUAL\n | PLUSEQUAL\n | MINUSEQUAL\n | LSHIFTEQUAL\n | RSHIFTEQUAL\n | ANDEQUAL\n | OREQUAL\n constant_expression : conditional_expression conditional_expression : binary_expression\n | binary_expression CONDOP expression COLON conditional_expression\n binary_expression : cast_expression\n | binary_expression TIMES binary_expression\n | binary_expression DIVIDE binary_expression\n | binary_expression MOD binary_expression\n | binary_expression PLUS binary_expression\n | binary_expression MINUS binary_expression\n | binary_expression RSHIFT binary_expression\n | binary_expression LSHIFT binary_expression\n | binary_expression LT binary_expression\n | binary_expression LE binary_expression\n | binary_expression GE binary_expression\n | binary_expression GT binary_expression\n | binary_expression EQ binary_expression\n | binary_expression NE binary_expression\n | binary_expression AND binary_expression\n | binary_expression OR binary_expression\n | binary_expression XOR binary_expression\n | binary_expression LAND binary_expression\n | binary_expression LOR binary_expression\n cast_expression : unary_expression cast_expression : LPAREN type_name RPAREN cast_expression unary_expression : postfix_expression unary_expression : PLUSPLUS unary_expression\n | MINUSMINUS unary_expression\n | unary_operator cast_expression\n unary_expression : SIZEOF unary_expression\n | SIZEOF LPAREN type_name RPAREN\n | _ALIGNOF LPAREN type_name RPAREN\n unary_operator : AND\n | TIMES\n | PLUS\n | MINUS\n | NOT\n | LNOT\n postfix_expression : primary_expression postfix_expression : postfix_expression LBRACKET expression RBRACKET postfix_expression : postfix_expression LPAREN argument_expression_list RPAREN\n | postfix_expression LPAREN RPAREN\n postfix_expression : postfix_expression PERIOD ID\n | postfix_expression PERIOD TYPEID\n | postfix_expression ARROW ID\n | postfix_expression ARROW TYPEID\n postfix_expression : postfix_expression PLUSPLUS\n | postfix_expression MINUSMINUS\n postfix_expression : LPAREN type_name RPAREN brace_open initializer_list brace_close\n | LPAREN type_name RPAREN brace_open initializer_list COMMA brace_close\n primary_expression : identifier primary_expression : constant primary_expression : unified_string_literal\n | unified_wstring_literal\n primary_expression : LPAREN expression RPAREN primary_expression : OFFSETOF LPAREN type_name COMMA offsetof_member_designator RPAREN\n offsetof_member_designator : identifier\n | offsetof_member_designator PERIOD identifier\n | offsetof_member_designator LBRACKET expression RBRACKET\n argument_expression_list : assignment_expression\n | argument_expression_list COMMA assignment_expression\n identifier : ID constant : INT_CONST_DEC\n | INT_CONST_OCT\n | INT_CONST_HEX\n | INT_CONST_BIN\n | INT_CONST_CHAR\n constant : FLOAT_CONST\n | HEX_FLOAT_CONST\n constant : CHAR_CONST\n | WCHAR_CONST\n | U8CHAR_CONST\n | U16CHAR_CONST\n | U32CHAR_CONST\n unified_string_literal : STRING_LITERAL\n | unified_string_literal STRING_LITERAL\n unified_wstring_literal : WSTRING_LITERAL\n | U8STRING_LITERAL\n | U16STRING_LITERAL\n | U32STRING_LITERAL\n | unified_wstring_literal WSTRING_LITERAL\n | unified_wstring_literal U8STRING_LITERAL\n | unified_wstring_literal U16STRING_LITERAL\n | unified_wstring_literal U32STRING_LITERAL\n brace_open : LBRACE\n brace_close : RBRACE\n empty : ' + +_lr_action_items = {'$end':([0,1,2,3,4,5,6,7,8,9,10,14,15,64,90,91,127,208,251,262,267,355,499,],[-340,0,-58,-59,-60,-62,-63,-64,-65,-66,-67,-70,-71,-61,-90,-72,-76,-339,-77,-73,-69,-221,-68,]),'SEMI':([0,2,4,5,6,7,8,9,10,12,13,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,69,70,71,72,73,74,75,76,77,78,79,81,83,84,85,86,87,88,89,90,91,97,98,99,100,101,102,103,104,105,106,107,108,110,111,112,117,118,119,121,122,123,124,127,128,130,132,139,140,143,144,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,203,204,205,206,207,208,209,210,211,212,214,220,221,222,223,224,225,226,227,228,229,230,231,232,233,236,239,242,245,246,247,248,249,250,251,252,253,254,255,262,263,267,291,292,293,295,296,297,300,301,302,303,311,312,326,327,330,333,334,335,336,337,338,339,340,341,342,343,344,345,346,348,349,353,354,355,356,357,358,360,361,369,370,371,372,373,374,375,376,377,403,404,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,439,440,459,460,463,464,465,468,469,470,471,473,475,479,480,481,482,483,484,485,486,493,494,497,499,501,502,505,506,508,509,522,523,524,525,526,527,529,530,531,535,536,538,552,553,554,555,556,558,561,563,570,571,574,579,580,582,584,585,586,],[9,9,-60,-62,-63,-64,-65,-66,-67,-340,90,-70,-71,-52,-340,-340,-340,-128,-102,-340,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,-340,-340,-129,-134,-181,-98,-99,-100,-101,-104,-88,-134,-19,-20,-135,-137,-182,-54,-37,-90,-72,-53,-93,-9,-10,-340,-94,-95,-103,-89,-129,-15,-16,-139,-141,-97,-96,-169,-170,-338,-149,-150,210,-76,-340,-181,-55,-328,-30,-306,-255,-256,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,210,210,210,-152,-159,-339,-340,-162,-163,-145,-147,-13,-340,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-315,361,-14,-340,374,375,377,-238,-242,-277,-77,-38,-136,-138,-196,-73,-329,-69,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-35,-36,-140,-142,-171,210,-154,210,-156,-151,-160,465,-143,-144,-148,-25,-26,-164,-166,-146,-130,-177,-178,-221,-220,-13,-340,-340,-237,-340,-87,-74,-340,483,-233,-234,484,-236,-43,-44,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,-276,-295,-296,-297,-298,-299,-31,-34,-172,-173,-153,-155,-161,-168,-222,-340,-224,-240,-239,-86,-75,529,-340,-232,-235,-243,-197,-39,-42,-278,-68,-293,-294,-284,-285,-32,-33,-165,-167,-223,-340,-340,-340,-340,559,-198,-40,-41,-257,-225,-87,-74,-227,-228,572,-302,-309,-340,580,-303,-226,-229,-340,-340,-231,-230,]),'PPHASH':([0,2,4,5,6,7,8,9,10,14,15,64,90,91,127,208,251,262,267,355,499,],[14,14,-60,-62,-63,-64,-65,-66,-67,-70,-71,-61,-90,-72,-76,-339,-77,-73,-69,-221,-68,]),'PPPRAGMA':([0,2,4,5,6,7,8,9,10,14,15,64,90,91,121,124,127,128,203,204,205,207,208,210,211,221,222,223,224,225,226,227,228,229,230,231,232,242,251,262,267,333,335,338,355,356,358,360,361,369,370,371,374,375,377,465,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[15,15,-60,-62,-63,-64,-65,-66,-67,-70,-71,-61,-90,-72,-338,15,-76,15,15,15,15,-159,-339,-162,-163,15,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,15,-77,-73,-69,15,15,-160,-221,-220,15,15,-237,15,-87,-74,-233,-234,-236,-161,-222,15,-224,-86,-75,-232,-235,-68,-223,15,15,15,-225,-87,-74,-227,-228,15,-226,-229,15,15,-231,-230,]),'_PRAGMA':([0,2,4,5,6,7,8,9,10,14,15,64,90,91,121,124,127,128,203,204,205,207,208,210,211,221,222,223,224,225,226,227,228,229,230,231,232,242,251,262,267,333,335,338,355,356,358,360,361,369,370,371,374,375,377,465,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[16,16,-60,-62,-63,-64,-65,-66,-67,-70,-71,-61,-90,-72,-338,16,-76,16,16,16,16,-159,-339,-162,-163,16,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,16,-77,-73,-69,16,16,-160,-221,-220,16,16,-237,16,-87,-74,-233,-234,-236,-161,-222,16,-224,-86,-75,-232,-235,-68,-223,16,16,16,-225,-87,-74,-227,-228,16,-226,-229,16,16,-231,-230,]),'_STATIC_ASSERT':([0,2,4,5,6,7,8,9,10,14,15,64,90,91,121,127,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,251,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[18,18,-60,-62,-63,-64,-65,-66,-67,-70,-71,-61,-90,-72,-338,-76,18,-339,18,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,18,-77,-73,-69,-221,-220,18,18,-237,18,-87,-74,-233,-234,-236,-222,18,-224,-86,-75,-232,-235,-68,-223,18,18,18,-225,-87,-74,-227,-228,18,-226,-229,18,18,-231,-230,]),'ID':([0,2,4,5,6,7,8,9,10,12,14,15,17,20,21,22,23,24,25,26,27,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,62,63,64,69,70,71,72,74,75,76,77,78,80,81,82,90,91,94,95,96,98,99,100,101,102,103,104,106,112,113,114,115,116,117,118,119,120,121,122,123,126,127,128,134,135,136,137,141,147,148,149,150,153,154,155,156,160,161,182,183,184,192,194,195,196,197,198,199,206,208,209,212,214,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,244,247,251,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,294,298,306,309,310,314,318,322,323,330,331,332,334,336,337,340,341,342,347,348,349,353,354,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,398,400,401,402,405,448,449,452,455,457,459,460,463,464,466,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,507,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,564,565,570,572,579,580,582,584,585,586,],[28,28,-60,-62,-63,-64,-65,-66,-67,28,-70,-71,28,28,-340,-340,-340,-128,-102,28,-340,-107,-340,-125,-126,-127,-129,-241,118,122,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-157,-158,-61,28,28,-129,-134,-98,-99,-100,-101,-104,28,-134,28,-90,-72,159,-340,159,-93,-9,-10,-340,-94,-95,-103,-129,-97,-183,-27,-28,-185,-96,-169,-170,202,-338,-149,-150,159,-76,233,28,159,-340,159,159,-287,-288,-289,-286,159,159,159,159,-290,-291,159,-340,-28,28,28,159,-184,-186,202,202,-152,-339,28,-145,-147,233,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,159,159,233,373,159,-77,-340,159,-340,-28,-73,-69,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,431,433,159,159,-287,159,159,159,28,28,-340,-171,202,159,-154,-156,-151,-143,-144,-148,159,-146,-130,-177,-178,-221,-220,233,233,-237,159,159,159,159,233,-87,-74,159,-233,-234,-236,159,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,159,-12,159,159,-287,159,159,159,-340,159,28,159,159,-172,-173,-153,-155,28,159,-222,233,-224,159,-86,-75,159,-232,-235,-340,-201,-340,-68,159,159,159,159,-340,-28,-287,-223,233,233,233,159,159,159,-11,-287,159,159,-225,-87,-74,-227,-228,159,-340,159,159,233,159,-226,-229,233,233,-231,-230,]),'LPAREN':([0,2,4,5,6,7,8,9,10,12,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,64,69,70,71,72,74,75,76,77,78,80,81,82,88,89,90,91,94,95,97,98,99,100,101,102,103,104,106,109,112,113,114,115,116,117,118,119,121,122,123,126,127,128,132,134,135,136,139,140,141,143,147,148,149,150,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,192,194,195,196,197,206,208,209,212,214,216,221,222,223,224,225,226,227,228,229,230,231,232,233,234,237,238,240,241,242,243,247,251,252,256,257,258,259,262,263,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,291,292,294,298,300,301,302,303,306,309,310,311,312,318,319,322,323,324,325,330,332,334,336,337,340,341,342,347,348,349,351,352,353,354,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,403,404,405,406,429,431,432,433,434,439,440,446,447,448,452,455,457,459,460,463,464,466,467,469,470,471,474,478,479,480,482,483,484,487,489,493,494,498,499,500,501,502,503,508,509,510,511,512,515,516,518,520,524,525,526,527,528,529,532,533,535,536,543,544,545,546,547,548,549,550,551,552,553,554,555,556,559,561,562,563,565,566,567,570,572,574,577,578,579,580,582,584,585,586,],[17,17,-60,-62,-63,-64,-65,-66,-67,82,-70,-71,92,17,94,96,17,-340,-340,-340,-128,-102,17,-340,-29,-107,-340,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,125,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,126,-61,82,17,-129,125,-98,-99,-100,-101,-104,82,-134,82,137,-37,-90,-72,141,-340,96,-93,-9,-10,-340,-94,-95,-103,-129,125,-97,-183,-27,-28,-185,-96,-169,-170,-338,-149,-150,141,-76,238,137,82,238,-340,-328,-30,238,-306,-287,-288,-289,-286,288,294,294,141,298,299,-292,-315,-290,-291,-304,-305,-307,304,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,238,-340,-28,322,82,238,-184,-186,-152,-339,82,-145,-147,351,238,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-315,141,362,238,366,367,238,372,238,-77,-38,-340,238,-340,-28,-73,-329,-69,238,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,238,238,-300,-301,238,238,-334,-335,-336,-337,-287,238,238,-35,-36,322,449,322,-340,-45,458,-171,141,-154,-156,-151,-143,-144,-148,141,-146,-130,351,351,-177,-178,-221,-220,238,238,-237,238,238,238,238,238,-87,-74,238,-233,-234,-236,238,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,238,-12,141,-287,238,238,-43,-44,141,-308,-295,-296,-297,-298,-299,-31,-34,449,458,-340,322,238,238,-172,-173,-153,-155,82,141,-222,238,-224,141,528,-86,-75,238,-232,-235,-340,-201,-39,-42,-340,-68,141,-293,-294,238,-32,-33,238,-340,-28,-210,-216,-214,-287,-223,238,238,238,238,238,238,-11,-40,-41,-287,238,238,-50,-51,-212,-211,-213,-215,-225,-87,-74,-227,-228,238,-302,-340,-309,238,-46,-49,238,238,-303,-47,-48,-226,-229,238,238,-231,-230,]),'TIMES':([0,2,4,5,6,7,8,9,10,12,14,15,17,21,22,23,24,25,26,27,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,69,70,71,72,74,75,76,77,78,81,82,90,91,94,95,98,99,100,101,102,103,104,106,112,113,114,115,116,117,118,119,121,122,123,126,127,128,134,135,136,139,141,143,145,146,147,148,149,150,151,152,153,154,155,156,158,159,160,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,192,194,195,197,206,208,209,212,214,216,221,222,223,224,225,226,227,228,229,230,231,232,233,234,238,242,247,250,251,256,257,258,259,262,263,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,291,292,293,294,295,296,297,298,300,301,302,303,306,309,310,322,323,330,332,334,336,337,340,341,342,347,348,349,351,353,354,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,448,455,457,459,460,463,464,466,467,469,470,471,474,479,480,482,483,484,487,489,497,498,499,500,501,502,503,505,506,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,561,562,563,565,570,572,574,579,580,582,584,585,586,],[30,30,-60,-62,-63,-64,-65,-66,-67,30,-70,-71,30,-340,-340,-340,-128,-102,30,-340,-107,-340,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,30,30,-129,-134,-98,-99,-100,-101,-104,-134,30,-90,-72,147,-340,-93,-9,-10,-340,-94,-95,-103,-129,-97,30,-27,-28,-185,-96,-169,-170,-338,-149,-150,147,-76,147,30,147,-340,-328,147,-306,269,-258,-287,-288,-289,-286,-277,-279,147,147,147,147,-292,-315,-290,-291,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,306,-340,-28,30,30,147,-186,-152,-339,30,-145,-147,30,147,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-315,147,147,147,147,-277,-77,-340,400,-340,-28,-73,-329,-69,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,-300,-301,-280,147,-281,-282,-283,147,-334,-335,-336,-337,-287,147,147,30,456,-171,147,-154,-156,-151,-143,-144,-148,147,-146,-130,30,-177,-178,-221,-220,147,147,-237,147,147,147,147,147,-87,-74,147,-233,-234,-236,147,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,147,-12,147,-287,147,147,147,-308,-259,-260,-261,269,269,269,269,269,269,269,269,269,269,269,269,269,269,269,-295,-296,-297,-298,-299,-340,147,520,-172,-173,-153,-155,30,147,-222,147,-224,147,-86,-75,147,-232,-235,-340,-201,-278,-340,-68,147,-293,-294,147,-284,-285,543,-340,-28,-287,-223,147,147,147,147,147,147,-11,-287,147,147,-225,-87,-74,-227,-228,147,-302,-340,-309,147,147,147,-303,-226,-229,147,147,-231,-230,]),'TYPEID':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,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,62,63,64,67,68,69,70,71,72,73,74,75,76,77,78,80,81,82,90,91,96,97,98,99,100,101,102,103,104,106,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,134,137,140,141,192,193,194,196,197,203,204,205,206,207,208,209,210,211,212,213,214,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,289,290,294,298,299,304,311,312,313,318,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,466,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[35,35,-60,-62,-63,-64,-65,-66,-67,35,89,-70,-71,-52,-340,-340,-340,-128,-102,35,-340,-29,-107,-340,-125,-126,-127,-129,-241,119,123,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-157,-158,-61,35,-91,89,35,-129,-134,35,-98,-99,-100,-101,-104,89,-134,89,-90,-72,35,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-183,-27,-28,-185,-96,-169,-170,-338,-149,-150,35,35,35,-76,35,-92,89,35,-30,35,324,35,89,-184,-186,35,35,35,-152,-159,-339,89,-162,-163,-145,35,-147,35,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,35,-77,-73,-69,432,434,35,35,35,35,-35,-36,35,324,35,-171,35,-154,35,-156,-151,-160,-143,-144,-148,-146,-130,35,-177,-178,-221,-220,-237,-87,-84,35,-233,-234,-236,-31,-34,35,35,-172,-173,-153,-155,-161,89,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'ENUM':([0,2,4,5,6,7,8,9,10,11,14,15,19,21,22,23,26,27,28,29,34,50,51,52,53,54,55,56,57,58,59,60,64,67,68,70,71,72,73,90,91,96,97,98,99,100,101,102,103,112,116,117,121,124,125,126,127,128,129,137,140,141,193,197,203,204,205,207,208,210,211,213,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,333,335,338,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[36,36,-60,-62,-63,-64,-65,-66,-67,36,-70,-71,-52,-340,-340,-340,36,-340,-29,-107,-340,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,36,-91,36,-340,-134,36,-90,-72,36,-53,-93,-9,-10,-340,-94,-95,-97,-185,-96,-338,36,36,36,-76,36,-92,36,-30,36,36,-186,36,36,36,-159,-339,-162,-163,36,36,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,36,-77,-73,-69,36,36,36,36,-35,-36,36,36,36,36,-160,-130,36,-177,-178,-221,-220,-237,-87,-84,36,-233,-234,-236,-31,-34,36,36,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'VOID':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[38,38,-60,-62,-63,-64,-65,-66,-67,38,38,-70,-71,-52,-340,-340,-340,-128,-102,38,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,38,-91,38,38,-129,-134,38,-98,-99,-100,-101,-104,-134,-90,-72,38,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,38,38,38,-76,38,-92,38,-30,38,38,38,-186,38,38,38,-152,-159,-339,38,-162,-163,-145,38,-147,38,38,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,38,-77,-73,-69,38,38,38,38,-35,-36,38,38,-171,38,-154,38,-156,-151,-160,-143,-144,-148,-146,-130,38,-177,-178,-221,-220,-237,-87,-84,38,-233,-234,-236,-31,-34,38,38,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'_BOOL':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[39,39,-60,-62,-63,-64,-65,-66,-67,39,39,-70,-71,-52,-340,-340,-340,-128,-102,39,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,39,-91,39,39,-129,-134,39,-98,-99,-100,-101,-104,-134,-90,-72,39,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,39,39,39,-76,39,-92,39,-30,39,39,39,-186,39,39,39,-152,-159,-339,39,-162,-163,-145,39,-147,39,39,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,39,-77,-73,-69,39,39,39,39,-35,-36,39,39,-171,39,-154,39,-156,-151,-160,-143,-144,-148,-146,-130,39,-177,-178,-221,-220,-237,-87,-84,39,-233,-234,-236,-31,-34,39,39,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'CHAR':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[40,40,-60,-62,-63,-64,-65,-66,-67,40,40,-70,-71,-52,-340,-340,-340,-128,-102,40,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,40,-91,40,40,-129,-134,40,-98,-99,-100,-101,-104,-134,-90,-72,40,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,40,40,40,-76,40,-92,40,-30,40,40,40,-186,40,40,40,-152,-159,-339,40,-162,-163,-145,40,-147,40,40,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,40,-77,-73,-69,40,40,40,40,-35,-36,40,40,-171,40,-154,40,-156,-151,-160,-143,-144,-148,-146,-130,40,-177,-178,-221,-220,-237,-87,-84,40,-233,-234,-236,-31,-34,40,40,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'SHORT':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[41,41,-60,-62,-63,-64,-65,-66,-67,41,41,-70,-71,-52,-340,-340,-340,-128,-102,41,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,41,-91,41,41,-129,-134,41,-98,-99,-100,-101,-104,-134,-90,-72,41,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,41,41,41,-76,41,-92,41,-30,41,41,41,-186,41,41,41,-152,-159,-339,41,-162,-163,-145,41,-147,41,41,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,41,-77,-73,-69,41,41,41,41,-35,-36,41,41,-171,41,-154,41,-156,-151,-160,-143,-144,-148,-146,-130,41,-177,-178,-221,-220,-237,-87,-84,41,-233,-234,-236,-31,-34,41,41,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'INT':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[42,42,-60,-62,-63,-64,-65,-66,-67,42,42,-70,-71,-52,-340,-340,-340,-128,-102,42,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,42,-91,42,42,-129,-134,42,-98,-99,-100,-101,-104,-134,-90,-72,42,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,42,42,42,-76,42,-92,42,-30,42,42,42,-186,42,42,42,-152,-159,-339,42,-162,-163,-145,42,-147,42,42,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,42,-77,-73,-69,42,42,42,42,-35,-36,42,42,-171,42,-154,42,-156,-151,-160,-143,-144,-148,-146,-130,42,-177,-178,-221,-220,-237,-87,-84,42,-233,-234,-236,-31,-34,42,42,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'LONG':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[43,43,-60,-62,-63,-64,-65,-66,-67,43,43,-70,-71,-52,-340,-340,-340,-128,-102,43,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,43,-91,43,43,-129,-134,43,-98,-99,-100,-101,-104,-134,-90,-72,43,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,43,43,43,-76,43,-92,43,-30,43,43,43,-186,43,43,43,-152,-159,-339,43,-162,-163,-145,43,-147,43,43,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,43,-77,-73,-69,43,43,43,43,-35,-36,43,43,-171,43,-154,43,-156,-151,-160,-143,-144,-148,-146,-130,43,-177,-178,-221,-220,-237,-87,-84,43,-233,-234,-236,-31,-34,43,43,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'FLOAT':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[44,44,-60,-62,-63,-64,-65,-66,-67,44,44,-70,-71,-52,-340,-340,-340,-128,-102,44,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,44,-91,44,44,-129,-134,44,-98,-99,-100,-101,-104,-134,-90,-72,44,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,44,44,44,-76,44,-92,44,-30,44,44,44,-186,44,44,44,-152,-159,-339,44,-162,-163,-145,44,-147,44,44,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,44,-77,-73,-69,44,44,44,44,-35,-36,44,44,-171,44,-154,44,-156,-151,-160,-143,-144,-148,-146,-130,44,-177,-178,-221,-220,-237,-87,-84,44,-233,-234,-236,-31,-34,44,44,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'DOUBLE':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[45,45,-60,-62,-63,-64,-65,-66,-67,45,45,-70,-71,-52,-340,-340,-340,-128,-102,45,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,45,-91,45,45,-129,-134,45,-98,-99,-100,-101,-104,-134,-90,-72,45,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,45,45,45,-76,45,-92,45,-30,45,45,45,-186,45,45,45,-152,-159,-339,45,-162,-163,-145,45,-147,45,45,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,45,-77,-73,-69,45,45,45,45,-35,-36,45,45,-171,45,-154,45,-156,-151,-160,-143,-144,-148,-146,-130,45,-177,-178,-221,-220,-237,-87,-84,45,-233,-234,-236,-31,-34,45,45,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'_COMPLEX':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[46,46,-60,-62,-63,-64,-65,-66,-67,46,46,-70,-71,-52,-340,-340,-340,-128,-102,46,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,46,-91,46,46,-129,-134,46,-98,-99,-100,-101,-104,-134,-90,-72,46,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,46,46,46,-76,46,-92,46,-30,46,46,46,-186,46,46,46,-152,-159,-339,46,-162,-163,-145,46,-147,46,46,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,46,-77,-73,-69,46,46,46,46,-35,-36,46,46,-171,46,-154,46,-156,-151,-160,-143,-144,-148,-146,-130,46,-177,-178,-221,-220,-237,-87,-84,46,-233,-234,-236,-31,-34,46,46,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'SIGNED':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[47,47,-60,-62,-63,-64,-65,-66,-67,47,47,-70,-71,-52,-340,-340,-340,-128,-102,47,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,47,-91,47,47,-129,-134,47,-98,-99,-100,-101,-104,-134,-90,-72,47,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,47,47,47,-76,47,-92,47,-30,47,47,47,-186,47,47,47,-152,-159,-339,47,-162,-163,-145,47,-147,47,47,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,47,-77,-73,-69,47,47,47,47,-35,-36,47,47,-171,47,-154,47,-156,-151,-160,-143,-144,-148,-146,-130,47,-177,-178,-221,-220,-237,-87,-84,47,-233,-234,-236,-31,-34,47,47,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'UNSIGNED':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[48,48,-60,-62,-63,-64,-65,-66,-67,48,48,-70,-71,-52,-340,-340,-340,-128,-102,48,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,48,-91,48,48,-129,-134,48,-98,-99,-100,-101,-104,-134,-90,-72,48,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,48,48,48,-76,48,-92,48,-30,48,48,48,-186,48,48,48,-152,-159,-339,48,-162,-163,-145,48,-147,48,48,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,48,-77,-73,-69,48,48,48,48,-35,-36,48,48,-171,48,-154,48,-156,-151,-160,-143,-144,-148,-146,-130,48,-177,-178,-221,-220,-237,-87,-84,48,-233,-234,-236,-31,-34,48,48,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'__INT128':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,96,97,98,99,100,101,102,103,104,106,112,116,117,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[49,49,-60,-62,-63,-64,-65,-66,-67,49,49,-70,-71,-52,-340,-340,-340,-128,-102,49,-340,-29,-107,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,49,-91,49,49,-129,-134,49,-98,-99,-100,-101,-104,-134,-90,-72,49,-53,-93,-9,-10,-340,-94,-95,-103,-129,-97,-185,-96,-169,-170,-338,-149,-150,49,49,49,-76,49,-92,49,-30,49,49,49,-186,49,49,49,-152,-159,-339,49,-162,-163,-145,49,-147,49,49,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,49,-77,-73,-69,49,49,49,49,-35,-36,49,49,-171,49,-154,49,-156,-151,-160,-143,-144,-148,-146,-130,49,-177,-178,-221,-220,-237,-87,-84,49,-233,-234,-236,-31,-34,49,49,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'_ATOMIC':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,70,71,72,73,74,75,76,77,78,81,90,91,95,96,97,98,99,100,101,102,103,104,106,112,115,116,117,118,119,121,122,123,124,125,126,127,128,129,136,137,140,141,183,184,192,193,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,258,259,262,267,294,298,299,304,311,312,313,322,323,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,448,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,511,512,524,552,553,554,555,556,579,580,585,586,],[50,50,-60,-62,-63,-64,-65,-66,-67,72,81,-70,-71,-52,72,72,72,-128,-102,109,72,-29,-107,81,-125,-126,-127,72,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,72,-91,81,109,72,-134,72,-98,-99,-100,-101,-104,-134,-90,-72,81,50,-53,-93,-9,-10,72,-94,-95,-103,-129,-97,81,-185,-96,-169,-170,-338,-149,-150,50,50,50,-76,72,-92,81,50,-30,50,81,81,81,109,-186,50,50,50,-152,-159,-339,81,-162,-163,-145,72,-147,81,72,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,50,-77,81,81,-73,-69,50,50,50,50,-35,-36,50,50,81,-171,50,-154,50,-156,-151,-160,-143,-144,-148,-146,-130,50,-177,-178,-221,-220,-237,-87,-84,72,-233,-234,-236,-31,-34,81,50,50,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,81,81,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'CONST':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,95,96,97,101,104,106,115,116,118,119,121,122,123,124,125,126,127,128,129,136,137,140,141,183,184,192,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,258,259,262,267,294,298,299,304,311,312,313,322,323,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,448,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,511,512,524,552,553,554,555,556,579,580,585,586,],[51,51,-60,-62,-63,-64,-65,-66,-67,51,51,-70,-71,-52,51,51,51,-128,-102,51,-29,-107,51,-125,-126,-127,51,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,51,-91,51,51,-134,51,-98,-99,-100,-101,-104,-134,-90,-72,51,51,-53,51,-103,-129,51,-185,-169,-170,-338,-149,-150,51,51,51,-76,51,-92,51,51,-30,51,51,51,51,-186,51,51,51,-152,-159,-339,51,-162,-163,-145,51,-147,51,51,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,51,-77,51,51,-73,-69,51,51,51,51,-35,-36,51,51,51,-171,51,-154,51,-156,-151,-160,-143,-144,-148,-146,-130,51,-177,-178,-221,-220,-237,-87,-84,51,-233,-234,-236,-31,-34,51,51,51,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,51,51,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'RESTRICT':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,95,96,97,101,104,106,115,116,118,119,121,122,123,124,125,126,127,128,129,136,137,140,141,183,184,192,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,258,259,262,267,294,298,299,304,311,312,313,322,323,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,448,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,511,512,524,552,553,554,555,556,579,580,585,586,],[52,52,-60,-62,-63,-64,-65,-66,-67,52,52,-70,-71,-52,52,52,52,-128,-102,52,-29,-107,52,-125,-126,-127,52,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,52,-91,52,52,-134,52,-98,-99,-100,-101,-104,-134,-90,-72,52,52,-53,52,-103,-129,52,-185,-169,-170,-338,-149,-150,52,52,52,-76,52,-92,52,52,-30,52,52,52,52,-186,52,52,52,-152,-159,-339,52,-162,-163,-145,52,-147,52,52,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,52,-77,52,52,-73,-69,52,52,52,52,-35,-36,52,52,52,-171,52,-154,52,-156,-151,-160,-143,-144,-148,-146,-130,52,-177,-178,-221,-220,-237,-87,-84,52,-233,-234,-236,-31,-34,52,52,52,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,52,52,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'VOLATILE':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,95,96,97,101,104,106,115,116,118,119,121,122,123,124,125,126,127,128,129,136,137,140,141,183,184,192,197,203,204,205,206,207,208,209,210,211,212,213,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,258,259,262,267,294,298,299,304,311,312,313,322,323,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,448,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,511,512,524,552,553,554,555,556,579,580,585,586,],[53,53,-60,-62,-63,-64,-65,-66,-67,53,53,-70,-71,-52,53,53,53,-128,-102,53,-29,-107,53,-125,-126,-127,53,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,53,-91,53,53,-134,53,-98,-99,-100,-101,-104,-134,-90,-72,53,53,-53,53,-103,-129,53,-185,-169,-170,-338,-149,-150,53,53,53,-76,53,-92,53,53,-30,53,53,53,53,-186,53,53,53,-152,-159,-339,53,-162,-163,-145,53,-147,53,53,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,53,-77,53,53,-73,-69,53,53,53,53,-35,-36,53,53,53,-171,53,-154,53,-156,-151,-160,-143,-144,-148,-146,-130,53,-177,-178,-221,-220,-237,-87,-84,53,-233,-234,-236,-31,-34,53,53,53,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,53,53,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'AUTO':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,96,97,101,104,106,118,119,121,122,123,127,128,129,137,140,192,206,208,221,222,223,224,225,226,227,228,229,230,231,232,251,262,267,311,312,313,322,330,334,336,337,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[54,54,-60,-62,-63,-64,-65,-66,-67,54,54,-70,-71,-52,54,54,54,-128,-102,54,-29,-107,-125,-126,-127,54,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,54,-91,54,54,-134,54,-98,-99,-100,-101,-104,-134,-90,-72,54,-53,54,-103,-129,-169,-170,-338,-149,-150,-76,54,-92,54,-30,54,-152,-339,54,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-77,-73,-69,-35,-36,54,54,-171,-154,-156,-151,-130,54,-177,-178,-221,-220,-237,-87,-84,54,-233,-234,-236,-31,-34,54,54,-172,-173,-153,-155,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'REGISTER':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,96,97,101,104,106,118,119,121,122,123,127,128,129,137,140,192,206,208,221,222,223,224,225,226,227,228,229,230,231,232,251,262,267,311,312,313,322,330,334,336,337,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[55,55,-60,-62,-63,-64,-65,-66,-67,55,55,-70,-71,-52,55,55,55,-128,-102,55,-29,-107,-125,-126,-127,55,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,55,-91,55,55,-134,55,-98,-99,-100,-101,-104,-134,-90,-72,55,-53,55,-103,-129,-169,-170,-338,-149,-150,-76,55,-92,55,-30,55,-152,-339,55,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-77,-73,-69,-35,-36,55,55,-171,-154,-156,-151,-130,55,-177,-178,-221,-220,-237,-87,-84,55,-233,-234,-236,-31,-34,55,55,-172,-173,-153,-155,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'STATIC':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,95,96,97,101,104,106,116,118,119,121,122,123,127,128,129,136,137,140,184,192,197,206,208,221,222,223,224,225,226,227,228,229,230,231,232,251,259,262,267,311,312,313,322,330,334,336,337,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,448,449,458,459,460,463,464,469,471,479,480,483,484,499,508,509,512,524,552,553,554,555,556,579,580,585,586,],[29,29,-60,-62,-63,-64,-65,-66,-67,29,29,-70,-71,-52,29,29,29,-128,-102,29,-29,-107,-125,-126,-127,29,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,29,-91,29,29,-134,29,-98,-99,-100,-101,-104,-134,-90,-72,183,29,-53,29,-103,-129,-185,-169,-170,-338,-149,-150,-76,29,-92,258,29,-30,310,29,-186,-152,-339,29,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-77,402,-73,-69,-35,-36,29,29,-171,-154,-156,-151,-130,29,-177,-178,-221,-220,-237,-87,-84,29,-233,-234,-236,-31,-34,511,29,29,-172,-173,-153,-155,-222,-224,-86,-84,-232,-235,-68,-32,-33,545,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'EXTERN':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,96,97,101,104,106,118,119,121,122,123,127,128,129,137,140,192,206,208,221,222,223,224,225,226,227,228,229,230,231,232,251,262,267,311,312,313,322,330,334,336,337,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[56,56,-60,-62,-63,-64,-65,-66,-67,56,56,-70,-71,-52,56,56,56,-128,-102,56,-29,-107,-125,-126,-127,56,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,56,-91,56,56,-134,56,-98,-99,-100,-101,-104,-134,-90,-72,56,-53,56,-103,-129,-169,-170,-338,-149,-150,-76,56,-92,56,-30,56,-152,-339,56,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-77,-73,-69,-35,-36,56,56,-171,-154,-156,-151,-130,56,-177,-178,-221,-220,-237,-87,-84,56,-233,-234,-236,-31,-34,56,56,-172,-173,-153,-155,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'TYPEDEF':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,96,97,101,104,106,118,119,121,122,123,127,128,129,137,140,192,206,208,221,222,223,224,225,226,227,228,229,230,231,232,251,262,267,311,312,313,322,330,334,336,337,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[57,57,-60,-62,-63,-64,-65,-66,-67,57,57,-70,-71,-52,57,57,57,-128,-102,57,-29,-107,-125,-126,-127,57,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,57,-91,57,57,-134,57,-98,-99,-100,-101,-104,-134,-90,-72,57,-53,57,-103,-129,-169,-170,-338,-149,-150,-76,57,-92,57,-30,57,-152,-339,57,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-77,-73,-69,-35,-36,57,57,-171,-154,-156,-151,-130,57,-177,-178,-221,-220,-237,-87,-84,57,-233,-234,-236,-31,-34,57,57,-172,-173,-153,-155,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'_THREAD_LOCAL':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,96,97,101,104,106,118,119,121,122,123,127,128,129,137,140,192,206,208,221,222,223,224,225,226,227,228,229,230,231,232,251,262,267,311,312,313,322,330,334,336,337,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[58,58,-60,-62,-63,-64,-65,-66,-67,58,58,-70,-71,-52,58,58,58,-128,-102,58,-29,-107,-125,-126,-127,58,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,58,-91,58,58,-134,58,-98,-99,-100,-101,-104,-134,-90,-72,58,-53,58,-103,-129,-169,-170,-338,-149,-150,-76,58,-92,58,-30,58,-152,-339,58,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-77,-73,-69,-35,-36,58,58,-171,-154,-156,-151,-130,58,-177,-178,-221,-220,-237,-87,-84,58,-233,-234,-236,-31,-34,58,58,-172,-173,-153,-155,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'INLINE':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,96,97,101,104,106,118,119,121,122,123,127,128,129,137,140,192,206,208,221,222,223,224,225,226,227,228,229,230,231,232,251,262,267,311,312,313,322,330,334,336,337,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[59,59,-60,-62,-63,-64,-65,-66,-67,59,59,-70,-71,-52,59,59,59,-128,-102,59,-29,-107,-125,-126,-127,59,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,59,-91,59,59,-134,59,-98,-99,-100,-101,-104,-134,-90,-72,59,-53,59,-103,-129,-169,-170,-338,-149,-150,-76,59,-92,59,-30,59,-152,-339,59,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-77,-73,-69,-35,-36,59,59,-171,-154,-156,-151,-130,59,-177,-178,-221,-220,-237,-87,-84,59,-233,-234,-236,-31,-34,59,59,-172,-173,-153,-155,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'_NORETURN':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,96,97,101,104,106,118,119,121,122,123,127,128,129,137,140,192,206,208,221,222,223,224,225,226,227,228,229,230,231,232,251,262,267,311,312,313,322,330,334,336,337,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[60,60,-60,-62,-63,-64,-65,-66,-67,60,60,-70,-71,-52,60,60,60,-128,-102,60,-29,-107,-125,-126,-127,60,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,60,-91,60,60,-134,60,-98,-99,-100,-101,-104,-134,-90,-72,60,-53,60,-103,-129,-169,-170,-338,-149,-150,-76,60,-92,60,-30,60,-152,-339,60,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-77,-73,-69,-35,-36,60,60,-171,-154,-156,-151,-130,60,-177,-178,-221,-220,-237,-87,-84,60,-233,-234,-236,-31,-34,60,60,-172,-173,-153,-155,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'_ALIGNAS':([0,2,4,5,6,7,8,9,10,11,12,14,15,19,21,22,23,24,25,27,28,29,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,64,67,68,69,71,72,73,74,75,76,77,78,81,90,91,96,97,101,104,106,118,119,121,122,123,124,125,126,127,128,129,137,140,141,192,203,204,205,206,207,208,209,210,211,212,214,216,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,330,333,334,335,336,337,338,340,341,342,348,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,459,460,463,464,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[61,61,-60,-62,-63,-64,-65,-66,-67,61,61,-70,-71,-52,61,61,61,-128,-102,61,-29,-107,-125,-126,-127,61,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,61,-91,61,61,-134,61,-98,-99,-100,-101,-104,-134,-90,-72,61,-53,61,-103,-129,-169,-170,-338,-149,-150,61,61,61,-76,61,-92,61,-30,61,61,61,61,61,-152,-159,-339,61,-162,-163,-145,-147,61,61,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,61,-77,-73,-69,61,61,61,61,-35,-36,61,61,-171,61,-154,61,-156,-151,-160,-143,-144,-148,-146,-130,61,-177,-178,-221,-220,-237,-87,-84,61,-233,-234,-236,-31,-34,61,61,-172,-173,-153,-155,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'STRUCT':([0,2,4,5,6,7,8,9,10,11,14,15,19,21,22,23,26,27,28,29,34,50,51,52,53,54,55,56,57,58,59,60,64,67,68,70,71,72,73,90,91,96,97,98,99,100,101,102,103,112,116,117,121,124,125,126,127,128,129,137,140,141,193,197,203,204,205,207,208,210,211,213,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,333,335,338,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[62,62,-60,-62,-63,-64,-65,-66,-67,62,-70,-71,-52,-340,-340,-340,62,-340,-29,-107,-340,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,62,-91,62,-340,-134,62,-90,-72,62,-53,-93,-9,-10,-340,-94,-95,-97,-185,-96,-338,62,62,62,-76,62,-92,62,-30,62,62,-186,62,62,62,-159,-339,-162,-163,62,62,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,62,-77,-73,-69,62,62,62,62,-35,-36,62,62,62,62,-160,-130,62,-177,-178,-221,-220,-237,-87,-84,62,-233,-234,-236,-31,-34,62,62,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'UNION':([0,2,4,5,6,7,8,9,10,11,14,15,19,21,22,23,26,27,28,29,34,50,51,52,53,54,55,56,57,58,59,60,64,67,68,70,71,72,73,90,91,96,97,98,99,100,101,102,103,112,116,117,121,124,125,126,127,128,129,137,140,141,193,197,203,204,205,207,208,210,211,213,221,222,223,224,225,226,227,228,229,230,231,232,238,251,262,267,294,298,299,304,311,312,313,322,333,335,338,349,351,353,354,355,356,361,370,371,372,374,375,377,439,440,449,458,465,469,471,479,480,483,484,499,508,509,524,552,553,554,555,556,579,580,585,586,],[63,63,-60,-62,-63,-64,-65,-66,-67,63,-70,-71,-52,-340,-340,-340,63,-340,-29,-107,-340,-134,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-61,63,-91,63,-340,-134,63,-90,-72,63,-53,-93,-9,-10,-340,-94,-95,-97,-185,-96,-338,63,63,63,-76,63,-92,63,-30,63,63,-186,63,63,63,-159,-339,-162,-163,63,63,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,63,-77,-73,-69,63,63,63,63,-35,-36,63,63,63,63,-160,-130,63,-177,-178,-221,-220,-237,-87,-84,63,-233,-234,-236,-31,-34,63,63,-161,-222,-224,-86,-84,-232,-235,-68,-32,-33,-223,-225,-87,-84,-227,-228,-226,-229,-231,-230,]),'LBRACE':([11,15,19,28,36,37,62,63,65,66,67,68,73,90,91,97,118,119,121,122,123,128,129,131,135,140,195,208,221,222,223,224,225,226,227,228,229,230,231,232,238,242,256,262,267,311,312,355,356,358,360,361,369,370,371,374,375,377,392,393,394,405,439,440,469,470,471,474,479,480,483,484,487,489,498,499,504,505,508,509,524,525,526,527,532,533,552,553,554,555,556,562,570,579,580,582,584,585,586,],[-340,-71,-52,-29,121,121,-157,-158,121,-7,-8,-91,-340,-90,-72,-53,121,121,-338,121,121,121,-92,121,121,-30,121,-339,121,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,121,121,-340,-73,-69,-35,-36,-221,-220,121,121,-237,121,-87,-74,-233,-234,-236,-11,121,-12,121,-31,-34,-222,121,-224,121,-86,-75,-232,-235,-340,-201,-340,-68,121,121,-32,-33,-223,121,121,121,121,-11,-225,-87,-74,-227,-228,-340,121,-226,-229,121,121,-231,-230,]),'RBRACE':([15,90,91,121,124,128,139,143,144,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,200,201,202,203,204,205,207,208,210,211,219,220,221,222,223,224,225,226,227,228,229,230,231,232,249,250,255,256,262,263,267,291,292,293,295,296,297,300,301,302,303,328,329,331,333,335,338,355,356,361,370,371,374,375,377,390,391,392,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,461,462,465,469,471,473,479,480,483,484,485,486,487,488,497,499,501,502,505,506,524,531,537,538,552,553,554,555,556,560,561,562,563,574,579,580,585,586,],[-71,-90,-72,-338,208,-340,-328,-306,-255,-256,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,208,-174,-179,208,208,208,-159,-339,-162,-163,208,-5,-6,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-242,-277,-196,-340,-73,-329,-69,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,208,208,-175,208,208,-160,-221,-220,-237,-87,-84,-233,-234,-236,208,-22,-21,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,-276,-295,-296,-297,-298,-299,-176,-180,-161,-222,-224,-240,-86,-84,-232,-235,-243,-197,208,-199,-278,-68,-293,-294,-284,-285,-223,-198,208,-257,-225,-87,-84,-227,-228,-200,-302,208,-309,-303,-226,-229,-231,-230,]),'CASE':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,234,-339,234,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,234,-73,-69,-221,-220,234,234,-237,234,-87,-74,-233,-234,-236,-222,234,-224,-86,-75,-232,-235,-68,-223,234,234,234,-225,-87,-74,-227,-228,234,-226,-229,234,234,-231,-230,]),'DEFAULT':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,235,-339,235,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,235,-73,-69,-221,-220,235,235,-237,235,-87,-74,-233,-234,-236,-222,235,-224,-86,-75,-232,-235,-68,-223,235,235,235,-225,-87,-74,-227,-228,235,-226,-229,235,235,-231,-230,]),'IF':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,237,-339,237,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,237,-73,-69,-221,-220,237,237,-237,237,-87,-74,-233,-234,-236,-222,237,-224,-86,-75,-232,-235,-68,-223,237,237,237,-225,-87,-74,-227,-228,237,-226,-229,237,237,-231,-230,]),'SWITCH':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,240,-339,240,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,240,-73,-69,-221,-220,240,240,-237,240,-87,-74,-233,-234,-236,-222,240,-224,-86,-75,-232,-235,-68,-223,240,240,240,-225,-87,-74,-227,-228,240,-226,-229,240,240,-231,-230,]),'WHILE':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,368,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,241,-339,241,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,241,-73,-69,-221,-220,241,241,-237,478,241,-87,-74,-233,-234,-236,-222,241,-224,-86,-75,-232,-235,-68,-223,241,241,241,-225,-87,-74,-227,-228,241,-226,-229,241,241,-231,-230,]),'DO':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,242,-339,242,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,242,-73,-69,-221,-220,242,242,-237,242,-87,-74,-233,-234,-236,-222,242,-224,-86,-75,-232,-235,-68,-223,242,242,242,-225,-87,-74,-227,-228,242,-226,-229,242,242,-231,-230,]),'FOR':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,243,-339,243,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,243,-73,-69,-221,-220,243,243,-237,243,-87,-74,-233,-234,-236,-222,243,-224,-86,-75,-232,-235,-68,-223,243,243,243,-225,-87,-74,-227,-228,243,-226,-229,243,243,-231,-230,]),'GOTO':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,244,-339,244,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,244,-73,-69,-221,-220,244,244,-237,244,-87,-74,-233,-234,-236,-222,244,-224,-86,-75,-232,-235,-68,-223,244,244,244,-225,-87,-74,-227,-228,244,-226,-229,244,244,-231,-230,]),'BREAK':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,245,-339,245,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,245,-73,-69,-221,-220,245,245,-237,245,-87,-74,-233,-234,-236,-222,245,-224,-86,-75,-232,-235,-68,-223,245,245,245,-225,-87,-74,-227,-228,245,-226,-229,245,245,-231,-230,]),'CONTINUE':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,246,-339,246,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,246,-73,-69,-221,-220,246,246,-237,246,-87,-74,-233,-234,-236,-222,246,-224,-86,-75,-232,-235,-68,-223,246,246,246,-225,-87,-74,-227,-228,246,-226,-229,246,246,-231,-230,]),'RETURN':([15,90,91,121,128,208,221,222,223,224,225,226,227,228,229,230,231,232,242,262,267,355,356,358,360,361,369,370,371,374,375,377,469,470,471,479,480,483,484,499,524,525,526,527,552,553,554,555,556,570,579,580,582,584,585,586,],[-71,-90,-72,-338,247,-339,247,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,247,-73,-69,-221,-220,247,247,-237,247,-87,-74,-233,-234,-236,-222,247,-224,-86,-75,-232,-235,-68,-223,247,247,247,-225,-87,-74,-227,-228,247,-226,-229,247,247,-231,-230,]),'PLUSPLUS':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,139,141,143,147,148,149,150,152,153,154,155,156,158,159,160,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,233,234,238,242,247,256,257,258,259,262,263,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,291,292,294,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,406,429,431,432,433,434,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,501,502,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,561,562,563,565,570,572,574,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,153,-340,-27,-28,-185,-338,153,153,153,-340,-328,153,-306,-287,-288,-289,-286,291,153,153,153,153,-292,-315,-290,-291,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,153,-340,-28,153,-186,-339,153,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-315,153,153,153,153,-340,153,-340,-28,-73,-329,-69,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,-300,-301,153,153,-334,-335,-336,-337,-287,153,153,-340,153,153,-221,-220,153,153,-237,153,153,153,153,153,-87,-74,153,-233,-234,-236,153,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,153,-12,153,-287,153,153,153,-308,-295,-296,-297,-298,-299,-340,153,153,153,-222,153,-224,153,-86,-75,153,-232,-235,-340,-201,-340,-68,153,-293,-294,153,153,-340,-28,-287,-223,153,153,153,153,153,153,-11,-287,153,153,-225,-87,-74,-227,-228,153,-302,-340,-309,153,153,153,-303,-226,-229,153,153,-231,-230,]),'MINUSMINUS':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,139,141,143,147,148,149,150,152,153,154,155,156,158,159,160,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,233,234,238,242,247,256,257,258,259,262,263,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,291,292,294,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,406,429,431,432,433,434,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,501,502,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,561,562,563,565,570,572,574,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,154,-340,-27,-28,-185,-338,154,154,154,-340,-328,154,-306,-287,-288,-289,-286,292,154,154,154,154,-292,-315,-290,-291,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,154,-340,-28,154,-186,-339,154,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-315,154,154,154,154,-340,154,-340,-28,-73,-329,-69,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,-300,-301,154,154,-334,-335,-336,-337,-287,154,154,-340,154,154,-221,-220,154,154,-237,154,154,154,154,154,-87,-74,154,-233,-234,-236,154,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,154,-12,154,-287,154,154,154,-308,-295,-296,-297,-298,-299,-340,154,154,154,-222,154,-224,154,-86,-75,154,-232,-235,-340,-201,-340,-68,154,-293,-294,154,154,-340,-28,-287,-223,154,154,154,154,154,154,-11,-287,154,154,-225,-87,-74,-227,-228,154,-302,-340,-309,154,154,154,-303,-226,-229,154,154,-231,-230,]),'SIZEOF':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,156,-340,-27,-28,-185,-338,156,156,156,-340,156,-287,-288,-289,-286,156,156,156,156,-290,-291,156,-340,-28,156,-186,-339,156,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,156,156,156,156,-340,156,-340,-28,-73,-69,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,-287,156,156,-340,156,156,-221,-220,156,156,-237,156,156,156,156,156,-87,-74,156,-233,-234,-236,156,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,156,-12,156,-287,156,156,156,-340,156,156,156,-222,156,-224,156,-86,-75,156,-232,-235,-340,-201,-340,-68,156,156,156,-340,-28,-287,-223,156,156,156,156,156,156,-11,-287,156,156,-225,-87,-74,-227,-228,156,-340,156,156,156,-226,-229,156,156,-231,-230,]),'_ALIGNOF':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,157,-340,-27,-28,-185,-338,157,157,157,-340,157,-287,-288,-289,-286,157,157,157,157,-290,-291,157,-340,-28,157,-186,-339,157,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,157,157,157,157,-340,157,-340,-28,-73,-69,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,-287,157,157,-340,157,157,-221,-220,157,157,-237,157,157,157,157,157,-87,-74,157,-233,-234,-236,157,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,157,-12,157,-287,157,157,157,-340,157,157,157,-222,157,-224,157,-86,-75,157,-232,-235,-340,-201,-340,-68,157,157,157,-340,-28,-287,-223,157,157,157,157,157,157,-11,-287,157,157,-225,-87,-74,-227,-228,157,-340,157,157,157,-226,-229,157,157,-231,-230,]),'AND':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,139,141,143,145,146,147,148,149,150,151,152,153,154,155,156,158,159,160,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,233,234,238,242,247,250,256,257,258,259,262,263,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,291,292,293,294,295,296,297,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,497,498,499,500,501,502,503,505,506,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,561,562,563,565,570,572,574,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,150,-340,-27,-28,-185,-338,150,150,150,-340,-328,150,-306,282,-258,-287,-288,-289,-286,-277,-279,150,150,150,150,-292,-315,-290,-291,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,150,-340,-28,150,-186,-339,150,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-315,150,150,150,150,-277,-340,150,-340,-28,-73,-329,-69,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,-300,-301,-280,150,-281,-282,-283,150,-334,-335,-336,-337,-287,150,150,-340,150,150,-221,-220,150,150,-237,150,150,150,150,150,-87,-74,150,-233,-234,-236,150,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,150,-12,150,-287,150,150,150,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,282,282,282,282,-295,-296,-297,-298,-299,-340,150,150,150,-222,150,-224,150,-86,-75,150,-232,-235,-340,-201,-278,-340,-68,150,-293,-294,150,-284,-285,150,-340,-28,-287,-223,150,150,150,150,150,150,-11,-287,150,150,-225,-87,-74,-227,-228,150,-302,-340,-309,150,150,150,-303,-226,-229,150,150,-231,-230,]),'PLUS':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,139,141,143,145,146,147,148,149,150,151,152,153,154,155,156,158,159,160,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,233,234,238,242,247,250,256,257,258,259,262,263,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,291,292,293,294,295,296,297,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,497,498,499,500,501,502,503,505,506,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,561,562,563,565,570,572,574,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,148,-340,-27,-28,-185,-338,148,148,148,-340,-328,148,-306,272,-258,-287,-288,-289,-286,-277,-279,148,148,148,148,-292,-315,-290,-291,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,148,-340,-28,148,-186,-339,148,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-315,148,148,148,148,-277,-340,148,-340,-28,-73,-329,-69,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,-300,-301,-280,148,-281,-282,-283,148,-334,-335,-336,-337,-287,148,148,-340,148,148,-221,-220,148,148,-237,148,148,148,148,148,-87,-74,148,-233,-234,-236,148,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,148,-12,148,-287,148,148,148,-308,-259,-260,-261,-262,-263,272,272,272,272,272,272,272,272,272,272,272,272,272,-295,-296,-297,-298,-299,-340,148,148,148,-222,148,-224,148,-86,-75,148,-232,-235,-340,-201,-278,-340,-68,148,-293,-294,148,-284,-285,148,-340,-28,-287,-223,148,148,148,148,148,148,-11,-287,148,148,-225,-87,-74,-227,-228,148,-302,-340,-309,148,148,148,-303,-226,-229,148,148,-231,-230,]),'MINUS':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,139,141,143,145,146,147,148,149,150,151,152,153,154,155,156,158,159,160,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,233,234,238,242,247,250,256,257,258,259,262,263,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,291,292,293,294,295,296,297,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,497,498,499,500,501,502,503,505,506,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,561,562,563,565,570,572,574,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,149,-340,-27,-28,-185,-338,149,149,149,-340,-328,149,-306,273,-258,-287,-288,-289,-286,-277,-279,149,149,149,149,-292,-315,-290,-291,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,149,-340,-28,149,-186,-339,149,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,-315,149,149,149,149,-277,-340,149,-340,-28,-73,-329,-69,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,-300,-301,-280,149,-281,-282,-283,149,-334,-335,-336,-337,-287,149,149,-340,149,149,-221,-220,149,149,-237,149,149,149,149,149,-87,-74,149,-233,-234,-236,149,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,149,-12,149,-287,149,149,149,-308,-259,-260,-261,-262,-263,273,273,273,273,273,273,273,273,273,273,273,273,273,-295,-296,-297,-298,-299,-340,149,149,149,-222,149,-224,149,-86,-75,149,-232,-235,-340,-201,-278,-340,-68,149,-293,-294,149,-284,-285,149,-340,-28,-287,-223,149,149,149,149,149,149,-11,-287,149,149,-225,-87,-74,-227,-228,149,-302,-340,-309,149,149,149,-303,-226,-229,149,149,-231,-230,]),'NOT':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,160,-340,-27,-28,-185,-338,160,160,160,-340,160,-287,-288,-289,-286,160,160,160,160,-290,-291,160,-340,-28,160,-186,-339,160,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,160,160,160,160,-340,160,-340,-28,-73,-69,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,-287,160,160,-340,160,160,-221,-220,160,160,-237,160,160,160,160,160,-87,-74,160,-233,-234,-236,160,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,160,-12,160,-287,160,160,160,-340,160,160,160,-222,160,-224,160,-86,-75,160,-232,-235,-340,-201,-340,-68,160,160,160,-340,-28,-287,-223,160,160,160,160,160,160,-11,-287,160,160,-225,-87,-74,-227,-228,160,-340,160,160,160,-226,-229,160,160,-231,-230,]),'LNOT':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,161,-340,-27,-28,-185,-338,161,161,161,-340,161,-287,-288,-289,-286,161,161,161,161,-290,-291,161,-340,-28,161,-186,-339,161,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,161,161,161,161,-340,161,-340,-28,-73,-69,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,-287,161,161,-340,161,161,-221,-220,161,161,-237,161,161,161,161,161,-87,-74,161,-233,-234,-236,161,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,161,-12,161,-287,161,161,161,-340,161,161,161,-222,161,-224,161,-86,-75,161,-232,-235,-340,-201,-340,-68,161,161,161,-340,-28,-287,-223,161,161,161,161,161,161,-11,-287,161,161,-225,-87,-74,-227,-228,161,-340,161,161,161,-226,-229,161,161,-231,-230,]),'OFFSETOF':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,165,-340,-27,-28,-185,-338,165,165,165,-340,165,-287,-288,-289,-286,165,165,165,165,-290,-291,165,-340,-28,165,-186,-339,165,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,165,165,165,165,-340,165,-340,-28,-73,-69,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,-287,165,165,-340,165,165,-221,-220,165,165,-237,165,165,165,165,165,-87,-74,165,-233,-234,-236,165,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,165,-12,165,-287,165,165,165,-340,165,165,165,-222,165,-224,165,-86,-75,165,-232,-235,-340,-201,-340,-68,165,165,165,-340,-28,-287,-223,165,165,165,165,165,165,-11,-287,165,165,-225,-87,-74,-227,-228,165,-340,165,165,165,-226,-229,165,165,-231,-230,]),'INT_CONST_DEC':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,166,-340,-27,-28,-185,-338,166,166,166,-340,166,-287,-288,-289,-286,166,166,166,166,-290,-291,166,-340,-28,166,-186,-339,166,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,166,166,166,166,-340,166,-340,-28,-73,-69,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,-287,166,166,-340,166,166,-221,-220,166,166,-237,166,166,166,166,166,-87,-74,166,-233,-234,-236,166,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,166,-12,166,-287,166,166,166,-340,166,166,166,-222,166,-224,166,-86,-75,166,-232,-235,-340,-201,-340,-68,166,166,166,-340,-28,-287,-223,166,166,166,166,166,166,-11,-287,166,166,-225,-87,-74,-227,-228,166,-340,166,166,166,-226,-229,166,166,-231,-230,]),'INT_CONST_OCT':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,167,-340,-27,-28,-185,-338,167,167,167,-340,167,-287,-288,-289,-286,167,167,167,167,-290,-291,167,-340,-28,167,-186,-339,167,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,167,167,167,167,-340,167,-340,-28,-73,-69,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,-287,167,167,-340,167,167,-221,-220,167,167,-237,167,167,167,167,167,-87,-74,167,-233,-234,-236,167,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,167,-12,167,-287,167,167,167,-340,167,167,167,-222,167,-224,167,-86,-75,167,-232,-235,-340,-201,-340,-68,167,167,167,-340,-28,-287,-223,167,167,167,167,167,167,-11,-287,167,167,-225,-87,-74,-227,-228,167,-340,167,167,167,-226,-229,167,167,-231,-230,]),'INT_CONST_HEX':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,168,-340,-27,-28,-185,-338,168,168,168,-340,168,-287,-288,-289,-286,168,168,168,168,-290,-291,168,-340,-28,168,-186,-339,168,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,168,168,168,168,-340,168,-340,-28,-73,-69,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,-287,168,168,-340,168,168,-221,-220,168,168,-237,168,168,168,168,168,-87,-74,168,-233,-234,-236,168,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,168,-12,168,-287,168,168,168,-340,168,168,168,-222,168,-224,168,-86,-75,168,-232,-235,-340,-201,-340,-68,168,168,168,-340,-28,-287,-223,168,168,168,168,168,168,-11,-287,168,168,-225,-87,-74,-227,-228,168,-340,168,168,168,-226,-229,168,168,-231,-230,]),'INT_CONST_BIN':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,169,-340,-27,-28,-185,-338,169,169,169,-340,169,-287,-288,-289,-286,169,169,169,169,-290,-291,169,-340,-28,169,-186,-339,169,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,169,169,169,169,-340,169,-340,-28,-73,-69,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,-287,169,169,-340,169,169,-221,-220,169,169,-237,169,169,169,169,169,-87,-74,169,-233,-234,-236,169,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,169,-12,169,-287,169,169,169,-340,169,169,169,-222,169,-224,169,-86,-75,169,-232,-235,-340,-201,-340,-68,169,169,169,-340,-28,-287,-223,169,169,169,169,169,169,-11,-287,169,169,-225,-87,-74,-227,-228,169,-340,169,169,169,-226,-229,169,169,-231,-230,]),'INT_CONST_CHAR':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,170,-340,-27,-28,-185,-338,170,170,170,-340,170,-287,-288,-289,-286,170,170,170,170,-290,-291,170,-340,-28,170,-186,-339,170,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,170,170,170,170,-340,170,-340,-28,-73,-69,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,-287,170,170,-340,170,170,-221,-220,170,170,-237,170,170,170,170,170,-87,-74,170,-233,-234,-236,170,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,170,-12,170,-287,170,170,170,-340,170,170,170,-222,170,-224,170,-86,-75,170,-232,-235,-340,-201,-340,-68,170,170,170,-340,-28,-287,-223,170,170,170,170,170,170,-11,-287,170,170,-225,-87,-74,-227,-228,170,-340,170,170,170,-226,-229,170,170,-231,-230,]),'FLOAT_CONST':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,171,-340,-27,-28,-185,-338,171,171,171,-340,171,-287,-288,-289,-286,171,171,171,171,-290,-291,171,-340,-28,171,-186,-339,171,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,171,171,171,171,-340,171,-340,-28,-73,-69,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,-287,171,171,-340,171,171,-221,-220,171,171,-237,171,171,171,171,171,-87,-74,171,-233,-234,-236,171,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,171,-12,171,-287,171,171,171,-340,171,171,171,-222,171,-224,171,-86,-75,171,-232,-235,-340,-201,-340,-68,171,171,171,-340,-28,-287,-223,171,171,171,171,171,171,-11,-287,171,171,-225,-87,-74,-227,-228,171,-340,171,171,171,-226,-229,171,171,-231,-230,]),'HEX_FLOAT_CONST':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,172,-340,-27,-28,-185,-338,172,172,172,-340,172,-287,-288,-289,-286,172,172,172,172,-290,-291,172,-340,-28,172,-186,-339,172,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,172,172,172,172,-340,172,-340,-28,-73,-69,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,-287,172,172,-340,172,172,-221,-220,172,172,-237,172,172,172,172,172,-87,-74,172,-233,-234,-236,172,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,172,-12,172,-287,172,172,172,-340,172,172,172,-222,172,-224,172,-86,-75,172,-232,-235,-340,-201,-340,-68,172,172,172,-340,-28,-287,-223,172,172,172,172,172,172,-11,-287,172,172,-225,-87,-74,-227,-228,172,-340,172,172,172,-226,-229,172,172,-231,-230,]),'CHAR_CONST':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,173,-340,-27,-28,-185,-338,173,173,173,-340,173,-287,-288,-289,-286,173,173,173,173,-290,-291,173,-340,-28,173,-186,-339,173,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,173,173,173,173,-340,173,-340,-28,-73,-69,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,-287,173,173,-340,173,173,-221,-220,173,173,-237,173,173,173,173,173,-87,-74,173,-233,-234,-236,173,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,173,-12,173,-287,173,173,173,-340,173,173,173,-222,173,-224,173,-86,-75,173,-232,-235,-340,-201,-340,-68,173,173,173,-340,-28,-287,-223,173,173,173,173,173,173,-11,-287,173,173,-225,-87,-74,-227,-228,173,-340,173,173,173,-226,-229,173,173,-231,-230,]),'WCHAR_CONST':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,174,-340,-27,-28,-185,-338,174,174,174,-340,174,-287,-288,-289,-286,174,174,174,174,-290,-291,174,-340,-28,174,-186,-339,174,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,174,174,174,174,-340,174,-340,-28,-73,-69,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,-287,174,174,-340,174,174,-221,-220,174,174,-237,174,174,174,174,174,-87,-74,174,-233,-234,-236,174,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,174,-12,174,-287,174,174,174,-340,174,174,174,-222,174,-224,174,-86,-75,174,-232,-235,-340,-201,-340,-68,174,174,174,-340,-28,-287,-223,174,174,174,174,174,174,-11,-287,174,174,-225,-87,-74,-227,-228,174,-340,174,174,174,-226,-229,174,174,-231,-230,]),'U8CHAR_CONST':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,175,-340,-27,-28,-185,-338,175,175,175,-340,175,-287,-288,-289,-286,175,175,175,175,-290,-291,175,-340,-28,175,-186,-339,175,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,175,175,175,175,-340,175,-340,-28,-73,-69,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,-287,175,175,-340,175,175,-221,-220,175,175,-237,175,175,175,175,175,-87,-74,175,-233,-234,-236,175,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,175,-12,175,-287,175,175,175,-340,175,175,175,-222,175,-224,175,-86,-75,175,-232,-235,-340,-201,-340,-68,175,175,175,-340,-28,-287,-223,175,175,175,175,175,175,-11,-287,175,175,-225,-87,-74,-227,-228,175,-340,175,175,175,-226,-229,175,175,-231,-230,]),'U16CHAR_CONST':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,176,-340,-27,-28,-185,-338,176,176,176,-340,176,-287,-288,-289,-286,176,176,176,176,-290,-291,176,-340,-28,176,-186,-339,176,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,176,176,176,176,-340,176,-340,-28,-73,-69,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,-287,176,176,-340,176,176,-221,-220,176,176,-237,176,176,176,176,176,-87,-74,176,-233,-234,-236,176,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,176,-12,176,-287,176,176,176,-340,176,176,176,-222,176,-224,176,-86,-75,176,-232,-235,-340,-201,-340,-68,176,176,176,-340,-28,-287,-223,176,176,176,176,176,176,-11,-287,176,176,-225,-87,-74,-227,-228,176,-340,176,176,176,-226,-229,176,176,-231,-230,]),'U32CHAR_CONST':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,177,-340,-27,-28,-185,-338,177,177,177,-340,177,-287,-288,-289,-286,177,177,177,177,-290,-291,177,-340,-28,177,-186,-339,177,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,177,177,177,177,-340,177,-340,-28,-73,-69,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,-287,177,177,-340,177,177,-221,-220,177,177,-237,177,177,177,177,177,-87,-74,177,-233,-234,-236,177,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,177,-12,177,-287,177,177,177,-340,177,177,177,-222,177,-224,177,-86,-75,177,-232,-235,-340,-201,-340,-68,177,177,177,-340,-28,-287,-223,177,177,177,177,177,177,-11,-287,177,177,-225,-87,-74,-227,-228,177,-340,177,177,177,-226,-229,177,177,-231,-230,]),'STRING_LITERAL':([15,51,52,53,81,90,91,92,94,95,114,115,116,121,126,128,135,136,138,139,141,143,147,148,149,150,153,154,155,156,160,161,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,263,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,407,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,139,139,-340,-27,-28,-185,-338,139,139,139,-340,263,-328,139,263,-287,-288,-289,-286,139,139,139,139,-290,-291,139,-340,-28,139,-186,-339,139,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,139,139,139,139,-340,139,-340,-28,-73,-329,139,-69,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,-287,139,139,-340,139,139,-221,-220,139,139,-237,139,139,139,139,139,-87,-74,139,-233,-234,-236,139,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,139,-12,139,-287,139,139,139,263,-340,139,139,139,-222,139,-224,139,-86,-75,139,-232,-235,-340,-201,-340,-68,139,139,139,-340,-28,-287,-223,139,139,139,139,139,139,-11,-287,139,139,-225,-87,-74,-227,-228,139,-340,139,139,139,-226,-229,139,139,-231,-230,]),'WSTRING_LITERAL':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,164,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,178,-340,-27,-28,-185,-338,178,178,178,-340,178,-287,-288,-289,-286,178,178,178,178,-290,-291,300,-330,-331,-332,-333,178,-340,-28,178,-186,-339,178,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,178,178,178,178,-340,178,-340,-28,-73,-69,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,-334,-335,-336,-337,-287,178,178,-340,178,178,-221,-220,178,178,-237,178,178,178,178,178,-87,-74,178,-233,-234,-236,178,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,178,-12,178,-287,178,178,178,-340,178,178,178,-222,178,-224,178,-86,-75,178,-232,-235,-340,-201,-340,-68,178,178,178,-340,-28,-287,-223,178,178,178,178,178,178,-11,-287,178,178,-225,-87,-74,-227,-228,178,-340,178,178,178,-226,-229,178,178,-231,-230,]),'U8STRING_LITERAL':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,164,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,179,-340,-27,-28,-185,-338,179,179,179,-340,179,-287,-288,-289,-286,179,179,179,179,-290,-291,301,-330,-331,-332,-333,179,-340,-28,179,-186,-339,179,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,179,179,179,179,-340,179,-340,-28,-73,-69,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,-334,-335,-336,-337,-287,179,179,-340,179,179,-221,-220,179,179,-237,179,179,179,179,179,-87,-74,179,-233,-234,-236,179,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,179,-12,179,-287,179,179,179,-340,179,179,179,-222,179,-224,179,-86,-75,179,-232,-235,-340,-201,-340,-68,179,179,179,-340,-28,-287,-223,179,179,179,179,179,179,-11,-287,179,179,-225,-87,-74,-227,-228,179,-340,179,179,179,-226,-229,179,179,-231,-230,]),'U16STRING_LITERAL':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,164,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,180,-340,-27,-28,-185,-338,180,180,180,-340,180,-287,-288,-289,-286,180,180,180,180,-290,-291,302,-330,-331,-332,-333,180,-340,-28,180,-186,-339,180,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,180,180,180,180,-340,180,-340,-28,-73,-69,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,-334,-335,-336,-337,-287,180,180,-340,180,180,-221,-220,180,180,-237,180,180,180,180,180,-87,-74,180,-233,-234,-236,180,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,180,-12,180,-287,180,180,180,-340,180,180,180,-222,180,-224,180,-86,-75,180,-232,-235,-340,-201,-340,-68,180,180,180,-340,-28,-287,-223,180,180,180,180,180,180,-11,-287,180,180,-225,-87,-74,-227,-228,180,-340,180,180,180,-226,-229,180,180,-231,-230,]),'U32STRING_LITERAL':([15,51,52,53,81,90,91,94,95,114,115,116,121,126,128,135,136,141,147,148,149,150,153,154,155,156,160,161,164,178,179,180,181,182,183,184,195,197,208,221,222,223,224,225,226,227,228,229,230,231,232,234,238,242,247,256,257,258,259,262,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,300,301,302,303,306,309,310,323,332,347,355,356,358,360,361,362,365,366,367,369,370,371,372,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,392,393,394,397,400,401,402,405,448,455,457,467,469,470,471,474,479,480,482,483,484,487,489,498,499,500,503,510,511,512,520,524,525,526,527,528,529,532,533,543,544,545,552,553,554,555,556,559,562,565,570,572,579,580,582,584,585,586,],[-71,-131,-132,-133,-134,-90,-72,181,-340,-27,-28,-185,-338,181,181,181,-340,181,-287,-288,-289,-286,181,181,181,181,-290,-291,303,-330,-331,-332,-333,181,-340,-28,181,-186,-339,181,-219,-217,-218,-78,-79,-80,-81,-82,-83,-84,-85,181,181,181,181,-340,181,-340,-28,-73,-69,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,-334,-335,-336,-337,-287,181,181,-340,181,181,-221,-220,181,181,-237,181,181,181,181,181,-87,-74,181,-233,-234,-236,181,-244,-245,-246,-247,-248,-249,-250,-251,-252,-253,-254,-11,181,-12,181,-287,181,181,181,-340,181,181,181,-222,181,-224,181,-86,-75,181,-232,-235,-340,-201,-340,-68,181,181,181,-340,-28,-287,-223,181,181,181,181,181,181,-11,-287,181,181,-225,-87,-74,-227,-228,181,-340,181,181,181,-226,-229,181,181,-231,-230,]),'ELSE':([15,91,208,225,226,227,228,229,230,232,262,267,355,361,370,371,374,375,377,469,471,479,480,483,484,499,524,552,553,554,555,556,579,580,585,586,],[-71,-72,-339,-78,-79,-80,-81,-82,-83,-85,-73,-69,-221,-237,-87,-84,-233,-234,-236,-222,-224,-86,-84,-232,-235,-68,-223,-225,570,-84,-227,-228,-226,-229,-231,-230,]),'PPPRAGMASTR':([15,],[91,]),'EQUALS':([19,28,73,86,87,88,89,97,111,130,132,139,140,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,202,208,233,250,252,263,291,292,293,295,296,297,300,301,302,303,311,312,395,396,403,404,406,429,431,432,433,434,439,440,490,492,493,494,497,501,502,505,506,508,509,534,535,536,561,563,574,],[-52,-29,-181,135,-182,-54,-37,-53,195,-181,-55,-328,-30,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,332,-339,-315,379,-38,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-35,-36,489,-202,-43,-44,-308,-295,-296,-297,-298,-299,-31,-34,-203,-205,-39,-42,-278,-293,-294,-284,-285,-32,-33,-204,-40,-41,-302,-309,-303,]),'COMMA':([19,24,25,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,51,52,53,54,55,56,57,58,59,60,73,74,75,76,77,78,81,84,85,86,87,88,89,97,104,106,108,110,111,113,114,115,116,118,119,122,123,130,132,139,140,142,143,144,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,187,189,190,191,192,196,197,200,201,202,206,208,212,214,216,233,239,248,249,250,252,253,254,255,263,265,291,292,293,295,296,297,300,301,302,303,311,312,315,316,317,318,319,320,321,324,325,326,327,328,329,330,331,334,336,337,340,341,342,344,345,346,348,349,350,352,353,354,376,391,403,404,406,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,438,439,440,444,445,446,447,459,460,461,462,463,464,468,472,473,475,476,477,485,486,488,493,494,497,501,502,505,506,508,509,515,516,518,522,523,531,535,536,537,538,539,546,547,548,549,550,551,557,560,561,563,566,567,574,576,577,578,],[-52,-128,-102,-29,-107,-340,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-181,-98,-99,-100,-101,-104,-134,134,-135,-137,-182,-54,-37,-53,-103,-129,194,-139,-141,-183,-27,-28,-185,-169,-170,-149,-150,-181,-55,-328,-30,266,-306,-255,-256,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,313,314,-189,-194,-340,-184,-186,331,-174,-179,-152,-339,-145,-147,-340,-315,365,-238,-242,-277,-38,-136,-138,-196,-329,365,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-35,-36,-191,-192,-193,-207,-56,-1,-2,-45,-209,-140,-142,331,331,-171,-175,-154,-156,-151,-143,-144,-148,466,-164,-166,-146,-130,-206,-207,-177,-178,365,487,-43,-44,-308,365,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,-276,365,503,-295,-313,-296,-297,-298,-299,507,-31,-34,-190,-195,-57,-208,-172,-173,-176,-180,-153,-155,-168,365,-240,-239,365,365,-243,-197,-199,-39,-42,-278,-293,-294,-284,-285,-32,-33,-210,-216,-214,-165,-167,-198,-40,-41,562,-257,-314,-50,-51,-212,-211,-213,-215,365,-200,-302,-309,-46,-49,-303,365,-47,-48,]),'RPAREN':([19,24,25,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,51,52,53,54,55,56,57,58,59,60,74,75,76,77,78,81,88,89,93,96,97,104,106,113,114,115,116,118,119,122,123,132,133,137,138,139,140,142,143,144,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,185,186,187,188,189,190,191,192,196,197,206,208,212,214,215,216,217,218,239,248,249,250,252,260,261,263,264,265,288,291,292,293,295,296,297,300,301,302,303,311,312,315,316,317,318,319,320,321,322,324,325,330,334,336,337,340,341,342,348,349,350,351,352,353,354,355,357,363,364,403,404,406,407,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,428,429,430,431,432,433,434,435,436,437,439,440,443,444,445,446,447,449,450,451,452,453,454,458,459,460,463,464,472,473,475,476,477,485,493,494,497,501,502,505,506,508,509,513,514,515,516,518,521,535,536,538,539,540,541,546,547,548,549,550,551,557,559,561,563,566,567,572,573,574,575,577,578,581,583,],[-52,-128,-102,-29,-107,-340,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-98,-99,-100,-101,-104,-134,-54,-37,140,-340,-53,-103,-129,-183,-27,-28,-185,-169,-170,-149,-150,-55,252,-340,262,-328,-30,267,-306,-255,-256,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,311,312,-187,-17,-18,-189,-194,-340,-184,-186,-152,-339,-145,-147,349,-340,353,354,-14,-238,-242,-277,-38,403,404,-329,405,406,429,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-35,-36,-191,-192,-193,-207,-56,-1,-2,-340,-45,-209,-171,-154,-156,-151,-143,-144,-148,-146,-130,-206,-340,-207,-177,-178,-221,-13,473,474,-43,-44,-308,499,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,-276,502,-295,-313,-296,-297,-298,-299,504,505,506,-31,-34,-188,-190,-195,-57,-208,-340,515,516,-207,-23,-24,-340,-172,-173,-153,-155,525,-240,-239,526,527,-243,-39,-42,-278,-293,-294,-284,-285,-32,-33,546,547,-210,-216,-214,551,-40,-41,-257,-314,563,-310,-50,-51,-212,-211,-213,-215,571,-340,-302,-309,-46,-49,-340,582,-303,-311,-47,-48,584,-312,]),'COLON':([19,24,28,31,32,33,35,38,39,40,41,42,43,44,45,46,47,48,49,51,52,53,81,87,88,89,97,106,118,119,122,123,130,132,139,140,143,144,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,206,208,209,212,214,233,235,248,249,250,252,263,291,292,293,295,296,297,300,301,302,303,311,312,330,334,336,337,340,341,342,346,348,349,353,354,359,403,404,406,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,439,440,459,460,463,464,466,473,475,485,493,494,497,501,502,505,506,508,509,535,536,538,561,563,574,],[-52,-128,-29,-125,-126,-127,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-131,-132,-133,-134,-182,-54,-37,-53,-129,-169,-170,-149,-150,-181,-55,-328,-30,-306,-255,-256,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-152,-339,347,-145,-147,358,360,-238,-242,-277,-38,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-35,-36,-171,-154,-156,-151,-143,-144,-148,467,-146,-130,-177,-178,470,-43,-44,-308,500,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,-276,-295,-296,-297,-298,-299,-31,-34,-172,-173,-153,-155,347,-240,-239,-243,-39,-42,-278,-293,-294,-284,-285,-32,-33,-40,-41,-257,-302,-309,-303,]),'LBRACKET':([19,24,25,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,51,52,53,54,55,56,57,58,59,60,74,75,76,77,78,81,88,89,97,104,106,113,114,115,116,118,119,121,122,123,132,139,140,143,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,192,196,197,206,208,212,214,216,233,252,256,263,291,292,300,301,302,303,311,312,318,319,322,324,325,330,334,336,337,340,341,342,348,349,351,352,353,354,395,396,403,404,406,429,431,432,433,434,439,440,446,447,452,459,460,463,464,487,490,492,493,494,498,501,502,508,509,515,516,518,534,535,536,540,541,546,547,548,549,550,551,561,562,563,566,567,574,575,577,578,583,],[95,-128,-102,-29,-107,-340,-125,-126,-127,-129,-241,-113,-114,-115,-116,-117,-118,-119,-120,-121,-122,-123,-124,-131,-132,-133,-105,-106,-108,-109,-110,-111,-112,-98,-99,-100,-101,-104,-134,136,-37,95,-103,-129,-183,-27,-28,-185,-169,-170,-338,-149,-150,136,-328,-30,-306,287,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,323,-184,-186,-152,-339,-145,-147,323,-315,-38,397,-329,-300,-301,-334,-335,-336,-337,-35,-36,323,448,323,-45,457,-171,-154,-156,-151,-143,-144,-148,-146,-130,323,323,-177,-178,397,-202,-43,-44,-308,-295,-296,-297,-298,-299,-31,-34,448,457,323,-172,-173,-153,-155,397,-203,-205,-39,-42,397,-293,-294,-32,-33,-210,-216,-214,-204,-40,-41,565,-310,-50,-51,-212,-211,-213,-215,-302,397,-309,-46,-49,-303,-311,-47,-48,-312,]),'RBRACKET':([51,52,53,81,95,114,115,116,136,139,143,144,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,184,197,208,248,249,250,257,259,263,291,292,293,295,296,297,300,301,302,303,305,306,307,308,323,399,400,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,429,431,432,433,434,441,442,448,455,456,457,473,475,485,491,495,496,497,501,502,505,506,510,512,517,519,520,538,542,543,561,563,568,569,574,576,],[-131,-132,-133,-134,-340,-27,-28,-185,-340,-328,-306,-255,-256,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-340,-28,-186,-339,-238,-242,-277,-340,-28,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,439,440,-3,-4,-340,493,494,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,-276,501,-295,-296,-297,-298,-299,508,509,-340,-340,518,-340,-240,-239,-243,534,535,536,-278,-293,-294,-284,-285,-340,-28,548,549,550,-257,566,567,-302,-309,577,578,-303,583,]),'PERIOD':([121,139,143,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,256,263,291,292,300,301,302,303,395,396,406,429,431,432,433,434,487,490,492,498,501,502,534,540,541,561,562,563,574,575,583,],[-338,-328,-306,289,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,398,-329,-300,-301,-334,-335,-336,-337,398,-202,-308,-295,-296,-297,-298,-299,398,-203,-205,398,-293,-294,-204,564,-310,-302,398,-309,-303,-311,-312,]),'ARROW':([139,143,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,263,291,292,300,301,302,303,406,429,431,432,433,434,501,502,561,563,574,],[-328,-306,290,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-329,-300,-301,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-293,-294,-302,-309,-303,]),'CONDOP':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,268,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,-276,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'DIVIDE':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,270,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,270,270,270,270,270,270,270,270,270,270,270,270,270,270,270,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'MOD':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,271,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,271,271,271,271,271,271,271,271,271,271,271,271,271,271,271,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'RSHIFT':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,274,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,274,274,274,274,274,274,274,274,274,274,274,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'LSHIFT':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,275,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,275,275,275,275,275,275,275,275,275,275,275,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'LT':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,276,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,276,276,276,276,276,276,276,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'LE':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,277,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,277,277,277,277,277,277,277,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'GE':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,278,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,278,278,278,278,278,278,278,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'GT':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,279,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,279,279,279,279,279,279,279,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'EQ':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,280,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,280,280,280,280,280,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'NE':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,281,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,281,281,281,281,281,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'OR':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,283,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,283,283,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'XOR':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,284,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,284,-274,284,284,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'LAND':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,285,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,285,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'LOR':([139,143,145,146,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,286,-258,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,-277,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-259,-260,-261,-262,-263,-264,-265,-266,-267,-268,-269,-270,-271,-272,-273,-274,-275,-276,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'XOREQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,380,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'TIMESEQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,381,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'DIVEQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,382,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'MODEQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,383,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'PLUSEQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,384,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'MINUSEQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,385,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'LSHIFTEQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,386,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'RSHIFTEQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,387,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'ANDEQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,388,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'OREQUAL':([139,143,151,152,158,159,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,208,233,250,263,291,292,293,295,296,297,300,301,302,303,406,429,431,432,433,434,497,501,502,505,506,561,563,574,],[-328,-306,-277,-279,-292,-315,-304,-305,-307,-316,-317,-318,-319,-320,-321,-322,-323,-324,-325,-326,-327,-330,-331,-332,-333,-339,-315,389,-329,-300,-301,-280,-281,-282,-283,-334,-335,-336,-337,-308,-295,-296,-297,-298,-299,-278,-293,-294,-284,-285,-302,-309,-303,]),'ELLIPSIS':([313,],[443,]),} + +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'translation_unit_or_empty':([0,],[1,]),'translation_unit':([0,],[2,]),'empty':([0,11,12,21,22,23,26,27,30,34,69,70,71,73,95,96,101,128,136,137,182,183,192,209,216,221,242,256,257,258,322,323,351,358,360,369,372,448,449,455,457,458,470,482,487,498,510,511,525,526,527,529,559,562,570,572,582,584,],[3,66,83,99,99,99,107,99,114,99,83,107,99,66,114,188,99,220,114,188,307,114,320,343,320,357,357,392,307,114,453,114,453,357,357,357,357,114,188,307,307,453,357,357,533,533,307,114,357,357,357,357,357,533,357,357,357,357,]),'external_declaration':([0,2,],[4,64,]),'function_definition':([0,2,],[5,5,]),'declaration':([0,2,11,67,73,128,221,372,],[6,6,68,129,68,223,223,482,]),'pp_directive':([0,2,],[7,7,]),'pppragma_directive':([0,2,124,128,203,204,205,221,242,333,335,358,360,369,470,525,526,527,570,582,584,],[8,8,211,231,211,211,211,231,371,211,211,371,371,480,371,554,371,371,371,371,371,]),'static_assert':([0,2,128,221,242,358,360,369,470,525,526,527,570,582,584,],[10,10,232,232,232,232,232,232,232,232,232,232,232,232,232,]),'id_declarator':([0,2,12,17,26,69,70,82,134,192,194,209,322,466,],[11,11,73,93,111,130,111,93,130,315,130,130,93,130,]),'declaration_specifiers':([0,2,11,67,73,96,128,137,221,313,322,351,372,449,458,],[12,12,69,69,69,192,69,192,69,192,192,192,69,192,192,]),'decl_body':([0,2,11,67,73,128,221,372,],[13,13,13,13,13,13,13,13,]),'direct_id_declarator':([0,2,12,17,20,26,69,70,80,82,134,192,194,209,318,322,452,466,],[19,19,19,19,97,19,19,19,97,19,19,19,19,19,97,19,97,19,]),'pointer':([0,2,12,17,26,69,70,82,113,134,192,194,209,216,322,351,466,],[20,20,80,20,20,80,20,80,196,80,318,80,80,352,452,352,80,]),'type_qualifier':([0,2,11,12,21,22,23,27,30,34,67,69,71,73,95,96,101,115,124,125,126,128,136,137,141,183,184,192,203,204,205,209,213,216,221,238,258,259,294,298,299,304,313,322,323,333,335,351,372,448,449,458,511,512,],[21,21,21,74,21,21,21,21,116,21,21,74,21,21,116,21,21,197,116,116,116,21,116,21,116,116,197,74,116,116,116,341,197,341,21,116,116,197,116,116,116,116,21,21,116,116,116,21,21,116,21,21,116,197,]),'storage_class_specifier':([0,2,11,12,21,22,23,27,34,67,69,71,73,96,101,128,137,192,221,313,322,351,372,449,458,],[22,22,22,75,22,22,22,22,22,22,75,22,22,22,22,22,22,75,22,22,22,22,22,22,22,]),'function_specifier':([0,2,11,12,21,22,23,27,34,67,69,71,73,96,101,128,137,192,221,313,322,351,372,449,458,],[23,23,23,76,23,23,23,23,23,23,76,23,23,23,23,23,23,76,23,23,23,23,23,23,23,]),'type_specifier_no_typeid':([0,2,11,12,26,67,69,70,73,96,124,125,126,128,137,141,192,193,203,204,205,209,213,216,221,238,294,298,299,304,313,322,333,335,351,372,449,458,],[24,24,24,77,24,24,77,24,24,24,24,24,24,24,24,24,77,24,24,24,24,340,24,340,24,24,24,24,24,24,24,24,24,24,24,24,24,24,]),'type_specifier':([0,2,11,26,67,70,73,96,124,125,126,128,137,141,193,203,204,205,213,221,238,294,298,299,304,313,322,333,335,351,372,449,458,],[25,25,25,104,25,104,25,25,212,212,212,25,25,212,104,212,212,212,348,25,212,212,212,212,212,25,25,212,212,25,25,25,25,]),'declaration_specifiers_no_type':([0,2,11,21,22,23,27,34,67,71,73,96,101,128,137,221,313,322,351,372,449,458,],[26,26,70,100,100,100,100,100,70,100,70,193,100,70,193,70,193,193,193,70,193,193,]),'alignment_specifier':([0,2,11,12,21,22,23,27,34,67,69,71,73,96,101,124,125,126,128,137,141,192,203,204,205,209,216,221,238,294,298,299,304,313,322,333,335,351,372,449,458,],[27,27,27,78,27,27,27,27,27,27,78,27,27,27,27,214,214,214,27,27,214,78,214,214,214,342,342,27,214,214,214,214,214,27,27,214,214,27,27,27,27,]),'typedef_name':([0,2,11,26,67,70,73,96,124,125,126,128,137,141,193,203,204,205,213,221,238,294,298,299,304,313,322,333,335,351,372,449,458,],[31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,]),'enum_specifier':([0,2,11,26,67,70,73,96,124,125,126,128,137,141,193,203,204,205,213,221,238,294,298,299,304,313,322,333,335,351,372,449,458,],[32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,]),'struct_or_union_specifier':([0,2,11,26,67,70,73,96,124,125,126,128,137,141,193,203,204,205,213,221,238,294,298,299,304,313,322,333,335,351,372,449,458,],[33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,]),'atomic_specifier':([0,2,11,21,22,23,26,27,34,67,70,71,73,96,101,124,125,126,128,137,141,193,203,204,205,213,221,238,294,298,299,304,313,322,333,335,351,372,449,458,],[34,34,71,101,101,101,106,101,101,71,106,101,71,34,101,106,106,106,71,34,106,106,106,106,106,106,71,106,106,106,106,106,34,34,106,106,34,71,34,34,]),'struct_or_union':([0,2,11,26,67,70,73,96,124,125,126,128,137,141,193,203,204,205,213,221,238,294,298,299,304,313,322,333,335,351,372,449,458,],[37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,]),'declaration_list_opt':([11,73,],[65,131,]),'declaration_list':([11,73,],[67,67,]),'init_declarator_list_opt':([12,69,],[79,79,]),'init_declarator_list':([12,69,],[84,84,]),'init_declarator':([12,69,134,194,],[85,85,253,326,]),'declarator':([12,69,134,194,209,466,],[86,86,86,86,346,346,]),'typeid_declarator':([12,69,82,134,194,209,466,],[87,87,133,87,87,87,87,]),'direct_typeid_declarator':([12,69,80,82,134,194,209,466,],[88,88,132,88,88,88,88,88,]),'declaration_specifiers_no_type_opt':([21,22,23,27,34,71,101,],[98,102,103,112,117,117,117,]),'id_init_declarator_list_opt':([26,70,],[105,105,]),'id_init_declarator_list':([26,70,],[108,108,]),'id_init_declarator':([26,70,],[110,110,]),'type_qualifier_list_opt':([30,95,136,183,258,323,448,511,],[113,182,257,309,401,455,510,544,]),'type_qualifier_list':([30,95,124,125,126,136,141,183,203,204,205,238,258,294,298,299,304,323,333,335,448,511,],[115,184,213,213,213,259,213,115,213,213,213,213,115,213,213,213,213,115,213,213,512,115,]),'brace_open':([36,37,65,118,119,122,123,128,131,135,195,221,238,242,358,360,369,393,405,470,474,504,505,525,526,527,532,570,582,584,],[120,124,128,198,199,203,204,128,128,256,256,128,128,128,128,128,128,256,498,128,498,498,498,128,128,128,256,128,128,128,]),'compound_statement':([65,128,131,221,238,242,358,360,369,470,525,526,527,570,582,584,],[127,227,251,227,363,227,227,227,227,227,227,227,227,227,227,227,]),'unified_string_literal':([92,94,126,128,135,141,153,154,155,156,182,195,221,234,238,242,247,257,266,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,405,455,457,467,470,474,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[138,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,407,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,]),'constant_expression':([94,126,234,332,347,397,467,],[142,218,359,462,468,491,523,]),'conditional_expression':([94,126,128,135,141,182,195,221,234,238,242,247,257,268,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,455,457,467,470,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[144,144,249,249,249,249,249,249,144,249,249,249,249,249,249,249,249,249,249,249,144,144,249,249,249,249,249,249,249,249,249,249,144,249,249,249,249,144,249,249,538,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,]),'binary_expression':([94,126,128,135,141,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,455,457,467,470,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[145,145,145,145,145,145,145,145,145,145,145,145,145,145,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,]),'cast_expression':([94,126,128,135,141,155,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,405,455,457,467,470,474,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[146,146,146,146,146,296,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,497,146,146,146,146,497,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,]),'unary_expression':([94,126,128,135,141,153,154,155,156,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,405,455,457,467,470,474,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[151,151,250,250,250,293,295,151,297,250,250,250,151,250,250,250,250,250,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,250,250,250,250,250,250,151,151,250,250,250,250,250,250,250,250,250,250,151,250,250,151,250,250,151,250,151,250,151,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,]),'postfix_expression':([94,126,128,135,141,153,154,155,156,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,405,455,457,467,470,474,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,]),'unary_operator':([94,126,128,135,141,153,154,155,156,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,405,455,457,467,470,474,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,]),'primary_expression':([94,126,128,135,141,153,154,155,156,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,405,455,457,467,470,474,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,]),'identifier':([94,96,126,128,135,137,141,153,154,155,156,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,314,332,347,358,360,362,365,366,367,369,372,378,393,397,398,401,402,405,449,455,457,467,470,474,482,500,503,507,510,525,526,527,528,529,532,544,545,559,564,565,570,572,582,584,],[162,191,162,162,162,191,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,445,162,162,162,162,162,162,162,162,162,162,162,162,162,492,162,162,162,191,162,162,162,162,162,162,162,162,541,162,162,162,162,162,162,162,162,162,162,575,162,162,162,162,162,]),'constant':([94,126,128,135,141,153,154,155,156,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,405,455,457,467,470,474,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,]),'unified_wstring_literal':([94,126,128,135,141,153,154,155,156,182,195,221,234,238,242,247,257,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,294,298,309,310,332,347,358,360,362,365,366,367,369,372,378,393,397,401,402,405,455,457,467,470,474,482,500,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,]),'parameter_type_list':([96,137,322,351,449,458,],[185,260,454,454,513,454,]),'identifier_list_opt':([96,137,449,],[186,261,514,]),'parameter_list':([96,137,322,351,449,458,],[187,187,187,187,187,187,]),'identifier_list':([96,137,449,],[189,189,189,]),'parameter_declaration':([96,137,313,322,351,449,458,],[190,190,444,190,190,190,190,]),'enumerator_list':([120,198,199,],[200,328,329,]),'enumerator':([120,198,199,331,],[201,201,201,461,]),'struct_declaration_list':([124,203,204,],[205,333,335,]),'brace_close':([124,200,203,204,205,219,328,329,333,335,390,487,537,562,],[206,330,334,336,337,355,459,460,463,464,486,531,561,574,]),'struct_declaration':([124,203,204,205,333,335,],[207,207,207,338,338,338,]),'specifier_qualifier_list':([124,125,126,141,203,204,205,238,294,298,299,304,333,335,],[209,216,216,216,209,209,209,216,216,216,216,216,209,209,]),'type_name':([125,126,141,238,294,298,299,304,],[215,217,264,364,435,436,437,438,]),'block_item_list_opt':([128,],[219,]),'block_item_list':([128,],[221,]),'block_item':([128,221,],[222,356,]),'statement':([128,221,242,358,360,369,470,525,526,527,570,582,584,],[224,224,370,370,370,479,370,553,370,370,370,370,370,]),'labeled_statement':([128,221,242,358,360,369,470,525,526,527,570,582,584,],[225,225,225,225,225,225,225,225,225,225,225,225,225,]),'expression_statement':([128,221,242,358,360,369,470,525,526,527,570,582,584,],[226,226,226,226,226,226,226,226,226,226,226,226,226,]),'selection_statement':([128,221,242,358,360,369,470,525,526,527,570,582,584,],[228,228,228,228,228,228,228,228,228,228,228,228,228,]),'iteration_statement':([128,221,242,358,360,369,470,525,526,527,570,582,584,],[229,229,229,229,229,229,229,229,229,229,229,229,229,]),'jump_statement':([128,221,242,358,360,369,470,525,526,527,570,582,584,],[230,230,230,230,230,230,230,230,230,230,230,230,230,]),'expression_opt':([128,221,242,358,360,369,372,470,482,525,526,527,529,559,570,572,582,584,],[236,236,236,236,236,236,481,236,530,236,236,236,558,573,236,581,236,236,]),'expression':([128,141,221,238,242,247,268,287,294,298,358,360,362,366,367,369,372,470,482,525,526,527,528,529,559,565,570,572,582,584,],[239,265,239,265,239,376,408,427,265,265,239,239,472,476,477,239,239,239,239,239,239,239,557,239,239,576,239,239,239,239,]),'assignment_expression':([128,135,141,182,195,221,238,242,247,257,268,287,288,294,298,309,310,358,360,362,365,366,367,369,372,378,393,401,402,455,457,470,482,503,510,525,526,527,528,529,532,544,545,559,565,570,572,582,584,],[248,255,248,308,255,248,248,248,248,308,248,248,430,248,248,441,442,248,248,248,475,248,248,248,248,485,255,495,496,308,308,248,248,539,308,248,248,248,248,248,255,568,569,248,248,248,248,248,248,]),'initializer':([135,195,393,532,],[254,327,488,560,]),'assignment_expression_opt':([182,257,455,457,510,],[305,399,517,519,542,]),'typeid_noparen_declarator':([192,],[316,]),'abstract_declarator_opt':([192,216,],[317,350,]),'direct_typeid_noparen_declarator':([192,318,],[319,446,]),'abstract_declarator':([192,216,322,351,],[321,321,450,450,]),'direct_abstract_declarator':([192,216,318,322,351,352,452,],[325,325,447,325,325,447,447,]),'struct_declarator_list_opt':([209,],[339,]),'struct_declarator_list':([209,],[344,]),'struct_declarator':([209,466,],[345,522,]),'pragmacomp_or_statement':([242,358,360,470,525,526,527,570,582,584,],[368,469,471,524,552,555,556,579,585,586,]),'pppragma_directive_list':([242,358,360,470,525,526,527,570,582,584,],[369,369,369,369,369,369,369,369,369,369,]),'assignment_operator':([250,],[378,]),'initializer_list_opt':([256,],[390,]),'initializer_list':([256,498,],[391,537,]),'designation_opt':([256,487,498,562,],[393,532,393,532,]),'designation':([256,487,498,562,],[394,394,394,394,]),'designator_list':([256,487,498,562,],[395,395,395,395,]),'designator':([256,395,487,498,562,],[396,490,396,396,396,]),'argument_expression_list':([288,],[428,]),'parameter_type_list_opt':([322,351,458,],[451,451,521,]),'offsetof_member_designator':([507,],[540,]),} + +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> translation_unit_or_empty","S'",1,None,None,None), + ('abstract_declarator_opt -> empty','abstract_declarator_opt',1,'p_abstract_declarator_opt','plyparser.py',43), + ('abstract_declarator_opt -> abstract_declarator','abstract_declarator_opt',1,'p_abstract_declarator_opt','plyparser.py',44), + ('assignment_expression_opt -> empty','assignment_expression_opt',1,'p_assignment_expression_opt','plyparser.py',43), + ('assignment_expression_opt -> assignment_expression','assignment_expression_opt',1,'p_assignment_expression_opt','plyparser.py',44), + ('block_item_list_opt -> empty','block_item_list_opt',1,'p_block_item_list_opt','plyparser.py',43), + ('block_item_list_opt -> block_item_list','block_item_list_opt',1,'p_block_item_list_opt','plyparser.py',44), + ('declaration_list_opt -> empty','declaration_list_opt',1,'p_declaration_list_opt','plyparser.py',43), + ('declaration_list_opt -> declaration_list','declaration_list_opt',1,'p_declaration_list_opt','plyparser.py',44), + ('declaration_specifiers_no_type_opt -> empty','declaration_specifiers_no_type_opt',1,'p_declaration_specifiers_no_type_opt','plyparser.py',43), + ('declaration_specifiers_no_type_opt -> declaration_specifiers_no_type','declaration_specifiers_no_type_opt',1,'p_declaration_specifiers_no_type_opt','plyparser.py',44), + ('designation_opt -> empty','designation_opt',1,'p_designation_opt','plyparser.py',43), + ('designation_opt -> designation','designation_opt',1,'p_designation_opt','plyparser.py',44), + ('expression_opt -> empty','expression_opt',1,'p_expression_opt','plyparser.py',43), + ('expression_opt -> expression','expression_opt',1,'p_expression_opt','plyparser.py',44), + ('id_init_declarator_list_opt -> empty','id_init_declarator_list_opt',1,'p_id_init_declarator_list_opt','plyparser.py',43), + ('id_init_declarator_list_opt -> id_init_declarator_list','id_init_declarator_list_opt',1,'p_id_init_declarator_list_opt','plyparser.py',44), + ('identifier_list_opt -> empty','identifier_list_opt',1,'p_identifier_list_opt','plyparser.py',43), + ('identifier_list_opt -> identifier_list','identifier_list_opt',1,'p_identifier_list_opt','plyparser.py',44), + ('init_declarator_list_opt -> empty','init_declarator_list_opt',1,'p_init_declarator_list_opt','plyparser.py',43), + ('init_declarator_list_opt -> init_declarator_list','init_declarator_list_opt',1,'p_init_declarator_list_opt','plyparser.py',44), + ('initializer_list_opt -> empty','initializer_list_opt',1,'p_initializer_list_opt','plyparser.py',43), + ('initializer_list_opt -> initializer_list','initializer_list_opt',1,'p_initializer_list_opt','plyparser.py',44), + ('parameter_type_list_opt -> empty','parameter_type_list_opt',1,'p_parameter_type_list_opt','plyparser.py',43), + ('parameter_type_list_opt -> parameter_type_list','parameter_type_list_opt',1,'p_parameter_type_list_opt','plyparser.py',44), + ('struct_declarator_list_opt -> empty','struct_declarator_list_opt',1,'p_struct_declarator_list_opt','plyparser.py',43), + ('struct_declarator_list_opt -> struct_declarator_list','struct_declarator_list_opt',1,'p_struct_declarator_list_opt','plyparser.py',44), + ('type_qualifier_list_opt -> empty','type_qualifier_list_opt',1,'p_type_qualifier_list_opt','plyparser.py',43), + ('type_qualifier_list_opt -> type_qualifier_list','type_qualifier_list_opt',1,'p_type_qualifier_list_opt','plyparser.py',44), + ('direct_id_declarator -> ID','direct_id_declarator',1,'p_direct_id_declarator_1','plyparser.py',126), + ('direct_id_declarator -> LPAREN id_declarator RPAREN','direct_id_declarator',3,'p_direct_id_declarator_2','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET','direct_id_declarator',5,'p_direct_id_declarator_3','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET','direct_id_declarator',6,'p_direct_id_declarator_4','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET','direct_id_declarator',6,'p_direct_id_declarator_4','plyparser.py',127), + ('direct_id_declarator -> direct_id_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET','direct_id_declarator',5,'p_direct_id_declarator_5','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LPAREN parameter_type_list RPAREN','direct_id_declarator',4,'p_direct_id_declarator_6','plyparser.py',126), + ('direct_id_declarator -> direct_id_declarator LPAREN identifier_list_opt RPAREN','direct_id_declarator',4,'p_direct_id_declarator_6','plyparser.py',127), + ('direct_typeid_declarator -> TYPEID','direct_typeid_declarator',1,'p_direct_typeid_declarator_1','plyparser.py',126), + ('direct_typeid_declarator -> LPAREN typeid_declarator RPAREN','direct_typeid_declarator',3,'p_direct_typeid_declarator_2','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET','direct_typeid_declarator',5,'p_direct_typeid_declarator_3','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET','direct_typeid_declarator',6,'p_direct_typeid_declarator_4','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET','direct_typeid_declarator',6,'p_direct_typeid_declarator_4','plyparser.py',127), + ('direct_typeid_declarator -> direct_typeid_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET','direct_typeid_declarator',5,'p_direct_typeid_declarator_5','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LPAREN parameter_type_list RPAREN','direct_typeid_declarator',4,'p_direct_typeid_declarator_6','plyparser.py',126), + ('direct_typeid_declarator -> direct_typeid_declarator LPAREN identifier_list_opt RPAREN','direct_typeid_declarator',4,'p_direct_typeid_declarator_6','plyparser.py',127), + ('direct_typeid_noparen_declarator -> TYPEID','direct_typeid_noparen_declarator',1,'p_direct_typeid_noparen_declarator_1','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET','direct_typeid_noparen_declarator',5,'p_direct_typeid_noparen_declarator_3','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET','direct_typeid_noparen_declarator',6,'p_direct_typeid_noparen_declarator_4','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET','direct_typeid_noparen_declarator',6,'p_direct_typeid_noparen_declarator_4','plyparser.py',127), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET','direct_typeid_noparen_declarator',5,'p_direct_typeid_noparen_declarator_5','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LPAREN parameter_type_list RPAREN','direct_typeid_noparen_declarator',4,'p_direct_typeid_noparen_declarator_6','plyparser.py',126), + ('direct_typeid_noparen_declarator -> direct_typeid_noparen_declarator LPAREN identifier_list_opt RPAREN','direct_typeid_noparen_declarator',4,'p_direct_typeid_noparen_declarator_6','plyparser.py',127), + ('id_declarator -> direct_id_declarator','id_declarator',1,'p_id_declarator_1','plyparser.py',126), + ('id_declarator -> pointer direct_id_declarator','id_declarator',2,'p_id_declarator_2','plyparser.py',126), + ('typeid_declarator -> direct_typeid_declarator','typeid_declarator',1,'p_typeid_declarator_1','plyparser.py',126), + ('typeid_declarator -> pointer direct_typeid_declarator','typeid_declarator',2,'p_typeid_declarator_2','plyparser.py',126), + ('typeid_noparen_declarator -> direct_typeid_noparen_declarator','typeid_noparen_declarator',1,'p_typeid_noparen_declarator_1','plyparser.py',126), + ('typeid_noparen_declarator -> pointer direct_typeid_noparen_declarator','typeid_noparen_declarator',2,'p_typeid_noparen_declarator_2','plyparser.py',126), + ('translation_unit_or_empty -> translation_unit','translation_unit_or_empty',1,'p_translation_unit_or_empty','c_parser.py',509), + ('translation_unit_or_empty -> empty','translation_unit_or_empty',1,'p_translation_unit_or_empty','c_parser.py',510), + ('translation_unit -> external_declaration','translation_unit',1,'p_translation_unit_1','c_parser.py',518), + ('translation_unit -> translation_unit external_declaration','translation_unit',2,'p_translation_unit_2','c_parser.py',524), + ('external_declaration -> function_definition','external_declaration',1,'p_external_declaration_1','c_parser.py',534), + ('external_declaration -> declaration','external_declaration',1,'p_external_declaration_2','c_parser.py',539), + ('external_declaration -> pp_directive','external_declaration',1,'p_external_declaration_3','c_parser.py',544), + ('external_declaration -> pppragma_directive','external_declaration',1,'p_external_declaration_3','c_parser.py',545), + ('external_declaration -> SEMI','external_declaration',1,'p_external_declaration_4','c_parser.py',550), + ('external_declaration -> static_assert','external_declaration',1,'p_external_declaration_5','c_parser.py',555), + ('static_assert -> _STATIC_ASSERT LPAREN constant_expression COMMA unified_string_literal RPAREN','static_assert',6,'p_static_assert_declaration','c_parser.py',560), + ('static_assert -> _STATIC_ASSERT LPAREN constant_expression RPAREN','static_assert',4,'p_static_assert_declaration','c_parser.py',561), + ('pp_directive -> PPHASH','pp_directive',1,'p_pp_directive','c_parser.py',569), + ('pppragma_directive -> PPPRAGMA','pppragma_directive',1,'p_pppragma_directive','c_parser.py',580), + ('pppragma_directive -> PPPRAGMA PPPRAGMASTR','pppragma_directive',2,'p_pppragma_directive','c_parser.py',581), + ('pppragma_directive -> _PRAGMA LPAREN unified_string_literal RPAREN','pppragma_directive',4,'p_pppragma_directive','c_parser.py',582), + ('pppragma_directive_list -> pppragma_directive','pppragma_directive_list',1,'p_pppragma_directive_list','c_parser.py',592), + ('pppragma_directive_list -> pppragma_directive_list pppragma_directive','pppragma_directive_list',2,'p_pppragma_directive_list','c_parser.py',593), + ('function_definition -> id_declarator declaration_list_opt compound_statement','function_definition',3,'p_function_definition_1','c_parser.py',600), + ('function_definition -> declaration_specifiers id_declarator declaration_list_opt compound_statement','function_definition',4,'p_function_definition_2','c_parser.py',618), + ('statement -> labeled_statement','statement',1,'p_statement','c_parser.py',633), + ('statement -> expression_statement','statement',1,'p_statement','c_parser.py',634), + ('statement -> compound_statement','statement',1,'p_statement','c_parser.py',635), + ('statement -> selection_statement','statement',1,'p_statement','c_parser.py',636), + ('statement -> iteration_statement','statement',1,'p_statement','c_parser.py',637), + ('statement -> jump_statement','statement',1,'p_statement','c_parser.py',638), + ('statement -> pppragma_directive','statement',1,'p_statement','c_parser.py',639), + ('statement -> static_assert','statement',1,'p_statement','c_parser.py',640), + ('pragmacomp_or_statement -> pppragma_directive_list statement','pragmacomp_or_statement',2,'p_pragmacomp_or_statement','c_parser.py',688), + ('pragmacomp_or_statement -> statement','pragmacomp_or_statement',1,'p_pragmacomp_or_statement','c_parser.py',689), + ('decl_body -> declaration_specifiers init_declarator_list_opt','decl_body',2,'p_decl_body','c_parser.py',708), + ('decl_body -> declaration_specifiers_no_type id_init_declarator_list_opt','decl_body',2,'p_decl_body','c_parser.py',709), + ('declaration -> decl_body SEMI','declaration',2,'p_declaration','c_parser.py',769), + ('declaration_list -> declaration','declaration_list',1,'p_declaration_list','c_parser.py',778), + ('declaration_list -> declaration_list declaration','declaration_list',2,'p_declaration_list','c_parser.py',779), + ('declaration_specifiers_no_type -> type_qualifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_1','c_parser.py',789), + ('declaration_specifiers_no_type -> storage_class_specifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_2','c_parser.py',794), + ('declaration_specifiers_no_type -> function_specifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_3','c_parser.py',799), + ('declaration_specifiers_no_type -> atomic_specifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_4','c_parser.py',806), + ('declaration_specifiers_no_type -> alignment_specifier declaration_specifiers_no_type_opt','declaration_specifiers_no_type',2,'p_declaration_specifiers_no_type_5','c_parser.py',811), + ('declaration_specifiers -> declaration_specifiers type_qualifier','declaration_specifiers',2,'p_declaration_specifiers_1','c_parser.py',816), + ('declaration_specifiers -> declaration_specifiers storage_class_specifier','declaration_specifiers',2,'p_declaration_specifiers_2','c_parser.py',821), + ('declaration_specifiers -> declaration_specifiers function_specifier','declaration_specifiers',2,'p_declaration_specifiers_3','c_parser.py',826), + ('declaration_specifiers -> declaration_specifiers type_specifier_no_typeid','declaration_specifiers',2,'p_declaration_specifiers_4','c_parser.py',831), + ('declaration_specifiers -> type_specifier','declaration_specifiers',1,'p_declaration_specifiers_5','c_parser.py',836), + ('declaration_specifiers -> declaration_specifiers_no_type type_specifier','declaration_specifiers',2,'p_declaration_specifiers_6','c_parser.py',841), + ('declaration_specifiers -> declaration_specifiers alignment_specifier','declaration_specifiers',2,'p_declaration_specifiers_7','c_parser.py',846), + ('storage_class_specifier -> AUTO','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',851), + ('storage_class_specifier -> REGISTER','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',852), + ('storage_class_specifier -> STATIC','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',853), + ('storage_class_specifier -> EXTERN','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',854), + ('storage_class_specifier -> TYPEDEF','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',855), + ('storage_class_specifier -> _THREAD_LOCAL','storage_class_specifier',1,'p_storage_class_specifier','c_parser.py',856), + ('function_specifier -> INLINE','function_specifier',1,'p_function_specifier','c_parser.py',861), + ('function_specifier -> _NORETURN','function_specifier',1,'p_function_specifier','c_parser.py',862), + ('type_specifier_no_typeid -> VOID','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',867), + ('type_specifier_no_typeid -> _BOOL','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',868), + ('type_specifier_no_typeid -> CHAR','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',869), + ('type_specifier_no_typeid -> SHORT','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',870), + ('type_specifier_no_typeid -> INT','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',871), + ('type_specifier_no_typeid -> LONG','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',872), + ('type_specifier_no_typeid -> FLOAT','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',873), + ('type_specifier_no_typeid -> DOUBLE','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',874), + ('type_specifier_no_typeid -> _COMPLEX','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',875), + ('type_specifier_no_typeid -> SIGNED','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',876), + ('type_specifier_no_typeid -> UNSIGNED','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',877), + ('type_specifier_no_typeid -> __INT128','type_specifier_no_typeid',1,'p_type_specifier_no_typeid','c_parser.py',878), + ('type_specifier -> typedef_name','type_specifier',1,'p_type_specifier','c_parser.py',883), + ('type_specifier -> enum_specifier','type_specifier',1,'p_type_specifier','c_parser.py',884), + ('type_specifier -> struct_or_union_specifier','type_specifier',1,'p_type_specifier','c_parser.py',885), + ('type_specifier -> type_specifier_no_typeid','type_specifier',1,'p_type_specifier','c_parser.py',886), + ('type_specifier -> atomic_specifier','type_specifier',1,'p_type_specifier','c_parser.py',887), + ('atomic_specifier -> _ATOMIC LPAREN type_name RPAREN','atomic_specifier',4,'p_atomic_specifier','c_parser.py',893), + ('type_qualifier -> CONST','type_qualifier',1,'p_type_qualifier','c_parser.py',900), + ('type_qualifier -> RESTRICT','type_qualifier',1,'p_type_qualifier','c_parser.py',901), + ('type_qualifier -> VOLATILE','type_qualifier',1,'p_type_qualifier','c_parser.py',902), + ('type_qualifier -> _ATOMIC','type_qualifier',1,'p_type_qualifier','c_parser.py',903), + ('init_declarator_list -> init_declarator','init_declarator_list',1,'p_init_declarator_list','c_parser.py',908), + ('init_declarator_list -> init_declarator_list COMMA init_declarator','init_declarator_list',3,'p_init_declarator_list','c_parser.py',909), + ('init_declarator -> declarator','init_declarator',1,'p_init_declarator','c_parser.py',917), + ('init_declarator -> declarator EQUALS initializer','init_declarator',3,'p_init_declarator','c_parser.py',918), + ('id_init_declarator_list -> id_init_declarator','id_init_declarator_list',1,'p_id_init_declarator_list','c_parser.py',923), + ('id_init_declarator_list -> id_init_declarator_list COMMA init_declarator','id_init_declarator_list',3,'p_id_init_declarator_list','c_parser.py',924), + ('id_init_declarator -> id_declarator','id_init_declarator',1,'p_id_init_declarator','c_parser.py',929), + ('id_init_declarator -> id_declarator EQUALS initializer','id_init_declarator',3,'p_id_init_declarator','c_parser.py',930), + ('specifier_qualifier_list -> specifier_qualifier_list type_specifier_no_typeid','specifier_qualifier_list',2,'p_specifier_qualifier_list_1','c_parser.py',937), + ('specifier_qualifier_list -> specifier_qualifier_list type_qualifier','specifier_qualifier_list',2,'p_specifier_qualifier_list_2','c_parser.py',942), + ('specifier_qualifier_list -> type_specifier','specifier_qualifier_list',1,'p_specifier_qualifier_list_3','c_parser.py',947), + ('specifier_qualifier_list -> type_qualifier_list type_specifier','specifier_qualifier_list',2,'p_specifier_qualifier_list_4','c_parser.py',952), + ('specifier_qualifier_list -> alignment_specifier','specifier_qualifier_list',1,'p_specifier_qualifier_list_5','c_parser.py',957), + ('specifier_qualifier_list -> specifier_qualifier_list alignment_specifier','specifier_qualifier_list',2,'p_specifier_qualifier_list_6','c_parser.py',962), + ('struct_or_union_specifier -> struct_or_union ID','struct_or_union_specifier',2,'p_struct_or_union_specifier_1','c_parser.py',970), + ('struct_or_union_specifier -> struct_or_union TYPEID','struct_or_union_specifier',2,'p_struct_or_union_specifier_1','c_parser.py',971), + ('struct_or_union_specifier -> struct_or_union brace_open struct_declaration_list brace_close','struct_or_union_specifier',4,'p_struct_or_union_specifier_2','c_parser.py',981), + ('struct_or_union_specifier -> struct_or_union brace_open brace_close','struct_or_union_specifier',3,'p_struct_or_union_specifier_2','c_parser.py',982), + ('struct_or_union_specifier -> struct_or_union ID brace_open struct_declaration_list brace_close','struct_or_union_specifier',5,'p_struct_or_union_specifier_3','c_parser.py',999), + ('struct_or_union_specifier -> struct_or_union ID brace_open brace_close','struct_or_union_specifier',4,'p_struct_or_union_specifier_3','c_parser.py',1000), + ('struct_or_union_specifier -> struct_or_union TYPEID brace_open struct_declaration_list brace_close','struct_or_union_specifier',5,'p_struct_or_union_specifier_3','c_parser.py',1001), + ('struct_or_union_specifier -> struct_or_union TYPEID brace_open brace_close','struct_or_union_specifier',4,'p_struct_or_union_specifier_3','c_parser.py',1002), + ('struct_or_union -> STRUCT','struct_or_union',1,'p_struct_or_union','c_parser.py',1018), + ('struct_or_union -> UNION','struct_or_union',1,'p_struct_or_union','c_parser.py',1019), + ('struct_declaration_list -> struct_declaration','struct_declaration_list',1,'p_struct_declaration_list','c_parser.py',1026), + ('struct_declaration_list -> struct_declaration_list struct_declaration','struct_declaration_list',2,'p_struct_declaration_list','c_parser.py',1027), + ('struct_declaration -> specifier_qualifier_list struct_declarator_list_opt SEMI','struct_declaration',3,'p_struct_declaration_1','c_parser.py',1035), + ('struct_declaration -> SEMI','struct_declaration',1,'p_struct_declaration_2','c_parser.py',1073), + ('struct_declaration -> pppragma_directive','struct_declaration',1,'p_struct_declaration_3','c_parser.py',1078), + ('struct_declarator_list -> struct_declarator','struct_declarator_list',1,'p_struct_declarator_list','c_parser.py',1083), + ('struct_declarator_list -> struct_declarator_list COMMA struct_declarator','struct_declarator_list',3,'p_struct_declarator_list','c_parser.py',1084), + ('struct_declarator -> declarator','struct_declarator',1,'p_struct_declarator_1','c_parser.py',1092), + ('struct_declarator -> declarator COLON constant_expression','struct_declarator',3,'p_struct_declarator_2','c_parser.py',1097), + ('struct_declarator -> COLON constant_expression','struct_declarator',2,'p_struct_declarator_2','c_parser.py',1098), + ('enum_specifier -> ENUM ID','enum_specifier',2,'p_enum_specifier_1','c_parser.py',1106), + ('enum_specifier -> ENUM TYPEID','enum_specifier',2,'p_enum_specifier_1','c_parser.py',1107), + ('enum_specifier -> ENUM brace_open enumerator_list brace_close','enum_specifier',4,'p_enum_specifier_2','c_parser.py',1112), + ('enum_specifier -> ENUM ID brace_open enumerator_list brace_close','enum_specifier',5,'p_enum_specifier_3','c_parser.py',1117), + ('enum_specifier -> ENUM TYPEID brace_open enumerator_list brace_close','enum_specifier',5,'p_enum_specifier_3','c_parser.py',1118), + ('enumerator_list -> enumerator','enumerator_list',1,'p_enumerator_list','c_parser.py',1123), + ('enumerator_list -> enumerator_list COMMA','enumerator_list',2,'p_enumerator_list','c_parser.py',1124), + ('enumerator_list -> enumerator_list COMMA enumerator','enumerator_list',3,'p_enumerator_list','c_parser.py',1125), + ('alignment_specifier -> _ALIGNAS LPAREN type_name RPAREN','alignment_specifier',4,'p_alignment_specifier','c_parser.py',1136), + ('alignment_specifier -> _ALIGNAS LPAREN constant_expression RPAREN','alignment_specifier',4,'p_alignment_specifier','c_parser.py',1137), + ('enumerator -> ID','enumerator',1,'p_enumerator','c_parser.py',1142), + ('enumerator -> ID EQUALS constant_expression','enumerator',3,'p_enumerator','c_parser.py',1143), + ('declarator -> id_declarator','declarator',1,'p_declarator','c_parser.py',1158), + ('declarator -> typeid_declarator','declarator',1,'p_declarator','c_parser.py',1159), + ('pointer -> TIMES type_qualifier_list_opt','pointer',2,'p_pointer','c_parser.py',1271), + ('pointer -> TIMES type_qualifier_list_opt pointer','pointer',3,'p_pointer','c_parser.py',1272), + ('type_qualifier_list -> type_qualifier','type_qualifier_list',1,'p_type_qualifier_list','c_parser.py',1301), + ('type_qualifier_list -> type_qualifier_list type_qualifier','type_qualifier_list',2,'p_type_qualifier_list','c_parser.py',1302), + ('parameter_type_list -> parameter_list','parameter_type_list',1,'p_parameter_type_list','c_parser.py',1307), + ('parameter_type_list -> parameter_list COMMA ELLIPSIS','parameter_type_list',3,'p_parameter_type_list','c_parser.py',1308), + ('parameter_list -> parameter_declaration','parameter_list',1,'p_parameter_list','c_parser.py',1316), + ('parameter_list -> parameter_list COMMA parameter_declaration','parameter_list',3,'p_parameter_list','c_parser.py',1317), + ('parameter_declaration -> declaration_specifiers id_declarator','parameter_declaration',2,'p_parameter_declaration_1','c_parser.py',1336), + ('parameter_declaration -> declaration_specifiers typeid_noparen_declarator','parameter_declaration',2,'p_parameter_declaration_1','c_parser.py',1337), + ('parameter_declaration -> declaration_specifiers abstract_declarator_opt','parameter_declaration',2,'p_parameter_declaration_2','c_parser.py',1348), + ('identifier_list -> identifier','identifier_list',1,'p_identifier_list','c_parser.py',1380), + ('identifier_list -> identifier_list COMMA identifier','identifier_list',3,'p_identifier_list','c_parser.py',1381), + ('initializer -> assignment_expression','initializer',1,'p_initializer_1','c_parser.py',1390), + ('initializer -> brace_open initializer_list_opt brace_close','initializer',3,'p_initializer_2','c_parser.py',1395), + ('initializer -> brace_open initializer_list COMMA brace_close','initializer',4,'p_initializer_2','c_parser.py',1396), + ('initializer_list -> designation_opt initializer','initializer_list',2,'p_initializer_list','c_parser.py',1404), + ('initializer_list -> initializer_list COMMA designation_opt initializer','initializer_list',4,'p_initializer_list','c_parser.py',1405), + ('designation -> designator_list EQUALS','designation',2,'p_designation','c_parser.py',1416), + ('designator_list -> designator','designator_list',1,'p_designator_list','c_parser.py',1424), + ('designator_list -> designator_list designator','designator_list',2,'p_designator_list','c_parser.py',1425), + ('designator -> LBRACKET constant_expression RBRACKET','designator',3,'p_designator','c_parser.py',1430), + ('designator -> PERIOD identifier','designator',2,'p_designator','c_parser.py',1431), + ('type_name -> specifier_qualifier_list abstract_declarator_opt','type_name',2,'p_type_name','c_parser.py',1436), + ('abstract_declarator -> pointer','abstract_declarator',1,'p_abstract_declarator_1','c_parser.py',1448), + ('abstract_declarator -> pointer direct_abstract_declarator','abstract_declarator',2,'p_abstract_declarator_2','c_parser.py',1456), + ('abstract_declarator -> direct_abstract_declarator','abstract_declarator',1,'p_abstract_declarator_3','c_parser.py',1461), + ('direct_abstract_declarator -> LPAREN abstract_declarator RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator_1','c_parser.py',1471), + ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator_2','c_parser.py',1475), + ('direct_abstract_declarator -> LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator_3','c_parser.py',1486), + ('direct_abstract_declarator -> direct_abstract_declarator LBRACKET TIMES RBRACKET','direct_abstract_declarator',4,'p_direct_abstract_declarator_4','c_parser.py',1496), + ('direct_abstract_declarator -> LBRACKET TIMES RBRACKET','direct_abstract_declarator',3,'p_direct_abstract_declarator_5','c_parser.py',1507), + ('direct_abstract_declarator -> direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN','direct_abstract_declarator',4,'p_direct_abstract_declarator_6','c_parser.py',1516), + ('direct_abstract_declarator -> LPAREN parameter_type_list_opt RPAREN','direct_abstract_declarator',3,'p_direct_abstract_declarator_7','c_parser.py',1526), + ('block_item -> declaration','block_item',1,'p_block_item','c_parser.py',1537), + ('block_item -> statement','block_item',1,'p_block_item','c_parser.py',1538), + ('block_item_list -> block_item','block_item_list',1,'p_block_item_list','c_parser.py',1545), + ('block_item_list -> block_item_list block_item','block_item_list',2,'p_block_item_list','c_parser.py',1546), + ('compound_statement -> brace_open block_item_list_opt brace_close','compound_statement',3,'p_compound_statement_1','c_parser.py',1552), + ('labeled_statement -> ID COLON pragmacomp_or_statement','labeled_statement',3,'p_labeled_statement_1','c_parser.py',1558), + ('labeled_statement -> CASE constant_expression COLON pragmacomp_or_statement','labeled_statement',4,'p_labeled_statement_2','c_parser.py',1562), + ('labeled_statement -> DEFAULT COLON pragmacomp_or_statement','labeled_statement',3,'p_labeled_statement_3','c_parser.py',1566), + ('selection_statement -> IF LPAREN expression RPAREN pragmacomp_or_statement','selection_statement',5,'p_selection_statement_1','c_parser.py',1570), + ('selection_statement -> IF LPAREN expression RPAREN statement ELSE pragmacomp_or_statement','selection_statement',7,'p_selection_statement_2','c_parser.py',1574), + ('selection_statement -> SWITCH LPAREN expression RPAREN pragmacomp_or_statement','selection_statement',5,'p_selection_statement_3','c_parser.py',1578), + ('iteration_statement -> WHILE LPAREN expression RPAREN pragmacomp_or_statement','iteration_statement',5,'p_iteration_statement_1','c_parser.py',1583), + ('iteration_statement -> DO pragmacomp_or_statement WHILE LPAREN expression RPAREN SEMI','iteration_statement',7,'p_iteration_statement_2','c_parser.py',1587), + ('iteration_statement -> FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement','iteration_statement',9,'p_iteration_statement_3','c_parser.py',1591), + ('iteration_statement -> FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement','iteration_statement',8,'p_iteration_statement_4','c_parser.py',1595), + ('jump_statement -> GOTO ID SEMI','jump_statement',3,'p_jump_statement_1','c_parser.py',1600), + ('jump_statement -> BREAK SEMI','jump_statement',2,'p_jump_statement_2','c_parser.py',1604), + ('jump_statement -> CONTINUE SEMI','jump_statement',2,'p_jump_statement_3','c_parser.py',1608), + ('jump_statement -> RETURN expression SEMI','jump_statement',3,'p_jump_statement_4','c_parser.py',1612), + ('jump_statement -> RETURN SEMI','jump_statement',2,'p_jump_statement_4','c_parser.py',1613), + ('expression_statement -> expression_opt SEMI','expression_statement',2,'p_expression_statement','c_parser.py',1618), + ('expression -> assignment_expression','expression',1,'p_expression','c_parser.py',1625), + ('expression -> expression COMMA assignment_expression','expression',3,'p_expression','c_parser.py',1626), + ('assignment_expression -> LPAREN compound_statement RPAREN','assignment_expression',3,'p_parenthesized_compound_expression','c_parser.py',1638), + ('typedef_name -> TYPEID','typedef_name',1,'p_typedef_name','c_parser.py',1642), + ('assignment_expression -> conditional_expression','assignment_expression',1,'p_assignment_expression','c_parser.py',1646), + ('assignment_expression -> unary_expression assignment_operator assignment_expression','assignment_expression',3,'p_assignment_expression','c_parser.py',1647), + ('assignment_operator -> EQUALS','assignment_operator',1,'p_assignment_operator','c_parser.py',1660), + ('assignment_operator -> XOREQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1661), + ('assignment_operator -> TIMESEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1662), + ('assignment_operator -> DIVEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1663), + ('assignment_operator -> MODEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1664), + ('assignment_operator -> PLUSEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1665), + ('assignment_operator -> MINUSEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1666), + ('assignment_operator -> LSHIFTEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1667), + ('assignment_operator -> RSHIFTEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1668), + ('assignment_operator -> ANDEQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1669), + ('assignment_operator -> OREQUAL','assignment_operator',1,'p_assignment_operator','c_parser.py',1670), + ('constant_expression -> conditional_expression','constant_expression',1,'p_constant_expression','c_parser.py',1675), + ('conditional_expression -> binary_expression','conditional_expression',1,'p_conditional_expression','c_parser.py',1679), + ('conditional_expression -> binary_expression CONDOP expression COLON conditional_expression','conditional_expression',5,'p_conditional_expression','c_parser.py',1680), + ('binary_expression -> cast_expression','binary_expression',1,'p_binary_expression','c_parser.py',1688), + ('binary_expression -> binary_expression TIMES binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1689), + ('binary_expression -> binary_expression DIVIDE binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1690), + ('binary_expression -> binary_expression MOD binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1691), + ('binary_expression -> binary_expression PLUS binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1692), + ('binary_expression -> binary_expression MINUS binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1693), + ('binary_expression -> binary_expression RSHIFT binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1694), + ('binary_expression -> binary_expression LSHIFT binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1695), + ('binary_expression -> binary_expression LT binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1696), + ('binary_expression -> binary_expression LE binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1697), + ('binary_expression -> binary_expression GE binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1698), + ('binary_expression -> binary_expression GT binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1699), + ('binary_expression -> binary_expression EQ binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1700), + ('binary_expression -> binary_expression NE binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1701), + ('binary_expression -> binary_expression AND binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1702), + ('binary_expression -> binary_expression OR binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1703), + ('binary_expression -> binary_expression XOR binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1704), + ('binary_expression -> binary_expression LAND binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1705), + ('binary_expression -> binary_expression LOR binary_expression','binary_expression',3,'p_binary_expression','c_parser.py',1706), + ('cast_expression -> unary_expression','cast_expression',1,'p_cast_expression_1','c_parser.py',1714), + ('cast_expression -> LPAREN type_name RPAREN cast_expression','cast_expression',4,'p_cast_expression_2','c_parser.py',1718), + ('unary_expression -> postfix_expression','unary_expression',1,'p_unary_expression_1','c_parser.py',1722), + ('unary_expression -> PLUSPLUS unary_expression','unary_expression',2,'p_unary_expression_2','c_parser.py',1726), + ('unary_expression -> MINUSMINUS unary_expression','unary_expression',2,'p_unary_expression_2','c_parser.py',1727), + ('unary_expression -> unary_operator cast_expression','unary_expression',2,'p_unary_expression_2','c_parser.py',1728), + ('unary_expression -> SIZEOF unary_expression','unary_expression',2,'p_unary_expression_3','c_parser.py',1733), + ('unary_expression -> SIZEOF LPAREN type_name RPAREN','unary_expression',4,'p_unary_expression_3','c_parser.py',1734), + ('unary_expression -> _ALIGNOF LPAREN type_name RPAREN','unary_expression',4,'p_unary_expression_3','c_parser.py',1735), + ('unary_operator -> AND','unary_operator',1,'p_unary_operator','c_parser.py',1743), + ('unary_operator -> TIMES','unary_operator',1,'p_unary_operator','c_parser.py',1744), + ('unary_operator -> PLUS','unary_operator',1,'p_unary_operator','c_parser.py',1745), + ('unary_operator -> MINUS','unary_operator',1,'p_unary_operator','c_parser.py',1746), + ('unary_operator -> NOT','unary_operator',1,'p_unary_operator','c_parser.py',1747), + ('unary_operator -> LNOT','unary_operator',1,'p_unary_operator','c_parser.py',1748), + ('postfix_expression -> primary_expression','postfix_expression',1,'p_postfix_expression_1','c_parser.py',1753), + ('postfix_expression -> postfix_expression LBRACKET expression RBRACKET','postfix_expression',4,'p_postfix_expression_2','c_parser.py',1757), + ('postfix_expression -> postfix_expression LPAREN argument_expression_list RPAREN','postfix_expression',4,'p_postfix_expression_3','c_parser.py',1761), + ('postfix_expression -> postfix_expression LPAREN RPAREN','postfix_expression',3,'p_postfix_expression_3','c_parser.py',1762), + ('postfix_expression -> postfix_expression PERIOD ID','postfix_expression',3,'p_postfix_expression_4','c_parser.py',1767), + ('postfix_expression -> postfix_expression PERIOD TYPEID','postfix_expression',3,'p_postfix_expression_4','c_parser.py',1768), + ('postfix_expression -> postfix_expression ARROW ID','postfix_expression',3,'p_postfix_expression_4','c_parser.py',1769), + ('postfix_expression -> postfix_expression ARROW TYPEID','postfix_expression',3,'p_postfix_expression_4','c_parser.py',1770), + ('postfix_expression -> postfix_expression PLUSPLUS','postfix_expression',2,'p_postfix_expression_5','c_parser.py',1776), + ('postfix_expression -> postfix_expression MINUSMINUS','postfix_expression',2,'p_postfix_expression_5','c_parser.py',1777), + ('postfix_expression -> LPAREN type_name RPAREN brace_open initializer_list brace_close','postfix_expression',6,'p_postfix_expression_6','c_parser.py',1782), + ('postfix_expression -> LPAREN type_name RPAREN brace_open initializer_list COMMA brace_close','postfix_expression',7,'p_postfix_expression_6','c_parser.py',1783), + ('primary_expression -> identifier','primary_expression',1,'p_primary_expression_1','c_parser.py',1788), + ('primary_expression -> constant','primary_expression',1,'p_primary_expression_2','c_parser.py',1792), + ('primary_expression -> unified_string_literal','primary_expression',1,'p_primary_expression_3','c_parser.py',1796), + ('primary_expression -> unified_wstring_literal','primary_expression',1,'p_primary_expression_3','c_parser.py',1797), + ('primary_expression -> LPAREN expression RPAREN','primary_expression',3,'p_primary_expression_4','c_parser.py',1802), + ('primary_expression -> OFFSETOF LPAREN type_name COMMA offsetof_member_designator RPAREN','primary_expression',6,'p_primary_expression_5','c_parser.py',1806), + ('offsetof_member_designator -> identifier','offsetof_member_designator',1,'p_offsetof_member_designator','c_parser.py',1814), + ('offsetof_member_designator -> offsetof_member_designator PERIOD identifier','offsetof_member_designator',3,'p_offsetof_member_designator','c_parser.py',1815), + ('offsetof_member_designator -> offsetof_member_designator LBRACKET expression RBRACKET','offsetof_member_designator',4,'p_offsetof_member_designator','c_parser.py',1816), + ('argument_expression_list -> assignment_expression','argument_expression_list',1,'p_argument_expression_list','c_parser.py',1828), + ('argument_expression_list -> argument_expression_list COMMA assignment_expression','argument_expression_list',3,'p_argument_expression_list','c_parser.py',1829), + ('identifier -> ID','identifier',1,'p_identifier','c_parser.py',1838), + ('constant -> INT_CONST_DEC','constant',1,'p_constant_1','c_parser.py',1842), + ('constant -> INT_CONST_OCT','constant',1,'p_constant_1','c_parser.py',1843), + ('constant -> INT_CONST_HEX','constant',1,'p_constant_1','c_parser.py',1844), + ('constant -> INT_CONST_BIN','constant',1,'p_constant_1','c_parser.py',1845), + ('constant -> INT_CONST_CHAR','constant',1,'p_constant_1','c_parser.py',1846), + ('constant -> FLOAT_CONST','constant',1,'p_constant_2','c_parser.py',1865), + ('constant -> HEX_FLOAT_CONST','constant',1,'p_constant_2','c_parser.py',1866), + ('constant -> CHAR_CONST','constant',1,'p_constant_3','c_parser.py',1882), + ('constant -> WCHAR_CONST','constant',1,'p_constant_3','c_parser.py',1883), + ('constant -> U8CHAR_CONST','constant',1,'p_constant_3','c_parser.py',1884), + ('constant -> U16CHAR_CONST','constant',1,'p_constant_3','c_parser.py',1885), + ('constant -> U32CHAR_CONST','constant',1,'p_constant_3','c_parser.py',1886), + ('unified_string_literal -> STRING_LITERAL','unified_string_literal',1,'p_unified_string_literal','c_parser.py',1897), + ('unified_string_literal -> unified_string_literal STRING_LITERAL','unified_string_literal',2,'p_unified_string_literal','c_parser.py',1898), + ('unified_wstring_literal -> WSTRING_LITERAL','unified_wstring_literal',1,'p_unified_wstring_literal','c_parser.py',1908), + ('unified_wstring_literal -> U8STRING_LITERAL','unified_wstring_literal',1,'p_unified_wstring_literal','c_parser.py',1909), + ('unified_wstring_literal -> U16STRING_LITERAL','unified_wstring_literal',1,'p_unified_wstring_literal','c_parser.py',1910), + ('unified_wstring_literal -> U32STRING_LITERAL','unified_wstring_literal',1,'p_unified_wstring_literal','c_parser.py',1911), + ('unified_wstring_literal -> unified_wstring_literal WSTRING_LITERAL','unified_wstring_literal',2,'p_unified_wstring_literal','c_parser.py',1912), + ('unified_wstring_literal -> unified_wstring_literal U8STRING_LITERAL','unified_wstring_literal',2,'p_unified_wstring_literal','c_parser.py',1913), + ('unified_wstring_literal -> unified_wstring_literal U16STRING_LITERAL','unified_wstring_literal',2,'p_unified_wstring_literal','c_parser.py',1914), + ('unified_wstring_literal -> unified_wstring_literal U32STRING_LITERAL','unified_wstring_literal',2,'p_unified_wstring_literal','c_parser.py',1915), + ('brace_open -> LBRACE','brace_open',1,'p_brace_open','c_parser.py',1925), + ('brace_close -> RBRACE','brace_close',1,'p_brace_close','c_parser.py',1931), + ('empty -> ','empty',0,'p_empty','c_parser.py',1937), +] diff --git a/www/run/amy.aw.js b/www/run/amy.aw.js new file mode 100644 index 00000000..2ff89862 --- /dev/null +++ b/www/run/amy.aw.js @@ -0,0 +1 @@ +function createWasmAudioWorkletProcessor(audioParams){class WasmAudioWorkletProcessor extends AudioWorkletProcessor{constructor(args){super();globalThis.stackAlloc=Module["stackAlloc"];globalThis.stackSave=Module["stackSave"];globalThis.stackRestore=Module["stackRestore"];globalThis.HEAPU32=Module["HEAPU32"];globalThis.HEAPF32=Module["HEAPF32"];let opts=args.processorOptions;this.callbackFunction=Module["wasmTable"].get(opts["cb"]);this.userData=opts["ud"]}static get parameterDescriptors(){return audioParams}process(inputList,outputList,parameters){let numInputs=inputList.length,numOutputs=outputList.length,numParams=0,i,j,k,dataPtr,stackMemoryNeeded=(numInputs+numOutputs)*8,oldStackPtr=stackSave(),inputsPtr,outputsPtr,outputDataPtr,paramsPtr,didProduceAudio,paramArray;for(i of inputList)stackMemoryNeeded+=i.length*512;for(i of outputList)stackMemoryNeeded+=i.length*512;for(i in parameters)stackMemoryNeeded+=parameters[i].byteLength+8,++numParams;inputsPtr=stackAlloc(stackMemoryNeeded);k=inputsPtr>>2;dataPtr=inputsPtr+numInputs*8;for(i of inputList){HEAPU32[k++]=i.length;HEAPU32[k++]=dataPtr;for(j of i){HEAPF32.set(j,dataPtr>>2);dataPtr+=512}}outputsPtr=dataPtr;k=outputsPtr>>2;outputDataPtr=(dataPtr+=numOutputs*8)>>2;for(i of outputList){HEAPU32[k++]=i.length;HEAPU32[k++]=dataPtr;dataPtr+=512*i.length}paramsPtr=dataPtr;k=paramsPtr>>2;dataPtr+=numParams*8;for(i=0;paramArray=parameters[i++];){HEAPU32[k++]=paramArray.length;HEAPU32[k++]=dataPtr;HEAPF32.set(paramArray,dataPtr>>2);dataPtr+=paramArray.length*4}if(didProduceAudio=this.callbackFunction(numInputs,inputsPtr,numOutputs,outputsPtr,numParams,paramsPtr,this.userData)){for(i of outputList){for(j of i){for(k=0;k<128;++k){j[k]=HEAPF32[outputDataPtr++]}}}}stackRestore(oldStackPtr);return!!didProduceAudio}}return WasmAudioWorkletProcessor}class BootstrapMessages extends AudioWorkletProcessor{constructor(arg){super();globalThis.Module=arg["processorOptions"];globalThis.Module["instantiateWasm"]=(info,receiveInstance)=>{var instance=new WebAssembly.Instance(Module["wasm"],info);receiveInstance(instance,Module["wasm"]);return instance.exports};let p=globalThis["messagePort"]=this.port;p.onmessage=async msg=>{let d=msg.data;if(d["_wpn"]){if(globalThis.AudioWorkletModule){globalThis.Module=await AudioWorkletModule(Module);delete globalThis.AudioWorkletModule}registerProcessor(d["_wpn"],createWasmAudioWorkletProcessor(d["audioParams"]));p.postMessage({_wsc:d["callback"],x:[d["contextHandle"],1,d["userData"]]})}else if(d["_wsc"]){Module["wasmTable"].get(d["_wsc"])(...d["x"])}}}process(){}}registerProcessor("message",BootstrapMessages); diff --git a/www/run/amy.js b/www/run/amy.js new file mode 100644 index 00000000..28029f9c --- /dev/null +++ b/www/run/amy.js @@ -0,0 +1,20 @@ + +var amyModule = (() => { + var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; + if (typeof __filename != 'undefined') _scriptName = _scriptName || __filename; + return ( +function(moduleArg = {}) { + var moduleRtn; + +function GROWABLE_HEAP_I8(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP8}function GROWABLE_HEAP_U8(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPU8}function GROWABLE_HEAP_I16(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP16}function GROWABLE_HEAP_I32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP32}function GROWABLE_HEAP_U32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPU32}function GROWABLE_HEAP_F32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPF32}function GROWABLE_HEAP_F64(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPF64}var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});["_amy_play_message","_amy_reset_sysclock","_amy_live_start","_amy_start","_sequencer_ticks","_malloc","_free","___indirect_function_table","_ma_device__on_notification_unlocked","_ma_malloc_emscripten","_ma_free_emscripten","_ma_device_process_pcm_frames_capture__webaudio","_ma_device_process_pcm_frames_playback__webaudio","onRuntimeInitialized"].forEach(prop=>{if(!Object.getOwnPropertyDescriptor(readyPromise,prop)){Object.defineProperty(readyPromise,prop,{get:()=>abort("You are getting "+prop+" on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js"),set:()=>abort("You are setting "+prop+" on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")})}});var ENVIRONMENT_IS_AUDIO_WORKLET=typeof AudioWorkletGlobalScope!=="undefined";var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER&&!ENVIRONMENT_IS_AUDIO_WORKLET;if(Module["ENVIRONMENT"]){throw new Error("Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)")}if(ENVIRONMENT_IS_NODE){var worker_threads=require("worker_threads");global.Worker=worker_threads.Worker;ENVIRONMENT_IS_WORKER=!worker_threads.isMainThread}var ENVIRONMENT_IS_WASM_WORKER=Module["$ww"];var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){if(typeof process=="undefined"||!process.release||process.release.name!=="node")throw new Error("not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)");var nodeVersion=process.versions.node;var numericVersion=nodeVersion.split(".").slice(0,3);numericVersion=numericVersion[0]*1e4+numericVersion[1]*100+numericVersion[2].split("-")[0]*1;if(numericVersion<16e4){throw new Error("This emscripten-generated code requires node v16.0.0 (detected v"+nodeVersion+")")}var fs=require("fs");var nodePath=require("path");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);var ret=fs.readFileSync(filename);assert(ret.buffer);return ret};readAsync=(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return new Promise((resolve,reject)=>{fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)reject(err);else resolve(binary?data.buffer:data)})})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_SHELL){if(typeof process=="object"&&typeof require==="function"||typeof window=="object"||typeof importScripts=="function")throw new Error("not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)")}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}if(!(typeof window=="object"||typeof importScripts=="function"))throw new Error("not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)");{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=url=>{if(isFileURI(url)){return new Promise((resolve,reject)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response);return}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}return fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))})}}}else if(!ENVIRONMENT_IS_AUDIO_WORKLET){throw new Error("environment detection error")}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;checkIncomingModuleAPI();if(Module["arguments"])arguments_=Module["arguments"];legacyModuleProp("arguments","arguments_");if(Module["thisProgram"])thisProgram=Module["thisProgram"];legacyModuleProp("thisProgram","thisProgram");assert(typeof Module["memoryInitializerPrefixURL"]=="undefined","Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["pthreadMainPrefixURL"]=="undefined","Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["cdInitializerPrefixURL"]=="undefined","Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["filePackagePrefixURL"]=="undefined","Module.filePackagePrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["read"]=="undefined","Module.read option was removed");assert(typeof Module["readAsync"]=="undefined","Module.readAsync option was removed (modify readAsync in JS)");assert(typeof Module["readBinary"]=="undefined","Module.readBinary option was removed (modify readBinary in JS)");assert(typeof Module["setWindowTitle"]=="undefined","Module.setWindowTitle option was removed (modify emscripten_set_window_title in JS)");assert(typeof Module["TOTAL_MEMORY"]=="undefined","Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY");legacyModuleProp("asm","wasmExports");legacyModuleProp("readAsync","readAsync");legacyModuleProp("readBinary","readBinary");legacyModuleProp("setWindowTitle","setWindowTitle");assert(!ENVIRONMENT_IS_SHELL,"shell environment detected but not enabled at build time. Add `shell` to `-sENVIRONMENT` to enable.");var wasmBinary=Module["wasmBinary"];legacyModuleProp("wasmBinary","wasmBinary");if(typeof WebAssembly!="object"){err("no native wasm support detected")}var wasmMemory;var wasmModule;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort("Assertion failed"+(text?": "+text:""))}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}assert(!Module["STACK_SIZE"],"STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time");assert(typeof Int32Array!="undefined"&&typeof Float64Array!=="undefined"&&Int32Array.prototype.subarray!=undefined&&Int32Array.prototype.set!=undefined,"JS engine does not provide full typed array support");if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||134217728;legacyModuleProp("INITIAL_MEMORY","INITIAL_MEMORY");assert(INITIAL_MEMORY>=67108864,"INITIAL_MEMORY should be larger than STACK_SIZE, was "+INITIAL_MEMORY+"! (STACK_SIZE="+67108864+")");wasmMemory=new WebAssembly.Memory({initial:INITIAL_MEMORY/65536,maximum:32768,shared:true});if(!(wasmMemory.buffer instanceof SharedArrayBuffer)){err("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag");if(ENVIRONMENT_IS_NODE){err("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and/or recent version)")}throw Error("bad memory")}}updateMemoryViews();function writeStackCookie(){var max=_emscripten_stack_get_end();assert((max&3)==0);if(max==0){max+=4}GROWABLE_HEAP_U32()[max>>2]=34821223;GROWABLE_HEAP_U32()[max+4>>2]=2310721022;GROWABLE_HEAP_U32()[0>>2]=1668509029}function checkStackCookie(){if(ABORT)return;var max=_emscripten_stack_get_end();if(max==0){max+=4}var cookie1=GROWABLE_HEAP_U32()[max>>2];var cookie2=GROWABLE_HEAP_U32()[max+4>>2];if(cookie1!=34821223||cookie2!=2310721022){abort(`Stack overflow! Stack cookie has been overwritten at ${ptrToString(max)}, expected hex dwords 0x89BACDFE and 0x2135467, but received ${ptrToString(cookie2)} ${ptrToString(cookie1)}`)}if(GROWABLE_HEAP_U32()[0>>2]!=1668509029){abort("Runtime error: The application has corrupted its heap memory area (address zero)!")}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){assert(!runtimeInitialized);runtimeInitialized=true;if(ENVIRONMENT_IS_WASM_WORKER)return _wasmWorkerInitializeRuntime();checkStackCookie();callRuntimeCallbacks(__ATINIT__)}function postRun(){checkStackCookie();if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}assert(Math.imul,"This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.fround,"This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.clz32,"This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.trunc,"This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;var runDependencyTracking={};function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies);if(id){assert(!runDependencyTracking[id]);runDependencyTracking[id]=1;if(runDependencyWatcher===null&&typeof setInterval!="undefined"){runDependencyWatcher=setInterval(()=>{if(ABORT){clearInterval(runDependencyWatcher);runDependencyWatcher=null;return}var shown=false;for(var dep in runDependencyTracking){if(!shown){shown=true;err("still waiting on run dependencies:")}err(`dependency: ${dep}`)}if(shown){err("(end of list)")}},1e4)}}else{err("warning: run dependency added without ID")}}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(id){assert(runDependencyTracking[id]);delete runDependencyTracking[id]}else{err("warning: run dependency removed without ID")}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;if(what.indexOf("RuntimeError: unreachable")>=0){what+='. "unreachable" may be due to ASYNCIFY_STACK_SIZE not being large enough (try increasing it)'}var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var FS={error(){abort("Filesystem support (FS) was not included. The problem is that you are using files from JS, but files were not used from C/C++, so filesystem support was not auto-included. You can force-include filesystem support with -sFORCE_FILESYSTEM")},init(){FS.error()},createDataFile(){FS.error()},createPreloadedFile(){FS.error()},createLazyFile(){FS.error()},open(){FS.error()},mkdev(){FS.error()},registerDevice(){FS.error()},analyzePath(){FS.error()},ErrnoError(){FS.error()}};Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");function createExportWrapper(name,nargs){return(...args)=>{assert(runtimeInitialized,`native function \`${name}\` called before runtime initialization`);var f=wasmExports[name];assert(f,`exported native function \`${name}\` not found`);assert(args.length<=nargs,`native function \`${name}\` called with ${args.length} args but expects ${nargs}`);return f(...args)}}function findWasmBinary(){var f="amy.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);if(isFileURI(wasmBinaryFile)){err(`warning: Loading from a file URI (${wasmBinaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`)}abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){Asyncify.instrumentWasmImports(wasmImports);return{env:wasmImports,wasi_snapshot_preview1:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=Asyncify.instrumentWasmExports(wasmExports);wasmTable=wasmExports["__indirect_function_table"];Module["wasmTable"]=wasmTable;assert(wasmTable,"table not found in wasm exports");addOnInit(wasmExports["__wasm_call_ctors"]);wasmModule=module;removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");var trueModule=Module;function receiveInstantiationResult(result){assert(Module===trueModule,"the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?");trueModule=null;receiveInstance(result["instance"],result["module"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}if(!wasmBinaryFile)wasmBinaryFile=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}(()=>{var h16=new Int16Array(1);var h8=new Int8Array(h16.buffer);h16[0]=25459;if(h8[0]!==115||h8[1]!==99)throw"Runtime error: expected the system to be little-endian! (Run with -sSUPPORT_BIG_ENDIAN to bypass)"})();function legacyModuleProp(prop,newName,incoming=true){if(!Object.getOwnPropertyDescriptor(Module,prop)){Object.defineProperty(Module,prop,{configurable:true,get(){let extra=incoming?" (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)":"";abort(`\`Module.${prop}\` has been replaced by \`${newName}\``+extra)}})}}function ignoredModuleProp(prop){if(Object.getOwnPropertyDescriptor(Module,prop)){abort(`\`Module.${prop}\` was supplied but \`${prop}\` not included in INCOMING_MODULE_JS_API`)}}function isExportedByForceFilesystem(name){return name==="FS_createPath"||name==="FS_createDataFile"||name==="FS_createPreloadedFile"||name==="FS_unlink"||name==="addRunDependency"||name==="FS_createLazyFile"||name==="FS_createDevice"||name==="removeRunDependency"}function missingGlobal(sym,msg){if(typeof globalThis!="undefined"){Object.defineProperty(globalThis,sym,{configurable:true,get(){warnOnce(`\`${sym}\` is not longer defined by emscripten. ${msg}`);return undefined}})}}missingGlobal("buffer","Please use HEAP8.buffer or wasmMemory.buffer");missingGlobal("asm","Please use wasmExports instead");function missingLibrarySymbol(sym){if(typeof globalThis!="undefined"&&!Object.getOwnPropertyDescriptor(globalThis,sym)){Object.defineProperty(globalThis,sym,{configurable:true,get(){var msg=`\`${sym}\` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line`;var librarySymbol=sym;if(!librarySymbol.startsWith("_")){librarySymbol="$"+sym}msg+=` (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='${librarySymbol}')`;if(isExportedByForceFilesystem(sym)){msg+=". Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you"}warnOnce(msg);return undefined}})}unexportedRuntimeSymbol(sym)}function unexportedRuntimeSymbol(sym){if(!Object.getOwnPropertyDescriptor(Module,sym)){Object.defineProperty(Module,sym,{configurable:true,get(){var msg=`'${sym}' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ)`;if(isExportedByForceFilesystem(sym)){msg+=". Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you"}abort(msg)}})}}var ASM_CONSTS={1109840:$0=>{amy_sequencer_js_hook($0)},1109871:($0,$1,$2,$3,$4)=>{if(typeof window==="undefined"||(window.AudioContext||window.webkitAudioContext)===undefined){return 0}if(typeof window.miniaudio==="undefined"){window.miniaudio={referenceCount:0};window.miniaudio.device_type={};window.miniaudio.device_type.playback=$0;window.miniaudio.device_type.capture=$1;window.miniaudio.device_type.duplex=$2;window.miniaudio.device_state={};window.miniaudio.device_state.stopped=$3;window.miniaudio.device_state.started=$4;miniaudio.devices=[];miniaudio.track_device=function(device){for(var iDevice=0;iDevice0){if(miniaudio.devices[miniaudio.devices.length-1]==null){miniaudio.devices.pop()}else{break}}};miniaudio.untrack_device=function(device){for(var iDevice=0;iDevice{Module._ma_device__on_notification_unlocked(device.pDevice)},error=>{console.error("Failed to resume audiocontext",error)})}}miniaudio.unlock_event_types.map(function(event_type){document.removeEventListener(event_type,miniaudio.unlock,true)})};miniaudio.unlock_event_types.map(function(event_type){document.addEventListener(event_type,miniaudio.unlock,true)})}window.miniaudio.referenceCount+=1;return 1},1112029:()=>{if(typeof window.miniaudio!=="undefined"){window.miniaudio.referenceCount-=1;if(window.miniaudio.referenceCount===0){delete window.miniaudio}}},1112193:()=>navigator.mediaDevices!==undefined&&navigator.mediaDevices.getUserMedia!==undefined,1112297:()=>{try{var temp=new(window.AudioContext||window.webkitAudioContext);var sampleRate=temp.sampleRate;temp.close();return sampleRate}catch(e){return 0}},1112468:$0=>miniaudio.track_device({webaudio:emscriptenGetAudioObject($0),state:1}),1112557:($0,$1)=>{var getUserMediaResult=0;var audioWorklet=emscriptenGetAudioObject($0);var audioContext=emscriptenGetAudioObject($1);navigator.mediaDevices.getUserMedia({audio:true,video:false}).then(function(stream){audioContext.streamNode=audioContext.createMediaStreamSource(stream);audioContext.streamNode.connect(audioWorklet);audioWorklet.connect(audioContext.destination);getUserMediaResult=0}).catch(function(error){console.log("navigator.mediaDevices.getUserMedia Failed: "+error);getUserMediaResult=-1});return getUserMediaResult},1113119:($0,$1)=>{var audioWorklet=emscriptenGetAudioObject($0);var audioContext=emscriptenGetAudioObject($1);audioWorklet.connect(audioContext.destination);return 0},1113279:$0=>emscriptenGetAudioObject($0).sampleRate,1113331:$0=>{var device=miniaudio.get_device_by_index($0);if(device.streamNode!==undefined){device.streamNode.disconnect();device.streamNode=undefined}},1113487:$0=>{miniaudio.untrack_device_by_index($0)},1113530:$0=>{var device=miniaudio.get_device_by_index($0);device.webaudio.resume();device.state=miniaudio.device_state.started},1113655:$0=>{var device=miniaudio.get_device_by_index($0);device.webaudio.suspend();device.state=miniaudio.device_state.stopped}};function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var _wasmWorkerDelayedMessageQueue=[];var wasmTableMirror=[];var wasmTable;var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}assert(wasmTable.get(funcPtr)==func,"JavaScript-side Wasm function table mirror is out of date!");return func};var _wasmWorkerRunPostMessage=e=>{let data=ENVIRONMENT_IS_NODE?e:e.data;let wasmCall=data["_wsc"];wasmCall&&getWasmTableEntry(wasmCall)(...data["x"])};var _wasmWorkerAppendToQueue=e=>{_wasmWorkerDelayedMessageQueue.push(e)};var _wasmWorkerInitializeRuntime=()=>{let m=Module;assert(m["sb"]%16==0);assert(m["sz"]%16==0);__emscripten_wasm_worker_initialize(m["sb"],m["sz"]);if(typeof AudioWorkletGlobalScope==="undefined"){removeEventListener("message",_wasmWorkerAppendToQueue);_wasmWorkerDelayedMessageQueue=_wasmWorkerDelayedMessageQueue.forEach(_wasmWorkerRunPostMessage);addEventListener("message",_wasmWorkerRunPostMessage)}};var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||true;var ptrToString=ptr=>{assert(typeof ptr==="number");ptr>>>=0;return"0x"+ptr.toString(16).padStart(8,"0")};var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var warnOnce=text=>{warnOnce.shown||={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.buffer instanceof SharedArrayBuffer?heapOrArray.slice(idx,endPtr):heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>{assert(typeof ptr=="number",`UTF8ToString expects a number (got ${typeof ptr})`);return ptr?UTF8ArrayToString(GROWABLE_HEAP_U8(),ptr,maxBytesToRead):""};var ___assert_fail=(condition,filename,line,func)=>{abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])};var __abort_js=()=>{abort("native code called abort()")};var nowIsMonotonic=1;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;var readEmAsmArgsArray=[];var readEmAsmArgs=(sigPtr,buf)=>{assert(Array.isArray(readEmAsmArgsArray));assert(buf%16==0);readEmAsmArgsArray.length=0;var ch;while(ch=GROWABLE_HEAP_U8()[sigPtr++]){var chr=String.fromCharCode(ch);var validChars=["d","f","i","p"];assert(validChars.includes(chr),`Invalid character ${ch}("${chr}") in readEmAsmArgs! Use only [${validChars}], and do not specify "v" for void return argument.`);var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?GROWABLE_HEAP_U32()[buf>>2]:ch==105?GROWABLE_HEAP_I32()[buf>>2]:GROWABLE_HEAP_F64()[buf>>3]);buf+=wide?8:4}return readEmAsmArgsArray};var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);assert(ASM_CONSTS.hasOwnProperty(code),`No EM_ASM constant found at address ${code}. The loaded WebAssembly file is likely out of sync with the generated JavaScript.`);return ASM_CONSTS[code](...args)};var _emscripten_asm_const_int=(code,sigPtr,argbuf)=>runEmAsmFunction(code,sigPtr,argbuf);var EmAudio={};var EmAudioCounter=0;var emscriptenRegisterAudioObject=object=>{assert(object,"Called emscriptenRegisterAudioObject() with a null object handle!");EmAudio[++EmAudioCounter]=object;return EmAudioCounter};var emscriptenGetAudioObject=objectHandle=>EmAudio[objectHandle];var _emscripten_create_audio_context=options=>{let ctx=window.AudioContext||window.webkitAudioContext;if(!ctx)console.error("emscripten_create_audio_context failed! Web Audio is not supported.");options>>=2;let opts=options?{latencyHint:GROWABLE_HEAP_U32()[options]?UTF8ToString(GROWABLE_HEAP_U32()[options]):void 0,sampleRate:GROWABLE_HEAP_I32()[options+1]||void 0}:void 0;return ctx&&emscriptenRegisterAudioObject(new ctx(opts))};var _emscripten_create_wasm_audio_worklet_node=(contextHandle,name,options,callback,userData)=>{assert(contextHandle,`Called emscripten_create_wasm_audio_worklet_node() with a null Web Audio Context handle!`);assert(EmAudio[contextHandle],`Called emscripten_create_wasm_audio_worklet_node() with a nonexisting/already freed Web Audio Context handle ${contextHandle}!`);assert(EmAudio[contextHandle]instanceof(window.AudioContext||window.webkitAudioContext),`Called emscripten_create_wasm_audio_worklet_node() on a context handle ${contextHandle} that is not an AudioContext, but of type ${typeof EmAudio[contextHandle]}`);options>>=2;function readChannelCountArray(heapIndex,numOutputs){let channelCounts=[];while(numOutputs--)channelCounts.push(GROWABLE_HEAP_U32()[heapIndex++]);return channelCounts}let opts=options?{numberOfInputs:GROWABLE_HEAP_I32()[options],numberOfOutputs:GROWABLE_HEAP_I32()[options+1],outputChannelCount:GROWABLE_HEAP_U32()[options+2]?readChannelCountArray(GROWABLE_HEAP_U32()[options+2]>>2,GROWABLE_HEAP_I32()[options+1]):void 0,processorOptions:{cb:callback,ud:userData}}:void 0;return emscriptenRegisterAudioObject(new AudioWorkletNode(EmAudio[contextHandle],UTF8ToString(name),opts))};var _emscripten_create_wasm_audio_worklet_processor_async=(contextHandle,options,callback,userData)=>{assert(contextHandle,`Called emscripten_create_wasm_audio_worklet_processor_async() with a null Web Audio Context handle!`);assert(EmAudio[contextHandle],`Called emscripten_create_wasm_audio_worklet_processor_async() with a nonexisting/already freed Web Audio Context handle ${contextHandle}!`);assert(EmAudio[contextHandle]instanceof(window.AudioContext||window.webkitAudioContext),`Called emscripten_create_wasm_audio_worklet_processor_async() on a context handle ${contextHandle} that is not an AudioContext, but of type ${typeof EmAudio[contextHandle]}`);options>>=2;let audioParams=[],numAudioParams=GROWABLE_HEAP_U32()[options+1],audioParamDescriptors=GROWABLE_HEAP_U32()[options+2]>>2,i=0;while(numAudioParams--){audioParams.push({name:i++,defaultValue:GROWABLE_HEAP_F32()[audioParamDescriptors++],minValue:GROWABLE_HEAP_F32()[audioParamDescriptors++],maxValue:GROWABLE_HEAP_F32()[audioParamDescriptors++],automationRate:["a","k"][GROWABLE_HEAP_U32()[audioParamDescriptors++]]+"-rate"})}EmAudio[contextHandle].audioWorklet.bootstrapMessage.port.postMessage({_wpn:UTF8ToString(GROWABLE_HEAP_U32()[options]),audioParams,contextHandle,callback,userData})};var _emscripten_date_now=()=>Date.now();var _emscripten_destroy_audio_context=contextHandle=>{assert(EmAudio[contextHandle],`Called emscripten_destroy_audio_context() on an already freed context handle ${contextHandle}`);assert(EmAudio[contextHandle]instanceof(window.AudioContext||window.webkitAudioContext),`Called emscripten_destroy_audio_context() on a context handle ${contextHandle} that is not an AudioContext, but of type ${typeof EmAudio[contextHandle]}`);EmAudio[contextHandle].suspend();delete EmAudio[contextHandle]};var _emscripten_destroy_web_audio_node=objectHandle=>{assert(EmAudio[objectHandle],`Called emscripten_destroy_web_audio_node() on a nonexisting/already freed object handle ${objectHandle}`);assert(EmAudio[objectHandle].disconnect,`Called emscripten_destroy_web_audio_node() on a handle ${objectHandle} that is not an Web Audio Node, but of type ${typeof EmAudio[objectHandle]}`);EmAudio[objectHandle].disconnect();delete EmAudio[objectHandle]};var _emscripten_get_now;if(typeof performance!="undefined"&&performance.now){_emscripten_get_now=()=>performance.now()}else{_emscripten_get_now=Date.now}var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>{assert(alignment,"alignment argument is required");return Math.ceil(size/alignment)*alignment};var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){err(`growMemory: Attempted to grow heap from ${b.byteLength} bytes to ${size} bytes, but got error: ${e}`)}};var _emscripten_resize_heap=requestedSize=>{var oldSize=GROWABLE_HEAP_U8().length;requestedSize>>>=0;if(requestedSize<=oldSize){return false}var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){err(`Cannot enlarge memory, requested ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`);return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}err(`Failed to grow the heap from ${oldSize} bytes to ${newSize} bytes, not enough memory!`);return false};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}checkStackCookie();if(e instanceof WebAssembly.RuntimeError){if(_emscripten_stack_get_current()<=0){err("Stack overflow detected. You can try increasing -sSTACK_SIZE (currently set to 67108864)")}}quit_(1,e)};var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;checkUnflushedContent();if(keepRuntimeAlive()&&!implicit){var msg=`program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`;readyPromiseReject(msg);err(msg)}_proc_exit(status)};var _exit=exitJS;var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(ABORT){err("user callback triggered after runtime exited or application aborted. Ignoring.");return}try{func();maybeExit()}catch(e){handleException(e)}};var safeSetTimeout=(func,timeout)=>setTimeout(()=>{callUserCallback(func)},timeout);var preloadPlugins=Module["preloadPlugins"]||[];var Browser={mainLoop:{running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining{assert(img.complete,`Image ${name} could not be decoded`);var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;URL.revokeObjectURL(url);onload?.(byteArray)};img.onerror=event=>{err(`Image ${url} could not be decoded`);onerror?.()};img.src=url};preloadPlugins.push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module["noAudioDecoding"]&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;onload?.(byteArray)}var b=new Blob([byteArray],{type:Browser.getMimetype(name)});var url=URL.createObjectURL(b);assert(typeof url=="string","createObjectURL must return a url as a string");var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`);function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(()=>{finish(audio)},1e4)};preloadPlugins.push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){if(!useWebGL)assert(typeof GLctx=="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Browser.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());Browser.init()}return ctx},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}Module["onFullScreen"]?.(Browser.isFullscreen);Module["onFullscreen"]?.(Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},requestFullScreen(){abort("Module.requestFullScreen has been replaced by Module.requestFullscreen (without a capital S)")},exitFullscreen(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||(()=>{});CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeSetTimeout(func,timeout){return safeSetTimeout(func,timeout)},safeRequestAnimationFrame(func){return Browser.requestAnimationFrame(()=>{callUserCallback(func)})},getMimetype(name){return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",bmp:"image/bmp",ogg:"audio/ogg",wav:"audio/wav",mp3:"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia(func){window.getUserMedia||=navigator["getUserMedia"]||navigator["mozGetUserMedia"];window.getUserMedia(func)},getMovementX(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseCoords(pageX,pageY){var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;assert(typeof scrollX!="undefined"&&typeof scrollY!="undefined","Unable to retrieve scroll position, mouse positions likely broken.");var adjustedX=pageX-(scrollX+rect.left);var adjustedY=pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);return{x:adjustedX,y:adjustedY}},setMouseCoords(pageX,pageY){const{x,y}=Browser.calculateMouseCoords(pageX,pageY);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y},calculateMouseEvent(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}else{if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var coords=Browser.calculateMouseCoords(touch.pageX,touch.pageY);if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];last||=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}Browser.setMouseCoords(event.pageX,event.pageY)}},resizeListeners:[],updateResizeListeners(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(listener=>listener(canvas.width,canvas.height))},setCanvasSize(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize(){if(typeof SDL!="undefined"){var flags=GROWABLE_HEAP_U32()[SDL.screen>>2];flags=flags|8388608;GROWABLE_HEAP_I32()[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize(){if(typeof SDL!="undefined"){var flags=GROWABLE_HEAP_U32()[SDL.screen>>2];flags=flags&~8388608;GROWABLE_HEAP_I32()[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h{Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){err("emscripten_set_main_loop_timing: Cannot set timing mode for main loop since a main loop does not exist! Call emscripten_set_main_loop first to set one up.");return 1}if(!Browser.mainLoop.running){Browser.mainLoop.running=true}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof Browser.setImmediate=="undefined"){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);Browser.setImmediate=func=>{setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){Module["setImmediates"]??=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}else{Browser.setImmediate=setImmediate}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){Browser.setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0};var setMainLoop=(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming)=>{assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}Browser.mainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(Browser.mainLoop.runner,0);return}if(!checkIsRunning())return;Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0;if(Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}if(Browser.mainLoop.method==="timeout"&&Module.ctx){warnOnce("Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!");Browser.mainLoop.method=""}Browser.mainLoop.runIter(browserIterationFunc);checkStackCookie();if(!checkIsRunning())return;if(typeof SDL=="object")SDL.audio?.queueNewAudioData?.();Browser.mainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}};var _emscripten_set_main_loop=(func,fps,simulateInfiniteLoop)=>{var browserIterationFunc=()=>dynCall_v(func);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop)};var _emscripten_sleep=ms=>Asyncify.handleSleep(wakeUp=>safeSetTimeout(wakeUp,ms));_emscripten_sleep.isAsync=true;var _wasmWorkersID=1;var _EmAudioDispatchProcessorCallback=e=>{let data=e.data;let wasmCall=data["_wsc"];wasmCall&&getWasmTableEntry(wasmCall)(...data["x"])};var _emscripten_start_wasm_audio_worklet_thread_async=(contextHandle,stackLowestAddress,stackSize,callback,userData)=>{assert(contextHandle,`Called emscripten_start_wasm_audio_worklet_thread_async() with a null Web Audio Context handle!`);assert(EmAudio[contextHandle],`Called emscripten_start_wasm_audio_worklet_thread_async() with a nonexisting/already freed Web Audio Context handle ${contextHandle}!`);assert(EmAudio[contextHandle]instanceof(window.AudioContext||window.webkitAudioContext),`Called emscripten_start_wasm_audio_worklet_thread_async() on a context handle ${contextHandle} that is not an AudioContext, but of type ${typeof EmAudio[contextHandle]}`);let audioContext=EmAudio[contextHandle],audioWorklet=audioContext.audioWorklet;assert(stackLowestAddress!=0,"AudioWorklets require a dedicated stack space for audio data marshalling between Wasm and JS!");assert(stackLowestAddress%16==0,`AudioWorklet stack should be aligned to 16 bytes! (was ${stackLowestAddress} == ${stackLowestAddress%16} mod 16) Use e.g. memalign(16, stackSize) to align the stack!`);assert(stackSize!=0,"AudioWorklets require a dedicated stack space for audio data marshalling between Wasm and JS!");assert(stackSize%16==0,`AudioWorklet stack size should be a multiple of 16 bytes! (was ${stackSize} == ${stackSize%16} mod 16)`);assert(!audioContext.audioWorkletInitialized,"emscripten_create_wasm_audio_worklet() was already called for AudioContext "+contextHandle+"! Only call this function once per AudioContext!");audioContext.audioWorkletInitialized=1;let audioWorkletCreationFailed=()=>{((a1,a2,a3)=>dynCall_viii(callback,a1,a2,a3))(contextHandle,0,userData)};if(!audioWorklet){return audioWorkletCreationFailed()}audioWorklet.addModule("amy.aw.js").then(()=>{audioWorklet.bootstrapMessage=new AudioWorkletNode(audioContext,"message",{processorOptions:{$ww:_wasmWorkersID++,wasm:wasmModule,wasmMemory,sb:stackLowestAddress,sz:stackSize}});audioWorklet.bootstrapMessage.port.onmessage=_EmAudioDispatchProcessorCallback;return audioWorklet.addModule(Module["mainScriptUrlOrBlob"]||_scriptName)}).then(()=>{((a1,a2,a3)=>dynCall_viii(callback,a1,a2,a3))(contextHandle,1,userData)}).catch(audioWorkletCreationFailed)};var _fd_close=fd=>{abort("fd_close called without SYSCALLS_REQUIRE_FILESYSTEM")};var convertI32PairToI53Checked=(lo,hi)=>{assert(lo==lo>>>0||lo==(lo|0));assert(hi===(hi|0));return hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN};function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);return 70}var printCharBuffers=[null,[],[]];var printChar=(stream,curr)=>{var buffer=printCharBuffers[stream];assert(buffer);if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}};var flush_NO_FILESYSTEM=()=>{_fflush(0);if(printCharBuffers[1].length)printChar(1,10);if(printCharBuffers[2].length)printChar(2,10)};var _fd_write=(fd,iov,iovcnt,pnum)=>{var num=0;for(var i=0;i>2];var len=GROWABLE_HEAP_U32()[iov+4>>2];iov+=8;for(var j=0;j>2]=num;return 0};var runAndAbortIfError=func=>{try{return func()}catch(e){abort(e)}};var runtimeKeepalivePush=()=>{runtimeKeepaliveCounter+=1};var runtimeKeepalivePop=()=>{assert(runtimeKeepaliveCounter>0);runtimeKeepaliveCounter-=1};var Asyncify={instrumentWasmImports(imports){var importPattern=/^(invoke_.*|__asyncjs__.*)$/;for(let[x,original]of Object.entries(imports)){if(typeof original=="function"){let isAsyncifyImport=original.isAsync||importPattern.test(x);imports[x]=(...args)=>{var originalAsyncifyState=Asyncify.state;try{return original(...args)}finally{var changedToDisabled=originalAsyncifyState===Asyncify.State.Normal&&Asyncify.state===Asyncify.State.Disabled;var ignoredInvoke=x.startsWith("invoke_")&&true;if(Asyncify.state!==originalAsyncifyState&&!isAsyncifyImport&&!changedToDisabled&&!ignoredInvoke){throw new Error(`import ${x} was not in ASYNCIFY_IMPORTS, but changed the state`)}}}}}},instrumentWasmExports(exports){var ret={};for(let[x,original]of Object.entries(exports)){if(typeof original=="function"){ret[x]=(...args)=>{Asyncify.exportCallStack.push(x);try{return original(...args)}finally{if(!ABORT){var y=Asyncify.exportCallStack.pop();assert(y===x);Asyncify.maybeStopUnwind()}}}}else{ret[x]=original}}return ret},State:{Normal:0,Unwinding:1,Rewinding:2,Disabled:3},state:0,StackSize:4096,currData:null,handleSleepReturnValue:0,exportCallStack:[],callStackNameToId:{},callStackIdToName:{},callStackId:0,asyncPromiseHandlers:null,sleepCallbacks:[],getCallStackId(funcName){var id=Asyncify.callStackNameToId[funcName];if(id===undefined){id=Asyncify.callStackId++;Asyncify.callStackNameToId[funcName]=id;Asyncify.callStackIdToName[id]=funcName}return id},maybeStopUnwind(){if(Asyncify.currData&&Asyncify.state===Asyncify.State.Unwinding&&Asyncify.exportCallStack.length===0){Asyncify.state=Asyncify.State.Normal;runAndAbortIfError(_asyncify_stop_unwind);if(typeof Fibers!="undefined"){Fibers.trampoline()}}},whenDone(){assert(Asyncify.currData,"Tried to wait for an async operation when none is in progress.");assert(!Asyncify.asyncPromiseHandlers,"Cannot have multiple async operations in flight at once");return new Promise((resolve,reject)=>{Asyncify.asyncPromiseHandlers={resolve,reject}})},allocateData(){var ptr=_malloc(12+Asyncify.StackSize);Asyncify.setDataHeader(ptr,ptr+12,Asyncify.StackSize);Asyncify.setDataRewindFunc(ptr);return ptr},setDataHeader(ptr,stack,stackSize){GROWABLE_HEAP_U32()[ptr>>2]=stack;GROWABLE_HEAP_U32()[ptr+4>>2]=stack+stackSize},setDataRewindFunc(ptr){var bottomOfCallStack=Asyncify.exportCallStack[0];var rewindId=Asyncify.getCallStackId(bottomOfCallStack);GROWABLE_HEAP_I32()[ptr+8>>2]=rewindId},getDataRewindFuncName(ptr){var id=GROWABLE_HEAP_I32()[ptr+8>>2];var name=Asyncify.callStackIdToName[id];return name},getDataRewindFunc(name){var func=wasmExports[name];return func},doRewind(ptr){var name=Asyncify.getDataRewindFuncName(ptr);var func=Asyncify.getDataRewindFunc(name);return func()},handleSleep(startAsync){assert(Asyncify.state!==Asyncify.State.Disabled,"Asyncify cannot be done during or after the runtime exits");if(ABORT)return;if(Asyncify.state===Asyncify.State.Normal){var reachedCallback=false;var reachedAfterCallback=false;startAsync((handleSleepReturnValue=0)=>{assert(!handleSleepReturnValue||typeof handleSleepReturnValue=="number"||typeof handleSleepReturnValue=="boolean");if(ABORT)return;Asyncify.handleSleepReturnValue=handleSleepReturnValue;reachedCallback=true;if(!reachedAfterCallback){return}assert(!Asyncify.exportCallStack.length,"Waking up (starting to rewind) must be done from JS, without compiled code on the stack.");Asyncify.state=Asyncify.State.Rewinding;runAndAbortIfError(()=>_asyncify_start_rewind(Asyncify.currData));if(typeof Browser!="undefined"&&Browser.mainLoop.func){Browser.mainLoop.resume()}var asyncWasmReturnValue,isError=false;try{asyncWasmReturnValue=Asyncify.doRewind(Asyncify.currData)}catch(err){asyncWasmReturnValue=err;isError=true}var handled=false;if(!Asyncify.currData){var asyncPromiseHandlers=Asyncify.asyncPromiseHandlers;if(asyncPromiseHandlers){Asyncify.asyncPromiseHandlers=null;(isError?asyncPromiseHandlers.reject:asyncPromiseHandlers.resolve)(asyncWasmReturnValue);handled=true}}if(isError&&!handled){throw asyncWasmReturnValue}});reachedAfterCallback=true;if(!reachedCallback){Asyncify.state=Asyncify.State.Unwinding;Asyncify.currData=Asyncify.allocateData();if(typeof Browser!="undefined"&&Browser.mainLoop.func){Browser.mainLoop.pause()}runAndAbortIfError(()=>_asyncify_start_unwind(Asyncify.currData))}}else if(Asyncify.state===Asyncify.State.Rewinding){Asyncify.state=Asyncify.State.Normal;runAndAbortIfError(_asyncify_stop_rewind);_free(Asyncify.currData);Asyncify.currData=null;Asyncify.sleepCallbacks.forEach(callUserCallback)}else{abort(`invalid state: ${Asyncify.state}`)}return Asyncify.handleSleepReturnValue},handleAsync(startAsync){return Asyncify.handleSleep(wakeUp=>{startAsync().then(wakeUp)})}};var getCFunc=ident=>{var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func};var writeArrayToMemory=(array,buffer)=>{assert(array.length>=0,"writeArrayToMemory array must have a length (should be an array or typed array)");GROWABLE_HEAP_I8().set(array,buffer)};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{assert(typeof str==="string",`stringToUTF8Array expects a string (got ${typeof str})`);if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;if(u>1114111)warnOnce("Invalid Unicode code point "+ptrToString(u)+" encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).");heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>{assert(typeof maxBytesToWrite=="number","stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!");return stringToUTF8Array(str,GROWABLE_HEAP_U8(),outPtr,maxBytesToWrite)};var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;assert(returnType!=="array",'Return type should not be "array".');if(args){for(var i=0;i(...args)=>ccall(ident,returnType,argTypes,args,opts);Module["requestFullscreen"]=Browser.requestFullscreen;Module["requestFullScreen"]=Browser.requestFullScreen;Module["requestAnimationFrame"]=Browser.requestAnimationFrame;Module["setCanvasSize"]=Browser.setCanvasSize;Module["pauseMainLoop"]=Browser.mainLoop.pause;Module["resumeMainLoop"]=Browser.mainLoop.resume;Module["getUserMedia"]=Browser.getUserMedia;Module["createContext"]=Browser.createContext;var preloadedImages={};var preloadedAudios={};function checkIncomingModuleAPI(){ignoredModuleProp("fetchSettings")}var wasmImports={__assert_fail:___assert_fail,_abort_js:__abort_js,_emscripten_get_now_is_monotonic:__emscripten_get_now_is_monotonic,emscripten_asm_const_int:_emscripten_asm_const_int,emscripten_create_audio_context:_emscripten_create_audio_context,emscripten_create_wasm_audio_worklet_node:_emscripten_create_wasm_audio_worklet_node,emscripten_create_wasm_audio_worklet_processor_async:_emscripten_create_wasm_audio_worklet_processor_async,emscripten_date_now:_emscripten_date_now,emscripten_destroy_audio_context:_emscripten_destroy_audio_context,emscripten_destroy_web_audio_node:_emscripten_destroy_web_audio_node,emscripten_get_now:_emscripten_get_now,emscripten_resize_heap:_emscripten_resize_heap,emscripten_set_main_loop:_emscripten_set_main_loop,emscripten_sleep:_emscripten_sleep,emscripten_start_wasm_audio_worklet_thread_async:_emscripten_start_wasm_audio_worklet_thread_async,exit:_exit,fd_close:_fd_close,fd_seek:_fd_seek,fd_write:_fd_write,memory:wasmMemory};var wasmExports=createWasm();var ___wasm_call_ctors=createExportWrapper("__wasm_call_ctors",0);var _free=Module["_free"]=createExportWrapper("free",1);var _malloc=Module["_malloc"]=createExportWrapper("malloc",1);var _amy_start=Module["_amy_start"]=createExportWrapper("amy_start",4);var _amy_reset_sysclock=Module["_amy_reset_sysclock"]=createExportWrapper("amy_reset_sysclock",0);var _amy_play_message=Module["_amy_play_message"]=createExportWrapper("amy_play_message",1);var _sequencer_ticks=Module["_sequencer_ticks"]=createExportWrapper("sequencer_ticks",0);var _ma_device__on_notification_unlocked=Module["_ma_device__on_notification_unlocked"]=createExportWrapper("ma_device__on_notification_unlocked",1);var _ma_malloc_emscripten=Module["_ma_malloc_emscripten"]=createExportWrapper("ma_malloc_emscripten",2);var _ma_free_emscripten=Module["_ma_free_emscripten"]=createExportWrapper("ma_free_emscripten",2);var _ma_device_process_pcm_frames_capture__webaudio=Module["_ma_device_process_pcm_frames_capture__webaudio"]=createExportWrapper("ma_device_process_pcm_frames_capture__webaudio",3);var _ma_device_process_pcm_frames_playback__webaudio=Module["_ma_device_process_pcm_frames_playback__webaudio"]=createExportWrapper("ma_device_process_pcm_frames_playback__webaudio",3);var _amy_live_start=Module["_amy_live_start"]=createExportWrapper("amy_live_start",0);var _fflush=createExportWrapper("fflush",1);var _strerror=createExportWrapper("strerror",1);var _emscripten_stack_init=()=>(_emscripten_stack_init=wasmExports["emscripten_stack_init"])();var _emscripten_stack_get_free=()=>(_emscripten_stack_get_free=wasmExports["emscripten_stack_get_free"])();var _emscripten_stack_get_base=()=>(_emscripten_stack_get_base=wasmExports["emscripten_stack_get_base"])();var _emscripten_stack_get_end=()=>(_emscripten_stack_get_end=wasmExports["emscripten_stack_get_end"])();var __emscripten_wasm_worker_initialize=createExportWrapper("_emscripten_wasm_worker_initialize",2);var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["_emscripten_stack_restore"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["_emscripten_stack_alloc"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["emscripten_stack_get_current"])();var dynCall_ii=Module["dynCall_ii"]=createExportWrapper("dynCall_ii",2);var dynCall_vii=Module["dynCall_vii"]=createExportWrapper("dynCall_vii",3);var dynCall_iiii=Module["dynCall_iiii"]=createExportWrapper("dynCall_iiii",4);var dynCall_iii=Module["dynCall_iii"]=createExportWrapper("dynCall_iii",3);var dynCall_iiiii=Module["dynCall_iiiii"]=createExportWrapper("dynCall_iiiii",5);var dynCall_viii=Module["dynCall_viii"]=createExportWrapper("dynCall_viii",4);var dynCall_viiii=Module["dynCall_viiii"]=createExportWrapper("dynCall_viiii",5);var dynCall_v=Module["dynCall_v"]=createExportWrapper("dynCall_v",1);var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=createExportWrapper("dynCall_iiiiiiii",8);var dynCall_iiiji=Module["dynCall_iiiji"]=createExportWrapper("dynCall_iiiji",6);var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=createExportWrapper("dynCall_iiiiiii",7);var dynCall_jii=Module["dynCall_jii"]=createExportWrapper("dynCall_jii",3);var dynCall_jiji=Module["dynCall_jiji"]=createExportWrapper("dynCall_jiji",5);var dynCall_iidiiii=Module["dynCall_iidiiii"]=createExportWrapper("dynCall_iidiiii",7);var _asyncify_start_unwind=createExportWrapper("asyncify_start_unwind",1);var _asyncify_stop_unwind=createExportWrapper("asyncify_stop_unwind",0);var _asyncify_start_rewind=createExportWrapper("asyncify_start_rewind",1);var _asyncify_stop_rewind=createExportWrapper("asyncify_stop_rewind",0);Module["stackSave"]=stackSave;Module["stackRestore"]=stackRestore;Module["stackAlloc"]=stackAlloc;Module["wasmTable"]=wasmTable;Module["ccall"]=ccall;Module["cwrap"]=cwrap;var missingLibrarySymbols=["writeI53ToI64","writeI53ToI64Clamped","writeI53ToI64Signaling","writeI53ToU64Clamped","writeI53ToU64Signaling","readI53FromI64","readI53FromU64","convertI32PairToI53","convertU32PairToI53","getTempRet0","setTempRet0","zeroMemory","strError","inetPton4","inetNtop4","inetPton6","inetNtop6","readSockaddr","writeSockaddr","initRandomFill","randomFill","emscriptenLog","runMainThreadEmAsm","jstoi_q","getExecutableName","listenOnce","autoResumeAudioContext","dynCallLegacy","getDynCaller","dynCall","asmjsMangle","asyncLoad","mmapAlloc","HandleAllocator","getNativeTypeSize","STACK_SIZE","STACK_ALIGN","POINTER_SIZE","ASSERTIONS","uleb128Encode","generateFuncType","convertJsFunctionToWasm","getEmptyTableSlot","updateTableMap","getFunctionAddress","addFunction","removeFunction","reallyNegative","unSign","strLen","reSign","formatString","intArrayFromString","intArrayToString","AsciiToString","stringToAscii","UTF16ToString","stringToUTF16","lengthBytesUTF16","UTF32ToString","stringToUTF32","lengthBytesUTF32","stringToNewUTF8","registerKeyEventCallback","maybeCStringToJsString","findEventTarget","getBoundingClientRect","fillMouseEventData","registerMouseEventCallback","registerWheelEventCallback","registerUiEventCallback","registerFocusEventCallback","fillDeviceOrientationEventData","registerDeviceOrientationEventCallback","fillDeviceMotionEventData","registerDeviceMotionEventCallback","screenOrientation","fillOrientationChangeEventData","registerOrientationChangeEventCallback","fillFullscreenChangeEventData","registerFullscreenChangeEventCallback","JSEvents_requestFullscreen","JSEvents_resizeCanvasForFullscreen","registerRestoreOldStyle","hideEverythingExceptGivenElement","restoreHiddenElements","setLetterbox","softFullscreenResizeWebGLRenderTarget","doRequestFullscreen","fillPointerlockChangeEventData","registerPointerlockChangeEventCallback","registerPointerlockErrorEventCallback","requestPointerLock","fillVisibilityChangeEventData","registerVisibilityChangeEventCallback","registerTouchEventCallback","fillGamepadEventData","registerGamepadEventCallback","registerBeforeUnloadEventCallback","fillBatteryEventData","battery","registerBatteryEventCallback","setCanvasElementSize","getCanvasElementSize","jsStackTrace","getCallstack","convertPCtoSourceLocation","getEnvStrings","checkWasiClock","wasiRightsToMuslOFlags","wasiOFlagsToMuslOFlags","createDyncallWrapper","setImmediateWrapped","clearImmediateWrapped","polyfillSetImmediate","getPromise","makePromise","idsToPromises","makePromiseCallback","ExceptionInfo","findMatchingCatch","Browser_asyncPrepareDataCounter","isLeapYear","ydayFromDate","arraySum","addDays","getSocketFromFD","getSocketAddress","FS_createPreloadedFile","FS_modeStringToFlags","FS_getMode","FS_stdin_getChar","FS_unlink","FS_createDataFile","FS_mkdirTree","_setNetworkCallback","heapObjectForWebGLType","toTypedArrayIndex","webgl_enable_ANGLE_instanced_arrays","webgl_enable_OES_vertex_array_object","webgl_enable_WEBGL_draw_buffers","webgl_enable_WEBGL_multi_draw","webgl_enable_EXT_polygon_offset_clamp","webgl_enable_EXT_clip_control","webgl_enable_WEBGL_polygon_mode","emscriptenWebGLGet","computeUnpackAlignedImageSize","colorChannelsInGlTextureFormat","emscriptenWebGLGetTexPixelData","emscriptenWebGLGetUniform","webglGetUniformLocation","webglPrepareUniformLocationsBeforeFirstUse","webglGetLeftBracePos","emscriptenWebGLGetVertexAttrib","__glGetActiveAttribOrUniform","writeGLArray","registerWebGlEventCallback","ALLOC_NORMAL","ALLOC_STACK","allocate","writeStringToMemory","writeAsciiToMemory","setErrNo","demangle","stackTrace","_wasmWorkerPostFunction1","_wasmWorkerPostFunction2","_wasmWorkerPostFunction3","emscripten_audio_worklet_post_function_1","emscripten_audio_worklet_post_function_2","emscripten_audio_worklet_post_function_3"];missingLibrarySymbols.forEach(missingLibrarySymbol);var unexportedSymbols=["run","addOnPreRun","addOnInit","addOnPreMain","addOnExit","addOnPostRun","addRunDependency","removeRunDependency","out","err","callMain","abort","wasmMemory","wasmExports","writeStackCookie","checkStackCookie","convertI32PairToI53Checked","ptrToString","exitJS","getHeapMax","growMemory","ENV","ERRNO_CODES","DNS","Protocols","Sockets","timers","warnOnce","readEmAsmArgsArray","readEmAsmArgs","runEmAsmFunction","jstoi_s","handleException","keepRuntimeAlive","runtimeKeepalivePush","runtimeKeepalivePop","callUserCallback","maybeExit","alignMemory","noExitRuntime","getCFunc","sigToWasmTypes","freeTableIndexes","functionsInTableMap","setValue","getValue","PATH","PATH_FS","UTF8Decoder","UTF8ArrayToString","UTF8ToString","stringToUTF8Array","stringToUTF8","lengthBytesUTF8","UTF16Decoder","stringToUTF8OnStack","writeArrayToMemory","JSEvents","specialHTMLTargets","findCanvasEventTarget","currentFullscreenStrategy","restoreOldWindowedStyle","UNWIND_CACHE","ExitStatus","flush_NO_FILESYSTEM","safeSetTimeout","promiseMap","uncaughtExceptionCount","exceptionLast","exceptionCaught","Browser","setMainLoop","getPreloadedImageData__data","wget","MONTH_DAYS_REGULAR","MONTH_DAYS_LEAP","MONTH_DAYS_REGULAR_CUMULATIVE","MONTH_DAYS_LEAP_CUMULATIVE","SYSCALLS","preloadPlugins","FS_stdin_getChar_buffer","FS_createPath","FS_createDevice","FS_readFile","FS","FS_createLazyFile","MEMFS","TTY","PIPEFS","SOCKFS","tempFixedLengthArray","miniTempWebGLFloatBuffers","miniTempWebGLIntBuffers","GL","AL","GLUT","EGL","GLEW","IDBStore","runAndAbortIfError","Asyncify","Fibers","SDL","SDL_gfx","allocateUTF8","allocateUTF8OnStack","print","printErr","_wasmWorkers","_wasmWorkersID","_wasmWorkerDelayedMessageQueue","_wasmWorkerAppendToQueue","_wasmWorkerRunPostMessage","_wasmWorkerInitializeRuntime","EmAudio","EmAudioCounter","emscriptenRegisterAudioObject","emscriptenDestroyAudioContext","emscriptenGetAudioObject","_EmAudioDispatchProcessorCallback"];unexportedSymbols.forEach(unexportedRuntimeSymbol);var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function stackCheckInit(){_emscripten_stack_init();writeStackCookie()}function run(){if(runDependencies>0){return}stackCheckInit();if(ENVIRONMENT_IS_WASM_WORKER){readyPromiseResolve(Module);return initRuntime()}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();assert(!Module["_main"],'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]');postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}checkStackCookie()}function checkUnflushedContent(){var oldOut=out;var oldErr=err;var has=false;out=err=x=>{has=true};try{flush_NO_FILESYSTEM()}catch(e){}out=oldOut;err=oldErr;if(has){warnOnce("stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the Emscripten FAQ), or make sure to emit a newline when you printf etc.");warnOnce("(this may also be due to not including full filesystem support - try building with -sFORCE_FILESYSTEM)")}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run();moduleRtn=readyPromise;for(const prop of Object.keys(Module)){if(!(prop in moduleArg)){Object.defineProperty(moduleArg,prop,{configurable:true,get(){abort(`Access to module property ('${prop}') is no longer possible via the module constructor argument; Instead, use the result of the module constructor.`)}})}} + + + return moduleRtn; +} +); +})(); +globalThis.AudioWorkletModule = amyModule; +if (typeof exports === 'object' && typeof module === 'object') + module.exports = amyModule; +else if (typeof define === 'function' && define['amd']) + define([], () => amyModule); diff --git a/www/run/amy.wasm b/www/run/amy.wasm new file mode 100755 index 00000000..f5c07383 Binary files /dev/null and b/www/run/amy.wasm differ diff --git a/www/run/enable-threads.js b/www/run/enable-threads.js new file mode 100644 index 00000000..a44179e9 --- /dev/null +++ b/www/run/enable-threads.js @@ -0,0 +1,75 @@ +// NOTE: This file creates a service worker that cross-origin-isolates the page (read more here: https://web.dev/coop-coep/) which allows us to use wasm threads. +// Normally you would set the COOP and COEP headers on the server to do this, but Github Pages doesn't allow this, so this is a hack to do that. + +/* Edited version of: coi-serviceworker v0.1.6 - Guido Zuidhof, licensed under MIT */ +// From here: https://github.com/gzuidhof/coi-serviceworker +if(typeof window === 'undefined') { + self.addEventListener("install", () => self.skipWaiting()); + self.addEventListener("activate", e => e.waitUntil(self.clients.claim())); + + async function handleFetch(request) { + if(request.cache === "only-if-cached" && request.mode !== "same-origin") { + return; + } + + if(request.mode === "no-cors") { // We need to set `credentials` to "omit" for no-cors requests, per this comment: https://bugs.chromium.org/p/chromium/issues/detail?id=1309901#c7 + request = new Request(request.url, { + cache: request.cache, + credentials: "omit", + headers: request.headers, + integrity: request.integrity, + destination: request.destination, + keepalive: request.keepalive, + method: request.method, + mode: request.mode, + redirect: request.redirect, + referrer: request.referrer, + referrerPolicy: request.referrerPolicy, + signal: request.signal, + }); + } + + let r = await fetch(request).catch(e => console.error(e)); + + if(r.status === 0) { + return r; + } + + const headers = new Headers(r.headers); + headers.set("Cross-Origin-Embedder-Policy", "require-corp"); // or: require-corp + headers.set("Cross-Origin-Opener-Policy", "same-origin"); + + return new Response(r.body, { status: r.status, statusText: r.statusText, headers }); + } + + self.addEventListener("fetch", function(e) { + e.respondWith(handleFetch(e.request)); // respondWith must be executed synchonously (but can be passed a Promise) + }); + +} else { + (async function() { + if(window.crossOriginIsolated !== false) return; + + let registration = await navigator.serviceWorker.register(window.document.currentScript.src).catch(e => console.error("COOP/COEP Service Worker failed to register:", e)); + if(registration) { + console.log("COOP/COEP Service Worker registered", registration.scope); + + registration.addEventListener("updatefound", () => { + console.log("Reloading page to make use of updated COOP/COEP Service Worker."); + window.location.reload(); + }); + + // If the registration is active, but it's not controlling the page + if(registration.active && !navigator.serviceWorker.controller) { + console.log("Reloading page to make use of COOP/COEP Service Worker."); + window.location.reload(); + } + } + })(); +} + +// Code to deregister: +// let registrations = await navigator.serviceWorker.getRegistrations(); +// for(let registration of registrations) { +// await registration.unregister(); +// } \ No newline at end of file diff --git a/www/run/favicon.ico b/www/run/favicon.ico new file mode 100644 index 00000000..d3edef5e Binary files /dev/null and b/www/run/favicon.ico differ diff --git a/www/run/index.html b/www/run/index.html new file mode 100644 index 00000000..8d03cd10 --- /dev/null +++ b/www/run/index.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + +
+

Tulip Web

+ + +
+
+
+ MIDI input: + +
+
+ MIDI output: + +
+
+ + +
+
+
+ + +
+ + + + + diff --git a/www/run/micropython.data b/www/run/micropython.data new file mode 100644 index 00000000..87b60033 Binary files /dev/null and b/www/run/micropython.data differ diff --git a/www/run/micropython.mjs b/www/run/micropython.mjs new file mode 100644 index 00000000..26c896e0 --- /dev/null +++ b/www/run/micropython.mjs @@ -0,0 +1,12409 @@ + +var _createMicroPythonModule = (() => { + var _scriptName = import.meta.url; + + return ( +async function(moduleArg = {}) { + var moduleRtn; + +// include: shell.js +// The Module object: Our interface to the outside world. We import +// and export values on it. There are various ways Module can be used: +// 1. Not defined. We create it here +// 2. A function parameter, function(moduleArg) => Promise +// 3. pre-run appended it, var Module = {}; ..generated code.. +// 4. External script tag defines var Module. +// We need to check if Module already exists (e.g. case 3 above). +// Substitution will be replaced with actual code on later stage of the build, +// this way Closure Compiler will not mangle it (e.g. case 4. above). +// Note that if you want to run closure, and also to use Module +// after the generated code, you will need to define var Module = {}; +// before the code. Then that object will be used in the code, and you +// can continue to use Module afterwards as well. +var Module = moduleArg; + +// Set up the promise that indicates the Module is initialized +var readyPromiseResolve, readyPromiseReject; +var readyPromise = new Promise((resolve, reject) => { + readyPromiseResolve = resolve; + readyPromiseReject = reject; +}); +["_free","_malloc","_mp_js_init","_mp_js_repl_init","_mp_js_repl_process_char","_mp_hal_get_interrupt_char","_mp_handle_pending","_process_single_midi_byte","_mp_sched_keyboard_interrupt","_mp_js_do_exec","_mp_js_do_exec_async","_mp_js_frozen_exec","_mp_js_do_import","_mp_js_register_js_module","_proxy_c_free_obj","_proxy_c_init","_proxy_c_to_js_call","_proxy_c_to_js_delete_attr","_proxy_c_to_js_dir","_proxy_c_to_js_get_array","_proxy_c_to_js_get_dict","_proxy_c_to_js_get_iter","_proxy_c_to_js_get_type","_proxy_c_to_js_has_attr","_proxy_c_to_js_iternext","_proxy_c_to_js_lookup_attr","_proxy_c_to_js_resume","_proxy_c_to_js_store_attr","_proxy_convert_mp_to_js_obj_cside","_tulip_tick","_memory","___indirect_function_table","_proxy_convert_mp_to_js_then_js_to_mp_obj_jsside","_proxy_convert_mp_to_js_then_js_to_js_then_js_to_mp_obj_jsside","_js_get_proxy_js_ref_info","_has_attr","_lookup_attr","_store_attr","_call0","_call1","_call2","_calln","_call0_kwarg","_call1_kwarg","_js_reflect_construct","_js_get_iter","_js_iter_next","_js_subscr_load","_js_subscr_store","_proxy_js_free_obj","_js_check_existing","_js_get_error_info","_js_then_resolve","_js_then_reject","_js_then_continue","_create_promise","___em_lib_deps_sdlaudio","___em_lib_deps_sdlmouse","onRuntimeInitialized"].forEach((prop) => { + if (!Object.getOwnPropertyDescriptor(readyPromise, prop)) { + Object.defineProperty(readyPromise, prop, { + get: () => abort('You are getting ' + prop + ' on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js'), + set: () => abort('You are setting ' + prop + ' on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js'), + }); + } +}); + +// Determine the runtime environment we are in. You can customize this by +// setting the ENVIRONMENT setting at compile time (see settings.js). + +// Attempt to auto-detect the environment +var ENVIRONMENT_IS_WEB = typeof window == 'object'; +var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'; +// N.b. Electron.js environment is simultaneously a NODE-environment, but +// also a web environment. +var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string'; +var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; + +if (Module['ENVIRONMENT']) { + throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)'); +} + +if (ENVIRONMENT_IS_NODE) { + // `require()` is no-op in an ESM module, use `createRequire()` to construct + // the require()` function. This is only necessary for multi-environment + // builds, `-sENVIRONMENT=node` emits a static import declaration instead. + // TODO: Swap all `require()`'s with `import()`'s? + const { createRequire } = await import('module'); + /** @suppress{duplicate} */ + var require = createRequire(import.meta.url); + +} + +// --pre-jses are emitted after the Module integration code, so that they can +// refer to Module (if they choose; they can also define Module) +// include: /var/folders/ys/g3zjs1s13z3chzx5zwnyk1bw0000gn/T/tmpub4_unxs.js + + if (!Module['expectedDataFileDownloads']) { + Module['expectedDataFileDownloads'] = 0; + } + + Module['expectedDataFileDownloads']++; + (() => { + // Do not attempt to redownload the virtual filesystem data when in a pthread or a Wasm Worker context. + var isPthread = typeof ENVIRONMENT_IS_PTHREAD != 'undefined' && ENVIRONMENT_IS_PTHREAD; + var isWasmWorker = typeof ENVIRONMENT_IS_WASM_WORKER != 'undefined' && ENVIRONMENT_IS_WASM_WORKER; + if (isPthread || isWasmWorker) return; + function loadPackage(metadata) { + + var PACKAGE_PATH = ''; + if (typeof window === 'object') { + PACKAGE_PATH = window['encodeURIComponent'](window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/'); + } else if (typeof process === 'undefined' && typeof location !== 'undefined') { + // web worker + PACKAGE_PATH = encodeURIComponent(location.pathname.toString().substring(0, location.pathname.toString().lastIndexOf('/')) + '/'); + } + var PACKAGE_NAME = 'build-standard/tulip/obj/micropython.data'; + var REMOTE_PACKAGE_BASE = 'micropython.data'; + if (typeof Module['locateFilePackage'] === 'function' && !Module['locateFile']) { + Module['locateFile'] = Module['locateFilePackage']; + err('warning: you defined Module.locateFilePackage, that has been renamed to Module.locateFile (using your locateFilePackage for now)'); + } + var REMOTE_PACKAGE_NAME = Module['locateFile'] ? Module['locateFile'](REMOTE_PACKAGE_BASE, '') : REMOTE_PACKAGE_BASE; +var REMOTE_PACKAGE_SIZE = metadata['remote_package_size']; + + function fetchRemotePackage(packageName, packageSize, callback, errback) { + if (typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string') { + require('fs').readFile(packageName, (err, contents) => { + if (err) { + errback(err); + } else { + callback(contents.buffer); + } + }); + return; + } + var xhr = new XMLHttpRequest(); + xhr.open('GET', packageName, true); + xhr.responseType = 'arraybuffer'; + xhr.onprogress = (event) => { + var url = packageName; + var size = packageSize; + if (event.total) size = event.total; + if (event.loaded) { + if (!xhr.addedTotal) { + xhr.addedTotal = true; + if (!Module['dataFileDownloads']) Module['dataFileDownloads'] = {}; + Module['dataFileDownloads'][url] = { + loaded: event.loaded, + total: size + }; + } else { + Module['dataFileDownloads'][url].loaded = event.loaded; + } + var total = 0; + var loaded = 0; + var num = 0; + for (var download in Module['dataFileDownloads']) { + var data = Module['dataFileDownloads'][download]; + total += data.total; + loaded += data.loaded; + num++; + } + total = Math.ceil(total * Module['expectedDataFileDownloads']/num); + Module['setStatus']?.(`Downloading data... (${loaded}/${total})`); + } else if (!Module['dataFileDownloads']) { + Module['setStatus']?.('Downloading data...'); + } + }; + xhr.onerror = (event) => { + throw new Error("NetworkError for: " + packageName); + } + xhr.onload = (event) => { + if (xhr.status == 200 || xhr.status == 304 || xhr.status == 206 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 + var packageData = xhr.response; + callback(packageData); + } else { + throw new Error(xhr.statusText + " : " + xhr.responseURL); + } + }; + xhr.send(null); + }; + + function handleError(error) { + console.error('package error:', error); + }; + + var fetchedCallback = null; + var fetched = Module['getPreloadedPackage'] ? Module['getPreloadedPackage'](REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE) : null; + + if (!fetched) fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, (data) => { + if (fetchedCallback) { + fetchedCallback(data); + fetchedCallback = null; + } else { + fetched = data; + } + }, handleError); + + function runWithFS(Module) { + + function assert(check, msg) { + if (!check) throw msg + new Error().stack; + } +Module['FS_createPath']("/", "tulip4", true, true); +Module['FS_createPath']("/tulip4", "sys", true, true); +Module['FS_createPath']("/tulip4/sys", "ex", true, true); +Module['FS_createPath']("/tulip4/sys/ex", "bunny_bounce", true, true); +Module['FS_createPath']("/tulip4/sys/ex/bunny_bounce", "pix", true, true); +Module['FS_createPath']("/tulip4/sys/ex", "g", true, true); +Module['FS_createPath']("/tulip4/sys/ex", "planet_boing", true, true); +Module['FS_createPath']("/tulip4/sys/ex/planet_boing", "pix", true, true); +Module['FS_createPath']("/tulip4/sys", "im", true, true); +Module['FS_createPath']("/tulip4/sys/im", "tiny_town", true, true); + + /** @constructor */ + function DataRequest(start, end, audio) { + this.start = start; + this.end = end; + this.audio = audio; + } + DataRequest.prototype = { + requests: {}, + open: function(mode, name) { + this.name = name; + this.requests[name] = this; + Module['addRunDependency'](`fp ${this.name}`); + }, + send: function() {}, + onload: function() { + var byteArray = this.byteArray.subarray(this.start, this.end); + this.finish(byteArray); + }, + finish: function(byteArray) { + var that = this; + // canOwn this data in the filesystem, it is a slide into the heap that will never change + Module['FS_createDataFile'](this.name, null, byteArray, true, true, true); + Module['removeRunDependency'](`fp ${that.name}`); + this.requests[this.name] = null; + } + }; + + var files = metadata['files']; + for (var i = 0; i < files.length; ++i) { + new DataRequest(files[i]['start'], files[i]['end'], files[i]['audio'] || 0).open('GET', files[i]['filename']); + } + + function processPackageData(arrayBuffer) { + assert(arrayBuffer, 'Loading data file failed.'); + assert(arrayBuffer.constructor.name === ArrayBuffer.name, 'bad input to processPackageData'); + var byteArray = new Uint8Array(arrayBuffer); + var curr; + // Reuse the bytearray from the XHR as the source for file reads. + DataRequest.prototype.byteArray = byteArray; + var files = metadata['files']; + for (var i = 0; i < files.length; ++i) { + DataRequest.prototype.requests[files[i].filename].onload(); + } Module['removeRunDependency']('datafile_build-standard/tulip/obj/micropython.data'); + + }; + Module['addRunDependency']('datafile_build-standard/tulip/obj/micropython.data'); + + if (!Module['preloadResults']) Module['preloadResults'] = {}; + + Module['preloadResults'][PACKAGE_NAME] = {fromCache: false}; + if (fetched) { + processPackageData(fetched); + fetched = null; + } else { + fetchedCallback = processPackageData; + } + + } + if (Module['calledRun']) { + runWithFS(Module); + } else { + if (!Module['preRun']) Module['preRun'] = []; + Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it + } + + } + loadPackage({"files": [{"filename": "/tulip4/sys/ex/.DS_Store", "start": 0, "end": 8196}, {"filename": "/tulip4/sys/ex/ansi.py", "start": 8196, "end": 8407}, {"filename": "/tulip4/sys/ex/bcla3.wav", "start": 8407, "end": 594189, "audio": 1}, {"filename": "/tulip4/sys/ex/bunny_bounce/bunny_bounce.py", "start": 594189, "end": 601964}, {"filename": "/tulip4/sys/ex/bunny_bounce/pix/rabbit_l_0.png", "start": 601964, "end": 604374}, {"filename": "/tulip4/sys/ex/bunny_bounce/pix/rabbit_l_1.png", "start": 604374, "end": 606569}, {"filename": "/tulip4/sys/ex/bunny_bounce/pix/rabbit_l_2.png", "start": 606569, "end": 608847}, {"filename": "/tulip4/sys/ex/bunny_bounce/pix/rabbit_l_3.png", "start": 608847, "end": 611145}, {"filename": "/tulip4/sys/ex/bunny_bounce/pix/rabbit_r_0.png", "start": 611145, "end": 613439}, {"filename": "/tulip4/sys/ex/bunny_bounce/pix/rabbit_r_1.png", "start": 613439, "end": 615715}, {"filename": "/tulip4/sys/ex/bunny_bounce/pix/rabbit_r_2.png", "start": 615715, "end": 617923}, {"filename": "/tulip4/sys/ex/bunny_bounce/pix/rabbit_r_3.png", "start": 617923, "end": 620343}, {"filename": "/tulip4/sys/ex/buttons.py", "start": 620343, "end": 621959}, {"filename": "/tulip4/sys/ex/calibrate.py", "start": 621959, "end": 623326}, {"filename": "/tulip4/sys/ex/fonts.py", "start": 623326, "end": 623497}, {"filename": "/tulip4/sys/ex/g/brick.png", "start": 623497, "end": 623790}, {"filename": "/tulip4/sys/ex/g/cave.png", "start": 623790, "end": 624392}, {"filename": "/tulip4/sys/ex/g/clouds.png", "start": 624392, "end": 625222}, {"filename": "/tulip4/sys/ex/g/clouds2.png", "start": 625222, "end": 626019}, {"filename": "/tulip4/sys/ex/g/colorbars.png", "start": 626019, "end": 635860}, {"filename": "/tulip4/sys/ex/g/desert.png", "start": 635860, "end": 636498}, {"filename": "/tulip4/sys/ex/g/earth.png", "start": 636498, "end": 637341}, {"filename": "/tulip4/sys/ex/g/earth2.png", "start": 637341, "end": 638187}, {"filename": "/tulip4/sys/ex/g/fire.png", "start": 638187, "end": 639177}, {"filename": "/tulip4/sys/ex/g/flowers.png", "start": 639177, "end": 639939}, {"filename": "/tulip4/sys/ex/g/grass.png", "start": 639939, "end": 641110}, {"filename": "/tulip4/sys/ex/g/meadow.png", "start": 641110, "end": 641616}, {"filename": "/tulip4/sys/ex/g/mountain-bg.png", "start": 641616, "end": 646219}, {"filename": "/tulip4/sys/ex/g/mountain-far.png", "start": 646219, "end": 648634}, {"filename": "/tulip4/sys/ex/g/mountain.png", "start": 648634, "end": 653516}, {"filename": "/tulip4/sys/ex/g/rabbit_l_0.png", "start": 653516, "end": 655926}, {"filename": "/tulip4/sys/ex/g/rabbit_l_1.png", "start": 655926, "end": 658121}, {"filename": "/tulip4/sys/ex/g/rabbit_l_2.png", "start": 658121, "end": 660399}, {"filename": "/tulip4/sys/ex/g/rabbit_l_3.png", "start": 660399, "end": 662697}, {"filename": "/tulip4/sys/ex/g/rabbit_r_0.png", "start": 662697, "end": 664991}, {"filename": "/tulip4/sys/ex/g/rabbit_r_1.png", "start": 664991, "end": 667267}, {"filename": "/tulip4/sys/ex/g/rabbit_r_2.png", "start": 667267, "end": 669475}, {"filename": "/tulip4/sys/ex/g/rabbit_r_3.png", "start": 669475, "end": 671895}, {"filename": "/tulip4/sys/ex/g/trees-far.png", "start": 671895, "end": 677610}, {"filename": "/tulip4/sys/ex/g/trees.png", "start": 677610, "end": 684536}, {"filename": "/tulip4/sys/ex/g/tulip3.png", "start": 684536, "end": 719654}, {"filename": "/tulip4/sys/ex/g/tulipbw.png", "start": 719654, "end": 722533}, {"filename": "/tulip4/sys/ex/g/water.png", "start": 722533, "end": 723117}, {"filename": "/tulip4/sys/ex/joy.py", "start": 723117, "end": 724118}, {"filename": "/tulip4/sys/ex/my_drums.py", "start": 724118, "end": 733715}, {"filename": "/tulip4/sys/ex/my_juno6.py", "start": 733715, "end": 758495}, {"filename": "/tulip4/sys/ex/my_voices.py", "start": 758495, "end": 771784}, {"filename": "/tulip4/sys/ex/my_worldui.py", "start": 771784, "end": 775795}, {"filename": "/tulip4/sys/ex/parallax.py", "start": 775795, "end": 780000}, {"filename": "/tulip4/sys/ex/planet_boing/pix/bang_texture_03.png", "start": 780000, "end": 781945}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_00.png", "start": 781945, "end": 783785}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_01.png", "start": 783785, "end": 787290}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_02.png", "start": 787290, "end": 789500}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_03.png", "start": 789500, "end": 791580}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_04.png", "start": 791580, "end": 793768}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_05.png", "start": 793768, "end": 795763}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_06.png", "start": 795763, "end": 797879}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_07.png", "start": 797879, "end": 800024}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_08.png", "start": 800024, "end": 802176}, {"filename": "/tulip4/sys/ex/planet_boing/pix/blob_texture_09.png", "start": 802176, "end": 804289}, {"filename": "/tulip4/sys/ex/planet_boing/pix/wormhole.png", "start": 804289, "end": 805051}, {"filename": "/tulip4/sys/ex/planet_boing/planet_boing.py", "start": 805051, "end": 820957}, {"filename": "/tulip4/sys/ex/rgb332.py", "start": 820957, "end": 821295}, {"filename": "/tulip4/sys/ex/screensaver.py", "start": 821295, "end": 822311}, {"filename": "/tulip4/sys/ex/vlng3.wav", "start": 822311, "end": 1125101, "audio": 1}, {"filename": "/tulip4/sys/ex/vlsa3.wav", "start": 1125101, "end": 1583675, "audio": 1}, {"filename": "/tulip4/sys/ex/woodpiano.txt", "start": 1583675, "end": 1584258}, {"filename": "/tulip4/sys/ex/wordpad.py", "start": 1584258, "end": 1584934}, {"filename": "/tulip4/sys/ex/xanadu.py", "start": 1584934, "end": 1590525}, {"filename": "/tulip4/sys/im/tiny_town/tile_0000.png", "start": 1590525, "end": 1590624}, {"filename": "/tulip4/sys/im/tiny_town/tile_0001.png", "start": 1590624, "end": 1590768}, {"filename": "/tulip4/sys/im/tiny_town/tile_0002.png", "start": 1590768, "end": 1590942}, {"filename": "/tulip4/sys/im/tiny_town/tile_0003.png", "start": 1590942, "end": 1591118}, {"filename": "/tulip4/sys/im/tiny_town/tile_0004.png", "start": 1591118, "end": 1591293}, {"filename": "/tulip4/sys/im/tiny_town/tile_0005.png", "start": 1591293, "end": 1591490}, {"filename": "/tulip4/sys/im/tiny_town/tile_0006.png", "start": 1591490, "end": 1591670}, {"filename": "/tulip4/sys/im/tiny_town/tile_0007.png", "start": 1591670, "end": 1591827}, {"filename": "/tulip4/sys/im/tiny_town/tile_0008.png", "start": 1591827, "end": 1592012}, {"filename": "/tulip4/sys/im/tiny_town/tile_0009.png", "start": 1592012, "end": 1592192}, {"filename": "/tulip4/sys/im/tiny_town/tile_0010.png", "start": 1592192, "end": 1592349}, {"filename": "/tulip4/sys/im/tiny_town/tile_0011.png", "start": 1592349, "end": 1592534}, {"filename": "/tulip4/sys/im/tiny_town/tile_0012.png", "start": 1592534, "end": 1592695}, {"filename": "/tulip4/sys/im/tiny_town/tile_0013.png", "start": 1592695, "end": 1592848}, {"filename": "/tulip4/sys/im/tiny_town/tile_0014.png", "start": 1592848, "end": 1593009}, {"filename": "/tulip4/sys/im/tiny_town/tile_0015.png", "start": 1593009, "end": 1593202}, {"filename": "/tulip4/sys/im/tiny_town/tile_0016.png", "start": 1593202, "end": 1593394}, {"filename": "/tulip4/sys/im/tiny_town/tile_0017.png", "start": 1593394, "end": 1593571}, {"filename": "/tulip4/sys/im/tiny_town/tile_0018.png", "start": 1593571, "end": 1593734}, {"filename": "/tulip4/sys/im/tiny_town/tile_0019.png", "start": 1593734, "end": 1593934}, {"filename": "/tulip4/sys/im/tiny_town/tile_0020.png", "start": 1593934, "end": 1594100}, {"filename": "/tulip4/sys/im/tiny_town/tile_0021.png", "start": 1594100, "end": 1594263}, {"filename": "/tulip4/sys/im/tiny_town/tile_0022.png", "start": 1594263, "end": 1594463}, {"filename": "/tulip4/sys/im/tiny_town/tile_0023.png", "start": 1594463, "end": 1594629}, {"filename": "/tulip4/sys/im/tiny_town/tile_0024.png", "start": 1594629, "end": 1594764}, {"filename": "/tulip4/sys/im/tiny_town/tile_0025.png", "start": 1594764, "end": 1594863}, {"filename": "/tulip4/sys/im/tiny_town/tile_0026.png", "start": 1594863, "end": 1595003}, {"filename": "/tulip4/sys/im/tiny_town/tile_0027.png", "start": 1595003, "end": 1595194}, {"filename": "/tulip4/sys/im/tiny_town/tile_0028.png", "start": 1595194, "end": 1595385}, {"filename": "/tulip4/sys/im/tiny_town/tile_0029.png", "start": 1595385, "end": 1595582}, {"filename": "/tulip4/sys/im/tiny_town/tile_0030.png", "start": 1595582, "end": 1595763}, {"filename": "/tulip4/sys/im/tiny_town/tile_0031.png", "start": 1595763, "end": 1595920}, {"filename": "/tulip4/sys/im/tiny_town/tile_0032.png", "start": 1595920, "end": 1596101}, {"filename": "/tulip4/sys/im/tiny_town/tile_0033.png", "start": 1596101, "end": 1596282}, {"filename": "/tulip4/sys/im/tiny_town/tile_0034.png", "start": 1596282, "end": 1596439}, {"filename": "/tulip4/sys/im/tiny_town/tile_0035.png", "start": 1596439, "end": 1596620}, {"filename": "/tulip4/sys/im/tiny_town/tile_0036.png", "start": 1596620, "end": 1596774}, {"filename": "/tulip4/sys/im/tiny_town/tile_0037.png", "start": 1596774, "end": 1596908}, {"filename": "/tulip4/sys/im/tiny_town/tile_0038.png", "start": 1596908, "end": 1597057}, {"filename": "/tulip4/sys/im/tiny_town/tile_0039.png", "start": 1597057, "end": 1597186}, {"filename": "/tulip4/sys/im/tiny_town/tile_0040.png", "start": 1597186, "end": 1597325}, {"filename": "/tulip4/sys/im/tiny_town/tile_0041.png", "start": 1597325, "end": 1597451}, {"filename": "/tulip4/sys/im/tiny_town/tile_0042.png", "start": 1597451, "end": 1597588}, {"filename": "/tulip4/sys/im/tiny_town/tile_0043.png", "start": 1597588, "end": 1597754}, {"filename": "/tulip4/sys/im/tiny_town/tile_0044.png", "start": 1597754, "end": 1597918}, {"filename": "/tulip4/sys/im/tiny_town/tile_0045.png", "start": 1597918, "end": 1598096}, {"filename": "/tulip4/sys/im/tiny_town/tile_0046.png", "start": 1598096, "end": 1598260}, {"filename": "/tulip4/sys/im/tiny_town/tile_0047.png", "start": 1598260, "end": 1598404}, {"filename": "/tulip4/sys/im/tiny_town/tile_0048.png", "start": 1598404, "end": 1598570}, {"filename": "/tulip4/sys/im/tiny_town/tile_0049.png", "start": 1598570, "end": 1598731}, {"filename": "/tulip4/sys/im/tiny_town/tile_0050.png", "start": 1598731, "end": 1598902}, {"filename": "/tulip4/sys/im/tiny_town/tile_0051.png", "start": 1598902, "end": 1599069}, {"filename": "/tulip4/sys/im/tiny_town/tile_0052.png", "start": 1599069, "end": 1599249}, {"filename": "/tulip4/sys/im/tiny_town/tile_0053.png", "start": 1599249, "end": 1599427}, {"filename": "/tulip4/sys/im/tiny_town/tile_0054.png", "start": 1599427, "end": 1599608}, {"filename": "/tulip4/sys/im/tiny_town/tile_0055.png", "start": 1599608, "end": 1599796}, {"filename": "/tulip4/sys/im/tiny_town/tile_0056.png", "start": 1599796, "end": 1599942}, {"filename": "/tulip4/sys/im/tiny_town/tile_0057.png", "start": 1599942, "end": 1600155}, {"filename": "/tulip4/sys/im/tiny_town/tile_0058.png", "start": 1600155, "end": 1600302}, {"filename": "/tulip4/sys/im/tiny_town/tile_0059.png", "start": 1600302, "end": 1600447}, {"filename": "/tulip4/sys/im/tiny_town/tile_0060.png", "start": 1600447, "end": 1600624}, {"filename": "/tulip4/sys/im/tiny_town/tile_0061.png", "start": 1600624, "end": 1600790}, {"filename": "/tulip4/sys/im/tiny_town/tile_0062.png", "start": 1600790, "end": 1600974}, {"filename": "/tulip4/sys/im/tiny_town/tile_0063.png", "start": 1600974, "end": 1601190}, {"filename": "/tulip4/sys/im/tiny_town/tile_0064.png", "start": 1601190, "end": 1601367}, {"filename": "/tulip4/sys/im/tiny_town/tile_0065.png", "start": 1601367, "end": 1601533}, {"filename": "/tulip4/sys/im/tiny_town/tile_0066.png", "start": 1601533, "end": 1601717}, {"filename": "/tulip4/sys/im/tiny_town/tile_0067.png", "start": 1601717, "end": 1601933}, {"filename": "/tulip4/sys/im/tiny_town/tile_0068.png", "start": 1601933, "end": 1602097}, {"filename": "/tulip4/sys/im/tiny_town/tile_0069.png", "start": 1602097, "end": 1602268}, {"filename": "/tulip4/sys/im/tiny_town/tile_0070.png", "start": 1602268, "end": 1602433}, {"filename": "/tulip4/sys/im/tiny_town/tile_0071.png", "start": 1602433, "end": 1602572}, {"filename": "/tulip4/sys/im/tiny_town/tile_0072.png", "start": 1602572, "end": 1602709}, {"filename": "/tulip4/sys/im/tiny_town/tile_0073.png", "start": 1602709, "end": 1602838}, {"filename": "/tulip4/sys/im/tiny_town/tile_0074.png", "start": 1602838, "end": 1602993}, {"filename": "/tulip4/sys/im/tiny_town/tile_0075.png", "start": 1602993, "end": 1603136}, {"filename": "/tulip4/sys/im/tiny_town/tile_0076.png", "start": 1603136, "end": 1603273}, {"filename": "/tulip4/sys/im/tiny_town/tile_0077.png", "start": 1603273, "end": 1603402}, {"filename": "/tulip4/sys/im/tiny_town/tile_0078.png", "start": 1603402, "end": 1603557}, {"filename": "/tulip4/sys/im/tiny_town/tile_0079.png", "start": 1603557, "end": 1603700}, {"filename": "/tulip4/sys/im/tiny_town/tile_0080.png", "start": 1603700, "end": 1603860}, {"filename": "/tulip4/sys/im/tiny_town/tile_0081.png", "start": 1603860, "end": 1603980}, {"filename": "/tulip4/sys/im/tiny_town/tile_0082.png", "start": 1603980, "end": 1604142}, {"filename": "/tulip4/sys/im/tiny_town/tile_0083.png", "start": 1604142, "end": 1604331}, {"filename": "/tulip4/sys/im/tiny_town/tile_0084.png", "start": 1604331, "end": 1604501}, {"filename": "/tulip4/sys/im/tiny_town/tile_0085.png", "start": 1604501, "end": 1604664}, {"filename": "/tulip4/sys/im/tiny_town/tile_0086.png", "start": 1604664, "end": 1604825}, {"filename": "/tulip4/sys/im/tiny_town/tile_0087.png", "start": 1604825, "end": 1604986}, {"filename": "/tulip4/sys/im/tiny_town/tile_0088.png", "start": 1604986, "end": 1605153}, {"filename": "/tulip4/sys/im/tiny_town/tile_0089.png", "start": 1605153, "end": 1605316}, {"filename": "/tulip4/sys/im/tiny_town/tile_0090.png", "start": 1605316, "end": 1605477}, {"filename": "/tulip4/sys/im/tiny_town/tile_0091.png", "start": 1605477, "end": 1605639}, {"filename": "/tulip4/sys/im/tiny_town/tile_0092.png", "start": 1605639, "end": 1605797}, {"filename": "/tulip4/sys/im/tiny_town/tile_0093.png", "start": 1605797, "end": 1605959}, {"filename": "/tulip4/sys/im/tiny_town/tile_0094.png", "start": 1605959, "end": 1606144}, {"filename": "/tulip4/sys/im/tiny_town/tile_0095.png", "start": 1606144, "end": 1606339}, {"filename": "/tulip4/sys/im/tiny_town/tile_0096.png", "start": 1606339, "end": 1606528}, {"filename": "/tulip4/sys/im/tiny_town/tile_0097.png", "start": 1606528, "end": 1606667}, {"filename": "/tulip4/sys/im/tiny_town/tile_0098.png", "start": 1606667, "end": 1606848}, {"filename": "/tulip4/sys/im/tiny_town/tile_0099.png", "start": 1606848, "end": 1607019}, {"filename": "/tulip4/sys/im/tiny_town/tile_0100.png", "start": 1607019, "end": 1607151}, {"filename": "/tulip4/sys/im/tiny_town/tile_0101.png", "start": 1607151, "end": 1607325}, {"filename": "/tulip4/sys/im/tiny_town/tile_0102.png", "start": 1607325, "end": 1607500}, {"filename": "/tulip4/sys/im/tiny_town/tile_0103.png", "start": 1607500, "end": 1607696}, {"filename": "/tulip4/sys/im/tiny_town/tile_0104.png", "start": 1607696, "end": 1607938}, {"filename": "/tulip4/sys/im/tiny_town/tile_0105.png", "start": 1607938, "end": 1608136}, {"filename": "/tulip4/sys/im/tiny_town/tile_0106.png", "start": 1608136, "end": 1608314}, {"filename": "/tulip4/sys/im/tiny_town/tile_0107.png", "start": 1608314, "end": 1608516}, {"filename": "/tulip4/sys/im/tiny_town/tile_0108.png", "start": 1608516, "end": 1608638}, {"filename": "/tulip4/sys/im/tiny_town/tile_0109.png", "start": 1608638, "end": 1608737}, {"filename": "/tulip4/sys/im/tiny_town/tile_0110.png", "start": 1608737, "end": 1608858}, {"filename": "/tulip4/sys/im/tiny_town/tile_0111.png", "start": 1608858, "end": 1609061}, {"filename": "/tulip4/sys/im/tiny_town/tile_0112.png", "start": 1609061, "end": 1609264}, {"filename": "/tulip4/sys/im/tiny_town/tile_0113.png", "start": 1609264, "end": 1609464}, {"filename": "/tulip4/sys/im/tiny_town/tile_0114.png", "start": 1609464, "end": 1609664}, {"filename": "/tulip4/sys/im/tiny_town/tile_0115.png", "start": 1609664, "end": 1609850}, {"filename": "/tulip4/sys/im/tiny_town/tile_0116.png", "start": 1609850, "end": 1610034}, {"filename": "/tulip4/sys/im/tiny_town/tile_0117.png", "start": 1610034, "end": 1610206}, {"filename": "/tulip4/sys/im/tiny_town/tile_0118.png", "start": 1610206, "end": 1610389}, {"filename": "/tulip4/sys/im/tiny_town/tile_0119.png", "start": 1610389, "end": 1610572}, {"filename": "/tulip4/sys/im/tiny_town/tile_0120.png", "start": 1610572, "end": 1610730}, {"filename": "/tulip4/sys/im/tiny_town/tile_0121.png", "start": 1610730, "end": 1610871}, {"filename": "/tulip4/sys/im/tiny_town/tile_0122.png", "start": 1610871, "end": 1611034}, {"filename": "/tulip4/sys/im/tiny_town/tile_0123.png", "start": 1611034, "end": 1611179}, {"filename": "/tulip4/sys/im/tiny_town/tile_0124.png", "start": 1611179, "end": 1611325}, {"filename": "/tulip4/sys/im/tiny_town/tile_0125.png", "start": 1611325, "end": 1611511}, {"filename": "/tulip4/sys/im/tiny_town/tile_0126.png", "start": 1611511, "end": 1611669}, {"filename": "/tulip4/sys/im/tiny_town/tile_0127.png", "start": 1611669, "end": 1611853}, {"filename": "/tulip4/sys/im/tiny_town/tile_0128.png", "start": 1611853, "end": 1612053}, {"filename": "/tulip4/sys/im/tiny_town/tile_0129.png", "start": 1612053, "end": 1612253}, {"filename": "/tulip4/sys/im/tiny_town/tile_0130.png", "start": 1612253, "end": 1612459}, {"filename": "/tulip4/sys/im/tiny_town/tile_0131.png", "start": 1612459, "end": 1612679}], "remote_package_size": 1612679}); + + })(); + +// end include: /var/folders/ys/g3zjs1s13z3chzx5zwnyk1bw0000gn/T/tmpub4_unxs.js +// include: /var/folders/ys/g3zjs1s13z3chzx5zwnyk1bw0000gn/T/tmpozo9hvlk.js + + // All the pre-js content up to here must remain later on, we need to run + // it. + if (Module['$ww'] || (typeof ENVIRONMENT_IS_PTHREAD != 'undefined' && ENVIRONMENT_IS_PTHREAD)) Module['preRun'] = []; + var necessaryPreJSTasks = Module['preRun'].slice(); + // end include: /var/folders/ys/g3zjs1s13z3chzx5zwnyk1bw0000gn/T/tmpozo9hvlk.js +// include: /var/folders/ys/g3zjs1s13z3chzx5zwnyk1bw0000gn/T/tmpwi308vqv.js + + if (!Module['preRun']) throw 'Module.preRun should exist because file support used it; did a pre-js delete it?'; + necessaryPreJSTasks.forEach((task) => { + if (Module['preRun'].indexOf(task) < 0) throw 'All preRun tasks that exist before user pre-js code should remain after; did you replace Module or modify Module.preRun?'; + }); + // end include: /var/folders/ys/g3zjs1s13z3chzx5zwnyk1bw0000gn/T/tmpwi308vqv.js + + +// Sometimes an existing Module object exists with properties +// meant to overwrite the default module functionality. Here +// we collect those properties and reapply _after_ we configure +// the current environment's defaults to avoid having to be so +// defensive during initialization. +var moduleOverrides = Object.assign({}, Module); + +var arguments_ = []; +var thisProgram = './this.program'; +var quit_ = (status, toThrow) => { + throw toThrow; +}; + +// `/` should be present at the end if `scriptDirectory` is not empty +var scriptDirectory = ''; +function locateFile(path) { + if (Module['locateFile']) { + return Module['locateFile'](path, scriptDirectory); + } + return scriptDirectory + path; +} + +// Hooks that are implemented differently in different runtime environments. +var readAsync, readBinary; + +if (ENVIRONMENT_IS_NODE) { + if (typeof process == 'undefined' || !process.release || process.release.name !== 'node') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); + + var nodeVersion = process.versions.node; + var numericVersion = nodeVersion.split('.').slice(0, 3); + numericVersion = (numericVersion[0] * 10000) + (numericVersion[1] * 100) + (numericVersion[2].split('-')[0] * 1); + var minVersion = 160000; + if (numericVersion < 160000) { + throw new Error('This emscripten-generated code requires node v16.0.0 (detected v' + nodeVersion + ')'); + } + + // These modules will usually be used on Node.js. Load them eagerly to avoid + // the complexity of lazy-loading. + var fs = require('fs'); + var nodePath = require('path'); + + // EXPORT_ES6 + ENVIRONMENT_IS_NODE always requires use of import.meta.url, + // since there's no way getting the current absolute path of the module when + // support for that is not available. + scriptDirectory = require('url').fileURLToPath(new URL('./', import.meta.url)); // includes trailing slash + +// include: node_shell_read.js +readBinary = (filename) => { + // We need to re-wrap `file://` strings to URLs. Normalizing isn't + // necessary in that case, the path should already be absolute. + filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); + var ret = fs.readFileSync(filename); + assert(ret.buffer); + return ret; +}; + +readAsync = (filename, binary = true) => { + // See the comment in the `readBinary` function. + filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); + return new Promise((resolve, reject) => { + fs.readFile(filename, binary ? undefined : 'utf8', (err, data) => { + if (err) reject(err); + else resolve(binary ? data.buffer : data); + }); + }); +}; +// end include: node_shell_read.js + if (!Module['thisProgram'] && process.argv.length > 1) { + thisProgram = process.argv[1].replace(/\\/g, '/'); + } + + arguments_ = process.argv.slice(2); + + // MODULARIZE will export the module in the proper place outside, we don't need to export here + + quit_ = (status, toThrow) => { + process.exitCode = status; + throw toThrow; + }; + +} else +if (ENVIRONMENT_IS_SHELL) { + + if ((typeof process == 'object' && typeof require === 'function') || typeof window == 'object' || typeof importScripts == 'function') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); + +} else + +// Note that this includes Node.js workers when relevant (pthreads is enabled). +// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and +// ENVIRONMENT_IS_NODE. +if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + if (ENVIRONMENT_IS_WORKER) { // Check worker, not web, since window could be polyfilled + scriptDirectory = self.location.href; + } else if (typeof document != 'undefined' && document.currentScript) { // web + scriptDirectory = document.currentScript.src; + } + // When MODULARIZE, this JS may be executed later, after document.currentScript + // is gone, so we saved it, and we use it here instead of any other info. + if (_scriptName) { + scriptDirectory = _scriptName; + } + // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them. + // otherwise, slice off the final part of the url to find the script directory. + // if scriptDirectory does not contain a slash, lastIndexOf will return -1, + // and scriptDirectory will correctly be replaced with an empty string. + // If scriptDirectory contains a query (starting with ?) or a fragment (starting with #), + // they are removed because they could contain a slash. + if (scriptDirectory.startsWith('blob:')) { + scriptDirectory = ''; + } else { + scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/')+1); + } + + if (!(typeof window == 'object' || typeof importScripts == 'function')) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); + + { +// include: web_or_worker_shell_read.js +if (ENVIRONMENT_IS_WORKER) { + readBinary = (url) => { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + xhr.responseType = 'arraybuffer'; + xhr.send(null); + return new Uint8Array(/** @type{!ArrayBuffer} */(xhr.response)); + }; + } + + readAsync = (url) => { + // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url. + // See https://github.com/github/fetch/pull/92#issuecomment-140665932 + // Cordova or Electron apps are typically loaded from a file:// url. + // So use XHR on webview if URL is a file URL. + if (isFileURI(url)) { + return new Promise((resolve, reject) => { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'arraybuffer'; + xhr.onload = () => { + if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 + resolve(xhr.response); + return; + } + reject(xhr.status); + }; + xhr.onerror = reject; + xhr.send(null); + }); + } + return fetch(url, { credentials: 'same-origin' }) + .then((response) => { + if (response.ok) { + return response.arrayBuffer(); + } + return Promise.reject(new Error(response.status + ' : ' + response.url)); + }) + }; +// end include: web_or_worker_shell_read.js + } +} else +{ + throw new Error('environment detection error'); +} + +var out = Module['print'] || console.log.bind(console); +var err = Module['printErr'] || console.error.bind(console); + +// Merge back in the overrides +Object.assign(Module, moduleOverrides); +// Free the object hierarchy contained in the overrides, this lets the GC +// reclaim data used. +moduleOverrides = null; +checkIncomingModuleAPI(); + +// Emit code to handle expected values on the Module object. This applies Module.x +// to the proper local x. This has two benefits: first, we only emit it if it is +// expected to arrive, and second, by using a local everywhere else that can be +// minified. + +if (Module['arguments']) arguments_ = Module['arguments'];legacyModuleProp('arguments', 'arguments_'); + +if (Module['thisProgram']) thisProgram = Module['thisProgram'];legacyModuleProp('thisProgram', 'thisProgram'); + +// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message +// Assertions on removed incoming Module JS APIs. +assert(typeof Module['memoryInitializerPrefixURL'] == 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead'); +assert(typeof Module['pthreadMainPrefixURL'] == 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead'); +assert(typeof Module['cdInitializerPrefixURL'] == 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead'); +assert(typeof Module['filePackagePrefixURL'] == 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead'); +assert(typeof Module['read'] == 'undefined', 'Module.read option was removed'); +assert(typeof Module['readAsync'] == 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)'); +assert(typeof Module['readBinary'] == 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)'); +assert(typeof Module['setWindowTitle'] == 'undefined', 'Module.setWindowTitle option was removed (modify emscripten_set_window_title in JS)'); +assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY'); +legacyModuleProp('asm', 'wasmExports'); +legacyModuleProp('readAsync', 'readAsync'); +legacyModuleProp('readBinary', 'readBinary'); +legacyModuleProp('setWindowTitle', 'setWindowTitle'); + +var PROXYFS = 'PROXYFS is no longer included by default; build with -lproxyfs.js'; +var WORKERFS = 'WORKERFS is no longer included by default; build with -lworkerfs.js'; +var FETCHFS = 'FETCHFS is no longer included by default; build with -lfetchfs.js'; +var ICASEFS = 'ICASEFS is no longer included by default; build with -licasefs.js'; +var JSFILEFS = 'JSFILEFS is no longer included by default; build with -ljsfilefs.js'; +var OPFS = 'OPFS is no longer included by default; build with -lopfs.js'; + +var NODEFS = 'NODEFS is no longer included by default; build with -lnodefs.js'; + +assert(!ENVIRONMENT_IS_SHELL, 'shell environment detected but not enabled at build time. Add `shell` to `-sENVIRONMENT` to enable.'); + +// end include: shell.js + +// include: preamble.js +// === Preamble library stuff === + +// Documentation for the public APIs defined in this file must be updated in: +// site/source/docs/api_reference/preamble.js.rst +// A prebuilt local version of the documentation is available at: +// site/build/text/docs/api_reference/preamble.js.txt +// You can also build docs locally as HTML or other formats in site/ +// An online HTML version (which may be of a different version of Emscripten) +// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html + +var wasmBinary = Module['wasmBinary'];legacyModuleProp('wasmBinary', 'wasmBinary'); + +if (typeof WebAssembly != 'object') { + err('no native wasm support detected'); +} + +// include: base64Utils.js +// Converts a string of base64 into a byte array (Uint8Array). +function intArrayFromBase64(s) { + if (typeof ENVIRONMENT_IS_NODE != 'undefined' && ENVIRONMENT_IS_NODE) { + var buf = Buffer.from(s, 'base64'); + return new Uint8Array(buf.buffer, buf.byteOffset, buf.length); + } + + var decoded = atob(s); + var bytes = new Uint8Array(decoded.length); + for (var i = 0 ; i < decoded.length ; ++i) { + bytes[i] = decoded.charCodeAt(i); + } + return bytes; +} + +// If filename is a base64 data URI, parses and returns data (Buffer on node, +// Uint8Array otherwise). If filename is not a base64 data URI, returns undefined. +function tryParseAsDataURI(filename) { + if (!isDataURI(filename)) { + return; + } + + return intArrayFromBase64(filename.slice(dataURIPrefix.length)); +} +// end include: base64Utils.js +// Wasm globals + +var wasmMemory; + +//======================================== +// Runtime essentials +//======================================== + +// whether we are quitting the application. no code should run after this. +// set in exit() and abort() +var ABORT = false; + +// set by exit() and abort(). Passed to 'onExit' handler. +// NOTE: This is also used as the process return code code in shell environments +// but only when noExitRuntime is false. +var EXITSTATUS; + +// In STRICT mode, we only define assert() when ASSERTIONS is set. i.e. we +// don't define it at all in release modes. This matches the behaviour of +// MINIMAL_RUNTIME. +// TODO(sbc): Make this the default even without STRICT enabled. +/** @type {function(*, string=)} */ +function assert(condition, text) { + if (!condition) { + abort('Assertion failed' + (text ? ': ' + text : '')); + } +} + +// We used to include malloc/free by default in the past. Show a helpful error in +// builds with assertions. + +// Memory management + +var HEAP, +/** @type {!Int8Array} */ + HEAP8, +/** @type {!Uint8Array} */ + HEAPU8, +/** @type {!Int16Array} */ + HEAP16, +/** @type {!Uint16Array} */ + HEAPU16, +/** @type {!Int32Array} */ + HEAP32, +/** @type {!Uint32Array} */ + HEAPU32, +/** @type {!Float32Array} */ + HEAPF32, +/** @type {!Float64Array} */ + HEAPF64; + +// include: runtime_shared.js +function updateMemoryViews() { + var b = wasmMemory.buffer; + Module['HEAP8'] = HEAP8 = new Int8Array(b); + Module['HEAP16'] = HEAP16 = new Int16Array(b); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); + Module['HEAPU16'] = HEAPU16 = new Uint16Array(b); + Module['HEAP32'] = HEAP32 = new Int32Array(b); + Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); + Module['HEAPF32'] = HEAPF32 = new Float32Array(b); + Module['HEAPF64'] = HEAPF64 = new Float64Array(b); +} + +// end include: runtime_shared.js +assert(!Module['STACK_SIZE'], 'STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time') + +assert(typeof Int32Array != 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray != undefined && Int32Array.prototype.set != undefined, + 'JS engine does not provide full typed array support'); + +// If memory is defined in wasm, the user can't provide it, or set INITIAL_MEMORY +assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally'); +assert(!Module['INITIAL_MEMORY'], 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically'); + +// include: runtime_stack_check.js +// Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode. +function writeStackCookie() { + var max = _emscripten_stack_get_end(); + assert((max & 3) == 0); + // If the stack ends at address zero we write our cookies 4 bytes into the + // stack. This prevents interference with SAFE_HEAP and ASAN which also + // monitor writes to address zero. + if (max == 0) { + max += 4; + } + // The stack grow downwards towards _emscripten_stack_get_end. + // We write cookies to the final two words in the stack and detect if they are + // ever overwritten. + HEAPU32[((max)>>2)] = 0x02135467; + HEAPU32[(((max)+(4))>>2)] = 0x89BACDFE; + // Also test the global address 0 for integrity. + HEAPU32[((0)>>2)] = 1668509029; +} + +function checkStackCookie() { + if (ABORT) return; + var max = _emscripten_stack_get_end(); + // See writeStackCookie(). + if (max == 0) { + max += 4; + } + var cookie1 = HEAPU32[((max)>>2)]; + var cookie2 = HEAPU32[(((max)+(4))>>2)]; + if (cookie1 != 0x02135467 || cookie2 != 0x89BACDFE) { + abort(`Stack overflow! Stack cookie has been overwritten at ${ptrToString(max)}, expected hex dwords 0x89BACDFE and 0x2135467, but received ${ptrToString(cookie2)} ${ptrToString(cookie1)}`); + } + // Also test the global address 0 for integrity. + if (HEAPU32[((0)>>2)] != 0x63736d65 /* 'emsc' */) { + abort('Runtime error: The application has corrupted its heap memory area (address zero)!'); + } +} +// end include: runtime_stack_check.js +var __ATPRERUN__ = []; // functions called before the runtime is initialized +var __ATINIT__ = []; // functions called during startup +var __ATEXIT__ = []; // functions called during shutdown +var __ATPOSTRUN__ = []; // functions called after the main() is called + +var runtimeInitialized = false; + +function preRun() { + if (Module['preRun']) { + if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; + while (Module['preRun'].length) { + addOnPreRun(Module['preRun'].shift()); + } + } + callRuntimeCallbacks(__ATPRERUN__); +} + +function initRuntime() { + assert(!runtimeInitialized); + runtimeInitialized = true; + + checkStackCookie(); + + +if (!Module['noFSInit'] && !FS.initialized) + FS.init(); +FS.ignorePermissions = false; + +TTY.init(); + callRuntimeCallbacks(__ATINIT__); +} + +function postRun() { + checkStackCookie(); + + if (Module['postRun']) { + if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']]; + while (Module['postRun'].length) { + addOnPostRun(Module['postRun'].shift()); + } + } + + callRuntimeCallbacks(__ATPOSTRUN__); +} + +function addOnPreRun(cb) { + __ATPRERUN__.unshift(cb); +} + +function addOnInit(cb) { + __ATINIT__.unshift(cb); +} + +function addOnExit(cb) { +} + +function addOnPostRun(cb) { + __ATPOSTRUN__.unshift(cb); +} + +// include: runtime_math.js +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc + +assert(Math.imul, 'This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); +assert(Math.fround, 'This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); +assert(Math.clz32, 'This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); +assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); +// end include: runtime_math.js +// A counter of dependencies for calling run(). If we need to +// do asynchronous work before running, increment this and +// decrement it. Incrementing must happen in a place like +// Module.preRun (used by emcc to add file preloading). +// Note that you can add dependencies in preRun, even though +// it happens right before run - run will be postponed until +// the dependencies are met. +var runDependencies = 0; +var runDependencyWatcher = null; +var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled +var runDependencyTracking = {}; + +function getUniqueRunDependency(id) { + var orig = id; + while (1) { + if (!runDependencyTracking[id]) return id; + id = orig + Math.random(); + } +} + +function addRunDependency(id) { + runDependencies++; + + Module['monitorRunDependencies']?.(runDependencies); + + if (id) { + assert(!runDependencyTracking[id]); + runDependencyTracking[id] = 1; + if (runDependencyWatcher === null && typeof setInterval != 'undefined') { + // Check for missing dependencies every few seconds + runDependencyWatcher = setInterval(() => { + if (ABORT) { + clearInterval(runDependencyWatcher); + runDependencyWatcher = null; + return; + } + var shown = false; + for (var dep in runDependencyTracking) { + if (!shown) { + shown = true; + err('still waiting on run dependencies:'); + } + err(`dependency: ${dep}`); + } + if (shown) { + err('(end of list)'); + } + }, 10000); + } + } else { + err('warning: run dependency added without ID'); + } +} + +function removeRunDependency(id) { + runDependencies--; + + Module['monitorRunDependencies']?.(runDependencies); + + if (id) { + assert(runDependencyTracking[id]); + delete runDependencyTracking[id]; + } else { + err('warning: run dependency removed without ID'); + } + if (runDependencies == 0) { + if (runDependencyWatcher !== null) { + clearInterval(runDependencyWatcher); + runDependencyWatcher = null; + } + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); // can add another dependenciesFulfilled + } + } +} + +/** @param {string|number=} what */ +function abort(what) { + Module['onAbort']?.(what); + + what = 'Aborted(' + what + ')'; + // TODO(sbc): Should we remove printing and leave it up to whoever + // catches the exception? + err(what); + + ABORT = true; + + if (what.indexOf('RuntimeError: unreachable') >= 0) { + what += '. "unreachable" may be due to ASYNCIFY_STACK_SIZE not being large enough (try increasing it)'; + } + + // Use a wasm runtime error, because a JS error might be seen as a foreign + // exception, which means we'd run destructors on it. We need the error to + // simply make the program stop. + // FIXME This approach does not work in Wasm EH because it currently does not assume + // all RuntimeErrors are from traps; it decides whether a RuntimeError is from + // a trap or not based on a hidden field within the object. So at the moment + // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that + // allows this in the wasm spec. + + // Suppress closure compiler warning here. Closure compiler's builtin extern + // definition for WebAssembly.RuntimeError claims it takes no arguments even + // though it can. + // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. + /** @suppress {checkTypes} */ + var e = new WebAssembly.RuntimeError(what); + + readyPromiseReject(e); + // Throw the error whether or not MODULARIZE is set because abort is used + // in code paths apart from instantiation where an exception is expected + // to be thrown when abort is called. + throw e; +} + +// include: memoryprofiler.js +// end include: memoryprofiler.js +// include: URIUtils.js +// Prefix of data URIs emitted by SINGLE_FILE and related options. +var dataURIPrefix = 'data:application/octet-stream;base64,'; + +/** + * Indicates whether filename is a base64 data URI. + * @noinline + */ +var isDataURI = (filename) => filename.startsWith(dataURIPrefix); + +/** + * Indicates whether filename is delivered via file protocol (as opposed to http/https) + * @noinline + */ +var isFileURI = (filename) => filename.startsWith('file://'); +// end include: URIUtils.js +function createExportWrapper(name, nargs) { + return (...args) => { + assert(runtimeInitialized, `native function \`${name}\` called before runtime initialization`); + var f = wasmExports[name]; + assert(f, `exported native function \`${name}\` not found`); + // Only assert for too many arguments. Too few can be valid since the missing arguments will be zero filled. + assert(args.length <= nargs, `native function \`${name}\` called with ${args.length} args but expects ${nargs}`); + return f(...args); + }; +} + +// include: runtime_exceptions.js +// end include: runtime_exceptions.js +function findWasmBinary() { + if (Module['locateFile']) { + var f = 'micropython.wasm'; + if (!isDataURI(f)) { + return locateFile(f); + } + return f; + } + // Use bundler-friendly `new URL(..., import.meta.url)` pattern; works in browsers too. + return new URL('micropython.wasm', import.meta.url).href; +} + +var wasmBinaryFile; + +function getBinarySync(file) { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } + throw 'both async and sync fetching of the wasm failed'; +} + +function getBinaryPromise(binaryFile) { + // If we don't have the binary yet, load it asynchronously using readAsync. + if (!wasmBinary + ) { + // Fetch the binary using readAsync + return readAsync(binaryFile).then( + (response) => new Uint8Array(/** @type{!ArrayBuffer} */(response)), + // Fall back to getBinarySync if readAsync fails + () => getBinarySync(binaryFile) + ); + } + + // Otherwise, getBinarySync should be able to get it synchronously + return Promise.resolve().then(() => getBinarySync(binaryFile)); +} + +function instantiateArrayBuffer(binaryFile, imports, receiver) { + return getBinaryPromise(binaryFile).then((binary) => { + return WebAssembly.instantiate(binary, imports); + }).then(receiver, (reason) => { + err(`failed to asynchronously prepare wasm: ${reason}`); + + // Warn on some common problems. + if (isFileURI(wasmBinaryFile)) { + err(`warning: Loading from a file URI (${wasmBinaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`); + } + abort(reason); + }); +} + +function instantiateAsync(binary, binaryFile, imports, callback) { + if (!binary && + typeof WebAssembly.instantiateStreaming == 'function' && + !isDataURI(binaryFile) && + // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously. + !isFileURI(binaryFile) && + // Avoid instantiateStreaming() on Node.js environment for now, as while + // Node.js v18.1.0 implements it, it does not have a full fetch() + // implementation yet. + // + // Reference: + // https://github.com/emscripten-core/emscripten/pull/16917 + !ENVIRONMENT_IS_NODE && + typeof fetch == 'function') { + return fetch(binaryFile, { credentials: 'same-origin' }).then((response) => { + // Suppress closure warning here since the upstream definition for + // instantiateStreaming only allows Promise rather than + // an actual Response. + // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed. + /** @suppress {checkTypes} */ + var result = WebAssembly.instantiateStreaming(response, imports); + + return result.then( + callback, + function(reason) { + // We expect the most common failure cause to be a bad MIME type for the binary, + // in which case falling back to ArrayBuffer instantiation should work. + err(`wasm streaming compile failed: ${reason}`); + err('falling back to ArrayBuffer instantiation'); + return instantiateArrayBuffer(binaryFile, imports, callback); + }); + }); + } + return instantiateArrayBuffer(binaryFile, imports, callback); +} + +function getWasmImports() { + // instrumenting imports is used in asyncify in two ways: to add assertions + // that check for proper import use, and for ASYNCIFY=2 we use them to set up + // the Promise API on the import side. + Asyncify.instrumentWasmImports(wasmImports); + // prepare imports + return { + 'env': wasmImports, + 'wasi_snapshot_preview1': wasmImports, + } +} + +// Create the wasm instance. +// Receives the wasm imports, returns the exports. +function createWasm() { + var info = getWasmImports(); + // Load the wasm module and create an instance of using native support in the JS engine. + // handle a generated wasm instance, receiving its exports and + // performing other necessary setup + /** @param {WebAssembly.Module=} module*/ + function receiveInstance(instance, module) { + wasmExports = instance.exports; + + wasmExports = Asyncify.instrumentWasmExports(wasmExports); + + + + wasmMemory = wasmExports['memory']; + + assert(wasmMemory, 'memory not found in wasm exports'); + updateMemoryViews(); + + wasmTable = wasmExports['__indirect_function_table']; + + assert(wasmTable, 'table not found in wasm exports'); + + addOnInit(wasmExports['__wasm_call_ctors']); + + removeRunDependency('wasm-instantiate'); + return wasmExports; + } + // wait for the pthread pool (if any) + addRunDependency('wasm-instantiate'); + + // Prefer streaming instantiation if available. + // Async compilation can be confusing when an error on the page overwrites Module + // (for example, if the order of elements is wrong, and the one defining Module is + // later), so we save Module and check it later. + var trueModule = Module; + function receiveInstantiationResult(result) { + // 'result' is a ResultObject object which has both the module and instance. + // receiveInstance() will swap in the exports (to Module.asm) so they can be called + assert(Module === trueModule, 'the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?'); + trueModule = null; + // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line. + // When the regression is fixed, can restore the above PTHREADS-enabled path. + receiveInstance(result['instance']); + } + + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback + // to manually instantiate the Wasm module themselves. This allows pages to + // run the instantiation parallel to any other async startup actions they are + // performing. + // Also pthreads and wasm workers initialize the wasm instance through this + // path. + if (Module['instantiateWasm']) { + try { + return Module['instantiateWasm'](info, receiveInstance); + } catch(e) { + err(`Module.instantiateWasm callback failed with error: ${e}`); + // If instantiation fails, reject the module ready promise. + readyPromiseReject(e); + } + } + + if (!wasmBinaryFile) wasmBinaryFile = findWasmBinary(); + + // If instantiation fails, reject the module ready promise. + instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject); + return {}; // no exports yet; we'll fill them in later +} + +// Globals used by JS i64 conversions (see makeSetValue) +var tempDouble; +var tempI64; + +// include: runtime_debug.js +// Endianness check +(() => { + var h16 = new Int16Array(1); + var h8 = new Int8Array(h16.buffer); + h16[0] = 0x6373; + if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian! (Run with -sSUPPORT_BIG_ENDIAN to bypass)'; +})(); + +function legacyModuleProp(prop, newName, incoming=true) { + if (!Object.getOwnPropertyDescriptor(Module, prop)) { + Object.defineProperty(Module, prop, { + configurable: true, + get() { + let extra = incoming ? ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)' : ''; + abort(`\`Module.${prop}\` has been replaced by \`${newName}\`` + extra); + + } + }); + } +} + +function ignoredModuleProp(prop) { + if (Object.getOwnPropertyDescriptor(Module, prop)) { + abort(`\`Module.${prop}\` was supplied but \`${prop}\` not included in INCOMING_MODULE_JS_API`); + } +} + +// forcing the filesystem exports a few things by default +function isExportedByForceFilesystem(name) { + return name === 'FS_createPath' || + name === 'FS_createDataFile' || + name === 'FS_createPreloadedFile' || + name === 'FS_unlink' || + name === 'addRunDependency' || + // The old FS has some functionality that WasmFS lacks. + name === 'FS_createLazyFile' || + name === 'FS_createDevice' || + name === 'removeRunDependency'; +} + +function missingGlobal(sym, msg) { + if (typeof globalThis != 'undefined') { + Object.defineProperty(globalThis, sym, { + configurable: true, + get() { + warnOnce(`\`${sym}\` is not longer defined by emscripten. ${msg}`); + return undefined; + } + }); + } +} + +missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer'); +missingGlobal('asm', 'Please use wasmExports instead'); + +function missingLibrarySymbol(sym) { + if (typeof globalThis != 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) { + Object.defineProperty(globalThis, sym, { + configurable: true, + get() { + // Can't `abort()` here because it would break code that does runtime + // checks. e.g. `if (typeof SDL === 'undefined')`. + var msg = `\`${sym}\` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line`; + // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in + // library.js, which means $name for a JS name with no prefix, or name + // for a JS name like _name. + var librarySymbol = sym; + if (!librarySymbol.startsWith('_')) { + librarySymbol = '$' + sym; + } + msg += ` (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='${librarySymbol}')`; + if (isExportedByForceFilesystem(sym)) { + msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; + } + warnOnce(msg); + return undefined; + } + }); + } + // Any symbol that is not included from the JS library is also (by definition) + // not exported on the Module object. + unexportedRuntimeSymbol(sym); +} + +function unexportedRuntimeSymbol(sym) { + if (!Object.getOwnPropertyDescriptor(Module, sym)) { + Object.defineProperty(Module, sym, { + configurable: true, + get() { + var msg = `'${sym}' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ)`; + if (isExportedByForceFilesystem(sym)) { + msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; + } + abort(msg); + } + }); + } +} + +// Used by XXXXX_DEBUG settings to output debug messages. +function dbg(...args) { + // TODO(sbc): Make this configurable somehow. Its not always convenient for + // logging to show up as warnings. + console.warn(...args); +} +// end include: runtime_debug.js +// === Body === + +var ASM_CONSTS = { + 67601776: () => { try { FS.mkdir('/tulip4/user'); } catch (err) { console.log('tulip4/user already exist'); } FS.mount(IDBFS, {autoPersist:true}, '/tulip4/user'); FS.syncfs(true, function (err) { }); }, + 67601958: ($0, $1) => { if(midiOutputDevice != null) { midiOutputDevice.send(HEAPU8.subarray($0, $0 + $1)); } }, + 67602044: ($0) => { var str = UTF8ToString($0) + '\n\n' + 'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :'; var reply = window.prompt(str, "i"); if (reply === null) { reply = "i"; } return allocate(intArrayFromString(reply), 'i8', ALLOC_NORMAL); }, + 67602269: () => { if (typeof(AudioContext) !== 'undefined') { return true; } else if (typeof(webkitAudioContext) !== 'undefined') { return true; } return false; }, + 67602416: () => { if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) { return true; } else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') { return true; } return false; }, + 67602650: ($0) => { if(typeof(Module['SDL2']) === 'undefined') { Module['SDL2'] = {}; } var SDL2 = Module['SDL2']; if (!$0) { SDL2.audio = {}; } else { SDL2.capture = {}; } if (!SDL2.audioContext) { if (typeof(AudioContext) !== 'undefined') { SDL2.audioContext = new AudioContext(); } else if (typeof(webkitAudioContext) !== 'undefined') { SDL2.audioContext = new webkitAudioContext(); } if (SDL2.audioContext) { autoResumeAudioContext(SDL2.audioContext); } } return SDL2.audioContext === undefined ? -1 : 0; }, + 67603143: () => { var SDL2 = Module['SDL2']; return SDL2.audioContext.sampleRate; }, + 67603211: ($0, $1, $2, $3) => { var SDL2 = Module['SDL2']; var have_microphone = function(stream) { if (SDL2.capture.silenceTimer !== undefined) { clearTimeout(SDL2.capture.silenceTimer); SDL2.capture.silenceTimer = undefined; } SDL2.capture.mediaStreamNode = SDL2.audioContext.createMediaStreamSource(stream); SDL2.capture.scriptProcessorNode = SDL2.audioContext.createScriptProcessor($1, $0, 1); SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) { if ((SDL2 === undefined) || (SDL2.capture === undefined)) { return; } audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0); SDL2.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer; dynCall('vi', $2, [$3]); }; SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode); SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination); SDL2.capture.stream = stream; }; var no_microphone = function(error) { }; SDL2.capture.silenceBuffer = SDL2.audioContext.createBuffer($0, $1, SDL2.audioContext.sampleRate); SDL2.capture.silenceBuffer.getChannelData(0).fill(0.0); var silence_callback = function() { SDL2.capture.currentCaptureBuffer = SDL2.capture.silenceBuffer; dynCall('vi', $2, [$3]); }; SDL2.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000); if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) { navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone); } else if (navigator.webkitGetUserMedia !== undefined) { navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone); } }, + 67604863: ($0, $1, $2, $3) => { var SDL2 = Module['SDL2']; SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0); SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) { if ((SDL2 === undefined) || (SDL2.audio === undefined)) { return; } SDL2.audio.currentOutputBuffer = e['outputBuffer']; dynCall('vi', $2, [$3]); }; SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']); }, + 67605273: ($0, $1) => { var SDL2 = Module['SDL2']; var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels; for (var c = 0; c < numChannels; ++c) { var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c); if (channelData.length != $1) { throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!'; } if (numChannels == 1) { for (var j = 0; j < $1; ++j) { setValue($0 + (j * 4), channelData[j], 'float'); } } else { for (var j = 0; j < $1; ++j) { setValue($0 + (((j * numChannels) + c) * 4), channelData[j], 'float'); } } } }, + 67605878: ($0, $1) => { var SDL2 = Module['SDL2']; var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels']; for (var c = 0; c < numChannels; ++c) { var channelData = SDL2.audio.currentOutputBuffer['getChannelData'](c); if (channelData.length != $1) { throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!'; } for (var j = 0; j < $1; ++j) { channelData[j] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2]; } } }, + 67606358: ($0) => { var SDL2 = Module['SDL2']; if ($0) { if (SDL2.capture.silenceTimer !== undefined) { clearTimeout(SDL2.capture.silenceTimer); } if (SDL2.capture.stream !== undefined) { var tracks = SDL2.capture.stream.getAudioTracks(); for (var i = 0; i < tracks.length; i++) { SDL2.capture.stream.removeTrack(tracks[i]); } SDL2.capture.stream = undefined; } if (SDL2.capture.scriptProcessorNode !== undefined) { SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {}; SDL2.capture.scriptProcessorNode.disconnect(); SDL2.capture.scriptProcessorNode = undefined; } if (SDL2.capture.mediaStreamNode !== undefined) { SDL2.capture.mediaStreamNode.disconnect(); SDL2.capture.mediaStreamNode = undefined; } if (SDL2.capture.silenceBuffer !== undefined) { SDL2.capture.silenceBuffer = undefined } SDL2.capture = undefined; } else { if (SDL2.audio.scriptProcessorNode != undefined) { SDL2.audio.scriptProcessorNode.disconnect(); SDL2.audio.scriptProcessorNode = undefined; } SDL2.audio = undefined; } if ((SDL2.audioContext !== undefined) && (SDL2.audio === undefined) && (SDL2.capture === undefined)) { SDL2.audioContext.close(); SDL2.audioContext = undefined; } }, + 67607530: ($0, $1, $2) => { var w = $0; var h = $1; var pixels = $2; if (!Module['SDL2']) Module['SDL2'] = {}; var SDL2 = Module['SDL2']; if (SDL2.ctxCanvas !== Module['canvas']) { SDL2.ctx = Module['createContext'](Module['canvas'], false, true); SDL2.ctxCanvas = Module['canvas']; } if (SDL2.w !== w || SDL2.h !== h || SDL2.imageCtx !== SDL2.ctx) { SDL2.image = SDL2.ctx.createImageData(w, h); SDL2.w = w; SDL2.h = h; SDL2.imageCtx = SDL2.ctx; } var data = SDL2.image.data; var src = pixels >> 2; var dst = 0; var num; if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) { num = data.length; while (dst < num) { var val = HEAP32[src]; data[dst ] = val & 0xff; data[dst+1] = (val >> 8) & 0xff; data[dst+2] = (val >> 16) & 0xff; data[dst+3] = 0xff; src++; dst += 4; } } else { if (SDL2.data32Data !== data) { SDL2.data32 = new Int32Array(data.buffer); SDL2.data8 = new Uint8Array(data.buffer); SDL2.data32Data = data; } var data32 = SDL2.data32; num = data32.length; data32.set(HEAP32.subarray(src, src + num)); var data8 = SDL2.data8; var i = 3; var j = i + 4*num; if (num % 8 == 0) { while (i < j) { data8[i] = 0xff; i = i + 4 | 0; data8[i] = 0xff; i = i + 4 | 0; data8[i] = 0xff; i = i + 4 | 0; data8[i] = 0xff; i = i + 4 | 0; data8[i] = 0xff; i = i + 4 | 0; data8[i] = 0xff; i = i + 4 | 0; data8[i] = 0xff; i = i + 4 | 0; data8[i] = 0xff; i = i + 4 | 0; } } else { while (i < j) { data8[i] = 0xff; i = i + 4 | 0; } } } SDL2.ctx.putImageData(SDL2.image, 0, 0); }, + 67608999: ($0, $1, $2, $3, $4) => { var w = $0; var h = $1; var hot_x = $2; var hot_y = $3; var pixels = $4; var canvas = document.createElement("canvas"); canvas.width = w; canvas.height = h; var ctx = canvas.getContext("2d"); var image = ctx.createImageData(w, h); var data = image.data; var src = pixels >> 2; var dst = 0; var num; if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) { num = data.length; while (dst < num) { var val = HEAP32[src]; data[dst ] = val & 0xff; data[dst+1] = (val >> 8) & 0xff; data[dst+2] = (val >> 16) & 0xff; data[dst+3] = (val >> 24) & 0xff; src++; dst += 4; } } else { var data32 = new Int32Array(data.buffer); num = data32.length; data32.set(HEAP32.subarray(src, src + num)); } ctx.putImageData(image, 0, 0); var url = hot_x === 0 && hot_y === 0 ? "url(" + canvas.toDataURL() + "), auto" : "url(" + canvas.toDataURL() + ") " + hot_x + " " + hot_y + ", auto"; var urlBuf = _malloc(url.length + 1); stringToUTF8(url, urlBuf, url.length + 1); return urlBuf; }, + 67609988: ($0) => { if (Module['canvas']) { Module['canvas'].style['cursor'] = UTF8ToString($0); } }, + 67610071: () => { if (Module['canvas']) { Module['canvas'].style['cursor'] = 'none'; } }, + 67610140: () => { return window.innerWidth; }, + 67610170: () => { return window.innerHeight; } +}; +function proxy_convert_mp_to_js_then_js_to_mp_obj_jsside(out) { const ret = proxy_convert_mp_to_js_obj_jsside(out); proxy_convert_js_to_mp_obj_jsside_force_double_proxy(ret, out); } +function proxy_convert_mp_to_js_then_js_to_js_then_js_to_mp_obj_jsside(out) { const ret = proxy_convert_mp_to_js_obj_jsside(out); const js_obj = PyProxy.toJs(ret); proxy_convert_js_to_mp_obj_jsside(js_obj, out); } +function js_get_proxy_js_ref_info(out) { let used = 0; for (const elem of proxy_js_ref) { if (elem !== undefined) { ++used; } } Module.setValue(out, proxy_js_ref.length, "i32"); Module.setValue(out + 4, used, "i32"); } +function has_attr(jsref,str) { const base = proxy_js_ref[jsref]; const attr = UTF8ToString(str); if (attr in base) { return true; } else { return false; } } +function lookup_attr(jsref,str,out) { const base = proxy_js_ref[jsref]; const attr = UTF8ToString(str); let value = base[attr]; if (value !== undefined || attr in base) { if (typeof value === "function") { if (base !== globalThis) { if ("_ref" in value) { } else { value = value.bind(base); } } } proxy_convert_js_to_mp_obj_jsside(value, out); return true; } else { return false; } } +function store_attr(jsref,attr_ptr,value_ref) { const attr = UTF8ToString(attr_ptr); const value = proxy_convert_mp_to_js_obj_jsside(value_ref); proxy_js_ref[jsref][attr] = value; } +function call0(f_ref,out) { const f = proxy_js_ref[f_ref]; const ret = f(); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function call1(f_ref,a0,out) { const a0_js = proxy_convert_mp_to_js_obj_jsside(a0); const f = proxy_js_ref[f_ref]; const ret = f(a0_js); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function call2(f_ref,a0,a1,out) { const a0_js = proxy_convert_mp_to_js_obj_jsside(a0); const a1_js = proxy_convert_mp_to_js_obj_jsside(a1); const f = proxy_js_ref[f_ref]; const ret = f(a0_js, a1_js); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function calln(f_ref,n_args,value,out) { const f = proxy_js_ref[f_ref]; const a = []; for (let i = 0; i < n_args; ++i) { const v = proxy_convert_mp_to_js_obj_jsside(value + i * 3 * 4); a.push(v); } const ret = f(... a); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function call0_kwarg(f_ref,n_kw,key,value,out) { const f = proxy_js_ref[f_ref]; const a = {}; for (let i = 0; i < n_kw; ++i) { const k = UTF8ToString(getValue(key + i * 4, "i32")); const v = proxy_convert_mp_to_js_obj_jsside(value + i * 3 * 4); a[k] = v; } const ret = f(a); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function call1_kwarg(f_ref,arg0,n_kw,key,value,out) { const f = proxy_js_ref[f_ref]; const a0 = proxy_convert_mp_to_js_obj_jsside(arg0); const a = {}; for (let i = 0; i < n_kw; ++i) { const k = UTF8ToString(getValue(key + i * 4, "i32")); const v = proxy_convert_mp_to_js_obj_jsside(value + i * 3 * 4); a[k] = v; } const ret = f(a0, a); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function js_reflect_construct(f_ref,n_args,args,out) { const f = proxy_js_ref[f_ref]; const as = []; for (let i = 0; i < n_args; ++i) { as.push(proxy_convert_mp_to_js_obj_jsside(args + i * 3 * 4)); } const ret = Reflect.construct(f, as); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function js_get_iter(f_ref,out) { const f = proxy_js_ref[f_ref]; const ret = f[Symbol.iterator](); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function js_iter_next(f_ref,out) { const f = proxy_js_ref[f_ref]; const ret = f.next(); if (ret.done) { return false; } else { proxy_convert_js_to_mp_obj_jsside(ret.value, out); return true; } } +function js_subscr_load(f_ref,index_ref,out) { const target = proxy_js_ref[f_ref]; const index = python_index_semantics(target, proxy_convert_mp_to_js_obj_jsside(index_ref)); const ret = target[index]; proxy_convert_js_to_mp_obj_jsside(ret, out); } +function js_subscr_store(f_ref,idx,value) { const f = proxy_js_ref[f_ref]; f[proxy_convert_mp_to_js_obj_jsside(idx)] = proxy_convert_mp_to_js_obj_jsside(value); } +function proxy_js_free_obj(js_ref) { if (js_ref >= PROXY_JS_REF_NUM_STATIC) { proxy_js_ref[js_ref] = undefined; if (js_ref < proxy_js_ref_next) { proxy_js_ref_next = js_ref; } } } +function js_check_existing(c_ref) { return proxy_js_check_existing(c_ref); } +function js_get_error_info(jsref,out_name,out_message) { const error = proxy_js_ref[jsref]; proxy_convert_js_to_mp_obj_jsside(error.name, out_name); proxy_convert_js_to_mp_obj_jsside(error.message, out_message); } +function js_then_resolve(ret_value,resolve) { const ret_value_js = proxy_convert_mp_to_js_obj_jsside(ret_value); const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve); resolve_js(ret_value_js); } +function js_then_reject(ret_value,reject) { let ret_value_js; try { ret_value_js = proxy_convert_mp_to_js_obj_jsside(ret_value); } catch(error) { ret_value_js = error; } const reject_js = proxy_convert_mp_to_js_obj_jsside(reject); reject_js(ret_value_js); } +function js_then_continue(jsref,py_resume,resolve,reject,out) { const py_resume_js = proxy_convert_mp_to_js_obj_jsside(py_resume); const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve); const reject_js = proxy_convert_mp_to_js_obj_jsside(reject); const ret = proxy_js_ref[jsref].then( (result) => { py_resume_js(result, null, resolve_js, reject_js); }, (reason) => { py_resume_js(null, reason, resolve_js, reject_js); }, ); proxy_convert_js_to_mp_obj_jsside(ret, out); } +function create_promise(out_set,out_promise) { const out_set_js = proxy_convert_mp_to_js_obj_jsside(out_set); const promise = new Promise(out_set_js); proxy_convert_js_to_mp_obj_jsside(promise, out_promise); } + +// end include: preamble.js + + + /** @constructor */ + function ExitStatus(status) { + this.name = 'ExitStatus'; + this.message = `Program terminated with exit(${status})`; + this.status = status; + } + + var callRuntimeCallbacks = (callbacks) => { + while (callbacks.length > 0) { + // Pass the module as the first argument. + callbacks.shift()(Module); + } + }; + + + /** + * @param {number} ptr + * @param {string} type + */ + function getValue(ptr, type = 'i8') { + if (type.endsWith('*')) type = '*'; + switch (type) { + case 'i1': return HEAP8[ptr]; + case 'i8': return HEAP8[ptr]; + case 'i16': return HEAP16[((ptr)>>1)]; + case 'i32': return HEAP32[((ptr)>>2)]; + case 'i64': abort('to do getValue(i64) use WASM_BIGINT'); + case 'float': return HEAPF32[((ptr)>>2)]; + case 'double': return HEAPF64[((ptr)>>3)]; + case '*': return HEAPU32[((ptr)>>2)]; + default: abort(`invalid type for getValue: ${type}`); + } + } + + var noExitRuntime = Module['noExitRuntime'] || true; + + var ptrToString = (ptr) => { + assert(typeof ptr === 'number'); + // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned. + ptr >>>= 0; + return '0x' + ptr.toString(16).padStart(8, '0'); + }; + + + /** + * @param {number} ptr + * @param {number} value + * @param {string} type + */ + function setValue(ptr, value, type = 'i8') { + if (type.endsWith('*')) type = '*'; + switch (type) { + case 'i1': HEAP8[ptr] = value; break; + case 'i8': HEAP8[ptr] = value; break; + case 'i16': HEAP16[((ptr)>>1)] = value; break; + case 'i32': HEAP32[((ptr)>>2)] = value; break; + case 'i64': abort('to do setValue(i64) use WASM_BIGINT'); + case 'float': HEAPF32[((ptr)>>2)] = value; break; + case 'double': HEAPF64[((ptr)>>3)] = value; break; + case '*': HEAPU32[((ptr)>>2)] = value; break; + default: abort(`invalid type for setValue: ${type}`); + } + } + + var stackRestore = (val) => __emscripten_stack_restore(val); + + var stackSave = () => _emscripten_stack_get_current(); + + var warnOnce = (text) => { + warnOnce.shown ||= {}; + if (!warnOnce.shown[text]) { + warnOnce.shown[text] = 1; + if (ENVIRONMENT_IS_NODE) text = 'warning: ' + text; + err(text); + } + }; + + var PATH = { + isAbs:(path) => path.charAt(0) === '/', + splitPath:(filename) => { + var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + return splitPathRe.exec(filename).slice(1); + }, + normalizeArray:(parts, allowAboveRoot) => { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up; up--) { + parts.unshift('..'); + } + } + return parts; + }, + normalize:(path) => { + var isAbsolute = PATH.isAbs(path), + trailingSlash = path.substr(-1) === '/'; + // Normalize the path + path = PATH.normalizeArray(path.split('/').filter((p) => !!p), !isAbsolute).join('/'); + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + return (isAbsolute ? '/' : '') + path; + }, + dirname:(path) => { + var result = PATH.splitPath(path), + root = result[0], + dir = result[1]; + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + return root + dir; + }, + basename:(path) => { + // EMSCRIPTEN return '/'' for '/', not an empty string + if (path === '/') return '/'; + path = PATH.normalize(path); + path = path.replace(/\/$/, ""); + var lastSlash = path.lastIndexOf('/'); + if (lastSlash === -1) return path; + return path.substr(lastSlash+1); + }, + join:(...paths) => PATH.normalize(paths.join('/')), + join2:(l, r) => PATH.normalize(l + '/' + r), + }; + + var initRandomFill = () => { + if (typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function') { + // for modern web browsers + return (view) => crypto.getRandomValues(view); + } else + if (ENVIRONMENT_IS_NODE) { + // for nodejs with or without crypto support included + try { + var crypto_module = require('crypto'); + var randomFillSync = crypto_module['randomFillSync']; + if (randomFillSync) { + // nodejs with LTS crypto support + return (view) => crypto_module['randomFillSync'](view); + } + // very old nodejs with the original crypto API + var randomBytes = crypto_module['randomBytes']; + return (view) => ( + view.set(randomBytes(view.byteLength)), + // Return the original view to match modern native implementations. + view + ); + } catch (e) { + // nodejs doesn't have crypto support + } + } + // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096 + abort('no cryptographic support found for randomDevice. consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: (array) => { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };'); + }; + var randomFill = (view) => { + // Lazily init on the first invocation. + return (randomFill = initRandomFill())(view); + }; + + + + var PATH_FS = { + resolve:(...args) => { + var resolvedPath = '', + resolvedAbsolute = false; + for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? args[i] : FS.cwd(); + // Skip empty and invalid entries + if (typeof path != 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + return ''; // an invalid portion invalidates the whole thing + } + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = PATH.isAbs(path); + } + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter((p) => !!p), !resolvedAbsolute).join('/'); + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; + }, + relative:(from, to) => { + from = PATH_FS.resolve(from).substr(1); + to = PATH_FS.resolve(to).substr(1); + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + return outputParts.join('/'); + }, + }; + + + var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder() : undefined; + + /** + * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given + * array that contains uint8 values, returns a copy of that string as a + * Javascript String object. + * heapOrArray is either a regular array, or a JavaScript typed array view. + * @param {number} idx + * @param {number=} maxBytesToRead + * @return {string} + */ + var UTF8ArrayToString = (heapOrArray, idx, maxBytesToRead) => { + var endIdx = idx + maxBytesToRead; + var endPtr = idx; + // TextDecoder needs to know the byte length in advance, it doesn't stop on + // null terminator by itself. Also, use the length info to avoid running tiny + // strings through TextDecoder, since .subarray() allocates garbage. + // (As a tiny code save trick, compare endPtr against endIdx using a negation, + // so that undefined means Infinity) + while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; + + if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { + return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); + } + var str = ''; + // If building with TextDecoder, we have already computed the string length + // above, so test loop end condition against that + while (idx < endPtr) { + // For UTF8 byte structure, see: + // http://en.wikipedia.org/wiki/UTF-8#Description + // https://www.ietf.org/rfc/rfc2279.txt + // https://tools.ietf.org/html/rfc3629 + var u0 = heapOrArray[idx++]; + if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } + var u1 = heapOrArray[idx++] & 63; + if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } + var u2 = heapOrArray[idx++] & 63; + if ((u0 & 0xF0) == 0xE0) { + u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; + } else { + if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte ' + ptrToString(u0) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!'); + u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63); + } + + if (u0 < 0x10000) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 0x10000; + str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); + } + } + return str; + }; + + var FS_stdin_getChar_buffer = []; + + var lengthBytesUTF8 = (str) => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var c = str.charCodeAt(i); // possibly a lead surrogate + if (c <= 0x7F) { + len++; + } else if (c <= 0x7FF) { + len += 2; + } else if (c >= 0xD800 && c <= 0xDFFF) { + len += 4; ++i; + } else { + len += 3; + } + } + return len; + }; + + var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { + assert(typeof str === 'string', `stringToUTF8Array expects a string (got ${typeof str})`); + // Parameter maxBytesToWrite is not optional. Negative values, 0, null, + // undefined and false each don't write out any bytes. + if (!(maxBytesToWrite > 0)) + return 0; + + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description + // and https://www.ietf.org/rfc/rfc2279.txt + // and https://tools.ietf.org/html/rfc3629 + var u = str.charCodeAt(i); // possibly a lead surrogate + if (u >= 0xD800 && u <= 0xDFFF) { + var u1 = str.charCodeAt(++i); + u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); + } + if (u <= 0x7F) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 0x7FF) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 0xC0 | (u >> 6); + heap[outIdx++] = 0x80 | (u & 63); + } else if (u <= 0xFFFF) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 0xE0 | (u >> 12); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + if (u > 0x10FFFF) warnOnce('Invalid Unicode code point ' + ptrToString(u) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).'); + heap[outIdx++] = 0xF0 | (u >> 18); + heap[outIdx++] = 0x80 | ((u >> 12) & 63); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } + } + // Null-terminate the pointer to the buffer. + heap[outIdx] = 0; + return outIdx - startIdx; + }; + /** @type {function(string, boolean=, number=)} */ + function intArrayFromString(stringy, dontAddNull, length) { + var len = length > 0 ? length : lengthBytesUTF8(stringy)+1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); + if (dontAddNull) u8array.length = numBytesWritten; + return u8array; + } + var FS_stdin_getChar = () => { + if (!FS_stdin_getChar_buffer.length) { + var result = null; + if (ENVIRONMENT_IS_NODE) { + // we will read data by chunks of BUFSIZE + var BUFSIZE = 256; + var buf = Buffer.alloc(BUFSIZE); + var bytesRead = 0; + + // For some reason we must suppress a closure warning here, even though + // fd definitely exists on process.stdin, and is even the proper way to + // get the fd of stdin, + // https://github.com/nodejs/help/issues/2136#issuecomment-523649904 + // This started to happen after moving this logic out of library_tty.js, + // so it is related to the surrounding code in some unclear manner. + /** @suppress {missingProperties} */ + var fd = process.stdin.fd; + + try { + bytesRead = fs.readSync(fd, buf, 0, BUFSIZE); + } catch(e) { + // Cross-platform differences: on Windows, reading EOF throws an + // exception, but on other OSes, reading EOF returns 0. Uniformize + // behavior by treating the EOF exception to return 0. + if (e.toString().includes('EOF')) bytesRead = 0; + else throw e; + } + + if (bytesRead > 0) { + result = buf.slice(0, bytesRead).toString('utf-8'); + } + } else + if (typeof window != 'undefined' && + typeof window.prompt == 'function') { + // Browser. + result = window.prompt('Input: '); // returns null on cancel + if (result !== null) { + result += '\n'; + } + } else + {} + if (!result) { + return null; + } + FS_stdin_getChar_buffer = intArrayFromString(result, true); + } + return FS_stdin_getChar_buffer.shift(); + }; + var TTY = { + ttys:[], + init() { + // https://github.com/emscripten-core/emscripten/pull/1555 + // if (ENVIRONMENT_IS_NODE) { + // // currently, FS.init does not distinguish if process.stdin is a file or TTY + // // device, it always assumes it's a TTY device. because of this, we're forcing + // // process.stdin to UTF8 encoding to at least make stdin reading compatible + // // with text files until FS.init can be refactored. + // process.stdin.setEncoding('utf8'); + // } + }, + shutdown() { + // https://github.com/emscripten-core/emscripten/pull/1555 + // if (ENVIRONMENT_IS_NODE) { + // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)? + // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation + // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists? + // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle + // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call + // process.stdin.pause(); + // } + }, + register(dev, ops) { + TTY.ttys[dev] = { input: [], output: [], ops: ops }; + FS.registerDevice(dev, TTY.stream_ops); + }, + stream_ops:{ + open(stream) { + var tty = TTY.ttys[stream.node.rdev]; + if (!tty) { + throw new FS.ErrnoError(43); + } + stream.tty = tty; + stream.seekable = false; + }, + close(stream) { + // flush any pending line data + stream.tty.ops.fsync(stream.tty); + }, + fsync(stream) { + stream.tty.ops.fsync(stream.tty); + }, + read(stream, buffer, offset, length, pos /* ignored */) { + if (!stream.tty || !stream.tty.ops.get_char) { + throw new FS.ErrnoError(60); + } + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = stream.tty.ops.get_char(stream.tty); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset+i] = result; + } + if (bytesRead) { + stream.node.timestamp = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.put_char) { + throw new FS.ErrnoError(60); + } + try { + for (var i = 0; i < length; i++) { + stream.tty.ops.put_char(stream.tty, buffer[offset+i]); + } + } catch (e) { + throw new FS.ErrnoError(29); + } + if (length) { + stream.node.timestamp = Date.now(); + } + return i; + }, + }, + default_tty_ops:{ + get_char(tty) { + return FS_stdin_getChar(); + }, + put_char(tty, val) { + if (val === null || val === 10) { + out(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle. + } + }, + fsync(tty) { + if (tty.output && tty.output.length > 0) { + out(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } + }, + ioctl_tcgets(tty) { + // typical setting + return { + c_iflag: 25856, + c_oflag: 5, + c_cflag: 191, + c_lflag: 35387, + c_cc: [ + 0x03, 0x1c, 0x7f, 0x15, 0x04, 0x00, 0x01, 0x00, 0x11, 0x13, 0x1a, 0x00, + 0x12, 0x0f, 0x17, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + }; + }, + ioctl_tcsets(tty, optional_actions, data) { + // currently just ignore + return 0; + }, + ioctl_tiocgwinsz(tty) { + return [24, 80]; + }, + }, + default_tty1_ops:{ + put_char(tty, val) { + if (val === null || val === 10) { + err(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync(tty) { + if (tty.output && tty.output.length > 0) { + err(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } + }, + }, + }; + + + var zeroMemory = (address, size) => { + HEAPU8.fill(0, address, address + size); + return address; + }; + + var alignMemory = (size, alignment) => { + assert(alignment, "alignment argument is required"); + return Math.ceil(size / alignment) * alignment; + }; + var mmapAlloc = (size) => { + abort('internal error: mmapAlloc called but `emscripten_builtin_memalign` native symbol not exported'); + }; + var MEMFS = { + ops_table:null, + mount(mount) { + return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0); + }, + createNode(parent, name, mode, dev) { + if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { + // no supported + throw new FS.ErrnoError(63); + } + MEMFS.ops_table ||= { + dir: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + lookup: MEMFS.node_ops.lookup, + mknod: MEMFS.node_ops.mknod, + rename: MEMFS.node_ops.rename, + unlink: MEMFS.node_ops.unlink, + rmdir: MEMFS.node_ops.rmdir, + readdir: MEMFS.node_ops.readdir, + symlink: MEMFS.node_ops.symlink + }, + stream: { + llseek: MEMFS.stream_ops.llseek + } + }, + file: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }, + stream: { + llseek: MEMFS.stream_ops.llseek, + read: MEMFS.stream_ops.read, + write: MEMFS.stream_ops.write, + allocate: MEMFS.stream_ops.allocate, + mmap: MEMFS.stream_ops.mmap, + msync: MEMFS.stream_ops.msync + } + }, + link: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + readlink: MEMFS.node_ops.readlink + }, + stream: {} + }, + chrdev: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }, + stream: FS.chrdev_stream_ops + } + }; + var node = FS.createNode(parent, name, mode, dev); + if (FS.isDir(node.mode)) { + node.node_ops = MEMFS.ops_table.dir.node; + node.stream_ops = MEMFS.ops_table.dir.stream; + node.contents = {}; + } else if (FS.isFile(node.mode)) { + node.node_ops = MEMFS.ops_table.file.node; + node.stream_ops = MEMFS.ops_table.file.stream; + node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity. + // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred + // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size + // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme. + node.contents = null; + } else if (FS.isLink(node.mode)) { + node.node_ops = MEMFS.ops_table.link.node; + node.stream_ops = MEMFS.ops_table.link.stream; + } else if (FS.isChrdev(node.mode)) { + node.node_ops = MEMFS.ops_table.chrdev.node; + node.stream_ops = MEMFS.ops_table.chrdev.stream; + } + node.timestamp = Date.now(); + // add the new node to the parent + if (parent) { + parent.contents[name] = node; + parent.timestamp = node.timestamp; + } + return node; + }, + getFileDataAsTypedArray(node) { + if (!node.contents) return new Uint8Array(0); + if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes. + return new Uint8Array(node.contents); + }, + expandFileStorage(node, newCapacity) { + var prevCapacity = node.contents ? node.contents.length : 0; + if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough. + // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity. + // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to + // avoid overshooting the allocation cap by a very large margin. + var CAPACITY_DOUBLING_MAX = 1024 * 1024; + newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> 0); + if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding. + var oldContents = node.contents; + node.contents = new Uint8Array(newCapacity); // Allocate new storage. + if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage. + }, + resizeFileStorage(node, newSize) { + if (node.usedBytes == newSize) return; + if (newSize == 0) { + node.contents = null; // Fully decommit when requesting a resize to zero. + node.usedBytes = 0; + } else { + var oldContents = node.contents; + node.contents = new Uint8Array(newSize); // Allocate new storage. + if (oldContents) { + node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); // Copy old data over to the new storage. + } + node.usedBytes = newSize; + } + }, + node_ops:{ + getattr(node) { + var attr = {}; + // device numbers reuse inode numbers. + attr.dev = FS.isChrdev(node.mode) ? node.id : 1; + attr.ino = node.id; + attr.mode = node.mode; + attr.nlink = 1; + attr.uid = 0; + attr.gid = 0; + attr.rdev = node.rdev; + if (FS.isDir(node.mode)) { + attr.size = 4096; + } else if (FS.isFile(node.mode)) { + attr.size = node.usedBytes; + } else if (FS.isLink(node.mode)) { + attr.size = node.link.length; + } else { + attr.size = 0; + } + attr.atime = new Date(node.timestamp); + attr.mtime = new Date(node.timestamp); + attr.ctime = new Date(node.timestamp); + // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize), + // but this is not required by the standard. + attr.blksize = 4096; + attr.blocks = Math.ceil(attr.size / attr.blksize); + return attr; + }, + setattr(node, attr) { + if (attr.mode !== undefined) { + node.mode = attr.mode; + } + if (attr.timestamp !== undefined) { + node.timestamp = attr.timestamp; + } + if (attr.size !== undefined) { + MEMFS.resizeFileStorage(node, attr.size); + } + }, + lookup(parent, name) { + throw FS.genericErrors[44]; + }, + mknod(parent, name, mode, dev) { + return MEMFS.createNode(parent, name, mode, dev); + }, + rename(old_node, new_dir, new_name) { + // if we're overwriting a directory at new_name, make sure it's empty. + if (FS.isDir(old_node.mode)) { + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) { + } + if (new_node) { + for (var i in new_node.contents) { + throw new FS.ErrnoError(55); + } + } + } + // do the internal rewiring + delete old_node.parent.contents[old_node.name]; + old_node.parent.timestamp = Date.now() + old_node.name = new_name; + new_dir.contents[new_name] = old_node; + new_dir.timestamp = old_node.parent.timestamp; + }, + unlink(parent, name) { + delete parent.contents[name]; + parent.timestamp = Date.now(); + }, + rmdir(parent, name) { + var node = FS.lookupNode(parent, name); + for (var i in node.contents) { + throw new FS.ErrnoError(55); + } + delete parent.contents[name]; + parent.timestamp = Date.now(); + }, + readdir(node) { + var entries = ['.', '..']; + for (var key of Object.keys(node.contents)) { + entries.push(key); + } + return entries; + }, + symlink(parent, newname, oldpath) { + var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0); + node.link = oldpath; + return node; + }, + readlink(node) { + if (!FS.isLink(node.mode)) { + throw new FS.ErrnoError(28); + } + return node.link; + }, + }, + stream_ops:{ + read(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= stream.node.usedBytes) return 0; + var size = Math.min(stream.node.usedBytes - position, length); + assert(size >= 0); + if (size > 8 && contents.subarray) { // non-trivial, and typed array + buffer.set(contents.subarray(position, position + size), offset); + } else { + for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i]; + } + return size; + }, + write(stream, buffer, offset, length, position, canOwn) { + // The data buffer should be a typed array view + assert(!(buffer instanceof ArrayBuffer)); + // If the buffer is located in main memory (HEAP), and if + // memory can grow, we can't hold on to references of the + // memory buffer, as they may get invalidated. That means we + // need to do copy its contents. + if (buffer.buffer === HEAP8.buffer) { + canOwn = false; + } + + if (!length) return 0; + var node = stream.node; + node.timestamp = Date.now(); + + if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array? + if (canOwn) { + assert(position === 0, 'canOwn must imply no weird position inside the file'); + node.contents = buffer.subarray(offset, offset + length); + node.usedBytes = length; + return length; + } else if (node.usedBytes === 0 && position === 0) { // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data. + node.contents = buffer.slice(offset, offset + length); + node.usedBytes = length; + return length; + } else if (position + length <= node.usedBytes) { // Writing to an already allocated and used subrange of the file? + node.contents.set(buffer.subarray(offset, offset + length), position); + return length; + } + } + + // Appending to an existing file and we need to reallocate, or source data did not come as a typed array. + MEMFS.expandFileStorage(node, position+length); + if (node.contents.subarray && buffer.subarray) { + // Use typed array write which is available. + node.contents.set(buffer.subarray(offset, offset + length), position); + } else { + for (var i = 0; i < length; i++) { + node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not. + } + } + node.usedBytes = Math.max(node.usedBytes, position + length); + return length; + }, + llseek(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + position += stream.node.usedBytes; + } + } + if (position < 0) { + throw new FS.ErrnoError(28); + } + return position; + }, + allocate(stream, offset, length) { + MEMFS.expandFileStorage(stream.node, offset + length); + stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length); + }, + mmap(stream, length, position, prot, flags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + var ptr; + var allocated; + var contents = stream.node.contents; + // Only make a new copy when MAP_PRIVATE is specified. + if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) { + // We can't emulate MAP_SHARED when the file is not backed by the + // buffer we're mapping to (e.g. the HEAP buffer). + allocated = false; + ptr = contents.byteOffset; + } else { + allocated = true; + ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + if (contents) { + // Try to avoid unnecessary slices. + if (position > 0 || position + length < contents.length) { + if (contents.subarray) { + contents = contents.subarray(position, position + length); + } else { + contents = Array.prototype.slice.call(contents, position, position + length); + } + } + HEAP8.set(contents, ptr); + } + } + return { ptr, allocated }; + }, + msync(stream, buffer, offset, length, mmapFlags) { + MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false); + // should we check if bytesWritten and length are the same? + return 0; + }, + }, + }; + + /** @param {boolean=} noRunDep */ + var asyncLoad = (url, onload, onerror, noRunDep) => { + var dep = !noRunDep ? getUniqueRunDependency(`al ${url}`) : ''; + readAsync(url).then( + (arrayBuffer) => { + assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`); + onload(new Uint8Array(arrayBuffer)); + if (dep) removeRunDependency(dep); + }, + (err) => { + if (onerror) { + onerror(); + } else { + throw `Loading data file "${url}" failed.`; + } + } + ); + if (dep) addRunDependency(dep); + }; + + + var FS_createDataFile = (parent, name, fileData, canRead, canWrite, canOwn) => { + FS.createDataFile(parent, name, fileData, canRead, canWrite, canOwn); + }; + + var preloadPlugins = Module['preloadPlugins'] || []; + var FS_handledByPreloadPlugin = (byteArray, fullname, finish, onerror) => { + // Ensure plugins are ready. + if (typeof Browser != 'undefined') Browser.init(); + + var handled = false; + preloadPlugins.forEach((plugin) => { + if (handled) return; + if (plugin['canHandle'](fullname)) { + plugin['handle'](byteArray, fullname, finish, onerror); + handled = true; + } + }); + return handled; + }; + var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => { + // TODO we should allow people to just pass in a complete filename instead + // of parent and name being that we just join them anyways + var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; + var dep = getUniqueRunDependency(`cp ${fullname}`); // might have several active requests for the same fullname + function processData(byteArray) { + function finish(byteArray) { + preFinish?.(); + if (!dontCreateFile) { + FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); + } + onload?.(); + removeRunDependency(dep); + } + if (FS_handledByPreloadPlugin(byteArray, fullname, finish, () => { + onerror?.(); + removeRunDependency(dep); + })) { + return; + } + finish(byteArray); + } + addRunDependency(dep); + if (typeof url == 'string') { + asyncLoad(url, processData, onerror); + } else { + processData(url); + } + }; + + var FS_modeStringToFlags = (str) => { + var flagModes = { + 'r': 0, + 'r+': 2, + 'w': 512 | 64 | 1, + 'w+': 512 | 64 | 2, + 'a': 1024 | 64 | 1, + 'a+': 1024 | 64 | 2, + }; + var flags = flagModes[str]; + if (typeof flags == 'undefined') { + throw new Error(`Unknown file open mode: ${str}`); + } + return flags; + }; + + var FS_getMode = (canRead, canWrite) => { + var mode = 0; + if (canRead) mode |= 292 | 73; + if (canWrite) mode |= 146; + return mode; + }; + + + + + + + var IDBFS = { + dbs:{ + }, + indexedDB:() => { + if (typeof indexedDB != 'undefined') return indexedDB; + var ret = null; + if (typeof window == 'object') ret = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; + assert(ret, 'IDBFS used, but indexedDB not supported'); + return ret; + }, + DB_VERSION:21, + DB_STORE_NAME:"FILE_DATA", + queuePersist:(mount) => { + function onPersistComplete() { + if (mount.idbPersistState === 'again') startPersist(); // If a new sync request has appeared in between, kick off a new sync + else mount.idbPersistState = 0; // Otherwise reset sync state back to idle to wait for a new sync later + } + function startPersist() { + mount.idbPersistState = 'idb'; // Mark that we are currently running a sync operation + IDBFS.syncfs(mount, /*populate:*/false, onPersistComplete); + } + + if (!mount.idbPersistState) { + // Programs typically write/copy/move multiple files in the in-memory + // filesystem within a single app frame, so when a filesystem sync + // command is triggered, do not start it immediately, but only after + // the current frame is finished. This way all the modified files + // inside the main loop tick will be batched up to the same sync. + mount.idbPersistState = setTimeout(startPersist, 0); + } else if (mount.idbPersistState === 'idb') { + // There is an active IndexedDB sync operation in-flight, but we now + // have accumulated more files to sync. We should therefore queue up + // a new sync after the current one finishes so that all writes + // will be properly persisted. + mount.idbPersistState = 'again'; + } + }, + mount:(mount) => { + // reuse core MEMFS functionality + var mnt = MEMFS.mount(mount); + // If the automatic IDBFS persistence option has been selected, then automatically persist + // all modifications to the filesystem as they occur. + if (mount?.opts?.autoPersist) { + mnt.idbPersistState = 0; // IndexedDB sync starts in idle state + var memfs_node_ops = mnt.node_ops; + mnt.node_ops = Object.assign({}, mnt.node_ops); // Clone node_ops to inject write tracking + mnt.node_ops.mknod = (parent, name, mode, dev) => { + var node = memfs_node_ops.mknod(parent, name, mode, dev); + // Propagate injected node_ops to the newly created child node + node.node_ops = mnt.node_ops; + // Remember for each IDBFS node which IDBFS mount point they came from so we know which mount to persist on modification. + node.idbfs_mount = mnt.mount; + // Remember original MEMFS stream_ops for this node + node.memfs_stream_ops = node.stream_ops; + // Clone stream_ops to inject write tracking + node.stream_ops = Object.assign({}, node.stream_ops); + + // Track all file writes + node.stream_ops.write = (stream, buffer, offset, length, position, canOwn) => { + // This file has been modified, we must persist IndexedDB when this file closes + stream.node.isModified = true; + return node.memfs_stream_ops.write(stream, buffer, offset, length, position, canOwn); + }; + + // Persist IndexedDB on file close + node.stream_ops.close = (stream) => { + var n = stream.node; + if (n.isModified) { + IDBFS.queuePersist(n.idbfs_mount); + n.isModified = false; + } + if (n.memfs_stream_ops.close) return n.memfs_stream_ops.close(stream); + }; + + return node; + }; + // Also kick off persisting the filesystem on other operations that modify the filesystem. + mnt.node_ops.mkdir = (...args) => (IDBFS.queuePersist(mnt.mount), memfs_node_ops.mkdir(...args)); + mnt.node_ops.rmdir = (...args) => (IDBFS.queuePersist(mnt.mount), memfs_node_ops.rmdir(...args)); + mnt.node_ops.symlink = (...args) => (IDBFS.queuePersist(mnt.mount), memfs_node_ops.symlink(...args)); + mnt.node_ops.unlink = (...args) => (IDBFS.queuePersist(mnt.mount), memfs_node_ops.unlink(...args)); + mnt.node_ops.rename = (...args) => (IDBFS.queuePersist(mnt.mount), memfs_node_ops.rename(...args)); + } + return mnt; + }, + syncfs:(mount, populate, callback) => { + IDBFS.getLocalSet(mount, (err, local) => { + if (err) return callback(err); + + IDBFS.getRemoteSet(mount, (err, remote) => { + if (err) return callback(err); + + var src = populate ? remote : local; + var dst = populate ? local : remote; + + IDBFS.reconcile(src, dst, callback); + }); + }); + }, + quit:() => { + Object.values(IDBFS.dbs).forEach((value) => value.close()); + IDBFS.dbs = {}; + }, + getDB:(name, callback) => { + // check the cache first + var db = IDBFS.dbs[name]; + if (db) { + return callback(null, db); + } + + var req; + try { + req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION); + } catch (e) { + return callback(e); + } + if (!req) { + return callback("Unable to connect to IndexedDB"); + } + req.onupgradeneeded = (e) => { + var db = /** @type {IDBDatabase} */ (e.target.result); + var transaction = e.target.transaction; + + var fileStore; + + if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) { + fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME); + } else { + fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME); + } + + if (!fileStore.indexNames.contains('timestamp')) { + fileStore.createIndex('timestamp', 'timestamp', { unique: false }); + } + }; + req.onsuccess = () => { + db = /** @type {IDBDatabase} */ (req.result); + + // add to the cache + IDBFS.dbs[name] = db; + callback(null, db); + }; + req.onerror = (e) => { + callback(e.target.error); + e.preventDefault(); + }; + }, + getLocalSet:(mount, callback) => { + var entries = {}; + + function isRealDir(p) { + return p !== '.' && p !== '..'; + }; + function toAbsolute(root) { + return (p) => PATH.join2(root, p); + }; + + var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint)); + + while (check.length) { + var path = check.pop(); + var stat; + + try { + stat = FS.stat(path); + } catch (e) { + return callback(e); + } + + if (FS.isDir(stat.mode)) { + check.push(...FS.readdir(path).filter(isRealDir).map(toAbsolute(path))); + } + + entries[path] = { 'timestamp': stat.mtime }; + } + + return callback(null, { type: 'local', entries: entries }); + }, + getRemoteSet:(mount, callback) => { + var entries = {}; + + IDBFS.getDB(mount.mountpoint, (err, db) => { + if (err) return callback(err); + + try { + var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly'); + transaction.onerror = (e) => { + callback(e.target.error); + e.preventDefault(); + }; + + var store = transaction.objectStore(IDBFS.DB_STORE_NAME); + var index = store.index('timestamp'); + + index.openKeyCursor().onsuccess = (event) => { + var cursor = event.target.result; + + if (!cursor) { + return callback(null, { type: 'remote', db, entries }); + } + + entries[cursor.primaryKey] = { 'timestamp': cursor.key }; + + cursor.continue(); + }; + } catch (e) { + return callback(e); + } + }); + }, + loadLocalEntry:(path, callback) => { + var stat, node; + + try { + var lookup = FS.lookupPath(path); + node = lookup.node; + stat = FS.stat(path); + } catch (e) { + return callback(e); + } + + if (FS.isDir(stat.mode)) { + return callback(null, { 'timestamp': stat.mtime, 'mode': stat.mode }); + } else if (FS.isFile(stat.mode)) { + // Performance consideration: storing a normal JavaScript array to a IndexedDB is much slower than storing a typed array. + // Therefore always convert the file contents to a typed array first before writing the data to IndexedDB. + node.contents = MEMFS.getFileDataAsTypedArray(node); + return callback(null, { 'timestamp': stat.mtime, 'mode': stat.mode, 'contents': node.contents }); + } else { + return callback(new Error('node type not supported')); + } + }, + storeLocalEntry:(path, entry, callback) => { + try { + if (FS.isDir(entry['mode'])) { + FS.mkdirTree(path, entry['mode']); + } else if (FS.isFile(entry['mode'])) { + FS.writeFile(path, entry['contents'], { canOwn: true }); + } else { + return callback(new Error('node type not supported')); + } + + FS.chmod(path, entry['mode']); + FS.utime(path, entry['timestamp'], entry['timestamp']); + } catch (e) { + return callback(e); + } + + callback(null); + }, + removeLocalEntry:(path, callback) => { + try { + var stat = FS.stat(path); + + if (FS.isDir(stat.mode)) { + FS.rmdir(path); + } else if (FS.isFile(stat.mode)) { + FS.unlink(path); + } + } catch (e) { + return callback(e); + } + + callback(null); + }, + loadRemoteEntry:(store, path, callback) => { + var req = store.get(path); + req.onsuccess = (event) => callback(null, event.target.result); + req.onerror = (e) => { + callback(e.target.error); + e.preventDefault(); + }; + }, + storeRemoteEntry:(store, path, entry, callback) => { + try { + var req = store.put(entry, path); + } catch (e) { + callback(e); + return; + } + req.onsuccess = (event) => callback(); + req.onerror = (e) => { + callback(e.target.error); + e.preventDefault(); + }; + }, + removeRemoteEntry:(store, path, callback) => { + var req = store.delete(path); + req.onsuccess = (event) => callback(); + req.onerror = (e) => { + callback(e.target.error); + e.preventDefault(); + }; + }, + reconcile:(src, dst, callback) => { + var total = 0; + + var create = []; + Object.keys(src.entries).forEach((key) => { + var e = src.entries[key]; + var e2 = dst.entries[key]; + if (!e2 || e['timestamp'].getTime() != e2['timestamp'].getTime()) { + create.push(key); + total++; + } + }); + + var remove = []; + Object.keys(dst.entries).forEach((key) => { + if (!src.entries[key]) { + remove.push(key); + total++; + } + }); + + if (!total) { + return callback(null); + } + + var errored = false; + var db = src.type === 'remote' ? src.db : dst.db; + var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite'); + var store = transaction.objectStore(IDBFS.DB_STORE_NAME); + + function done(err) { + if (err && !errored) { + errored = true; + return callback(err); + } + }; + + // transaction may abort if (for example) there is a QuotaExceededError + transaction.onerror = transaction.onabort = (e) => { + done(e.target.error); + e.preventDefault(); + }; + + transaction.oncomplete = (e) => { + if (!errored) { + callback(null); + } + }; + + // sort paths in ascending order so directory entries are created + // before the files inside them + create.sort().forEach((path) => { + if (dst.type === 'local') { + IDBFS.loadRemoteEntry(store, path, (err, entry) => { + if (err) return done(err); + IDBFS.storeLocalEntry(path, entry, done); + }); + } else { + IDBFS.loadLocalEntry(path, (err, entry) => { + if (err) return done(err); + IDBFS.storeRemoteEntry(store, path, entry, done); + }); + } + }); + + // sort paths in descending order so files are deleted before their + // parent directories + remove.sort().reverse().forEach((path) => { + if (dst.type === 'local') { + IDBFS.removeLocalEntry(path, done); + } else { + IDBFS.removeRemoteEntry(store, path, done); + } + }); + }, + }; + + + + /** + * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the + * emscripten HEAP, returns a copy of that string as a Javascript String object. + * + * @param {number} ptr + * @param {number=} maxBytesToRead - An optional length that specifies the + * maximum number of bytes to read. You can omit this parameter to scan the + * string until the first 0 byte. If maxBytesToRead is passed, and the string + * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the + * string will cut short at that byte index (i.e. maxBytesToRead will not + * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing + * frequent uses of UTF8ToString() with and without maxBytesToRead may throw + * JS JIT optimizations off, so it is worth to consider consistently using one + * @return {string} + */ + var UTF8ToString = (ptr, maxBytesToRead) => { + assert(typeof ptr == 'number', `UTF8ToString expects a number (got ${typeof ptr})`); + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; + }; + + var strError = (errno) => { + return UTF8ToString(_strerror(errno)); + }; + + var ERRNO_CODES = { + 'EPERM': 63, + 'ENOENT': 44, + 'ESRCH': 71, + 'EINTR': 27, + 'EIO': 29, + 'ENXIO': 60, + 'E2BIG': 1, + 'ENOEXEC': 45, + 'EBADF': 8, + 'ECHILD': 12, + 'EAGAIN': 6, + 'EWOULDBLOCK': 6, + 'ENOMEM': 48, + 'EACCES': 2, + 'EFAULT': 21, + 'ENOTBLK': 105, + 'EBUSY': 10, + 'EEXIST': 20, + 'EXDEV': 75, + 'ENODEV': 43, + 'ENOTDIR': 54, + 'EISDIR': 31, + 'EINVAL': 28, + 'ENFILE': 41, + 'EMFILE': 33, + 'ENOTTY': 59, + 'ETXTBSY': 74, + 'EFBIG': 22, + 'ENOSPC': 51, + 'ESPIPE': 70, + 'EROFS': 69, + 'EMLINK': 34, + 'EPIPE': 64, + 'EDOM': 18, + 'ERANGE': 68, + 'ENOMSG': 49, + 'EIDRM': 24, + 'ECHRNG': 106, + 'EL2NSYNC': 156, + 'EL3HLT': 107, + 'EL3RST': 108, + 'ELNRNG': 109, + 'EUNATCH': 110, + 'ENOCSI': 111, + 'EL2HLT': 112, + 'EDEADLK': 16, + 'ENOLCK': 46, + 'EBADE': 113, + 'EBADR': 114, + 'EXFULL': 115, + 'ENOANO': 104, + 'EBADRQC': 103, + 'EBADSLT': 102, + 'EDEADLOCK': 16, + 'EBFONT': 101, + 'ENOSTR': 100, + 'ENODATA': 116, + 'ETIME': 117, + 'ENOSR': 118, + 'ENONET': 119, + 'ENOPKG': 120, + 'EREMOTE': 121, + 'ENOLINK': 47, + 'EADV': 122, + 'ESRMNT': 123, + 'ECOMM': 124, + 'EPROTO': 65, + 'EMULTIHOP': 36, + 'EDOTDOT': 125, + 'EBADMSG': 9, + 'ENOTUNIQ': 126, + 'EBADFD': 127, + 'EREMCHG': 128, + 'ELIBACC': 129, + 'ELIBBAD': 130, + 'ELIBSCN': 131, + 'ELIBMAX': 132, + 'ELIBEXEC': 133, + 'ENOSYS': 52, + 'ENOTEMPTY': 55, + 'ENAMETOOLONG': 37, + 'ELOOP': 32, + 'EOPNOTSUPP': 138, + 'EPFNOSUPPORT': 139, + 'ECONNRESET': 15, + 'ENOBUFS': 42, + 'EAFNOSUPPORT': 5, + 'EPROTOTYPE': 67, + 'ENOTSOCK': 57, + 'ENOPROTOOPT': 50, + 'ESHUTDOWN': 140, + 'ECONNREFUSED': 14, + 'EADDRINUSE': 3, + 'ECONNABORTED': 13, + 'ENETUNREACH': 40, + 'ENETDOWN': 38, + 'ETIMEDOUT': 73, + 'EHOSTDOWN': 142, + 'EHOSTUNREACH': 23, + 'EINPROGRESS': 26, + 'EALREADY': 7, + 'EDESTADDRREQ': 17, + 'EMSGSIZE': 35, + 'EPROTONOSUPPORT': 66, + 'ESOCKTNOSUPPORT': 137, + 'EADDRNOTAVAIL': 4, + 'ENETRESET': 39, + 'EISCONN': 30, + 'ENOTCONN': 53, + 'ETOOMANYREFS': 141, + 'EUSERS': 136, + 'EDQUOT': 19, + 'ESTALE': 72, + 'ENOTSUP': 138, + 'ENOMEDIUM': 148, + 'EILSEQ': 25, + 'EOVERFLOW': 61, + 'ECANCELED': 11, + 'ENOTRECOVERABLE': 56, + 'EOWNERDEAD': 62, + 'ESTRPIPE': 135, + }; + var FS = { + root:null, + mounts:[], + devices:{ + }, + streams:[], + nextInode:1, + nameTable:null, + currentPath:"/", + initialized:false, + ignorePermissions:true, + ErrnoError:class extends Error { + // We set the `name` property to be able to identify `FS.ErrnoError` + // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway. + // - when using PROXYFS, an error can come from an underlying FS + // as different FS objects have their own FS.ErrnoError each, + // the test `err instanceof FS.ErrnoError` won't detect an error coming from another filesystem, causing bugs. + // we'll use the reliable test `err.name == "ErrnoError"` instead + constructor(errno) { + super(runtimeInitialized ? strError(errno) : ''); + // TODO(sbc): Use the inline member declaration syntax once we + // support it in acorn and closure. + this.name = 'ErrnoError'; + this.errno = errno; + for (var key in ERRNO_CODES) { + if (ERRNO_CODES[key] === errno) { + this.code = key; + break; + } + } + } + }, + genericErrors:{ + }, + filesystems:null, + syncFSRequests:0, + FSStream:class { + constructor() { + // TODO(https://github.com/emscripten-core/emscripten/issues/21414): + // Use inline field declarations. + this.shared = {}; + } + get object() { + return this.node; + } + set object(val) { + this.node = val; + } + get isRead() { + return (this.flags & 2097155) !== 1; + } + get isWrite() { + return (this.flags & 2097155) !== 0; + } + get isAppend() { + return (this.flags & 1024); + } + get flags() { + return this.shared.flags; + } + set flags(val) { + this.shared.flags = val; + } + get position() { + return this.shared.position; + } + set position(val) { + this.shared.position = val; + } + }, + FSNode:class { + constructor(parent, name, mode, rdev) { + if (!parent) { + parent = this; // root node sets parent to itself + } + this.parent = parent; + this.mount = parent.mount; + this.mounted = null; + this.id = FS.nextInode++; + this.name = name; + this.mode = mode; + this.node_ops = {}; + this.stream_ops = {}; + this.rdev = rdev; + this.readMode = 292 | 73; + this.writeMode = 146; + } + get read() { + return (this.mode & this.readMode) === this.readMode; + } + set read(val) { + val ? this.mode |= this.readMode : this.mode &= ~this.readMode; + } + get write() { + return (this.mode & this.writeMode) === this.writeMode; + } + set write(val) { + val ? this.mode |= this.writeMode : this.mode &= ~this.writeMode; + } + get isFolder() { + return FS.isDir(this.mode); + } + get isDevice() { + return FS.isChrdev(this.mode); + } + }, + lookupPath(path, opts = {}) { + path = PATH_FS.resolve(path); + + if (!path) return { path: '', node: null }; + + var defaults = { + follow_mount: true, + recurse_count: 0 + }; + opts = Object.assign(defaults, opts) + + if (opts.recurse_count > 8) { // max recursive lookup of 8 + throw new FS.ErrnoError(32); + } + + // split the absolute path + var parts = path.split('/').filter((p) => !!p); + + // start at the root + var current = FS.root; + var current_path = '/'; + + for (var i = 0; i < parts.length; i++) { + var islast = (i === parts.length-1); + if (islast && opts.parent) { + // stop resolving + break; + } + + current = FS.lookupNode(current, parts[i]); + current_path = PATH.join2(current_path, parts[i]); + + // jump to the mount's root node if this is a mountpoint + if (FS.isMountpoint(current)) { + if (!islast || (islast && opts.follow_mount)) { + current = current.mounted.root; + } + } + + // by default, lookupPath will not follow a symlink if it is the final path component. + // setting opts.follow = true will override this behavior. + if (!islast || opts.follow) { + var count = 0; + while (FS.isLink(current.mode)) { + var link = FS.readlink(current_path); + current_path = PATH_FS.resolve(PATH.dirname(current_path), link); + + var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count + 1 }); + current = lookup.node; + + if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX). + throw new FS.ErrnoError(32); + } + } + } + } + + return { path: current_path, node: current }; + }, + getPath(node) { + var path; + while (true) { + if (FS.isRoot(node)) { + var mount = node.mount.mountpoint; + if (!path) return mount; + return mount[mount.length-1] !== '/' ? `${mount}/${path}` : mount + path; + } + path = path ? `${node.name}/${path}` : node.name; + node = node.parent; + } + }, + hashName(parentid, name) { + var hash = 0; + + for (var i = 0; i < name.length; i++) { + hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; + } + return ((parentid + hash) >>> 0) % FS.nameTable.length; + }, + hashAddNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + node.name_next = FS.nameTable[hash]; + FS.nameTable[hash] = node; + }, + hashRemoveNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + if (FS.nameTable[hash] === node) { + FS.nameTable[hash] = node.name_next; + } else { + var current = FS.nameTable[hash]; + while (current) { + if (current.name_next === node) { + current.name_next = node.name_next; + break; + } + current = current.name_next; + } + } + }, + lookupNode(parent, name) { + var errCode = FS.mayLookup(parent); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + var hash = FS.hashName(parent.id, name); + for (var node = FS.nameTable[hash]; node; node = node.name_next) { + var nodeName = node.name; + if (node.parent.id === parent.id && nodeName === name) { + return node; + } + } + // if we failed to find it in the cache, call into the VFS + return FS.lookup(parent, name); + }, + createNode(parent, name, mode, rdev) { + assert(typeof parent == 'object') + var node = new FS.FSNode(parent, name, mode, rdev); + + FS.hashAddNode(node); + + return node; + }, + destroyNode(node) { + FS.hashRemoveNode(node); + }, + isRoot(node) { + return node === node.parent; + }, + isMountpoint(node) { + return !!node.mounted; + }, + isFile(mode) { + return (mode & 61440) === 32768; + }, + isDir(mode) { + return (mode & 61440) === 16384; + }, + isLink(mode) { + return (mode & 61440) === 40960; + }, + isChrdev(mode) { + return (mode & 61440) === 8192; + }, + isBlkdev(mode) { + return (mode & 61440) === 24576; + }, + isFIFO(mode) { + return (mode & 61440) === 4096; + }, + isSocket(mode) { + return (mode & 49152) === 49152; + }, + flagsToPermissionString(flag) { + var perms = ['r', 'w', 'rw'][flag & 3]; + if ((flag & 512)) { + perms += 'w'; + } + return perms; + }, + nodePermissions(node, perms) { + if (FS.ignorePermissions) { + return 0; + } + // return 0 if any user, group or owner bits are set. + if (perms.includes('r') && !(node.mode & 292)) { + return 2; + } else if (perms.includes('w') && !(node.mode & 146)) { + return 2; + } else if (perms.includes('x') && !(node.mode & 73)) { + return 2; + } + return 0; + }, + mayLookup(dir) { + if (!FS.isDir(dir.mode)) return 54; + var errCode = FS.nodePermissions(dir, 'x'); + if (errCode) return errCode; + if (!dir.node_ops.lookup) return 2; + return 0; + }, + mayCreate(dir, name) { + try { + var node = FS.lookupNode(dir, name); + return 20; + } catch (e) { + } + return FS.nodePermissions(dir, 'wx'); + }, + mayDelete(dir, name, isdir) { + var node; + try { + node = FS.lookupNode(dir, name); + } catch (e) { + return e.errno; + } + var errCode = FS.nodePermissions(dir, 'wx'); + if (errCode) { + return errCode; + } + if (isdir) { + if (!FS.isDir(node.mode)) { + return 54; + } + if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { + return 10; + } + } else { + if (FS.isDir(node.mode)) { + return 31; + } + } + return 0; + }, + mayOpen(node, flags) { + if (!node) { + return 44; + } + if (FS.isLink(node.mode)) { + return 32; + } else if (FS.isDir(node.mode)) { + if (FS.flagsToPermissionString(flags) !== 'r' || // opening for write + (flags & 512)) { // TODO: check for O_SEARCH? (== search for dir only) + return 31; + } + } + return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); + }, + MAX_OPEN_FDS:4096, + nextfd() { + for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { + if (!FS.streams[fd]) { + return fd; + } + } + throw new FS.ErrnoError(33); + }, + getStreamChecked(fd) { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + return stream; + }, + getStream:(fd) => FS.streams[fd], + createStream(stream, fd = -1) { + assert(fd >= -1); + + // clone it, so we can return an instance of FSStream + stream = Object.assign(new FS.FSStream(), stream); + if (fd == -1) { + fd = FS.nextfd(); + } + stream.fd = fd; + FS.streams[fd] = stream; + return stream; + }, + closeStream(fd) { + FS.streams[fd] = null; + }, + dupStream(origStream, fd = -1) { + var stream = FS.createStream(origStream, fd); + stream.stream_ops?.dup?.(stream); + return stream; + }, + chrdev_stream_ops:{ + open(stream) { + var device = FS.getDevice(stream.node.rdev); + // override node's stream ops with the device's + stream.stream_ops = device.stream_ops; + // forward the open call + stream.stream_ops.open?.(stream); + }, + llseek() { + throw new FS.ErrnoError(70); + }, + }, + major:(dev) => ((dev) >> 8), + minor:(dev) => ((dev) & 0xff), + makedev:(ma, mi) => ((ma) << 8 | (mi)), + registerDevice(dev, ops) { + FS.devices[dev] = { stream_ops: ops }; + }, + getDevice:(dev) => FS.devices[dev], + getMounts(mount) { + var mounts = []; + var check = [mount]; + + while (check.length) { + var m = check.pop(); + + mounts.push(m); + + check.push(...m.mounts); + } + + return mounts; + }, + syncfs(populate, callback) { + if (typeof populate == 'function') { + callback = populate; + populate = false; + } + + FS.syncFSRequests++; + + if (FS.syncFSRequests > 1) { + err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`); + } + + var mounts = FS.getMounts(FS.root.mount); + var completed = 0; + + function doCallback(errCode) { + assert(FS.syncFSRequests > 0); + FS.syncFSRequests--; + return callback(errCode); + } + + function done(errCode) { + if (errCode) { + if (!done.errored) { + done.errored = true; + return doCallback(errCode); + } + return; + } + if (++completed >= mounts.length) { + doCallback(null); + } + }; + + // sync all mounts + mounts.forEach((mount) => { + if (!mount.type.syncfs) { + return done(null); + } + mount.type.syncfs(mount, populate, done); + }); + }, + mount(type, opts, mountpoint) { + if (typeof type == 'string') { + // The filesystem was not included, and instead we have an error + // message stored in the variable. + throw type; + } + var root = mountpoint === '/'; + var pseudo = !mountpoint; + var node; + + if (root && FS.root) { + throw new FS.ErrnoError(10); + } else if (!root && !pseudo) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + + mountpoint = lookup.path; // use the absolute path + node = lookup.node; + + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + + if (!FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + } + + var mount = { + type, + opts, + mountpoint, + mounts: [] + }; + + // create a root node for the fs + var mountRoot = type.mount(mount); + mountRoot.mount = mount; + mount.root = mountRoot; + + if (root) { + FS.root = mountRoot; + } else if (node) { + // set as a mountpoint + node.mounted = mount; + + // add the new mount to the current mount's children + if (node.mount) { + node.mount.mounts.push(mount); + } + } + + return mountRoot; + }, + unmount(mountpoint) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + + if (!FS.isMountpoint(lookup.node)) { + throw new FS.ErrnoError(28); + } + + // destroy the nodes for this mount, and all its child mounts + var node = lookup.node; + var mount = node.mounted; + var mounts = FS.getMounts(mount); + + Object.keys(FS.nameTable).forEach((hash) => { + var current = FS.nameTable[hash]; + + while (current) { + var next = current.name_next; + + if (mounts.includes(current.mount)) { + FS.destroyNode(current); + } + + current = next; + } + }); + + // no longer a mountpoint + node.mounted = null; + + // remove this mount from the child mounts + var idx = node.mount.mounts.indexOf(mount); + assert(idx !== -1); + node.mount.mounts.splice(idx, 1); + }, + lookup(parent, name) { + return parent.node_ops.lookup(parent, name); + }, + mknod(path, mode, dev) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name = PATH.basename(path); + if (!name || name === '.' || name === '..') { + throw new FS.ErrnoError(28); + } + var errCode = FS.mayCreate(parent, name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.mknod) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.mknod(parent, name, mode, dev); + }, + create(path, mode) { + mode = mode !== undefined ? mode : 438 /* 0666 */; + mode &= 4095; + mode |= 32768; + return FS.mknod(path, mode, 0); + }, + mkdir(path, mode) { + mode = mode !== undefined ? mode : 511 /* 0777 */; + mode &= 511 | 512; + mode |= 16384; + return FS.mknod(path, mode, 0); + }, + mkdirTree(path, mode) { + var dirs = path.split('/'); + var d = ''; + for (var i = 0; i < dirs.length; ++i) { + if (!dirs[i]) continue; + d += '/' + dirs[i]; + try { + FS.mkdir(d, mode); + } catch(e) { + if (e.errno != 20) throw e; + } + } + }, + mkdev(path, mode, dev) { + if (typeof dev == 'undefined') { + dev = mode; + mode = 438 /* 0666 */; + } + mode |= 8192; + return FS.mknod(path, mode, dev); + }, + symlink(oldpath, newpath) { + if (!PATH_FS.resolve(oldpath)) { + throw new FS.ErrnoError(44); + } + var lookup = FS.lookupPath(newpath, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var newname = PATH.basename(newpath); + var errCode = FS.mayCreate(parent, newname); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.symlink) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.symlink(parent, newname, oldpath); + }, + rename(old_path, new_path) { + var old_dirname = PATH.dirname(old_path); + var new_dirname = PATH.dirname(new_path); + var old_name = PATH.basename(old_path); + var new_name = PATH.basename(new_path); + // parents must exist + var lookup, old_dir, new_dir; + + // let the errors from non existent directories percolate up + lookup = FS.lookupPath(old_path, { parent: true }); + old_dir = lookup.node; + lookup = FS.lookupPath(new_path, { parent: true }); + new_dir = lookup.node; + + if (!old_dir || !new_dir) throw new FS.ErrnoError(44); + // need to be part of the same mount + if (old_dir.mount !== new_dir.mount) { + throw new FS.ErrnoError(75); + } + // source must exist + var old_node = FS.lookupNode(old_dir, old_name); + // old path should not be an ancestor of the new path + var relative = PATH_FS.relative(old_path, new_dirname); + if (relative.charAt(0) !== '.') { + throw new FS.ErrnoError(28); + } + // new path should not be an ancestor of the old path + relative = PATH_FS.relative(new_path, old_dirname); + if (relative.charAt(0) !== '.') { + throw new FS.ErrnoError(55); + } + // see if the new path already exists + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) { + // not fatal + } + // early out if nothing needs to change + if (old_node === new_node) { + return; + } + // we'll need to delete the old entry + var isdir = FS.isDir(old_node.mode); + var errCode = FS.mayDelete(old_dir, old_name, isdir); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + // need delete permissions if we'll be overwriting. + // need create permissions if new doesn't already exist. + errCode = new_node ? + FS.mayDelete(new_dir, new_name, isdir) : + FS.mayCreate(new_dir, new_name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!old_dir.node_ops.rename) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) { + throw new FS.ErrnoError(10); + } + // if we are going to change the parent, check write permissions + if (new_dir !== old_dir) { + errCode = FS.nodePermissions(old_dir, 'w'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + // remove the node from the lookup hash + FS.hashRemoveNode(old_node); + // do the underlying fs rename + try { + old_dir.node_ops.rename(old_node, new_dir, new_name); + // update old node (we do this here to avoid each backend + // needing to) + old_node.parent = new_dir; + } catch (e) { + throw e; + } finally { + // add the node back to the hash (in case node_ops.rename + // changed its name) + FS.hashAddNode(old_node); + } + }, + rmdir(path) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, true); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.rmdir) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.rmdir(parent, name); + FS.destroyNode(node); + }, + readdir(path) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + if (!node.node_ops.readdir) { + throw new FS.ErrnoError(54); + } + return node.node_ops.readdir(node); + }, + unlink(path) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, false); + if (errCode) { + // According to POSIX, we should map EISDIR to EPERM, but + // we instead do what Linux does (and we must, as we use + // the musl linux libc). + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.unlink) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.unlink(parent, name); + FS.destroyNode(node); + }, + readlink(path) { + var lookup = FS.lookupPath(path); + var link = lookup.node; + if (!link) { + throw new FS.ErrnoError(44); + } + if (!link.node_ops.readlink) { + throw new FS.ErrnoError(28); + } + return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link)); + }, + stat(path, dontFollow) { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + var node = lookup.node; + if (!node) { + throw new FS.ErrnoError(44); + } + if (!node.node_ops.getattr) { + throw new FS.ErrnoError(63); + } + return node.node_ops.getattr(node); + }, + lstat(path) { + return FS.stat(path, true); + }, + chmod(path, mode, dontFollow) { + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + node.node_ops.setattr(node, { + mode: (mode & 4095) | (node.mode & ~4095), + timestamp: Date.now() + }); + }, + lchmod(path, mode) { + FS.chmod(path, mode, true); + }, + fchmod(fd, mode) { + var stream = FS.getStreamChecked(fd); + FS.chmod(stream.node, mode); + }, + chown(path, uid, gid, dontFollow) { + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + node.node_ops.setattr(node, { + timestamp: Date.now() + // we ignore the uid / gid for now + }); + }, + lchown(path, uid, gid) { + FS.chown(path, uid, gid, true); + }, + fchown(fd, uid, gid) { + var stream = FS.getStreamChecked(fd); + FS.chown(stream.node, uid, gid); + }, + truncate(path, len) { + if (len < 0) { + throw new FS.ErrnoError(28); + } + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: true }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + if (FS.isDir(node.mode)) { + throw new FS.ErrnoError(31); + } + if (!FS.isFile(node.mode)) { + throw new FS.ErrnoError(28); + } + var errCode = FS.nodePermissions(node, 'w'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + node.node_ops.setattr(node, { + size: len, + timestamp: Date.now() + }); + }, + ftruncate(fd, len) { + var stream = FS.getStreamChecked(fd); + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(28); + } + FS.truncate(stream.node, len); + }, + utime(path, atime, mtime) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + node.node_ops.setattr(node, { + timestamp: Math.max(atime, mtime) + }); + }, + open(path, flags, mode) { + if (path === "") { + throw new FS.ErrnoError(44); + } + flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; + if ((flags & 64)) { + mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; + mode = (mode & 4095) | 32768; + } else { + mode = 0; + } + var node; + if (typeof path == 'object') { + node = path; + } else { + path = PATH.normalize(path); + try { + var lookup = FS.lookupPath(path, { + follow: !(flags & 131072) + }); + node = lookup.node; + } catch (e) { + // ignore + } + } + // perhaps we need to create the node + var created = false; + if ((flags & 64)) { + if (node) { + // if O_CREAT and O_EXCL are set, error out if the node already exists + if ((flags & 128)) { + throw new FS.ErrnoError(20); + } + } else { + // node doesn't exist, try to create it + node = FS.mknod(path, mode, 0); + created = true; + } + } + if (!node) { + throw new FS.ErrnoError(44); + } + // can't truncate a device + if (FS.isChrdev(node.mode)) { + flags &= ~512; + } + // if asked only for a directory, then this must be one + if ((flags & 65536) && !FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + // check permissions, if this is not a file we just created now (it is ok to + // create and write to a file with read-only permissions; it is read-only + // for later use) + if (!created) { + var errCode = FS.mayOpen(node, flags); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + // do truncation if necessary + if ((flags & 512) && !created) { + FS.truncate(node, 0); + } + // we've already handled these, don't pass down to the underlying vfs + flags &= ~(128 | 512 | 131072); + + // register the stream with the filesystem + var stream = FS.createStream({ + node, + path: FS.getPath(node), // we want the absolute path to the node + flags, + seekable: true, + position: 0, + stream_ops: node.stream_ops, + // used by the file family libc calls (fopen, fwrite, ferror, etc.) + ungotten: [], + error: false + }); + // call the new stream's open function + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + if (Module['logReadFiles'] && !(flags & 1)) { + if (!FS.readFiles) FS.readFiles = {}; + if (!(path in FS.readFiles)) { + FS.readFiles[path] = 1; + } + } + return stream; + }, + close(stream) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (stream.getdents) stream.getdents = null; // free readdir state + try { + if (stream.stream_ops.close) { + stream.stream_ops.close(stream); + } + } catch (e) { + throw e; + } finally { + FS.closeStream(stream.fd); + } + stream.fd = null; + }, + isClosed(stream) { + return stream.fd === null; + }, + llseek(stream, offset, whence) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (!stream.seekable || !stream.stream_ops.llseek) { + throw new FS.ErrnoError(70); + } + if (whence != 0 && whence != 1 && whence != 2) { + throw new FS.ErrnoError(28); + } + stream.position = stream.stream_ops.llseek(stream, offset, whence); + stream.ungotten = []; + return stream.position; + }, + read(stream, buffer, offset, length, position) { + assert(offset >= 0); + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.read) { + throw new FS.ErrnoError(28); + } + var seeking = typeof position != 'undefined'; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position); + if (!seeking) stream.position += bytesRead; + return bytesRead; + }, + write(stream, buffer, offset, length, position, canOwn) { + assert(offset >= 0); + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.write) { + throw new FS.ErrnoError(28); + } + if (stream.seekable && stream.flags & 1024) { + // seek to the end before writing in append mode + FS.llseek(stream, 0, 2); + } + var seeking = typeof position != 'undefined'; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); + if (!seeking) stream.position += bytesWritten; + return bytesWritten; + }, + allocate(stream, offset, length) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (offset < 0 || length <= 0) { + throw new FS.ErrnoError(28); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (!stream.stream_ops.allocate) { + throw new FS.ErrnoError(138); + } + stream.stream_ops.allocate(stream, offset, length); + }, + mmap(stream, length, position, prot, flags) { + // User requests writing to file (prot & PROT_WRITE != 0). + // Checking if we have permissions to write to the file unless + // MAP_PRIVATE flag is set. According to POSIX spec it is possible + // to write to file opened in read-only mode with MAP_PRIVATE flag, + // as all modifications will be visible only in the memory of + // the current process. + if ((prot & 2) !== 0 + && (flags & 2) === 0 + && (stream.flags & 2097155) !== 2) { + throw new FS.ErrnoError(2); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(2); + } + if (!stream.stream_ops.mmap) { + throw new FS.ErrnoError(43); + } + if (!length) { + throw new FS.ErrnoError(28); + } + return stream.stream_ops.mmap(stream, length, position, prot, flags); + }, + msync(stream, buffer, offset, length, mmapFlags) { + assert(offset >= 0); + if (!stream.stream_ops.msync) { + return 0; + } + return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags); + }, + ioctl(stream, cmd, arg) { + if (!stream.stream_ops.ioctl) { + throw new FS.ErrnoError(59); + } + return stream.stream_ops.ioctl(stream, cmd, arg); + }, + readFile(path, opts = {}) { + opts.flags = opts.flags || 0; + opts.encoding = opts.encoding || 'binary'; + if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { + throw new Error(`Invalid encoding type "${opts.encoding}"`); + } + var ret; + var stream = FS.open(path, opts.flags); + var stat = FS.stat(path); + var length = stat.size; + var buf = new Uint8Array(length); + FS.read(stream, buf, 0, length, 0); + if (opts.encoding === 'utf8') { + ret = UTF8ArrayToString(buf, 0); + } else if (opts.encoding === 'binary') { + ret = buf; + } + FS.close(stream); + return ret; + }, + writeFile(path, data, opts = {}) { + opts.flags = opts.flags || 577; + var stream = FS.open(path, opts.flags, opts.mode); + if (typeof data == 'string') { + var buf = new Uint8Array(lengthBytesUTF8(data)+1); + var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); + FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn); + } else if (ArrayBuffer.isView(data)) { + FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); + } else { + throw new Error('Unsupported data type'); + } + FS.close(stream); + }, + cwd:() => FS.currentPath, + chdir(path) { + var lookup = FS.lookupPath(path, { follow: true }); + if (lookup.node === null) { + throw new FS.ErrnoError(44); + } + if (!FS.isDir(lookup.node.mode)) { + throw new FS.ErrnoError(54); + } + var errCode = FS.nodePermissions(lookup.node, 'x'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.currentPath = lookup.path; + }, + createDefaultDirectories() { + FS.mkdir('/tmp'); + FS.mkdir('/home'); + FS.mkdir('/home/web_user'); + }, + createDefaultDevices() { + // create /dev + FS.mkdir('/dev'); + // setup /dev/null + FS.registerDevice(FS.makedev(1, 3), { + read: () => 0, + write: (stream, buffer, offset, length, pos) => length, + }); + FS.mkdev('/dev/null', FS.makedev(1, 3)); + // setup /dev/tty and /dev/tty1 + // stderr needs to print output using err() rather than out() + // so we register a second tty just for it. + TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); + TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); + FS.mkdev('/dev/tty', FS.makedev(5, 0)); + FS.mkdev('/dev/tty1', FS.makedev(6, 0)); + // setup /dev/[u]random + // use a buffer to avoid overhead of individual crypto calls per byte + var randomBuffer = new Uint8Array(1024), randomLeft = 0; + var randomByte = () => { + if (randomLeft === 0) { + randomLeft = randomFill(randomBuffer).byteLength; + } + return randomBuffer[--randomLeft]; + }; + FS.createDevice('/dev', 'random', randomByte); + FS.createDevice('/dev', 'urandom', randomByte); + // we're not going to emulate the actual shm device, + // just create the tmp dirs that reside in it commonly + FS.mkdir('/dev/shm'); + FS.mkdir('/dev/shm/tmp'); + }, + createSpecialDirectories() { + // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the + // name of the stream for fd 6 (see test_unistd_ttyname) + FS.mkdir('/proc'); + var proc_self = FS.mkdir('/proc/self'); + FS.mkdir('/proc/self/fd'); + FS.mount({ + mount() { + var node = FS.createNode(proc_self, 'fd', 16384 | 511 /* 0777 */, 73); + node.node_ops = { + lookup(parent, name) { + var fd = +name; + var stream = FS.getStreamChecked(fd); + var ret = { + parent: null, + mount: { mountpoint: 'fake' }, + node_ops: { readlink: () => stream.path }, + }; + ret.parent = ret; // make it look like a simple root node + return ret; + } + }; + return node; + } + }, {}, '/proc/self/fd'); + }, + createStandardStreams(input, output, error) { + // TODO deprecate the old functionality of a single + // input / output callback and that utilizes FS.createDevice + // and instead require a unique set of stream ops + + // by default, we symlink the standard streams to the + // default tty devices. however, if the standard streams + // have been overwritten we create a unique device for + // them instead. + if (input) { + FS.createDevice('/dev', 'stdin', input); + } else { + FS.symlink('/dev/tty', '/dev/stdin'); + } + if (output) { + FS.createDevice('/dev', 'stdout', null, output); + } else { + FS.symlink('/dev/tty', '/dev/stdout'); + } + if (error) { + FS.createDevice('/dev', 'stderr', null, error); + } else { + FS.symlink('/dev/tty1', '/dev/stderr'); + } + + // open default streams for the stdin, stdout and stderr devices + var stdin = FS.open('/dev/stdin', 0); + var stdout = FS.open('/dev/stdout', 1); + var stderr = FS.open('/dev/stderr', 1); + assert(stdin.fd === 0, `invalid handle for stdin (${stdin.fd})`); + assert(stdout.fd === 1, `invalid handle for stdout (${stdout.fd})`); + assert(stderr.fd === 2, `invalid handle for stderr (${stderr.fd})`); + }, + staticInit() { + // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info) + [44].forEach((code) => { + FS.genericErrors[code] = new FS.ErrnoError(code); + FS.genericErrors[code].stack = ''; + }); + + FS.nameTable = new Array(4096); + + FS.mount(MEMFS, {}, '/'); + + FS.createDefaultDirectories(); + FS.createDefaultDevices(); + FS.createSpecialDirectories(); + + FS.filesystems = { + 'MEMFS': MEMFS, + 'IDBFS': IDBFS, + }; + }, + init(input, output, error) { + assert(!FS.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'); + FS.initialized = true; + + // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here + input ??= Module['stdin']; + output ??= Module['stdout']; + error ??= Module['stderr']; + + FS.createStandardStreams(input, output, error); + }, + quit() { + FS.initialized = false; + // force-flush all streams, so we get musl std streams printed out + _fflush(0); + // close all of our streams + for (var i = 0; i < FS.streams.length; i++) { + var stream = FS.streams[i]; + if (!stream) { + continue; + } + FS.close(stream); + } + }, + findObject(path, dontResolveLastLink) { + var ret = FS.analyzePath(path, dontResolveLastLink); + if (!ret.exists) { + return null; + } + return ret.object; + }, + analyzePath(path, dontResolveLastLink) { + // operate from within the context of the symlink's target + try { + var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + path = lookup.path; + } catch (e) { + } + var ret = { + isRoot: false, exists: false, error: 0, name: null, path: null, object: null, + parentExists: false, parentPath: null, parentObject: null + }; + try { + var lookup = FS.lookupPath(path, { parent: true }); + ret.parentExists = true; + ret.parentPath = lookup.path; + ret.parentObject = lookup.node; + ret.name = PATH.basename(path); + lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + ret.exists = true; + ret.path = lookup.path; + ret.object = lookup.node; + ret.name = lookup.node.name; + ret.isRoot = lookup.path === '/'; + } catch (e) { + ret.error = e.errno; + }; + return ret; + }, + createPath(parent, path, canRead, canWrite) { + parent = typeof parent == 'string' ? parent : FS.getPath(parent); + var parts = path.split('/').reverse(); + while (parts.length) { + var part = parts.pop(); + if (!part) continue; + var current = PATH.join2(parent, part); + try { + FS.mkdir(current); + } catch (e) { + // ignore EEXIST + } + parent = current; + } + return current; + }, + createFile(parent, name, properties, canRead, canWrite) { + var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); + var mode = FS_getMode(canRead, canWrite); + return FS.create(path, mode); + }, + createDataFile(parent, name, data, canRead, canWrite, canOwn) { + var path = name; + if (parent) { + parent = typeof parent == 'string' ? parent : FS.getPath(parent); + path = name ? PATH.join2(parent, name) : parent; + } + var mode = FS_getMode(canRead, canWrite); + var node = FS.create(path, mode); + if (data) { + if (typeof data == 'string') { + var arr = new Array(data.length); + for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); + data = arr; + } + // make sure we can write to the file + FS.chmod(node, mode | 146); + var stream = FS.open(node, 577); + FS.write(stream, data, 0, data.length, 0, canOwn); + FS.close(stream); + FS.chmod(node, mode); + } + }, + createDevice(parent, name, input, output) { + var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); + var mode = FS_getMode(!!input, !!output); + if (!FS.createDevice.major) FS.createDevice.major = 64; + var dev = FS.makedev(FS.createDevice.major++, 0); + // Create a fake device that a set of stream ops to emulate + // the old behavior. + FS.registerDevice(dev, { + open(stream) { + stream.seekable = false; + }, + close(stream) { + // flush any pending line data + if (output?.buffer?.length) { + output(10); + } + }, + read(stream, buffer, offset, length, pos /* ignored */) { + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = input(); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset+i] = result; + } + if (bytesRead) { + stream.node.timestamp = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + for (var i = 0; i < length; i++) { + try { + output(buffer[offset+i]); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + if (length) { + stream.node.timestamp = Date.now(); + } + return i; + } + }); + return FS.mkdev(path, mode, dev); + }, + forceLoadFile(obj) { + if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; + if (typeof XMLHttpRequest != 'undefined') { + throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); + } else { // Command-line. + try { + obj.contents = readBinary(obj.url); + obj.usedBytes = obj.contents.length; + } catch (e) { + throw new FS.ErrnoError(29); + } + } + }, + createLazyFile(parent, name, url, canRead, canWrite) { + // Lazy chunked Uint8Array (implements get and length from Uint8Array). + // Actual getting is abstracted away for eventual reuse. + class LazyUint8Array { + constructor() { + this.lengthKnown = false; + this.chunks = []; // Loaded chunks. Index is the chunk number + } + get(idx) { + if (idx > this.length-1 || idx < 0) { + return undefined; + } + var chunkOffset = idx % this.chunkSize; + var chunkNum = (idx / this.chunkSize)|0; + return this.getter(chunkNum)[chunkOffset]; + } + setDataGetter(getter) { + this.getter = getter; + } + cacheLength() { + // Find length + var xhr = new XMLHttpRequest(); + xhr.open('HEAD', url, false); + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); + var datalength = Number(xhr.getResponseHeader("Content-length")); + var header; + var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; + var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip"; + + var chunkSize = 1024*1024; // Chunk size in bytes + + if (!hasByteServing) chunkSize = datalength; + + // Function to get a range from the remote URL. + var doXHR = (from, to) => { + if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!"); + if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!"); + + // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); + + // Some hints to the browser that we want binary data. + xhr.responseType = 'arraybuffer'; + if (xhr.overrideMimeType) { + xhr.overrideMimeType('text/plain; charset=x-user-defined'); + } + + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); + if (xhr.response !== undefined) { + return new Uint8Array(/** @type{Array} */(xhr.response || [])); + } + return intArrayFromString(xhr.responseText || '', true); + }; + var lazyArray = this; + lazyArray.setDataGetter((chunkNum) => { + var start = chunkNum * chunkSize; + var end = (chunkNum+1) * chunkSize - 1; // including this byte + end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block + if (typeof lazyArray.chunks[chunkNum] == 'undefined') { + lazyArray.chunks[chunkNum] = doXHR(start, end); + } + if (typeof lazyArray.chunks[chunkNum] == 'undefined') throw new Error('doXHR failed!'); + return lazyArray.chunks[chunkNum]; + }); + + if (usesGzip || !datalength) { + // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length + chunkSize = datalength = 1; // this will force getter(0)/doXHR do download the whole file + datalength = this.getter(0).length; + chunkSize = datalength; + out("LazyFiles on gzip forces download of the whole file when length is accessed"); + } + + this._length = datalength; + this._chunkSize = chunkSize; + this.lengthKnown = true; + } + get length() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._length; + } + get chunkSize() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._chunkSize; + } + } + + if (typeof XMLHttpRequest != 'undefined') { + if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; + var lazyArray = new LazyUint8Array(); + var properties = { isDevice: false, contents: lazyArray }; + } else { + var properties = { isDevice: false, url: url }; + } + + var node = FS.createFile(parent, name, properties, canRead, canWrite); + // This is a total hack, but I want to get this lazy file code out of the + // core of MEMFS. If we want to keep this lazy file concept I feel it should + // be its own thin LAZYFS proxying calls to MEMFS. + if (properties.contents) { + node.contents = properties.contents; + } else if (properties.url) { + node.contents = null; + node.url = properties.url; + } + // Add a function that defers querying the file size until it is asked the first time. + Object.defineProperties(node, { + usedBytes: { + get: function() { return this.contents.length; } + } + }); + // override each stream op with one that tries to force load the lazy file first + var stream_ops = {}; + var keys = Object.keys(node.stream_ops); + keys.forEach((key) => { + var fn = node.stream_ops[key]; + stream_ops[key] = (...args) => { + FS.forceLoadFile(node); + return fn(...args); + }; + }); + function writeChunks(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= contents.length) + return 0; + var size = Math.min(contents.length - position, length); + assert(size >= 0); + if (contents.slice) { // normal array + for (var i = 0; i < size; i++) { + buffer[offset + i] = contents[position + i]; + } + } else { + for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR + buffer[offset + i] = contents.get(position + i); + } + } + return size; + } + // use a custom read function + stream_ops.read = (stream, buffer, offset, length, position) => { + FS.forceLoadFile(node); + return writeChunks(stream, buffer, offset, length, position) + }; + // use a custom mmap function + stream_ops.mmap = (stream, length, position, prot, flags) => { + FS.forceLoadFile(node); + var ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + writeChunks(stream, HEAP8, ptr, length, position); + return { ptr, allocated: true }; + }; + node.stream_ops = stream_ops; + return node; + }, + absolutePath() { + abort('FS.absolutePath has been removed; use PATH_FS.resolve instead'); + }, + createFolder() { + abort('FS.createFolder has been removed; use FS.mkdir instead'); + }, + createLink() { + abort('FS.createLink has been removed; use FS.symlink instead'); + }, + joinPath() { + abort('FS.joinPath has been removed; use PATH.join instead'); + }, + mmapAlloc() { + abort('FS.mmapAlloc has been replaced by the top level function mmapAlloc'); + }, + standardizePath() { + abort('FS.standardizePath has been removed; use PATH.normalize instead'); + }, + }; + + var SYSCALLS = { + DEFAULT_POLLMASK:5, + calculateAt(dirfd, path, allowEmpty) { + if (PATH.isAbs(path)) { + return path; + } + // relative path + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = SYSCALLS.getStreamFromFD(dirfd); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44);; + } + return dir; + } + return PATH.join2(dir, path); + }, + doStat(func, path, buf) { + var stat = func(path); + HEAP32[((buf)>>2)] = stat.dev; + HEAP32[(((buf)+(4))>>2)] = stat.mode; + HEAPU32[(((buf)+(8))>>2)] = stat.nlink; + HEAP32[(((buf)+(12))>>2)] = stat.uid; + HEAP32[(((buf)+(16))>>2)] = stat.gid; + HEAP32[(((buf)+(20))>>2)] = stat.rdev; + (tempI64 = [stat.size>>>0,(tempDouble = stat.size,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(24))>>2)] = tempI64[0],HEAP32[(((buf)+(28))>>2)] = tempI64[1]); + HEAP32[(((buf)+(32))>>2)] = 4096; + HEAP32[(((buf)+(36))>>2)] = stat.blocks; + var atime = stat.atime.getTime(); + var mtime = stat.mtime.getTime(); + var ctime = stat.ctime.getTime(); + (tempI64 = [Math.floor(atime / 1000)>>>0,(tempDouble = Math.floor(atime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(40))>>2)] = tempI64[0],HEAP32[(((buf)+(44))>>2)] = tempI64[1]); + HEAPU32[(((buf)+(48))>>2)] = (atime % 1000) * 1000 * 1000; + (tempI64 = [Math.floor(mtime / 1000)>>>0,(tempDouble = Math.floor(mtime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(56))>>2)] = tempI64[0],HEAP32[(((buf)+(60))>>2)] = tempI64[1]); + HEAPU32[(((buf)+(64))>>2)] = (mtime % 1000) * 1000 * 1000; + (tempI64 = [Math.floor(ctime / 1000)>>>0,(tempDouble = Math.floor(ctime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(72))>>2)] = tempI64[0],HEAP32[(((buf)+(76))>>2)] = tempI64[1]); + HEAPU32[(((buf)+(80))>>2)] = (ctime % 1000) * 1000 * 1000; + (tempI64 = [stat.ino>>>0,(tempDouble = stat.ino,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(88))>>2)] = tempI64[0],HEAP32[(((buf)+(92))>>2)] = tempI64[1]); + return 0; + }, + doMsync(addr, stream, len, flags, offset) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (flags & 2) { + // MAP_PRIVATE calls need not to be synced back to underlying fs + return 0; + } + var buffer = HEAPU8.slice(addr, addr + len); + FS.msync(stream, buffer, offset, len, flags); + }, + getStreamFromFD(fd) { + var stream = FS.getStreamChecked(fd); + return stream; + }, + varargs:undefined, + getStr(ptr) { + var ret = UTF8ToString(ptr); + return ret; + }, + }; + function ___syscall_chdir(path) { + try { + + path = SYSCALLS.getStr(path); + FS.chdir(path); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + /** @suppress {duplicate } */ + function syscallGetVarargI() { + assert(SYSCALLS.varargs != undefined); + // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number. + var ret = HEAP32[((+SYSCALLS.varargs)>>2)]; + SYSCALLS.varargs += 4; + return ret; + } + var syscallGetVarargP = syscallGetVarargI; + + + function ___syscall_fcntl64(fd, cmd, varargs) { + SYSCALLS.varargs = varargs; + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + switch (cmd) { + case 0: { + var arg = syscallGetVarargI(); + if (arg < 0) { + return -28; + } + while (FS.streams[arg]) { + arg++; + } + var newStream; + newStream = FS.dupStream(stream, arg); + return newStream.fd; + } + case 1: + case 2: + return 0; // FD_CLOEXEC makes no sense for a single process. + case 3: + return stream.flags; + case 4: { + var arg = syscallGetVarargI(); + stream.flags |= arg; + return 0; + } + case 12: { + var arg = syscallGetVarargP(); + var offset = 0; + // We're always unlocked. + HEAP16[(((arg)+(offset))>>1)] = 2; + return 0; + } + case 13: + case 14: + return 0; // Pretend that the locking is successful. + } + return -28; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_fstat64(fd, buf) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + return SYSCALLS.doStat(FS.stat, stream.path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + + var stringToUTF8 = (str, outPtr, maxBytesToWrite) => { + assert(typeof maxBytesToWrite == 'number', 'stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); + return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + }; + function ___syscall_getcwd(buf, size) { + try { + + if (size === 0) return -28; + var cwd = FS.cwd(); + var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; + if (size < cwdLengthInBytes) return -68; + stringToUTF8(cwd, buf, size); + return cwdLengthInBytes; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + + function ___syscall_getdents64(fd, dirp, count) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd) + stream.getdents ||= FS.readdir(stream.path); + + var struct_size = 280; + var pos = 0; + var off = FS.llseek(stream, 0, 1); + + var idx = Math.floor(off / struct_size); + + while (idx < stream.getdents.length && pos + struct_size <= count) { + var id; + var type; + var name = stream.getdents[idx]; + if (name === '.') { + id = stream.node.id; + type = 4; // DT_DIR + } + else if (name === '..') { + var lookup = FS.lookupPath(stream.path, { parent: true }); + id = lookup.node.id; + type = 4; // DT_DIR + } + else { + var child = FS.lookupNode(stream.node, name); + id = child.id; + type = FS.isChrdev(child.mode) ? 2 : // DT_CHR, character device. + FS.isDir(child.mode) ? 4 : // DT_DIR, directory. + FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link. + 8; // DT_REG, regular file. + } + assert(id); + (tempI64 = [id>>>0,(tempDouble = id,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[((dirp + pos)>>2)] = tempI64[0],HEAP32[(((dirp + pos)+(4))>>2)] = tempI64[1]); + (tempI64 = [(idx + 1) * struct_size>>>0,(tempDouble = (idx + 1) * struct_size,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((dirp + pos)+(8))>>2)] = tempI64[0],HEAP32[(((dirp + pos)+(12))>>2)] = tempI64[1]); + HEAP16[(((dirp + pos)+(16))>>1)] = 280; + HEAP8[(dirp + pos)+(18)] = type; + stringToUTF8(name, dirp + pos + 19, 256); + pos += struct_size; + idx += 1; + } + FS.llseek(stream, idx * struct_size, 0); + return pos; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + + function ___syscall_ioctl(fd, op, varargs) { + SYSCALLS.varargs = varargs; + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + switch (op) { + case 21509: { + if (!stream.tty) return -59; + return 0; + } + case 21505: { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcgets) { + var termios = stream.tty.ops.ioctl_tcgets(stream); + var argp = syscallGetVarargP(); + HEAP32[((argp)>>2)] = termios.c_iflag || 0; + HEAP32[(((argp)+(4))>>2)] = termios.c_oflag || 0; + HEAP32[(((argp)+(8))>>2)] = termios.c_cflag || 0; + HEAP32[(((argp)+(12))>>2)] = termios.c_lflag || 0; + for (var i = 0; i < 32; i++) { + HEAP8[(argp + i)+(17)] = termios.c_cc[i] || 0; + } + return 0; + } + return 0; + } + case 21510: + case 21511: + case 21512: { + if (!stream.tty) return -59; + return 0; // no-op, not actually adjusting terminal settings + } + case 21506: + case 21507: + case 21508: { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcsets) { + var argp = syscallGetVarargP(); + var c_iflag = HEAP32[((argp)>>2)]; + var c_oflag = HEAP32[(((argp)+(4))>>2)]; + var c_cflag = HEAP32[(((argp)+(8))>>2)]; + var c_lflag = HEAP32[(((argp)+(12))>>2)]; + var c_cc = [] + for (var i = 0; i < 32; i++) { + c_cc.push(HEAP8[(argp + i)+(17)]); + } + return stream.tty.ops.ioctl_tcsets(stream.tty, op, { c_iflag, c_oflag, c_cflag, c_lflag, c_cc }); + } + return 0; // no-op, not actually adjusting terminal settings + } + case 21519: { + if (!stream.tty) return -59; + var argp = syscallGetVarargP(); + HEAP32[((argp)>>2)] = 0; + return 0; + } + case 21520: { + if (!stream.tty) return -59; + return -28; // not supported + } + case 21531: { + var argp = syscallGetVarargP(); + return FS.ioctl(stream, op, argp); + } + case 21523: { + // TODO: in theory we should write to the winsize struct that gets + // passed in, but for now musl doesn't read anything on it + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tiocgwinsz) { + var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty); + var argp = syscallGetVarargP(); + HEAP16[((argp)>>1)] = winsize[0]; + HEAP16[(((argp)+(2))>>1)] = winsize[1]; + } + return 0; + } + case 21524: { + // TODO: technically, this ioctl call should change the window size. + // but, since emscripten doesn't have any concept of a terminal window + // yet, we'll just silently throw it away as we do TIOCGWINSZ + if (!stream.tty) return -59; + return 0; + } + case 21515: { + if (!stream.tty) return -59; + return 0; + } + default: return -28; // not supported + } + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_lstat64(path, buf) { + try { + + path = SYSCALLS.getStr(path); + return SYSCALLS.doStat(FS.lstat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_mkdirat(dirfd, path, mode) { + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + // remove a trailing slash, if one - /a/b/ has basename of '', but + // we want to create b in the context of this function + path = PATH.normalize(path); + if (path[path.length-1] === '/') path = path.substr(0, path.length-1); + FS.mkdir(path, mode, 0); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_newfstatat(dirfd, path, buf, flags) { + try { + + path = SYSCALLS.getStr(path); + var nofollow = flags & 256; + var allowEmpty = flags & 4096; + flags = flags & (~6400); + assert(!flags, `unknown flags in __syscall_newfstatat: ${flags}`); + path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); + return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + + function ___syscall_openat(dirfd, path, flags, varargs) { + SYSCALLS.varargs = varargs; + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + var mode = varargs ? syscallGetVarargI() : 0; + return FS.open(path, flags, mode).fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_poll(fds, nfds, timeout) { + try { + + var nonzero = 0; + for (var i = 0; i < nfds; i++) { + var pollfd = fds + 8 * i; + var fd = HEAP32[((pollfd)>>2)]; + var events = HEAP16[(((pollfd)+(4))>>1)]; + var mask = 32; + var stream = FS.getStream(fd); + if (stream) { + mask = SYSCALLS.DEFAULT_POLLMASK; + if (stream.stream_ops.poll) { + mask = stream.stream_ops.poll(stream, -1); + } + } + mask &= events | 8 | 16; + if (mask) nonzero++; + HEAP16[(((pollfd)+(6))>>1)] = mask; + } + return nonzero; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_renameat(olddirfd, oldpath, newdirfd, newpath) { + try { + + oldpath = SYSCALLS.getStr(oldpath); + newpath = SYSCALLS.getStr(newpath); + oldpath = SYSCALLS.calculateAt(olddirfd, oldpath); + newpath = SYSCALLS.calculateAt(newdirfd, newpath); + FS.rename(oldpath, newpath); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_rmdir(path) { + try { + + path = SYSCALLS.getStr(path); + FS.rmdir(path); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_stat64(path, buf) { + try { + + path = SYSCALLS.getStr(path); + return SYSCALLS.doStat(FS.stat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_statfs64(path, size, buf) { + try { + + path = SYSCALLS.getStr(path); + assert(size === 64); + // NOTE: None of the constants here are true. We're just returning safe and + // sane values. + HEAP32[(((buf)+(4))>>2)] = 4096; + HEAP32[(((buf)+(40))>>2)] = 4096; + HEAP32[(((buf)+(8))>>2)] = 1000000; + HEAP32[(((buf)+(12))>>2)] = 500000; + HEAP32[(((buf)+(16))>>2)] = 500000; + HEAP32[(((buf)+(20))>>2)] = FS.nextInode; + HEAP32[(((buf)+(24))>>2)] = 1000000; + HEAP32[(((buf)+(28))>>2)] = 42; + HEAP32[(((buf)+(44))>>2)] = 2; // ST_NOSUID + HEAP32[(((buf)+(36))>>2)] = 255; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + function ___syscall_unlinkat(dirfd, path, flags) { + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (flags === 0) { + FS.unlink(path); + } else if (flags === 512) { + FS.rmdir(path); + } else { + abort('Invalid flags passed to unlinkat'); + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + var nowIsMonotonic = 1; + var __emscripten_get_now_is_monotonic = () => nowIsMonotonic; + + var __emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num); + + var __emscripten_throw_longjmp = () => { + throw Infinity; + }; + + var _emscripten_set_main_loop_timing = (mode, value) => { + Browser.mainLoop.timingMode = mode; + Browser.mainLoop.timingValue = value; + + if (!Browser.mainLoop.func) { + err('emscripten_set_main_loop_timing: Cannot set timing mode for main loop since a main loop does not exist! Call emscripten_set_main_loop first to set one up.'); + return 1; // Return non-zero on failure, can't set timing mode when there is no main loop. + } + + if (!Browser.mainLoop.running) { + + Browser.mainLoop.running = true; + } + if (mode == 0) { + Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_setTimeout() { + var timeUntilNextTick = Math.max(0, Browser.mainLoop.tickStartTime + value - _emscripten_get_now())|0; + setTimeout(Browser.mainLoop.runner, timeUntilNextTick); // doing this each time means that on exception, we stop + }; + Browser.mainLoop.method = 'timeout'; + } else if (mode == 1) { + Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_rAF() { + Browser.requestAnimationFrame(Browser.mainLoop.runner); + }; + Browser.mainLoop.method = 'rAF'; + } else if (mode == 2) { + if (typeof Browser.setImmediate == 'undefined') { + if (typeof setImmediate == 'undefined') { + // Emulate setImmediate. (note: not a complete polyfill, we don't emulate clearImmediate() to keep code size to minimum, since not needed) + var setImmediates = []; + var emscriptenMainLoopMessageId = 'setimmediate'; + /** @param {Event} event */ + var Browser_setImmediate_messageHandler = (event) => { + // When called in current thread or Worker, the main loop ID is structured slightly different to accommodate for --proxy-to-worker runtime listening to Worker events, + // so check for both cases. + if (event.data === emscriptenMainLoopMessageId || event.data.target === emscriptenMainLoopMessageId) { + event.stopPropagation(); + setImmediates.shift()(); + } + }; + addEventListener("message", Browser_setImmediate_messageHandler, true); + Browser.setImmediate = /** @type{function(function(): ?, ...?): number} */((func) => { + setImmediates.push(func); + if (ENVIRONMENT_IS_WORKER) { + Module['setImmediates'] ??= []; + Module['setImmediates'].push(func); + postMessage({target: emscriptenMainLoopMessageId}); // In --proxy-to-worker, route the message via proxyClient.js + } else postMessage(emscriptenMainLoopMessageId, "*"); // On the main thread, can just send the message to itself. + }); + } else { + Browser.setImmediate = setImmediate; + } + } + Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_setImmediate() { + Browser.setImmediate(Browser.mainLoop.runner); + }; + Browser.mainLoop.method = 'immediate'; + } + return 0; + }; + + var _emscripten_get_now; + // Modern environment where performance.now() is supported: + // N.B. a shorter form "_emscripten_get_now = performance.now;" is + // unfortunately not allowed even in current browsers (e.g. FF Nightly 75). + _emscripten_get_now = () => performance.now(); + ; + + + var runtimeKeepaliveCounter = 0; + var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; + var _proc_exit = (code) => { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + Module['onExit']?.(code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); + }; + + /** @suppress {duplicate } */ + /** @param {boolean|number=} implicit */ + var exitJS = (status, implicit) => { + EXITSTATUS = status; + + checkUnflushedContent(); + + // if exit() was called explicitly, warn the user if the runtime isn't actually being shut down + if (keepRuntimeAlive() && !implicit) { + var msg = `program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`; + readyPromiseReject(msg); + err(msg); + } + + _proc_exit(status); + }; + var _exit = exitJS; + + var handleException = (e) => { + // Certain exception types we do not treat as errors since they are used for + // internal control flow. + // 1. ExitStatus, which is thrown by exit() + // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others + // that wish to return to JS event loop. + if (e instanceof ExitStatus || e == 'unwind') { + return EXITSTATUS; + } + checkStackCookie(); + if (e instanceof WebAssembly.RuntimeError) { + if (_emscripten_stack_get_current() <= 0) { + err('Stack overflow detected. You can try increasing -sSTACK_SIZE (currently set to 67108864)'); + } + } + quit_(1, e); + }; + + var maybeExit = () => { + if (!keepRuntimeAlive()) { + try { + _exit(EXITSTATUS); + } catch (e) { + handleException(e); + } + } + }; + + + /** + * @param {number=} arg + * @param {boolean=} noSetTiming + */ + var setMainLoop = (browserIterationFunc, fps, simulateInfiniteLoop, arg, noSetTiming) => { + assert(!Browser.mainLoop.func, 'emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.'); + Browser.mainLoop.func = browserIterationFunc; + Browser.mainLoop.arg = arg; + + // Closure compiler bug(?): Closure does not see that the assignment + // var thisMainLoopId = Browser.mainLoop.currentlyRunningMainloop + // is a value copy of a number (even with the JSDoc @type annotation) + // but optimizeis the code as if the assignment was a reference assignment, + // which results in Browser.mainLoop.pause() not working. Hence use a + // workaround to make Closure believe this is a value copy that should occur: + // (TODO: Minimize this down to a small test case and report - was unable + // to reproduce in a small written test case) + /** @type{number} */ + var thisMainLoopId = (() => Browser.mainLoop.currentlyRunningMainloop)(); + function checkIsRunning() { + if (thisMainLoopId < Browser.mainLoop.currentlyRunningMainloop) { + + maybeExit(); + return false; + } + return true; + } + + // We create the loop runner here but it is not actually running until + // _emscripten_set_main_loop_timing is called (which might happen a + // later time). This member signifies that the current runner has not + // yet been started so that we can call runtimeKeepalivePush when it + // gets it timing set for the first time. + Browser.mainLoop.running = false; + Browser.mainLoop.runner = function Browser_mainLoop_runner() { + if (ABORT) return; + if (Browser.mainLoop.queue.length > 0) { + var start = Date.now(); + var blocker = Browser.mainLoop.queue.shift(); + blocker.func(blocker.arg); + if (Browser.mainLoop.remainingBlockers) { + var remaining = Browser.mainLoop.remainingBlockers; + var next = remaining%1 == 0 ? remaining-1 : Math.floor(remaining); + if (blocker.counted) { + Browser.mainLoop.remainingBlockers = next; + } else { + // not counted, but move the progress along a tiny bit + next = next + 0.5; // do not steal all the next one's progress + Browser.mainLoop.remainingBlockers = (8*remaining + next)/9; + } + } + Browser.mainLoop.updateStatus(); + + // catches pause/resume main loop from blocker execution + if (!checkIsRunning()) return; + + setTimeout(Browser.mainLoop.runner, 0); + return; + } + + // catch pauses from non-main loop sources + if (!checkIsRunning()) return; + + // Implement very basic swap interval control + Browser.mainLoop.currentFrameNumber = Browser.mainLoop.currentFrameNumber + 1 | 0; + if (Browser.mainLoop.timingMode == 1 && Browser.mainLoop.timingValue > 1 && Browser.mainLoop.currentFrameNumber % Browser.mainLoop.timingValue != 0) { + // Not the scheduled time to render this frame - skip. + Browser.mainLoop.scheduler(); + return; + } else if (Browser.mainLoop.timingMode == 0) { + Browser.mainLoop.tickStartTime = _emscripten_get_now(); + } + + // Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize + // VBO double-buffering and reduce GPU stalls. + + if (Browser.mainLoop.method === 'timeout' && Module.ctx) { + warnOnce('Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!'); + Browser.mainLoop.method = ''; // just warn once per call to set main loop + } + + Browser.mainLoop.runIter(browserIterationFunc); + + checkStackCookie(); + + // catch pauses from the main loop itself + if (!checkIsRunning()) return; + + // Queue new audio data. This is important to be right after the main loop invocation, so that we will immediately be able + // to queue the newest produced audio samples. + // TODO: Consider adding pre- and post- rAF callbacks so that GL.newRenderingFrameStarted() and SDL.audio.queueNewAudioData() + // do not need to be hardcoded into this function, but can be more generic. + if (typeof SDL == 'object') SDL.audio?.queueNewAudioData?.(); + + Browser.mainLoop.scheduler(); + } + + if (!noSetTiming) { + if (fps && fps > 0) { + _emscripten_set_main_loop_timing(0, 1000.0 / fps); + } else { + // Do rAF by rendering each frame (no decimating) + _emscripten_set_main_loop_timing(1, 1); + } + + Browser.mainLoop.scheduler(); + } + + if (simulateInfiniteLoop) { + throw 'unwind'; + } + }; + + + var callUserCallback = (func) => { + if (ABORT) { + err('user callback triggered after runtime exited or application aborted. Ignoring.'); + return; + } + try { + func(); + maybeExit(); + } catch (e) { + handleException(e); + } + }; + + /** @param {number=} timeout */ + var safeSetTimeout = (func, timeout) => { + + return setTimeout(() => { + + callUserCallback(func); + }, timeout); + }; + + + + + var Browser = { + mainLoop:{ + running:false, + scheduler:null, + method:"", + currentlyRunningMainloop:0, + func:null, + arg:0, + timingMode:0, + timingValue:0, + currentFrameNumber:0, + queue:[], + pause() { + Browser.mainLoop.scheduler = null; + // Incrementing this signals the previous main loop that it's now become old, and it must return. + Browser.mainLoop.currentlyRunningMainloop++; + }, + resume() { + Browser.mainLoop.currentlyRunningMainloop++; + var timingMode = Browser.mainLoop.timingMode; + var timingValue = Browser.mainLoop.timingValue; + var func = Browser.mainLoop.func; + Browser.mainLoop.func = null; + // do not set timing and call scheduler, we will do it on the next lines + setMainLoop(func, 0, false, Browser.mainLoop.arg, true); + _emscripten_set_main_loop_timing(timingMode, timingValue); + Browser.mainLoop.scheduler(); + }, + updateStatus() { + if (Module['setStatus']) { + var message = Module['statusMessage'] || 'Please wait...'; + var remaining = Browser.mainLoop.remainingBlockers; + var expected = Browser.mainLoop.expectedBlockers; + if (remaining) { + if (remaining < expected) { + Module['setStatus'](`{message} ({expected - remaining}/{expected})`); + } else { + Module['setStatus'](message); + } + } else { + Module['setStatus'](''); + } + } + }, + runIter(func) { + if (ABORT) return; + if (Module['preMainLoop']) { + var preRet = Module['preMainLoop'](); + if (preRet === false) { + return; // |return false| skips a frame + } + } + callUserCallback(func); + Module['postMainLoop']?.(); + }, + }, + useWebGL:false, + isFullscreen:false, + pointerLock:false, + moduleContextCreatedCallbacks:[], + workers:[], + init() { + if (Browser.initted) return; + Browser.initted = true; + + // Support for plugins that can process preloaded files. You can add more of these to + // your app by creating and appending to preloadPlugins. + // + // Each plugin is asked if it can handle a file based on the file's name. If it can, + // it is given the file's raw data. When it is done, it calls a callback with the file's + // (possibly modified) data. For example, a plugin might decompress a file, or it + // might create some side data structure for use later (like an Image element, etc.). + + var imagePlugin = {}; + imagePlugin['canHandle'] = function imagePlugin_canHandle(name) { + return !Module['noImageDecoding'] && /\.(jpg|jpeg|png|bmp|webp)$/i.test(name); + }; + imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) { + var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); + if (b.size !== byteArray.length) { // Safari bug #118630 + // Safari's Blob can only take an ArrayBuffer + b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) }); + } + var url = URL.createObjectURL(b); + assert(typeof url == 'string', 'createObjectURL must return a url as a string'); + var img = new Image(); + img.onload = () => { + assert(img.complete, `Image ${name} could not be decoded`); + var canvas = /** @type {!HTMLCanvasElement} */ (document.createElement('canvas')); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + preloadedImages[name] = canvas; + URL.revokeObjectURL(url); + onload?.(byteArray); + }; + img.onerror = (event) => { + err(`Image ${url} could not be decoded`); + onerror?.(); + }; + img.src = url; + }; + preloadPlugins.push(imagePlugin); + + var audioPlugin = {}; + audioPlugin['canHandle'] = function audioPlugin_canHandle(name) { + return !Module['noAudioDecoding'] && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 }; + }; + audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) { + var done = false; + function finish(audio) { + if (done) return; + done = true; + preloadedAudios[name] = audio; + onload?.(byteArray); + } + function fail() { + if (done) return; + done = true; + preloadedAudios[name] = new Audio(); // empty shim + onerror?.(); + } + var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); + var url = URL.createObjectURL(b); // XXX we never revoke this! + assert(typeof url == 'string', 'createObjectURL must return a url as a string'); + var audio = new Audio(); + audio.addEventListener('canplaythrough', () => finish(audio), false); // use addEventListener due to chromium bug 124926 + audio.onerror = function audio_onerror(event) { + if (done) return; + err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`); + function encode64(data) { + var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + var PAD = '='; + var ret = ''; + var leftchar = 0; + var leftbits = 0; + for (var i = 0; i < data.length; i++) { + leftchar = (leftchar << 8) | data[i]; + leftbits += 8; + while (leftbits >= 6) { + var curr = (leftchar >> (leftbits-6)) & 0x3f; + leftbits -= 6; + ret += BASE[curr]; + } + } + if (leftbits == 2) { + ret += BASE[(leftchar&3) << 4]; + ret += PAD + PAD; + } else if (leftbits == 4) { + ret += BASE[(leftchar&0xf) << 2]; + ret += PAD; + } + return ret; + } + audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray); + finish(audio); // we don't wait for confirmation this worked - but it's worth trying + }; + audio.src = url; + // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror + safeSetTimeout(() => { + finish(audio); // try to use it even though it is not necessarily ready to play + }, 10000); + }; + preloadPlugins.push(audioPlugin); + + // Canvas event setup + + function pointerLockChange() { + Browser.pointerLock = document['pointerLockElement'] === Module['canvas'] || + document['mozPointerLockElement'] === Module['canvas'] || + document['webkitPointerLockElement'] === Module['canvas'] || + document['msPointerLockElement'] === Module['canvas']; + } + var canvas = Module['canvas']; + if (canvas) { + // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module + // Module['forcedAspectRatio'] = 4 / 3; + + canvas.requestPointerLock = canvas['requestPointerLock'] || + canvas['mozRequestPointerLock'] || + canvas['webkitRequestPointerLock'] || + canvas['msRequestPointerLock'] || + (() => {}); + canvas.exitPointerLock = document['exitPointerLock'] || + document['mozExitPointerLock'] || + document['webkitExitPointerLock'] || + document['msExitPointerLock'] || + (() => {}); // no-op if function does not exist + canvas.exitPointerLock = canvas.exitPointerLock.bind(document); + + document.addEventListener('pointerlockchange', pointerLockChange, false); + document.addEventListener('mozpointerlockchange', pointerLockChange, false); + document.addEventListener('webkitpointerlockchange', pointerLockChange, false); + document.addEventListener('mspointerlockchange', pointerLockChange, false); + + if (Module['elementPointerLock']) { + canvas.addEventListener("click", (ev) => { + if (!Browser.pointerLock && Module['canvas'].requestPointerLock) { + Module['canvas'].requestPointerLock(); + ev.preventDefault(); + } + }, false); + } + } + }, + createContext(/** @type {HTMLCanvasElement} */ canvas, useWebGL, setInModule, webGLContextAttributes) { + if (useWebGL && Module.ctx && canvas == Module.canvas) return Module.ctx; // no need to recreate GL context if it's already been created for this canvas. + + var ctx; + var contextHandle; + if (useWebGL) { + // For GLES2/desktop GL compatibility, adjust a few defaults to be different to WebGL defaults, so that they align better with the desktop defaults. + var contextAttributes = { + antialias: false, + alpha: false, + majorVersion: 1, + }; + + if (webGLContextAttributes) { + for (var attribute in webGLContextAttributes) { + contextAttributes[attribute] = webGLContextAttributes[attribute]; + } + } + + // This check of existence of GL is here to satisfy Closure compiler, which yells if variable GL is referenced below but GL object is not + // actually compiled in because application is not doing any GL operations. TODO: Ideally if GL is not being used, this function + // Browser.createContext() should not even be emitted. + if (typeof GL != 'undefined') { + contextHandle = GL.createContext(canvas, contextAttributes); + if (contextHandle) { + ctx = GL.getContext(contextHandle).GLctx; + } + } + } else { + ctx = canvas.getContext('2d'); + } + + if (!ctx) return null; + + if (setInModule) { + if (!useWebGL) assert(typeof GLctx == 'undefined', 'cannot set in module if GLctx is used, but we are a non-GL context that would replace it'); + Module.ctx = ctx; + if (useWebGL) GL.makeContextCurrent(contextHandle); + Browser.useWebGL = useWebGL; + Browser.moduleContextCreatedCallbacks.forEach((callback) => callback()); + Browser.init(); + } + return ctx; + }, + fullscreenHandlersInstalled:false, + lockPointer:undefined, + resizeCanvas:undefined, + requestFullscreen(lockPointer, resizeCanvas) { + Browser.lockPointer = lockPointer; + Browser.resizeCanvas = resizeCanvas; + if (typeof Browser.lockPointer == 'undefined') Browser.lockPointer = true; + if (typeof Browser.resizeCanvas == 'undefined') Browser.resizeCanvas = false; + + var canvas = Module['canvas']; + function fullscreenChange() { + Browser.isFullscreen = false; + var canvasContainer = canvas.parentNode; + if ((document['fullscreenElement'] || document['mozFullScreenElement'] || + document['msFullscreenElement'] || document['webkitFullscreenElement'] || + document['webkitCurrentFullScreenElement']) === canvasContainer) { + canvas.exitFullscreen = Browser.exitFullscreen; + if (Browser.lockPointer) canvas.requestPointerLock(); + Browser.isFullscreen = true; + if (Browser.resizeCanvas) { + Browser.setFullscreenCanvasSize(); + } else { + Browser.updateCanvasDimensions(canvas); + } + } else { + // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen + canvasContainer.parentNode.insertBefore(canvas, canvasContainer); + canvasContainer.parentNode.removeChild(canvasContainer); + + if (Browser.resizeCanvas) { + Browser.setWindowedCanvasSize(); + } else { + Browser.updateCanvasDimensions(canvas); + } + } + Module['onFullScreen']?.(Browser.isFullscreen); + Module['onFullscreen']?.(Browser.isFullscreen); + } + + if (!Browser.fullscreenHandlersInstalled) { + Browser.fullscreenHandlersInstalled = true; + document.addEventListener('fullscreenchange', fullscreenChange, false); + document.addEventListener('mozfullscreenchange', fullscreenChange, false); + document.addEventListener('webkitfullscreenchange', fullscreenChange, false); + document.addEventListener('MSFullscreenChange', fullscreenChange, false); + } + + // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root + var canvasContainer = document.createElement("div"); + canvas.parentNode.insertBefore(canvasContainer, canvas); + canvasContainer.appendChild(canvas); + + // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size) + canvasContainer.requestFullscreen = canvasContainer['requestFullscreen'] || + canvasContainer['mozRequestFullScreen'] || + canvasContainer['msRequestFullscreen'] || + (canvasContainer['webkitRequestFullscreen'] ? () => canvasContainer['webkitRequestFullscreen'](Element['ALLOW_KEYBOARD_INPUT']) : null) || + (canvasContainer['webkitRequestFullScreen'] ? () => canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) : null); + + canvasContainer.requestFullscreen(); + }, + requestFullScreen() { + abort('Module.requestFullScreen has been replaced by Module.requestFullscreen (without a capital S)'); + }, + exitFullscreen() { + // This is workaround for chrome. Trying to exit from fullscreen + // not in fullscreen state will cause "TypeError: Document not active" + // in chrome. See https://github.com/emscripten-core/emscripten/pull/8236 + if (!Browser.isFullscreen) { + return false; + } + + var CFS = document['exitFullscreen'] || + document['cancelFullScreen'] || + document['mozCancelFullScreen'] || + document['msExitFullscreen'] || + document['webkitCancelFullScreen'] || + (() => {}); + CFS.apply(document, []); + return true; + }, + nextRAF:0, + fakeRequestAnimationFrame(func) { + // try to keep 60fps between calls to here + var now = Date.now(); + if (Browser.nextRAF === 0) { + Browser.nextRAF = now + 1000/60; + } else { + while (now + 2 >= Browser.nextRAF) { // fudge a little, to avoid timer jitter causing us to do lots of delay:0 + Browser.nextRAF += 1000/60; + } + } + var delay = Math.max(Browser.nextRAF - now, 0); + setTimeout(func, delay); + }, + requestAnimationFrame(func) { + if (typeof requestAnimationFrame == 'function') { + requestAnimationFrame(func); + return; + } + var RAF = Browser.fakeRequestAnimationFrame; + RAF(func); + }, + safeSetTimeout(func, timeout) { + // Legacy function, this is used by the SDL2 port so we need to keep it + // around at least until that is updated. + // See https://github.com/libsdl-org/SDL/pull/6304 + return safeSetTimeout(func, timeout); + }, + safeRequestAnimationFrame(func) { + + return Browser.requestAnimationFrame(() => { + + callUserCallback(func); + }); + }, + getMimetype(name) { + return { + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + 'bmp': 'image/bmp', + 'ogg': 'audio/ogg', + 'wav': 'audio/wav', + 'mp3': 'audio/mpeg' + }[name.substr(name.lastIndexOf('.')+1)]; + }, + getUserMedia(func) { + window.getUserMedia ||= navigator['getUserMedia'] || + navigator['mozGetUserMedia']; + window.getUserMedia(func); + }, + getMovementX(event) { + return event['movementX'] || + event['mozMovementX'] || + event['webkitMovementX'] || + 0; + }, + getMovementY(event) { + return event['movementY'] || + event['mozMovementY'] || + event['webkitMovementY'] || + 0; + }, + getMouseWheelDelta(event) { + var delta = 0; + switch (event.type) { + case 'DOMMouseScroll': + // 3 lines make up a step + delta = event.detail / 3; + break; + case 'mousewheel': + // 120 units make up a step + delta = event.wheelDelta / 120; + break; + case 'wheel': + delta = event.deltaY + switch (event.deltaMode) { + case 0: + // DOM_DELTA_PIXEL: 100 pixels make up a step + delta /= 100; + break; + case 1: + // DOM_DELTA_LINE: 3 lines make up a step + delta /= 3; + break; + case 2: + // DOM_DELTA_PAGE: A page makes up 80 steps + delta *= 80; + break; + default: + throw 'unrecognized mouse wheel delta mode: ' + event.deltaMode; + } + break; + default: + throw 'unrecognized mouse wheel event: ' + event.type; + } + return delta; + }, + mouseX:0, + mouseY:0, + mouseMovementX:0, + mouseMovementY:0, + touches:{ + }, + lastTouches:{ + }, + calculateMouseCoords(pageX, pageY) { + // Calculate the movement based on the changes + // in the coordinates. + var rect = Module["canvas"].getBoundingClientRect(); + var cw = Module["canvas"].width; + var ch = Module["canvas"].height; + + // Neither .scrollX or .pageXOffset are defined in a spec, but + // we prefer .scrollX because it is currently in a spec draft. + // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/) + var scrollX = ((typeof window.scrollX != 'undefined') ? window.scrollX : window.pageXOffset); + var scrollY = ((typeof window.scrollY != 'undefined') ? window.scrollY : window.pageYOffset); + // If this assert lands, it's likely because the browser doesn't support scrollX or pageXOffset + // and we have no viable fallback. + assert((typeof scrollX != 'undefined') && (typeof scrollY != 'undefined'), 'Unable to retrieve scroll position, mouse positions likely broken.'); + var adjustedX = pageX - (scrollX + rect.left); + var adjustedY = pageY - (scrollY + rect.top); + + // the canvas might be CSS-scaled compared to its backbuffer; + // SDL-using content will want mouse coordinates in terms + // of backbuffer units. + adjustedX = adjustedX * (cw / rect.width); + adjustedY = adjustedY * (ch / rect.height); + + return { x: adjustedX, y: adjustedY }; + }, + setMouseCoords(pageX, pageY) { + const {x, y} = Browser.calculateMouseCoords(pageX, pageY); + Browser.mouseMovementX = x - Browser.mouseX; + Browser.mouseMovementY = y - Browser.mouseY; + Browser.mouseX = x; + Browser.mouseY = y; + }, + calculateMouseEvent(event) { // event should be mousemove, mousedown or mouseup + if (Browser.pointerLock) { + // When the pointer is locked, calculate the coordinates + // based on the movement of the mouse. + // Workaround for Firefox bug 764498 + if (event.type != 'mousemove' && + ('mozMovementX' in event)) { + Browser.mouseMovementX = Browser.mouseMovementY = 0; + } else { + Browser.mouseMovementX = Browser.getMovementX(event); + Browser.mouseMovementY = Browser.getMovementY(event); + } + + // add the mouse delta to the current absolute mouse position + Browser.mouseX += Browser.mouseMovementX; + Browser.mouseY += Browser.mouseMovementY; + } else { + if (event.type === 'touchstart' || event.type === 'touchend' || event.type === 'touchmove') { + var touch = event.touch; + if (touch === undefined) { + return; // the "touch" property is only defined in SDL + + } + var coords = Browser.calculateMouseCoords(touch.pageX, touch.pageY); + + if (event.type === 'touchstart') { + Browser.lastTouches[touch.identifier] = coords; + Browser.touches[touch.identifier] = coords; + } else if (event.type === 'touchend' || event.type === 'touchmove') { + var last = Browser.touches[touch.identifier]; + last ||= coords; + Browser.lastTouches[touch.identifier] = last; + Browser.touches[touch.identifier] = coords; + } + return; + } + + Browser.setMouseCoords(event.pageX, event.pageY); + } + }, + resizeListeners:[], + updateResizeListeners() { + var canvas = Module['canvas']; + Browser.resizeListeners.forEach((listener) => listener(canvas.width, canvas.height)); + }, + setCanvasSize(width, height, noUpdates) { + var canvas = Module['canvas']; + Browser.updateCanvasDimensions(canvas, width, height); + if (!noUpdates) Browser.updateResizeListeners(); + }, + windowedWidth:0, + windowedHeight:0, + setFullscreenCanvasSize() { + // check if SDL is available + if (typeof SDL != "undefined") { + var flags = HEAPU32[((SDL.screen)>>2)]; + flags = flags | 0x00800000; // set SDL_FULLSCREEN flag + HEAP32[((SDL.screen)>>2)] = flags; + } + Browser.updateCanvasDimensions(Module['canvas']); + Browser.updateResizeListeners(); + }, + setWindowedCanvasSize() { + // check if SDL is available + if (typeof SDL != "undefined") { + var flags = HEAPU32[((SDL.screen)>>2)]; + flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag + HEAP32[((SDL.screen)>>2)] = flags; + } + Browser.updateCanvasDimensions(Module['canvas']); + Browser.updateResizeListeners(); + }, + updateCanvasDimensions(canvas, wNative, hNative) { + if (wNative && hNative) { + canvas.widthNative = wNative; + canvas.heightNative = hNative; + } else { + wNative = canvas.widthNative; + hNative = canvas.heightNative; + } + var w = wNative; + var h = hNative; + if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) { + if (w/h < Module['forcedAspectRatio']) { + w = Math.round(h * Module['forcedAspectRatio']); + } else { + h = Math.round(w / Module['forcedAspectRatio']); + } + } + if (((document['fullscreenElement'] || document['mozFullScreenElement'] || + document['msFullscreenElement'] || document['webkitFullscreenElement'] || + document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) { + var factor = Math.min(screen.width / w, screen.height / h); + w = Math.round(w * factor); + h = Math.round(h * factor); + } + if (Browser.resizeCanvas) { + if (canvas.width != w) canvas.width = w; + if (canvas.height != h) canvas.height = h; + if (typeof canvas.style != 'undefined') { + canvas.style.removeProperty( "width"); + canvas.style.removeProperty("height"); + } + } else { + if (canvas.width != wNative) canvas.width = wNative; + if (canvas.height != hNative) canvas.height = hNative; + if (typeof canvas.style != 'undefined') { + if (w != wNative || h != hNative) { + canvas.style.setProperty( "width", w + "px", "important"); + canvas.style.setProperty("height", h + "px", "important"); + } else { + canvas.style.removeProperty( "width"); + canvas.style.removeProperty("height"); + } + } + } + }, + }; + + var EGL = { + errorCode:12288, + defaultDisplayInitialized:false, + currentContext:0, + currentReadSurface:0, + currentDrawSurface:0, + contextAttributes:{ + alpha:false, + depth:false, + stencil:false, + antialias:false, + }, + stringCache:{ + }, + setErrorCode(code) { + EGL.errorCode = code; + }, + chooseConfig(display, attribList, config, config_size, numConfigs) { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + + if (attribList) { + // read attribList if it is non-null + for (;;) { + var param = HEAP32[((attribList)>>2)]; + if (param == 0x3021 /*EGL_ALPHA_SIZE*/) { + var alphaSize = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.alpha = (alphaSize > 0); + } else if (param == 0x3025 /*EGL_DEPTH_SIZE*/) { + var depthSize = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.depth = (depthSize > 0); + } else if (param == 0x3026 /*EGL_STENCIL_SIZE*/) { + var stencilSize = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.stencil = (stencilSize > 0); + } else if (param == 0x3031 /*EGL_SAMPLES*/) { + var samples = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.antialias = (samples > 0); + } else if (param == 0x3032 /*EGL_SAMPLE_BUFFERS*/) { + var samples = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.antialias = (samples == 1); + } else if (param == 0x3100 /*EGL_CONTEXT_PRIORITY_LEVEL_IMG*/) { + var requestedPriority = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.lowLatency = (requestedPriority != 0x3103 /*EGL_CONTEXT_PRIORITY_LOW_IMG*/); + } else if (param == 0x3038 /*EGL_NONE*/) { + break; + } + attribList += 8; + } + } + + if ((!config || !config_size) && !numConfigs) { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + } + if (numConfigs) { + HEAP32[((numConfigs)>>2)] = 1; // Total number of supported configs: 1. + } + if (config && config_size > 0) { + HEAPU32[((config)>>2)] = 62002; + } + + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }, + }; + var _eglBindAPI = (api) => { + if (api == 0x30A0 /* EGL_OPENGL_ES_API */) { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + } + // if (api == 0x30A1 /* EGL_OPENVG_API */ || api == 0x30A2 /* EGL_OPENGL_API */) { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + }; + + var _eglChooseConfig = (display, attrib_list, configs, config_size, numConfigs) => { + return EGL.chooseConfig(display, attrib_list, configs, config_size, numConfigs); + }; + + var GLctx; + + var webgl_enable_ANGLE_instanced_arrays = (ctx) => { + // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension('ANGLE_instanced_arrays'); + // Because this extension is a core function in WebGL 2, assign the extension entry points in place of + // where the core functions will reside in WebGL 2. This way the calling code can call these without + // having to dynamically branch depending if running against WebGL 1 or WebGL 2. + if (ext) { + ctx['vertexAttribDivisor'] = (index, divisor) => ext['vertexAttribDivisorANGLE'](index, divisor); + ctx['drawArraysInstanced'] = (mode, first, count, primcount) => ext['drawArraysInstancedANGLE'](mode, first, count, primcount); + ctx['drawElementsInstanced'] = (mode, count, type, indices, primcount) => ext['drawElementsInstancedANGLE'](mode, count, type, indices, primcount); + return 1; + } + }; + + var webgl_enable_OES_vertex_array_object = (ctx) => { + // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension('OES_vertex_array_object'); + if (ext) { + ctx['createVertexArray'] = () => ext['createVertexArrayOES'](); + ctx['deleteVertexArray'] = (vao) => ext['deleteVertexArrayOES'](vao); + ctx['bindVertexArray'] = (vao) => ext['bindVertexArrayOES'](vao); + ctx['isVertexArray'] = (vao) => ext['isVertexArrayOES'](vao); + return 1; + } + }; + + var webgl_enable_WEBGL_draw_buffers = (ctx) => { + // Extension available in WebGL 1 from Firefox 28 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension('WEBGL_draw_buffers'); + if (ext) { + ctx['drawBuffers'] = (n, bufs) => ext['drawBuffersWEBGL'](n, bufs); + return 1; + } + }; + + var webgl_enable_EXT_polygon_offset_clamp = (ctx) => { + return !!(ctx.extPolygonOffsetClamp = ctx.getExtension('EXT_polygon_offset_clamp')); + }; + + var webgl_enable_EXT_clip_control = (ctx) => { + return !!(ctx.extClipControl = ctx.getExtension('EXT_clip_control')); + }; + + var webgl_enable_WEBGL_polygon_mode = (ctx) => { + return !!(ctx.webglPolygonMode = ctx.getExtension('WEBGL_polygon_mode')); + }; + + var webgl_enable_WEBGL_multi_draw = (ctx) => { + // Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted. + return !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw')); + }; + + var getEmscriptenSupportedExtensions = (ctx) => { + // Restrict the list of advertised extensions to those that we actually + // support. + var supportedExtensions = [ + // WebGL 1 extensions + 'ANGLE_instanced_arrays', + 'EXT_blend_minmax', + 'EXT_disjoint_timer_query', + 'EXT_frag_depth', + 'EXT_shader_texture_lod', + 'EXT_sRGB', + 'OES_element_index_uint', + 'OES_fbo_render_mipmap', + 'OES_standard_derivatives', + 'OES_texture_float', + 'OES_texture_half_float', + 'OES_texture_half_float_linear', + 'OES_vertex_array_object', + 'WEBGL_color_buffer_float', + 'WEBGL_depth_texture', + 'WEBGL_draw_buffers', + // WebGL 1 and WebGL 2 extensions + 'EXT_clip_control', + 'EXT_color_buffer_half_float', + 'EXT_depth_clamp', + 'EXT_float_blend', + 'EXT_polygon_offset_clamp', + 'EXT_texture_compression_bptc', + 'EXT_texture_compression_rgtc', + 'EXT_texture_filter_anisotropic', + 'KHR_parallel_shader_compile', + 'OES_texture_float_linear', + 'WEBGL_blend_func_extended', + 'WEBGL_compressed_texture_astc', + 'WEBGL_compressed_texture_etc', + 'WEBGL_compressed_texture_etc1', + 'WEBGL_compressed_texture_s3tc', + 'WEBGL_compressed_texture_s3tc_srgb', + 'WEBGL_debug_renderer_info', + 'WEBGL_debug_shaders', + 'WEBGL_lose_context', + 'WEBGL_multi_draw', + 'WEBGL_polygon_mode' + ]; + // .getSupportedExtensions() can return null if context is lost, so coerce to empty array. + return (ctx.getSupportedExtensions() || []).filter(ext => supportedExtensions.includes(ext)); + }; + + + var GL = { + counter:1, + buffers:[], + programs:[], + framebuffers:[], + renderbuffers:[], + textures:[], + shaders:[], + vaos:[], + contexts:[], + offscreenCanvases:{ + }, + queries:[], + stringCache:{ + }, + unpackAlignment:4, + unpackRowLength:0, + recordError:(errorCode) => { + if (!GL.lastError) { + GL.lastError = errorCode; + } + }, + getNewId:(table) => { + var ret = GL.counter++; + for (var i = table.length; i < ret; i++) { + table[i] = null; + } + return ret; + }, + genObject:(n, buffers, createFunction, objectTable + ) => { + for (var i = 0; i < n; i++) { + var buffer = GLctx[createFunction](); + var id = buffer && GL.getNewId(objectTable); + if (buffer) { + buffer.name = id; + objectTable[id] = buffer; + } else { + GL.recordError(0x502 /* GL_INVALID_OPERATION */); + } + HEAP32[(((buffers)+(i*4))>>2)] = id; + } + }, + getSource:(shader, count, string, length) => { + var source = ''; + for (var i = 0; i < count; ++i) { + var len = length ? HEAPU32[(((length)+(i*4))>>2)] : undefined; + source += UTF8ToString(HEAPU32[(((string)+(i*4))>>2)], len); + } + return source; + }, + createContext:(/** @type {HTMLCanvasElement} */ canvas, webGLContextAttributes) => { + + // BUG: Workaround Safari WebGL issue: After successfully acquiring WebGL + // context on a canvas, calling .getContext() will always return that + // context independent of which 'webgl' or 'webgl2' + // context version was passed. See: + // https://bugs.webkit.org/show_bug.cgi?id=222758 + // and: + // https://github.com/emscripten-core/emscripten/issues/13295. + // TODO: Once the bug is fixed and shipped in Safari, adjust the Safari + // version field in above check. + if (!canvas.getContextSafariWebGL2Fixed) { + canvas.getContextSafariWebGL2Fixed = canvas.getContext; + /** @type {function(this:HTMLCanvasElement, string, (Object|null)=): (Object|null)} */ + function fixedGetContext(ver, attrs) { + var gl = canvas.getContextSafariWebGL2Fixed(ver, attrs); + return ((ver == 'webgl') == (gl instanceof WebGLRenderingContext)) ? gl : null; + } + canvas.getContext = fixedGetContext; + } + + var ctx = + (canvas.getContext("webgl", webGLContextAttributes) + // https://caniuse.com/#feat=webgl + ); + + if (!ctx) return 0; + + var handle = GL.registerContext(ctx, webGLContextAttributes); + + return handle; + }, + registerContext:(ctx, webGLContextAttributes) => { + // without pthreads a context is just an integer ID + var handle = GL.getNewId(GL.contexts); + + var context = { + handle, + attributes: webGLContextAttributes, + version: webGLContextAttributes.majorVersion, + GLctx: ctx + }; + + // Store the created context object so that we can access the context + // given a canvas without having to pass the parameters again. + if (ctx.canvas) ctx.canvas.GLctxObject = context; + GL.contexts[handle] = context; + if (typeof webGLContextAttributes.enableExtensionsByDefault == 'undefined' || webGLContextAttributes.enableExtensionsByDefault) { + GL.initExtensions(context); + } + + return handle; + }, + makeContextCurrent:(contextHandle) => { + + // Active Emscripten GL layer context object. + GL.currentContext = GL.contexts[contextHandle]; + // Active WebGL context object. + Module.ctx = GLctx = GL.currentContext?.GLctx; + return !(contextHandle && !GLctx); + }, + getContext:(contextHandle) => { + return GL.contexts[contextHandle]; + }, + deleteContext:(contextHandle) => { + if (GL.currentContext === GL.contexts[contextHandle]) { + GL.currentContext = null; + } + if (typeof JSEvents == 'object') { + // Release all JS event handlers on the DOM element that the GL context is + // associated with since the context is now deleted. + JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); + } + // Make sure the canvas object no longer refers to the context object so + // there are no GC surprises. + if (GL.contexts[contextHandle] && GL.contexts[contextHandle].GLctx.canvas) { + GL.contexts[contextHandle].GLctx.canvas.GLctxObject = undefined; + } + GL.contexts[contextHandle] = null; + }, + initExtensions:(context) => { + // If this function is called without a specific context object, init the + // extensions of the currently active context. + context ||= GL.currentContext; + + if (context.initExtensionsDone) return; + context.initExtensionsDone = true; + + var GLctx = context.GLctx; + + // Detect the presence of a few extensions manually, ction GL interop + // layer itself will need to know if they exist. + + // Extensions that are available in both WebGL 1 and WebGL 2 + webgl_enable_WEBGL_multi_draw(GLctx); + webgl_enable_EXT_polygon_offset_clamp(GLctx); + webgl_enable_EXT_clip_control(GLctx); + webgl_enable_WEBGL_polygon_mode(GLctx); + // Extensions that are only available in WebGL 1 (the calls will be no-ops + // if called on a WebGL 2 context active) + webgl_enable_ANGLE_instanced_arrays(GLctx); + webgl_enable_OES_vertex_array_object(GLctx); + webgl_enable_WEBGL_draw_buffers(GLctx); + { + GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query"); + } + + getEmscriptenSupportedExtensions(GLctx).forEach((ext) => { + // WEBGL_lose_context, WEBGL_debug_renderer_info and WEBGL_debug_shaders + // are not enabled by default. + if (!ext.includes('lose_context') && !ext.includes('debug')) { + // Call .getExtension() to enable that extension permanently. + GLctx.getExtension(ext); + } + }); + }, + }; + + var _eglCreateContext = (display, config, hmm, contextAttribs) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + + // EGL 1.4 spec says default EGL_CONTEXT_CLIENT_VERSION is GLES1, but this is not supported by Emscripten. + // So user must pass EGL_CONTEXT_CLIENT_VERSION == 2 to initialize EGL. + var glesContextVersion = 1; + for (;;) { + var param = HEAP32[((contextAttribs)>>2)]; + if (param == 0x3098 /*EGL_CONTEXT_CLIENT_VERSION*/) { + glesContextVersion = HEAP32[(((contextAttribs)+(4))>>2)]; + } else if (param == 0x3038 /*EGL_NONE*/) { + break; + } else { + /* EGL1.4 specifies only EGL_CONTEXT_CLIENT_VERSION as supported attribute */ + EGL.setErrorCode(0x3004 /*EGL_BAD_ATTRIBUTE*/); + return 0; + } + contextAttribs += 8; + } + if (glesContextVersion != 2) { + EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); + return 0; /* EGL_NO_CONTEXT */ + } + + EGL.contextAttributes.majorVersion = glesContextVersion - 1; // WebGL 1 is GLES 2, WebGL2 is GLES3 + EGL.contextAttributes.minorVersion = 0; + + EGL.context = GL.createContext(Module['canvas'], EGL.contextAttributes); + + if (EGL.context != 0) { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + + // Run callbacks so that GL emulation works + GL.makeContextCurrent(EGL.context); + Browser.useWebGL = true; + Browser.moduleContextCreatedCallbacks.forEach((callback) => callback()); + + // Note: This function only creates a context, but it shall not make it active. + GL.makeContextCurrent(null); + return 62004; + } else { + EGL.setErrorCode(0x3009 /* EGL_BAD_MATCH */); // By the EGL 1.4 spec, an implementation that does not support GLES2 (WebGL in this case), this error code is set. + return 0; /* EGL_NO_CONTEXT */ + } + }; + + var _eglCreateWindowSurface = (display, config, win, attrib_list) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (config != 62002) { + EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); + return 0; + } + // TODO: Examine attrib_list! Parameters that can be present there are: + // - EGL_RENDER_BUFFER (must be EGL_BACK_BUFFER) + // - EGL_VG_COLORSPACE (can't be set) + // - EGL_VG_ALPHA_FORMAT (can't be set) + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 62006; /* Magic ID for Emscripten 'default surface' */ + }; + + + var _eglDestroyContext = (display, context) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (context != 62004) { + EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); + return 0; + } + + GL.deleteContext(EGL.context); + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + if (EGL.currentContext == context) { + EGL.currentContext = 0; + } + return 1 /* EGL_TRUE */; + }; + + var _eglDestroySurface = (display, surface) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (surface != 62006 /* Magic ID for the only EGLSurface supported by Emscripten */) { + EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); + return 1; + } + if (EGL.currentReadSurface == surface) { + EGL.currentReadSurface = 0; + } + if (EGL.currentDrawSurface == surface) { + EGL.currentDrawSurface = 0; + } + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; /* Magic ID for Emscripten 'default surface' */ + }; + + var _eglGetConfigAttrib = (display, config, attribute, value) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (config != 62002) { + EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); + return 0; + } + if (!value) { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + } + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + switch (attribute) { + case 0x3020: // EGL_BUFFER_SIZE + HEAP32[((value)>>2)] = EGL.contextAttributes.alpha ? 32 : 24; + return 1; + case 0x3021: // EGL_ALPHA_SIZE + HEAP32[((value)>>2)] = EGL.contextAttributes.alpha ? 8 : 0; + return 1; + case 0x3022: // EGL_BLUE_SIZE + HEAP32[((value)>>2)] = 8; + return 1; + case 0x3023: // EGL_GREEN_SIZE + HEAP32[((value)>>2)] = 8; + return 1; + case 0x3024: // EGL_RED_SIZE + HEAP32[((value)>>2)] = 8; + return 1; + case 0x3025: // EGL_DEPTH_SIZE + HEAP32[((value)>>2)] = EGL.contextAttributes.depth ? 24 : 0; + return 1; + case 0x3026: // EGL_STENCIL_SIZE + HEAP32[((value)>>2)] = EGL.contextAttributes.stencil ? 8 : 0; + return 1; + case 0x3027: // EGL_CONFIG_CAVEAT + // We can return here one of EGL_NONE (0x3038), EGL_SLOW_CONFIG (0x3050) or EGL_NON_CONFORMANT_CONFIG (0x3051). + HEAP32[((value)>>2)] = 0x3038; + return 1; + case 0x3028: // EGL_CONFIG_ID + HEAP32[((value)>>2)] = 62002; + return 1; + case 0x3029: // EGL_LEVEL + HEAP32[((value)>>2)] = 0; + return 1; + case 0x302A: // EGL_MAX_PBUFFER_HEIGHT + HEAP32[((value)>>2)] = 4096; + return 1; + case 0x302B: // EGL_MAX_PBUFFER_PIXELS + HEAP32[((value)>>2)] = 16777216; + return 1; + case 0x302C: // EGL_MAX_PBUFFER_WIDTH + HEAP32[((value)>>2)] = 4096; + return 1; + case 0x302D: // EGL_NATIVE_RENDERABLE + HEAP32[((value)>>2)] = 0; + return 1; + case 0x302E: // EGL_NATIVE_VISUAL_ID + HEAP32[((value)>>2)] = 0; + return 1; + case 0x302F: // EGL_NATIVE_VISUAL_TYPE + HEAP32[((value)>>2)] = 0x3038; + return 1; + case 0x3031: // EGL_SAMPLES + HEAP32[((value)>>2)] = EGL.contextAttributes.antialias ? 4 : 0; + return 1; + case 0x3032: // EGL_SAMPLE_BUFFERS + HEAP32[((value)>>2)] = EGL.contextAttributes.antialias ? 1 : 0; + return 1; + case 0x3033: // EGL_SURFACE_TYPE + HEAP32[((value)>>2)] = 0x4; + return 1; + case 0x3034: // EGL_TRANSPARENT_TYPE + // If this returns EGL_TRANSPARENT_RGB (0x3052), transparency is used through color-keying. No such thing applies to Emscripten canvas. + HEAP32[((value)>>2)] = 0x3038; + return 1; + case 0x3035: // EGL_TRANSPARENT_BLUE_VALUE + case 0x3036: // EGL_TRANSPARENT_GREEN_VALUE + case 0x3037: // EGL_TRANSPARENT_RED_VALUE + // "If EGL_TRANSPARENT_TYPE is EGL_NONE, then the values for EGL_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_GREEN_VALUE, and EGL_TRANSPARENT_BLUE_VALUE are undefined." + HEAP32[((value)>>2)] = -1; + return 1; + case 0x3039: // EGL_BIND_TO_TEXTURE_RGB + case 0x303A: // EGL_BIND_TO_TEXTURE_RGBA + HEAP32[((value)>>2)] = 0; + return 1; + case 0x303B: // EGL_MIN_SWAP_INTERVAL + HEAP32[((value)>>2)] = 0; + return 1; + case 0x303C: // EGL_MAX_SWAP_INTERVAL + HEAP32[((value)>>2)] = 1; + return 1; + case 0x303D: // EGL_LUMINANCE_SIZE + case 0x303E: // EGL_ALPHA_MASK_SIZE + HEAP32[((value)>>2)] = 0; + return 1; + case 0x303F: // EGL_COLOR_BUFFER_TYPE + // EGL has two types of buffers: EGL_RGB_BUFFER and EGL_LUMINANCE_BUFFER. + HEAP32[((value)>>2)] = 0x308E; + return 1; + case 0x3040: // EGL_RENDERABLE_TYPE + // A bit combination of EGL_OPENGL_ES_BIT,EGL_OPENVG_BIT,EGL_OPENGL_ES2_BIT and EGL_OPENGL_BIT. + HEAP32[((value)>>2)] = 0x4; + return 1; + case 0x3042: // EGL_CONFORMANT + // "EGL_CONFORMANT is a mask indicating if a client API context created with respect to the corresponding EGLConfig will pass the required conformance tests for that API." + HEAP32[((value)>>2)] = 0; + return 1; + default: + EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */); + return 0; + } + }; + + var _eglGetDisplay = (nativeDisplayType) => { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + // Emscripten EGL implementation "emulates" X11, and eglGetDisplay is + // expected to accept/receive a pointer to an X11 Display object (or + // EGL_DEFAULT_DISPLAY). + if (nativeDisplayType != 0 /* EGL_DEFAULT_DISPLAY */ && nativeDisplayType != 1 /* see library_xlib.js */) { + return 0; // EGL_NO_DISPLAY + } + return 62000; + }; + + var _eglGetError = () => EGL.errorCode; + + var _eglInitialize = (display, majorVersion, minorVersion) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (majorVersion) { + HEAP32[((majorVersion)>>2)] = 1; // Advertise EGL Major version: '1' + } + if (minorVersion) { + HEAP32[((minorVersion)>>2)] = 4; // Advertise EGL Minor version: '4' + } + EGL.defaultDisplayInitialized = true; + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + + + var _eglMakeCurrent = (display, draw, read, context) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0 /* EGL_FALSE */; + } + //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. + if (context != 0 && context != 62004) { + EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); + return 0; + } + if ((read != 0 && read != 62006) || (draw != 0 && draw != 62006 /* Magic ID for Emscripten 'default surface' */)) { + EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); + return 0; + } + + GL.makeContextCurrent(context ? EGL.context : null); + + EGL.currentContext = context; + EGL.currentDrawSurface = draw; + EGL.currentReadSurface = read; + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1 /* EGL_TRUE */; + }; + + + + var stringToNewUTF8 = (str) => { + var size = lengthBytesUTF8(str) + 1; + var ret = _malloc(size); + if (ret) stringToUTF8(str, ret, size); + return ret; + }; + + var _eglQueryString = (display, name) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + if (EGL.stringCache[name]) return EGL.stringCache[name]; + var ret; + switch (name) { + case 0x3053 /* EGL_VENDOR */: ret = stringToNewUTF8("Emscripten"); break; + case 0x3054 /* EGL_VERSION */: ret = stringToNewUTF8("1.4 Emscripten EGL"); break; + case 0x3055 /* EGL_EXTENSIONS */: ret = stringToNewUTF8(""); break; // Currently not supporting any EGL extensions. + case 0x308D /* EGL_CLIENT_APIS */: ret = stringToNewUTF8("OpenGL_ES"); break; + default: + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + } + EGL.stringCache[name] = ret; + return ret; + }; + + var _eglSwapBuffers = (dpy, surface) => { + + if (!EGL.defaultDisplayInitialized) { + EGL.setErrorCode(0x3001 /* EGL_NOT_INITIALIZED */); + } else if (!Module.ctx) { + EGL.setErrorCode(0x3002 /* EGL_BAD_ACCESS */); + } else if (Module.ctx.isContextLost()) { + EGL.setErrorCode(0x300E /* EGL_CONTEXT_LOST */); + } else { + // According to documentation this does an implicit flush. + // Due to discussion at https://github.com/emscripten-core/emscripten/pull/1871 + // the flush was removed since this _may_ result in slowing code down. + //_glFlush(); + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1 /* EGL_TRUE */; + } + return 0 /* EGL_FALSE */; + }; + + + var _eglSwapInterval = (display, interval) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (interval == 0) _emscripten_set_main_loop_timing(0, 0); + else _emscripten_set_main_loop_timing(1, interval); + + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + + var _eglTerminate = (display) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + EGL.currentContext = 0; + EGL.currentReadSurface = 0; + EGL.currentDrawSurface = 0; + EGL.defaultDisplayInitialized = false; + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + + + /** @suppress {duplicate } */ + var _eglWaitClient = () => { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + var _eglWaitGL = _eglWaitClient; + + var _eglWaitNative = (nativeEngineId) => { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + + var readEmAsmArgsArray = []; + var readEmAsmArgs = (sigPtr, buf) => { + // Nobody should have mutated _readEmAsmArgsArray underneath us to be something else than an array. + assert(Array.isArray(readEmAsmArgsArray)); + // The input buffer is allocated on the stack, so it must be stack-aligned. + assert(buf % 16 == 0); + readEmAsmArgsArray.length = 0; + var ch; + // Most arguments are i32s, so shift the buffer pointer so it is a plain + // index into HEAP32. + while (ch = HEAPU8[sigPtr++]) { + var chr = String.fromCharCode(ch); + var validChars = ['d', 'f', 'i', 'p']; + assert(validChars.includes(chr), `Invalid character ${ch}("${chr}") in readEmAsmArgs! Use only [${validChars}], and do not specify "v" for void return argument.`); + // Floats are always passed as doubles, so all types except for 'i' + // are 8 bytes and require alignment. + var wide = (ch != 105); + wide &= (ch != 112); + buf += wide && (buf % 8) ? 4 : 0; + readEmAsmArgsArray.push( + // Special case for pointers under wasm64 or CAN_ADDRESS_2GB mode. + ch == 112 ? HEAPU32[((buf)>>2)] : + ch == 105 ? + HEAP32[((buf)>>2)] : + HEAPF64[((buf)>>3)] + ); + buf += wide ? 8 : 4; + } + return readEmAsmArgsArray; + }; + var runEmAsmFunction = (code, sigPtr, argbuf) => { + var args = readEmAsmArgs(sigPtr, argbuf); + assert(ASM_CONSTS.hasOwnProperty(code), `No EM_ASM constant found at address ${code}. The loaded WebAssembly file is likely out of sync with the generated JavaScript.`); + return ASM_CONSTS[code](...args); + }; + var _emscripten_asm_const_int = (code, sigPtr, argbuf) => { + return runEmAsmFunction(code, sigPtr, argbuf); + }; + + var runMainThreadEmAsm = (emAsmAddr, sigPtr, argbuf, sync) => { + var args = readEmAsmArgs(sigPtr, argbuf); + assert(ASM_CONSTS.hasOwnProperty(emAsmAddr), `No EM_ASM constant found at address ${emAsmAddr}. The loaded WebAssembly file is likely out of sync with the generated JavaScript.`); + return ASM_CONSTS[emAsmAddr](...args); + }; + var _emscripten_asm_const_int_sync_on_main_thread = (emAsmAddr, sigPtr, argbuf) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 1); + + var _emscripten_asm_const_ptr_sync_on_main_thread = (emAsmAddr, sigPtr, argbuf) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 1); + + var _emscripten_cancel_main_loop = () => { + Browser.mainLoop.pause(); + Browser.mainLoop.func = null; + }; + + var _emscripten_date_now = () => Date.now(); + + var JSEvents = { + removeAllEventListeners() { + while (JSEvents.eventHandlers.length) { + JSEvents._removeHandler(JSEvents.eventHandlers.length - 1); + } + JSEvents.deferredCalls = []; + }, + inEventHandler:0, + deferredCalls:[], + deferCall(targetFunction, precedence, argsList) { + function arraysHaveEqualContent(arrA, arrB) { + if (arrA.length != arrB.length) return false; + + for (var i in arrA) { + if (arrA[i] != arrB[i]) return false; + } + return true; + } + // Test if the given call was already queued, and if so, don't add it again. + for (var call of JSEvents.deferredCalls) { + if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) { + return; + } + } + JSEvents.deferredCalls.push({ + targetFunction, + precedence, + argsList + }); + + JSEvents.deferredCalls.sort((x,y) => x.precedence < y.precedence); + }, + removeDeferredCalls(targetFunction) { + JSEvents.deferredCalls = JSEvents.deferredCalls.filter((call) => call.targetFunction != targetFunction); + }, + canPerformEventHandlerRequests() { + if (navigator.userActivation) { + // Verify against transient activation status from UserActivation API + // whether it is possible to perform a request here without needing to defer. See + // https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation + // and https://caniuse.com/mdn-api_useractivation + // At the time of writing, Firefox does not support this API: https://bugzilla.mozilla.org/show_bug.cgi?id=1791079 + return navigator.userActivation.isActive; + } + + return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls; + }, + runDeferredCalls() { + if (!JSEvents.canPerformEventHandlerRequests()) { + return; + } + var deferredCalls = JSEvents.deferredCalls; + JSEvents.deferredCalls = []; + for (var call of deferredCalls) { + call.targetFunction(...call.argsList); + } + }, + eventHandlers:[], + removeAllHandlersOnTarget:(target, eventTypeString) => { + for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { + if (JSEvents.eventHandlers[i].target == target && + (!eventTypeString || eventTypeString == JSEvents.eventHandlers[i].eventTypeString)) { + JSEvents._removeHandler(i--); + } + } + }, + _removeHandler(i) { + var h = JSEvents.eventHandlers[i]; + h.target.removeEventListener(h.eventTypeString, h.eventListenerFunc, h.useCapture); + JSEvents.eventHandlers.splice(i, 1); + }, + registerOrRemoveHandler(eventHandler) { + if (!eventHandler.target) { + err('registerOrRemoveHandler: the target element for event handler registration does not exist, when processing the following event handler registration:'); + console.dir(eventHandler); + return -4; + } + if (eventHandler.callbackfunc) { + eventHandler.eventListenerFunc = function(event) { + // Increment nesting count for the event handler. + ++JSEvents.inEventHandler; + JSEvents.currentEventHandler = eventHandler; + // Process any old deferred calls the user has placed. + JSEvents.runDeferredCalls(); + // Process the actual event, calls back to user C code handler. + eventHandler.handlerFunc(event); + // Process any new deferred calls that were placed right now from this event handler. + JSEvents.runDeferredCalls(); + // Out of event handler - restore nesting count. + --JSEvents.inEventHandler; + }; + + eventHandler.target.addEventListener(eventHandler.eventTypeString, + eventHandler.eventListenerFunc, + eventHandler.useCapture); + JSEvents.eventHandlers.push(eventHandler); + } else { + for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { + if (JSEvents.eventHandlers[i].target == eventHandler.target + && JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) { + JSEvents._removeHandler(i--); + } + } + } + return 0; + }, + getNodeNameForTarget(target) { + if (!target) return ''; + if (target == window) return '#window'; + if (target == screen) return '#screen'; + return target?.nodeName || ''; + }, + fullscreenEnabled() { + return document.fullscreenEnabled + // Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitFullscreenEnabled. + // TODO: If Safari at some point ships with unprefixed version, update the version check above. + || document.webkitFullscreenEnabled + ; + }, + }; + + var currentFullscreenStrategy = { + }; + + + + + var maybeCStringToJsString = (cString) => { + // "cString > 2" checks if the input is a number, and isn't of the special + // values we accept here, EMSCRIPTEN_EVENT_TARGET_* (which map to 0, 1, 2). + // In other words, if cString > 2 then it's a pointer to a valid place in + // memory, and points to a C string. + return cString > 2 ? UTF8ToString(cString) : cString; + }; + + /** @type {Object} */ + var specialHTMLTargets = [0, typeof document != 'undefined' ? document : 0, typeof window != 'undefined' ? window : 0]; + /** @suppress {duplicate } */ + var findEventTarget = (target) => { + target = maybeCStringToJsString(target); + var domElement = specialHTMLTargets[target] || (typeof document != 'undefined' ? document.querySelector(target) : undefined); + return domElement; + }; + var findCanvasEventTarget = findEventTarget; + var _emscripten_get_canvas_element_size = (target, width, height) => { + var canvas = findCanvasEventTarget(target); + if (!canvas) return -4; + HEAP32[((width)>>2)] = canvas.width; + HEAP32[((height)>>2)] = canvas.height; + }; + + + + + + var stackAlloc = (sz) => __emscripten_stack_alloc(sz); + var stringToUTF8OnStack = (str) => { + var size = lengthBytesUTF8(str) + 1; + var ret = stackAlloc(size); + stringToUTF8(str, ret, size); + return ret; + }; + var getCanvasElementSize = (target) => { + var sp = stackSave(); + var w = stackAlloc(8); + var h = w + 4; + + var targetInt = stringToUTF8OnStack(target.id); + var ret = _emscripten_get_canvas_element_size(targetInt, w, h); + var size = [HEAP32[((w)>>2)], HEAP32[((h)>>2)]]; + stackRestore(sp); + return size; + }; + + + var _emscripten_set_canvas_element_size = (target, width, height) => { + var canvas = findCanvasEventTarget(target); + if (!canvas) return -4; + canvas.width = width; + canvas.height = height; + return 0; + }; + + + + var setCanvasElementSize = (target, width, height) => { + if (!target.controlTransferredOffscreen) { + target.width = width; + target.height = height; + } else { + // This function is being called from high-level JavaScript code instead of asm.js/Wasm, + // and it needs to synchronously proxy over to another thread, so marshal the string onto the heap to do the call. + var sp = stackSave(); + var targetInt = stringToUTF8OnStack(target.id); + _emscripten_set_canvas_element_size(targetInt, width, height); + stackRestore(sp); + } + }; + var registerRestoreOldStyle = (canvas) => { + var canvasSize = getCanvasElementSize(canvas); + var oldWidth = canvasSize[0]; + var oldHeight = canvasSize[1]; + var oldCssWidth = canvas.style.width; + var oldCssHeight = canvas.style.height; + var oldBackgroundColor = canvas.style.backgroundColor; // Chrome reads color from here. + var oldDocumentBackgroundColor = document.body.style.backgroundColor; // IE11 reads color from here. + // Firefox always has black background color. + var oldPaddingLeft = canvas.style.paddingLeft; // Chrome, FF, Safari + var oldPaddingRight = canvas.style.paddingRight; + var oldPaddingTop = canvas.style.paddingTop; + var oldPaddingBottom = canvas.style.paddingBottom; + var oldMarginLeft = canvas.style.marginLeft; // IE11 + var oldMarginRight = canvas.style.marginRight; + var oldMarginTop = canvas.style.marginTop; + var oldMarginBottom = canvas.style.marginBottom; + var oldDocumentBodyMargin = document.body.style.margin; + var oldDocumentOverflow = document.documentElement.style.overflow; // Chrome, Firefox + var oldDocumentScroll = document.body.scroll; // IE + var oldImageRendering = canvas.style.imageRendering; + + function restoreOldStyle() { + var fullscreenElement = document.fullscreenElement + || document.webkitFullscreenElement + ; + if (!fullscreenElement) { + document.removeEventListener('fullscreenchange', restoreOldStyle); + + // Unprefixed Fullscreen API shipped in Chromium 71 (https://bugs.chromium.org/p/chromium/issues/detail?id=383813) + // As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version. + document.removeEventListener('webkitfullscreenchange', restoreOldStyle); + + setCanvasElementSize(canvas, oldWidth, oldHeight); + + canvas.style.width = oldCssWidth; + canvas.style.height = oldCssHeight; + canvas.style.backgroundColor = oldBackgroundColor; // Chrome + // IE11 hack: assigning 'undefined' or an empty string to document.body.style.backgroundColor has no effect, so first assign back the default color + // before setting the undefined value. Setting undefined value is also important, or otherwise we would later treat that as something that the user + // had explicitly set so subsequent fullscreen transitions would not set background color properly. + if (!oldDocumentBackgroundColor) document.body.style.backgroundColor = 'white'; + document.body.style.backgroundColor = oldDocumentBackgroundColor; // IE11 + canvas.style.paddingLeft = oldPaddingLeft; // Chrome, FF, Safari + canvas.style.paddingRight = oldPaddingRight; + canvas.style.paddingTop = oldPaddingTop; + canvas.style.paddingBottom = oldPaddingBottom; + canvas.style.marginLeft = oldMarginLeft; // IE11 + canvas.style.marginRight = oldMarginRight; + canvas.style.marginTop = oldMarginTop; + canvas.style.marginBottom = oldMarginBottom; + document.body.style.margin = oldDocumentBodyMargin; + document.documentElement.style.overflow = oldDocumentOverflow; // Chrome, Firefox + document.body.scroll = oldDocumentScroll; // IE + canvas.style.imageRendering = oldImageRendering; + if (canvas.GLctxObject) canvas.GLctxObject.GLctx.viewport(0, 0, oldWidth, oldHeight); + + if (currentFullscreenStrategy.canvasResizedCallback) { + ((a1, a2, a3) => dynCall_iiii(currentFullscreenStrategy.canvasResizedCallback, a1, a2, a3))(37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); + } + } + } + document.addEventListener('fullscreenchange', restoreOldStyle); + // Unprefixed Fullscreen API shipped in Chromium 71 (https://bugs.chromium.org/p/chromium/issues/detail?id=383813) + // As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version. + document.addEventListener('webkitfullscreenchange', restoreOldStyle); + return restoreOldStyle; + }; + + + var setLetterbox = (element, topBottom, leftRight) => { + // Cannot use margin to specify letterboxes in FF or Chrome, since those ignore margins in fullscreen mode. + element.style.paddingLeft = element.style.paddingRight = leftRight + 'px'; + element.style.paddingTop = element.style.paddingBottom = topBottom + 'px'; + }; + + + var getBoundingClientRect = (e) => specialHTMLTargets.indexOf(e) < 0 ? e.getBoundingClientRect() : {'left':0,'top':0}; + var JSEvents_resizeCanvasForFullscreen = (target, strategy) => { + var restoreOldStyle = registerRestoreOldStyle(target); + var cssWidth = strategy.softFullscreen ? innerWidth : screen.width; + var cssHeight = strategy.softFullscreen ? innerHeight : screen.height; + var rect = getBoundingClientRect(target); + var windowedCssWidth = rect.width; + var windowedCssHeight = rect.height; + var canvasSize = getCanvasElementSize(target); + var windowedRttWidth = canvasSize[0]; + var windowedRttHeight = canvasSize[1]; + + if (strategy.scaleMode == 3) { + setLetterbox(target, (cssHeight - windowedCssHeight) / 2, (cssWidth - windowedCssWidth) / 2); + cssWidth = windowedCssWidth; + cssHeight = windowedCssHeight; + } else if (strategy.scaleMode == 2) { + if (cssWidth*windowedRttHeight < windowedRttWidth*cssHeight) { + var desiredCssHeight = windowedRttHeight * cssWidth / windowedRttWidth; + setLetterbox(target, (cssHeight - desiredCssHeight) / 2, 0); + cssHeight = desiredCssHeight; + } else { + var desiredCssWidth = windowedRttWidth * cssHeight / windowedRttHeight; + setLetterbox(target, 0, (cssWidth - desiredCssWidth) / 2); + cssWidth = desiredCssWidth; + } + } + + // If we are adding padding, must choose a background color or otherwise Chrome will give the + // padding a default white color. Do it only if user has not customized their own background color. + if (!target.style.backgroundColor) target.style.backgroundColor = 'black'; + // IE11 does the same, but requires the color to be set in the document body. + if (!document.body.style.backgroundColor) document.body.style.backgroundColor = 'black'; // IE11 + // Firefox always shows black letterboxes independent of style color. + + target.style.width = cssWidth + 'px'; + target.style.height = cssHeight + 'px'; + + if (strategy.filteringMode == 1) { + target.style.imageRendering = 'optimizeSpeed'; + target.style.imageRendering = '-moz-crisp-edges'; + target.style.imageRendering = '-o-crisp-edges'; + target.style.imageRendering = '-webkit-optimize-contrast'; + target.style.imageRendering = 'optimize-contrast'; + target.style.imageRendering = 'crisp-edges'; + target.style.imageRendering = 'pixelated'; + } + + var dpiScale = (strategy.canvasResolutionScaleMode == 2) ? devicePixelRatio : 1; + if (strategy.canvasResolutionScaleMode != 0) { + var newWidth = (cssWidth * dpiScale)|0; + var newHeight = (cssHeight * dpiScale)|0; + setCanvasElementSize(target, newWidth, newHeight); + if (target.GLctxObject) target.GLctxObject.GLctx.viewport(0, 0, newWidth, newHeight); + } + return restoreOldStyle; + }; + var JSEvents_requestFullscreen = (target, strategy) => { + // EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT + EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE is a mode where no extra logic is performed to the DOM elements. + if (strategy.scaleMode != 0 || strategy.canvasResolutionScaleMode != 0) { + JSEvents_resizeCanvasForFullscreen(target, strategy); + } + + if (target.requestFullscreen) { + target.requestFullscreen(); + } else if (target.webkitRequestFullscreen) { + target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } else { + return JSEvents.fullscreenEnabled() ? -3 : -1; + } + + currentFullscreenStrategy = strategy; + + if (strategy.canvasResizedCallback) { + ((a1, a2, a3) => dynCall_iiii(strategy.canvasResizedCallback, a1, a2, a3))(37, 0, strategy.canvasResizedCallbackUserData); + } + + return 0; + }; + + var _emscripten_exit_fullscreen = () => { + if (!JSEvents.fullscreenEnabled()) return -1; + // Make sure no queued up calls will fire after this. + JSEvents.removeDeferredCalls(JSEvents_requestFullscreen); + + var d = specialHTMLTargets[1]; + if (d.exitFullscreen) { + d.fullscreenElement && d.exitFullscreen(); + } else if (d.webkitExitFullscreen) { + d.webkitFullscreenElement && d.webkitExitFullscreen(); + } else { + return -1; + } + + return 0; + }; + + + var requestPointerLock = (target) => { + if (target.requestPointerLock) { + target.requestPointerLock(); + } else { + // document.body is known to accept pointer lock, so use that to differentiate if the user passed a bad element, + // or if the whole browser just doesn't support the feature. + if (document.body.requestPointerLock + ) { + return -3; + } + return -1; + } + return 0; + }; + var _emscripten_exit_pointerlock = () => { + // Make sure no queued up calls will fire after this. + JSEvents.removeDeferredCalls(requestPointerLock); + + if (document.exitPointerLock) { + document.exitPointerLock(); + } else { + return -1; + } + return 0; + }; + + + var __emscripten_runtime_keepalive_clear = () => { + noExitRuntime = false; + runtimeKeepaliveCounter = 0; + }; + + + var _emscripten_force_exit = (status) => { + warnOnce('emscripten_force_exit cannot actually shut down the runtime, as the build does not have EXIT_RUNTIME set'); + __emscripten_runtime_keepalive_clear(); + _exit(status); + }; + + var _emscripten_get_device_pixel_ratio = () => { + return (typeof devicePixelRatio == 'number' && devicePixelRatio) || 1.0; + }; + + + + var _emscripten_get_element_css_size = (target, width, height) => { + target = findEventTarget(target); + if (!target) return -4; + + var rect = getBoundingClientRect(target); + HEAPF64[((width)>>3)] = rect.width; + HEAPF64[((height)>>3)] = rect.height; + + return 0; + }; + + + var fillGamepadEventData = (eventStruct, e) => { + HEAPF64[((eventStruct)>>3)] = e.timestamp; + for (var i = 0; i < e.axes.length; ++i) { + HEAPF64[(((eventStruct+i*8)+(16))>>3)] = e.axes[i]; + } + for (var i = 0; i < e.buttons.length; ++i) { + if (typeof e.buttons[i] == 'object') { + HEAPF64[(((eventStruct+i*8)+(528))>>3)] = e.buttons[i].value; + } else { + HEAPF64[(((eventStruct+i*8)+(528))>>3)] = e.buttons[i]; + } + } + for (var i = 0; i < e.buttons.length; ++i) { + if (typeof e.buttons[i] == 'object') { + HEAP8[(eventStruct+i)+(1040)] = e.buttons[i].pressed; + } else { + // Assigning a boolean to HEAP32, that's ok, but Closure would like to warn about it: + /** @suppress {checkTypes} */ + HEAP8[(eventStruct+i)+(1040)] = e.buttons[i] == 1; + } + } + HEAP8[(eventStruct)+(1104)] = e.connected; + HEAP32[(((eventStruct)+(1108))>>2)] = e.index; + HEAP32[(((eventStruct)+(8))>>2)] = e.axes.length; + HEAP32[(((eventStruct)+(12))>>2)] = e.buttons.length; + stringToUTF8(e.id, eventStruct + 1112, 64); + stringToUTF8(e.mapping, eventStruct + 1176, 64); + }; + var _emscripten_get_gamepad_status = (index, gamepadState) => { + if (!JSEvents.lastGamepadState) throw 'emscripten_get_gamepad_status() can only be called after having first called emscripten_sample_gamepad_data() and that function has returned EMSCRIPTEN_RESULT_SUCCESS!'; + // INVALID_PARAM is returned on a Gamepad index that never was there. + if (index < 0 || index >= JSEvents.lastGamepadState.length) return -5; + + // NO_DATA is returned on a Gamepad index that was removed. + // For previously disconnected gamepads there should be an empty slot (null/undefined/false) at the index. + // This is because gamepads must keep their original position in the array. + // For example, removing the first of two gamepads produces [null/undefined/false, gamepad]. + if (!JSEvents.lastGamepadState[index]) return -7; + + fillGamepadEventData(gamepadState, JSEvents.lastGamepadState[index]); + return 0; + }; + + + var _emscripten_get_num_gamepads = () => { + if (!JSEvents.lastGamepadState) throw 'emscripten_get_num_gamepads() can only be called after having first called emscripten_sample_gamepad_data() and that function has returned EMSCRIPTEN_RESULT_SUCCESS!'; + // N.B. Do not call emscripten_get_num_gamepads() unless having first called emscripten_sample_gamepad_data(), and that has returned EMSCRIPTEN_RESULT_SUCCESS. + // Otherwise the following line will throw an exception. + return JSEvents.lastGamepadState.length; + }; + + var _emscripten_get_screen_size = (width, height) => { + HEAP32[((width)>>2)] = screen.width; + HEAP32[((height)>>2)] = screen.height; + }; + + /** @suppress {duplicate } */ + var _glActiveTexture = (x0) => GLctx.activeTexture(x0); + var _emscripten_glActiveTexture = _glActiveTexture; + + /** @suppress {duplicate } */ + var _glAttachShader = (program, shader) => { + GLctx.attachShader(GL.programs[program], GL.shaders[shader]); + }; + var _emscripten_glAttachShader = _glAttachShader; + + /** @suppress {duplicate } */ + var _glBeginQueryEXT = (target, id) => { + GLctx.disjointTimerQueryExt['beginQueryEXT'](target, GL.queries[id]); + }; + var _emscripten_glBeginQueryEXT = _glBeginQueryEXT; + + + /** @suppress {duplicate } */ + var _glBindAttribLocation = (program, index, name) => { + GLctx.bindAttribLocation(GL.programs[program], index, UTF8ToString(name)); + }; + var _emscripten_glBindAttribLocation = _glBindAttribLocation; + + /** @suppress {duplicate } */ + var _glBindBuffer = (target, buffer) => { + + GLctx.bindBuffer(target, GL.buffers[buffer]); + }; + var _emscripten_glBindBuffer = _glBindBuffer; + + /** @suppress {duplicate } */ + var _glBindFramebuffer = (target, framebuffer) => { + + GLctx.bindFramebuffer(target, GL.framebuffers[framebuffer]); + + }; + var _emscripten_glBindFramebuffer = _glBindFramebuffer; + + /** @suppress {duplicate } */ + var _glBindRenderbuffer = (target, renderbuffer) => { + GLctx.bindRenderbuffer(target, GL.renderbuffers[renderbuffer]); + }; + var _emscripten_glBindRenderbuffer = _glBindRenderbuffer; + + /** @suppress {duplicate } */ + var _glBindTexture = (target, texture) => { + GLctx.bindTexture(target, GL.textures[texture]); + }; + var _emscripten_glBindTexture = _glBindTexture; + + + /** @suppress {duplicate } */ + var _glBindVertexArray = (vao) => { + GLctx.bindVertexArray(GL.vaos[vao]); + }; + /** @suppress {duplicate } */ + var _glBindVertexArrayOES = _glBindVertexArray; + var _emscripten_glBindVertexArrayOES = _glBindVertexArrayOES; + + /** @suppress {duplicate } */ + var _glBlendColor = (x0, x1, x2, x3) => GLctx.blendColor(x0, x1, x2, x3); + var _emscripten_glBlendColor = _glBlendColor; + + /** @suppress {duplicate } */ + var _glBlendEquation = (x0) => GLctx.blendEquation(x0); + var _emscripten_glBlendEquation = _glBlendEquation; + + /** @suppress {duplicate } */ + var _glBlendEquationSeparate = (x0, x1) => GLctx.blendEquationSeparate(x0, x1); + var _emscripten_glBlendEquationSeparate = _glBlendEquationSeparate; + + /** @suppress {duplicate } */ + var _glBlendFunc = (x0, x1) => GLctx.blendFunc(x0, x1); + var _emscripten_glBlendFunc = _glBlendFunc; + + /** @suppress {duplicate } */ + var _glBlendFuncSeparate = (x0, x1, x2, x3) => GLctx.blendFuncSeparate(x0, x1, x2, x3); + var _emscripten_glBlendFuncSeparate = _glBlendFuncSeparate; + + /** @suppress {duplicate } */ + var _glBufferData = (target, size, data, usage) => { + + // N.b. here first form specifies a heap subarray, second form an integer + // size, so the ?: code here is polymorphic. It is advised to avoid + // randomly mixing both uses in calling code, to avoid any potential JS + // engine JIT issues. + GLctx.bufferData(target, data ? HEAPU8.subarray(data, data+size) : size, usage); + }; + var _emscripten_glBufferData = _glBufferData; + + /** @suppress {duplicate } */ + var _glBufferSubData = (target, offset, size, data) => { + GLctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size)); + }; + var _emscripten_glBufferSubData = _glBufferSubData; + + /** @suppress {duplicate } */ + var _glCheckFramebufferStatus = (x0) => GLctx.checkFramebufferStatus(x0); + var _emscripten_glCheckFramebufferStatus = _glCheckFramebufferStatus; + + /** @suppress {duplicate } */ + var _glClear = (x0) => GLctx.clear(x0); + var _emscripten_glClear = _glClear; + + /** @suppress {duplicate } */ + var _glClearColor = (x0, x1, x2, x3) => GLctx.clearColor(x0, x1, x2, x3); + var _emscripten_glClearColor = _glClearColor; + + /** @suppress {duplicate } */ + var _glClearDepthf = (x0) => GLctx.clearDepth(x0); + var _emscripten_glClearDepthf = _glClearDepthf; + + /** @suppress {duplicate } */ + var _glClearStencil = (x0) => GLctx.clearStencil(x0); + var _emscripten_glClearStencil = _glClearStencil; + + /** @suppress {duplicate } */ + var _glClipControlEXT = (origin, depth) => { + GLctx.extClipControl['clipControlEXT'](origin, depth); + }; + var _emscripten_glClipControlEXT = _glClipControlEXT; + + /** @suppress {duplicate } */ + var _glColorMask = (red, green, blue, alpha) => { + GLctx.colorMask(!!red, !!green, !!blue, !!alpha); + }; + var _emscripten_glColorMask = _glColorMask; + + /** @suppress {duplicate } */ + var _glCompileShader = (shader) => { + GLctx.compileShader(GL.shaders[shader]); + }; + var _emscripten_glCompileShader = _glCompileShader; + + /** @suppress {duplicate } */ + var _glCompressedTexImage2D = (target, level, internalFormat, width, height, border, imageSize, data) => { + // `data` may be null here, which means "allocate uniniitalized space but + // don't upload" in GLES parlance, but `compressedTexImage2D` requires the + // final data parameter, so we simply pass a heap view starting at zero + // effectively uploading whatever happens to be near address zero. See + // https://github.com/emscripten-core/emscripten/issues/19300. + GLctx.compressedTexImage2D(target, level, internalFormat, width, height, border, HEAPU8.subarray((data), data+imageSize)); + }; + var _emscripten_glCompressedTexImage2D = _glCompressedTexImage2D; + + /** @suppress {duplicate } */ + var _glCompressedTexSubImage2D = (target, level, xoffset, yoffset, width, height, format, imageSize, data) => { + GLctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, HEAPU8.subarray((data), data+imageSize)); + }; + var _emscripten_glCompressedTexSubImage2D = _glCompressedTexSubImage2D; + + /** @suppress {duplicate } */ + var _glCopyTexImage2D = (x0, x1, x2, x3, x4, x5, x6, x7) => GLctx.copyTexImage2D(x0, x1, x2, x3, x4, x5, x6, x7); + var _emscripten_glCopyTexImage2D = _glCopyTexImage2D; + + /** @suppress {duplicate } */ + var _glCopyTexSubImage2D = (x0, x1, x2, x3, x4, x5, x6, x7) => GLctx.copyTexSubImage2D(x0, x1, x2, x3, x4, x5, x6, x7); + var _emscripten_glCopyTexSubImage2D = _glCopyTexSubImage2D; + + /** @suppress {duplicate } */ + var _glCreateProgram = () => { + var id = GL.getNewId(GL.programs); + var program = GLctx.createProgram(); + // Store additional information needed for each shader program: + program.name = id; + // Lazy cache results of + // glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH/GL_ACTIVE_ATTRIBUTE_MAX_LENGTH/GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) + program.maxUniformLength = program.maxAttributeLength = program.maxUniformBlockNameLength = 0; + program.uniformIdCounter = 1; + GL.programs[id] = program; + return id; + }; + var _emscripten_glCreateProgram = _glCreateProgram; + + /** @suppress {duplicate } */ + var _glCreateShader = (shaderType) => { + var id = GL.getNewId(GL.shaders); + GL.shaders[id] = GLctx.createShader(shaderType); + + return id; + }; + var _emscripten_glCreateShader = _glCreateShader; + + /** @suppress {duplicate } */ + var _glCullFace = (x0) => GLctx.cullFace(x0); + var _emscripten_glCullFace = _glCullFace; + + /** @suppress {duplicate } */ + var _glDeleteBuffers = (n, buffers) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((buffers)+(i*4))>>2)]; + var buffer = GL.buffers[id]; + + // From spec: "glDeleteBuffers silently ignores 0's and names that do not + // correspond to existing buffer objects." + if (!buffer) continue; + + GLctx.deleteBuffer(buffer); + buffer.name = 0; + GL.buffers[id] = null; + + } + }; + var _emscripten_glDeleteBuffers = _glDeleteBuffers; + + /** @suppress {duplicate } */ + var _glDeleteFramebuffers = (n, framebuffers) => { + for (var i = 0; i < n; ++i) { + var id = HEAP32[(((framebuffers)+(i*4))>>2)]; + var framebuffer = GL.framebuffers[id]; + if (!framebuffer) continue; // GL spec: "glDeleteFramebuffers silently ignores 0s and names that do not correspond to existing framebuffer objects". + GLctx.deleteFramebuffer(framebuffer); + framebuffer.name = 0; + GL.framebuffers[id] = null; + } + }; + var _emscripten_glDeleteFramebuffers = _glDeleteFramebuffers; + + /** @suppress {duplicate } */ + var _glDeleteProgram = (id) => { + if (!id) return; + var program = GL.programs[id]; + if (!program) { + // glDeleteProgram actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + GLctx.deleteProgram(program); + program.name = 0; + GL.programs[id] = null; + }; + var _emscripten_glDeleteProgram = _glDeleteProgram; + + /** @suppress {duplicate } */ + var _glDeleteQueriesEXT = (n, ids) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((ids)+(i*4))>>2)]; + var query = GL.queries[id]; + if (!query) continue; // GL spec: "unused names in ids are ignored, as is the name zero." + GLctx.disjointTimerQueryExt['deleteQueryEXT'](query); + GL.queries[id] = null; + } + }; + var _emscripten_glDeleteQueriesEXT = _glDeleteQueriesEXT; + + /** @suppress {duplicate } */ + var _glDeleteRenderbuffers = (n, renderbuffers) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((renderbuffers)+(i*4))>>2)]; + var renderbuffer = GL.renderbuffers[id]; + if (!renderbuffer) continue; // GL spec: "glDeleteRenderbuffers silently ignores 0s and names that do not correspond to existing renderbuffer objects". + GLctx.deleteRenderbuffer(renderbuffer); + renderbuffer.name = 0; + GL.renderbuffers[id] = null; + } + }; + var _emscripten_glDeleteRenderbuffers = _glDeleteRenderbuffers; + + /** @suppress {duplicate } */ + var _glDeleteShader = (id) => { + if (!id) return; + var shader = GL.shaders[id]; + if (!shader) { + // glDeleteShader actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + GLctx.deleteShader(shader); + GL.shaders[id] = null; + }; + var _emscripten_glDeleteShader = _glDeleteShader; + + /** @suppress {duplicate } */ + var _glDeleteTextures = (n, textures) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((textures)+(i*4))>>2)]; + var texture = GL.textures[id]; + // GL spec: "glDeleteTextures silently ignores 0s and names that do not + // correspond to existing textures". + if (!texture) continue; + GLctx.deleteTexture(texture); + texture.name = 0; + GL.textures[id] = null; + } + }; + var _emscripten_glDeleteTextures = _glDeleteTextures; + + + /** @suppress {duplicate } */ + var _glDeleteVertexArrays = (n, vaos) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((vaos)+(i*4))>>2)]; + GLctx.deleteVertexArray(GL.vaos[id]); + GL.vaos[id] = null; + } + }; + /** @suppress {duplicate } */ + var _glDeleteVertexArraysOES = _glDeleteVertexArrays; + var _emscripten_glDeleteVertexArraysOES = _glDeleteVertexArraysOES; + + /** @suppress {duplicate } */ + var _glDepthFunc = (x0) => GLctx.depthFunc(x0); + var _emscripten_glDepthFunc = _glDepthFunc; + + /** @suppress {duplicate } */ + var _glDepthMask = (flag) => { + GLctx.depthMask(!!flag); + }; + var _emscripten_glDepthMask = _glDepthMask; + + /** @suppress {duplicate } */ + var _glDepthRangef = (x0, x1) => GLctx.depthRange(x0, x1); + var _emscripten_glDepthRangef = _glDepthRangef; + + /** @suppress {duplicate } */ + var _glDetachShader = (program, shader) => { + GLctx.detachShader(GL.programs[program], GL.shaders[shader]); + }; + var _emscripten_glDetachShader = _glDetachShader; + + /** @suppress {duplicate } */ + var _glDisable = (x0) => GLctx.disable(x0); + var _emscripten_glDisable = _glDisable; + + /** @suppress {duplicate } */ + var _glDisableVertexAttribArray = (index) => { + GLctx.disableVertexAttribArray(index); + }; + var _emscripten_glDisableVertexAttribArray = _glDisableVertexAttribArray; + + /** @suppress {duplicate } */ + var _glDrawArrays = (mode, first, count) => { + + GLctx.drawArrays(mode, first, count); + + }; + var _emscripten_glDrawArrays = _glDrawArrays; + + + /** @suppress {duplicate } */ + var _glDrawArraysInstanced = (mode, first, count, primcount) => { + GLctx.drawArraysInstanced(mode, first, count, primcount); + }; + /** @suppress {duplicate } */ + var _glDrawArraysInstancedANGLE = _glDrawArraysInstanced; + var _emscripten_glDrawArraysInstancedANGLE = _glDrawArraysInstancedANGLE; + + + var tempFixedLengthArray = []; + + /** @suppress {duplicate } */ + var _glDrawBuffers = (n, bufs) => { + + var bufArray = tempFixedLengthArray[n]; + for (var i = 0; i < n; i++) { + bufArray[i] = HEAP32[(((bufs)+(i*4))>>2)]; + } + + GLctx.drawBuffers(bufArray); + }; + /** @suppress {duplicate } */ + var _glDrawBuffersWEBGL = _glDrawBuffers; + var _emscripten_glDrawBuffersWEBGL = _glDrawBuffersWEBGL; + + /** @suppress {duplicate } */ + var _glDrawElements = (mode, count, type, indices) => { + + GLctx.drawElements(mode, count, type, indices); + + }; + var _emscripten_glDrawElements = _glDrawElements; + + + /** @suppress {duplicate } */ + var _glDrawElementsInstanced = (mode, count, type, indices, primcount) => { + GLctx.drawElementsInstanced(mode, count, type, indices, primcount); + }; + /** @suppress {duplicate } */ + var _glDrawElementsInstancedANGLE = _glDrawElementsInstanced; + var _emscripten_glDrawElementsInstancedANGLE = _glDrawElementsInstancedANGLE; + + /** @suppress {duplicate } */ + var _glEnable = (x0) => GLctx.enable(x0); + var _emscripten_glEnable = _glEnable; + + /** @suppress {duplicate } */ + var _glEnableVertexAttribArray = (index) => { + GLctx.enableVertexAttribArray(index); + }; + var _emscripten_glEnableVertexAttribArray = _glEnableVertexAttribArray; + + /** @suppress {duplicate } */ + var _glEndQueryEXT = (target) => { + GLctx.disjointTimerQueryExt['endQueryEXT'](target); + }; + var _emscripten_glEndQueryEXT = _glEndQueryEXT; + + /** @suppress {duplicate } */ + var _glFinish = () => GLctx.finish(); + var _emscripten_glFinish = _glFinish; + + /** @suppress {duplicate } */ + var _glFlush = () => GLctx.flush(); + var _emscripten_glFlush = _glFlush; + + /** @suppress {duplicate } */ + var _glFramebufferRenderbuffer = (target, attachment, renderbuffertarget, renderbuffer) => { + GLctx.framebufferRenderbuffer(target, attachment, renderbuffertarget, + GL.renderbuffers[renderbuffer]); + }; + var _emscripten_glFramebufferRenderbuffer = _glFramebufferRenderbuffer; + + /** @suppress {duplicate } */ + var _glFramebufferTexture2D = (target, attachment, textarget, texture, level) => { + GLctx.framebufferTexture2D(target, attachment, textarget, + GL.textures[texture], level); + }; + var _emscripten_glFramebufferTexture2D = _glFramebufferTexture2D; + + /** @suppress {duplicate } */ + var _glFrontFace = (x0) => GLctx.frontFace(x0); + var _emscripten_glFrontFace = _glFrontFace; + + /** @suppress {duplicate } */ + var _glGenBuffers = (n, buffers) => { + GL.genObject(n, buffers, 'createBuffer', GL.buffers + ); + }; + var _emscripten_glGenBuffers = _glGenBuffers; + + /** @suppress {duplicate } */ + var _glGenFramebuffers = (n, ids) => { + GL.genObject(n, ids, 'createFramebuffer', GL.framebuffers + ); + }; + var _emscripten_glGenFramebuffers = _glGenFramebuffers; + + /** @suppress {duplicate } */ + var _glGenQueriesEXT = (n, ids) => { + for (var i = 0; i < n; i++) { + var query = GLctx.disjointTimerQueryExt['createQueryEXT'](); + if (!query) { + GL.recordError(0x502 /* GL_INVALID_OPERATION */); + while (i < n) HEAP32[(((ids)+(i++*4))>>2)] = 0; + return; + } + var id = GL.getNewId(GL.queries); + query.name = id; + GL.queries[id] = query; + HEAP32[(((ids)+(i*4))>>2)] = id; + } + }; + var _emscripten_glGenQueriesEXT = _glGenQueriesEXT; + + /** @suppress {duplicate } */ + var _glGenRenderbuffers = (n, renderbuffers) => { + GL.genObject(n, renderbuffers, 'createRenderbuffer', GL.renderbuffers + ); + }; + var _emscripten_glGenRenderbuffers = _glGenRenderbuffers; + + /** @suppress {duplicate } */ + var _glGenTextures = (n, textures) => { + GL.genObject(n, textures, 'createTexture', GL.textures + ); + }; + var _emscripten_glGenTextures = _glGenTextures; + + + /** @suppress {duplicate } */ + var _glGenVertexArrays = (n, arrays) => { + GL.genObject(n, arrays, 'createVertexArray', GL.vaos + ); + }; + /** @suppress {duplicate } */ + var _glGenVertexArraysOES = _glGenVertexArrays; + var _emscripten_glGenVertexArraysOES = _glGenVertexArraysOES; + + /** @suppress {duplicate } */ + var _glGenerateMipmap = (x0) => GLctx.generateMipmap(x0); + var _emscripten_glGenerateMipmap = _glGenerateMipmap; + + + var __glGetActiveAttribOrUniform = (funcName, program, index, bufSize, length, size, type, name) => { + program = GL.programs[program]; + var info = GLctx[funcName](program, index); + if (info) { + // If an error occurs, nothing will be written to length, size and type and name. + var numBytesWrittenExclNull = name && stringToUTF8(info.name, name, bufSize); + if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull; + if (size) HEAP32[((size)>>2)] = info.size; + if (type) HEAP32[((type)>>2)] = info.type; + } + }; + + /** @suppress {duplicate } */ + var _glGetActiveAttrib = (program, index, bufSize, length, size, type, name) => { + __glGetActiveAttribOrUniform('getActiveAttrib', program, index, bufSize, length, size, type, name); + }; + var _emscripten_glGetActiveAttrib = _glGetActiveAttrib; + + + /** @suppress {duplicate } */ + var _glGetActiveUniform = (program, index, bufSize, length, size, type, name) => { + __glGetActiveAttribOrUniform('getActiveUniform', program, index, bufSize, length, size, type, name); + }; + var _emscripten_glGetActiveUniform = _glGetActiveUniform; + + /** @suppress {duplicate } */ + var _glGetAttachedShaders = (program, maxCount, count, shaders) => { + var result = GLctx.getAttachedShaders(GL.programs[program]); + var len = result.length; + if (len > maxCount) { + len = maxCount; + } + HEAP32[((count)>>2)] = len; + for (var i = 0; i < len; ++i) { + var id = GL.shaders.indexOf(result[i]); + HEAP32[(((shaders)+(i*4))>>2)] = id; + } + }; + var _emscripten_glGetAttachedShaders = _glGetAttachedShaders; + + + /** @suppress {duplicate } */ + var _glGetAttribLocation = (program, name) => { + return GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); + }; + var _emscripten_glGetAttribLocation = _glGetAttribLocation; + + var readI53FromI64 = (ptr) => { + return HEAPU32[((ptr)>>2)] + HEAP32[(((ptr)+(4))>>2)] * 4294967296; + }; + + var readI53FromU64 = (ptr) => { + return HEAPU32[((ptr)>>2)] + HEAPU32[(((ptr)+(4))>>2)] * 4294967296; + }; + var writeI53ToI64 = (ptr, num) => { + HEAPU32[((ptr)>>2)] = num; + var lower = HEAPU32[((ptr)>>2)]; + HEAPU32[(((ptr)+(4))>>2)] = (num - lower)/4294967296; + var deserialized = (num >= 0) ? readI53FromU64(ptr) : readI53FromI64(ptr); + var offset = ((ptr)>>2); + if (deserialized != num) warnOnce(`writeI53ToI64() out of range: serialized JS Number ${num} to Wasm heap as bytes lo=${ptrToString(HEAPU32[offset])}, hi=${ptrToString(HEAPU32[offset+1])}, which deserializes back to ${deserialized} instead!`); + }; + + var emscriptenWebGLGet = (name_, p, type) => { + // Guard against user passing a null pointer. + // Note that GLES2 spec does not say anything about how passing a null + // pointer should be treated. Testing on desktop core GL 3, the application + // crashes on glGetIntegerv to a null pointer, but better to report an error + // instead of doing anything random. + if (!p) { + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + var ret = undefined; + switch (name_) { // Handle a few trivial GLES values + case 0x8DFA: // GL_SHADER_COMPILER + ret = 1; + break; + case 0x8DF8: // GL_SHADER_BINARY_FORMATS + if (type != 0 && type != 1) { + GL.recordError(0x500); // GL_INVALID_ENUM + } + // Do not write anything to the out pointer, since no binary formats are + // supported. + return; + case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS + ret = 0; + break; + case 0x86A2: // GL_NUM_COMPRESSED_TEXTURE_FORMATS + // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete + // since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be + // queried for length), so implement it ourselves to allow C++ GLES2 + // code get the length. + var formats = GLctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/); + ret = formats ? formats.length : 0; + break; + + } + + if (ret === undefined) { + var result = GLctx.getParameter(name_); + switch (typeof result) { + case "number": + ret = result; + break; + case "boolean": + ret = result ? 1 : 0; + break; + case "string": + GL.recordError(0x500); // GL_INVALID_ENUM + return; + case "object": + if (result === null) { + // null is a valid result for some (e.g., which buffer is bound - + // perhaps nothing is bound), but otherwise can mean an invalid + // name_, which we need to report as an error + switch (name_) { + case 0x8894: // ARRAY_BUFFER_BINDING + case 0x8B8D: // CURRENT_PROGRAM + case 0x8895: // ELEMENT_ARRAY_BUFFER_BINDING + case 0x8CA6: // FRAMEBUFFER_BINDING or DRAW_FRAMEBUFFER_BINDING + case 0x8CA7: // RENDERBUFFER_BINDING + case 0x8069: // TEXTURE_BINDING_2D + case 0x85B5: // WebGL 2 GL_VERTEX_ARRAY_BINDING, or WebGL 1 extension OES_vertex_array_object GL_VERTEX_ARRAY_BINDING_OES + case 0x8514: { // TEXTURE_BINDING_CUBE_MAP + ret = 0; + break; + } + default: { + GL.recordError(0x500); // GL_INVALID_ENUM + return; + } + } + } else if (result instanceof Float32Array || + result instanceof Uint32Array || + result instanceof Int32Array || + result instanceof Array) { + for (var i = 0; i < result.length; ++i) { + switch (type) { + case 0: HEAP32[(((p)+(i*4))>>2)] = result[i]; break; + case 2: HEAPF32[(((p)+(i*4))>>2)] = result[i]; break; + case 4: HEAP8[(p)+(i)] = result[i] ? 1 : 0; break; + } + } + return; + } else { + try { + ret = result.name | 0; + } catch(e) { + GL.recordError(0x500); // GL_INVALID_ENUM + err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`); + return; + } + } + break; + default: + GL.recordError(0x500); // GL_INVALID_ENUM + err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof(result)}!`); + return; + } + } + + switch (type) { + case 1: writeI53ToI64(p, ret); break; + case 0: HEAP32[((p)>>2)] = ret; break; + case 2: HEAPF32[((p)>>2)] = ret; break; + case 4: HEAP8[p] = ret ? 1 : 0; break; + } + }; + + /** @suppress {duplicate } */ + var _glGetBooleanv = (name_, p) => emscriptenWebGLGet(name_, p, 4); + var _emscripten_glGetBooleanv = _glGetBooleanv; + + /** @suppress {duplicate } */ + var _glGetBufferParameteriv = (target, value, data) => { + if (!data) { + // GLES2 specification does not specify how to behave if data is a null + // pointer. Since calling this function does not make sense if data == + // null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((data)>>2)] = GLctx.getBufferParameter(target, value); + }; + var _emscripten_glGetBufferParameteriv = _glGetBufferParameteriv; + + /** @suppress {duplicate } */ + var _glGetError = () => { + var error = GLctx.getError() || GL.lastError; + GL.lastError = 0/*GL_NO_ERROR*/; + return error; + }; + var _emscripten_glGetError = _glGetError; + + + /** @suppress {duplicate } */ + var _glGetFloatv = (name_, p) => emscriptenWebGLGet(name_, p, 2); + var _emscripten_glGetFloatv = _glGetFloatv; + + /** @suppress {duplicate } */ + var _glGetFramebufferAttachmentParameteriv = (target, attachment, pname, params) => { + var result = GLctx.getFramebufferAttachmentParameter(target, attachment, pname); + if (result instanceof WebGLRenderbuffer || + result instanceof WebGLTexture) { + result = result.name | 0; + } + HEAP32[((params)>>2)] = result; + }; + var _emscripten_glGetFramebufferAttachmentParameteriv = _glGetFramebufferAttachmentParameteriv; + + + /** @suppress {duplicate } */ + var _glGetIntegerv = (name_, p) => emscriptenWebGLGet(name_, p, 0); + var _emscripten_glGetIntegerv = _glGetIntegerv; + + /** @suppress {duplicate } */ + var _glGetProgramInfoLog = (program, maxLength, length, infoLog) => { + var log = GLctx.getProgramInfoLog(GL.programs[program]); + if (log === null) log = '(unknown error)'; + var numBytesWrittenExclNull = (maxLength > 0 && infoLog) ? stringToUTF8(log, infoLog, maxLength) : 0; + if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull; + }; + var _emscripten_glGetProgramInfoLog = _glGetProgramInfoLog; + + /** @suppress {duplicate } */ + var _glGetProgramiv = (program, pname, p) => { + if (!p) { + // GLES2 specification does not specify how to behave if p is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + + if (program >= GL.counter) { + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + + program = GL.programs[program]; + + if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH + var log = GLctx.getProgramInfoLog(program); + if (log === null) log = '(unknown error)'; + HEAP32[((p)>>2)] = log.length + 1; + } else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) { + if (!program.maxUniformLength) { + var numActiveUniforms = GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); + for (var i = 0; i < numActiveUniforms; ++i) { + program.maxUniformLength = Math.max(program.maxUniformLength, GLctx.getActiveUniform(program, i).name.length+1); + } + } + HEAP32[((p)>>2)] = program.maxUniformLength; + } else if (pname == 0x8B8A /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */) { + if (!program.maxAttributeLength) { + var numActiveAttributes = GLctx.getProgramParameter(program, 0x8B89/*GL_ACTIVE_ATTRIBUTES*/); + for (var i = 0; i < numActiveAttributes; ++i) { + program.maxAttributeLength = Math.max(program.maxAttributeLength, GLctx.getActiveAttrib(program, i).name.length+1); + } + } + HEAP32[((p)>>2)] = program.maxAttributeLength; + } else if (pname == 0x8A35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */) { + if (!program.maxUniformBlockNameLength) { + var numActiveUniformBlocks = GLctx.getProgramParameter(program, 0x8A36/*GL_ACTIVE_UNIFORM_BLOCKS*/); + for (var i = 0; i < numActiveUniformBlocks; ++i) { + program.maxUniformBlockNameLength = Math.max(program.maxUniformBlockNameLength, GLctx.getActiveUniformBlockName(program, i).length+1); + } + } + HEAP32[((p)>>2)] = program.maxUniformBlockNameLength; + } else { + HEAP32[((p)>>2)] = GLctx.getProgramParameter(program, pname); + } + }; + var _emscripten_glGetProgramiv = _glGetProgramiv; + + + /** @suppress {duplicate } */ + var _glGetQueryObjecti64vEXT = (id, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense + // if p == null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + var query = GL.queries[id]; + var param; + { + param = GLctx.disjointTimerQueryExt['getQueryObjectEXT'](query, pname); + } + var ret; + if (typeof param == 'boolean') { + ret = param ? 1 : 0; + } else { + ret = param; + } + writeI53ToI64(params, ret); + }; + var _emscripten_glGetQueryObjecti64vEXT = _glGetQueryObjecti64vEXT; + + /** @suppress {duplicate } */ + var _glGetQueryObjectivEXT = (id, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense + // if p == null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + var query = GL.queries[id]; + var param = GLctx.disjointTimerQueryExt['getQueryObjectEXT'](query, pname); + var ret; + if (typeof param == 'boolean') { + ret = param ? 1 : 0; + } else { + ret = param; + } + HEAP32[((params)>>2)] = ret; + }; + var _emscripten_glGetQueryObjectivEXT = _glGetQueryObjectivEXT; + + + /** @suppress {duplicate } */ + var _glGetQueryObjectui64vEXT = _glGetQueryObjecti64vEXT; + var _emscripten_glGetQueryObjectui64vEXT = _glGetQueryObjectui64vEXT; + + + /** @suppress {duplicate } */ + var _glGetQueryObjectuivEXT = _glGetQueryObjectivEXT; + var _emscripten_glGetQueryObjectuivEXT = _glGetQueryObjectuivEXT; + + /** @suppress {duplicate } */ + var _glGetQueryivEXT = (target, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense + // if p == null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((params)>>2)] = GLctx.disjointTimerQueryExt['getQueryEXT'](target, pname); + }; + var _emscripten_glGetQueryivEXT = _glGetQueryivEXT; + + /** @suppress {duplicate } */ + var _glGetRenderbufferParameteriv = (target, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense + // if params == null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((params)>>2)] = GLctx.getRenderbufferParameter(target, pname); + }; + var _emscripten_glGetRenderbufferParameteriv = _glGetRenderbufferParameteriv; + + + /** @suppress {duplicate } */ + var _glGetShaderInfoLog = (shader, maxLength, length, infoLog) => { + var log = GLctx.getShaderInfoLog(GL.shaders[shader]); + if (log === null) log = '(unknown error)'; + var numBytesWrittenExclNull = (maxLength > 0 && infoLog) ? stringToUTF8(log, infoLog, maxLength) : 0; + if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull; + }; + var _emscripten_glGetShaderInfoLog = _glGetShaderInfoLog; + + /** @suppress {duplicate } */ + var _glGetShaderPrecisionFormat = (shaderType, precisionType, range, precision) => { + var result = GLctx.getShaderPrecisionFormat(shaderType, precisionType); + HEAP32[((range)>>2)] = result.rangeMin; + HEAP32[(((range)+(4))>>2)] = result.rangeMax; + HEAP32[((precision)>>2)] = result.precision; + }; + var _emscripten_glGetShaderPrecisionFormat = _glGetShaderPrecisionFormat; + + /** @suppress {duplicate } */ + var _glGetShaderSource = (shader, bufSize, length, source) => { + var result = GLctx.getShaderSource(GL.shaders[shader]); + if (!result) return; // If an error occurs, nothing will be written to length or source. + var numBytesWrittenExclNull = (bufSize > 0 && source) ? stringToUTF8(result, source, bufSize) : 0; + if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull; + }; + var _emscripten_glGetShaderSource = _glGetShaderSource; + + /** @suppress {duplicate } */ + var _glGetShaderiv = (shader, pname, p) => { + if (!p) { + // GLES2 specification does not specify how to behave if p is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH + var log = GLctx.getShaderInfoLog(GL.shaders[shader]); + if (log === null) log = '(unknown error)'; + // The GLES2 specification says that if the shader has an empty info log, + // a value of 0 is returned. Otherwise the log has a null char appended. + // (An empty string is falsey, so we can just check that instead of + // looking at log.length.) + var logLength = log ? log.length + 1 : 0; + HEAP32[((p)>>2)] = logLength; + } else if (pname == 0x8B88) { // GL_SHADER_SOURCE_LENGTH + var source = GLctx.getShaderSource(GL.shaders[shader]); + // source may be a null, or the empty string, both of which are falsey + // values that we report a 0 length for. + var sourceLength = source ? source.length + 1 : 0; + HEAP32[((p)>>2)] = sourceLength; + } else { + HEAP32[((p)>>2)] = GLctx.getShaderParameter(GL.shaders[shader], pname); + } + }; + var _emscripten_glGetShaderiv = _glGetShaderiv; + + + + var webglGetExtensions = function $webglGetExtensions() { + var exts = getEmscriptenSupportedExtensions(GLctx); + exts = exts.concat(exts.map((e) => "GL_" + e)); + return exts; + }; + + /** @suppress {duplicate } */ + var _glGetString = (name_) => { + var ret = GL.stringCache[name_]; + if (!ret) { + switch (name_) { + case 0x1F03 /* GL_EXTENSIONS */: + ret = stringToNewUTF8(webglGetExtensions().join(' ')); + break; + case 0x1F00 /* GL_VENDOR */: + case 0x1F01 /* GL_RENDERER */: + case 0x9245 /* UNMASKED_VENDOR_WEBGL */: + case 0x9246 /* UNMASKED_RENDERER_WEBGL */: + var s = GLctx.getParameter(name_); + if (!s) { + GL.recordError(0x500/*GL_INVALID_ENUM*/); + } + ret = s ? stringToNewUTF8(s) : 0; + break; + + case 0x1F02 /* GL_VERSION */: + var webGLVersion = GLctx.getParameter(0x1F02 /*GL_VERSION*/); + // return GLES version string corresponding to the version of the WebGL context + var glVersion = `OpenGL ES 2.0 (${webGLVersion})`; + ret = stringToNewUTF8(glVersion); + break; + case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */: + var glslVersion = GLctx.getParameter(0x8B8C /*GL_SHADING_LANGUAGE_VERSION*/); + // extract the version number 'N.M' from the string 'WebGL GLSL ES N.M ...' + var ver_re = /^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/; + var ver_num = glslVersion.match(ver_re); + if (ver_num !== null) { + if (ver_num[1].length == 3) ver_num[1] = ver_num[1] + '0'; // ensure minor version has 2 digits + glslVersion = `OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`; + } + ret = stringToNewUTF8(glslVersion); + break; + default: + GL.recordError(0x500/*GL_INVALID_ENUM*/); + // fall through + } + GL.stringCache[name_] = ret; + } + return ret; + }; + var _emscripten_glGetString = _glGetString; + + /** @suppress {duplicate } */ + var _glGetTexParameterfv = (target, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAPF32[((params)>>2)] = GLctx.getTexParameter(target, pname); + }; + var _emscripten_glGetTexParameterfv = _glGetTexParameterfv; + + /** @suppress {duplicate } */ + var _glGetTexParameteriv = (target, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((params)>>2)] = GLctx.getTexParameter(target, pname); + }; + var _emscripten_glGetTexParameteriv = _glGetTexParameteriv; + + /** @suppress {checkTypes} */ + var jstoi_q = (str) => parseInt(str); + + /** @noinline */ + var webglGetLeftBracePos = (name) => name.slice(-1) == ']' && name.lastIndexOf('['); + + var webglPrepareUniformLocationsBeforeFirstUse = (program) => { + var uniformLocsById = program.uniformLocsById, // Maps GLuint -> WebGLUniformLocation + uniformSizeAndIdsByName = program.uniformSizeAndIdsByName, // Maps name -> [uniform array length, GLuint] + i, j; + + // On the first time invocation of glGetUniformLocation on this shader program: + // initialize cache data structures and discover which uniforms are arrays. + if (!uniformLocsById) { + // maps GLint integer locations to WebGLUniformLocations + program.uniformLocsById = uniformLocsById = {}; + // maps integer locations back to uniform name strings, so that we can lazily fetch uniform array locations + program.uniformArrayNamesById = {}; + + var numActiveUniforms = GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); + for (i = 0; i < numActiveUniforms; ++i) { + var u = GLctx.getActiveUniform(program, i); + var nm = u.name; + var sz = u.size; + var lb = webglGetLeftBracePos(nm); + var arrayName = lb > 0 ? nm.slice(0, lb) : nm; + + // Assign a new location. + var id = program.uniformIdCounter; + program.uniformIdCounter += sz; + // Eagerly get the location of the uniformArray[0] base element. + // The remaining indices >0 will be left for lazy evaluation to + // improve performance. Those may never be needed to fetch, if the + // application fills arrays always in full starting from the first + // element of the array. + uniformSizeAndIdsByName[arrayName] = [sz, id]; + + // Store placeholder integers in place that highlight that these + // >0 index locations are array indices pending population. + for (j = 0; j < sz; ++j) { + uniformLocsById[id] = j; + program.uniformArrayNamesById[id++] = arrayName; + } + } + } + }; + + + + /** @suppress {duplicate } */ + var _glGetUniformLocation = (program, name) => { + + name = UTF8ToString(name); + + if (program = GL.programs[program]) { + webglPrepareUniformLocationsBeforeFirstUse(program); + var uniformLocsById = program.uniformLocsById; // Maps GLuint -> WebGLUniformLocation + var arrayIndex = 0; + var uniformBaseName = name; + + // Invariant: when populating integer IDs for uniform locations, we must + // maintain the precondition that arrays reside in contiguous addresses, + // i.e. for a 'vec4 colors[10];', colors[4] must be at location + // colors[0]+4. However, user might call glGetUniformLocation(program, + // "colors") for an array, so we cannot discover based on the user input + // arguments whether the uniform we are dealing with is an array. The only + // way to discover which uniforms are arrays is to enumerate over all the + // active uniforms in the program. + var leftBrace = webglGetLeftBracePos(name); + + // If user passed an array accessor "[index]", parse the array index off the accessor. + if (leftBrace > 0) { + arrayIndex = jstoi_q(name.slice(leftBrace + 1)) >>> 0; // "index]", coerce parseInt(']') with >>>0 to treat "foo[]" as "foo[0]" and foo[-1] as unsigned out-of-bounds. + uniformBaseName = name.slice(0, leftBrace); + } + + // Have we cached the location of this uniform before? + // A pair [array length, GLint of the uniform location] + var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName]; + + // If an uniform with this name exists, and if its index is within the + // array limits (if it's even an array), query the WebGLlocation, or + // return an existing cached location. + if (sizeAndId && arrayIndex < sizeAndId[0]) { + arrayIndex += sizeAndId[1]; // Add the base location of the uniform to the array index offset. + if ((uniformLocsById[arrayIndex] = uniformLocsById[arrayIndex] || GLctx.getUniformLocation(program, name))) { + return arrayIndex; + } + } + } + else { + // N.b. we are currently unable to distinguish between GL program IDs that + // never existed vs GL program IDs that have been deleted, so report + // GL_INVALID_VALUE in both cases. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + } + return -1; + }; + var _emscripten_glGetUniformLocation = _glGetUniformLocation; + + var webglGetUniformLocation = (location) => { + var p = GLctx.currentProgram; + + if (p) { + var webglLoc = p.uniformLocsById[location]; + // p.uniformLocsById[location] stores either an integer, or a + // WebGLUniformLocation. + // If an integer, we have not yet bound the location, so do it now. The + // integer value specifies the array index we should bind to. + if (typeof webglLoc == 'number') { + p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[location] + (webglLoc > 0 ? `[${webglLoc}]` : '')); + } + // Else an already cached WebGLUniformLocation, return it. + return webglLoc; + } else { + GL.recordError(0x502/*GL_INVALID_OPERATION*/); + } + }; + + + /** @suppress{checkTypes} */ + var emscriptenWebGLGetUniform = (program, location, params, type) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null + // pointer. Since calling this function does not make sense if params == + // null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + program = GL.programs[program]; + webglPrepareUniformLocationsBeforeFirstUse(program); + var data = GLctx.getUniform(program, webglGetUniformLocation(location)); + if (typeof data == 'number' || typeof data == 'boolean') { + switch (type) { + case 0: HEAP32[((params)>>2)] = data; break; + case 2: HEAPF32[((params)>>2)] = data; break; + } + } else { + for (var i = 0; i < data.length; i++) { + switch (type) { + case 0: HEAP32[(((params)+(i*4))>>2)] = data[i]; break; + case 2: HEAPF32[(((params)+(i*4))>>2)] = data[i]; break; + } + } + } + }; + + /** @suppress {duplicate } */ + var _glGetUniformfv = (program, location, params) => { + emscriptenWebGLGetUniform(program, location, params, 2); + }; + var _emscripten_glGetUniformfv = _glGetUniformfv; + + + /** @suppress {duplicate } */ + var _glGetUniformiv = (program, location, params) => { + emscriptenWebGLGetUniform(program, location, params, 0); + }; + var _emscripten_glGetUniformiv = _glGetUniformiv; + + /** @suppress {duplicate } */ + var _glGetVertexAttribPointerv = (index, pname, pointer) => { + if (!pointer) { + // GLES2 specification does not specify how to behave if pointer is a null + // pointer. Since calling this function does not make sense if pointer == + // null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((pointer)>>2)] = GLctx.getVertexAttribOffset(index, pname); + }; + var _emscripten_glGetVertexAttribPointerv = _glGetVertexAttribPointerv; + + /** @suppress{checkTypes} */ + var emscriptenWebGLGetVertexAttrib = (index, pname, params, type) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null + // pointer. Since calling this function does not make sense if params == + // null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + var data = GLctx.getVertexAttrib(index, pname); + if (pname == 0x889F/*VERTEX_ATTRIB_ARRAY_BUFFER_BINDING*/) { + HEAP32[((params)>>2)] = data && data["name"]; + } else if (typeof data == 'number' || typeof data == 'boolean') { + switch (type) { + case 0: HEAP32[((params)>>2)] = data; break; + case 2: HEAPF32[((params)>>2)] = data; break; + case 5: HEAP32[((params)>>2)] = Math.fround(data); break; + } + } else { + for (var i = 0; i < data.length; i++) { + switch (type) { + case 0: HEAP32[(((params)+(i*4))>>2)] = data[i]; break; + case 2: HEAPF32[(((params)+(i*4))>>2)] = data[i]; break; + case 5: HEAP32[(((params)+(i*4))>>2)] = Math.fround(data[i]); break; + } + } + } + }; + + /** @suppress {duplicate } */ + var _glGetVertexAttribfv = (index, pname, params) => { + // N.B. This function may only be called if the vertex attribute was + // specified using the function glVertexAttrib*f(), otherwise the results + // are undefined. (GLES3 spec 6.1.12) + emscriptenWebGLGetVertexAttrib(index, pname, params, 2); + }; + var _emscripten_glGetVertexAttribfv = _glGetVertexAttribfv; + + + /** @suppress {duplicate } */ + var _glGetVertexAttribiv = (index, pname, params) => { + // N.B. This function may only be called if the vertex attribute was + // specified using the function glVertexAttrib*f(), otherwise the results + // are undefined. (GLES3 spec 6.1.12) + emscriptenWebGLGetVertexAttrib(index, pname, params, 5); + }; + var _emscripten_glGetVertexAttribiv = _glGetVertexAttribiv; + + /** @suppress {duplicate } */ + var _glHint = (x0, x1) => GLctx.hint(x0, x1); + var _emscripten_glHint = _glHint; + + /** @suppress {duplicate } */ + var _glIsBuffer = (buffer) => { + var b = GL.buffers[buffer]; + if (!b) return 0; + return GLctx.isBuffer(b); + }; + var _emscripten_glIsBuffer = _glIsBuffer; + + /** @suppress {duplicate } */ + var _glIsEnabled = (x0) => GLctx.isEnabled(x0); + var _emscripten_glIsEnabled = _glIsEnabled; + + /** @suppress {duplicate } */ + var _glIsFramebuffer = (framebuffer) => { + var fb = GL.framebuffers[framebuffer]; + if (!fb) return 0; + return GLctx.isFramebuffer(fb); + }; + var _emscripten_glIsFramebuffer = _glIsFramebuffer; + + /** @suppress {duplicate } */ + var _glIsProgram = (program) => { + program = GL.programs[program]; + if (!program) return 0; + return GLctx.isProgram(program); + }; + var _emscripten_glIsProgram = _glIsProgram; + + /** @suppress {duplicate } */ + var _glIsQueryEXT = (id) => { + var query = GL.queries[id]; + if (!query) return 0; + return GLctx.disjointTimerQueryExt['isQueryEXT'](query); + }; + var _emscripten_glIsQueryEXT = _glIsQueryEXT; + + /** @suppress {duplicate } */ + var _glIsRenderbuffer = (renderbuffer) => { + var rb = GL.renderbuffers[renderbuffer]; + if (!rb) return 0; + return GLctx.isRenderbuffer(rb); + }; + var _emscripten_glIsRenderbuffer = _glIsRenderbuffer; + + /** @suppress {duplicate } */ + var _glIsShader = (shader) => { + var s = GL.shaders[shader]; + if (!s) return 0; + return GLctx.isShader(s); + }; + var _emscripten_glIsShader = _glIsShader; + + /** @suppress {duplicate } */ + var _glIsTexture = (id) => { + var texture = GL.textures[id]; + if (!texture) return 0; + return GLctx.isTexture(texture); + }; + var _emscripten_glIsTexture = _glIsTexture; + + + /** @suppress {duplicate } */ + var _glIsVertexArray = (array) => { + + var vao = GL.vaos[array]; + if (!vao) return 0; + return GLctx.isVertexArray(vao); + }; + /** @suppress {duplicate } */ + var _glIsVertexArrayOES = _glIsVertexArray; + var _emscripten_glIsVertexArrayOES = _glIsVertexArrayOES; + + /** @suppress {duplicate } */ + var _glLineWidth = (x0) => GLctx.lineWidth(x0); + var _emscripten_glLineWidth = _glLineWidth; + + /** @suppress {duplicate } */ + var _glLinkProgram = (program) => { + program = GL.programs[program]; + GLctx.linkProgram(program); + // Invalidate earlier computed uniform->ID mappings, those have now become stale + program.uniformLocsById = 0; // Mark as null-like so that glGetUniformLocation() knows to populate this again. + program.uniformSizeAndIdsByName = {}; + + }; + var _emscripten_glLinkProgram = _glLinkProgram; + + /** @suppress {duplicate } */ + var _glPixelStorei = (pname, param) => { + if (pname == 3317) { + GL.unpackAlignment = param; + } else if (pname == 3314) { + GL.unpackRowLength = param; + } + GLctx.pixelStorei(pname, param); + }; + var _emscripten_glPixelStorei = _glPixelStorei; + + /** @suppress {duplicate } */ + var _glPolygonModeWEBGL = (face, mode) => { + GLctx.webglPolygonMode['polygonModeWEBGL'](face, mode); + }; + var _emscripten_glPolygonModeWEBGL = _glPolygonModeWEBGL; + + /** @suppress {duplicate } */ + var _glPolygonOffset = (x0, x1) => GLctx.polygonOffset(x0, x1); + var _emscripten_glPolygonOffset = _glPolygonOffset; + + /** @suppress {duplicate } */ + var _glPolygonOffsetClampEXT = (factor, units, clamp) => { + GLctx.extPolygonOffsetClamp['polygonOffsetClampEXT'](factor, units, clamp); + }; + var _emscripten_glPolygonOffsetClampEXT = _glPolygonOffsetClampEXT; + + /** @suppress {duplicate } */ + var _glQueryCounterEXT = (id, target) => { + GLctx.disjointTimerQueryExt['queryCounterEXT'](GL.queries[id], target); + }; + var _emscripten_glQueryCounterEXT = _glQueryCounterEXT; + + var computeUnpackAlignedImageSize = (width, height, sizePerPixel) => { + function roundedToNextMultipleOf(x, y) { + return (x + y - 1) & -y; + } + var plainRowSize = (GL.unpackRowLength || width) * sizePerPixel; + var alignedRowSize = roundedToNextMultipleOf(plainRowSize, GL.unpackAlignment); + return height * alignedRowSize; + }; + + var colorChannelsInGlTextureFormat = (format) => { + // Micro-optimizations for size: map format to size by subtracting smallest + // enum value (0x1902) from all values first. Also omit the most common + // size value (1) from the list, which is assumed by formats not on the + // list. + var colorChannels = { + // 0x1902 /* GL_DEPTH_COMPONENT */ - 0x1902: 1, + // 0x1906 /* GL_ALPHA */ - 0x1902: 1, + 5: 3, + 6: 4, + // 0x1909 /* GL_LUMINANCE */ - 0x1902: 1, + 8: 2, + 29502: 3, + 29504: 4, + }; + return colorChannels[format - 0x1902]||1; + }; + + var heapObjectForWebGLType = (type) => { + // Micro-optimization for size: Subtract lowest GL enum number (0x1400/* GL_BYTE */) from type to compare + // smaller values for the heap, for shorter generated code size. + // Also the type HEAPU16 is not tested for explicitly, but any unrecognized type will return out HEAPU16. + // (since most types are HEAPU16) + type -= 0x1400; + + if (type == 1) return HEAPU8; + + if (type == 4) return HEAP32; + + if (type == 6) return HEAPF32; + + if (type == 5 + || type == 28922 + ) + return HEAPU32; + + return HEAPU16; + }; + + var toTypedArrayIndex = (pointer, heap) => + pointer >>> (31 - Math.clz32(heap.BYTES_PER_ELEMENT)); + + var emscriptenWebGLGetTexPixelData = (type, format, width, height, pixels, internalFormat) => { + var heap = heapObjectForWebGLType(type); + var sizePerPixel = colorChannelsInGlTextureFormat(format) * heap.BYTES_PER_ELEMENT; + var bytes = computeUnpackAlignedImageSize(width, height, sizePerPixel); + return heap.subarray(toTypedArrayIndex(pixels, heap), toTypedArrayIndex(pixels + bytes, heap)); + }; + + /** @suppress {duplicate } */ + var _glReadPixels = (x, y, width, height, format, type, pixels) => { + var pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, format); + if (!pixelData) { + GL.recordError(0x500/*GL_INVALID_ENUM*/); + return; + } + GLctx.readPixels(x, y, width, height, format, type, pixelData); + }; + var _emscripten_glReadPixels = _glReadPixels; + + /** @suppress {duplicate } */ + var _glReleaseShaderCompiler = () => { + // NOP (as allowed by GLES 2.0 spec) + }; + var _emscripten_glReleaseShaderCompiler = _glReleaseShaderCompiler; + + /** @suppress {duplicate } */ + var _glRenderbufferStorage = (x0, x1, x2, x3) => GLctx.renderbufferStorage(x0, x1, x2, x3); + var _emscripten_glRenderbufferStorage = _glRenderbufferStorage; + + /** @suppress {duplicate } */ + var _glSampleCoverage = (value, invert) => { + GLctx.sampleCoverage(value, !!invert); + }; + var _emscripten_glSampleCoverage = _glSampleCoverage; + + /** @suppress {duplicate } */ + var _glScissor = (x0, x1, x2, x3) => GLctx.scissor(x0, x1, x2, x3); + var _emscripten_glScissor = _glScissor; + + /** @suppress {duplicate } */ + var _glShaderBinary = (count, shaders, binaryformat, binary, length) => { + GL.recordError(0x500/*GL_INVALID_ENUM*/); + }; + var _emscripten_glShaderBinary = _glShaderBinary; + + /** @suppress {duplicate } */ + var _glShaderSource = (shader, count, string, length) => { + var source = GL.getSource(shader, count, string, length); + + GLctx.shaderSource(GL.shaders[shader], source); + }; + var _emscripten_glShaderSource = _glShaderSource; + + /** @suppress {duplicate } */ + var _glStencilFunc = (x0, x1, x2) => GLctx.stencilFunc(x0, x1, x2); + var _emscripten_glStencilFunc = _glStencilFunc; + + /** @suppress {duplicate } */ + var _glStencilFuncSeparate = (x0, x1, x2, x3) => GLctx.stencilFuncSeparate(x0, x1, x2, x3); + var _emscripten_glStencilFuncSeparate = _glStencilFuncSeparate; + + /** @suppress {duplicate } */ + var _glStencilMask = (x0) => GLctx.stencilMask(x0); + var _emscripten_glStencilMask = _glStencilMask; + + /** @suppress {duplicate } */ + var _glStencilMaskSeparate = (x0, x1) => GLctx.stencilMaskSeparate(x0, x1); + var _emscripten_glStencilMaskSeparate = _glStencilMaskSeparate; + + /** @suppress {duplicate } */ + var _glStencilOp = (x0, x1, x2) => GLctx.stencilOp(x0, x1, x2); + var _emscripten_glStencilOp = _glStencilOp; + + /** @suppress {duplicate } */ + var _glStencilOpSeparate = (x0, x1, x2, x3) => GLctx.stencilOpSeparate(x0, x1, x2, x3); + var _emscripten_glStencilOpSeparate = _glStencilOpSeparate; + + + /** @suppress {duplicate } */ + var _glTexImage2D = (target, level, internalFormat, width, height, border, format, type, pixels) => { + var pixelData = pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null; + GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixelData); + }; + var _emscripten_glTexImage2D = _glTexImage2D; + + /** @suppress {duplicate } */ + var _glTexParameterf = (x0, x1, x2) => GLctx.texParameterf(x0, x1, x2); + var _emscripten_glTexParameterf = _glTexParameterf; + + /** @suppress {duplicate } */ + var _glTexParameterfv = (target, pname, params) => { + var param = HEAPF32[((params)>>2)]; + GLctx.texParameterf(target, pname, param); + }; + var _emscripten_glTexParameterfv = _glTexParameterfv; + + /** @suppress {duplicate } */ + var _glTexParameteri = (x0, x1, x2) => GLctx.texParameteri(x0, x1, x2); + var _emscripten_glTexParameteri = _glTexParameteri; + + /** @suppress {duplicate } */ + var _glTexParameteriv = (target, pname, params) => { + var param = HEAP32[((params)>>2)]; + GLctx.texParameteri(target, pname, param); + }; + var _emscripten_glTexParameteriv = _glTexParameteriv; + + + /** @suppress {duplicate } */ + var _glTexSubImage2D = (target, level, xoffset, yoffset, width, height, format, type, pixels) => { + var pixelData = pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, 0) : null; + GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixelData); + }; + var _emscripten_glTexSubImage2D = _glTexSubImage2D; + + + /** @suppress {duplicate } */ + var _glUniform1f = (location, v0) => { + GLctx.uniform1f(webglGetUniformLocation(location), v0); + }; + var _emscripten_glUniform1f = _glUniform1f; + + + var miniTempWebGLFloatBuffers = []; + + /** @suppress {duplicate } */ + var _glUniform1fv = (location, count, value) => { + + if (count <= 288) { + // avoid allocation when uploading few enough uniforms + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; ++i) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*4)>>2)); + } + GLctx.uniform1fv(webglGetUniformLocation(location), view); + }; + var _emscripten_glUniform1fv = _glUniform1fv; + + + /** @suppress {duplicate } */ + var _glUniform1i = (location, v0) => { + GLctx.uniform1i(webglGetUniformLocation(location), v0); + }; + var _emscripten_glUniform1i = _glUniform1i; + + + var miniTempWebGLIntBuffers = []; + + /** @suppress {duplicate } */ + var _glUniform1iv = (location, count, value) => { + + if (count <= 288) { + // avoid allocation when uploading few enough uniforms + var view = miniTempWebGLIntBuffers[count]; + for (var i = 0; i < count; ++i) { + view[i] = HEAP32[(((value)+(4*i))>>2)]; + } + } else + { + var view = HEAP32.subarray((((value)>>2)), ((value+count*4)>>2)); + } + GLctx.uniform1iv(webglGetUniformLocation(location), view); + }; + var _emscripten_glUniform1iv = _glUniform1iv; + + + /** @suppress {duplicate } */ + var _glUniform2f = (location, v0, v1) => { + GLctx.uniform2f(webglGetUniformLocation(location), v0, v1); + }; + var _emscripten_glUniform2f = _glUniform2f; + + + + /** @suppress {duplicate } */ + var _glUniform2fv = (location, count, value) => { + + if (count <= 144) { + // avoid allocation when uploading few enough uniforms + count *= 2; + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; i += 2) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*8)>>2)); + } + GLctx.uniform2fv(webglGetUniformLocation(location), view); + }; + var _emscripten_glUniform2fv = _glUniform2fv; + + + /** @suppress {duplicate } */ + var _glUniform2i = (location, v0, v1) => { + GLctx.uniform2i(webglGetUniformLocation(location), v0, v1); + }; + var _emscripten_glUniform2i = _glUniform2i; + + + + /** @suppress {duplicate } */ + var _glUniform2iv = (location, count, value) => { + + if (count <= 144) { + // avoid allocation when uploading few enough uniforms + count *= 2; + var view = miniTempWebGLIntBuffers[count]; + for (var i = 0; i < count; i += 2) { + view[i] = HEAP32[(((value)+(4*i))>>2)]; + view[i+1] = HEAP32[(((value)+(4*i+4))>>2)]; + } + } else + { + var view = HEAP32.subarray((((value)>>2)), ((value+count*8)>>2)); + } + GLctx.uniform2iv(webglGetUniformLocation(location), view); + }; + var _emscripten_glUniform2iv = _glUniform2iv; + + + /** @suppress {duplicate } */ + var _glUniform3f = (location, v0, v1, v2) => { + GLctx.uniform3f(webglGetUniformLocation(location), v0, v1, v2); + }; + var _emscripten_glUniform3f = _glUniform3f; + + + + /** @suppress {duplicate } */ + var _glUniform3fv = (location, count, value) => { + + if (count <= 96) { + // avoid allocation when uploading few enough uniforms + count *= 3; + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; i += 3) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAPF32[(((value)+(4*i+8))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*12)>>2)); + } + GLctx.uniform3fv(webglGetUniformLocation(location), view); + }; + var _emscripten_glUniform3fv = _glUniform3fv; + + + /** @suppress {duplicate } */ + var _glUniform3i = (location, v0, v1, v2) => { + GLctx.uniform3i(webglGetUniformLocation(location), v0, v1, v2); + }; + var _emscripten_glUniform3i = _glUniform3i; + + + + /** @suppress {duplicate } */ + var _glUniform3iv = (location, count, value) => { + + if (count <= 96) { + // avoid allocation when uploading few enough uniforms + count *= 3; + var view = miniTempWebGLIntBuffers[count]; + for (var i = 0; i < count; i += 3) { + view[i] = HEAP32[(((value)+(4*i))>>2)]; + view[i+1] = HEAP32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAP32[(((value)+(4*i+8))>>2)]; + } + } else + { + var view = HEAP32.subarray((((value)>>2)), ((value+count*12)>>2)); + } + GLctx.uniform3iv(webglGetUniformLocation(location), view); + }; + var _emscripten_glUniform3iv = _glUniform3iv; + + + /** @suppress {duplicate } */ + var _glUniform4f = (location, v0, v1, v2, v3) => { + GLctx.uniform4f(webglGetUniformLocation(location), v0, v1, v2, v3); + }; + var _emscripten_glUniform4f = _glUniform4f; + + + + /** @suppress {duplicate } */ + var _glUniform4fv = (location, count, value) => { + + if (count <= 72) { + // avoid allocation when uploading few enough uniforms + var view = miniTempWebGLFloatBuffers[4*count]; + // hoist the heap out of the loop for size and for pthreads+growth. + var heap = HEAPF32; + value = ((value)>>2); + count *= 4; + for (var i = 0; i < count; i += 4) { + var dst = value + i; + view[i] = heap[dst]; + view[i + 1] = heap[dst + 1]; + view[i + 2] = heap[dst + 2]; + view[i + 3] = heap[dst + 3]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*16)>>2)); + } + GLctx.uniform4fv(webglGetUniformLocation(location), view); + }; + var _emscripten_glUniform4fv = _glUniform4fv; + + + /** @suppress {duplicate } */ + var _glUniform4i = (location, v0, v1, v2, v3) => { + GLctx.uniform4i(webglGetUniformLocation(location), v0, v1, v2, v3); + }; + var _emscripten_glUniform4i = _glUniform4i; + + + + /** @suppress {duplicate } */ + var _glUniform4iv = (location, count, value) => { + + if (count <= 72) { + // avoid allocation when uploading few enough uniforms + count *= 4; + var view = miniTempWebGLIntBuffers[count]; + for (var i = 0; i < count; i += 4) { + view[i] = HEAP32[(((value)+(4*i))>>2)]; + view[i+1] = HEAP32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAP32[(((value)+(4*i+8))>>2)]; + view[i+3] = HEAP32[(((value)+(4*i+12))>>2)]; + } + } else + { + var view = HEAP32.subarray((((value)>>2)), ((value+count*16)>>2)); + } + GLctx.uniform4iv(webglGetUniformLocation(location), view); + }; + var _emscripten_glUniform4iv = _glUniform4iv; + + + + /** @suppress {duplicate } */ + var _glUniformMatrix2fv = (location, count, transpose, value) => { + + if (count <= 72) { + // avoid allocation when uploading few enough uniforms + count *= 4; + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; i += 4) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAPF32[(((value)+(4*i+8))>>2)]; + view[i+3] = HEAPF32[(((value)+(4*i+12))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*16)>>2)); + } + GLctx.uniformMatrix2fv(webglGetUniformLocation(location), !!transpose, view); + }; + var _emscripten_glUniformMatrix2fv = _glUniformMatrix2fv; + + + + /** @suppress {duplicate } */ + var _glUniformMatrix3fv = (location, count, transpose, value) => { + + if (count <= 32) { + // avoid allocation when uploading few enough uniforms + count *= 9; + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; i += 9) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAPF32[(((value)+(4*i+8))>>2)]; + view[i+3] = HEAPF32[(((value)+(4*i+12))>>2)]; + view[i+4] = HEAPF32[(((value)+(4*i+16))>>2)]; + view[i+5] = HEAPF32[(((value)+(4*i+20))>>2)]; + view[i+6] = HEAPF32[(((value)+(4*i+24))>>2)]; + view[i+7] = HEAPF32[(((value)+(4*i+28))>>2)]; + view[i+8] = HEAPF32[(((value)+(4*i+32))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*36)>>2)); + } + GLctx.uniformMatrix3fv(webglGetUniformLocation(location), !!transpose, view); + }; + var _emscripten_glUniformMatrix3fv = _glUniformMatrix3fv; + + + + /** @suppress {duplicate } */ + var _glUniformMatrix4fv = (location, count, transpose, value) => { + + if (count <= 18) { + // avoid allocation when uploading few enough uniforms + var view = miniTempWebGLFloatBuffers[16*count]; + // hoist the heap out of the loop for size and for pthreads+growth. + var heap = HEAPF32; + value = ((value)>>2); + count *= 16; + for (var i = 0; i < count; i += 16) { + var dst = value + i; + view[i] = heap[dst]; + view[i + 1] = heap[dst + 1]; + view[i + 2] = heap[dst + 2]; + view[i + 3] = heap[dst + 3]; + view[i + 4] = heap[dst + 4]; + view[i + 5] = heap[dst + 5]; + view[i + 6] = heap[dst + 6]; + view[i + 7] = heap[dst + 7]; + view[i + 8] = heap[dst + 8]; + view[i + 9] = heap[dst + 9]; + view[i + 10] = heap[dst + 10]; + view[i + 11] = heap[dst + 11]; + view[i + 12] = heap[dst + 12]; + view[i + 13] = heap[dst + 13]; + view[i + 14] = heap[dst + 14]; + view[i + 15] = heap[dst + 15]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*64)>>2)); + } + GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, view); + }; + var _emscripten_glUniformMatrix4fv = _glUniformMatrix4fv; + + /** @suppress {duplicate } */ + var _glUseProgram = (program) => { + program = GL.programs[program]; + GLctx.useProgram(program); + // Record the currently active program so that we can access the uniform + // mapping table of that program. + GLctx.currentProgram = program; + }; + var _emscripten_glUseProgram = _glUseProgram; + + /** @suppress {duplicate } */ + var _glValidateProgram = (program) => { + GLctx.validateProgram(GL.programs[program]); + }; + var _emscripten_glValidateProgram = _glValidateProgram; + + /** @suppress {duplicate } */ + var _glVertexAttrib1f = (x0, x1) => GLctx.vertexAttrib1f(x0, x1); + var _emscripten_glVertexAttrib1f = _glVertexAttrib1f; + + /** @suppress {duplicate } */ + var _glVertexAttrib1fv = (index, v) => { + + GLctx.vertexAttrib1f(index, HEAPF32[v>>2]); + }; + var _emscripten_glVertexAttrib1fv = _glVertexAttrib1fv; + + /** @suppress {duplicate } */ + var _glVertexAttrib2f = (x0, x1, x2) => GLctx.vertexAttrib2f(x0, x1, x2); + var _emscripten_glVertexAttrib2f = _glVertexAttrib2f; + + /** @suppress {duplicate } */ + var _glVertexAttrib2fv = (index, v) => { + + GLctx.vertexAttrib2f(index, HEAPF32[v>>2], HEAPF32[v+4>>2]); + }; + var _emscripten_glVertexAttrib2fv = _glVertexAttrib2fv; + + /** @suppress {duplicate } */ + var _glVertexAttrib3f = (x0, x1, x2, x3) => GLctx.vertexAttrib3f(x0, x1, x2, x3); + var _emscripten_glVertexAttrib3f = _glVertexAttrib3f; + + /** @suppress {duplicate } */ + var _glVertexAttrib3fv = (index, v) => { + + GLctx.vertexAttrib3f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2]); + }; + var _emscripten_glVertexAttrib3fv = _glVertexAttrib3fv; + + /** @suppress {duplicate } */ + var _glVertexAttrib4f = (x0, x1, x2, x3, x4) => GLctx.vertexAttrib4f(x0, x1, x2, x3, x4); + var _emscripten_glVertexAttrib4f = _glVertexAttrib4f; + + /** @suppress {duplicate } */ + var _glVertexAttrib4fv = (index, v) => { + + GLctx.vertexAttrib4f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2], HEAPF32[v+12>>2]); + }; + var _emscripten_glVertexAttrib4fv = _glVertexAttrib4fv; + + + /** @suppress {duplicate } */ + var _glVertexAttribDivisor = (index, divisor) => { + GLctx.vertexAttribDivisor(index, divisor); + }; + /** @suppress {duplicate } */ + var _glVertexAttribDivisorANGLE = _glVertexAttribDivisor; + var _emscripten_glVertexAttribDivisorANGLE = _glVertexAttribDivisorANGLE; + + /** @suppress {duplicate } */ + var _glVertexAttribPointer = (index, size, type, normalized, stride, ptr) => { + GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr); + }; + var _emscripten_glVertexAttribPointer = _glVertexAttribPointer; + + /** @suppress {duplicate } */ + var _glViewport = (x0, x1, x2, x3) => GLctx.viewport(x0, x1, x2, x3); + var _emscripten_glViewport = _glViewport; + + var _emscripten_has_asyncify = () => 1; + + + + + + + + + var doRequestFullscreen = (target, strategy) => { + if (!JSEvents.fullscreenEnabled()) return -1; + target = findEventTarget(target); + if (!target) return -4; + + if (!target.requestFullscreen + && !target.webkitRequestFullscreen + ) { + return -3; + } + + // Queue this function call if we're not currently in an event handler and + // the user saw it appropriate to do so. + if (!JSEvents.canPerformEventHandlerRequests()) { + if (strategy.deferUntilInEventHandler) { + JSEvents.deferCall(JSEvents_requestFullscreen, 1 /* priority over pointer lock */, [target, strategy]); + return 1; + } + return -2; + } + + return JSEvents_requestFullscreen(target, strategy); + }; + + + var _emscripten_request_fullscreen_strategy = (target, deferUntilInEventHandler, fullscreenStrategy) => { + var strategy = { + scaleMode: HEAP32[((fullscreenStrategy)>>2)], + canvasResolutionScaleMode: HEAP32[(((fullscreenStrategy)+(4))>>2)], + filteringMode: HEAP32[(((fullscreenStrategy)+(8))>>2)], + deferUntilInEventHandler, + canvasResizedCallback: HEAP32[(((fullscreenStrategy)+(12))>>2)], + canvasResizedCallbackUserData: HEAP32[(((fullscreenStrategy)+(16))>>2)] + }; + + return doRequestFullscreen(target, strategy); + }; + + + + var _emscripten_request_pointerlock = (target, deferUntilInEventHandler) => { + target = findEventTarget(target); + if (!target) return -4; + if (!target.requestPointerLock + ) { + return -1; + } + + // Queue this function call if we're not currently in an event handler and + // the user saw it appropriate to do so. + if (!JSEvents.canPerformEventHandlerRequests()) { + if (deferUntilInEventHandler) { + JSEvents.deferCall(requestPointerLock, 2 /* priority below fullscreen */, [target]); + return 1; + } + return -2; + } + + return requestPointerLock(target); + }; + + var getHeapMax = () => + // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate + // full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side + // for any code that deals with heap sizes, which would require special + // casing all heap size related code to treat 0 specially. + 2147483648; + + + var growMemory = (size) => { + var b = wasmMemory.buffer; + var pages = (size - b.byteLength + 65535) / 65536; + try { + // round size grow request up to wasm page size (fixed 64KB per spec) + wasmMemory.grow(pages); // .grow() takes a delta compared to the previous size + updateMemoryViews(); + return 1 /*success*/; + } catch(e) { + err(`growMemory: Attempted to grow heap from ${b.byteLength} bytes to ${size} bytes, but got error: ${e}`); + } + // implicit 0 return to save code size (caller will cast "undefined" into 0 + // anyhow) + }; + var _emscripten_resize_heap = (requestedSize) => { + var oldSize = HEAPU8.length; + // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned. + requestedSize >>>= 0; + // With multithreaded builds, races can happen (another thread might increase the size + // in between), so return a failure, and let the caller retry. + assert(requestedSize > oldSize); + + // Memory resize rules: + // 1. Always increase heap size to at least the requested size, rounded up + // to next page multiple. + // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap + // geometrically: increase the heap size according to + // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most + // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB). + // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap + // linearly: increase the heap size by at least + // MEMORY_GROWTH_LINEAR_STEP bytes. + // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by + // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest + // 4. If we were unable to allocate as much memory, it may be due to + // over-eager decision to excessively reserve due to (3) above. + // Hence if an allocation fails, cut down on the amount of excess + // growth, in an attempt to succeed to perform a smaller allocation. + + // A limit is set for how much we can grow. We should not exceed that + // (the wasm binary specifies it, so if we tried, we'd fail anyhow). + var maxHeapSize = getHeapMax(); + if (requestedSize > maxHeapSize) { + err(`Cannot enlarge memory, requested ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`); + return false; + } + + // Loop through potential heap size increases. If we attempt a too eager + // reservation that fails, cut down on the attempted size and reserve a + // smaller bump instead. (max 3 times, chosen somewhat arbitrarily) + for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth + // but limit overreserving (default to capping at +96MB overgrowth at most) + overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 ); + + var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536)); + + var replacement = growMemory(newSize); + if (replacement) { + + return true; + } + } + err(`Failed to grow the heap from ${oldSize} bytes to ${newSize} bytes, not enough memory!`); + return false; + }; + + /** @suppress {checkTypes} */ + var _emscripten_sample_gamepad_data = () => { + try { + if (navigator.getGamepads) return (JSEvents.lastGamepadState = navigator.getGamepads()) + ? 0 : -1; + } catch(e) { + err(`navigator.getGamepads() exists, but failed to execute with exception ${e}. Disabling Gamepad access.`); + navigator.getGamepads = null; // Disable getGamepads() so that it won't be attempted to be used again. + } + return -1; + }; + + var _emscripten_scan_registers = (func) => { + return Asyncify.handleSleep((wakeUp) => { + // We must first unwind, so things are spilled to the stack. Then while + // we are pausing we do the actual scan. After that we can resume. Note + // how using a timeout here avoids unbounded call stack growth, which + // could happen if we tried to scan the stack immediately after unwinding. + safeSetTimeout(() => { + var stackBegin = Asyncify.currData + 12; + var stackEnd = HEAPU32[((Asyncify.currData)>>2)]; + ((a1, a2) => dynCall_vii(func, a1, a2))(stackBegin, stackEnd); + wakeUp(); + }, 0); + }); + }; + _emscripten_scan_registers.isAsync = true; + + + + var registerBeforeUnloadEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) => { + var beforeUnloadEventHandlerFunc = (e = event) => { + // Note: This is always called on the main browser thread, since it needs synchronously return a value! + var confirmationMessage = ((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, 0, userData); + + if (confirmationMessage) { + confirmationMessage = UTF8ToString(confirmationMessage); + } + if (confirmationMessage) { + e.preventDefault(); + e.returnValue = confirmationMessage; + return confirmationMessage; + } + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: beforeUnloadEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + var _emscripten_set_beforeunload_callback_on_thread = (userData, callbackfunc, targetThread) => { + if (typeof onbeforeunload == 'undefined') return -1; + // beforeunload callback can only be registered on the main browser thread, because the page will go away immediately after returning from the handler, + // and there is no time to start proxying it anywhere. + if (targetThread !== 1) return -5; + return registerBeforeUnloadEventCallback(2, userData, true, callbackfunc, 28, "beforeunload"); + }; + + + + + var registerFocusEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.focusEvent) JSEvents.focusEvent = _malloc(256); + + var focusEventHandlerFunc = (e = event) => { + var nodeName = JSEvents.getNodeNameForTarget(e.target); + var id = e.target.id ? e.target.id : ''; + + var focusEvent = JSEvents.focusEvent; + stringToUTF8(nodeName, focusEvent + 0, 128); + stringToUTF8(id, focusEvent + 128, 128); + + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, focusEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: focusEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + var _emscripten_set_blur_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerFocusEventCallback(target, userData, useCapture, callbackfunc, 12, "blur", targetThread); + + + + var _emscripten_set_element_css_size = (target, width, height) => { + target = findEventTarget(target); + if (!target) return -4; + + target.style.width = width + "px"; + target.style.height = height + "px"; + + return 0; + }; + + var _emscripten_set_focus_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerFocusEventCallback(target, userData, useCapture, callbackfunc, 13, "focus", targetThread); + + + + + var fillFullscreenChangeEventData = (eventStruct) => { + var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement; + var isFullscreen = !!fullscreenElement; + // Assigning a boolean to HEAP32 with expected type coercion. + /** @suppress{checkTypes} */ + HEAP8[eventStruct] = isFullscreen; + HEAP8[(eventStruct)+(1)] = JSEvents.fullscreenEnabled(); + // If transitioning to fullscreen, report info about the element that is now fullscreen. + // If transitioning to windowed mode, report info about the element that just was fullscreen. + var reportedElement = isFullscreen ? fullscreenElement : JSEvents.previousFullscreenElement; + var nodeName = JSEvents.getNodeNameForTarget(reportedElement); + var id = reportedElement?.id || ''; + stringToUTF8(nodeName, eventStruct + 2, 128); + stringToUTF8(id, eventStruct + 130, 128); + HEAP32[(((eventStruct)+(260))>>2)] = reportedElement ? reportedElement.clientWidth : 0; + HEAP32[(((eventStruct)+(264))>>2)] = reportedElement ? reportedElement.clientHeight : 0; + HEAP32[(((eventStruct)+(268))>>2)] = screen.width; + HEAP32[(((eventStruct)+(272))>>2)] = screen.height; + if (isFullscreen) { + JSEvents.previousFullscreenElement = fullscreenElement; + } + }; + + + var registerFullscreenChangeEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.fullscreenChangeEvent) JSEvents.fullscreenChangeEvent = _malloc(276); + + var fullscreenChangeEventhandlerFunc = (e = event) => { + var fullscreenChangeEvent = JSEvents.fullscreenChangeEvent; + + fillFullscreenChangeEventData(fullscreenChangeEvent); + + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, fullscreenChangeEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: fullscreenChangeEventhandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + var _emscripten_set_fullscreenchange_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + if (!JSEvents.fullscreenEnabled()) return -1; + target = findEventTarget(target); + if (!target) return -4; + + // Unprefixed Fullscreen API shipped in Chromium 71 (https://bugs.chromium.org/p/chromium/issues/detail?id=383813) + // As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version. + registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, 19, "webkitfullscreenchange", targetThread); + + return registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, 19, "fullscreenchange", targetThread); + }; + + + + + var registerGamepadEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.gamepadEvent) JSEvents.gamepadEvent = _malloc(1240); + + var gamepadEventHandlerFunc = (e = event) => { + var gamepadEvent = JSEvents.gamepadEvent; + fillGamepadEventData(gamepadEvent, e["gamepad"]); + + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, gamepadEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString, + callbackfunc, + handlerFunc: gamepadEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_gamepadconnected_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => { + if (_emscripten_sample_gamepad_data()) return -1; + return registerGamepadEventCallback(2, userData, useCapture, callbackfunc, 26, "gamepadconnected", targetThread); + }; + + + var _emscripten_set_gamepaddisconnected_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => { + if (_emscripten_sample_gamepad_data()) return -1; + return registerGamepadEventCallback(2, userData, useCapture, callbackfunc, 27, "gamepaddisconnected", targetThread); + }; + + + + + var registerKeyEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.keyEvent) JSEvents.keyEvent = _malloc(160); + + var keyEventHandlerFunc = (e) => { + assert(e); + + var keyEventData = JSEvents.keyEvent; + HEAPF64[((keyEventData)>>3)] = e.timeStamp; + + var idx = ((keyEventData)>>2); + + HEAP32[idx + 2] = e.location; + HEAP8[keyEventData + 12] = e.ctrlKey; + HEAP8[keyEventData + 13] = e.shiftKey; + HEAP8[keyEventData + 14] = e.altKey; + HEAP8[keyEventData + 15] = e.metaKey; + HEAP8[keyEventData + 16] = e.repeat; + HEAP32[idx + 5] = e.charCode; + HEAP32[idx + 6] = e.keyCode; + HEAP32[idx + 7] = e.which; + stringToUTF8(e.key || '', keyEventData + 32, 32); + stringToUTF8(e.code || '', keyEventData + 64, 32); + stringToUTF8(e.char || '', keyEventData + 96, 32); + stringToUTF8(e.locale || '', keyEventData + 128, 32); + + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, keyEventData, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: keyEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + var _emscripten_set_keydown_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerKeyEventCallback(target, userData, useCapture, callbackfunc, 2, "keydown", targetThread); + + var _emscripten_set_keypress_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerKeyEventCallback(target, userData, useCapture, callbackfunc, 1, "keypress", targetThread); + + var _emscripten_set_keyup_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerKeyEventCallback(target, userData, useCapture, callbackfunc, 3, "keyup", targetThread); + + + var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { + var browserIterationFunc = (() => dynCall_v(func)); + setMainLoop(browserIterationFunc, fps, simulateInfiniteLoop); + }; + + + + + var fillMouseEventData = (eventStruct, e, target) => { + assert(eventStruct % 4 == 0); + HEAPF64[((eventStruct)>>3)] = e.timeStamp; + var idx = ((eventStruct)>>2); + HEAP32[idx + 2] = e.screenX; + HEAP32[idx + 3] = e.screenY; + HEAP32[idx + 4] = e.clientX; + HEAP32[idx + 5] = e.clientY; + HEAP8[eventStruct + 24] = e.ctrlKey; + HEAP8[eventStruct + 25] = e.shiftKey; + HEAP8[eventStruct + 26] = e.altKey; + HEAP8[eventStruct + 27] = e.metaKey; + HEAP16[idx*2 + 14] = e.button; + HEAP16[idx*2 + 15] = e.buttons; + + HEAP32[idx + 8] = e["movementX"] + ; + + HEAP32[idx + 9] = e["movementY"] + ; + + // Note: rect contains doubles (truncated to placate SAFE_HEAP, which is the same behaviour when writing to HEAP32 anyway) + var rect = getBoundingClientRect(target); + HEAP32[idx + 10] = e.clientX - (rect.left | 0); + HEAP32[idx + 11] = e.clientY - (rect.top | 0); + + }; + + + var registerMouseEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.mouseEvent) JSEvents.mouseEvent = _malloc(64); + target = findEventTarget(target); + + var mouseEventHandlerFunc = (e = event) => { + // TODO: Make this access thread safe, or this could update live while app is reading it. + fillMouseEventData(JSEvents.mouseEvent, e, target); + + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, JSEvents.mouseEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + allowsDeferredCalls: eventTypeString != 'mousemove' && eventTypeString != 'mouseenter' && eventTypeString != 'mouseleave', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them! + eventTypeString, + callbackfunc, + handlerFunc: mouseEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + var _emscripten_set_mousedown_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 5, "mousedown", targetThread); + + var _emscripten_set_mouseenter_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 33, "mouseenter", targetThread); + + var _emscripten_set_mouseleave_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 34, "mouseleave", targetThread); + + var _emscripten_set_mousemove_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 8, "mousemove", targetThread); + + var _emscripten_set_mouseup_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 6, "mouseup", targetThread); + + + + + var fillPointerlockChangeEventData = (eventStruct) => { + var pointerLockElement = document.pointerLockElement || document.mozPointerLockElement || document.webkitPointerLockElement || document.msPointerLockElement; + var isPointerlocked = !!pointerLockElement; + // Assigning a boolean to HEAP32 with expected type coercion. + /** @suppress{checkTypes} */ + HEAP8[eventStruct] = isPointerlocked; + var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement); + var id = pointerLockElement?.id || ''; + stringToUTF8(nodeName, eventStruct + 1, 128); + stringToUTF8(id, eventStruct + 129, 128); + }; + + + var registerPointerlockChangeEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.pointerlockChangeEvent) JSEvents.pointerlockChangeEvent = _malloc(257); + + var pointerlockChangeEventHandlerFunc = (e = event) => { + var pointerlockChangeEvent = JSEvents.pointerlockChangeEvent; + fillPointerlockChangeEventData(pointerlockChangeEvent); + + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, pointerlockChangeEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: pointerlockChangeEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + /** @suppress {missingProperties} */ + var _emscripten_set_pointerlockchange_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + // TODO: Currently not supported in pthreads or in --proxy-to-worker mode. (In pthreads mode, document object is not defined) + if (!document || !document.body || (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock)) { + return -1; + } + + target = findEventTarget(target); + if (!target) return -4; + registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, 20, "mozpointerlockchange", targetThread); + registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, 20, "webkitpointerlockchange", targetThread); + registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, 20, "mspointerlockchange", targetThread); + return registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, 20, "pointerlockchange", targetThread); + }; + + + + var registerUiEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.uiEvent) JSEvents.uiEvent = _malloc(36); + + target = findEventTarget(target); + + var uiEventHandlerFunc = (e = event) => { + if (e.target != target) { + // Never take ui events such as scroll via a 'bubbled' route, but always from the direct element that + // was targeted. Otherwise e.g. if app logs a message in response to a page scroll, the Emscripten log + // message box could cause to scroll, generating a new (bubbled) scroll message, causing a new log print, + // causing a new scroll, etc.. + return; + } + var b = document.body; // Take document.body to a variable, Closure compiler does not outline access to it on its own. + if (!b) { + // During a page unload 'body' can be null, with "Cannot read property 'clientWidth' of null" being thrown + return; + } + var uiEvent = JSEvents.uiEvent; + HEAP32[((uiEvent)>>2)] = 0; // always zero for resize and scroll + HEAP32[(((uiEvent)+(4))>>2)] = b.clientWidth; + HEAP32[(((uiEvent)+(8))>>2)] = b.clientHeight; + HEAP32[(((uiEvent)+(12))>>2)] = innerWidth; + HEAP32[(((uiEvent)+(16))>>2)] = innerHeight; + HEAP32[(((uiEvent)+(20))>>2)] = outerWidth; + HEAP32[(((uiEvent)+(24))>>2)] = outerHeight; + HEAP32[(((uiEvent)+(28))>>2)] = pageXOffset | 0; // scroll offsets are float + HEAP32[(((uiEvent)+(32))>>2)] = pageYOffset | 0; + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, uiEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: uiEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + var _emscripten_set_resize_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerUiEventCallback(target, userData, useCapture, callbackfunc, 10, "resize", targetThread); + + + + + var registerTouchEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.touchEvent) JSEvents.touchEvent = _malloc(1552); + + target = findEventTarget(target); + + var touchEventHandlerFunc = (e) => { + assert(e); + var t, touches = {}, et = e.touches; + // To ease marshalling different kinds of touches that browser reports (all touches are listed in e.touches, + // only changed touches in e.changedTouches, and touches on target at a.targetTouches), mark a boolean in + // each Touch object so that we can later loop only once over all touches we see to marshall over to Wasm. + + for (let t of et) { + // Browser might recycle the generated Touch objects between each frame (Firefox on Android), so reset any + // changed/target states we may have set from previous frame. + t.isChanged = t.onTarget = 0; + touches[t.identifier] = t; + } + // Mark which touches are part of the changedTouches list. + for (let t of e.changedTouches) { + t.isChanged = 1; + touches[t.identifier] = t; + } + // Mark which touches are part of the targetTouches list. + for (let t of e.targetTouches) { + touches[t.identifier].onTarget = 1; + } + + var touchEvent = JSEvents.touchEvent; + HEAPF64[((touchEvent)>>3)] = e.timeStamp; + HEAP8[touchEvent + 12] = e.ctrlKey; + HEAP8[touchEvent + 13] = e.shiftKey; + HEAP8[touchEvent + 14] = e.altKey; + HEAP8[touchEvent + 15] = e.metaKey; + var idx = touchEvent + 16; + var targetRect = getBoundingClientRect(target); + var numTouches = 0; + for (let t of Object.values(touches)) { + var idx32 = ((idx)>>2); // Pre-shift the ptr to index to HEAP32 to save code size + HEAP32[idx32 + 0] = t.identifier; + HEAP32[idx32 + 1] = t.screenX; + HEAP32[idx32 + 2] = t.screenY; + HEAP32[idx32 + 3] = t.clientX; + HEAP32[idx32 + 4] = t.clientY; + HEAP32[idx32 + 5] = t.pageX; + HEAP32[idx32 + 6] = t.pageY; + HEAP8[idx + 28] = t.isChanged; + HEAP8[idx + 29] = t.onTarget; + HEAP32[idx32 + 8] = t.clientX - (targetRect.left | 0); + HEAP32[idx32 + 9] = t.clientY - (targetRect.top | 0); + + idx += 48; + + if (++numTouches > 31) { + break; + } + } + HEAP32[(((touchEvent)+(8))>>2)] = numTouches; + + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, touchEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + allowsDeferredCalls: eventTypeString == 'touchstart' || eventTypeString == 'touchend', + eventTypeString, + callbackfunc, + handlerFunc: touchEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + var _emscripten_set_touchcancel_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerTouchEventCallback(target, userData, useCapture, callbackfunc, 25, "touchcancel", targetThread); + + var _emscripten_set_touchend_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerTouchEventCallback(target, userData, useCapture, callbackfunc, 23, "touchend", targetThread); + + var _emscripten_set_touchmove_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerTouchEventCallback(target, userData, useCapture, callbackfunc, 24, "touchmove", targetThread); + + var _emscripten_set_touchstart_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerTouchEventCallback(target, userData, useCapture, callbackfunc, 22, "touchstart", targetThread); + + + var fillVisibilityChangeEventData = (eventStruct) => { + var visibilityStates = [ "hidden", "visible", "prerender", "unloaded" ]; + var visibilityState = visibilityStates.indexOf(document.visibilityState); + + // Assigning a boolean to HEAP32 with expected type coercion. + /** @suppress{checkTypes} */ + HEAP8[eventStruct] = document.hidden; + HEAP32[(((eventStruct)+(4))>>2)] = visibilityState; + }; + + + var registerVisibilityChangeEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.visibilityChangeEvent) JSEvents.visibilityChangeEvent = _malloc(8); + + var visibilityChangeEventHandlerFunc = (e = event) => { + var visibilityChangeEvent = JSEvents.visibilityChangeEvent; + + fillVisibilityChangeEventData(visibilityChangeEvent); + + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, visibilityChangeEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: visibilityChangeEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_visibilitychange_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => { + if (!specialHTMLTargets[1]) { + return -4; + } + return registerVisibilityChangeEventCallback(specialHTMLTargets[1], userData, useCapture, callbackfunc, 21, "visibilitychange", targetThread); + }; + + + + + + var registerWheelEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + if (!JSEvents.wheelEvent) JSEvents.wheelEvent = _malloc(96); + + // The DOM Level 3 events spec event 'wheel' + var wheelHandlerFunc = (e = event) => { + var wheelEvent = JSEvents.wheelEvent; + fillMouseEventData(wheelEvent, e, target); + HEAPF64[(((wheelEvent)+(64))>>3)] = e["deltaX"]; + HEAPF64[(((wheelEvent)+(72))>>3)] = e["deltaY"]; + HEAPF64[(((wheelEvent)+(80))>>3)] = e["deltaZ"]; + HEAP32[(((wheelEvent)+(88))>>2)] = e["deltaMode"]; + if (((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId, wheelEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + allowsDeferredCalls: true, + eventTypeString, + callbackfunc, + handlerFunc: wheelHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_wheel_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + target = findEventTarget(target); + if (!target) return -4; + if (typeof target.onwheel != 'undefined') { + return registerWheelEventCallback(target, userData, useCapture, callbackfunc, 9, "wheel", targetThread); + } else { + return -1; + } + }; + + + var _emscripten_set_window_title = (title) => document.title = UTF8ToString(title); + + var _emscripten_sleep = (ms) => { + // emscripten_sleep() does not return a value, but we still need a |return| + // here for stack switching support (ASYNCIFY=2). In that mode this function + // returns a Promise instead of nothing, and that Promise is what tells the + // wasm VM to pause the stack. + return Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)); + }; + _emscripten_sleep.isAsync = true; + + var ENV = { + }; + + var getExecutableName = () => { + return thisProgram || './this.program'; + }; + var getEnvStrings = () => { + if (!getEnvStrings.strings) { + // Default values. + // Browser language detection #8751 + var lang = ((typeof navigator == 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8'; + var env = { + 'USER': 'web_user', + 'LOGNAME': 'web_user', + 'PATH': '/', + 'PWD': '/', + 'HOME': '/home/web_user', + 'LANG': lang, + '_': getExecutableName() + }; + // Apply the user-provided values, if any. + for (var x in ENV) { + // x is a key in ENV; if ENV[x] is undefined, that means it was + // explicitly set to be so. We allow user code to do that to + // force variables with default values to remain unset. + if (ENV[x] === undefined) delete env[x]; + else env[x] = ENV[x]; + } + var strings = []; + for (var x in env) { + strings.push(`${x}=${env[x]}`); + } + getEnvStrings.strings = strings; + } + return getEnvStrings.strings; + }; + + var stringToAscii = (str, buffer) => { + for (var i = 0; i < str.length; ++i) { + assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff)); + HEAP8[buffer++] = str.charCodeAt(i); + } + // Null-terminate the string + HEAP8[buffer] = 0; + }; + var _environ_get = (__environ, environ_buf) => { + var bufSize = 0; + getEnvStrings().forEach((string, i) => { + var ptr = environ_buf + bufSize; + HEAPU32[(((__environ)+(i*4))>>2)] = ptr; + stringToAscii(string, ptr); + bufSize += string.length + 1; + }); + return 0; + }; + + var _environ_sizes_get = (penviron_count, penviron_buf_size) => { + var strings = getEnvStrings(); + HEAPU32[((penviron_count)>>2)] = strings.length; + var bufSize = 0; + strings.forEach((string) => bufSize += string.length + 1); + HEAPU32[((penviron_buf_size)>>2)] = bufSize; + return 0; + }; + + function _fd_close(fd) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + FS.close(stream); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + + /** @param {number=} offset */ + var doReadv = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[((iov)>>2)]; + var len = HEAPU32[(((iov)+(4))>>2)]; + iov += 8; + var curr = FS.read(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) break; // nothing more to read + if (typeof offset != 'undefined') { + offset += curr; + } + } + return ret; + }; + + function _fd_read(fd, iov, iovcnt, pnum) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doReadv(stream, iov, iovcnt); + HEAPU32[((pnum)>>2)] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + + + var convertI32PairToI53Checked = (lo, hi) => { + assert(lo == (lo >>> 0) || lo == (lo|0)); // lo should either be a i32 or a u32 + assert(hi === (hi|0)); // hi should be a i32 + return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; + }; + function _fd_seek(fd,offset_low, offset_high,whence,newOffset) { + var offset = convertI32PairToI53Checked(offset_low, offset_high); + + + try { + + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + FS.llseek(stream, offset, whence); + (tempI64 = [stream.position>>>0,(tempDouble = stream.position,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[((newOffset)>>2)] = tempI64[0],HEAP32[(((newOffset)+(4))>>2)] = tempI64[1]); + if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + ; + } + + var _fd_sync = function (fd) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + return Asyncify.handleSleep((wakeUp) => { + var mount = stream.node.mount; + if (!mount.type.syncfs) { + // We write directly to the file system, so there's nothing to do here. + wakeUp(0); + return; + } + mount.type.syncfs(mount, false, (err) => { + if (err) { + wakeUp(29); + return; + } + wakeUp(0); + }); + }); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + }; + _fd_sync.isAsync = true; + + /** @param {number=} offset */ + var doWritev = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[((iov)>>2)]; + var len = HEAPU32[(((iov)+(4))>>2)]; + iov += 8; + var curr = FS.write(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) { + // No more space to write. + break; + } + if (typeof offset != 'undefined') { + offset += curr; + } + } + return ret; + }; + + function _fd_write(fd, iov, iovcnt, pnum) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doWritev(stream, iov, iovcnt); + HEAPU32[((pnum)>>2)] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + + var _mp_js_hook = () => { + if (ENVIRONMENT_IS_NODE) { + const mp_interrupt_char = Module.ccall( + "mp_hal_get_interrupt_char", + "number", + ["number"], + ["null"], + ); + const fs = require("fs"); + + const buf = Buffer.alloc(1); + try { + const n = fs.readSync(process.stdin.fd, buf, 0, 1); + if (n > 0) { + if (buf[0] === mp_interrupt_char) { + Module.ccall( + "mp_sched_keyboard_interrupt", + "null", + ["null"], + ["null"], + ); + } else { + process.stdout.write(String.fromCharCode(buf[0])); + } + } + } catch (e) { + if (e.code === "EAGAIN") { + } else { + throw e; + } + } + } + }; + + var _mp_js_random_u32 = () => + globalThis.crypto.getRandomValues(new Uint32Array(1))[0]; + + var _mp_js_ticks_ms = () => Date.now() - MP_JS_EPOCH; + + var _mp_js_time_ms = () => Date.now(); + + var listenOnce = (object, event, func) => { + object.addEventListener(event, func, { 'once': true }); + }; + /** @param {Object=} elements */ + var autoResumeAudioContext = (ctx, elements) => { + if (!elements) { + elements = [document, document.getElementById('canvas')]; + } + ['keydown', 'mousedown', 'touchstart'].forEach((event) => { + elements.forEach((element) => { + if (element) { + listenOnce(element, event, () => { + if (ctx.state === 'suspended') ctx.resume(); + }); + } + }); + }); + }; + + var dynCallLegacy = (sig, ptr, args) => { + sig = sig.replace(/p/g, 'i') + assert(('dynCall_' + sig) in Module, `bad function pointer type - dynCall function not found for sig '${sig}'`); + if (args?.length) { + // j (64-bit integer) must be passed in as two numbers [low 32, high 32]. + assert(args.length === sig.substring(1).replace(/j/g, '--').length); + } else { + assert(sig.length == 1); + } + var f = Module['dynCall_' + sig]; + return f(ptr, ...args); + }; + + var wasmTableMirror = []; + + /** @type {WebAssembly.Table} */ + var wasmTable; + var getWasmTableEntry = (funcPtr) => { + var func = wasmTableMirror[funcPtr]; + if (!func) { + if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1; + wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); + } + assert(wasmTable.get(funcPtr) == func, 'JavaScript-side Wasm function table mirror is out of date!'); + return func; + }; + var dynCall = (sig, ptr, args = []) => { + var rtn = dynCallLegacy(sig, ptr, args); + return rtn; + }; + + + + + + var runAndAbortIfError = (func) => { + try { + return func(); + } catch (e) { + abort(e); + } + }; + + + var sigToWasmTypes = (sig) => { + assert(!sig.includes('j'), 'i64 not permitted in function signatures when WASM_BIGINT is disabled'); + var typeNames = { + 'i': 'i32', + 'j': 'i64', + 'f': 'f32', + 'd': 'f64', + 'e': 'externref', + 'p': 'i32', + }; + var type = { + parameters: [], + results: sig[0] == 'v' ? [] : [typeNames[sig[0]]] + }; + for (var i = 1; i < sig.length; ++i) { + assert(sig[i] in typeNames, 'invalid signature char: ' + sig[i]); + type.parameters.push(typeNames[sig[i]]); + } + return type; + }; + + var runtimeKeepalivePush = () => { + runtimeKeepaliveCounter += 1; + }; + + var runtimeKeepalivePop = () => { + assert(runtimeKeepaliveCounter > 0); + runtimeKeepaliveCounter -= 1; + }; + + + var Asyncify = { + instrumentWasmImports(imports) { + var importPattern = /^(invoke_.*|__asyncjs__.*)$/; + + for (let [x, original] of Object.entries(imports)) { + if (typeof original == 'function') { + let isAsyncifyImport = original.isAsync || importPattern.test(x); + imports[x] = (...args) => { + var originalAsyncifyState = Asyncify.state; + try { + return original(...args); + } finally { + // Only asyncify-declared imports are allowed to change the + // state. + // Changing the state from normal to disabled is allowed (in any + // function) as that is what shutdown does (and we don't have an + // explicit list of shutdown imports). + var changedToDisabled = + originalAsyncifyState === Asyncify.State.Normal && + Asyncify.state === Asyncify.State.Disabled; + // invoke_* functions are allowed to change the state if we do + // not ignore indirect calls. + var ignoredInvoke = x.startsWith('invoke_') && + true; + if (Asyncify.state !== originalAsyncifyState && + !isAsyncifyImport && + !changedToDisabled && + !ignoredInvoke) { + throw new Error(`import ${x} was not in ASYNCIFY_IMPORTS, but changed the state`); + } + } + }; + } + } + }, + instrumentWasmExports(exports) { + var ret = {}; + for (let [x, original] of Object.entries(exports)) { + if (typeof original == 'function') { + ret[x] = (...args) => { + Asyncify.exportCallStack.push(x); + try { + return original(...args); + } finally { + if (!ABORT) { + var y = Asyncify.exportCallStack.pop(); + assert(y === x); + Asyncify.maybeStopUnwind(); + } + } + }; + } else { + ret[x] = original; + } + } + return ret; + }, + State:{ + Normal:0, + Unwinding:1, + Rewinding:2, + Disabled:3, + }, + state:0, + StackSize:16000, + currData:null, + handleSleepReturnValue:0, + exportCallStack:[], + callStackNameToId:{ + }, + callStackIdToName:{ + }, + callStackId:0, + asyncPromiseHandlers:null, + sleepCallbacks:[], + getCallStackId(funcName) { + var id = Asyncify.callStackNameToId[funcName]; + if (id === undefined) { + id = Asyncify.callStackId++; + Asyncify.callStackNameToId[funcName] = id; + Asyncify.callStackIdToName[id] = funcName; + } + return id; + }, + maybeStopUnwind() { + if (Asyncify.currData && + Asyncify.state === Asyncify.State.Unwinding && + Asyncify.exportCallStack.length === 0) { + // We just finished unwinding. + // Be sure to set the state before calling any other functions to avoid + // possible infinite recursion here (For example in debug pthread builds + // the dbg() function itself can call back into WebAssembly to get the + // current pthread_self() pointer). + Asyncify.state = Asyncify.State.Normal; + + // Keep the runtime alive so that a re-wind can be done later. + runAndAbortIfError(_asyncify_stop_unwind); + if (typeof Fibers != 'undefined') { + Fibers.trampoline(); + } + } + }, + whenDone() { + assert(Asyncify.currData, 'Tried to wait for an async operation when none is in progress.'); + assert(!Asyncify.asyncPromiseHandlers, 'Cannot have multiple async operations in flight at once'); + return new Promise((resolve, reject) => { + Asyncify.asyncPromiseHandlers = { resolve, reject }; + }); + }, + allocateData() { + // An asyncify data structure has three fields: + // 0 current stack pos + // 4 max stack pos + // 8 id of function at bottom of the call stack (callStackIdToName[id] == name of js function) + // + // The Asyncify ABI only interprets the first two fields, the rest is for the runtime. + // We also embed a stack in the same memory region here, right next to the structure. + // This struct is also defined as asyncify_data_t in emscripten/fiber.h + var ptr = _malloc(12 + Asyncify.StackSize); + Asyncify.setDataHeader(ptr, ptr + 12, Asyncify.StackSize); + Asyncify.setDataRewindFunc(ptr); + return ptr; + }, + setDataHeader(ptr, stack, stackSize) { + HEAPU32[((ptr)>>2)] = stack; + HEAPU32[(((ptr)+(4))>>2)] = stack + stackSize; + }, + setDataRewindFunc(ptr) { + var bottomOfCallStack = Asyncify.exportCallStack[0]; + var rewindId = Asyncify.getCallStackId(bottomOfCallStack); + HEAP32[(((ptr)+(8))>>2)] = rewindId; + }, + getDataRewindFuncName(ptr) { + var id = HEAP32[(((ptr)+(8))>>2)]; + var name = Asyncify.callStackIdToName[id]; + return name; + }, + getDataRewindFunc(name) { + var func = wasmExports[name]; + return func; + }, + doRewind(ptr) { + var name = Asyncify.getDataRewindFuncName(ptr); + var func = Asyncify.getDataRewindFunc(name); + // Once we have rewound and the stack we no longer need to artificially + // keep the runtime alive. + + return func(); + }, + handleSleep(startAsync) { + assert(Asyncify.state !== Asyncify.State.Disabled, 'Asyncify cannot be done during or after the runtime exits'); + if (ABORT) return; + if (Asyncify.state === Asyncify.State.Normal) { + // Prepare to sleep. Call startAsync, and see what happens: + // if the code decided to call our callback synchronously, + // then no async operation was in fact begun, and we don't + // need to do anything. + var reachedCallback = false; + var reachedAfterCallback = false; + startAsync((handleSleepReturnValue = 0) => { + assert(!handleSleepReturnValue || typeof handleSleepReturnValue == 'number' || typeof handleSleepReturnValue == 'boolean'); // old emterpretify API supported other stuff + if (ABORT) return; + Asyncify.handleSleepReturnValue = handleSleepReturnValue; + reachedCallback = true; + if (!reachedAfterCallback) { + // We are happening synchronously, so no need for async. + return; + } + // This async operation did not happen synchronously, so we did + // unwind. In that case there can be no compiled code on the stack, + // as it might break later operations (we can rewind ok now, but if + // we unwind again, we would unwind through the extra compiled code + // too). + assert(!Asyncify.exportCallStack.length, 'Waking up (starting to rewind) must be done from JS, without compiled code on the stack.'); + Asyncify.state = Asyncify.State.Rewinding; + runAndAbortIfError(() => _asyncify_start_rewind(Asyncify.currData)); + if (typeof Browser != 'undefined' && Browser.mainLoop.func) { + Browser.mainLoop.resume(); + } + var asyncWasmReturnValue, isError = false; + try { + asyncWasmReturnValue = Asyncify.doRewind(Asyncify.currData); + } catch (err) { + asyncWasmReturnValue = err; + isError = true; + } + // Track whether the return value was handled by any promise handlers. + var handled = false; + if (!Asyncify.currData) { + // All asynchronous execution has finished. + // `asyncWasmReturnValue` now contains the final + // return value of the exported async WASM function. + // + // Note: `asyncWasmReturnValue` is distinct from + // `Asyncify.handleSleepReturnValue`. + // `Asyncify.handleSleepReturnValue` contains the return + // value of the last C function to have executed + // `Asyncify.handleSleep()`, where as `asyncWasmReturnValue` + // contains the return value of the exported WASM function + // that may have called C functions that + // call `Asyncify.handleSleep()`. + var asyncPromiseHandlers = Asyncify.asyncPromiseHandlers; + if (asyncPromiseHandlers) { + Asyncify.asyncPromiseHandlers = null; + (isError ? asyncPromiseHandlers.reject : asyncPromiseHandlers.resolve)(asyncWasmReturnValue); + handled = true; + } + } + if (isError && !handled) { + // If there was an error and it was not handled by now, we have no choice but to + // rethrow that error into the global scope where it can be caught only by + // `onerror` or `onunhandledpromiserejection`. + throw asyncWasmReturnValue; + } + }); + reachedAfterCallback = true; + if (!reachedCallback) { + // A true async operation was begun; start a sleep. + Asyncify.state = Asyncify.State.Unwinding; + // TODO: reuse, don't alloc/free every sleep + Asyncify.currData = Asyncify.allocateData(); + if (typeof Browser != 'undefined' && Browser.mainLoop.func) { + Browser.mainLoop.pause(); + } + runAndAbortIfError(() => _asyncify_start_unwind(Asyncify.currData)); + } + } else if (Asyncify.state === Asyncify.State.Rewinding) { + // Stop a resume. + Asyncify.state = Asyncify.State.Normal; + runAndAbortIfError(_asyncify_stop_rewind); + _free(Asyncify.currData); + Asyncify.currData = null; + // Call all sleep callbacks now that the sleep-resume is all done. + Asyncify.sleepCallbacks.forEach(callUserCallback); + } else { + abort(`invalid state: ${Asyncify.state}`); + } + return Asyncify.handleSleepReturnValue; + }, + handleAsync(startAsync) { + return Asyncify.handleSleep((wakeUp) => { + // TODO: add error handling as a second param when handleSleep implements it. + startAsync().then(wakeUp); + }); + }, + }; + + var getCFunc = (ident) => { + var func = Module['_' + ident]; // closure exported function + assert(func, 'Cannot call unknown function ' + ident + ', make sure it is exported'); + return func; + }; + + var writeArrayToMemory = (array, buffer) => { + assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)') + HEAP8.set(array, buffer); + }; + + + + + + + + + /** + * @param {string|null=} returnType + * @param {Array=} argTypes + * @param {Arguments|Array=} args + * @param {Object=} opts + */ + var ccall = (ident, returnType, argTypes, args, opts) => { + // For fast lookup of conversion functions + var toC = { + 'string': (str) => { + var ret = 0; + if (str !== null && str !== undefined && str !== 0) { // null string + // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' + ret = stringToUTF8OnStack(str); + } + return ret; + }, + 'array': (arr) => { + var ret = stackAlloc(arr.length); + writeArrayToMemory(arr, ret); + return ret; + } + }; + + function convertReturnValue(ret) { + if (returnType === 'string') { + return UTF8ToString(ret); + } + if (returnType === 'boolean') return Boolean(ret); + return ret; + } + + var func = getCFunc(ident); + var cArgs = []; + var stack = 0; + assert(returnType !== 'array', 'Return type should not be "array".'); + if (args) { + for (var i = 0; i < args.length; i++) { + var converter = toC[argTypes[i]]; + if (converter) { + if (stack === 0) stack = stackSave(); + cArgs[i] = converter(args[i]); + } else { + cArgs[i] = args[i]; + } + } + } + // Data for a previous async operation that was in flight before us. + var previousAsync = Asyncify.currData; + var ret = func(...cArgs); + function onDone(ret) { + runtimeKeepalivePop(); + if (stack !== 0) stackRestore(stack); + return convertReturnValue(ret); + } + var asyncMode = opts?.async; + + // Keep the runtime alive through all calls. Note that this call might not be + // async, but for simplicity we push and pop in all calls. + runtimeKeepalivePush(); + if (Asyncify.currData != previousAsync) { + // A change in async operation happened. If there was already an async + // operation in flight before us, that is an error: we should not start + // another async operation while one is active, and we should not stop one + // either. The only valid combination is to have no change in the async + // data (so we either had one in flight and left it alone, or we didn't have + // one), or to have nothing in flight and to start one. + assert(!(previousAsync && Asyncify.currData), 'We cannot start an async operation when one is already flight'); + assert(!(previousAsync && !Asyncify.currData), 'We cannot stop an async operation in flight'); + // This is a new async operation. The wasm is paused and has unwound its stack. + // We need to return a Promise that resolves the return value + // once the stack is rewound and execution finishes. + assert(asyncMode, 'The call to ' + ident + ' is running asynchronously. If this was intended, add the async option to the ccall/cwrap call.'); + return Asyncify.whenDone().then(onDone); + } + + ret = onDone(ret); + // If this is an async ccall, ensure we return a promise + if (asyncMode) return Promise.resolve(ret); + return ret; + }; + + + + /** + * @param {string=} returnType + * @param {Array=} argTypes + * @param {Object=} opts + */ + var cwrap = (ident, returnType, argTypes, opts) => { + return (...args) => ccall(ident, returnType, argTypes, args, opts); + }; + + + + + + + + + + var FS_createPath = FS.createPath; + + + + var FS_unlink = (path) => FS.unlink(path); + + var FS_createLazyFile = FS.createLazyFile; + + var FS_createDevice = FS.createDevice; + + FS.createPreloadedFile = FS_createPreloadedFile; + FS.staticInit(); + // Set module methods based on EXPORTED_RUNTIME_METHODS + Module["FS_createPath"] = FS.createPath; + Module["FS_createDataFile"] = FS.createDataFile; + Module["FS_createPreloadedFile"] = FS.createPreloadedFile; + Module["FS_unlink"] = FS.unlink; + Module["FS_createLazyFile"] = FS.createLazyFile; + Module["FS_createDevice"] = FS.createDevice; + ; + + // exports + Module["requestFullscreen"] = Browser.requestFullscreen; + Module["requestFullScreen"] = Browser.requestFullScreen; + Module["requestAnimationFrame"] = Browser.requestAnimationFrame; + Module["setCanvasSize"] = Browser.setCanvasSize; + Module["pauseMainLoop"] = Browser.mainLoop.pause; + Module["resumeMainLoop"] = Browser.mainLoop.resume; + Module["getUserMedia"] = Browser.getUserMedia; + Module["createContext"] = Browser.createContext; + var preloadedImages = {}; + var preloadedAudios = {};; +for (var i = 0; i < 32; ++i) tempFixedLengthArray.push(new Array(i));; +var miniTempWebGLFloatBuffersStorage = new Float32Array(288); + // Create GL_POOL_TEMP_BUFFERS_SIZE+1 temporary buffers, for uploads of size 0 through GL_POOL_TEMP_BUFFERS_SIZE inclusive + for (/**@suppress{duplicate}*/var i = 0; i <= 288; ++i) { + miniTempWebGLFloatBuffers[i] = miniTempWebGLFloatBuffersStorage.subarray(0, i); + }; +var miniTempWebGLIntBuffersStorage = new Int32Array(288); + // Create GL_POOL_TEMP_BUFFERS_SIZE+1 temporary buffers, for uploads of size 0 through GL_POOL_TEMP_BUFFERS_SIZE inclusive + for (/**@suppress{duplicate}*/var i = 0; i <= 288; ++i) { + miniTempWebGLIntBuffers[i] = miniTempWebGLIntBuffersStorage.subarray(0, i); + }; +if (globalThis.crypto === undefined) { globalThis.crypto = require('crypto'); }; +var MP_JS_EPOCH = Date.now(); +function checkIncomingModuleAPI() { + ignoredModuleProp('fetchSettings'); +} +var wasmImports = { + /** @export */ + __syscall_chdir: ___syscall_chdir, + /** @export */ + __syscall_fcntl64: ___syscall_fcntl64, + /** @export */ + __syscall_fstat64: ___syscall_fstat64, + /** @export */ + __syscall_getcwd: ___syscall_getcwd, + /** @export */ + __syscall_getdents64: ___syscall_getdents64, + /** @export */ + __syscall_ioctl: ___syscall_ioctl, + /** @export */ + __syscall_lstat64: ___syscall_lstat64, + /** @export */ + __syscall_mkdirat: ___syscall_mkdirat, + /** @export */ + __syscall_newfstatat: ___syscall_newfstatat, + /** @export */ + __syscall_openat: ___syscall_openat, + /** @export */ + __syscall_poll: ___syscall_poll, + /** @export */ + __syscall_renameat: ___syscall_renameat, + /** @export */ + __syscall_rmdir: ___syscall_rmdir, + /** @export */ + __syscall_stat64: ___syscall_stat64, + /** @export */ + __syscall_statfs64: ___syscall_statfs64, + /** @export */ + __syscall_unlinkat: ___syscall_unlinkat, + /** @export */ + _emscripten_get_now_is_monotonic: __emscripten_get_now_is_monotonic, + /** @export */ + _emscripten_memcpy_js: __emscripten_memcpy_js, + /** @export */ + _emscripten_throw_longjmp: __emscripten_throw_longjmp, + /** @export */ + call0, + /** @export */ + call0_kwarg, + /** @export */ + call1, + /** @export */ + call1_kwarg, + /** @export */ + call2, + /** @export */ + calln, + /** @export */ + create_promise, + /** @export */ + eglBindAPI: _eglBindAPI, + /** @export */ + eglChooseConfig: _eglChooseConfig, + /** @export */ + eglCreateContext: _eglCreateContext, + /** @export */ + eglCreateWindowSurface: _eglCreateWindowSurface, + /** @export */ + eglDestroyContext: _eglDestroyContext, + /** @export */ + eglDestroySurface: _eglDestroySurface, + /** @export */ + eglGetConfigAttrib: _eglGetConfigAttrib, + /** @export */ + eglGetDisplay: _eglGetDisplay, + /** @export */ + eglGetError: _eglGetError, + /** @export */ + eglInitialize: _eglInitialize, + /** @export */ + eglMakeCurrent: _eglMakeCurrent, + /** @export */ + eglQueryString: _eglQueryString, + /** @export */ + eglSwapBuffers: _eglSwapBuffers, + /** @export */ + eglSwapInterval: _eglSwapInterval, + /** @export */ + eglTerminate: _eglTerminate, + /** @export */ + eglWaitGL: _eglWaitGL, + /** @export */ + eglWaitNative: _eglWaitNative, + /** @export */ + emscripten_asm_const_int: _emscripten_asm_const_int, + /** @export */ + emscripten_asm_const_int_sync_on_main_thread: _emscripten_asm_const_int_sync_on_main_thread, + /** @export */ + emscripten_asm_const_ptr_sync_on_main_thread: _emscripten_asm_const_ptr_sync_on_main_thread, + /** @export */ + emscripten_cancel_main_loop: _emscripten_cancel_main_loop, + /** @export */ + emscripten_date_now: _emscripten_date_now, + /** @export */ + emscripten_exit_fullscreen: _emscripten_exit_fullscreen, + /** @export */ + emscripten_exit_pointerlock: _emscripten_exit_pointerlock, + /** @export */ + emscripten_force_exit: _emscripten_force_exit, + /** @export */ + emscripten_get_device_pixel_ratio: _emscripten_get_device_pixel_ratio, + /** @export */ + emscripten_get_element_css_size: _emscripten_get_element_css_size, + /** @export */ + emscripten_get_gamepad_status: _emscripten_get_gamepad_status, + /** @export */ + emscripten_get_now: _emscripten_get_now, + /** @export */ + emscripten_get_num_gamepads: _emscripten_get_num_gamepads, + /** @export */ + emscripten_get_screen_size: _emscripten_get_screen_size, + /** @export */ + emscripten_glActiveTexture: _emscripten_glActiveTexture, + /** @export */ + emscripten_glAttachShader: _emscripten_glAttachShader, + /** @export */ + emscripten_glBeginQueryEXT: _emscripten_glBeginQueryEXT, + /** @export */ + emscripten_glBindAttribLocation: _emscripten_glBindAttribLocation, + /** @export */ + emscripten_glBindBuffer: _emscripten_glBindBuffer, + /** @export */ + emscripten_glBindFramebuffer: _emscripten_glBindFramebuffer, + /** @export */ + emscripten_glBindRenderbuffer: _emscripten_glBindRenderbuffer, + /** @export */ + emscripten_glBindTexture: _emscripten_glBindTexture, + /** @export */ + emscripten_glBindVertexArrayOES: _emscripten_glBindVertexArrayOES, + /** @export */ + emscripten_glBlendColor: _emscripten_glBlendColor, + /** @export */ + emscripten_glBlendEquation: _emscripten_glBlendEquation, + /** @export */ + emscripten_glBlendEquationSeparate: _emscripten_glBlendEquationSeparate, + /** @export */ + emscripten_glBlendFunc: _emscripten_glBlendFunc, + /** @export */ + emscripten_glBlendFuncSeparate: _emscripten_glBlendFuncSeparate, + /** @export */ + emscripten_glBufferData: _emscripten_glBufferData, + /** @export */ + emscripten_glBufferSubData: _emscripten_glBufferSubData, + /** @export */ + emscripten_glCheckFramebufferStatus: _emscripten_glCheckFramebufferStatus, + /** @export */ + emscripten_glClear: _emscripten_glClear, + /** @export */ + emscripten_glClearColor: _emscripten_glClearColor, + /** @export */ + emscripten_glClearDepthf: _emscripten_glClearDepthf, + /** @export */ + emscripten_glClearStencil: _emscripten_glClearStencil, + /** @export */ + emscripten_glClipControlEXT: _emscripten_glClipControlEXT, + /** @export */ + emscripten_glColorMask: _emscripten_glColorMask, + /** @export */ + emscripten_glCompileShader: _emscripten_glCompileShader, + /** @export */ + emscripten_glCompressedTexImage2D: _emscripten_glCompressedTexImage2D, + /** @export */ + emscripten_glCompressedTexSubImage2D: _emscripten_glCompressedTexSubImage2D, + /** @export */ + emscripten_glCopyTexImage2D: _emscripten_glCopyTexImage2D, + /** @export */ + emscripten_glCopyTexSubImage2D: _emscripten_glCopyTexSubImage2D, + /** @export */ + emscripten_glCreateProgram: _emscripten_glCreateProgram, + /** @export */ + emscripten_glCreateShader: _emscripten_glCreateShader, + /** @export */ + emscripten_glCullFace: _emscripten_glCullFace, + /** @export */ + emscripten_glDeleteBuffers: _emscripten_glDeleteBuffers, + /** @export */ + emscripten_glDeleteFramebuffers: _emscripten_glDeleteFramebuffers, + /** @export */ + emscripten_glDeleteProgram: _emscripten_glDeleteProgram, + /** @export */ + emscripten_glDeleteQueriesEXT: _emscripten_glDeleteQueriesEXT, + /** @export */ + emscripten_glDeleteRenderbuffers: _emscripten_glDeleteRenderbuffers, + /** @export */ + emscripten_glDeleteShader: _emscripten_glDeleteShader, + /** @export */ + emscripten_glDeleteTextures: _emscripten_glDeleteTextures, + /** @export */ + emscripten_glDeleteVertexArraysOES: _emscripten_glDeleteVertexArraysOES, + /** @export */ + emscripten_glDepthFunc: _emscripten_glDepthFunc, + /** @export */ + emscripten_glDepthMask: _emscripten_glDepthMask, + /** @export */ + emscripten_glDepthRangef: _emscripten_glDepthRangef, + /** @export */ + emscripten_glDetachShader: _emscripten_glDetachShader, + /** @export */ + emscripten_glDisable: _emscripten_glDisable, + /** @export */ + emscripten_glDisableVertexAttribArray: _emscripten_glDisableVertexAttribArray, + /** @export */ + emscripten_glDrawArrays: _emscripten_glDrawArrays, + /** @export */ + emscripten_glDrawArraysInstancedANGLE: _emscripten_glDrawArraysInstancedANGLE, + /** @export */ + emscripten_glDrawBuffersWEBGL: _emscripten_glDrawBuffersWEBGL, + /** @export */ + emscripten_glDrawElements: _emscripten_glDrawElements, + /** @export */ + emscripten_glDrawElementsInstancedANGLE: _emscripten_glDrawElementsInstancedANGLE, + /** @export */ + emscripten_glEnable: _emscripten_glEnable, + /** @export */ + emscripten_glEnableVertexAttribArray: _emscripten_glEnableVertexAttribArray, + /** @export */ + emscripten_glEndQueryEXT: _emscripten_glEndQueryEXT, + /** @export */ + emscripten_glFinish: _emscripten_glFinish, + /** @export */ + emscripten_glFlush: _emscripten_glFlush, + /** @export */ + emscripten_glFramebufferRenderbuffer: _emscripten_glFramebufferRenderbuffer, + /** @export */ + emscripten_glFramebufferTexture2D: _emscripten_glFramebufferTexture2D, + /** @export */ + emscripten_glFrontFace: _emscripten_glFrontFace, + /** @export */ + emscripten_glGenBuffers: _emscripten_glGenBuffers, + /** @export */ + emscripten_glGenFramebuffers: _emscripten_glGenFramebuffers, + /** @export */ + emscripten_glGenQueriesEXT: _emscripten_glGenQueriesEXT, + /** @export */ + emscripten_glGenRenderbuffers: _emscripten_glGenRenderbuffers, + /** @export */ + emscripten_glGenTextures: _emscripten_glGenTextures, + /** @export */ + emscripten_glGenVertexArraysOES: _emscripten_glGenVertexArraysOES, + /** @export */ + emscripten_glGenerateMipmap: _emscripten_glGenerateMipmap, + /** @export */ + emscripten_glGetActiveAttrib: _emscripten_glGetActiveAttrib, + /** @export */ + emscripten_glGetActiveUniform: _emscripten_glGetActiveUniform, + /** @export */ + emscripten_glGetAttachedShaders: _emscripten_glGetAttachedShaders, + /** @export */ + emscripten_glGetAttribLocation: _emscripten_glGetAttribLocation, + /** @export */ + emscripten_glGetBooleanv: _emscripten_glGetBooleanv, + /** @export */ + emscripten_glGetBufferParameteriv: _emscripten_glGetBufferParameteriv, + /** @export */ + emscripten_glGetError: _emscripten_glGetError, + /** @export */ + emscripten_glGetFloatv: _emscripten_glGetFloatv, + /** @export */ + emscripten_glGetFramebufferAttachmentParameteriv: _emscripten_glGetFramebufferAttachmentParameteriv, + /** @export */ + emscripten_glGetIntegerv: _emscripten_glGetIntegerv, + /** @export */ + emscripten_glGetProgramInfoLog: _emscripten_glGetProgramInfoLog, + /** @export */ + emscripten_glGetProgramiv: _emscripten_glGetProgramiv, + /** @export */ + emscripten_glGetQueryObjecti64vEXT: _emscripten_glGetQueryObjecti64vEXT, + /** @export */ + emscripten_glGetQueryObjectivEXT: _emscripten_glGetQueryObjectivEXT, + /** @export */ + emscripten_glGetQueryObjectui64vEXT: _emscripten_glGetQueryObjectui64vEXT, + /** @export */ + emscripten_glGetQueryObjectuivEXT: _emscripten_glGetQueryObjectuivEXT, + /** @export */ + emscripten_glGetQueryivEXT: _emscripten_glGetQueryivEXT, + /** @export */ + emscripten_glGetRenderbufferParameteriv: _emscripten_glGetRenderbufferParameteriv, + /** @export */ + emscripten_glGetShaderInfoLog: _emscripten_glGetShaderInfoLog, + /** @export */ + emscripten_glGetShaderPrecisionFormat: _emscripten_glGetShaderPrecisionFormat, + /** @export */ + emscripten_glGetShaderSource: _emscripten_glGetShaderSource, + /** @export */ + emscripten_glGetShaderiv: _emscripten_glGetShaderiv, + /** @export */ + emscripten_glGetString: _emscripten_glGetString, + /** @export */ + emscripten_glGetTexParameterfv: _emscripten_glGetTexParameterfv, + /** @export */ + emscripten_glGetTexParameteriv: _emscripten_glGetTexParameteriv, + /** @export */ + emscripten_glGetUniformLocation: _emscripten_glGetUniformLocation, + /** @export */ + emscripten_glGetUniformfv: _emscripten_glGetUniformfv, + /** @export */ + emscripten_glGetUniformiv: _emscripten_glGetUniformiv, + /** @export */ + emscripten_glGetVertexAttribPointerv: _emscripten_glGetVertexAttribPointerv, + /** @export */ + emscripten_glGetVertexAttribfv: _emscripten_glGetVertexAttribfv, + /** @export */ + emscripten_glGetVertexAttribiv: _emscripten_glGetVertexAttribiv, + /** @export */ + emscripten_glHint: _emscripten_glHint, + /** @export */ + emscripten_glIsBuffer: _emscripten_glIsBuffer, + /** @export */ + emscripten_glIsEnabled: _emscripten_glIsEnabled, + /** @export */ + emscripten_glIsFramebuffer: _emscripten_glIsFramebuffer, + /** @export */ + emscripten_glIsProgram: _emscripten_glIsProgram, + /** @export */ + emscripten_glIsQueryEXT: _emscripten_glIsQueryEXT, + /** @export */ + emscripten_glIsRenderbuffer: _emscripten_glIsRenderbuffer, + /** @export */ + emscripten_glIsShader: _emscripten_glIsShader, + /** @export */ + emscripten_glIsTexture: _emscripten_glIsTexture, + /** @export */ + emscripten_glIsVertexArrayOES: _emscripten_glIsVertexArrayOES, + /** @export */ + emscripten_glLineWidth: _emscripten_glLineWidth, + /** @export */ + emscripten_glLinkProgram: _emscripten_glLinkProgram, + /** @export */ + emscripten_glPixelStorei: _emscripten_glPixelStorei, + /** @export */ + emscripten_glPolygonModeWEBGL: _emscripten_glPolygonModeWEBGL, + /** @export */ + emscripten_glPolygonOffset: _emscripten_glPolygonOffset, + /** @export */ + emscripten_glPolygonOffsetClampEXT: _emscripten_glPolygonOffsetClampEXT, + /** @export */ + emscripten_glQueryCounterEXT: _emscripten_glQueryCounterEXT, + /** @export */ + emscripten_glReadPixels: _emscripten_glReadPixels, + /** @export */ + emscripten_glReleaseShaderCompiler: _emscripten_glReleaseShaderCompiler, + /** @export */ + emscripten_glRenderbufferStorage: _emscripten_glRenderbufferStorage, + /** @export */ + emscripten_glSampleCoverage: _emscripten_glSampleCoverage, + /** @export */ + emscripten_glScissor: _emscripten_glScissor, + /** @export */ + emscripten_glShaderBinary: _emscripten_glShaderBinary, + /** @export */ + emscripten_glShaderSource: _emscripten_glShaderSource, + /** @export */ + emscripten_glStencilFunc: _emscripten_glStencilFunc, + /** @export */ + emscripten_glStencilFuncSeparate: _emscripten_glStencilFuncSeparate, + /** @export */ + emscripten_glStencilMask: _emscripten_glStencilMask, + /** @export */ + emscripten_glStencilMaskSeparate: _emscripten_glStencilMaskSeparate, + /** @export */ + emscripten_glStencilOp: _emscripten_glStencilOp, + /** @export */ + emscripten_glStencilOpSeparate: _emscripten_glStencilOpSeparate, + /** @export */ + emscripten_glTexImage2D: _emscripten_glTexImage2D, + /** @export */ + emscripten_glTexParameterf: _emscripten_glTexParameterf, + /** @export */ + emscripten_glTexParameterfv: _emscripten_glTexParameterfv, + /** @export */ + emscripten_glTexParameteri: _emscripten_glTexParameteri, + /** @export */ + emscripten_glTexParameteriv: _emscripten_glTexParameteriv, + /** @export */ + emscripten_glTexSubImage2D: _emscripten_glTexSubImage2D, + /** @export */ + emscripten_glUniform1f: _emscripten_glUniform1f, + /** @export */ + emscripten_glUniform1fv: _emscripten_glUniform1fv, + /** @export */ + emscripten_glUniform1i: _emscripten_glUniform1i, + /** @export */ + emscripten_glUniform1iv: _emscripten_glUniform1iv, + /** @export */ + emscripten_glUniform2f: _emscripten_glUniform2f, + /** @export */ + emscripten_glUniform2fv: _emscripten_glUniform2fv, + /** @export */ + emscripten_glUniform2i: _emscripten_glUniform2i, + /** @export */ + emscripten_glUniform2iv: _emscripten_glUniform2iv, + /** @export */ + emscripten_glUniform3f: _emscripten_glUniform3f, + /** @export */ + emscripten_glUniform3fv: _emscripten_glUniform3fv, + /** @export */ + emscripten_glUniform3i: _emscripten_glUniform3i, + /** @export */ + emscripten_glUniform3iv: _emscripten_glUniform3iv, + /** @export */ + emscripten_glUniform4f: _emscripten_glUniform4f, + /** @export */ + emscripten_glUniform4fv: _emscripten_glUniform4fv, + /** @export */ + emscripten_glUniform4i: _emscripten_glUniform4i, + /** @export */ + emscripten_glUniform4iv: _emscripten_glUniform4iv, + /** @export */ + emscripten_glUniformMatrix2fv: _emscripten_glUniformMatrix2fv, + /** @export */ + emscripten_glUniformMatrix3fv: _emscripten_glUniformMatrix3fv, + /** @export */ + emscripten_glUniformMatrix4fv: _emscripten_glUniformMatrix4fv, + /** @export */ + emscripten_glUseProgram: _emscripten_glUseProgram, + /** @export */ + emscripten_glValidateProgram: _emscripten_glValidateProgram, + /** @export */ + emscripten_glVertexAttrib1f: _emscripten_glVertexAttrib1f, + /** @export */ + emscripten_glVertexAttrib1fv: _emscripten_glVertexAttrib1fv, + /** @export */ + emscripten_glVertexAttrib2f: _emscripten_glVertexAttrib2f, + /** @export */ + emscripten_glVertexAttrib2fv: _emscripten_glVertexAttrib2fv, + /** @export */ + emscripten_glVertexAttrib3f: _emscripten_glVertexAttrib3f, + /** @export */ + emscripten_glVertexAttrib3fv: _emscripten_glVertexAttrib3fv, + /** @export */ + emscripten_glVertexAttrib4f: _emscripten_glVertexAttrib4f, + /** @export */ + emscripten_glVertexAttrib4fv: _emscripten_glVertexAttrib4fv, + /** @export */ + emscripten_glVertexAttribDivisorANGLE: _emscripten_glVertexAttribDivisorANGLE, + /** @export */ + emscripten_glVertexAttribPointer: _emscripten_glVertexAttribPointer, + /** @export */ + emscripten_glViewport: _emscripten_glViewport, + /** @export */ + emscripten_has_asyncify: _emscripten_has_asyncify, + /** @export */ + emscripten_request_fullscreen_strategy: _emscripten_request_fullscreen_strategy, + /** @export */ + emscripten_request_pointerlock: _emscripten_request_pointerlock, + /** @export */ + emscripten_resize_heap: _emscripten_resize_heap, + /** @export */ + emscripten_sample_gamepad_data: _emscripten_sample_gamepad_data, + /** @export */ + emscripten_scan_registers: _emscripten_scan_registers, + /** @export */ + emscripten_set_beforeunload_callback_on_thread: _emscripten_set_beforeunload_callback_on_thread, + /** @export */ + emscripten_set_blur_callback_on_thread: _emscripten_set_blur_callback_on_thread, + /** @export */ + emscripten_set_canvas_element_size: _emscripten_set_canvas_element_size, + /** @export */ + emscripten_set_element_css_size: _emscripten_set_element_css_size, + /** @export */ + emscripten_set_focus_callback_on_thread: _emscripten_set_focus_callback_on_thread, + /** @export */ + emscripten_set_fullscreenchange_callback_on_thread: _emscripten_set_fullscreenchange_callback_on_thread, + /** @export */ + emscripten_set_gamepadconnected_callback_on_thread: _emscripten_set_gamepadconnected_callback_on_thread, + /** @export */ + emscripten_set_gamepaddisconnected_callback_on_thread: _emscripten_set_gamepaddisconnected_callback_on_thread, + /** @export */ + emscripten_set_keydown_callback_on_thread: _emscripten_set_keydown_callback_on_thread, + /** @export */ + emscripten_set_keypress_callback_on_thread: _emscripten_set_keypress_callback_on_thread, + /** @export */ + emscripten_set_keyup_callback_on_thread: _emscripten_set_keyup_callback_on_thread, + /** @export */ + emscripten_set_main_loop: _emscripten_set_main_loop, + /** @export */ + emscripten_set_mousedown_callback_on_thread: _emscripten_set_mousedown_callback_on_thread, + /** @export */ + emscripten_set_mouseenter_callback_on_thread: _emscripten_set_mouseenter_callback_on_thread, + /** @export */ + emscripten_set_mouseleave_callback_on_thread: _emscripten_set_mouseleave_callback_on_thread, + /** @export */ + emscripten_set_mousemove_callback_on_thread: _emscripten_set_mousemove_callback_on_thread, + /** @export */ + emscripten_set_mouseup_callback_on_thread: _emscripten_set_mouseup_callback_on_thread, + /** @export */ + emscripten_set_pointerlockchange_callback_on_thread: _emscripten_set_pointerlockchange_callback_on_thread, + /** @export */ + emscripten_set_resize_callback_on_thread: _emscripten_set_resize_callback_on_thread, + /** @export */ + emscripten_set_touchcancel_callback_on_thread: _emscripten_set_touchcancel_callback_on_thread, + /** @export */ + emscripten_set_touchend_callback_on_thread: _emscripten_set_touchend_callback_on_thread, + /** @export */ + emscripten_set_touchmove_callback_on_thread: _emscripten_set_touchmove_callback_on_thread, + /** @export */ + emscripten_set_touchstart_callback_on_thread: _emscripten_set_touchstart_callback_on_thread, + /** @export */ + emscripten_set_visibilitychange_callback_on_thread: _emscripten_set_visibilitychange_callback_on_thread, + /** @export */ + emscripten_set_wheel_callback_on_thread: _emscripten_set_wheel_callback_on_thread, + /** @export */ + emscripten_set_window_title: _emscripten_set_window_title, + /** @export */ + emscripten_sleep: _emscripten_sleep, + /** @export */ + environ_get: _environ_get, + /** @export */ + environ_sizes_get: _environ_sizes_get, + /** @export */ + fd_close: _fd_close, + /** @export */ + fd_read: _fd_read, + /** @export */ + fd_seek: _fd_seek, + /** @export */ + fd_sync: _fd_sync, + /** @export */ + fd_write: _fd_write, + /** @export */ + has_attr, + /** @export */ + invoke_i, + /** @export */ + invoke_ii, + /** @export */ + invoke_iii, + /** @export */ + invoke_iiii, + /** @export */ + invoke_iiiii, + /** @export */ + invoke_iiiiii, + /** @export */ + invoke_v, + /** @export */ + invoke_vi, + /** @export */ + invoke_vii, + /** @export */ + invoke_viii, + /** @export */ + invoke_viiii, + /** @export */ + js_check_existing, + /** @export */ + js_get_error_info, + /** @export */ + js_get_iter, + /** @export */ + js_get_proxy_js_ref_info, + /** @export */ + js_iter_next, + /** @export */ + js_reflect_construct, + /** @export */ + js_subscr_load, + /** @export */ + js_subscr_store, + /** @export */ + js_then_continue, + /** @export */ + js_then_reject, + /** @export */ + js_then_resolve, + /** @export */ + lookup_attr, + /** @export */ + mp_js_hook: _mp_js_hook, + /** @export */ + mp_js_random_u32: _mp_js_random_u32, + /** @export */ + mp_js_ticks_ms: _mp_js_ticks_ms, + /** @export */ + mp_js_time_ms: _mp_js_time_ms, + /** @export */ + proxy_convert_mp_to_js_then_js_to_js_then_js_to_mp_obj_jsside, + /** @export */ + proxy_convert_mp_to_js_then_js_to_mp_obj_jsside, + /** @export */ + proxy_js_free_obj, + /** @export */ + store_attr +}; +var wasmExports = createWasm(); +var ___wasm_call_ctors = createExportWrapper('__wasm_call_ctors', 0); +var _mp_sched_keyboard_interrupt = Module['_mp_sched_keyboard_interrupt'] = createExportWrapper('mp_sched_keyboard_interrupt', 0); +var _mp_handle_pending = Module['_mp_handle_pending'] = createExportWrapper('mp_handle_pending', 1); +var _tulip_tick = Module['_tulip_tick'] = createExportWrapper('tulip_tick', 1); +var _mp_js_init = Module['_mp_js_init'] = createExportWrapper('mp_js_init', 2); +var _malloc = Module['_malloc'] = createExportWrapper('malloc', 1); +var _mp_js_register_js_module = Module['_mp_js_register_js_module'] = createExportWrapper('mp_js_register_js_module', 2); +var _mp_js_do_import = Module['_mp_js_do_import'] = createExportWrapper('mp_js_do_import', 2); +var _proxy_convert_mp_to_js_obj_cside = Module['_proxy_convert_mp_to_js_obj_cside'] = createExportWrapper('proxy_convert_mp_to_js_obj_cside', 2); +var _mp_js_do_exec = Module['_mp_js_do_exec'] = createExportWrapper('mp_js_do_exec', 3); +var _mp_js_frozen_exec = Module['_mp_js_frozen_exec'] = createExportWrapper('mp_js_frozen_exec', 1); +var _mp_js_do_exec_async = Module['_mp_js_do_exec_async'] = createExportWrapper('mp_js_do_exec_async', 3); +var _mp_js_repl_init = Module['_mp_js_repl_init'] = createExportWrapper('mp_js_repl_init', 0); +var _mp_js_repl_process_char = Module['_mp_js_repl_process_char'] = createExportWrapper('mp_js_repl_process_char', 1); +var _mp_hal_get_interrupt_char = Module['_mp_hal_get_interrupt_char'] = createExportWrapper('mp_hal_get_interrupt_char', 1); +var _proxy_c_init = Module['_proxy_c_init'] = createExportWrapper('proxy_c_init', 0); +var _proxy_c_free_obj = Module['_proxy_c_free_obj'] = createExportWrapper('proxy_c_free_obj', 1); +var _free = Module['_free'] = createExportWrapper('free', 1); +var _proxy_c_to_js_call = Module['_proxy_c_to_js_call'] = createExportWrapper('proxy_c_to_js_call', 4); +var _proxy_c_to_js_dir = Module['_proxy_c_to_js_dir'] = createExportWrapper('proxy_c_to_js_dir', 2); +var _proxy_c_to_js_has_attr = Module['_proxy_c_to_js_has_attr'] = createExportWrapper('proxy_c_to_js_has_attr', 2); +var _proxy_c_to_js_lookup_attr = Module['_proxy_c_to_js_lookup_attr'] = createExportWrapper('proxy_c_to_js_lookup_attr', 3); +var _proxy_c_to_js_store_attr = Module['_proxy_c_to_js_store_attr'] = createExportWrapper('proxy_c_to_js_store_attr', 3); +var _proxy_c_to_js_delete_attr = Module['_proxy_c_to_js_delete_attr'] = createExportWrapper('proxy_c_to_js_delete_attr', 2); +var _proxy_c_to_js_get_type = Module['_proxy_c_to_js_get_type'] = createExportWrapper('proxy_c_to_js_get_type', 1); +var _proxy_c_to_js_get_array = Module['_proxy_c_to_js_get_array'] = createExportWrapper('proxy_c_to_js_get_array', 2); +var _proxy_c_to_js_get_dict = Module['_proxy_c_to_js_get_dict'] = createExportWrapper('proxy_c_to_js_get_dict', 2); +var _proxy_c_to_js_get_iter = Module['_proxy_c_to_js_get_iter'] = createExportWrapper('proxy_c_to_js_get_iter', 1); +var _proxy_c_to_js_iternext = Module['_proxy_c_to_js_iternext'] = createExportWrapper('proxy_c_to_js_iternext', 2); +var _proxy_c_to_js_resume = Module['_proxy_c_to_js_resume'] = createExportWrapper('proxy_c_to_js_resume', 2); +var _process_single_midi_byte = Module['_process_single_midi_byte'] = createExportWrapper('process_single_midi_byte', 1); +var _emscripten_stack_get_base = () => (_emscripten_stack_get_base = wasmExports['emscripten_stack_get_base'])(); +var _emscripten_stack_get_current = () => (_emscripten_stack_get_current = wasmExports['emscripten_stack_get_current'])(); +var _fflush = createExportWrapper('fflush', 1); +var _strerror = createExportWrapper('strerror', 1); +var _setThrew = createExportWrapper('setThrew', 2); +var _emscripten_stack_init = () => (_emscripten_stack_init = wasmExports['emscripten_stack_init'])(); +var _emscripten_stack_get_free = () => (_emscripten_stack_get_free = wasmExports['emscripten_stack_get_free'])(); +var _emscripten_stack_get_end = () => (_emscripten_stack_get_end = wasmExports['emscripten_stack_get_end'])(); +var __emscripten_stack_restore = (a0) => (__emscripten_stack_restore = wasmExports['_emscripten_stack_restore'])(a0); +var __emscripten_stack_alloc = (a0) => (__emscripten_stack_alloc = wasmExports['_emscripten_stack_alloc'])(a0); +var dynCall_viii = Module['dynCall_viii'] = createExportWrapper('dynCall_viii', 4); +var dynCall_vi = Module['dynCall_vi'] = createExportWrapper('dynCall_vi', 2); +var dynCall_ii = Module['dynCall_ii'] = createExportWrapper('dynCall_ii', 2); +var dynCall_vii = Module['dynCall_vii'] = createExportWrapper('dynCall_vii', 3); +var dynCall_iii = Module['dynCall_iii'] = createExportWrapper('dynCall_iii', 3); +var dynCall_viiii = Module['dynCall_viiii'] = createExportWrapper('dynCall_viiii', 5); +var dynCall_iiii = Module['dynCall_iiii'] = createExportWrapper('dynCall_iiii', 4); +var dynCall_v = Module['dynCall_v'] = createExportWrapper('dynCall_v', 1); +var dynCall_iiiii = Module['dynCall_iiiii'] = createExportWrapper('dynCall_iiiii', 5); +var dynCall_i = Module['dynCall_i'] = createExportWrapper('dynCall_i', 1); +var dynCall_viiiiii = Module['dynCall_viiiiii'] = createExportWrapper('dynCall_viiiiii', 7); +var dynCall_iiiiii = Module['dynCall_iiiiii'] = createExportWrapper('dynCall_iiiiii', 6); +var dynCall_viiiii = Module['dynCall_viiiii'] = createExportWrapper('dynCall_viiiii', 6); +var dynCall_jji = Module['dynCall_jji'] = createExportWrapper('dynCall_jji', 4); +var dynCall_viiiiiii = Module['dynCall_viiiiiii'] = createExportWrapper('dynCall_viiiiiii', 8); +var dynCall_viiiiiiii = Module['dynCall_viiiiiiii'] = createExportWrapper('dynCall_viiiiiiii', 9); +var dynCall_iiiiiiii = Module['dynCall_iiiiiiii'] = createExportWrapper('dynCall_iiiiiiii', 8); +var dynCall_viiiiiiiiii = Module['dynCall_viiiiiiiiii'] = createExportWrapper('dynCall_viiiiiiiiii', 11); +var dynCall_iiiiiiiiii = Module['dynCall_iiiiiiiiii'] = createExportWrapper('dynCall_iiiiiiiiii', 10); +var dynCall_iiiiiiiiiiiiiiff = Module['dynCall_iiiiiiiiiiiiiiff'] = createExportWrapper('dynCall_iiiiiiiiiiiiiiff', 16); +var dynCall_iiiiiiiii = Module['dynCall_iiiiiiiii'] = createExportWrapper('dynCall_iiiiiiiii', 9); +var dynCall_viiiiiiiiiii = Module['dynCall_viiiiiiiiiii'] = createExportWrapper('dynCall_viiiiiiiiiii', 12); +var dynCall_iiiiiidiiff = Module['dynCall_iiiiiidiiff'] = createExportWrapper('dynCall_iiiiiidiiff', 11); +var dynCall_jiji = Module['dynCall_jiji'] = createExportWrapper('dynCall_jiji', 5); +var dynCall_ji = Module['dynCall_ji'] = createExportWrapper('dynCall_ji', 2); +var dynCall_vffff = Module['dynCall_vffff'] = createExportWrapper('dynCall_vffff', 5); +var dynCall_vf = Module['dynCall_vf'] = createExportWrapper('dynCall_vf', 2); +var dynCall_viiiiiiiii = Module['dynCall_viiiiiiiii'] = createExportWrapper('dynCall_viiiiiiiii', 10); +var dynCall_vff = Module['dynCall_vff'] = createExportWrapper('dynCall_vff', 3); +var dynCall_vfi = Module['dynCall_vfi'] = createExportWrapper('dynCall_vfi', 3); +var dynCall_viif = Module['dynCall_viif'] = createExportWrapper('dynCall_viif', 4); +var dynCall_vif = Module['dynCall_vif'] = createExportWrapper('dynCall_vif', 3); +var dynCall_viff = Module['dynCall_viff'] = createExportWrapper('dynCall_viff', 4); +var dynCall_vifff = Module['dynCall_vifff'] = createExportWrapper('dynCall_vifff', 5); +var dynCall_viffff = Module['dynCall_viffff'] = createExportWrapper('dynCall_viffff', 6); +var dynCall_vfff = Module['dynCall_vfff'] = createExportWrapper('dynCall_vfff', 4); +var dynCall_iidiiii = Module['dynCall_iidiiii'] = createExportWrapper('dynCall_iidiiii', 7); +var _asyncify_start_unwind = createExportWrapper('asyncify_start_unwind', 1); +var _asyncify_stop_unwind = createExportWrapper('asyncify_stop_unwind', 0); +var _asyncify_start_rewind = createExportWrapper('asyncify_start_rewind', 1); +var _asyncify_stop_rewind = createExportWrapper('asyncify_stop_rewind', 0); + +function invoke_ii(index,a1) { + var sp = stackSave(); + try { + return dynCall_ii(index,a1); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_viii(index,a1,a2,a3) { + var sp = stackSave(); + try { + dynCall_viii(index,a1,a2,a3); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_iiiii(index,a1,a2,a3,a4) { + var sp = stackSave(); + try { + return dynCall_iiiii(index,a1,a2,a3,a4); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_v(index) { + var sp = stackSave(); + try { + dynCall_v(index); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_iii(index,a1,a2) { + var sp = stackSave(); + try { + return dynCall_iii(index,a1,a2); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_vi(index,a1) { + var sp = stackSave(); + try { + dynCall_vi(index,a1); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_vii(index,a1,a2) { + var sp = stackSave(); + try { + dynCall_vii(index,a1,a2); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_iiii(index,a1,a2,a3) { + var sp = stackSave(); + try { + return dynCall_iiii(index,a1,a2,a3); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_i(index) { + var sp = stackSave(); + try { + return dynCall_i(index); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_viiii(index,a1,a2,a3,a4) { + var sp = stackSave(); + try { + dynCall_viiii(index,a1,a2,a3,a4); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_iiiiii(index,a1,a2,a3,a4,a5) { + var sp = stackSave(); + try { + return dynCall_iiiiii(index,a1,a2,a3,a4,a5); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + + +// include: postamble.js +// === Auto-generated postamble setup entry stuff === + +Module['addRunDependency'] = addRunDependency; +Module['removeRunDependency'] = removeRunDependency; +Module['ccall'] = ccall; +Module['cwrap'] = cwrap; +Module['setValue'] = setValue; +Module['getValue'] = getValue; +Module['PATH'] = PATH; +Module['PATH_FS'] = PATH_FS; +Module['UTF8ToString'] = UTF8ToString; +Module['stringToUTF8'] = stringToUTF8; +Module['lengthBytesUTF8'] = lengthBytesUTF8; +Module['FS_createPreloadedFile'] = FS_createPreloadedFile; +Module['FS_unlink'] = FS_unlink; +Module['FS_createPath'] = FS_createPath; +Module['FS_createDevice'] = FS_createDevice; +Module['FS'] = FS; +Module['FS_createDataFile'] = FS_createDataFile; +Module['FS_createLazyFile'] = FS_createLazyFile; +var missingLibrarySymbols = [ + 'writeI53ToI64Clamped', + 'writeI53ToI64Signaling', + 'writeI53ToU64Clamped', + 'writeI53ToU64Signaling', + 'convertI32PairToI53', + 'convertU32PairToI53', + 'getTempRet0', + 'setTempRet0', + 'inetPton4', + 'inetNtop4', + 'inetPton6', + 'inetNtop6', + 'readSockaddr', + 'writeSockaddr', + 'emscriptenLog', + 'getDynCaller', + 'asmjsMangle', + 'HandleAllocator', + 'getNativeTypeSize', + 'STACK_SIZE', + 'STACK_ALIGN', + 'POINTER_SIZE', + 'ASSERTIONS', + 'uleb128Encode', + 'generateFuncType', + 'convertJsFunctionToWasm', + 'getEmptyTableSlot', + 'updateTableMap', + 'getFunctionAddress', + 'addFunction', + 'removeFunction', + 'reallyNegative', + 'unSign', + 'strLen', + 'reSign', + 'formatString', + 'intArrayToString', + 'AsciiToString', + 'UTF16ToString', + 'stringToUTF16', + 'lengthBytesUTF16', + 'UTF32ToString', + 'stringToUTF32', + 'lengthBytesUTF32', + 'fillDeviceOrientationEventData', + 'registerDeviceOrientationEventCallback', + 'fillDeviceMotionEventData', + 'registerDeviceMotionEventCallback', + 'screenOrientation', + 'fillOrientationChangeEventData', + 'registerOrientationChangeEventCallback', + 'hideEverythingExceptGivenElement', + 'restoreHiddenElements', + 'softFullscreenResizeWebGLRenderTarget', + 'registerPointerlockErrorEventCallback', + 'fillBatteryEventData', + 'battery', + 'registerBatteryEventCallback', + 'jsStackTrace', + 'getCallstack', + 'convertPCtoSourceLocation', + 'checkWasiClock', + 'wasiRightsToMuslOFlags', + 'wasiOFlagsToMuslOFlags', + 'createDyncallWrapper', + 'setImmediateWrapped', + 'clearImmediateWrapped', + 'polyfillSetImmediate', + 'getPromise', + 'makePromise', + 'idsToPromises', + 'makePromiseCallback', + 'ExceptionInfo', + 'findMatchingCatch', + 'Browser_asyncPrepareDataCounter', + 'isLeapYear', + 'ydayFromDate', + 'arraySum', + 'addDays', + 'getSocketFromFD', + 'getSocketAddress', + 'FS_mkdirTree', + '_setNetworkCallback', + 'writeGLArray', + 'registerWebGlEventCallback', + 'ALLOC_NORMAL', + 'ALLOC_STACK', + 'allocate', + 'writeStringToMemory', + 'writeAsciiToMemory', + 'setErrNo', + 'demangle', + 'stackTrace', +]; +missingLibrarySymbols.forEach(missingLibrarySymbol) + +var unexportedSymbols = [ + 'run', + 'addOnPreRun', + 'addOnInit', + 'addOnPreMain', + 'addOnExit', + 'addOnPostRun', + 'out', + 'err', + 'callMain', + 'abort', + 'wasmMemory', + 'wasmExports', + 'writeStackCookie', + 'checkStackCookie', + 'writeI53ToI64', + 'readI53FromI64', + 'readI53FromU64', + 'convertI32PairToI53Checked', + 'stackSave', + 'stackRestore', + 'stackAlloc', + 'ptrToString', + 'zeroMemory', + 'exitJS', + 'getHeapMax', + 'growMemory', + 'ENV', + 'ERRNO_CODES', + 'strError', + 'DNS', + 'Protocols', + 'Sockets', + 'initRandomFill', + 'randomFill', + 'timers', + 'warnOnce', + 'readEmAsmArgsArray', + 'readEmAsmArgs', + 'runEmAsmFunction', + 'runMainThreadEmAsm', + 'jstoi_q', + 'jstoi_s', + 'getExecutableName', + 'listenOnce', + 'autoResumeAudioContext', + 'dynCallLegacy', + 'dynCall', + 'handleException', + 'keepRuntimeAlive', + 'runtimeKeepalivePush', + 'runtimeKeepalivePop', + 'callUserCallback', + 'maybeExit', + 'asyncLoad', + 'alignMemory', + 'mmapAlloc', + 'wasmTable', + 'noExitRuntime', + 'getCFunc', + 'sigToWasmTypes', + 'freeTableIndexes', + 'functionsInTableMap', + 'UTF8Decoder', + 'UTF8ArrayToString', + 'stringToUTF8Array', + 'intArrayFromString', + 'stringToAscii', + 'UTF16Decoder', + 'stringToNewUTF8', + 'stringToUTF8OnStack', + 'writeArrayToMemory', + 'JSEvents', + 'registerKeyEventCallback', + 'specialHTMLTargets', + 'maybeCStringToJsString', + 'findEventTarget', + 'findCanvasEventTarget', + 'getBoundingClientRect', + 'fillMouseEventData', + 'registerMouseEventCallback', + 'registerWheelEventCallback', + 'registerUiEventCallback', + 'registerFocusEventCallback', + 'fillFullscreenChangeEventData', + 'registerFullscreenChangeEventCallback', + 'JSEvents_requestFullscreen', + 'JSEvents_resizeCanvasForFullscreen', + 'registerRestoreOldStyle', + 'setLetterbox', + 'currentFullscreenStrategy', + 'restoreOldWindowedStyle', + 'doRequestFullscreen', + 'fillPointerlockChangeEventData', + 'registerPointerlockChangeEventCallback', + 'requestPointerLock', + 'fillVisibilityChangeEventData', + 'registerVisibilityChangeEventCallback', + 'registerTouchEventCallback', + 'fillGamepadEventData', + 'registerGamepadEventCallback', + 'registerBeforeUnloadEventCallback', + 'setCanvasElementSize', + 'getCanvasElementSize', + 'UNWIND_CACHE', + 'ExitStatus', + 'getEnvStrings', + 'doReadv', + 'doWritev', + 'safeSetTimeout', + 'promiseMap', + 'uncaughtExceptionCount', + 'exceptionLast', + 'exceptionCaught', + 'Browser', + 'setMainLoop', + 'getPreloadedImageData__data', + 'wget', + 'MONTH_DAYS_REGULAR', + 'MONTH_DAYS_LEAP', + 'MONTH_DAYS_REGULAR_CUMULATIVE', + 'MONTH_DAYS_LEAP_CUMULATIVE', + 'SYSCALLS', + 'preloadPlugins', + 'FS_modeStringToFlags', + 'FS_getMode', + 'FS_stdin_getChar_buffer', + 'FS_stdin_getChar', + 'FS_readFile', + 'MEMFS', + 'TTY', + 'PIPEFS', + 'SOCKFS', + 'tempFixedLengthArray', + 'miniTempWebGLFloatBuffers', + 'miniTempWebGLIntBuffers', + 'heapObjectForWebGLType', + 'toTypedArrayIndex', + 'webgl_enable_ANGLE_instanced_arrays', + 'webgl_enable_OES_vertex_array_object', + 'webgl_enable_WEBGL_draw_buffers', + 'webgl_enable_WEBGL_multi_draw', + 'webgl_enable_EXT_polygon_offset_clamp', + 'webgl_enable_EXT_clip_control', + 'webgl_enable_WEBGL_polygon_mode', + 'GL', + 'emscriptenWebGLGet', + 'computeUnpackAlignedImageSize', + 'colorChannelsInGlTextureFormat', + 'emscriptenWebGLGetTexPixelData', + 'emscriptenWebGLGetUniform', + 'webglGetUniformLocation', + 'webglPrepareUniformLocationsBeforeFirstUse', + 'webglGetLeftBracePos', + 'emscriptenWebGLGetVertexAttrib', + '__glGetActiveAttribOrUniform', + 'AL', + 'GLUT', + 'EGL', + 'GLEW', + 'IDBStore', + 'runAndAbortIfError', + 'Asyncify', + 'Fibers', + 'allocateUTF8', + 'allocateUTF8OnStack', + 'print', + 'printErr', + 'IDBFS', +]; +unexportedSymbols.forEach(unexportedRuntimeSymbol); + + + +var calledRun; + +dependenciesFulfilled = function runCaller() { + // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false) + if (!calledRun) run(); + if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled +}; + +function stackCheckInit() { + // This is normally called automatically during __wasm_call_ctors but need to + // get these values before even running any of the ctors so we call it redundantly + // here. + _emscripten_stack_init(); + // TODO(sbc): Move writeStackCookie to native to to avoid this. + writeStackCookie(); +} + +function run() { + + if (runDependencies > 0) { + return; + } + + stackCheckInit(); + + preRun(); + + // a preRun added a dependency, run will be called later + if (runDependencies > 0) { + return; + } + + function doRun() { + // run may have just been called through dependencies being fulfilled just in this very frame, + // or while the async setStatus time below was happening + if (calledRun) return; + calledRun = true; + Module['calledRun'] = true; + + if (ABORT) return; + + initRuntime(); + + readyPromiseResolve(Module); + Module['onRuntimeInitialized']?.(); + + assert(!Module['_main'], 'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]'); + + postRun(); + } + + if (Module['setStatus']) { + Module['setStatus']('Running...'); + setTimeout(() => { + setTimeout(() => Module['setStatus'](''), 1); + doRun(); + }, 1); + } else + { + doRun(); + } + checkStackCookie(); +} + +function checkUnflushedContent() { + // Compiler settings do not allow exiting the runtime, so flushing + // the streams is not possible. but in ASSERTIONS mode we check + // if there was something to flush, and if so tell the user they + // should request that the runtime be exitable. + // Normally we would not even include flush() at all, but in ASSERTIONS + // builds we do so just for this check, and here we see if there is any + // content to flush, that is, we check if there would have been + // something a non-ASSERTIONS build would have not seen. + // How we flush the streams depends on whether we are in SYSCALLS_REQUIRE_FILESYSTEM=0 + // mode (which has its own special function for this; otherwise, all + // the code is inside libc) + var oldOut = out; + var oldErr = err; + var has = false; + out = err = (x) => { + has = true; + } + try { // it doesn't matter if it fails + _fflush(0); + // also flush in the JS FS layer + ['stdout', 'stderr'].forEach((name) => { + var info = FS.analyzePath('/dev/' + name); + if (!info) return; + var stream = info.object; + var rdev = stream.rdev; + var tty = TTY.ttys[rdev]; + if (tty?.output?.length) { + has = true; + } + }); + } catch(e) {} + out = oldOut; + err = oldErr; + if (has) { + warnOnce('stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the Emscripten FAQ), or make sure to emit a newline when you printf etc.'); + } +} + +if (Module['preInit']) { + if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']]; + while (Module['preInit'].length > 0) { + Module['preInit'].pop()(); + } +} + +run(); + +// end include: postamble.js + +// include: postamble_modularize.js +// In MODULARIZE mode we wrap the generated code in a factory function +// and return either the Module itself, or a promise of the module. +// +// We assign to the `moduleRtn` global here and configure closure to see +// this as and extern so it won't get minified. + +moduleRtn = readyPromise; + +// Assertion for attempting to access module properties on the incoming +// moduleArg. In the past we used this object as the prototype of the module +// and assigned properties to it, but now we return a distinct object. This +// keeps the instance private until it is ready (i.e the promise has been +// resolved). +for (const prop of Object.keys(Module)) { + if (!(prop in moduleArg)) { + Object.defineProperty(moduleArg, prop, { + configurable: true, + get() { + abort(`Access to module property ('${prop}') is no longer possible via the module constructor argument; Instead, use the result of the module constructor.`) + } + }); + } +} +// end include: postamble_modularize.js + + + + return moduleRtn; +} +); +})(); +export default _createMicroPythonModule; +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Options: +// - pystack: size in words of the MicroPython Python stack. +// - heapsize: size in bytes of the MicroPython GC heap. +// - url: location to load `micropython.mjs`. +// - stdin: function to return input characters. +// - stdout: function that takes one argument, and is passed lines of stdout +// output as they are produced. By default this is handled by Emscripten +// and in a browser goes to console, in node goes to process.stdout.write. +// - stderr: same behaviour as stdout but for error output. +// - linebuffer: whether to buffer line-by-line to stdout/stderr. +export async function loadMicroPython(options) { + const { pystack, heapsize, url, stdin, stdout, stderr, linebuffer } = + Object.assign( + { pystack: 2 * 1024, heapsize: 1024 * 1024, linebuffer: true }, + options, + ); + let Module = {}; + Module.locateFile = (path, scriptDirectory) => + url || scriptDirectory + path; + Module._textDecoder = new TextDecoder(); + if (stdin !== undefined) { + Module.stdin = stdin; + } + if (stdout !== undefined) { + if (linebuffer) { + Module._stdoutBuffer = []; + Module.stdout = (c) => { + if (c === 10) { + stdout( + Module._textDecoder.decode( + new Uint8Array(Module._stdoutBuffer), + ), + ); + Module._stdoutBuffer = []; + } else { + Module._stdoutBuffer.push(c); + } + }; + } else { + Module.stdout = (c) => stdout(new Uint8Array([c])); + } + } + if (stderr !== undefined) { + if (linebuffer) { + Module._stderrBuffer = []; + Module.stderr = (c) => { + if (c === 10) { + stderr( + Module._textDecoder.decode( + new Uint8Array(Module._stderrBuffer), + ), + ); + Module._stderrBuffer = []; + } else { + Module._stderrBuffer.push(c); + } + }; + } else { + Module.stderr = (c) => stderr(new Uint8Array([c])); + } + } + Module = await _createMicroPythonModule(Module); + Module.canvas = (function() { return document.getElementById('canvas'); })(); + + globalThis.Module = Module; + proxy_js_init(); + const pyimport = (name) => { + const value = Module._malloc(3 * 4); + Module.ccall( + "mp_js_do_import", + "null", + ["string", "pointer"], + [name, value], + ); + return proxy_convert_mp_to_js_obj_jsside_with_free(value); + }; + Module.ccall( + "mp_js_init", + "null", + ["number", "number"], + [pystack, heapsize], + ); + Module.ccall("proxy_c_init", "null", [], []); + return { + _module: Module, + PyProxy: PyProxy, + FS: Module.FS, + globals: { + __dict__: pyimport("__main__").__dict__, + get(key) { + return this.__dict__[key]; + }, + set(key, value) { + this.__dict__[key] = value; + }, + delete(key) { + delete this.__dict__[key]; + }, + }, + registerJsModule(name, module) { + const value = Module._malloc(3 * 4); + proxy_convert_js_to_mp_obj_jsside(module, value); + Module.ccall( + "mp_js_register_js_module", + "null", + ["string", "pointer"], + [name, value], + ); + Module._free(value); + }, + pyimport: pyimport, + runPython(code) { + const len = Module.lengthBytesUTF8(code); + const buf = Module._malloc(len + 1); + Module.stringToUTF8(code, buf, len + 1); + const value = Module._malloc(3 * 4); + Module.ccall( + "mp_js_do_exec", + "number", + ["pointer", "number", "pointer"], + [buf, len, value], + ); + Module._free(buf); + return proxy_convert_mp_to_js_obj_jsside_with_free(value); + }, + runPythonAsync(code) { + const len = Module.lengthBytesUTF8(code); + const buf = Module._malloc(len + 1); + Module.stringToUTF8(code, buf, len + 1); + const value = Module._malloc(3 * 4); + Module.ccall( + "mp_js_do_exec_async", + "number", + ["pointer", "number", "pointer"], + [buf, len, value], + { async: true }, + ); + Module._free(buf); + const ret = proxy_convert_mp_to_js_obj_jsside_with_free(value); + if (ret instanceof PyProxyThenable) { + return Promise.resolve(ret); + } + return ret; + }, + handlePending() { + return Module.ccall( + "mp_handle_pending", "null", ["boolean"], [true] + ); + }, + runFrozenAsync(module) { + const len = Module.lengthBytesUTF8(module); + const buf = Module._malloc(len + 1); + Module.stringToUTF8(module, buf, len + 1); + Module.ccall( + "mp_js_frozen_exec", + "number", + ["pointer"], + [buf], + { async: true }, + ); + Module._free(buf); + }, + replInit() { + Module.ccall("mp_js_repl_init", "null", ["null"], {async: true}); + }, + replProcessChar(chr) { + return Module.ccall( + "mp_js_repl_process_char", + "number", + ["number"], + [chr], + ); + }, + tulipTick(tick) { + return Module.ccall( + "tulip_tick", "null", ["number"], [tick], {async:true} + ); + }, + midiByte(byte) { + return Module.ccall( + "process_single_midi_byte", "null", ["number"], [byte], {async:true} + ); + }, + // Needed if the GC/asyncify is enabled. + async replProcessCharWithAsyncify(chr) { + return Module.ccall( + "mp_js_repl_process_char", + "number", + ["number"], + [chr], + { async: true }, + ); + }, + }; +} + +globalThis.loadMicroPython = loadMicroPython; + +async function runCLI() { + const fs = await import("fs"); + let heap_size = 128 * 1024; + let contents = ""; + let repl = true; + + for (let i = 2; i < process.argv.length; i++) { + if (process.argv[i] === "-X" && i < process.argv.length - 1) { + if (process.argv[i + 1].includes("heapsize=")) { + heap_size = parseInt(process.argv[i + 1].split("heapsize=")[1]); + const suffix = process.argv[i + 1].substr(-1).toLowerCase(); + if (suffix === "k") { + heap_size *= 1024; + } else if (suffix === "m") { + heap_size *= 1024 * 1024; + } + ++i; + } + } else { + contents += fs.readFileSync(process.argv[i], "utf8"); + repl = false; + } + } + + if (process.stdin.isTTY === false) { + contents = fs.readFileSync(0, "utf8"); + repl = false; + } + + const mp = await loadMicroPython({ + heapsize: heap_size, + stdout: (data) => process.stdout.write(data), + linebuffer: false, + }); + + if (repl) { + mp.replInit(); + process.stdin.setRawMode(true); + process.stdin.on("data", (data) => { + for (let i = 0; i < data.length; i++) { + mp.replProcessCharWithAsyncify(data[i]).then((result) => { + if (result) { + process.exit(); + } + }); + } + }); + } else { + // If the script to run ends with a running of the asyncio main loop, then inject + // a simple `asyncio.run` hook that starts the main task. This is primarily to + // support running the standard asyncio tests. + if (contents.endsWith("asyncio.run(main())\n")) { + const asyncio = mp.pyimport("asyncio"); + asyncio.run = async (task) => { + await asyncio.create_task(task); + }; + } + + try { + mp.runPython(contents); + } catch (error) { + if (error.name === "PythonError") { + if (error.type === "SystemExit") { + // SystemExit, this is a valid exception to successfully end a script. + } else { + // An unhandled Python exception, print in out. + console.error(error.message); + } + } else { + // A non-Python exception. Re-raise it. + throw error; + } + } + } +} + +// Check if Node is running (equivalent to ENVIRONMENT_IS_NODE). +if ( + typeof process === "object" && + typeof process.versions === "object" && + typeof process.versions.node === "string" +) { + // Check if this module is run from the command line via `node micropython.mjs`. + // + // See https://stackoverflow.com/questions/6398196/detect-if-called-through-require-or-directly-by-command-line/66309132#66309132 + // + // Note: + // - `resolve()` is used to handle symlinks + // - `includes()` is used to handle cases where the file extension was omitted when passed to node + + if (process.argv.length > 1) { + const path = await import("path"); + const url = await import("url"); + + const pathToThisFile = path.resolve(url.fileURLToPath(import.meta.url)); + const pathPassedToNode = path.resolve(process.argv[1]); + const isThisFileBeingRunViaCLI = + pathToThisFile.includes(pathPassedToNode); + + if (isThisFileBeingRunViaCLI) { + runCLI(); + } + } +} +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +class PyProxy { + constructor(ref) { + this._ref = ref; + } + + // Convert js_obj -- which is possibly a PyProxy -- to a JavaScript object. + static toJs(js_obj) { + if (!(js_obj instanceof PyProxy)) { + return js_obj; + } + + const type = Module.ccall( + "proxy_c_to_js_get_type", + "number", + ["number"], + [js_obj._ref], + ); + + if (type === 1 || type === 2) { + // List or tuple. + const array_ref = Module._malloc(2 * 4); + const item = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_get_array", + "null", + ["number", "pointer"], + [js_obj._ref, array_ref], + ); + const len = Module.getValue(array_ref, "i32"); + const items_ptr = Module.getValue(array_ref + 4, "i32"); + const js_array = []; + for (let i = 0; i < len; ++i) { + Module.ccall( + "proxy_convert_mp_to_js_obj_cside", + "null", + ["pointer", "pointer"], + [Module.getValue(items_ptr + i * 4, "i32"), item], + ); + const js_item = proxy_convert_mp_to_js_obj_jsside(item); + js_array.push(PyProxy.toJs(js_item)); + } + Module._free(array_ref); + Module._free(item); + return js_array; + } + + if (type === 3) { + // Dict. + const map_ref = Module._malloc(2 * 4); + const item = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_get_dict", + "null", + ["number", "pointer"], + [js_obj._ref, map_ref], + ); + const alloc = Module.getValue(map_ref, "i32"); + const table_ptr = Module.getValue(map_ref + 4, "i32"); + const js_dict = {}; + for (let i = 0; i < alloc; ++i) { + const mp_key = Module.getValue(table_ptr + i * 8, "i32"); + if (mp_key > 8) { + // Convert key to JS object. + Module.ccall( + "proxy_convert_mp_to_js_obj_cside", + "null", + ["pointer", "pointer"], + [mp_key, item], + ); + const js_key = proxy_convert_mp_to_js_obj_jsside(item); + + // Convert value to JS object. + const mp_value = Module.getValue( + table_ptr + i * 8 + 4, + "i32", + ); + Module.ccall( + "proxy_convert_mp_to_js_obj_cside", + "null", + ["pointer", "pointer"], + [mp_value, item], + ); + const js_value = proxy_convert_mp_to_js_obj_jsside(item); + + // Populate JS dict. + js_dict[js_key] = PyProxy.toJs(js_value); + } + } + Module._free(map_ref); + Module._free(item); + return js_dict; + } + + // Cannot convert to JS, leave as a PyProxy. + return js_obj; + } +} + +// This handler's goal is to allow minimal introspection +// of Python references from the JS world/utilities. +const py_proxy_handler = { + isExtensible() { + return true; + }, + ownKeys(target) { + const value = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_dir", + "null", + ["number", "pointer"], + [target._ref, value], + ); + const dir = proxy_convert_mp_to_js_obj_jsside_with_free(value); + return PyProxy.toJs(dir).filter((attr) => !attr.startsWith("__")); + }, + getOwnPropertyDescriptor(target, prop) { + return { + value: target[prop], + enumerable: true, + writable: true, + configurable: true, + }; + }, + has(target, prop) { + return Module.ccall( + "proxy_c_to_js_has_attr", + "number", + ["number", "string"], + [target._ref, prop], + ); + }, + get(target, prop) { + if (prop === "_ref") { + return target._ref; + } + if (prop === "then") { + return null; + } + + if (prop === Symbol.iterator) { + // Get the Python object iterator, and return a JavaScript generator. + const iter_ref = Module.ccall( + "proxy_c_to_js_get_iter", + "number", + ["number"], + [target._ref], + ); + return function* () { + const value = Module._malloc(3 * 4); + while (true) { + const valid = Module.ccall( + "proxy_c_to_js_iternext", + "number", + ["number", "pointer"], + [iter_ref, value], + ); + if (!valid) { + break; + } + yield proxy_convert_mp_to_js_obj_jsside(value); + } + Module._free(value); + }; + } + + const value = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_lookup_attr", + "null", + ["number", "string", "pointer"], + [target._ref, prop, value], + ); + return proxy_convert_mp_to_js_obj_jsside_with_free(value); + }, + set(target, prop, value) { + const value_conv = Module._malloc(3 * 4); + proxy_convert_js_to_mp_obj_jsside(value, value_conv); + const ret = Module.ccall( + "proxy_c_to_js_store_attr", + "number", + ["number", "string", "number"], + [target._ref, prop, value_conv], + ); + Module._free(value_conv); + return ret; + }, + deleteProperty(target, prop) { + return Module.ccall( + "proxy_c_to_js_delete_attr", + "number", + ["number", "string"], + [target._ref, prop], + ); + }, +}; + +// PyProxy of a Python generator, that implements the thenable interface. +class PyProxyThenable { + constructor(ref) { + this._ref = ref; + } + + then(resolve, reject) { + const values = Module._malloc(3 * 3 * 4); + proxy_convert_js_to_mp_obj_jsside(resolve, values + 3 * 4); + proxy_convert_js_to_mp_obj_jsside(reject, values + 2 * 3 * 4); + Module.ccall( + "proxy_c_to_js_resume", + "null", + ["number", "pointer"], + [this._ref, values], + ); + return proxy_convert_mp_to_js_obj_jsside_with_free(values); + } +} +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023-2024 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Number of static entries at the start of proxy_js_ref. +const PROXY_JS_REF_NUM_STATIC = 2; + +// These constants should match the constants in proxy_c.c. + +const PROXY_KIND_MP_EXCEPTION = -1; +const PROXY_KIND_MP_NULL = 0; +const PROXY_KIND_MP_NONE = 1; +const PROXY_KIND_MP_BOOL = 2; +const PROXY_KIND_MP_INT = 3; +const PROXY_KIND_MP_FLOAT = 4; +const PROXY_KIND_MP_STR = 5; +const PROXY_KIND_MP_CALLABLE = 6; +const PROXY_KIND_MP_GENERATOR = 7; +const PROXY_KIND_MP_OBJECT = 8; +const PROXY_KIND_MP_JSPROXY = 9; +const PROXY_KIND_MP_EXISTING = 10; + +const PROXY_KIND_JS_UNDEFINED = 0; +const PROXY_KIND_JS_NULL = 1; +const PROXY_KIND_JS_BOOLEAN = 2; +const PROXY_KIND_JS_INTEGER = 3; +const PROXY_KIND_JS_DOUBLE = 4; +const PROXY_KIND_JS_STRING = 5; +const PROXY_KIND_JS_OBJECT = 6; +const PROXY_KIND_JS_PYPROXY = 7; + +class PythonError extends Error { + constructor(exc_type, exc_details) { + super(exc_details); + this.name = "PythonError"; + this.type = exc_type; + } +} + +function proxy_js_init() { + globalThis.proxy_js_ref = [globalThis, undefined]; + globalThis.proxy_js_ref_next = PROXY_JS_REF_NUM_STATIC; + globalThis.proxy_js_map = new Map(); + globalThis.proxy_js_existing = [undefined]; + globalThis.pyProxyFinalizationRegistry = new FinalizationRegistry( + (cRef) => { + globalThis.proxy_js_map.delete(cRef); + Module.ccall("proxy_c_free_obj", "null", ["number"], [cRef]); + }, + ); +} + +// Check if the c_ref (Python proxy index) has a corresponding JavaScript-side PyProxy +// associated with it. If so, take a concrete reference to this PyProxy from the WeakRef +// and put it in proxy_js_existing, to be referenced and reused by PROXY_KIND_MP_EXISTING. +function proxy_js_check_existing(c_ref) { + const existing_obj = globalThis.proxy_js_map.get(c_ref)?.deref(); + if (existing_obj === undefined) { + return -1; + } + + // Search for a free slot in proxy_js_existing. + for (let i = 0; i < globalThis.proxy_js_existing.length; ++i) { + if (globalThis.proxy_js_existing[i] === undefined) { + // Free slot found, put existing_obj here and return the index. + globalThis.proxy_js_existing[i] = existing_obj; + return i; + } + } + + // No free slot, so append to proxy_js_existing and return the new index. + globalThis.proxy_js_existing.push(existing_obj); + return globalThis.proxy_js_existing.length - 1; +} + +// js_obj cannot be undefined +function proxy_js_add_obj(js_obj) { + // Search for the first free slot in proxy_js_ref. + while (proxy_js_ref_next < proxy_js_ref.length) { + if (proxy_js_ref[proxy_js_ref_next] === undefined) { + // Free slot found, reuse it. + const id = proxy_js_ref_next; + ++proxy_js_ref_next; + proxy_js_ref[id] = js_obj; + return id; + } + ++proxy_js_ref_next; + } + + // No free slots, so grow proxy_js_ref by one (append at the end of the array). + const id = proxy_js_ref.length; + proxy_js_ref[id] = js_obj; + proxy_js_ref_next = proxy_js_ref.length; + return id; +} + +function proxy_call_python(target, argumentsList) { + let args = 0; + + // Strip trailing "undefined" arguments. + while ( + argumentsList.length > 0 && + argumentsList[argumentsList.length - 1] === undefined + ) { + argumentsList.pop(); + } + + if (argumentsList.length > 0) { + // TODO use stackAlloc/stackRestore? + args = Module._malloc(argumentsList.length * 3 * 4); + for (const i in argumentsList) { + proxy_convert_js_to_mp_obj_jsside( + argumentsList[i], + args + i * 3 * 4, + ); + } + } + const value = Module._malloc(3 * 4); + Module.ccall( + "proxy_c_to_js_call", + "null", + ["number", "number", "number", "pointer"], + [target, argumentsList.length, args, value], + {async:true}, + ); + if (argumentsList.length > 0) { + Module._free(args); + } + const ret = proxy_convert_mp_to_js_obj_jsside_with_free(value); + if (ret instanceof PyProxyThenable) { + // In Python when an async function is called it creates the + // corresponding "generator", which must then be executed at + // the top level by an asyncio-like scheduler. In JavaScript + // the semantics for async functions is that they are started + // immediately (their non-async prefix code is executed immediately) + // and only if they await do they return a Promise to delay the + // execution of the remainder of the function. + // + // Emulate the JavaScript behaviour here by resolving the Python + // async function. We assume that the caller who gets this + // return is JavaScript. + return Promise.resolve(ret); + } + return ret; +} + +function proxy_convert_js_to_mp_obj_jsside(js_obj, out) { + let kind; + if (js_obj === undefined) { + kind = PROXY_KIND_JS_UNDEFINED; + } else if (js_obj === null) { + kind = PROXY_KIND_JS_NULL; + } else if (typeof js_obj === "boolean") { + kind = PROXY_KIND_JS_BOOLEAN; + Module.setValue(out + 4, js_obj, "i32"); + } else if (typeof js_obj === "number") { + if (Number.isInteger(js_obj)) { + kind = PROXY_KIND_JS_INTEGER; + Module.setValue(out + 4, js_obj, "i32"); + } else { + kind = PROXY_KIND_JS_DOUBLE; + // double must be stored to an address that's a multiple of 8 + const temp = (out + 4) & ~7; + Module.setValue(temp, js_obj, "double"); + const double_lo = Module.getValue(temp, "i32"); + const double_hi = Module.getValue(temp + 4, "i32"); + Module.setValue(out + 4, double_lo, "i32"); + Module.setValue(out + 8, double_hi, "i32"); + } + } else if (typeof js_obj === "string") { + kind = PROXY_KIND_JS_STRING; + const len = Module.lengthBytesUTF8(js_obj); + const buf = Module._malloc(len + 1); + Module.stringToUTF8(js_obj, buf, len + 1); + Module.setValue(out + 4, len, "i32"); + Module.setValue(out + 8, buf, "i32"); + } else if ( + js_obj instanceof PyProxy || + (typeof js_obj === "function" && "_ref" in js_obj) || + js_obj instanceof PyProxyThenable + ) { + kind = PROXY_KIND_JS_PYPROXY; + Module.setValue(out + 4, js_obj._ref, "i32"); + } else { + kind = PROXY_KIND_JS_OBJECT; + const id = proxy_js_add_obj(js_obj); + Module.setValue(out + 4, id, "i32"); + } + Module.setValue(out + 0, kind, "i32"); +} + +function proxy_convert_js_to_mp_obj_jsside_force_double_proxy(js_obj, out) { + if ( + js_obj instanceof PyProxy || + (typeof js_obj === "function" && "_ref" in js_obj) || + js_obj instanceof PyProxyThenable + ) { + const kind = PROXY_KIND_JS_OBJECT; + const id = proxy_js_add_obj(js_obj); + Module.setValue(out + 4, id, "i32"); + Module.setValue(out + 0, kind, "i32"); + } else { + proxy_convert_js_to_mp_obj_jsside(js_obj, out); + } +} + +function proxy_convert_mp_to_js_obj_jsside(value) { + const kind = Module.getValue(value, "i32"); + let obj; + if (kind === PROXY_KIND_MP_EXCEPTION) { + // Exception + const str_len = Module.getValue(value + 4, "i32"); + const str_ptr = Module.getValue(value + 8, "i32"); + const str = Module.UTF8ToString(str_ptr, str_len); + Module._free(str_ptr); + const str_split = str.split("\x04"); + throw new PythonError(str_split[0], str_split[1]); + } + if (kind === PROXY_KIND_MP_NULL) { + // MP_OBJ_NULL + throw new Error("NULL object"); + } + if (kind === PROXY_KIND_MP_NONE) { + // None + obj = null; + } else if (kind === PROXY_KIND_MP_BOOL) { + // bool + obj = Module.getValue(value + 4, "i32") ? true : false; + } else if (kind === PROXY_KIND_MP_INT) { + // int + obj = Module.getValue(value + 4, "i32"); + } else if (kind === PROXY_KIND_MP_FLOAT) { + // float + // double must be loaded from an address that's a multiple of 8 + const temp = (value + 4) & ~7; + const double_lo = Module.getValue(value + 4, "i32"); + const double_hi = Module.getValue(value + 8, "i32"); + Module.setValue(temp, double_lo, "i32"); + Module.setValue(temp + 4, double_hi, "i32"); + obj = Module.getValue(temp, "double"); + } else if (kind === PROXY_KIND_MP_STR) { + // str + const str_len = Module.getValue(value + 4, "i32"); + const str_ptr = Module.getValue(value + 8, "i32"); + obj = Module.UTF8ToString(str_ptr, str_len); + } else if (kind === PROXY_KIND_MP_JSPROXY) { + // js proxy + const id = Module.getValue(value + 4, "i32"); + obj = proxy_js_ref[id]; + } else if (kind === PROXY_KIND_MP_EXISTING) { + const id = Module.getValue(value + 4, "i32"); + obj = globalThis.proxy_js_existing[id]; + globalThis.proxy_js_existing[id] = undefined; + } else { + // obj + const id = Module.getValue(value + 4, "i32"); + if (kind === PROXY_KIND_MP_CALLABLE) { + obj = (...args) => { + return proxy_call_python(id, args); + }; + obj._ref = id; + } else if (kind === PROXY_KIND_MP_GENERATOR) { + obj = new PyProxyThenable(id); + } else { + // PROXY_KIND_MP_OBJECT + const target = new PyProxy(id); + obj = new Proxy(target, py_proxy_handler); + } + globalThis.pyProxyFinalizationRegistry.register(obj, id); + globalThis.proxy_js_map.set(id, new WeakRef(obj)); + } + return obj; +} + +function proxy_convert_mp_to_js_obj_jsside_with_free(value) { + const ret = proxy_convert_mp_to_js_obj_jsside(value); + Module._free(value); + return ret; +} + +function python_index_semantics(target, index_in) { + let index = index_in; + if (typeof index === "number") { + if (index < 0) { + index += target.length; + } + if (index < 0 || index >= target.length) { + throw new PythonError("IndexError", "index out of range"); + } + } + return index; +} diff --git a/www/run/micropython.wasm b/www/run/micropython.wasm new file mode 100755 index 00000000..a3035022 Binary files /dev/null and b/www/run/micropython.wasm differ diff --git a/www/run/spss.js b/www/run/spss.js new file mode 100644 index 00000000..3ed113b0 --- /dev/null +++ b/www/run/spss.js @@ -0,0 +1,149 @@ +var amy_play_message = null; +var amy_live_start = null; +var audio_started = false; +var tulip_started = false; +var mp = null; +var midiOutputDevice = null; +var midiInputDevice = null; + +// Once AMY module is loaded, register its functions and start AMY (not yet audio, you need to click for that) +amyModule().then(async function(am) { + amy_live_start = am.cwrap( + 'amy_live_start', null, null, {async: true} + ); + amy_start = am.cwrap( + 'amy_start', null, ['number', 'number', 'number'] + ); + amy_play_message = am.cwrap( + 'amy_play_message', null, ['string'] + ); + amy_reset_sysclock = am.cwrap( + 'amy_reset_sysclock', null, null + ); + amy_ticks = am.cwrap( + 'sequencer_ticks', 'number', [null] + ); + amy_start(1,1,1,1); +}); + +// Called from AMY to update Tulip about what tick it is, for the sequencer +function amy_sequencer_js_hook(tick) { + mp.tulipTick(tick); +} + +async function clear_storage() { + if(confirm("This will delete your Tulip user folder and start again.\nAre you sure?")) { + indexedDB.deleteDatabase('/tulip4/user'); + location.reload(true); + } +} + +async function restart_tulip() { + location.reload(true); +} + + +async function setup_midi_devices() { + var midi_in = document.tulip_settings.midi_input; + var midi_out = document.tulip_settings.midi_output; + if(WebMidi.inputs.length > midi_in.selectedIndex) { + if(midiInputDevice != null) midiInputDevice.destroy(); + midiInputDevice = WebMidi.getInputById(WebMidi.inputs[midi_in.selectedIndex].id); + midiInputDevice.addListener("midimessage", e => { + for(byte in e.message.data) { + mp.midiByte(e.message.data[byte]); + } + }); + } + if(WebMidi.outputs.length > midi_out.selectedIndex) { + if(midiOutputDevice != null) midiOutputDevice.destroy(); + midiOutputDevice = WebMidi.getOutputById(WebMidi.outputs[midi_out.selectedIndex].id); + } +} + +async function start_midi() { + function onEnabled() { + // Populate the dropdowns + var midi_in = document.tulip_settings.midi_input; + var midi_out = document.tulip_settings.midi_output; + + if(WebMidi.inputs.length>0) { + midi_in.options.length = 0; + WebMidi.inputs.forEach(input => { + midi_in.options[midi_in.options.length] = new Option(input.manufacturer + " " + input.name); + }); + } + + if(WebMidi.outputs.length>0) { + midi_out.options.length = 0; + WebMidi.outputs.forEach(output => { + midi_out.options[midi_out.options.length] = new Option(output.manufacturer + " " + output.name); + }); + } + // First run setup + setup_midi_devices(); + } + + if(WebMidi.supported) { + WebMidi + .enable({sysex:true}) + .then(onEnabled) + .catch(err => console.log("MIDI: " + err)); + } +} +async function get_test() { + await mp.runPythonAsync(` + import js + url = "https://api.github.com/users/micropython" + print(f"fetching {url}...") + res = await js.fetch(url) + json = await res.json() + for i in dir(json): + print(f"{i}: {json[i]}") + `); +} +async function sleep_ms(ms) { + await new Promise((r) => setTimeout(r, ms)); +} + +async function start_tulip() { + // Don't run this twice + if(tulip_started) return; + + // Start midi + await start_midi(); + + // Let micropython call an exported AMY function + await mp.registerJsModule('amy_js_message', amy_play_message); + + // time.sleep on this would block the browser from executing anything, so we override it to a JS thing + //mp.registerJsModule("time", { + // sleep: async (s) => await new Promise((r) => setTimeout(r, s * 1000)), + //}); + + // Set up the micropython context for AMY. + await mp.runPythonAsync(` + import amy, amy_js_message + amy.override_send = amy_js_message + `); + // If you don't have these sleeps we get a MemoryError with a locked heap. Not sure why yet. + await sleep_ms(200); + await mp.runFrozenAsync('_boot.py'); + await sleep_ms(200); + await mp.runFrozenAsync('/tulip4/user/boot.py'); + tulip_started = true; +} + +async function start_audio() { + document.body.removeEventListener('click', start_audio, true); + document.body.removeEventListener('keydown', start_audio, true); + // Don't run this twice + if(audio_started) return; + // Start the audio worklet (miniaudio) + await amy_live_start(); + // Wait 1s for audio to start + await sleep_ms(1000); + // Play the bleep + await mp.runPythonAsync(`midi.startup_bleep()`); + audio_started = true; +} \ No newline at end of file