this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #2184 from koltenpearson/pocketpy

Python language bindings

authored by

Vadim Grigoruk and committed by
GitHub
cb962910 ec42f8b3

+10954 -5
+3 -2
.github/workflows/build.yml
··· 287 287 - name: Install Host toolchain 288 288 run: | 289 289 apt-get update 290 - apt-get install --assume-yes build-essential ruby-full 290 + apt-get install --assume-yes build-essential ruby-full gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf 291 291 292 292 - name: Build 293 293 run: | ··· 328 328 - name: Install Host toolchain 329 329 run: | 330 330 apt-get update 331 - apt-get install --assume-yes build-essential ruby-full 331 + apt-get install --assume-yes build-essential ruby-full gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf 332 + 332 333 333 334 - name: Build 334 335 run: |
+24 -1
CMakeLists.txt
··· 49 49 endif() 50 50 51 51 if(APPLE) 52 - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version") 52 + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") 53 53 endif() 54 54 55 55 ··· 387 387 ${SQUIRREL_DIR}/sqstdlib/sqstdstream.cpp 388 388 ${SQUIRREL_DIR}/sqstdlib/sqstdstring.cpp 389 389 ${SQUIRREL_DIR}/sqstdlib/sqstdsystem.cpp 390 + 390 391 ) 391 392 392 393 add_library(squirrel STATIC ${SQUIRREL_SRC}) ··· 396 397 target_include_directories(squirrel PRIVATE ${SQUIRREL_DIR}/sqstdlib) 397 398 398 399 ################################ 400 + # PocketPy (Python) 401 + ################################ 402 + 403 + set(POCKETPY_DIR ${THIRDPARTY_DIR}/pocketpy) 404 + set(POCKETPY_SRC 405 + ${POCKETPY_DIR}/pocketpy_c.cpp 406 + ) 407 + 408 + add_library(pocketpy STATIC ${POCKETPY_SRC}) 409 + set_target_properties(pocketpy PROPERTIES LINKER_LANGUAGE CXX) 410 + target_include_directories(pocketpy PUBLIC ${POCKETPY_DIR}) 411 + if (${CMAKE_VERSION} VERSION_LESS "3.8.0") 412 + set_target_properties(pocketpy PROPERTIES COMPILE_FLAGS "--std=c++17") 413 + else() 414 + target_compile_features(pocketpy PRIVATE cxx_std_17) 415 + endif() 416 + 417 + ################################ 399 418 # GIFLIB 400 419 ################################ 401 420 ··· 484 503 ${TIC80CORE_DIR}/api/wren.c 485 504 ${TIC80CORE_DIR}/api/wasm.c 486 505 ${TIC80CORE_DIR}/api/squirrel.c 506 + ${TIC80CORE_DIR}/api/python.c 487 507 ${TIC80CORE_DIR}/api/scheme.c 488 508 ${TIC80CORE_DIR}/api/mruby.c 489 509 ${TIC80CORE_DIR}/api/janet.c ··· 518 538 wren 519 539 wasm 520 540 squirrel 541 + pocketpy 521 542 scheme 522 543 duktape 523 544 blipbuf ··· 555 576 MACRO_CORE(js TIC_BUILD_WITH_JS FALSE) 556 577 MACRO_CORE(wren TIC_BUILD_WITH_WREN FALSE) 557 578 MACRO_CORE(squirrel TIC_BUILD_WITH_SQUIRREL FALSE) 579 + MACRO_CORE(pocketpy TIC_BUILD_WITH_PYTHON FALSE) 558 580 MACRO_CORE(scheme TIC_BUILD_WITH_SCHEME FALSE) 559 581 MACRO_CORE(wasm TIC_BUILD_WITH_WASM FALSE) 560 582 ··· 1335 1357 MACRO_STUB(js) 1336 1358 MACRO_STUB(wren) 1337 1359 MACRO_STUB(squirrel) 1360 + MACRO_STUB(pocketpy) 1338 1361 MACRO_STUB(scheme) 1339 1362 1340 1363 if(BUILD_WITH_JANET)
+1
build/assets/pythondemo.tic.dat
··· 1 + 0x78, 0xda, 0xed, 0x52, 0xc1, 0x6a, 0xdb, 0x40, 0x10, 0x95, 0x9b, 0xf6, 0xa0, 0x3d, 0x04, 0xfa, 0x07, 0xd3, 0x84, 0x82, 0xdc, 0xa8, 0x89, 0x24, 0x9b, 0xd0, 0x1a, 0xd4, 0x4b, 0x5b, 0x48, 0xc0, 0x25, 0x50, 0x02, 0x3d, 0xcb, 0xf2, 0xda, 0x5a, 0xb2, 0xd1, 0x0a, 0x69, 0x93, 0x58, 0x7f, 0xa0, 0x43, 0x3f, 0xa2, 0xc7, 0x22, 0xf4, 0x11, 0x7b, 0x0e, 0x4b, 0xbe, 0xc4, 0xe8, 0x1b, 0x3a, 0xbb, 0x49, 0x8c, 0x0f, 0xa5, 0x3d, 0xe4, 0xd0, 0x4b, 0x47, 0x0c, 0x33, 0xef, 0xcd, 0xcc, 0xce, 0xc0, 0xd3, 0x4b, 0xc7, 0x71, 0x06, 0x3f, 0x9e, 0x39, 0x7f, 0xb3, 0x3b, 0x8d, 0xd6, 0x34, 0x4d, 0xd7, 0xb6, 0x6d, 0x67, 0x22, 0xc2, 0x4e, 0xab, 0x8d, 0x6b, 0xbd, 0xee, 0x9b, 0x46, 0xf7, 0x6d, 0xab, 0xfa, 0xe6, 0xa7, 0xea, 0x75, 0xa7, 0xb4, 0xea, 0x94, 0x7a, 0xf4, 0xdf, 0xcf, 0xeb, 0x3f, 0xce, 0xeb, 0xad, 0x79, 0xe7, 0xbf, 0xfd, 0x53, 0xb3, 0x5a, 0x19, 0xed, 0xec, 0x77, 0x6b, 0xf3, 0xef, 0xa8, 0xa3, 0x76, 0x94, 0x46, 0x6d, 0xef, 0x74, 0xe7, 0x68, 0xd4, 0x6e, 0xdd, 0xa1, 0x7e, 0xed, 0x83, 0x1b, 0x3d, 0x1d, 0xb5, 0xee, 0xb5, 0xee, 0xfb, 0xa7, 0xce, 0xbb, 0x1f, 0x9e, 0x76, 0xff, 0xce, 0xf3, 0xdd, 0x01, 0xfe, 0xe9, 0x2f, 0xf4, 0xc0, 0xd9, 0x07, 0xc9, 0x24, 0xa7, 0x13, 0x00, 0x58, 0x26, 0x97, 0xf4, 0x1e, 0x91, 0x7d, 0x48, 0xae, 0x64, 0x26, 0xca, 0xc9, 0x03, 0x3b, 0xa7, 0xd7, 0x94, 0x8b, 0x82, 0x96, 0x95, 0x0f, 0xf4, 0x32, 0x61, 0x1c, 0x83, 0x4c, 0x0f, 0xb1, 0x6f, 0x4e, 0xab, 0xd4, 0x0c, 0x43, 0x85, 0xed, 0xd2, 0xc2, 0x92, 0x15, 0x92, 0x89, 0x1c, 0x8b, 0x15, 0x93, 0xf6, 0x65, 0xb8, 0xa1, 0x33, 0x93, 0x03, 0x67, 0xf9, 0x05, 0xf2, 0x9c, 0xa5, 0x34, 0xaf, 0xb0, 0xf4, 0xe5, 0xf4, 0x1c, 0xa6, 0xf7, 0x00, 0xbc, 0x34, 0x4b, 0xf2, 0x25, 0x5e, 0x90, 0xb1, 0x0a, 0xa4, 0x80, 0x5a, 0x5c, 0x95, 0x8f, 0x9d, 0x20, 0x16, 0x90, 0x66, 0x02, 0xc1, 0x10, 0xc7, 0xaf, 0xf1, 0x0e, 0x5c, 0x30, 0x81, 0xe0, 0x30, 0x34, 0x5b, 0xec, 0x46, 0xdc, 0x53, 0xd4, 0x78, 0x73, 0x4e, 0x88, 0x8c, 0x03, 0xb2, 0x8a, 0xdf, 0x1f, 0x93, 0x3a, 0x8e, 0xc6, 0x84, 0xcc, 0xe9, 0x02, 0xce, 0x4f, 0x3f, 0x7a, 0x43, 0x98, 0x10, 0x77, 0xc9, 0xc5, 0x2c, 0xe1, 0x20, 0x37, 0xd9, 0x6a, 0x93, 0xd5, 0xc4, 0x25, 0x2e, 0x5b, 0xc0, 0x4c, 0xe6, 0x5e, 0x80, 0xcd, 0x50, 0xbf, 0x8d, 0xc3, 0x0d, 0x13, 0x5a, 0xe6, 0x60, 0x8b, 0x89, 0x0c, 0xb3, 0xda, 0xee, 0x19, 0x59, 0xc6, 0xf6, 0x10, 0x37, 0xe5, 0x95, 0x17, 0x8e, 0x86, 0xc4, 0xad, 0x8a, 0xd2, 0x23, 0xae, 0x1b, 0x1e, 0xc8, 0xd7, 0xc7, 0xc1, 0xd1, 0xd1, 0x28, 0x78, 0x13, 0xf9, 0x88, 0x57, 0x7e, 0x6d, 0x42, 0x2a, 0xb8, 0x28, 0x2f, 0x68, 0x1d, 0x87, 0x63, 0x03, 0xab, 0x34, 0xe1, 0x34, 0x1e, 0x99, 0xf4, 0x26, 0x8e, 0xfc, 0x2c, 0x8e, 0x88, 0x8b, 0x6f, 0x14, 0x25, 0xcb, 0xa5, 0xb7, 0x77, 0xf2, 0x79, 0x3a, 0x3d, 0x83, 0x6f, 0x67, 0x5f, 0xa7, 0x9f, 0x5e, 0xed, 0xf9, 0xf0, 0x6e, 0x6c, 0x1c, 0xcb, 0xd2, 0xec, 0x24, 0xbf, 0x00, 0xd7, 0x01, 0x38, 0x7c,
+1
build/assets/pythonmark.tic.dat
··· 1 + 0x05, 0x02, 0x00, 0x00, 0x0c, 0x30,
+1
build/baremetalpi/Makefile
··· 31 31 $(TIC80LIB)/libzip.a \ 32 32 $(TIC80LIB)/libblipbuf.a \ 33 33 $(TIC80LIB)/libsquirrel.a \ 34 + $(TIC80LIB)/libpocketpy.a \ 34 35 $(TIC80LIB)/libscheme.a \ 35 36 $(TIC80LIB)/libwren.a \ 36 37 $(TIC80LIB)/libwasm.a \
+2 -2
build/rpi/toolchain.cmake
··· 6 6 set(SYSROOT_PATH /opt/sysroot) 7 7 8 8 # Define the cross compiler locations 9 - set(CMAKE_C_COMPILER /opt/tools/arm-bcm2708/${CMAKE_LIBRARY_ARCHITECTURE}/bin/${CMAKE_LIBRARY_ARCHITECTURE}-gcc) 10 - set(CMAKE_CXX_COMPILER /opt/tools/arm-bcm2708/${CMAKE_LIBRARY_ARCHITECTURE}/bin/${CMAKE_LIBRARY_ARCHITECTURE}-g++) 9 + set(CMAKE_C_COMPILER /usr/bin/${CMAKE_LIBRARY_ARCHITECTURE}-gcc-8) 10 + set(CMAKE_CXX_COMPILER /usr/bin/${CMAKE_LIBRARY_ARCHITECTURE}-g++-8) 11 11 12 12 # Define the sysroot path for the RaspberryPi distribution in our tools folder 13 13 set(CMAKE_FIND_ROOT_PATH ${SYSROOT_PATH})
demos/bunny/pythonmark.py

This is a binary file and will not be displayed.

+63
demos/pythondemo.py
··· 1 + # title: game title 2 + # author: game developers, email, etc. 3 + # desc: short description 4 + # site: website link 5 + # license: MIT License (change this to your license of choice) 6 + # version: 0.1 7 + # script: python 8 + 9 + t=0 10 + x=96 11 + y=24 12 + 13 + def TIC() : 14 + global t 15 + global x 16 + global y 17 + 18 + if btn(0) : y-=1 19 + if btn(1) : y+=1 20 + if btn(2) : x-=1 21 + if btn(3) : x+=1 22 + 23 + cls(13) 24 + spr( 25 + 1+t%60//30*2, 26 + x,y, 27 + colorkey=14, 28 + scale=3, 29 + w=2,h=2 30 + ) 31 + print("HELLO WORLD!", 84, 84) 32 + t+=1 33 + 34 + 35 + # <TILES> 36 + # 001:eccccccccc888888caaaaaaaca888888cacccccccacc0ccccacc0ccccacc0ccc 37 + # 002:ccccceee8888cceeaaaa0cee888a0ceeccca0ccc0cca0c0c0cca0c0c0cca0c0c 38 + # 003:eccccccccc888888caaaaaaaca888888cacccccccacccccccacc0ccccacc0ccc 39 + # 004:ccccceee8888cceeaaaa0cee888a0ceeccca0cccccca0c0c0cca0c0c0cca0c0c 40 + # 017:cacccccccaaaaaaacaaacaaacaaaaccccaaaaaaac8888888cc000cccecccccec 41 + # 018:ccca00ccaaaa0ccecaaa0ceeaaaa0ceeaaaa0cee8888ccee000cceeecccceeee 42 + # 019:cacccccccaaaaaaacaaacaaacaaaaccccaaaaaaac8888888cc000cccecccccec 43 + # 020:ccca00ccaaaa0ccecaaa0ceeaaaa0ceeaaaa0cee8888ccee000cceeecccceeee 44 + # </TILES> 45 + 46 + # <WAVES> 47 + # 000:00000000ffffffff00000000ffffffff 48 + # 001:0123456789abcdeffedcba9876543210 49 + # 002:0123456789abcdef0123456789abcdef 50 + # </WAVES> 51 + 52 + # <SFX> 53 + # 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000 54 + # </SFX> 55 + 56 + # <TRACKS> 57 + # 000:100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 58 + # </TRACKS> 59 + 60 + # <PALETTE> 61 + # 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57 62 + # </PALETTE> 63 +
+2
include/tic80_config.h
··· 29 29 !defined(TIC_BUILD_WITH_WREN) && \ 30 30 !defined(TIC_BUILD_WITH_SCHEME) && \ 31 31 !defined(TIC_BUILD_WITH_SQUIRREL) && \ 32 + !defined(TIC_BUILD_WITH_PYTHON) && \ 32 33 !defined(TIC_BUILD_WITH_WASM) 33 34 34 35 # define TIC_BUILD_WITH_LUA 1 ··· 38 39 # define TIC_BUILD_WITH_WREN 1 39 40 # define TIC_BUILD_WITH_SCHEME 1 40 41 # define TIC_BUILD_WITH_SQUIRREL 1 42 + # define TIC_BUILD_WITH_PYTHON 1 41 43 # define TIC_BUILD_WITH_WASM 1 42 44 43 45 #endif
+1646
src/api/python.c
··· 1 + 2 + #include "core/core.h" 3 + 4 + #if defined(TIC_BUILD_WITH_PYTHON) 5 + 6 + #include "pocketpy_c.h" 7 + #include <stdio.h> 8 + #include <string.h> 9 + 10 + static bool get_core(pkpy_vm* vm, tic_core** core) 11 + { 12 + pkpy_get_global(vm, "_tic_core"); 13 + return pkpy_to_voidp(vm, -1, (void**) core); 14 + } 15 + 16 + static bool setup_core(pkpy_vm* vm, tic_core* core) 17 + { 18 + if (!pkpy_push_voidp(vm, core)) return false; 19 + if (!pkpy_set_global(vm, "_tic_core")) return false; 20 + return true; 21 + } 22 + 23 + //index should be a postive index 24 + static int prepare_colorindex(pkpy_vm* vm, int index, u8 * buffer) 25 + { 26 + if (pkpy_is_int(vm, index)) 27 + { 28 + int value; 29 + pkpy_to_int(vm, index, &value); 30 + 31 + if (value == -1) 32 + return 0; 33 + else 34 + { 35 + buffer[0] = value; 36 + return 1; 37 + } 38 + } 39 + else 40 + { //should be a list then 41 + pkpy_get_global(vm, "len"); 42 + pkpy_push(vm, index); //get the list 43 + pkpy_call(vm, 1); 44 + 45 + int list_len; 46 + pkpy_to_int(vm, -1, &list_len); 47 + pkpy_pop(vm, 1); 48 + 49 + list_len = (list_len < TIC_PALETTE_SIZE)?(list_len):(TIC_PALETTE_SIZE); 50 + 51 + for(int i = 0; i < list_len; i++) 52 + { 53 + int list_val; 54 + pkpy_push(vm, index); 55 + pkpy_push_int(vm, i); 56 + pkpy_call_method(vm, "__getitem__", 1); 57 + pkpy_to_int(vm, -1, &list_val); 58 + buffer[i] = list_val; 59 + pkpy_pop(vm, 1); 60 + } 61 + 62 + return list_len; 63 + } 64 + } 65 + 66 + 67 + static int py_trace(pkpy_vm* vm) 68 + { 69 + tic_mem* tic; 70 + char* message = NULL; 71 + int color; 72 + 73 + pkpy_to_string(vm, 0, &message); 74 + pkpy_to_int(vm, 1, &color); 75 + get_core(vm, (tic_core**) &tic); 76 + if (pkpy_check_error(vm)) 77 + { 78 + if (message != NULL) free(message); 79 + return 0; 80 + } 81 + 82 + tic_api_trace(tic, message, (u8) color); 83 + free(message); 84 + return 0; 85 + } 86 + 87 + static int py_cls(pkpy_vm* vm) 88 + { 89 + tic_mem* tic; 90 + int color; 91 + 92 + pkpy_to_int(vm, 0, &color); 93 + get_core(vm, (tic_core**) &tic); 94 + if (pkpy_check_error(vm)) 95 + return 0; 96 + 97 + tic_api_cls(tic, (u8) color); 98 + return 0; 99 + } 100 + 101 + static int py_btn(pkpy_vm* vm) 102 + { 103 + tic_mem* tic; 104 + int button_id; 105 + 106 + get_core(vm, (tic_core**) &tic); 107 + pkpy_to_int(vm, 0, &button_id); 108 + if(pkpy_check_error(vm)) 109 + return 0; 110 + 111 + bool pressed = tic_api_btn(tic, button_id & 0x1f); 112 + pkpy_push_bool(vm, pressed); 113 + return 1; 114 + } 115 + 116 + static int py_btnp(pkpy_vm* vm) 117 + { 118 + tic_mem* tic; 119 + int button_id; 120 + int hold; 121 + int period; 122 + 123 + pkpy_to_int(vm, 0, &button_id); 124 + pkpy_to_int(vm, 1, &hold); 125 + pkpy_to_int(vm, 2, &period); 126 + get_core(vm, (tic_core**) &tic); 127 + if(pkpy_check_error(vm)) 128 + return 0; 129 + 130 + bool pressed = tic_api_btnp(tic, button_id, hold, period); 131 + pkpy_push_bool(vm, pressed); 132 + return 1; 133 + } 134 + 135 + static int py_circ(pkpy_vm* vm) 136 + { 137 + tic_mem* tic; 138 + int x; 139 + int y; 140 + int radius; 141 + int color; 142 + 143 + pkpy_to_int(vm, 0, &x); 144 + pkpy_to_int(vm, 1, &y); 145 + pkpy_to_int(vm, 2, &radius); 146 + pkpy_to_int(vm, 3, &color); 147 + get_core(vm, (tic_core**) &tic); 148 + if(pkpy_check_error(vm)) 149 + return 0; 150 + 151 + tic_api_circ(tic, x, y, radius, color); 152 + return 0; 153 + } 154 + 155 + static int py_circb(pkpy_vm* vm) 156 + { 157 + tic_mem* tic; 158 + int x; 159 + int y; 160 + int radius; 161 + int color; 162 + 163 + pkpy_to_int(vm, 0, &x); 164 + pkpy_to_int(vm, 1, &y); 165 + pkpy_to_int(vm, 2, &radius); 166 + pkpy_to_int(vm, 3, &color); 167 + get_core(vm, (tic_core**) &tic); 168 + if(pkpy_check_error(vm)) 169 + return 0; 170 + 171 + tic_api_circb(tic, x, y, radius, color); 172 + return 0; 173 + } 174 + 175 + static int py_elli(pkpy_vm* vm) 176 + { 177 + tic_mem* tic; 178 + int x; 179 + int y; 180 + int a; 181 + int b; 182 + int color; 183 + 184 + pkpy_to_int(vm, 0, &x); 185 + pkpy_to_int(vm, 1, &y); 186 + pkpy_to_int(vm, 2, &a); 187 + pkpy_to_int(vm, 3, &b); 188 + pkpy_to_int(vm, 4, &color); 189 + get_core(vm, (tic_core**) &tic); 190 + if(pkpy_check_error(vm)) 191 + return 0; 192 + 193 + tic_api_elli(tic, x, y, a, b, color); 194 + return 0; 195 + } 196 + 197 + static int py_ellib(pkpy_vm* vm) 198 + { 199 + tic_mem* tic; 200 + int x; 201 + int y; 202 + int a; 203 + int b; 204 + int color; 205 + 206 + pkpy_to_int(vm, 0, &x); 207 + pkpy_to_int(vm, 1, &y); 208 + pkpy_to_int(vm, 2, &a); 209 + pkpy_to_int(vm, 3, &b); 210 + pkpy_to_int(vm, 4, &color); 211 + get_core(vm, (tic_core**) &tic); 212 + if(pkpy_check_error(vm)) 213 + return 0; 214 + 215 + tic_api_ellib(tic, x, y, a, b, color); 216 + return 0; 217 + } 218 + 219 + static int py_clip(pkpy_vm* vm) 220 + { 221 + tic_mem* tic; 222 + int x; 223 + int y; 224 + int w; 225 + int h; 226 + 227 + pkpy_to_int(vm, 0, &x); 228 + pkpy_to_int(vm, 1, &y); 229 + pkpy_to_int(vm, 2, &w); 230 + pkpy_to_int(vm, 3, &h); 231 + get_core(vm, (tic_core**) &tic); 232 + if(pkpy_check_error(vm)) 233 + return 0; 234 + 235 + tic_api_clip(tic, x, y, w, h); 236 + return 0; 237 + } 238 + 239 + static int py_exit(pkpy_vm* vm) 240 + { 241 + tic_mem* tic; 242 + 243 + get_core(vm, (tic_core**) &tic); 244 + if(pkpy_check_error(vm)) 245 + return 0; 246 + 247 + tic_api_exit(tic); 248 + return 0; 249 + } 250 + 251 + static int py_fget(pkpy_vm* vm) 252 + { 253 + tic_mem* tic; 254 + int sprite_id; 255 + unsigned flag; 256 + 257 + pkpy_to_int(vm, 0, &sprite_id); 258 + pkpy_to_int(vm, 1, &flag); 259 + get_core(vm, (tic_core**) &tic); 260 + if(pkpy_check_error(vm)) 261 + return 0; 262 + 263 + bool set = tic_api_fget(tic, sprite_id, flag); 264 + pkpy_push_bool(vm, set); 265 + return 1; 266 + } 267 + 268 + static int py_fset(pkpy_vm* vm) 269 + { 270 + tic_mem* tic; 271 + int sprite_id; 272 + unsigned flag; 273 + bool set_to; 274 + 275 + pkpy_to_int(vm, 0, &sprite_id); 276 + pkpy_to_int(vm, 1, &flag); 277 + pkpy_to_bool(vm, 2, &set_to); 278 + get_core(vm, (tic_core**) &tic); 279 + if(pkpy_check_error(vm)) 280 + return 0; 281 + 282 + tic_api_fset(tic, sprite_id, flag, set_to); 283 + return 0; 284 + } 285 + 286 + static int py_font(pkpy_vm* vm) 287 + { 288 + tic_mem* tic; 289 + char* text = NULL; 290 + int x; 291 + int y; 292 + int width; 293 + int height; 294 + int chromakey_raw; 295 + bool fixed; 296 + int scale; 297 + bool alt; 298 + 299 + pkpy_to_string(vm, 0, &text); 300 + pkpy_to_int(vm, 1, &x); 301 + pkpy_to_int(vm, 2, &y); 302 + pkpy_to_int(vm, 3, &width); 303 + pkpy_to_int(vm, 4, &height); 304 + pkpy_to_int(vm, 5, &chromakey_raw); 305 + pkpy_to_bool(vm, 6, &fixed); 306 + pkpy_to_int(vm, 7, &scale); 307 + pkpy_to_bool(vm, 8, &alt); 308 + get_core(vm, (tic_core**) &tic); 309 + if(pkpy_check_error(vm)) { 310 + if (text != NULL) free(text); 311 + return 0; 312 + } 313 + 314 + if (scale == 0) 315 + { 316 + pkpy_push_int(vm, 0); 317 + } 318 + else 319 + { 320 + u8 chromakey = (u8) chromakey_raw; 321 + s32 size = tic_api_font(tic, text, x, y, &chromakey, 1, width, height, fixed, scale, alt); 322 + pkpy_push_int(vm, size); 323 + } 324 + 325 + free(text); 326 + return 1; 327 + } 328 + 329 + static int py_key(pkpy_vm* vm) 330 + { 331 + tic_mem* tic; 332 + int key_id; 333 + 334 + pkpy_to_int(vm, 0, &key_id); 335 + get_core(vm, (tic_core**) &tic); 336 + if(pkpy_check_error(vm)) 337 + return 0; 338 + 339 + if (key_id >= tic_keys_count) { 340 + pkpy_error(vm, "unknown keyboard code\n"); 341 + return 0; 342 + } 343 + 344 + bool pressed = tic_api_key(tic, key_id); 345 + pkpy_push_bool(vm, pressed); 346 + return 1; 347 + } 348 + 349 + static int py_keyp(pkpy_vm* vm) 350 + { 351 + tic_mem* tic; 352 + int key_id; 353 + int hold; 354 + int period; 355 + 356 + pkpy_to_int(vm, 0, &key_id); 357 + pkpy_to_int(vm, 1, &hold); 358 + pkpy_to_int(vm, 2, &period); 359 + get_core(vm, (tic_core**) &tic); 360 + if(pkpy_check_error(vm)) 361 + return 0; 362 + 363 + if (key_id >= tic_keys_count) { 364 + pkpy_error(vm, "unknown keyboard code\n"); 365 + return 0; 366 + } 367 + 368 + bool pressed = tic_api_keyp(tic, key_id, hold, period); 369 + pkpy_push_bool(vm, pressed); 370 + return 1; 371 + } 372 + 373 + static int py_line(pkpy_vm* vm) 374 + { 375 + tic_mem* tic; 376 + double x0; 377 + double y0; 378 + double x1; 379 + double y1; 380 + int color; 381 + 382 + pkpy_to_float(vm, 0, &x0); 383 + pkpy_to_float(vm, 1, &y0); 384 + pkpy_to_float(vm, 2, &x1); 385 + pkpy_to_float(vm, 3, &y1); 386 + pkpy_to_int(vm, 4, &color); 387 + get_core(vm, (tic_core**) &tic); 388 + if(pkpy_check_error(vm)) 389 + return 0; 390 + 391 + tic_api_line(tic, x0, y0, x1, y1, color); 392 + return 0; 393 + } 394 + 395 + static void remap_callback(void* data, s32 x, s32 y, RemapResult* result) { 396 + pkpy_vm* vm = data; 397 + 398 + pkpy_push(vm, -1); //get copy of remap callable 399 + pkpy_push_int(vm, x); 400 + pkpy_push_int(vm, y); 401 + pkpy_call(vm, 2); 402 + 403 + 404 + int index, flip, rotate; 405 + pkpy_to_int(vm, -3, &index); 406 + pkpy_to_int(vm, -2, &flip); 407 + pkpy_to_int(vm, -1, &rotate); 408 + pkpy_pop(vm, 3); //reset stack for next remap_callback call 409 + 410 + result->index = (u8) index; 411 + result->flip = flip; 412 + result->rotate = rotate; 413 + } 414 + 415 + static int py_map(pkpy_vm* vm) 416 + { 417 + tic_mem* tic; 418 + int x; 419 + int y; 420 + int w; 421 + int h; 422 + int sx; 423 + int sy; 424 + int color_count; 425 + int scale; 426 + bool used_remap; 427 + 428 + static u8 colors[TIC_PALETTE_SIZE]; 429 + 430 + pkpy_to_int(vm, 0, &x); 431 + pkpy_to_int(vm, 1, &y); 432 + pkpy_to_int(vm, 2, &w); 433 + pkpy_to_int(vm, 3, &h); 434 + pkpy_to_int(vm, 4, &sx); 435 + pkpy_to_int(vm, 5, &sy); 436 + color_count = prepare_colorindex(vm, 6, colors); 437 + pkpy_to_int(vm, 7, &scale); 438 + used_remap = !pkpy_is_none(vm, 8); 439 + get_core(vm, (tic_core**) &tic); 440 + if(pkpy_check_error(vm)) 441 + return 0; 442 + 443 + //last element on the stack should be the function, so no need to adjust anything 444 + if (used_remap) 445 + tic_api_map(tic, x, y, w, h, sx, sy, colors, color_count, scale, remap_callback, vm); 446 + else 447 + tic_api_map(tic, x, y, w, h, sx, sy, colors, color_count, scale, NULL, NULL); 448 + 449 + return 0; 450 + } 451 + 452 + static int py_memcpy(pkpy_vm* vm) { 453 + 454 + tic_mem* tic; 455 + int dest; 456 + int src; 457 + int size; 458 + 459 + pkpy_to_int(vm, 0, &dest); 460 + pkpy_to_int(vm, 1, &src); 461 + pkpy_to_int(vm, 2, &size); 462 + get_core(vm, (tic_core**) &tic); 463 + if(pkpy_check_error(vm)) 464 + return 0; 465 + 466 + tic_api_memcpy(tic, dest, src, size); 467 + 468 + return 0; 469 + } 470 + 471 + static int py_memset(pkpy_vm* vm) { 472 + 473 + tic_mem* tic; 474 + int dest; 475 + int value; 476 + int size; 477 + 478 + pkpy_to_int(vm, 0, &dest); 479 + pkpy_to_int(vm, 1, &value); 480 + pkpy_to_int(vm, 2, &size); 481 + get_core(vm, (tic_core**) &tic); 482 + if(pkpy_check_error(vm)) 483 + return 0; 484 + 485 + tic_api_memset(tic, dest, value, size); 486 + 487 + return 0; 488 + } 489 + 490 + static int py_mget(pkpy_vm* vm) { 491 + 492 + tic_mem* tic; 493 + int x; 494 + int y; 495 + 496 + pkpy_to_int(vm, 0, &x); 497 + pkpy_to_int(vm, 1, &y); 498 + get_core(vm, (tic_core**) &tic); 499 + if(pkpy_check_error(vm)) 500 + return 0; 501 + 502 + int value = tic_api_mget(tic, x, y); 503 + pkpy_push_int(vm, value); 504 + 505 + return 1; 506 + } 507 + 508 + static int py_mset(pkpy_vm* vm) { 509 + 510 + tic_mem* tic; 511 + int x; 512 + int y; 513 + int tile_id; 514 + 515 + pkpy_to_int(vm, 0, &x); 516 + pkpy_to_int(vm, 1, &y); 517 + pkpy_to_int(vm, 2, &tile_id); 518 + get_core(vm, (tic_core**) &tic); 519 + if(pkpy_check_error(vm)) 520 + return 0; 521 + 522 + tic_api_mset(tic, x, y, tile_id); 523 + 524 + return 0; 525 + } 526 + 527 + 528 + static int py_mouse(pkpy_vm* vm) { 529 + 530 + tic_core* core; 531 + get_core(vm, &core); 532 + if(pkpy_check_error(vm)) 533 + return 0; 534 + 535 + tic_point pos = tic_api_mouse((tic_mem*)core); 536 + 537 + const tic80_mouse* mouse = &core->memory.ram->input.mouse; 538 + 539 + pkpy_push_int(vm, pos.x); 540 + pkpy_push_int(vm, pos.y); 541 + pkpy_push_bool(vm, mouse->left); 542 + pkpy_push_bool(vm, mouse->middle); 543 + pkpy_push_bool(vm, mouse->right); 544 + pkpy_push_int(vm, mouse->scrollx); 545 + pkpy_push_int(vm, mouse->scrolly); 546 + 547 + return 7; 548 + } 549 + 550 + static int py_music(pkpy_vm* vm) { 551 + 552 + tic_mem* tic; 553 + int track; 554 + int frame; 555 + int row; 556 + bool loop; 557 + bool sustain; 558 + int tempo; 559 + int speed; 560 + 561 + pkpy_to_int(vm, 0, &track); 562 + pkpy_to_int(vm, 1, &frame); 563 + pkpy_to_int(vm, 2, &row); 564 + pkpy_to_bool(vm, 3, &loop); 565 + pkpy_to_bool(vm, 4, &sustain); 566 + pkpy_to_int(vm, 5, &tempo); 567 + pkpy_to_int(vm, 6, &speed); 568 + get_core(vm, (tic_core**) &tic); 569 + if(pkpy_check_error(vm)) 570 + return 0; 571 + 572 + if (track > MUSIC_TRACKS - 1 ) 573 + pkpy_error(vm, "invalid music track index\n"); 574 + 575 + //stop the music first I guess 576 + tic_api_music(tic, -1, 0, 0, false, false, -1, -1); 577 + if (track >= 0) 578 + tic_api_music(tic, track, frame, row, loop, sustain, tempo, speed); 579 + 580 + return 0; 581 + } 582 + 583 + static int py_peek(pkpy_vm* vm) { 584 + 585 + tic_mem* tic; 586 + int address; 587 + int bits; 588 + 589 + pkpy_to_int(vm, 0, &address); 590 + pkpy_to_int(vm, 1, &bits); 591 + get_core(vm, (tic_core**) &tic); 592 + if(pkpy_check_error(vm)) 593 + return 0; 594 + 595 + int value = tic_api_peek(tic, address, bits); 596 + pkpy_push_int(vm, value); 597 + 598 + return 1; 599 + } 600 + 601 + static int py_peek1(pkpy_vm* vm) { 602 + 603 + tic_mem* tic; 604 + int address; 605 + 606 + pkpy_to_int(vm, 0, &address); 607 + get_core(vm, (tic_core**) &tic); 608 + if(pkpy_check_error(vm)) 609 + return 0; 610 + 611 + int value = tic_api_peek1(tic, address); 612 + pkpy_push_int(vm, value); 613 + 614 + return 1; 615 + } 616 + 617 + static int py_peek2(pkpy_vm* vm) { 618 + 619 + tic_mem* tic; 620 + int address; 621 + 622 + pkpy_to_int(vm, 0, &address); 623 + get_core(vm, (tic_core**) &tic); 624 + if(pkpy_check_error(vm)) 625 + return 0; 626 + 627 + int value = tic_api_peek2(tic, address); 628 + pkpy_push_int(vm, value); 629 + 630 + return 1; 631 + } 632 + 633 + static int py_peek4(pkpy_vm* vm) { 634 + 635 + tic_mem* tic; 636 + int address; 637 + 638 + pkpy_to_int(vm, 0, &address); 639 + get_core(vm, (tic_core**) &tic); 640 + if(pkpy_check_error(vm)) 641 + return 0; 642 + 643 + int value = tic_api_peek4(tic, address); 644 + pkpy_push_int(vm, value); 645 + 646 + return 1; 647 + } 648 + 649 + static int py_pix(pkpy_vm* vm) { 650 + tic_mem* tic; 651 + int x; 652 + int y; 653 + int color = -1; 654 + 655 + 656 + pkpy_to_int(vm, 0, &x); 657 + pkpy_to_int(vm, 1, &y); 658 + if (pkpy_is_int(vm, 2)) 659 + pkpy_to_int(vm, 2, &color); 660 + get_core(vm, (tic_core**) &tic); 661 + if(pkpy_check_error(vm)) 662 + return 0; 663 + 664 + if(color >= 0) { //set the pixel 665 + tic_api_pix(tic, x, y, color, false); 666 + return 0; 667 + } else { //get the pixel 668 + int value = tic_api_pix(tic, x, y, 0, true); 669 + pkpy_push_int(vm, value); 670 + return 1; 671 + } 672 + } 673 + 674 + static int py_pmem(pkpy_vm* vm) { 675 + tic_mem* tic; 676 + int index; 677 + bool provided_value = false; 678 + int value; 679 + 680 + pkpy_to_int(vm, 0, &index); 681 + if (!pkpy_is_none(vm, 1)) { 682 + provided_value = true; 683 + pkpy_to_int(vm, 1, &value); 684 + } 685 + get_core(vm, (tic_core**) &tic); 686 + if(pkpy_check_error(vm)) 687 + return 0; 688 + 689 + if (index >= TIC_PERSISTENT_SIZE) { 690 + pkpy_error(vm, "invalid persistent tic index\n"); 691 + return 0; 692 + } 693 + 694 + int stored = tic_api_pmem(tic, index, 0, false); 695 + pkpy_push_int(vm, stored); 696 + 697 + if(provided_value) //set the value 698 + tic_api_pmem(tic, index, value, true); 699 + 700 + return 1; 701 + } 702 + 703 + static int py_poke(pkpy_vm* vm) { 704 + 705 + tic_mem* tic; 706 + int address; 707 + int value; 708 + int bits; 709 + 710 + pkpy_to_int(vm, 0, &address); 711 + pkpy_to_int(vm, 1, &value); 712 + pkpy_to_int(vm, 2, &bits); 713 + get_core(vm, (tic_core**) &tic); 714 + if(pkpy_check_error(vm)) 715 + return 0; 716 + 717 + tic_api_poke(tic, address, value, bits); 718 + 719 + return 0; 720 + } 721 + 722 + static int py_poke1(pkpy_vm* vm) { 723 + 724 + tic_mem* tic; 725 + int address; 726 + int value; 727 + 728 + pkpy_to_int(vm, 0, &address); 729 + pkpy_to_int(vm, 1, &value); 730 + get_core(vm, (tic_core**) &tic); 731 + if(pkpy_check_error(vm)) 732 + return 0; 733 + 734 + tic_api_poke1(tic, address, value); 735 + 736 + return 0; 737 + } 738 + 739 + static int py_poke2(pkpy_vm* vm) { 740 + 741 + tic_mem* tic; 742 + int address; 743 + int value; 744 + 745 + pkpy_to_int(vm, 0, &address); 746 + pkpy_to_int(vm, 1, &value); 747 + get_core(vm, (tic_core**) &tic); 748 + if(pkpy_check_error(vm)) 749 + return 0; 750 + 751 + tic_api_poke2(tic, address, value); 752 + 753 + return 0; 754 + } 755 + 756 + static int py_poke4(pkpy_vm* vm) { 757 + 758 + tic_mem* tic; 759 + int address; 760 + int value; 761 + 762 + pkpy_to_int(vm, 0, &address); 763 + pkpy_to_int(vm, 1, &value); 764 + get_core(vm, (tic_core**) &tic); 765 + if(pkpy_check_error(vm)) 766 + return 0; 767 + 768 + tic_api_poke4(tic, address, value); 769 + 770 + return 0; 771 + } 772 + 773 + static int py_print(pkpy_vm* vm) { 774 + 775 + tic_mem* tic; 776 + char* text = NULL; 777 + int x; 778 + int y; 779 + int color; 780 + bool fixed; 781 + int scale; 782 + bool small; 783 + bool alt; 784 + 785 + pkpy_to_string(vm, 0, &text); 786 + pkpy_to_int(vm, 1, &x); 787 + pkpy_to_int(vm, 2, &y); 788 + pkpy_to_int(vm, 3, &color); 789 + pkpy_to_bool(vm, 4, &fixed); 790 + pkpy_to_int(vm, 5, &scale); 791 + pkpy_to_bool(vm, 6, &small); 792 + pkpy_to_bool(vm, 7, &alt); 793 + get_core(vm, (tic_core**) &tic); 794 + if(pkpy_check_error(vm)) { 795 + if (text != NULL) free(text); 796 + return 0; 797 + } 798 + 799 + s32 size = tic_api_print(tic, text, x, y, color, fixed, scale, alt); 800 + 801 + pkpy_push_int(vm, size); 802 + 803 + free(text); 804 + return 1; 805 + } 806 + 807 + static int py_rect(pkpy_vm* vm) 808 + { 809 + tic_mem* tic; 810 + int x; 811 + int y; 812 + int w; 813 + int h; 814 + int color; 815 + 816 + pkpy_to_int(vm, 0, &x); 817 + pkpy_to_int(vm, 1, &y); 818 + pkpy_to_int(vm, 2, &w); 819 + pkpy_to_int(vm, 3, &h); 820 + pkpy_to_int(vm, 4, &color); 821 + get_core(vm, (tic_core**) &tic); 822 + if(pkpy_check_error(vm)) 823 + return 0; 824 + 825 + tic_api_rect(tic, x, y, w, h, color); 826 + return 0; 827 + } 828 + 829 + static int py_rectb(pkpy_vm* vm) 830 + { 831 + tic_mem* tic; 832 + int x; 833 + int y; 834 + int w; 835 + int h; 836 + int color; 837 + 838 + pkpy_to_int(vm, 0, &x); 839 + pkpy_to_int(vm, 1, &y); 840 + pkpy_to_int(vm, 2, &w); 841 + pkpy_to_int(vm, 3, &h); 842 + pkpy_to_int(vm, 4, &color); 843 + get_core(vm, (tic_core**) &tic); 844 + if(pkpy_check_error(vm)) 845 + return 0; 846 + 847 + tic_api_rectb(tic, x, y, w, h, color); 848 + return 0; 849 + } 850 + 851 + static int py_sfx(pkpy_vm* vm) 852 + { 853 + tic_mem* tic; 854 + int sfx_id; 855 + 856 + bool parse_note = false; 857 + char* string_note = NULL; 858 + int int_note; 859 + 860 + int duration; 861 + int channel; 862 + int volume; 863 + int speed; 864 + 865 + pkpy_to_int(vm, 0, &sfx_id); 866 + 867 + if (pkpy_is_string(vm, 1)) { 868 + parse_note = true; 869 + pkpy_to_string(vm, 1, &string_note); 870 + } else { 871 + pkpy_to_int(vm, 1, &int_note); 872 + } 873 + 874 + pkpy_to_int(vm, 2, &duration); 875 + pkpy_to_int(vm, 3, &channel); 876 + pkpy_to_int(vm, 4, &volume); 877 + pkpy_to_int(vm, 5, &speed); 878 + get_core(vm, (tic_core**) &tic); 879 + if(pkpy_check_error(vm)) 880 + goto cleanup; 881 + int note, octave; 882 + 883 + if (parse_note) { 884 + if(!tic_tool_parse_note(string_note, &note, &octave)) { 885 + pkpy_error(vm, "invalid note, should like C#4\n"); 886 + goto cleanup; //error in future; 887 + } 888 + 889 + } else { 890 + note = int_note % NOTES; 891 + octave = int_note/ NOTES; 892 + } 893 + 894 + if (channel < 0 || channel >= TIC_SOUND_CHANNELS) { 895 + pkpy_error(vm, "unknown channel\n"); 896 + goto cleanup; 897 + } 898 + 899 + if (sfx_id >= SFX_COUNT) { 900 + pkpy_error(vm, "unknown sfx index\n"); 901 + goto cleanup; 902 + } 903 + 904 + 905 + //for now we won't support two channel volumes 906 + tic_api_sfx(tic, sfx_id, note, octave, duration, channel, volume & 0xf, volume & 0xf, speed); 907 + 908 + cleanup : 909 + if (string_note != NULL) free(string_note); 910 + return 0; 911 + } 912 + 913 + static int py_spr(pkpy_vm* vm) 914 + { 915 + tic_mem* tic; 916 + int spr_id; 917 + int x; 918 + int y; 919 + int color_count; 920 + int scale; 921 + int flip; 922 + int rotate; 923 + int w; 924 + int h; 925 + 926 + static u8 colors[TIC_PALETTE_SIZE]; 927 + 928 + pkpy_to_int(vm, 0, &spr_id); 929 + pkpy_to_int(vm, 1, &x); 930 + pkpy_to_int(vm, 2, &y); 931 + color_count = prepare_colorindex(vm, 3, colors); 932 + pkpy_to_int(vm, 4, &scale); 933 + pkpy_to_int(vm, 5, &flip); 934 + pkpy_to_int(vm, 6, &rotate); 935 + pkpy_to_int(vm, 7, &w); 936 + pkpy_to_int(vm, 8, &h); 937 + get_core(vm, (tic_core**) &tic); 938 + if(pkpy_check_error(vm)) 939 + return 0; 940 + 941 + tic_api_spr(tic, spr_id, x, y, w, h, colors, color_count, scale, flip, rotate); 942 + 943 + return 0; 944 + } 945 + 946 + static int py_reset(pkpy_vm* vm) { 947 + tic_core* core; 948 + get_core(vm, &core); 949 + if(pkpy_check_error(vm)) 950 + return 0; 951 + 952 + core->state.initialized = false; 953 + 954 + return 0; 955 + } 956 + 957 + static int py_sync(pkpy_vm* vm) 958 + { 959 + tic_mem* tic; 960 + int mask; 961 + int bank; 962 + bool tocart; 963 + 964 + pkpy_to_int(vm, 0, &mask); 965 + pkpy_to_int(vm, 1, &bank); 966 + pkpy_to_bool(vm, 2, &tocart); 967 + get_core(vm, (tic_core**) &tic); 968 + if(pkpy_check_error(vm)) 969 + return 0; 970 + 971 + if (bank < 0 || bank >= TIC_BANKS) { 972 + pkpy_error(vm, "sync() error, invalid bank\n"); 973 + return 0; 974 + } 975 + 976 + 977 + tic_api_sync(tic, mask, bank, tocart); 978 + return 0; 979 + } 980 + 981 + static int py_time(pkpy_vm* vm) 982 + { 983 + tic_mem* tic; 984 + get_core(vm, (tic_core**) &tic); 985 + if(pkpy_check_error(vm)) 986 + return 0; 987 + 988 + int time = tic_api_time(tic); 989 + pkpy_push_int(vm, time); 990 + return 1; 991 + } 992 + 993 + static int py_tstamp(pkpy_vm* vm) 994 + { 995 + tic_mem* tic; 996 + get_core(vm, (tic_core**) &tic); 997 + if(pkpy_check_error(vm)) 998 + return 0; 999 + 1000 + int tstamp = tic_api_tstamp(tic); 1001 + pkpy_push_int(vm, tstamp); 1002 + return 1; 1003 + } 1004 + 1005 + static int py_tri(pkpy_vm* vm) 1006 + { 1007 + tic_mem* tic; 1008 + double x1; 1009 + double y1; 1010 + double x2; 1011 + double y2; 1012 + double x3; 1013 + double y3; 1014 + int color; 1015 + 1016 + pkpy_to_float(vm, 0, &x1); 1017 + pkpy_to_float(vm, 1, &y1); 1018 + pkpy_to_float(vm, 2, &x2); 1019 + pkpy_to_float(vm, 3, &y2); 1020 + pkpy_to_float(vm, 4, &x3); 1021 + pkpy_to_float(vm, 5, &y3); 1022 + pkpy_to_int(vm, 6, &color); 1023 + get_core(vm, (tic_core**) &tic); 1024 + if(pkpy_check_error(vm)) 1025 + return 0; 1026 + 1027 + tic_api_tri(tic, x1, y1, x2, y2, x3, y3, color); 1028 + return 0; 1029 + } 1030 + 1031 + static int py_trib(pkpy_vm* vm) 1032 + { 1033 + tic_mem* tic; 1034 + double x1; 1035 + double y1; 1036 + double x2; 1037 + double y2; 1038 + double x3; 1039 + double y3; 1040 + int color; 1041 + 1042 + pkpy_to_float(vm, 0, &x1); 1043 + pkpy_to_float(vm, 1, &y1); 1044 + pkpy_to_float(vm, 2, &x2); 1045 + pkpy_to_float(vm, 3, &y2); 1046 + pkpy_to_float(vm, 4, &x3); 1047 + pkpy_to_float(vm, 5, &y3); 1048 + pkpy_to_int(vm, 6, &color); 1049 + get_core(vm, (tic_core**) &tic); 1050 + if(pkpy_check_error(vm)) 1051 + return 0; 1052 + 1053 + tic_api_trib(tic, x1, y1, x2, y2, x3, y3, color); 1054 + return 0; 1055 + } 1056 + 1057 + static int py_ttri(pkpy_vm* vm) 1058 + { 1059 + tic_mem* tic; 1060 + double x1; 1061 + double y1; 1062 + double x2; 1063 + double y2; 1064 + double x3; 1065 + double y3; 1066 + double u1; 1067 + double v1; 1068 + double u2; 1069 + double v2; 1070 + double u3; 1071 + double v3; 1072 + int texsrc; 1073 + int color_count; 1074 + double z1; 1075 + double z2; 1076 + double z3; 1077 + 1078 + static u8 colors[TIC_PALETTE_SIZE]; 1079 + 1080 + pkpy_to_float(vm, 0, &x1); 1081 + pkpy_to_float(vm, 1, &y1); 1082 + pkpy_to_float(vm, 2, &x2); 1083 + pkpy_to_float(vm, 3, &y2); 1084 + pkpy_to_float(vm, 4, &x3); 1085 + pkpy_to_float(vm, 5, &y3); 1086 + 1087 + pkpy_to_float(vm, 6, &u1); 1088 + pkpy_to_float(vm, 7, &v1); 1089 + pkpy_to_float(vm, 8, &u2); 1090 + pkpy_to_float(vm, 9, &v2); 1091 + pkpy_to_float(vm, 10, &u3); 1092 + pkpy_to_float(vm, 11, &v3); 1093 + 1094 + pkpy_to_int(vm, 12, &texsrc); 1095 + color_count = prepare_colorindex(vm, 13, colors); 1096 + 1097 + pkpy_to_float(vm, 14, &z1); 1098 + pkpy_to_float(vm, 15, &z2); 1099 + pkpy_to_float(vm, 16, &z3); 1100 + 1101 + get_core(vm, (tic_core**) &tic); 1102 + if(pkpy_check_error(vm)) 1103 + return 0; 1104 + 1105 + tic_api_ttri( 1106 + tic, 1107 + x1,y1,x2,y2,x3,y3, 1108 + u1,v1,u2,v2,u3,v3, 1109 + texsrc, 1110 + colors,color_count, 1111 + z1,z2,z3, 1112 + z1 != 0 || z2 != 0 || z3 != 0 1113 + ); 1114 + 1115 + return 0; 1116 + } 1117 + 1118 + static int py_vbank(pkpy_vm* vm) { 1119 + tic_core* core; 1120 + 1121 + int bank_id = -1; 1122 + 1123 + if (!pkpy_is_none(vm, 0)) 1124 + pkpy_to_int(vm, 0, &bank_id); 1125 + get_core(vm, &core); 1126 + if(pkpy_check_error(vm)) 1127 + return 0; 1128 + 1129 + tic_mem* tic = (tic_mem*) core; 1130 + 1131 + s32 prev = core->state.vbank.id; 1132 + 1133 + if (bank_id >= 0) 1134 + tic_api_vbank(tic, bank_id); 1135 + 1136 + pkpy_push_int(vm, prev); 1137 + return 1; 1138 + } 1139 + 1140 + static bool setup_c_bindings(pkpy_vm* vm) { 1141 + 1142 + pkpy_push_function(vm, py_trace); 1143 + pkpy_set_global(vm, "_trace"); 1144 + 1145 + pkpy_push_function(vm, py_cls); 1146 + pkpy_set_global(vm, "_cls"); 1147 + 1148 + pkpy_push_function(vm, py_btn); 1149 + pkpy_set_global(vm, "_btn"); 1150 + 1151 + pkpy_push_function(vm, py_btnp); 1152 + pkpy_set_global(vm, "_btnp"); 1153 + 1154 + pkpy_push_function(vm, py_circ); 1155 + pkpy_set_global(vm, "_circ"); 1156 + 1157 + pkpy_push_function(vm, py_circb); 1158 + pkpy_set_global(vm, "_circb"); 1159 + 1160 + pkpy_push_function(vm, py_clip); 1161 + pkpy_set_global(vm, "_clip"); 1162 + 1163 + pkpy_push_function(vm, py_elli); 1164 + pkpy_set_global(vm, "_elli"); 1165 + 1166 + pkpy_push_function(vm, py_ellib); 1167 + pkpy_set_global(vm, "_ellib"); 1168 + 1169 + pkpy_push_function(vm, py_exit); 1170 + pkpy_set_global(vm, "_exit"); 1171 + 1172 + pkpy_push_function(vm, py_fget); 1173 + pkpy_set_global(vm, "_fget"); 1174 + 1175 + pkpy_push_function(vm, py_fget); 1176 + pkpy_set_global(vm, "_fset"); 1177 + 1178 + pkpy_push_function(vm, py_font); 1179 + pkpy_set_global(vm, "_font"); 1180 + 1181 + pkpy_push_function(vm, py_key); 1182 + pkpy_set_global(vm, "_key"); 1183 + 1184 + pkpy_push_function(vm, py_keyp); 1185 + pkpy_set_global(vm, "_keyp"); 1186 + 1187 + pkpy_push_function(vm, py_line); 1188 + pkpy_set_global(vm, "_line"); 1189 + 1190 + pkpy_push_function(vm, py_map); 1191 + pkpy_set_global(vm, "_map"); 1192 + 1193 + pkpy_push_function(vm, py_memcpy); 1194 + pkpy_set_global(vm, "_memcpy"); 1195 + 1196 + pkpy_push_function(vm, py_memset); 1197 + pkpy_set_global(vm, "_memset"); 1198 + 1199 + pkpy_push_function(vm, py_mget); 1200 + pkpy_set_global(vm, "_mget"); 1201 + 1202 + pkpy_push_function(vm, py_mouse); 1203 + pkpy_set_global(vm, "_mouse"); 1204 + 1205 + pkpy_push_function(vm, py_mset); 1206 + pkpy_set_global(vm, "_mset"); 1207 + 1208 + pkpy_push_function(vm, py_music); 1209 + pkpy_set_global(vm, "_music"); 1210 + 1211 + pkpy_push_function(vm, py_peek); 1212 + pkpy_set_global(vm, "_peek"); 1213 + 1214 + pkpy_push_function(vm, py_peek1); 1215 + pkpy_set_global(vm, "_peek1"); 1216 + 1217 + pkpy_push_function(vm, py_peek1); 1218 + pkpy_set_global(vm, "_peek2"); 1219 + 1220 + pkpy_push_function(vm, py_peek1); 1221 + pkpy_set_global(vm, "_peek4"); 1222 + 1223 + pkpy_push_function(vm, py_pix); 1224 + pkpy_set_global(vm, "_pix"); 1225 + 1226 + pkpy_push_function(vm, py_pmem); 1227 + pkpy_set_global(vm, "_pmem"); 1228 + 1229 + pkpy_push_function(vm, py_poke); 1230 + pkpy_set_global(vm, "_poke"); 1231 + 1232 + pkpy_push_function(vm, py_poke1); 1233 + pkpy_set_global(vm, "_poke1"); 1234 + 1235 + pkpy_push_function(vm, py_poke1); 1236 + pkpy_set_global(vm, "_poke2"); 1237 + 1238 + pkpy_push_function(vm, py_poke1); 1239 + pkpy_set_global(vm, "_poke4"); 1240 + 1241 + pkpy_push_function(vm, py_print); 1242 + pkpy_set_global(vm, "_print"); 1243 + 1244 + pkpy_push_function(vm, py_rect); 1245 + pkpy_set_global(vm, "_rect"); 1246 + 1247 + pkpy_push_function(vm, py_rectb); 1248 + pkpy_set_global(vm, "_rectb"); 1249 + 1250 + pkpy_push_function(vm, py_reset); 1251 + pkpy_set_global(vm, "_reset"); 1252 + 1253 + pkpy_push_function(vm, py_sfx); 1254 + pkpy_set_global(vm, "_sfx"); 1255 + 1256 + pkpy_push_function(vm, py_spr); 1257 + pkpy_set_global(vm, "_spr"); 1258 + 1259 + pkpy_push_function(vm, py_sync); 1260 + pkpy_set_global(vm, "_sync"); 1261 + 1262 + pkpy_push_function(vm, py_time); 1263 + pkpy_set_global(vm, "_time"); 1264 + 1265 + pkpy_push_function(vm, py_tri); 1266 + pkpy_set_global(vm, "_tri"); 1267 + 1268 + pkpy_push_function(vm, py_trib); 1269 + pkpy_set_global(vm, "_trib"); 1270 + 1271 + pkpy_push_function(vm, py_tstamp); 1272 + pkpy_set_global(vm, "_tstamp"); 1273 + 1274 + pkpy_push_function(vm, py_ttri); 1275 + pkpy_set_global(vm, "_ttri"); 1276 + 1277 + pkpy_push_function(vm, py_vbank); 1278 + pkpy_set_global(vm, "_vbank"); 1279 + 1280 + if(pkpy_check_error(vm)) 1281 + return false; 1282 + 1283 + return true; 1284 + } 1285 + 1286 + static bool setup_py_bindings(pkpy_vm* vm) { 1287 + pkpy_vm_run(vm, "def trace(message, color=15) : return _trace(str(message), int(color))"); 1288 + 1289 + pkpy_vm_run(vm, "def cls(color=0) : return _cls(int(color))"); 1290 + 1291 + //lua api does this for btn 1292 + pkpy_vm_run(vm, "def btn(id) : return _btn(id)"); 1293 + pkpy_vm_run(vm, "def btnp(id, hold=-1, period=-1) : return _btnp(int(id), int(hold), int(period))"); 1294 + 1295 + //even if there are no keyword args, this also gives us argument count checks 1296 + pkpy_vm_run(vm, "def circ(x, y, radius, color) : return _circ(int(x), int(y), int(radius), int(color))"); 1297 + pkpy_vm_run(vm, "def circb(x, y, radius, color) : return _circb(int(x), int(y), int(radius), int(color))\n"); 1298 + 1299 + pkpy_vm_run(vm, "def elli(x, y, a, b, color) : return _elli(int(x), int(y), int(radius), int(color))"); 1300 + pkpy_vm_run(vm, "def ellib(x, y, a, b, color) : return _ellib(int(x), int(y), int(radius), int(color))"); 1301 + 1302 + pkpy_vm_run(vm, "def clip(x, y, width, height) : return _clip(int(x), int(y), int(width), int(height))"); 1303 + pkpy_vm_run(vm, "def exit() : return _exit()\n"); 1304 + 1305 + pkpy_vm_run(vm, "def fget(sprite_id, flag) : return _fget(int(sprite_id), int(flag))"); 1306 + pkpy_vm_run(vm, "def fset(sprite_id, flag, b) : return _fset(int(sprite_id), int(flag), bool(b))"); 1307 + 1308 + pkpy_vm_run(vm, 1309 + "def font(text, x, y, chromakey, char_width=8, char_height=8, fixed=False, scale=1, alt=False) : " 1310 + "return _font(str(text), int(x), int(y), chromakey, int(char_width), int(char_height), bool(fixed), int(scale), bool(alt))" 1311 + ); 1312 + 1313 + pkpy_vm_run(vm, "def key(code=-1) : return _key(code)"); 1314 + pkpy_vm_run(vm, "def keyp(code=-1, hold=-1, period=-17) : return _keyp(int(code), int(hold), int(period))"); 1315 + 1316 + pkpy_vm_run(vm, "def line(x0, y0, x1, y1, color) : _line(int(x0), int(y0), int(x1), int(y1), int(color))"); 1317 + pkpy_vm_run(vm, 1318 + "def map(x=0, y=0, w=30, h=17, sx=0, sy=0, colorkey=-1, scale=1, remap=None) : " 1319 + " return _map(int(x),int(y),int(w),int(h),int(sx),int(sy),colorkey,int(scale),remap)" 1320 + ); 1321 + 1322 + pkpy_vm_run(vm, "def memcpy(dest, source, size) : return _memcpy(int(dest), int(source), int(size))"); 1323 + pkpy_vm_run(vm, "def memset(dest, value, size) : return _memset(int(dest), int(value), int(size))"); 1324 + 1325 + pkpy_vm_run(vm, "def mget(x, y) : return _mget(int(x), int(y))"); 1326 + pkpy_vm_run(vm, "def mset(x, y, tile_id) : return _mset(int(x), int(y), int(tile_id))"); 1327 + 1328 + pkpy_vm_run(vm, "def mouse() : return _mouse()"); 1329 + 1330 + pkpy_vm_run(vm, 1331 + "def music(track=-1, frame=-1, row=-1, loop=True, sustain=False, tempo=-1, speed=-1) :" 1332 + "return _music(int(track), int(frame), int(row), bool(loop), bool(sustain), int(tempo), int(speed))" 1333 + ); 1334 + 1335 + pkpy_vm_run(vm, "def peek(addr, bits=8) : return _peek(int(addr), int(bits)) "); 1336 + pkpy_vm_run(vm, "def peek1(addr) : return _peek1(int(addr)) "); 1337 + pkpy_vm_run(vm, "def peek2(addr) : return _peek2(int(addr)) "); 1338 + pkpy_vm_run(vm, "def peek4(addr) : return _peek4(int(addr)) "); 1339 + 1340 + pkpy_vm_run(vm, "def pix(x, y, color=None) : return _pix(int(x), int(y), color)"); 1341 + 1342 + pkpy_vm_run(vm, "def pmem(index, value=None) : return _pmem(int(index), value)"); 1343 + 1344 + pkpy_vm_run(vm, "def poke(addr, value, bits=8) : return _poke(int(addr), int(value), int(bits)) "); 1345 + pkpy_vm_run(vm, "def poke1(addr, value) : return _poke1(int(addr), int(value)) "); 1346 + pkpy_vm_run(vm, "def poke2(addr, value) : return _poke2(int(addr), int(value)) "); 1347 + pkpy_vm_run(vm, "def poke4(addr, value) : return _poke4(int(addr), int(value)) "); 1348 + 1349 + pkpy_vm_run(vm, 1350 + "def print(text, x=0, y=0, color=15, fixed=False, scale=1, smallfont=False, alt=False) :" 1351 + " return _print(str(text), int(x), int(y), int(color), bool(fixed), int(scale), bool(smallfont), bool(alt))" 1352 + ); 1353 + 1354 + pkpy_vm_run(vm, "def rect(x, y, w, h, color) : return _rect(int(x),int(y),int(w),int(h),int(color))"); 1355 + pkpy_vm_run(vm, "def rectb(x, y, w, h, color) : return _rectb(int(x),int(y),int(w),int(h),int(color))"); 1356 + 1357 + pkpy_vm_run(vm, "def reset() : return _reset()"); 1358 + 1359 + pkpy_vm_run(vm, 1360 + "def sfx(id, note=-1, duration=-1, channel=0, volume=15, speed=0) : " 1361 + "return _sfx(id, int(note), int(duration), int(channel), int(volume), int(speed))" 1362 + ); 1363 + 1364 + pkpy_vm_run(vm, 1365 + "def spr(id, x, y, colorkey=-1, scale=1, flip=0, rotate=0, w=1, h=1) : " 1366 + "return _spr(int(id), int(x), int(y), colorkey, int(scale), int(flip), int(rotate), int(w), int(h))" 1367 + ); 1368 + 1369 + pkpy_vm_run(vm, "def sync(mask=0, bank=0, tocart=False) : return _sync(int(mask), int(bank), bool(tocart))"); 1370 + 1371 + pkpy_vm_run(vm, "def time() : return _time()"); 1372 + pkpy_vm_run(vm, "def tstamp() : return _tstamp()"); 1373 + 1374 + pkpy_vm_run(vm, 1375 + "def tri(x1, y1, x2, y2, x3, y3, color) : " 1376 + "return _tri(float(x1), float(y1), float(x2), float(y2), float(x3), float(y3), int(color))" 1377 + ); 1378 + pkpy_vm_run(vm, 1379 + "def trib(x1, y1, x2, y2, x3, y3, color) : " 1380 + "return _trib(float(x1), float(y1), float(x2), float(y2), float(x3), float(y3), int(color))" 1381 + ); 1382 + 1383 + pkpy_vm_run(vm, 1384 + "def ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, texsrc=0, chromakey=-1, z1=0, z2=0, z3=0) : " 1385 + "return _ttri(float(x1),float(y1),float(x2),float(y2),float(x3),float(y3),float(u1),float(v1),float(u2),float(v2),float(u3),float(v3),int(texsrc),chromakey,float(z1),float(z2),float(z3))" 1386 + ); 1387 + 1388 + pkpy_vm_run(vm, "def vbank(bank=None) : return _vbank(bank)"); 1389 + 1390 + if(pkpy_check_error(vm)) 1391 + return false; 1392 + 1393 + return true; 1394 + } 1395 + 1396 + void closePython(tic_mem* tic) 1397 + { 1398 + tic_core* core = (tic_core*)tic; 1399 + 1400 + if (core->currentVM) 1401 + { 1402 + pkpy_vm_destroy(core->currentVM); 1403 + core->currentVM = NULL; 1404 + } 1405 + } 1406 + 1407 + static void report_error(tic_core* core, char* prefix) { 1408 + pkpy_vm* vm = core->currentVM; 1409 + core->data->error(core->data->data, prefix); 1410 + char* message; 1411 + if (!pkpy_clear_error(vm, &message)) 1412 + core->data->error(core->data->data, "error was thrown but not register (pocketpy c binding bug)"); 1413 + else 1414 + core->data->error(core->data->data, message); 1415 + } 1416 + 1417 + static bool initPython(tic_mem* tic, const char* code) 1418 + { 1419 + closePython(tic); 1420 + tic_core* core = (tic_core*)tic; 1421 + 1422 + pkpy_vm* vm = pkpy_vm_create(false, false); 1423 + 1424 + core->currentVM = vm; 1425 + 1426 + if (!setup_core(vm, core)) { 1427 + report_error(core, "problem binding tic_core (pocketpy c binding bug)\n"); 1428 + return false; 1429 + } 1430 + if (!setup_c_bindings(vm)) 1431 + { 1432 + report_error(core, "problem setting up the c bindings (pocketpy c binding bug\n"); 1433 + return false; 1434 + } 1435 + if (!setup_py_bindings(vm)) 1436 + { 1437 + report_error(core, "problem setting up the py bindings (pocketpy c binding bug\n"); 1438 + return false; 1439 + } 1440 + 1441 + if(!pkpy_vm_run(vm, code)) 1442 + { 1443 + report_error(core, "error while processing the main code\n"); 1444 + 1445 + return false; 1446 + } 1447 + 1448 + return true; 1449 + } 1450 + 1451 + void callPythonTick(tic_mem* tic) 1452 + { 1453 + tic_core* core = (tic_core*)tic; 1454 + if (!core->currentVM) 1455 + return; 1456 + 1457 + if (pkpy_check_global(core->currentVM, TIC_FN)) 1458 + { 1459 + pkpy_get_global(core->currentVM, TIC_FN); 1460 + if(!pkpy_call(core->currentVM, 0)) 1461 + report_error(core, "error while running TIC\n"); 1462 + } 1463 + } 1464 + void callPythonBoot(tic_mem* tic) { 1465 + tic_core* core = (tic_core*)tic; 1466 + if (!core->currentVM) 1467 + return; 1468 + 1469 + if (pkpy_check_global(core->currentVM, BOOT_FN)) 1470 + { 1471 + pkpy_get_global(core->currentVM, BOOT_FN); 1472 + if(!pkpy_call(core->currentVM, 0)) 1473 + report_error(core, "error while running BOOT\n"); 1474 + } 1475 + } 1476 + 1477 + void callPythonScanline(tic_mem* tic, s32 row, void* data) { 1478 + tic_core* core = (tic_core*)tic; 1479 + if (!core->currentVM) 1480 + return; 1481 + 1482 + if (pkpy_check_global(core->currentVM, SCN_FN)) 1483 + { 1484 + pkpy_get_global(core->currentVM, SCN_FN); 1485 + pkpy_push_int(core->currentVM, row); 1486 + if(!pkpy_call(core->currentVM, 1)) 1487 + report_error(core, "error while running SCN\n"); 1488 + } 1489 + } 1490 + 1491 + void callPythonBorder(tic_mem* tic, s32 row, void* data) { 1492 + tic_core* core = (tic_core*)tic; 1493 + if (!core->currentVM) 1494 + return; 1495 + 1496 + if (pkpy_check_global(core->currentVM, BDR_FN)) 1497 + { 1498 + pkpy_get_global(core->currentVM, BDR_FN); 1499 + pkpy_push_int(core->currentVM, row); 1500 + if(!pkpy_call(core->currentVM, 1)) 1501 + report_error(core, "error while running BDR\n"); 1502 + } 1503 + } 1504 + 1505 + void callPythonMenu(tic_mem* tic, s32 index, void* data) { 1506 + tic_core* core = (tic_core*)tic; 1507 + if (!core->currentVM) 1508 + return; 1509 + 1510 + if (pkpy_check_global(core->currentVM, MENU_FN)) 1511 + { 1512 + pkpy_get_global(core->currentVM, MENU_FN); 1513 + pkpy_push_int(core->currentVM, index); 1514 + if(!pkpy_call(core->currentVM, 1)) 1515 + report_error(core, "error while running MENU\n"); 1516 + } 1517 + } 1518 + 1519 + static bool is_alnum_(char c) { 1520 + return ( 1521 + (c >= 'a' && c <= 'z') 1522 + || (c >= 'A' && c <= 'Z') 1523 + || (c >= '0' && c <= '9') 1524 + || (c == '_') 1525 + ); 1526 + } 1527 + 1528 + static const tic_outline_item* getPythonOutline(const char* code, s32* size) 1529 + { 1530 + 1531 + *size = 0; 1532 + static tic_outline_item* items = NULL; 1533 + if (items) 1534 + { 1535 + free(items); 1536 + items = NULL; 1537 + } 1538 + 1539 + const char* name_start; 1540 + 1541 + start: 1542 + if (*code == 0) goto end; 1543 + else if (strncmp(code, "def", 3) == 0) { code += 3; goto next_word_ws; } 1544 + else if (*code == '#') { code++; goto comment; } 1545 + else if (strncmp(code, "\"\"\"", 3) == 0) { code += 3; goto multiline_string; } 1546 + else if (*code == '"') { code++; goto string; } 1547 + else { code++; goto start; } 1548 + 1549 + next_word_ws : 1550 + if (*code == 0) goto end; 1551 + else if (*code=='\t' || *code==' ' || *code=='\n') { code++; goto next_word_ws; } 1552 + else if (is_alnum_(*code)) { name_start = code; code++; goto next_word; } 1553 + else goto start; 1554 + 1555 + next_word : 1556 + if (is_alnum_(*code)) { code++; goto next_word; } 1557 + else //store item 1558 + { 1559 + items = realloc(items, (*size + 1) * sizeof(tic_outline_item)); 1560 + items[*size].pos = name_start; 1561 + items[*size].size = (s32)(code - name_start); 1562 + (*size)++; 1563 + goto start; 1564 + } 1565 + 1566 + comment : 1567 + if (*code == 0) goto end; 1568 + else if (*code == '\n') { code++; goto start; } 1569 + else { *code++; goto comment; } 1570 + 1571 + string : 1572 + if (*code == 0) goto end; 1573 + else if (*code == '"') { code++; goto start; } 1574 + else if (*code == '\\') { code++; goto string_escape; } 1575 + else { code++; goto string; } 1576 + 1577 + string_escape : 1578 + if (*code == 0) goto end; 1579 + else { code++; goto string; } 1580 + 1581 + multiline_string : 1582 + if (*code == 0) goto end; 1583 + else if (*code == '\\') { code++; goto multiline_string_escape; } 1584 + else if (strncmp(code, "\"\"\"", 3) == 0) { code += 3; goto start; } 1585 + else {code++; goto string; } 1586 + 1587 + multiline_string_escape : 1588 + if (*code == 0) goto end; 1589 + else { code++; goto multiline_string; } 1590 + 1591 + end: 1592 + return items; 1593 + 1594 + } 1595 + 1596 + void evalPython(tic_mem* tic, const char* code) 1597 + { 1598 + printf("TODO: python eval not yet implemented\n."); 1599 + } 1600 + 1601 + 1602 + static const char* const PythonKeywords[] = 1603 + { 1604 + "is not", "not in", "yield from", 1605 + "class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "yield", 1606 + "None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally", 1607 + "while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise" 1608 + }; 1609 + 1610 + 1611 + const tic_script_config PythonSyntaxConfig = 1612 + { 1613 + .id = 20, 1614 + .name = "python", 1615 + .fileExtension = ".py", 1616 + .projectComment = "#", 1617 + .init = initPython, 1618 + .close = closePython, 1619 + .tick = callPythonTick, 1620 + .boot = callPythonBoot, 1621 + 1622 + .callback = 1623 + { 1624 + .scanline = callPythonScanline, 1625 + .border = callPythonBorder, 1626 + .menu = callPythonMenu, 1627 + }, 1628 + 1629 + .getOutline = getPythonOutline, 1630 + .eval = evalPython, 1631 + 1632 + .blockCommentStart = NULL, 1633 + .blockCommentEnd = NULL, 1634 + .blockCommentStart2 = NULL, 1635 + .blockCommentEnd2 = NULL, 1636 + .singleComment = "#", 1637 + .blockStringStart = NULL, 1638 + .blockStringEnd = NULL, 1639 + .blockEnd = NULL, 1640 + .stdStringStartEnd = "'\"", 1641 + 1642 + .keywords = PythonKeywords, 1643 + .keywordsCount = COUNT_OF(PythonKeywords), 1644 + }; 1645 + 1646 + #endif/* defined(TIC_BUILD_WITH_PYTHON) */
+8
src/core/languages.c
··· 41 41 extern tic_script_config JanetSyntaxConfig; 42 42 #endif 43 43 44 + #if defined(TIC_BUILD_WITH_PYTHON) 45 + extern tic_script_config PythonSyntaxConfig; 46 + #endif 47 + 44 48 45 49 tic_script_config* Languages[] = { 46 50 ··· 82 86 83 87 #if defined(TIC_BUILD_WITH_JANET) 84 88 &JanetSyntaxConfig, 89 + #endif 90 + 91 + #if defined(TIC_BUILD_WITH_PYTHON) 92 + &PythonSyntaxConfig, 85 93 #endif 86 94 87 95 NULL};
+27
src/studio/demos.c
··· 222 222 223 223 #endif 224 224 225 + #if defined(TIC_BUILD_WITH_PYTHON) 226 + 227 + static const u8 PythonDemoRom[] = 228 + { 229 + #include "../build/assets/pythondemo.tic.dat" 230 + }; 231 + 232 + static const u8 pythonmark[] = 233 + { 234 + #include "../build/assets/pythonmark.tic.dat" 235 + }; 236 + 237 + tic_script_config_extra PythonSyntaxConfigExtra = 238 + { 239 + .name = "python", 240 + .demoRom = PythonDemoRom, 241 + .demoRomSize = sizeof PythonDemoRom, 242 + .markRom = pythonmark, 243 + .markRomSize = sizeof pythonmark, 244 + }; 245 + 246 + #endif 247 + 248 + 225 249 tic_script_config_extra* getConfigExtra(const tic_script_config* config) 226 250 { 227 251 ··· 266 290 #endif 267 291 #if defined(TIC_BUILD_WITH_JANET) 268 292 &JanetSyntaxConfigExtra, 293 + #endif 294 + #if defined(TIC_BUILD_WITH_PYTHON) 295 + &PythonSyntaxConfigExtra, 269 296 #endif 270 297 NULL 271 298 };
+8483
vendor/pocketpy/pocketpy.h
··· 1 + /* 2 + * Copyright (c) 2023 blueloveTH 3 + * Distributed Under The MIT License 4 + * https://github.com/blueloveTH/pocketpy 5 + */ 6 + 7 + #ifndef POCKETPY_H 8 + #define POCKETPY_H 9 + 10 + 11 + #ifdef _MSC_VER 12 + #pragma warning (disable:4267) 13 + #pragma warning (disable:4101) 14 + #pragma warning (disable:4244) 15 + #define _CRT_NONSTDC_NO_DEPRECATE 16 + #define strdup _strdup 17 + #endif 18 + 19 + #include <cmath> 20 + #include <cstring> 21 + 22 + #include <sstream> 23 + #include <regex> 24 + #include <stdexcept> 25 + #include <vector> 26 + #include <string> 27 + #include <chrono> 28 + #include <string_view> 29 + #include <iomanip> 30 + #include <memory> 31 + #include <iostream> 32 + #include <map> 33 + #include <set> 34 + #include <algorithm> 35 + #include <random> 36 + #include <initializer_list> 37 + #include <variant> 38 + #include <type_traits> 39 + 40 + #define PK_VERSION "0.9.9" 41 + 42 + // debug macros 43 + #define DEBUG_NO_BUILTIN_MODULES 0 44 + #define DEBUG_EXTRA_CHECK 0 45 + #define DEBUG_DIS_EXEC 0 46 + #define DEBUG_CEVAL_STEP 0 47 + #define DEBUG_CEVAL_STEP_MIN 0 48 + #define DEBUG_FULL_EXCEPTION 0 49 + #define DEBUG_MEMORY_POOL 0 50 + #define DEBUG_NO_MEMORY_POOL 0 51 + #define DEBUG_NO_AUTO_GC 0 52 + #define DEBUG_GC_STATS 0 53 + 54 + #ifdef __ANDROID__ 55 + #include <android/ndk-version.h> 56 + 57 + #if __NDK_MAJOR__ <= 22 58 + #define PK_ENABLE_OS 0 59 + #else 60 + #define PK_ENABLE_OS 0 61 + #endif 62 + 63 + #else 64 + #define PK_ENABLE_OS 0 65 + #endif 66 + 67 + // This is the maximum number of arguments in a function declaration 68 + // including positional arguments, keyword-only arguments, and varargs 69 + #define PK_MAX_CO_VARNAMES 255 70 + 71 + #if _MSC_VER 72 + #define PK_ENABLE_COMPUTED_GOTO 0 73 + #define UNREACHABLE() __assume(0) 74 + #else 75 + #define PK_ENABLE_COMPUTED_GOTO 1 76 + #define UNREACHABLE() __builtin_unreachable() 77 + 78 + #if DEBUG_CEVAL_STEP || DEBUG_CEVAL_STEP_MIN 79 + #undef PK_ENABLE_COMPUTED_GOTO 80 + #endif 81 + 82 + #endif 83 + 84 + namespace pkpy{ 85 + 86 + namespace std = ::std; 87 + 88 + template <size_t T> 89 + struct NumberTraits; 90 + 91 + template <> 92 + struct NumberTraits<4> { 93 + using int_t = int32_t; 94 + using float_t = float; 95 + 96 + template<typename... Args> 97 + static int_t stoi(Args&&... args) { return std::stoi(std::forward<Args>(args)...); } 98 + template<typename... Args> 99 + static float_t stof(Args&&... args) { return std::stof(std::forward<Args>(args)...); } 100 + }; 101 + 102 + template <> 103 + struct NumberTraits<8> { 104 + using int_t = int64_t; 105 + using float_t = double; 106 + 107 + template<typename... Args> 108 + static int_t stoi(Args&&... args) { return std::stoll(std::forward<Args>(args)...); } 109 + template<typename... Args> 110 + static float_t stof(Args&&... args) { return std::stod(std::forward<Args>(args)...); } 111 + }; 112 + 113 + using Number = NumberTraits<sizeof(void*)>; 114 + using i64 = Number::int_t; 115 + using f64 = Number::float_t; 116 + 117 + static_assert(sizeof(i64) == sizeof(void*)); 118 + static_assert(sizeof(f64) == sizeof(void*)); 119 + static_assert(std::numeric_limits<f64>::is_iec559); 120 + 121 + struct Dummy { }; 122 + struct DummyInstance { }; 123 + struct DummyModule { }; 124 + struct Discarded { }; 125 + 126 + struct Type { 127 + int index; 128 + Type(): index(-1) {} 129 + Type(int index): index(index) {} 130 + bool operator==(Type other) const noexcept { return this->index == other.index; } 131 + bool operator!=(Type other) const noexcept { return this->index != other.index; } 132 + operator int() const noexcept { return this->index; } 133 + }; 134 + 135 + #define THREAD_LOCAL // thread_local 136 + #define CPP_LAMBDA(x) ([](VM* vm, ArgsView args) { return x; }) 137 + #define CPP_NOT_IMPLEMENTED() ([](VM* vm, ArgsView args) { vm->NotImplementedError(); return vm->None; }) 138 + 139 + #ifdef POCKETPY_H 140 + #define FATAL_ERROR() throw std::runtime_error( "L" + std::to_string(__LINE__) + " FATAL_ERROR()!"); 141 + #else 142 + #define FATAL_ERROR() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " FATAL_ERROR()!"); 143 + #endif 144 + 145 + inline const float kInstAttrLoadFactor = 0.67f; 146 + inline const float kTypeAttrLoadFactor = 0.5f; 147 + 148 + struct PyObject; 149 + #define BITS(p) (reinterpret_cast<i64>(p)) 150 + inline bool is_tagged(PyObject* p) noexcept { return (BITS(p) & 0b11) != 0b00; } 151 + inline bool is_int(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b01; } 152 + inline bool is_float(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b10; } 153 + inline bool is_special(PyObject* p) noexcept { return (BITS(p) & 0b11) == 0b11; } 154 + 155 + inline bool is_both_int_or_float(PyObject* a, PyObject* b) noexcept { 156 + return is_tagged(a) && is_tagged(b); 157 + } 158 + 159 + inline bool is_both_int(PyObject* a, PyObject* b) noexcept { 160 + return is_int(a) && is_int(b); 161 + } 162 + 163 + // special singals, is_tagged() for them is true 164 + inline PyObject* const PY_NULL = (PyObject*)0b000011; 165 + inline PyObject* const PY_BEGIN_CALL = (PyObject*)0b010011; 166 + inline PyObject* const PY_OP_CALL = (PyObject*)0b100011; 167 + inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011; 168 + 169 + struct Expr; 170 + typedef std::unique_ptr<Expr> Expr_; 171 + 172 + } // namespace pkpy 173 + 174 + 175 + namespace pkpy{ 176 + 177 + struct LinkedListNode{ 178 + LinkedListNode* prev; 179 + LinkedListNode* next; 180 + }; 181 + 182 + template<typename T> 183 + struct DoubleLinkedList{ 184 + static_assert(std::is_base_of_v<LinkedListNode, T>); 185 + int _size; 186 + LinkedListNode head; 187 + LinkedListNode tail; 188 + 189 + DoubleLinkedList(): _size(0){ 190 + head.prev = nullptr; 191 + head.next = &tail; 192 + tail.prev = &head; 193 + tail.next = nullptr; 194 + } 195 + 196 + void push_back(T* node){ 197 + node->prev = tail.prev; 198 + node->next = &tail; 199 + tail.prev->next = node; 200 + tail.prev = node; 201 + _size++; 202 + } 203 + 204 + void push_front(T* node){ 205 + node->prev = &head; 206 + node->next = head.next; 207 + head.next->prev = node; 208 + head.next = node; 209 + _size++; 210 + } 211 + 212 + void pop_back(){ 213 + #if DEBUG_MEMORY_POOL 214 + if(empty()) throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list"); 215 + #endif 216 + tail.prev->prev->next = &tail; 217 + tail.prev = tail.prev->prev; 218 + _size--; 219 + } 220 + 221 + void pop_front(){ 222 + #if DEBUG_MEMORY_POOL 223 + if(empty()) throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list"); 224 + #endif 225 + head.next->next->prev = &head; 226 + head.next = head.next->next; 227 + _size--; 228 + } 229 + 230 + T* back() const { 231 + #if DEBUG_MEMORY_POOL 232 + if(empty()) throw std::runtime_error("DoubleLinkedList::back() called on empty list"); 233 + #endif 234 + return static_cast<T*>(tail.prev); 235 + } 236 + 237 + T* front() const { 238 + #if DEBUG_MEMORY_POOL 239 + if(empty()) throw std::runtime_error("DoubleLinkedList::front() called on empty list"); 240 + #endif 241 + return static_cast<T*>(head.next); 242 + } 243 + 244 + void erase(T* node){ 245 + #if DEBUG_MEMORY_POOL 246 + if(empty()) throw std::runtime_error("DoubleLinkedList::erase() called on empty list"); 247 + LinkedListNode* n = head.next; 248 + while(n != &tail){ 249 + if(n == node) break; 250 + n = n->next; 251 + } 252 + if(n != node) throw std::runtime_error("DoubleLinkedList::erase() called on node not in the list"); 253 + #endif 254 + node->prev->next = node->next; 255 + node->next->prev = node->prev; 256 + _size--; 257 + } 258 + 259 + void move_all_back(DoubleLinkedList<T>& other){ 260 + if(other.empty()) return; 261 + other.tail.prev->next = &tail; 262 + tail.prev->next = other.head.next; 263 + other.head.next->prev = tail.prev; 264 + tail.prev = other.tail.prev; 265 + _size += other._size; 266 + other.head.next = &other.tail; 267 + other.tail.prev = &other.head; 268 + other._size = 0; 269 + } 270 + 271 + bool empty() const { 272 + #if DEBUG_MEMORY_POOL 273 + if(size() == 0){ 274 + if(head.next != &tail || tail.prev != &head){ 275 + throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty"); 276 + } 277 + return true; 278 + } 279 + #endif 280 + return _size == 0; 281 + } 282 + 283 + int size() const { return _size; } 284 + 285 + template<typename Func> 286 + void apply(Func func){ 287 + LinkedListNode* p = head.next; 288 + while(p != &tail){ 289 + LinkedListNode* next = p->next; 290 + func(static_cast<T*>(p)); 291 + p = next; 292 + } 293 + } 294 + }; 295 + 296 + template<int __BlockSize=128> 297 + struct MemoryPool{ 298 + static const size_t __MaxBlocks = 256*1024 / __BlockSize; 299 + struct Block{ 300 + void* arena; 301 + char data[__BlockSize]; 302 + }; 303 + 304 + struct Arena: LinkedListNode{ 305 + Block _blocks[__MaxBlocks]; 306 + Block* _free_list[__MaxBlocks]; 307 + int _free_list_size; 308 + bool dirty; 309 + 310 + Arena(): _free_list_size(__MaxBlocks), dirty(false){ 311 + for(int i=0; i<__MaxBlocks; i++){ 312 + _blocks[i].arena = this; 313 + _free_list[i] = &_blocks[i]; 314 + } 315 + } 316 + 317 + bool empty() const { return _free_list_size == 0; } 318 + bool full() const { return _free_list_size == __MaxBlocks; } 319 + 320 + size_t allocated_size() const{ 321 + return __BlockSize * (__MaxBlocks - _free_list_size); 322 + } 323 + 324 + Block* alloc(){ 325 + #if DEBUG_MEMORY_POOL 326 + if(empty()) throw std::runtime_error("Arena::alloc() called on empty arena"); 327 + #endif 328 + _free_list_size--; 329 + return _free_list[_free_list_size]; 330 + } 331 + 332 + void dealloc(Block* block){ 333 + #if DEBUG_MEMORY_POOL 334 + if(full()) throw std::runtime_error("Arena::dealloc() called on full arena"); 335 + #endif 336 + _free_list[_free_list_size] = block; 337 + _free_list_size++; 338 + } 339 + }; 340 + 341 + DoubleLinkedList<Arena> _arenas; 342 + DoubleLinkedList<Arena> _empty_arenas; 343 + 344 + template<typename __T> 345 + void* alloc() { return alloc(sizeof(__T)); } 346 + 347 + void* alloc(size_t size){ 348 + #if DEBUG_NO_MEMORY_POOL 349 + return malloc(size); 350 + #endif 351 + if(size > __BlockSize){ 352 + void* p = malloc(sizeof(void*) + size); 353 + memset(p, 0, sizeof(void*)); 354 + return (char*)p + sizeof(void*); 355 + } 356 + 357 + if(_arenas.empty()){ 358 + // std::cout << _arenas.size() << ',' << _empty_arenas.size() << ',' << _full_arenas.size() << std::endl; 359 + _arenas.push_back(new Arena()); 360 + } 361 + Arena* arena = _arenas.back(); 362 + void* p = arena->alloc()->data; 363 + if(arena->empty()){ 364 + _arenas.pop_back(); 365 + arena->dirty = true; 366 + _empty_arenas.push_back(arena); 367 + } 368 + return p; 369 + } 370 + 371 + void dealloc(void* p){ 372 + #if DEBUG_NO_MEMORY_POOL 373 + free(p); 374 + return; 375 + #endif 376 + #if DEBUG_MEMORY_POOL 377 + if(p == nullptr) throw std::runtime_error("MemoryPool::dealloc() called on nullptr"); 378 + #endif 379 + Block* block = (Block*)((char*)p - sizeof(void*)); 380 + if(block->arena == nullptr){ 381 + free(block); 382 + }else{ 383 + Arena* arena = (Arena*)block->arena; 384 + if(arena->empty()){ 385 + _empty_arenas.erase(arena); 386 + _arenas.push_front(arena); 387 + arena->dealloc(block); 388 + }else{ 389 + arena->dealloc(block); 390 + if(arena->full() && arena->dirty){ 391 + _arenas.erase(arena); 392 + delete arena; 393 + } 394 + } 395 + } 396 + } 397 + 398 + size_t allocated_size() { 399 + size_t n = 0; 400 + _arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); }); 401 + _empty_arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); }); 402 + return n; 403 + } 404 + 405 + ~MemoryPool(){ 406 + _arenas.apply([](Arena* arena){ delete arena; }); 407 + _empty_arenas.apply([](Arena* arena){ delete arena; }); 408 + } 409 + }; 410 + 411 + inline MemoryPool<64> pool64; 412 + inline MemoryPool<128> pool128; 413 + 414 + // get the total memory usage of pkpy (across all VMs) 415 + inline size_t memory_usage(){ 416 + return pool64.allocated_size() + pool128.allocated_size(); 417 + } 418 + 419 + #define SP_MALLOC(size) pool128.alloc(size) 420 + #define SP_FREE(p) pool128.dealloc(p) 421 + 422 + template <typename T> 423 + struct shared_ptr { 424 + int* counter; 425 + 426 + T* _t() const noexcept { return (T*)(counter + 1); } 427 + void _inc_counter() { if(counter) ++(*counter); } 428 + void _dec_counter() { if(counter && --(*counter) == 0) {((T*)(counter + 1))->~T(); SP_FREE(counter);} } 429 + 430 + public: 431 + shared_ptr() : counter(nullptr) {} 432 + shared_ptr(int* counter) : counter(counter) {} 433 + shared_ptr(const shared_ptr& other) : counter(other.counter) { 434 + _inc_counter(); 435 + } 436 + shared_ptr(shared_ptr&& other) noexcept : counter(other.counter) { 437 + other.counter = nullptr; 438 + } 439 + ~shared_ptr() { _dec_counter(); } 440 + 441 + bool operator==(const shared_ptr& other) const { return counter == other.counter; } 442 + bool operator!=(const shared_ptr& other) const { return counter != other.counter; } 443 + bool operator<(const shared_ptr& other) const { return counter < other.counter; } 444 + bool operator>(const shared_ptr& other) const { return counter > other.counter; } 445 + bool operator<=(const shared_ptr& other) const { return counter <= other.counter; } 446 + bool operator>=(const shared_ptr& other) const { return counter >= other.counter; } 447 + bool operator==(std::nullptr_t) const { return counter == nullptr; } 448 + bool operator!=(std::nullptr_t) const { return counter != nullptr; } 449 + 450 + shared_ptr& operator=(const shared_ptr& other) { 451 + _dec_counter(); 452 + counter = other.counter; 453 + _inc_counter(); 454 + return *this; 455 + } 456 + 457 + shared_ptr& operator=(shared_ptr&& other) noexcept { 458 + _dec_counter(); 459 + counter = other.counter; 460 + other.counter = nullptr; 461 + return *this; 462 + } 463 + 464 + T& operator*() const { return *_t(); } 465 + T* operator->() const { return _t(); } 466 + T* get() const { return _t(); } 467 + 468 + int use_count() const { 469 + return counter ? *counter : 0; 470 + } 471 + 472 + void reset(){ 473 + _dec_counter(); 474 + counter = nullptr; 475 + } 476 + }; 477 + 478 + template <typename T, typename... Args> 479 + shared_ptr<T> make_sp(Args&&... args) { 480 + int* p = (int*)SP_MALLOC(sizeof(int) + sizeof(T)); 481 + *p = 1; 482 + new(p+1) T(std::forward<Args>(args)...); 483 + return shared_ptr<T>(p); 484 + } 485 + 486 + }; // namespace pkpy 487 + 488 + 489 + 490 + namespace pkpy{ 491 + 492 + template<typename T> 493 + struct pod_vector{ 494 + static_assert(128 % sizeof(T) == 0); 495 + static_assert(std::is_pod_v<T>); 496 + static constexpr int N = 128 / sizeof(T); 497 + static_assert(N > 4); 498 + int _size; 499 + int _capacity; 500 + T* _data; 501 + 502 + pod_vector(): _size(0), _capacity(N) { 503 + _data = (T*)pool128.alloc(_capacity * sizeof(T)); 504 + } 505 + 506 + pod_vector(int size): _size(size), _capacity(std::max(N, size)) { 507 + _data = (T*)pool128.alloc(_capacity * sizeof(T)); 508 + } 509 + 510 + pod_vector(const pod_vector& other): _size(other._size), _capacity(other._capacity) { 511 + _data = (T*)pool128.alloc(_capacity * sizeof(T)); 512 + memcpy(_data, other._data, sizeof(T) * _size); 513 + } 514 + 515 + pod_vector(pod_vector&& other) noexcept { 516 + _size = other._size; 517 + _capacity = other._capacity; 518 + _data = other._data; 519 + other._data = nullptr; 520 + } 521 + 522 + pod_vector& operator=(pod_vector&& other) noexcept { 523 + if(_data!=nullptr) pool128.dealloc(_data); 524 + _size = other._size; 525 + _capacity = other._capacity; 526 + _data = other._data; 527 + other._data = nullptr; 528 + return *this; 529 + } 530 + 531 + // remove copy assignment 532 + pod_vector& operator=(const pod_vector& other) = delete; 533 + 534 + template<typename __ValueT> 535 + void push_back(__ValueT&& t) { 536 + if (_size == _capacity) reserve(_capacity*2); 537 + _data[_size++] = std::forward<__ValueT>(t); 538 + } 539 + 540 + template<typename... Args> 541 + void emplace_back(Args&&... args) { 542 + if (_size == _capacity) reserve(_capacity*2); 543 + new (&_data[_size++]) T(std::forward<Args>(args)...); 544 + } 545 + 546 + void reserve(int cap){ 547 + if(cap <= _capacity) return; 548 + _capacity = cap; 549 + T* old_data = _data; 550 + _data = (T*)pool128.alloc(_capacity * sizeof(T)); 551 + if(old_data!=nullptr){ 552 + memcpy(_data, old_data, sizeof(T) * _size); 553 + pool128.dealloc(old_data); 554 + } 555 + } 556 + 557 + void pop_back() { _size--; } 558 + T popx_back() { T t = std::move(_data[_size-1]); _size--; return t; } 559 + void extend(const pod_vector& other){ 560 + for(int i=0; i<other.size(); i++) push_back(other[i]); 561 + } 562 + 563 + T& operator[](int index) { return _data[index]; } 564 + const T& operator[](int index) const { return _data[index]; } 565 + 566 + T* begin() { return _data; } 567 + T* end() { return _data + _size; } 568 + const T* begin() const { return _data; } 569 + const T* end() const { return _data + _size; } 570 + T& back() { return _data[_size - 1]; } 571 + const T& back() const { return _data[_size - 1]; } 572 + 573 + bool empty() const { return _size == 0; } 574 + int size() const { return _size; } 575 + T* data() { return _data; } 576 + const T* data() const { return _data; } 577 + void clear() { _size=0; } 578 + 579 + template<typename __ValueT> 580 + void insert(int i, __ValueT&& val){ 581 + if (_size == _capacity) reserve(_capacity*2); 582 + for(int j=_size; j>i; j--) _data[j] = _data[j-1]; 583 + _data[i] = std::forward<__ValueT>(val); 584 + _size++; 585 + } 586 + 587 + void erase(int i){ 588 + for(int j=i; j<_size-1; j++) _data[j] = _data[j+1]; 589 + _size--; 590 + } 591 + 592 + void resize(int size){ 593 + if(size > _capacity) reserve(size); 594 + _size = size; 595 + } 596 + 597 + ~pod_vector() { 598 + if(_data!=nullptr) pool128.dealloc(_data); 599 + } 600 + }; 601 + 602 + 603 + template <typename T, typename Container=std::vector<T>> 604 + class stack{ 605 + Container vec; 606 + public: 607 + void push(const T& t){ vec.push_back(t); } 608 + void push(T&& t){ vec.push_back(std::move(t)); } 609 + template<typename... Args> 610 + void emplace(Args&&... args){ 611 + vec.emplace_back(std::forward<Args>(args)...); 612 + } 613 + void pop(){ vec.pop_back(); } 614 + void clear(){ vec.clear(); } 615 + bool empty() const { return vec.empty(); } 616 + size_t size() const { return vec.size(); } 617 + T& top(){ return vec.back(); } 618 + const T& top() const { return vec.back(); } 619 + T popx(){ T t = std::move(vec.back()); vec.pop_back(); return t; } 620 + void reserve(int n){ vec.reserve(n); } 621 + Container& data() { return vec; } 622 + }; 623 + 624 + template <typename T> 625 + using pod_stack = stack<T, pod_vector<T>>; 626 + } // namespace pkpy 627 + 628 + 629 + namespace pkpy { 630 + 631 + inline int utf8len(unsigned char c, bool suppress=false){ 632 + if((c & 0b10000000) == 0) return 1; 633 + if((c & 0b11100000) == 0b11000000) return 2; 634 + if((c & 0b11110000) == 0b11100000) return 3; 635 + if((c & 0b11111000) == 0b11110000) return 4; 636 + if((c & 0b11111100) == 0b11111000) return 5; 637 + if((c & 0b11111110) == 0b11111100) return 6; 638 + if(!suppress) throw std::runtime_error("invalid utf8 char: " + std::to_string(c)); 639 + return 0; 640 + } 641 + 642 + struct Str{ 643 + int size; 644 + bool is_ascii; 645 + char* data; 646 + 647 + Str(): size(0), is_ascii(true), data(nullptr) {} 648 + 649 + Str(int size, bool is_ascii): size(size), is_ascii(is_ascii) { 650 + data = (char*)pool64.alloc(size); 651 + } 652 + 653 + #define STR_INIT() \ 654 + data = (char*)pool64.alloc(size); \ 655 + for(int i=0; i<size; i++){ \ 656 + data[i] = s[i]; \ 657 + if(!isascii(s[i])) is_ascii = false; \ 658 + } 659 + 660 + Str(const std::string& s): size(s.size()), is_ascii(true) { 661 + STR_INIT() 662 + } 663 + 664 + Str(std::string_view s): size(s.size()), is_ascii(true) { 665 + STR_INIT() 666 + } 667 + 668 + Str(const char* s): size(strlen(s)), is_ascii(true) { 669 + STR_INIT() 670 + } 671 + 672 + Str(const char* s, int len): size(len), is_ascii(true) { 673 + STR_INIT() 674 + } 675 + 676 + #undef STR_INIT 677 + 678 + Str(const Str& other): size(other.size), is_ascii(other.is_ascii) { 679 + data = (char*)pool64.alloc(size); 680 + memcpy(data, other.data, size); 681 + } 682 + 683 + Str(Str&& other): size(other.size), is_ascii(other.is_ascii), data(other.data) { 684 + other.data = nullptr; 685 + other.size = 0; 686 + } 687 + 688 + const char* begin() const { return data; } 689 + const char* end() const { return data + size; } 690 + char operator[](int idx) const { return data[idx]; } 691 + int length() const { return size; } 692 + bool empty() const { return size == 0; } 693 + size_t hash() const{ return std::hash<std::string_view>()(sv()); } 694 + 695 + Str& operator=(const Str& other){ 696 + if(data!=nullptr) pool64.dealloc(data); 697 + size = other.size; 698 + is_ascii = other.is_ascii; 699 + data = (char*)pool64.alloc(size); 700 + memcpy(data, other.data, size); 701 + return *this; 702 + } 703 + 704 + Str& operator=(Str&& other) noexcept{ 705 + if(data!=nullptr) pool64.dealloc(data); 706 + size = other.size; 707 + is_ascii = other.is_ascii; 708 + data = other.data; 709 + other.data = nullptr; 710 + return *this; 711 + } 712 + 713 + ~Str(){ 714 + if(data!=nullptr) pool64.dealloc(data); 715 + } 716 + 717 + Str operator+(const Str& other) const { 718 + Str ret(size + other.size, is_ascii && other.is_ascii); 719 + memcpy(ret.data, data, size); 720 + memcpy(ret.data + size, other.data, other.size); 721 + return ret; 722 + } 723 + 724 + Str operator+(const char* p) const { 725 + Str other(p); 726 + return *this + other; 727 + } 728 + 729 + friend Str operator+(const char* p, const Str& str){ 730 + Str other(p); 731 + return other + str; 732 + } 733 + 734 + friend std::ostream& operator<<(std::ostream& os, const Str& str){ 735 + if(str.data!=nullptr) os.write(str.data, str.size); 736 + return os; 737 + } 738 + 739 + bool operator==(const Str& other) const { 740 + if(size != other.size) return false; 741 + return memcmp(data, other.data, size) == 0; 742 + } 743 + 744 + bool operator!=(const Str& other) const { 745 + if(size != other.size) return true; 746 + return memcmp(data, other.data, size) != 0; 747 + } 748 + 749 + bool operator<(const Str& other) const { 750 + int ret = strncmp(data, other.data, std::min(size, other.size)); 751 + if(ret != 0) return ret < 0; 752 + return size < other.size; 753 + } 754 + 755 + bool operator<(const std::string_view& other) const { 756 + int ret = strncmp(data, other.data(), std::min(size, (int)other.size())); 757 + if(ret != 0) return ret < 0; 758 + return size < (int)other.size(); 759 + } 760 + 761 + friend bool operator<(const std::string_view& other, const Str& str){ 762 + return str > other; 763 + } 764 + 765 + bool operator>(const Str& other) const { 766 + int ret = strncmp(data, other.data, std::min(size, other.size)); 767 + if(ret != 0) return ret > 0; 768 + return size > other.size; 769 + } 770 + 771 + bool operator<=(const Str& other) const { 772 + int ret = strncmp(data, other.data, std::min(size, other.size)); 773 + if(ret != 0) return ret < 0; 774 + return size <= other.size; 775 + } 776 + 777 + bool operator>=(const Str& other) const { 778 + int ret = strncmp(data, other.data, std::min(size, other.size)); 779 + if(ret != 0) return ret > 0; 780 + return size >= other.size; 781 + } 782 + 783 + Str substr(int start, int len) const { 784 + Str ret(len, is_ascii); 785 + memcpy(ret.data, data + start, len); 786 + return ret; 787 + } 788 + 789 + Str substr(int start) const { 790 + return substr(start, size - start); 791 + } 792 + 793 + char* c_str_dup() const { 794 + char* p = (char*)malloc(size + 1); 795 + memcpy(p, data, size); 796 + p[size] = 0; 797 + return p; 798 + } 799 + 800 + std::string_view sv() const { 801 + return std::string_view(data, size); 802 + } 803 + 804 + std::string str() const { 805 + return std::string(data, size); 806 + } 807 + 808 + Str lstrip() const { 809 + std::string copy(data, size); 810 + copy.erase(copy.begin(), std::find_if(copy.begin(), copy.end(), [](char c) { 811 + // std::isspace(c) does not working on windows (Debug) 812 + return c != ' ' && c != '\t' && c != '\r' && c != '\n'; 813 + })); 814 + return Str(copy); 815 + } 816 + 817 + Str escape(bool single_quote=true) const { 818 + std::stringstream ss; 819 + ss << (single_quote ? '\'' : '"'); 820 + for (int i=0; i<length(); i++) { 821 + char c = this->operator[](i); 822 + switch (c) { 823 + case '"': 824 + if(!single_quote) ss << '\\'; 825 + ss << '"'; 826 + break; 827 + case '\'': 828 + if(single_quote) ss << '\\'; 829 + ss << '\''; 830 + break; 831 + case '\\': ss << '\\' << '\\'; break; 832 + case '\n': ss << "\\n"; break; 833 + case '\r': ss << "\\r"; break; 834 + case '\t': ss << "\\t"; break; 835 + default: 836 + if ('\x00' <= c && c <= '\x1f') { 837 + ss << "\\x" << std::hex << std::setw(2) << std::setfill('0') << (int)c; 838 + } else { 839 + ss << c; 840 + } 841 + } 842 + } 843 + ss << (single_quote ? '\'' : '"'); 844 + return ss.str(); 845 + } 846 + 847 + int index(const Str& sub, int start=0) const { 848 + auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size); 849 + if(p == data + size) return -1; 850 + return p - data; 851 + } 852 + 853 + Str replace(const Str& old, const Str& new_, int count=-1) const { 854 + std::stringstream ss; 855 + int start = 0; 856 + while(true){ 857 + int i = index(old, start); 858 + if(i == -1) break; 859 + ss << substr(start, i - start); 860 + ss << new_; 861 + start = i + old.size; 862 + if(count != -1 && --count == 0) break; 863 + } 864 + ss << substr(start, size - start); 865 + return ss.str(); 866 + } 867 + 868 + /*************unicode*************/ 869 + 870 + int _unicode_index_to_byte(int i) const{ 871 + if(is_ascii) return i; 872 + int j = 0; 873 + while(i > 0){ 874 + j += utf8len(data[j]); 875 + i--; 876 + } 877 + return j; 878 + } 879 + 880 + int _byte_index_to_unicode(int n) const{ 881 + if(is_ascii) return n; 882 + int cnt = 0; 883 + for(int i=0; i<n; i++){ 884 + if((data[i] & 0xC0) != 0x80) cnt++; 885 + } 886 + return cnt; 887 + } 888 + 889 + Str u8_getitem(int i) const{ 890 + i = _unicode_index_to_byte(i); 891 + return substr(i, utf8len(data[i])); 892 + } 893 + 894 + Str u8_slice(int start, int stop, int step) const{ 895 + std::stringstream ss; 896 + if(is_ascii){ 897 + for(int i=start; step>0?i<stop:i>stop; i+=step) ss << data[i]; 898 + }else{ 899 + for(int i=start; step>0?i<stop:i>stop; i+=step) ss << u8_getitem(i); 900 + } 901 + return ss.str(); 902 + } 903 + 904 + int u8_length() const { 905 + return _byte_index_to_unicode(size); 906 + } 907 + }; 908 + 909 + template<typename... Args> 910 + inline std::string fmt(Args&&... args) { 911 + std::stringstream ss; 912 + (ss << ... << args); 913 + return ss.str(); 914 + } 915 + 916 + const uint32_t kLoRangeA[] = {170,186,443,448,660,1488,1519,1568,1601,1646,1649,1749,1774,1786,1791,1808,1810,1869,1969,1994,2048,2112,2144,2208,2230,2308,2365,2384,2392,2418,2437,2447,2451,2474,2482,2486,2493,2510,2524,2527,2544,2556,2565,2575,2579,2602,2610,2613,2616,2649,2654,2674,2693,2703,2707,2730,2738,2741,2749,2768,2784,2809,2821,2831,2835,2858,2866,2869,2877,2908,2911,2929,2947,2949,2958,2962,2969,2972,2974,2979,2984,2990,3024,3077,3086,3090,3114,3133,3160,3168,3200,3205,3214,3218,3242,3253,3261,3294,3296,3313,3333,3342,3346,3389,3406,3412,3423,3450,3461,3482,3507,3517,3520,3585,3634,3648,3713,3716,3718,3724,3749,3751,3762,3773,3776,3804,3840,3904,3913,3976,4096,4159,4176,4186,4193,4197,4206,4213,4238,4352,4682,4688,4696,4698,4704,4746,4752,4786,4792,4800,4802,4808,4824,4882,4888,4992,5121,5743,5761,5792,5873,5888,5902,5920,5952,5984,5998,6016,6108,6176,6212,6272,6279,6314,6320,6400,6480,6512,6528,6576,6656,6688,6917,6981,7043,7086,7098,7168,7245,7258,7401,7406,7413,7418,8501,11568,11648,11680,11688,11696,11704,11712,11720,11728,11736,12294,12348,12353,12447,12449,12543,12549,12593,12704,12784,13312,19968,40960,40982,42192,42240,42512,42538,42606,42656,42895,42999,43003,43011,43015,43020,43072,43138,43250,43259,43261,43274,43312,43360,43396,43488,43495,43514,43520,43584,43588,43616,43633,43642,43646,43697,43701,43705,43712,43714,43739,43744,43762,43777,43785,43793,43808,43816,43968,44032,55216,55243,63744,64112,64285,64287,64298,64312,64318,64320,64323,64326,64467,64848,64914,65008,65136,65142,65382,65393,65440,65474,65482,65490,65498,65536,65549,65576,65596,65599,65616,65664,66176,66208,66304,66349,66370,66384,66432,66464,66504,66640,66816,66864,67072,67392,67424,67584,67592,67594,67639,67644,67647,67680,67712,67808,67828,67840,67872,67968,68030,68096,68112,68117,68121,68192,68224,68288,68297,68352,68416,68448,68480,68608,68864,69376,69415,69424,69600,69635,69763,69840,69891,69956,69968,70006,70019,70081,70106,70108,70144,70163,70272,70280,70282,70287,70303,70320,70405,70415,70419,70442,70450,70453,70461,70480,70493,70656,70727,70751,70784,70852,70855,71040,71128,71168,71236,71296,71352,71424,71680,71935,72096,72106,72161,72163,72192,72203,72250,72272,72284,72349,72384,72704,72714,72768,72818,72960,72968,72971,73030,73056,73063,73066,73112,73440,73728,74880,77824,82944,92160,92736,92880,92928,93027,93053,93952,94032,94208,100352,110592,110928,110948,110960,113664,113776,113792,113808,123136,123214,123584,124928,126464,126469,126497,126500,126503,126505,126516,126521,126523,126530,126535,126537,126539,126541,126545,126548,126551,126553,126555,126557,126559,126561,126564,126567,126572,126580,126585,126590,126592,126603,126625,126629,126635,131072,173824,177984,178208,183984,194560}; 917 + const uint32_t kLoRangeB[] = {170,186,443,451,660,1514,1522,1599,1610,1647,1747,1749,1775,1788,1791,1808,1839,1957,1969,2026,2069,2136,2154,2228,2237,2361,2365,2384,2401,2432,2444,2448,2472,2480,2482,2489,2493,2510,2525,2529,2545,2556,2570,2576,2600,2608,2611,2614,2617,2652,2654,2676,2701,2705,2728,2736,2739,2745,2749,2768,2785,2809,2828,2832,2856,2864,2867,2873,2877,2909,2913,2929,2947,2954,2960,2965,2970,2972,2975,2980,2986,3001,3024,3084,3088,3112,3129,3133,3162,3169,3200,3212,3216,3240,3251,3257,3261,3294,3297,3314,3340,3344,3386,3389,3406,3414,3425,3455,3478,3505,3515,3517,3526,3632,3635,3653,3714,3716,3722,3747,3749,3760,3763,3773,3780,3807,3840,3911,3948,3980,4138,4159,4181,4189,4193,4198,4208,4225,4238,4680,4685,4694,4696,4701,4744,4749,4784,4789,4798,4800,4805,4822,4880,4885,4954,5007,5740,5759,5786,5866,5880,5900,5905,5937,5969,5996,6000,6067,6108,6210,6264,6276,6312,6314,6389,6430,6509,6516,6571,6601,6678,6740,6963,6987,7072,7087,7141,7203,7247,7287,7404,7411,7414,7418,8504,11623,11670,11686,11694,11702,11710,11718,11726,11734,11742,12294,12348,12438,12447,12538,12543,12591,12686,12730,12799,19893,40943,40980,42124,42231,42507,42527,42539,42606,42725,42895,42999,43009,43013,43018,43042,43123,43187,43255,43259,43262,43301,43334,43388,43442,43492,43503,43518,43560,43586,43595,43631,43638,43642,43695,43697,43702,43709,43712,43714,43740,43754,43762,43782,43790,43798,43814,43822,44002,55203,55238,55291,64109,64217,64285,64296,64310,64316,64318,64321,64324,64433,64829,64911,64967,65019,65140,65276,65391,65437,65470,65479,65487,65495,65500,65547,65574,65594,65597,65613,65629,65786,66204,66256,66335,66368,66377,66421,66461,66499,66511,66717,66855,66915,67382,67413,67431,67589,67592,67637,67640,67644,67669,67702,67742,67826,67829,67861,67897,68023,68031,68096,68115,68119,68149,68220,68252,68295,68324,68405,68437,68466,68497,68680,68899,69404,69415,69445,69622,69687,69807,69864,69926,69956,70002,70006,70066,70084,70106,70108,70161,70187,70278,70280,70285,70301,70312,70366,70412,70416,70440,70448,70451,70457,70461,70480,70497,70708,70730,70751,70831,70853,70855,71086,71131,71215,71236,71338,71352,71450,71723,71935,72103,72144,72161,72163,72192,72242,72250,72272,72329,72349,72440,72712,72750,72768,72847,72966,72969,73008,73030,73061,73064,73097,73112,73458,74649,75075,78894,83526,92728,92766,92909,92975,93047,93071,94026,94032,100343,101106,110878,110930,110951,111355,113770,113788,113800,113817,123180,123214,123627,125124,126467,126495,126498,126500,126503,126514,126519,126521,126523,126530,126535,126537,126539,126543,126546,126548,126551,126553,126555,126557,126559,126562,126564,126570,126578,126583,126588,126590,126601,126619,126627,126633,126651,173782,177972,178205,183969,191456,195101}; 918 + 919 + inline bool is_unicode_Lo_char(uint32_t c) { 920 + auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA; 921 + if(c == kLoRangeA[index]) return true; 922 + index -= 1; 923 + if(index < 0) return false; 924 + return c >= kLoRangeA[index] && c <= kLoRangeB[index]; 925 + } 926 + 927 + 928 + struct StrName { 929 + uint16_t index; 930 + StrName(): index(0) {} 931 + StrName(uint16_t index): index(index) {} 932 + StrName(const char* s): index(get(s).index) {} 933 + StrName(const Str& s){ 934 + index = get(s.sv()).index; 935 + } 936 + std::string_view sv() const { return _r_interned[index-1].sv(); } 937 + bool empty() const { return index == 0; } 938 + 939 + friend std::ostream& operator<<(std::ostream& os, const StrName& sn){ 940 + return os << sn.sv(); 941 + } 942 + 943 + Str escape() const { 944 + return _r_interned[index-1].escape(); 945 + } 946 + 947 + bool operator==(const StrName& other) const noexcept { 948 + return this->index == other.index; 949 + } 950 + 951 + bool operator!=(const StrName& other) const noexcept { 952 + return this->index != other.index; 953 + } 954 + 955 + bool operator<(const StrName& other) const noexcept { 956 + return this->index < other.index; 957 + } 958 + 959 + bool operator>(const StrName& other) const noexcept { 960 + return this->index > other.index; 961 + } 962 + 963 + static std::map<Str, uint16_t, std::less<>> _interned; 964 + static std::vector<Str> _r_interned; 965 + 966 + static StrName get(std::string_view s){ 967 + auto it = _interned.find(s); 968 + if(it != _interned.end()) return StrName(it->second); 969 + uint16_t index = (uint16_t)(_r_interned.size() + 1); 970 + _interned[s] = index; 971 + _r_interned.push_back(s); 972 + return StrName(index); 973 + } 974 + }; 975 + 976 + struct FastStrStream{ 977 + pod_vector<const Str*> parts; 978 + 979 + FastStrStream& operator<<(const Str& s){ 980 + parts.push_back(&s); 981 + return *this; 982 + } 983 + 984 + Str str() const{ 985 + int len = 0; 986 + bool is_ascii = true; 987 + for(auto& s: parts){ 988 + len += s->length(); 989 + is_ascii &= s->is_ascii; 990 + } 991 + Str result(len, is_ascii); 992 + char* p = result.data; 993 + for(auto& s: parts){ 994 + memcpy(p, s->data, s->length()); 995 + p += s->length(); 996 + } 997 + return result; 998 + } 999 + }; 1000 + 1001 + inline std::map<Str, uint16_t, std::less<>> StrName::_interned; 1002 + inline std::vector<Str> StrName::_r_interned; 1003 + 1004 + const StrName __class__ = StrName::get("__class__"); 1005 + const StrName __base__ = StrName::get("__base__"); 1006 + const StrName __new__ = StrName::get("__new__"); 1007 + const StrName __iter__ = StrName::get("__iter__"); 1008 + const StrName __next__ = StrName::get("__next__"); 1009 + const StrName __str__ = StrName::get("__str__"); 1010 + const StrName __repr__ = StrName::get("__repr__"); 1011 + const StrName __getitem__ = StrName::get("__getitem__"); 1012 + const StrName __setitem__ = StrName::get("__setitem__"); 1013 + const StrName __delitem__ = StrName::get("__delitem__"); 1014 + const StrName __contains__ = StrName::get("__contains__"); 1015 + const StrName __init__ = StrName::get("__init__"); 1016 + const StrName __json__ = StrName::get("__json__"); 1017 + const StrName __name__ = StrName::get("__name__"); 1018 + const StrName __len__ = StrName::get("__len__"); 1019 + const StrName __get__ = StrName::get("__get__"); 1020 + const StrName __set__ = StrName::get("__set__"); 1021 + const StrName __getattr__ = StrName::get("__getattr__"); 1022 + const StrName __setattr__ = StrName::get("__setattr__"); 1023 + const StrName __call__ = StrName::get("__call__"); 1024 + const StrName __doc__ = StrName::get("__doc__"); 1025 + 1026 + const StrName m_self = StrName::get("self"); 1027 + const StrName m_dict = StrName::get("dict"); 1028 + const StrName m_set = StrName::get("set"); 1029 + const StrName m_add = StrName::get("add"); 1030 + const StrName __enter__ = StrName::get("__enter__"); 1031 + const StrName __exit__ = StrName::get("__exit__"); 1032 + 1033 + const StrName __add__ = StrName::get("__add__"); 1034 + const StrName __sub__ = StrName::get("__sub__"); 1035 + const StrName __mul__ = StrName::get("__mul__"); 1036 + // const StrName __truediv__ = StrName::get("__truediv__"); 1037 + const StrName __floordiv__ = StrName::get("__floordiv__"); 1038 + const StrName __mod__ = StrName::get("__mod__"); 1039 + // const StrName __pow__ = StrName::get("__pow__"); 1040 + 1041 + const StrName BINARY_SPECIAL_METHODS[] = { 1042 + StrName::get("__add__"), StrName::get("__sub__"), StrName::get("__mul__"), 1043 + StrName::get("__truediv__"), StrName::get("__floordiv__"), 1044 + StrName::get("__mod__"), StrName::get("__pow__") 1045 + }; 1046 + 1047 + const StrName __lt__ = StrName::get("__lt__"); 1048 + const StrName __le__ = StrName::get("__le__"); 1049 + const StrName __eq__ = StrName::get("__eq__"); 1050 + const StrName __ne__ = StrName::get("__ne__"); 1051 + const StrName __gt__ = StrName::get("__gt__"); 1052 + const StrName __ge__ = StrName::get("__ge__"); 1053 + 1054 + const StrName __lshift__ = StrName::get("__lshift__"); 1055 + const StrName __rshift__ = StrName::get("__rshift__"); 1056 + const StrName __and__ = StrName::get("__and__"); 1057 + const StrName __or__ = StrName::get("__or__"); 1058 + const StrName __xor__ = StrName::get("__xor__"); 1059 + 1060 + } // namespace pkpy 1061 + 1062 + 1063 + namespace pkpy { 1064 + 1065 + using List = pod_vector<PyObject*>; 1066 + 1067 + class Tuple { 1068 + PyObject** _args; 1069 + int _size; 1070 + 1071 + void _alloc(int n){ 1072 + this->_args = (n==0) ? nullptr : (PyObject**)pool64.alloc(n * sizeof(void*)); 1073 + this->_size = n; 1074 + } 1075 + 1076 + public: 1077 + Tuple(int n){ _alloc(n); } 1078 + 1079 + Tuple(const Tuple& other){ 1080 + _alloc(other._size); 1081 + for(int i=0; i<_size; i++) _args[i] = other._args[i]; 1082 + } 1083 + 1084 + Tuple(Tuple&& other) noexcept { 1085 + this->_args = other._args; 1086 + this->_size = other._size; 1087 + other._args = nullptr; 1088 + other._size = 0; 1089 + } 1090 + 1091 + Tuple(std::initializer_list<PyObject*> list) : Tuple(list.size()){ 1092 + int i = 0; 1093 + for(PyObject* p : list) _args[i++] = p; 1094 + } 1095 + 1096 + // TODO: poor performance 1097 + // List is allocated by pool128 while tuple is by pool64 1098 + // ... 1099 + Tuple(List&& other) noexcept : Tuple(other.size()){ 1100 + for(int i=0; i<_size; i++) _args[i] = other[i]; 1101 + other.clear(); 1102 + } 1103 + 1104 + PyObject*& operator[](int i){ return _args[i]; } 1105 + PyObject* operator[](int i) const { return _args[i]; } 1106 + 1107 + Tuple& operator=(Tuple&& other) noexcept { 1108 + if(_args!=nullptr) pool64.dealloc(_args); 1109 + this->_args = other._args; 1110 + this->_size = other._size; 1111 + other._args = nullptr; 1112 + other._size = 0; 1113 + return *this; 1114 + } 1115 + 1116 + int size() const { return _size; } 1117 + 1118 + PyObject** begin() const { return _args; } 1119 + PyObject** end() const { return _args + _size; } 1120 + 1121 + ~Tuple(){ if(_args!=nullptr) pool64.dealloc(_args); } 1122 + }; 1123 + 1124 + // a lightweight view for function args, it does not own the memory 1125 + struct ArgsView{ 1126 + PyObject** _begin; 1127 + PyObject** _end; 1128 + 1129 + ArgsView(PyObject** begin, PyObject** end) : _begin(begin), _end(end) {} 1130 + ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {} 1131 + ArgsView(): _begin(nullptr), _end(nullptr) {} 1132 + 1133 + PyObject** begin() const { return _begin; } 1134 + PyObject** end() const { return _end; } 1135 + int size() const { return _end - _begin; } 1136 + bool empty() const { return _begin == _end; } 1137 + PyObject* operator[](int i) const { return _begin[i]; } 1138 + 1139 + List to_list() const{ 1140 + List ret(size()); 1141 + for(int i=0; i<size(); i++) ret[i] = _begin[i]; 1142 + return ret; 1143 + } 1144 + 1145 + Tuple to_tuple() const{ 1146 + Tuple ret(size()); 1147 + for(int i=0; i<size(); i++) ret[i] = _begin[i]; 1148 + return ret; 1149 + } 1150 + }; 1151 + } // namespace pkpy 1152 + 1153 + 1154 + namespace pkpy{ 1155 + 1156 + const std::vector<uint16_t> kHashSeeds = {9629, 43049, 13267, 59509, 39251, 1249, 35803, 54469, 27689, 9719, 34897, 18973, 30661, 19913, 27919, 32143}; 1157 + 1158 + inline uint16_t find_next_power_of_2(uint16_t n){ 1159 + uint16_t x = 2; 1160 + while(x < n) x <<= 1; 1161 + return x; 1162 + } 1163 + 1164 + #define _hash(key, mask, hash_seed) ( ( (key).index * (hash_seed) >> 8 ) & (mask) ) 1165 + 1166 + inline uint16_t find_perfect_hash_seed(uint16_t capacity, const std::vector<StrName>& keys){ 1167 + if(keys.empty()) return kHashSeeds[0]; 1168 + static std::set<uint16_t> indices; 1169 + indices.clear(); 1170 + std::pair<uint16_t, float> best_score = {kHashSeeds[0], 0.0f}; 1171 + for(int i=0; i<kHashSeeds.size(); i++){ 1172 + indices.clear(); 1173 + for(auto key: keys){ 1174 + uint16_t index = _hash(key, capacity-1, kHashSeeds[i]); 1175 + indices.insert(index); 1176 + } 1177 + float score = indices.size() / (float)keys.size(); 1178 + if(score > best_score.second) best_score = {kHashSeeds[i], score}; 1179 + } 1180 + return best_score.first; 1181 + } 1182 + 1183 + template<typename T> 1184 + struct NameDictImpl { 1185 + using Item = std::pair<StrName, T>; 1186 + static constexpr uint16_t __Capacity = 8; 1187 + // ensure the initial capacity is ok for memory pool 1188 + static_assert(std::is_pod_v<T>); 1189 + static_assert(sizeof(Item) * __Capacity <= 128); 1190 + 1191 + float _load_factor; 1192 + uint16_t _capacity; 1193 + uint16_t _size; 1194 + uint16_t _hash_seed; 1195 + uint16_t _mask; 1196 + Item* _items; 1197 + 1198 + void _alloc(int cap){ 1199 + _items = (Item*)pool128.alloc(cap * sizeof(Item)); 1200 + memset(_items, 0, cap * sizeof(Item)); 1201 + } 1202 + 1203 + NameDictImpl(float load_factor=0.67, uint16_t capacity=__Capacity, uint16_t hash_seed=kHashSeeds[0]): 1204 + _load_factor(load_factor), _capacity(capacity), _size(0), 1205 + _hash_seed(hash_seed), _mask(capacity-1) { 1206 + _alloc(capacity); 1207 + } 1208 + 1209 + NameDictImpl(const NameDictImpl& other) { 1210 + memcpy(this, &other, sizeof(NameDictImpl)); 1211 + _alloc(_capacity); 1212 + for(int i=0; i<_capacity; i++){ 1213 + _items[i] = other._items[i]; 1214 + } 1215 + } 1216 + 1217 + NameDictImpl& operator=(const NameDictImpl& other) { 1218 + pool128.dealloc(_items); 1219 + memcpy(this, &other, sizeof(NameDictImpl)); 1220 + _alloc(_capacity); 1221 + for(int i=0; i<_capacity; i++){ 1222 + _items[i] = other._items[i]; 1223 + } 1224 + return *this; 1225 + } 1226 + 1227 + ~NameDictImpl(){ pool128.dealloc(_items); } 1228 + 1229 + NameDictImpl(NameDictImpl&&) = delete; 1230 + NameDictImpl& operator=(NameDictImpl&&) = delete; 1231 + uint16_t size() const { return _size; } 1232 + 1233 + #define HASH_PROBE(key, ok, i) \ 1234 + ok = false; \ 1235 + i = _hash(key, _mask, _hash_seed); \ 1236 + while(!_items[i].first.empty()) { \ 1237 + if(_items[i].first == (key)) { ok = true; break; } \ 1238 + i = (i + 1) & _mask; \ 1239 + } 1240 + 1241 + T operator[](StrName key) const { 1242 + bool ok; uint16_t i; 1243 + HASH_PROBE(key, ok, i); 1244 + if(!ok) throw std::out_of_range(fmt("NameDict key not found: ", key)); 1245 + return _items[i].second; 1246 + } 1247 + 1248 + void set(StrName key, T val){ 1249 + bool ok; uint16_t i; 1250 + HASH_PROBE(key, ok, i); 1251 + if(!ok) { 1252 + _size++; 1253 + if(_size > _capacity*_load_factor){ 1254 + _rehash(true); 1255 + HASH_PROBE(key, ok, i); 1256 + } 1257 + _items[i].first = key; 1258 + } 1259 + _items[i].second = val; 1260 + } 1261 + 1262 + void _rehash(bool resize){ 1263 + Item* old_items = _items; 1264 + uint16_t old_capacity = _capacity; 1265 + if(resize){ 1266 + _capacity = find_next_power_of_2(_capacity * 2); 1267 + _mask = _capacity - 1; 1268 + } 1269 + _alloc(_capacity); 1270 + for(uint16_t i=0; i<old_capacity; i++){ 1271 + if(old_items[i].first.empty()) continue; 1272 + bool ok; uint16_t j; 1273 + HASH_PROBE(old_items[i].first, ok, j); 1274 + if(ok) FATAL_ERROR(); 1275 + _items[j] = old_items[i]; 1276 + } 1277 + pool128.dealloc(old_items); 1278 + } 1279 + 1280 + void _try_perfect_rehash(){ 1281 + _hash_seed = find_perfect_hash_seed(_capacity, keys()); 1282 + _rehash(false); // do not resize 1283 + } 1284 + 1285 + T try_get(StrName key) const{ 1286 + bool ok; uint16_t i; 1287 + HASH_PROBE(key, ok, i); 1288 + if(!ok){ 1289 + if constexpr(std::is_pointer_v<T>) return nullptr; 1290 + else if constexpr(std::is_same_v<int, T>) return -1; 1291 + else return Discarded(); 1292 + } 1293 + return _items[i].second; 1294 + } 1295 + 1296 + bool try_set(StrName key, T val){ 1297 + bool ok; uint16_t i; 1298 + HASH_PROBE(key, ok, i); 1299 + if(!ok) return false; 1300 + _items[i].second = val; 1301 + return true; 1302 + } 1303 + 1304 + bool contains(StrName key) const { 1305 + bool ok; uint16_t i; 1306 + HASH_PROBE(key, ok, i); 1307 + return ok; 1308 + } 1309 + 1310 + void update(const NameDictImpl& other){ 1311 + for(uint16_t i=0; i<other._capacity; i++){ 1312 + auto& item = other._items[i]; 1313 + if(!item.first.empty()) set(item.first, item.second); 1314 + } 1315 + } 1316 + 1317 + void erase(StrName key){ 1318 + bool ok; uint16_t i; 1319 + HASH_PROBE(key, ok, i); 1320 + if(!ok) throw std::out_of_range(fmt("NameDict key not found: ", key)); 1321 + _items[i].first = StrName(); 1322 + _items[i].second = nullptr; 1323 + _size--; 1324 + } 1325 + 1326 + std::vector<Item> items() const { 1327 + std::vector<Item> v; 1328 + for(uint16_t i=0; i<_capacity; i++){ 1329 + if(_items[i].first.empty()) continue; 1330 + v.push_back(_items[i]); 1331 + } 1332 + return v; 1333 + } 1334 + 1335 + std::vector<StrName> keys() const { 1336 + std::vector<StrName> v; 1337 + for(uint16_t i=0; i<_capacity; i++){ 1338 + if(_items[i].first.empty()) continue; 1339 + v.push_back(_items[i].first); 1340 + } 1341 + return v; 1342 + } 1343 + 1344 + void clear(){ 1345 + for(uint16_t i=0; i<_capacity; i++){ 1346 + _items[i].first = StrName(); 1347 + _items[i].second = nullptr; 1348 + } 1349 + _size = 0; 1350 + } 1351 + #undef HASH_PROBE 1352 + #undef _hash 1353 + }; 1354 + 1355 + using NameDict = NameDictImpl<PyObject*>; 1356 + using NameDict_ = shared_ptr<NameDict>; 1357 + using NameDictInt = NameDictImpl<int>; 1358 + 1359 + } // namespace pkpy 1360 + 1361 + 1362 + namespace pkpy{ 1363 + 1364 + struct NeedMoreLines { 1365 + NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {} 1366 + bool is_compiling_class; 1367 + }; 1368 + 1369 + struct HandledException {}; 1370 + struct UnhandledException {}; 1371 + struct ToBeRaisedException {}; 1372 + 1373 + enum CompileMode { 1374 + EXEC_MODE, 1375 + EVAL_MODE, 1376 + REPL_MODE, 1377 + JSON_MODE, 1378 + }; 1379 + 1380 + struct SourceData { 1381 + std::string source; 1382 + Str filename; 1383 + std::vector<const char*> line_starts; 1384 + CompileMode mode; 1385 + 1386 + std::pair<const char*,const char*> get_line(int lineno) const { 1387 + if(lineno == -1) return {nullptr, nullptr}; 1388 + lineno -= 1; 1389 + if(lineno < 0) lineno = 0; 1390 + const char* _start = line_starts.at(lineno); 1391 + const char* i = _start; 1392 + while(*i != '\n' && *i != '\0') i++; 1393 + return {_start, i}; 1394 + } 1395 + 1396 + SourceData(const Str& source, const Str& filename, CompileMode mode) { 1397 + int index = 0; 1398 + // Skip utf8 BOM if there is any. 1399 + if (strncmp(source.begin(), "\xEF\xBB\xBF", 3) == 0) index += 3; 1400 + // Remove all '\r' 1401 + std::stringstream ss; 1402 + while(index < source.length()){ 1403 + if(source[index] != '\r') ss << source[index]; 1404 + index++; 1405 + } 1406 + 1407 + this->filename = filename; 1408 + this->source = ss.str(); 1409 + line_starts.push_back(this->source.c_str()); 1410 + this->mode = mode; 1411 + } 1412 + 1413 + Str snapshot(int lineno, const char* cursor=nullptr){ 1414 + std::stringstream ss; 1415 + ss << " " << "File \"" << filename << "\", line " << lineno << '\n'; 1416 + std::pair<const char*,const char*> pair = get_line(lineno); 1417 + Str line = "<?>"; 1418 + int removed_spaces = 0; 1419 + if(pair.first && pair.second){ 1420 + line = Str(pair.first, pair.second-pair.first).lstrip(); 1421 + removed_spaces = pair.second - pair.first - line.length(); 1422 + if(line.empty()) line = "<?>"; 1423 + } 1424 + ss << " " << line; 1425 + if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second){ 1426 + auto column = cursor - pair.first - removed_spaces; 1427 + if(column >= 0) ss << "\n " << std::string(column, ' ') << "^"; 1428 + } 1429 + return ss.str(); 1430 + } 1431 + }; 1432 + 1433 + class Exception { 1434 + using StackTrace = stack<Str>; 1435 + StrName type; 1436 + Str msg; 1437 + StackTrace stacktrace; 1438 + public: 1439 + Exception(StrName type, Str msg): type(type), msg(msg) {} 1440 + bool match_type(StrName type) const { return this->type == type;} 1441 + bool is_re = true; 1442 + 1443 + void st_push(Str snapshot){ 1444 + if(stacktrace.size() >= 8) return; 1445 + stacktrace.push(snapshot); 1446 + } 1447 + 1448 + Str summary() const { 1449 + StackTrace st(stacktrace); 1450 + std::stringstream ss; 1451 + if(is_re) ss << "Traceback (most recent call last):\n"; 1452 + while(!st.empty()) { ss << st.top() << '\n'; st.pop(); } 1453 + if (!msg.empty()) ss << type.sv() << ": " << msg; 1454 + else ss << type.sv(); 1455 + return ss.str(); 1456 + } 1457 + }; 1458 + 1459 + } // namespace pkpy 1460 + 1461 + 1462 + namespace pkpy{ 1463 + 1464 + typedef uint8_t TokenIndex; 1465 + 1466 + constexpr const char* kTokens[] = { 1467 + "is not", "not in", "yield from", 1468 + "@eof", "@eol", "@sof", 1469 + "@id", "@num", "@str", "@fstr", 1470 + "@indent", "@dedent", 1471 + /*****************************************/ 1472 + "+", "+=", "-", "-=", // (INPLACE_OP - 1) can get '=' removed 1473 + "*", "*=", "/", "/=", "//", "//=", "%", "%=", 1474 + "&", "&=", "|", "|=", "^", "^=", 1475 + "<<", "<<=", ">>", ">>=", 1476 + /*****************************************/ 1477 + ".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}", 1478 + "**", "=", ">", "<", "...", "->", "?", "@", "==", "!=", ">=", "<=", 1479 + /** SPEC_BEGIN **/ 1480 + "$goto", "$label", 1481 + /** KW_BEGIN **/ 1482 + "class", "import", "as", "def", "lambda", "pass", "del", "from", "with", "yield", 1483 + "None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally", 1484 + "while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise" 1485 + }; 1486 + 1487 + using TokenValue = std::variant<std::monostate, i64, f64, Str>; 1488 + const TokenIndex kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]); 1489 + 1490 + constexpr TokenIndex TK(const char token[]) { 1491 + for(int k=0; k<kTokenCount; k++){ 1492 + const char* i = kTokens[k]; 1493 + const char* j = token; 1494 + while(*i && *j && *i == *j) { i++; j++;} 1495 + if(*i == *j) return k; 1496 + } 1497 + return 255; 1498 + } 1499 + 1500 + #define TK_STR(t) kTokens[t] 1501 + const std::map<std::string_view, TokenIndex> kTokenKwMap = [](){ 1502 + std::map<std::string_view, TokenIndex> map; 1503 + for(int k=TK("class"); k<kTokenCount; k++) map[kTokens[k]] = k; 1504 + return map; 1505 + }(); 1506 + 1507 + 1508 + struct Token{ 1509 + TokenIndex type; 1510 + const char* start; 1511 + int length; 1512 + int line; 1513 + TokenValue value; 1514 + 1515 + Str str() const { return Str(start, length);} 1516 + std::string_view sv() const { return std::string_view(start, length);} 1517 + 1518 + std::string info() const { 1519 + std::stringstream ss; 1520 + ss << line << ": " << TK_STR(type) << " '" << ( 1521 + sv()=="\n" ? "\\n" : sv() 1522 + ) << "'"; 1523 + return ss.str(); 1524 + } 1525 + }; 1526 + 1527 + // https://docs.python.org/3/reference/expressions.html#operator-precedence 1528 + enum Precedence { 1529 + PREC_NONE, 1530 + PREC_TUPLE, // , 1531 + PREC_LAMBDA, // lambda 1532 + PREC_TERNARY, // ?: 1533 + PREC_LOGICAL_OR, // or 1534 + PREC_LOGICAL_AND, // and 1535 + PREC_LOGICAL_NOT, // not 1536 + PREC_EQUALITY, // == != 1537 + PREC_TEST, // in / is / is not / not in 1538 + PREC_COMPARISION, // < > <= >= 1539 + PREC_BITWISE_OR, // | 1540 + PREC_BITWISE_XOR, // ^ 1541 + PREC_BITWISE_AND, // & 1542 + PREC_BITWISE_SHIFT, // << >> 1543 + PREC_TERM, // + - 1544 + PREC_FACTOR, // * / % // 1545 + PREC_UNARY, // - not 1546 + PREC_EXPONENT, // ** 1547 + PREC_CALL, // () 1548 + PREC_SUBSCRIPT, // [] 1549 + PREC_ATTRIB, // .index 1550 + PREC_PRIMARY, 1551 + }; 1552 + 1553 + enum StringType { NORMAL_STRING, RAW_STRING, F_STRING }; 1554 + 1555 + struct Lexer { 1556 + shared_ptr<SourceData> src; 1557 + const char* token_start; 1558 + const char* curr_char; 1559 + int current_line = 1; 1560 + std::vector<Token> nexts; 1561 + stack<int> indents; 1562 + int brackets_level = 0; 1563 + bool used = false; 1564 + 1565 + char peekchar() const{ return *curr_char; } 1566 + 1567 + bool match_n_chars(int n, char c0){ 1568 + const char* c = curr_char; 1569 + for(int i=0; i<n; i++){ 1570 + if(*c == '\0') return false; 1571 + if(*c != c0) return false; 1572 + c++; 1573 + } 1574 + for(int i=0; i<n; i++) eatchar_include_newline(); 1575 + return true; 1576 + } 1577 + 1578 + bool match_string(const char* s){ 1579 + int s_len = strlen(s); 1580 + bool ok = strncmp(curr_char, s, s_len) == 0; 1581 + if(ok) for(int i=0; i<s_len; i++) eatchar_include_newline(); 1582 + return ok; 1583 + } 1584 + 1585 + int eat_spaces(){ 1586 + int count = 0; 1587 + while (true) { 1588 + switch (peekchar()) { 1589 + case ' ' : count+=1; break; 1590 + case '\t': count+=4; break; 1591 + default: return count; 1592 + } 1593 + eatchar(); 1594 + } 1595 + } 1596 + 1597 + bool eat_indentation(){ 1598 + if(brackets_level > 0) return true; 1599 + int spaces = eat_spaces(); 1600 + if(peekchar() == '#') skip_line_comment(); 1601 + if(peekchar() == '\0' || peekchar() == '\n') return true; 1602 + // https://docs.python.org/3/reference/lexical_analysis.html#indentation 1603 + if(spaces > indents.top()){ 1604 + indents.push(spaces); 1605 + nexts.push_back(Token{TK("@indent"), token_start, 0, current_line}); 1606 + } else if(spaces < indents.top()){ 1607 + while(spaces < indents.top()){ 1608 + indents.pop(); 1609 + nexts.push_back(Token{TK("@dedent"), token_start, 0, current_line}); 1610 + } 1611 + if(spaces != indents.top()){ 1612 + return false; 1613 + } 1614 + } 1615 + return true; 1616 + } 1617 + 1618 + char eatchar() { 1619 + char c = peekchar(); 1620 + if(c == '\n') throw std::runtime_error("eatchar() cannot consume a newline"); 1621 + curr_char++; 1622 + return c; 1623 + } 1624 + 1625 + char eatchar_include_newline() { 1626 + char c = peekchar(); 1627 + curr_char++; 1628 + if (c == '\n'){ 1629 + current_line++; 1630 + src->line_starts.push_back(curr_char); 1631 + } 1632 + return c; 1633 + } 1634 + 1635 + int eat_name() { 1636 + curr_char--; 1637 + while(true){ 1638 + unsigned char c = peekchar(); 1639 + int u8bytes = utf8len(c, true); 1640 + if(u8bytes == 0) return 1; 1641 + if(u8bytes == 1){ 1642 + if(isalpha(c) || c=='_' || isdigit(c)) { 1643 + curr_char++; 1644 + continue; 1645 + }else{ 1646 + break; 1647 + } 1648 + } 1649 + // handle multibyte char 1650 + std::string u8str(curr_char, u8bytes); 1651 + if(u8str.size() != u8bytes) return 2; 1652 + uint32_t value = 0; 1653 + for(int k=0; k < u8bytes; k++){ 1654 + uint8_t b = u8str[k]; 1655 + if(k==0){ 1656 + if(u8bytes == 2) value = (b & 0b00011111) << 6; 1657 + else if(u8bytes == 3) value = (b & 0b00001111) << 12; 1658 + else if(u8bytes == 4) value = (b & 0b00000111) << 18; 1659 + }else{ 1660 + value |= (b & 0b00111111) << (6*(u8bytes-k-1)); 1661 + } 1662 + } 1663 + if(is_unicode_Lo_char(value)) curr_char += u8bytes; 1664 + else break; 1665 + } 1666 + 1667 + int length = (int)(curr_char - token_start); 1668 + if(length == 0) return 3; 1669 + std::string_view name(token_start, length); 1670 + 1671 + if(src->mode == JSON_MODE){ 1672 + if(name == "true"){ 1673 + add_token(TK("True")); 1674 + } else if(name == "false"){ 1675 + add_token(TK("False")); 1676 + } else if(name == "null"){ 1677 + add_token(TK("None")); 1678 + } else { 1679 + return 4; 1680 + } 1681 + return 0; 1682 + } 1683 + 1684 + if(kTokenKwMap.count(name)){ 1685 + if(name == "not"){ 1686 + if(strncmp(curr_char, " in", 3) == 0){ 1687 + curr_char += 3; 1688 + add_token(TK("not in")); 1689 + return 0; 1690 + } 1691 + }else if(name == "is"){ 1692 + if(strncmp(curr_char, " not", 4) == 0){ 1693 + curr_char += 4; 1694 + add_token(TK("is not")); 1695 + return 0; 1696 + } 1697 + }else if(name == "yield"){ 1698 + if(strncmp(curr_char, " from", 5) == 0){ 1699 + curr_char += 5; 1700 + add_token(TK("yield from")); 1701 + return 0; 1702 + } 1703 + } 1704 + add_token(kTokenKwMap.at(name)); 1705 + } else { 1706 + add_token(TK("@id")); 1707 + } 1708 + return 0; 1709 + } 1710 + 1711 + void skip_line_comment() { 1712 + char c; 1713 + while ((c = peekchar()) != '\0') { 1714 + if (c == '\n') return; 1715 + eatchar(); 1716 + } 1717 + } 1718 + 1719 + bool matchchar(char c) { 1720 + if (peekchar() != c) return false; 1721 + eatchar_include_newline(); 1722 + return true; 1723 + } 1724 + 1725 + void add_token(TokenIndex type, TokenValue value={}) { 1726 + switch(type){ 1727 + case TK("{"): case TK("["): case TK("("): brackets_level++; break; 1728 + case TK(")"): case TK("]"): case TK("}"): brackets_level--; break; 1729 + } 1730 + nexts.push_back( Token{ 1731 + type, 1732 + token_start, 1733 + (int)(curr_char - token_start), 1734 + current_line - ((type == TK("@eol")) ? 1 : 0), 1735 + value 1736 + }); 1737 + } 1738 + 1739 + void add_token_2(char c, TokenIndex one, TokenIndex two) { 1740 + if (matchchar(c)) add_token(two); 1741 + else add_token(one); 1742 + } 1743 + 1744 + Str eat_string_until(char quote, bool raw) { 1745 + bool quote3 = match_n_chars(2, quote); 1746 + std::vector<char> buff; 1747 + while (true) { 1748 + char c = eatchar_include_newline(); 1749 + if (c == quote){ 1750 + if(quote3 && !match_n_chars(2, quote)){ 1751 + buff.push_back(c); 1752 + continue; 1753 + } 1754 + break; 1755 + } 1756 + if (c == '\0'){ 1757 + if(quote3 && src->mode == REPL_MODE){ 1758 + throw NeedMoreLines(false); 1759 + } 1760 + SyntaxError("EOL while scanning string literal"); 1761 + } 1762 + if (c == '\n'){ 1763 + if(!quote3) SyntaxError("EOL while scanning string literal"); 1764 + else{ 1765 + buff.push_back(c); 1766 + continue; 1767 + } 1768 + } 1769 + if (!raw && c == '\\') { 1770 + switch (eatchar_include_newline()) { 1771 + case '"': buff.push_back('"'); break; 1772 + case '\'': buff.push_back('\''); break; 1773 + case '\\': buff.push_back('\\'); break; 1774 + case 'n': buff.push_back('\n'); break; 1775 + case 'r': buff.push_back('\r'); break; 1776 + case 't': buff.push_back('\t'); break; 1777 + default: SyntaxError("invalid escape char"); 1778 + } 1779 + } else { 1780 + buff.push_back(c); 1781 + } 1782 + } 1783 + return Str(buff.data(), buff.size()); 1784 + } 1785 + 1786 + void eat_string(char quote, StringType type) { 1787 + Str s = eat_string_until(quote, type == RAW_STRING); 1788 + if(type == F_STRING){ 1789 + add_token(TK("@fstr"), s); 1790 + }else{ 1791 + add_token(TK("@str"), s); 1792 + } 1793 + } 1794 + 1795 + void eat_number() { 1796 + static const std::regex pattern("^(0x)?[0-9a-fA-F]+(\\.[0-9]+)?"); 1797 + std::smatch m; 1798 + 1799 + const char* i = token_start; 1800 + while(*i != '\n' && *i != '\0') i++; 1801 + std::string s = std::string(token_start, i); 1802 + 1803 + try{ 1804 + if (std::regex_search(s, m, pattern)) { 1805 + // here is m.length()-1, since the first char was eaten by lex_token() 1806 + for(int j=0; j<m.length()-1; j++) eatchar(); 1807 + 1808 + int base = 10; 1809 + size_t size; 1810 + if (m[1].matched) base = 16; 1811 + if (m[2].matched) { 1812 + if(base == 16) SyntaxError("hex literal should not contain a dot"); 1813 + add_token(TK("@num"), Number::stof(m[0], &size)); 1814 + } else { 1815 + add_token(TK("@num"), Number::stoi(m[0], &size, base)); 1816 + } 1817 + if (size != m.length()) FATAL_ERROR(); 1818 + } 1819 + }catch(std::exception& _){ 1820 + SyntaxError("invalid number literal"); 1821 + } 1822 + } 1823 + 1824 + bool lex_one_token() { 1825 + while (peekchar() != '\0') { 1826 + token_start = curr_char; 1827 + char c = eatchar_include_newline(); 1828 + switch (c) { 1829 + case '\'': case '"': eat_string(c, NORMAL_STRING); return true; 1830 + case '#': skip_line_comment(); break; 1831 + case '{': add_token(TK("{")); return true; 1832 + case '}': add_token(TK("}")); return true; 1833 + case ',': add_token(TK(",")); return true; 1834 + case ':': add_token(TK(":")); return true; 1835 + case ';': add_token(TK(";")); return true; 1836 + case '(': add_token(TK("(")); return true; 1837 + case ')': add_token(TK(")")); return true; 1838 + case '[': add_token(TK("[")); return true; 1839 + case ']': add_token(TK("]")); return true; 1840 + case '@': add_token(TK("@")); return true; 1841 + case '$': { 1842 + for(int i=TK("$goto"); i<=TK("$label"); i++){ 1843 + // +1 to skip the '$' 1844 + if(match_string(TK_STR(i) + 1)){ 1845 + add_token((TokenIndex)i); 1846 + return true; 1847 + } 1848 + } 1849 + SyntaxError("invalid special token"); 1850 + } 1851 + case '%': add_token_2('=', TK("%"), TK("%=")); return true; 1852 + case '&': add_token_2('=', TK("&"), TK("&=")); return true; 1853 + case '|': add_token_2('=', TK("|"), TK("|=")); return true; 1854 + case '^': add_token_2('=', TK("^"), TK("^=")); return true; 1855 + case '?': add_token(TK("?")); return true; 1856 + case '.': { 1857 + if(matchchar('.')) { 1858 + if(matchchar('.')) { 1859 + add_token(TK("...")); 1860 + } else { 1861 + SyntaxError("invalid token '..'"); 1862 + } 1863 + } else { 1864 + add_token(TK(".")); 1865 + } 1866 + return true; 1867 + } 1868 + case '=': add_token_2('=', TK("="), TK("==")); return true; 1869 + case '+': add_token_2('=', TK("+"), TK("+=")); return true; 1870 + case '>': { 1871 + if(matchchar('=')) add_token(TK(">=")); 1872 + else if(matchchar('>')) add_token_2('=', TK(">>"), TK(">>=")); 1873 + else add_token(TK(">")); 1874 + return true; 1875 + } 1876 + case '<': { 1877 + if(matchchar('=')) add_token(TK("<=")); 1878 + else if(matchchar('<')) add_token_2('=', TK("<<"), TK("<<=")); 1879 + else add_token(TK("<")); 1880 + return true; 1881 + } 1882 + case '-': { 1883 + if(matchchar('=')) add_token(TK("-=")); 1884 + else if(matchchar('>')) add_token(TK("->")); 1885 + else add_token(TK("-")); 1886 + return true; 1887 + } 1888 + case '!': 1889 + if(matchchar('=')) add_token(TK("!=")); 1890 + else SyntaxError("expected '=' after '!'"); 1891 + break; 1892 + case '*': 1893 + if (matchchar('*')) { 1894 + add_token(TK("**")); // '**' 1895 + } else { 1896 + add_token_2('=', TK("*"), TK("*=")); 1897 + } 1898 + return true; 1899 + case '/': 1900 + if(matchchar('/')) { 1901 + add_token_2('=', TK("//"), TK("//=")); 1902 + } else { 1903 + add_token_2('=', TK("/"), TK("/=")); 1904 + } 1905 + return true; 1906 + case ' ': case '\t': eat_spaces(); break; 1907 + case '\n': { 1908 + add_token(TK("@eol")); 1909 + if(!eat_indentation()) IndentationError("unindent does not match any outer indentation level"); 1910 + return true; 1911 + } 1912 + default: { 1913 + if(c == 'f'){ 1914 + if(matchchar('\'')) {eat_string('\'', F_STRING); return true;} 1915 + if(matchchar('"')) {eat_string('"', F_STRING); return true;} 1916 + }else if(c == 'r'){ 1917 + if(matchchar('\'')) {eat_string('\'', RAW_STRING); return true;} 1918 + if(matchchar('"')) {eat_string('"', RAW_STRING); return true;} 1919 + } 1920 + if (c >= '0' && c <= '9') { 1921 + eat_number(); 1922 + return true; 1923 + } 1924 + switch (eat_name()) 1925 + { 1926 + case 0: break; 1927 + case 1: SyntaxError("invalid char: " + std::string(1, c)); 1928 + case 2: SyntaxError("invalid utf8 sequence: " + std::string(1, c)); 1929 + case 3: SyntaxError("@id contains invalid char"); break; 1930 + case 4: SyntaxError("invalid JSON token"); break; 1931 + default: FATAL_ERROR(); 1932 + } 1933 + return true; 1934 + } 1935 + } 1936 + } 1937 + 1938 + token_start = curr_char; 1939 + while(indents.size() > 1){ 1940 + indents.pop(); 1941 + add_token(TK("@dedent")); 1942 + return true; 1943 + } 1944 + add_token(TK("@eof")); 1945 + return false; 1946 + } 1947 + 1948 + /***** Error Reporter *****/ 1949 + void throw_err(Str type, Str msg){ 1950 + int lineno = current_line; 1951 + const char* cursor = curr_char; 1952 + if(peekchar() == '\n'){ 1953 + lineno--; 1954 + cursor--; 1955 + } 1956 + throw_err(type, msg, lineno, cursor); 1957 + } 1958 + 1959 + void throw_err(Str type, Str msg, int lineno, const char* cursor){ 1960 + auto e = Exception("SyntaxError", msg); 1961 + e.st_push(src->snapshot(lineno, cursor)); 1962 + throw e; 1963 + } 1964 + void SyntaxError(Str msg){ throw_err("SyntaxError", msg); } 1965 + void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); } 1966 + void IndentationError(Str msg){ throw_err("IndentationError", msg); } 1967 + 1968 + Lexer(shared_ptr<SourceData> src) { 1969 + this->src = src; 1970 + this->token_start = src->source.c_str(); 1971 + this->curr_char = src->source.c_str(); 1972 + this->nexts.push_back(Token{TK("@sof"), token_start, 0, current_line}); 1973 + this->indents.push(0); 1974 + } 1975 + 1976 + std::vector<Token> run() { 1977 + if(used) FATAL_ERROR(); 1978 + used = true; 1979 + while (lex_one_token()); 1980 + return std::move(nexts); 1981 + } 1982 + }; 1983 + 1984 + } // namespace pkpy 1985 + 1986 + 1987 + 1988 + namespace pkpy { 1989 + 1990 + struct CodeObject; 1991 + struct Frame; 1992 + struct Function; 1993 + class VM; 1994 + 1995 + typedef PyObject* (*NativeFuncC)(VM*, ArgsView); 1996 + typedef int (*LuaStyleFuncC)(VM*); 1997 + 1998 + struct NativeFunc { 1999 + NativeFuncC f; 2000 + int argc; // DONOT include self 2001 + bool method; 2002 + 2003 + // this is designed for lua style C bindings 2004 + // access it via `CAST(NativeFunc&, args[-2])._lua_f` 2005 + LuaStyleFuncC _lua_f; 2006 + 2007 + NativeFunc(NativeFuncC f, int argc, bool method) : f(f), argc(argc), method(method), _lua_f(nullptr) {} 2008 + PyObject* operator()(VM* vm, ArgsView args) const; 2009 + }; 2010 + 2011 + typedef shared_ptr<CodeObject> CodeObject_; 2012 + 2013 + struct FuncDecl { 2014 + struct KwArg { 2015 + int key; // index in co->varnames 2016 + PyObject* value; // default value 2017 + }; 2018 + CodeObject_ code; // code object of this function 2019 + pod_vector<int> args; // indices in co->varnames 2020 + int starred_arg = -1; // index in co->varnames, -1 if no *arg 2021 + pod_vector<KwArg> kwargs; // indices in co->varnames 2022 + bool nested = false; // whether this function is nested 2023 + void _gc_mark() const; 2024 + }; 2025 + 2026 + using FuncDecl_ = shared_ptr<FuncDecl>; 2027 + 2028 + struct Function{ 2029 + FuncDecl_ decl; 2030 + bool is_simple; 2031 + int argc; // cached argc 2032 + PyObject* _module; 2033 + NameDict_ _closure; 2034 + }; 2035 + 2036 + struct BoundMethod { 2037 + PyObject* self; 2038 + PyObject* func; 2039 + BoundMethod(PyObject* self, PyObject* func) : self(self), func(func) {} 2040 + 2041 + bool operator==(const BoundMethod& rhs) const noexcept { 2042 + return self == rhs.self && func == rhs.func; 2043 + } 2044 + bool operator!=(const BoundMethod& rhs) const noexcept { 2045 + return self != rhs.self || func != rhs.func; 2046 + } 2047 + }; 2048 + 2049 + struct Range { 2050 + i64 start = 0; 2051 + i64 stop = -1; 2052 + i64 step = 1; 2053 + }; 2054 + 2055 + struct Bytes{ 2056 + std::vector<char> _data; 2057 + bool _ok; 2058 + 2059 + int size() const noexcept { return _data.size(); } 2060 + int operator[](int i) const noexcept { return (int)(uint8_t)_data[i]; } 2061 + const char* data() const noexcept { return _data.data(); } 2062 + 2063 + bool operator==(const Bytes& rhs) const noexcept { 2064 + return _data == rhs._data; 2065 + } 2066 + bool operator!=(const Bytes& rhs) const noexcept { 2067 + return _data != rhs._data; 2068 + } 2069 + 2070 + std::string str() const noexcept { return std::string(_data.begin(), _data.end()); } 2071 + 2072 + Bytes() : _data(), _ok(false) {} 2073 + Bytes(std::vector<char>&& data) : _data(std::move(data)), _ok(true) {} 2074 + Bytes(const std::string& data) : _data(data.begin(), data.end()), _ok(true) {} 2075 + operator bool() const noexcept { return _ok; } 2076 + }; 2077 + 2078 + using Super = std::pair<PyObject*, Type>; 2079 + 2080 + struct Slice { 2081 + PyObject* start; 2082 + PyObject* stop; 2083 + PyObject* step; 2084 + Slice(PyObject* start, PyObject* stop, PyObject* step) : start(start), stop(stop), step(step) {} 2085 + }; 2086 + 2087 + class BaseIter { 2088 + protected: 2089 + VM* vm; 2090 + public: 2091 + BaseIter(VM* vm) : vm(vm) {} 2092 + virtual PyObject* next() = 0; 2093 + virtual ~BaseIter() = default; 2094 + }; 2095 + 2096 + struct GCHeader { 2097 + bool enabled; // whether this object is managed by GC 2098 + bool marked; // whether this object is marked 2099 + GCHeader() : enabled(true), marked(false) {} 2100 + }; 2101 + 2102 + struct PyObject{ 2103 + GCHeader gc; 2104 + Type type; 2105 + NameDict* _attr; 2106 + 2107 + bool is_attr_valid() const noexcept { return _attr != nullptr; } 2108 + NameDict& attr() noexcept { return *_attr; } 2109 + PyObject* attr(StrName name) const noexcept { return (*_attr)[name]; } 2110 + virtual void* value() = 0; 2111 + virtual void _obj_gc_mark() = 0; 2112 + 2113 + PyObject(Type type) : type(type), _attr(nullptr) {} 2114 + 2115 + virtual ~PyObject() { 2116 + if(_attr == nullptr) return; 2117 + _attr->~NameDict(); 2118 + pool64.dealloc(_attr); 2119 + } 2120 + 2121 + void enable_instance_dict(float lf=kInstAttrLoadFactor) noexcept { 2122 + _attr = new(pool64.alloc<NameDict>()) NameDict(lf); 2123 + } 2124 + }; 2125 + 2126 + template <typename, typename=void> struct has_gc_marker : std::false_type {}; 2127 + template <typename T> struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {}; 2128 + 2129 + template <typename T> 2130 + struct Py_ final: PyObject { 2131 + T _value; 2132 + void* value() override { return &_value; } 2133 + void _obj_gc_mark() override { 2134 + if constexpr (has_gc_marker<T>::value) { 2135 + _value._gc_mark(); 2136 + } 2137 + } 2138 + Py_(Type type, const T& value) : PyObject(type), _value(value) {} 2139 + Py_(Type type, T&& value) : PyObject(type), _value(std::move(value)) {} 2140 + }; 2141 + 2142 + struct MappingProxy{ 2143 + PyObject* obj; 2144 + MappingProxy(PyObject* obj) : obj(obj) {} 2145 + NameDict& attr() noexcept { return obj->attr(); } 2146 + }; 2147 + 2148 + #define OBJ_GET(T, obj) (((Py_<T>*)(obj))->_value) 2149 + // #define OBJ_GET(T, obj) (*reinterpret_cast<T*>((obj)->value())) 2150 + 2151 + #define OBJ_MARK(obj) \ 2152 + if(!is_tagged(obj) && !(obj)->gc.marked) { \ 2153 + (obj)->gc.marked = true; \ 2154 + (obj)->_obj_gc_mark(); \ 2155 + if((obj)->is_attr_valid()) gc_mark_namedict((obj)->attr()); \ 2156 + } 2157 + 2158 + inline void gc_mark_namedict(NameDict& t){ 2159 + if(t.size() == 0) return; 2160 + for(uint16_t i=0; i<t._capacity; i++){ 2161 + if(t._items[i].first.empty()) continue; 2162 + OBJ_MARK(t._items[i].second); 2163 + } 2164 + } 2165 + 2166 + Str obj_type_name(VM* vm, Type type); 2167 + 2168 + #if DEBUG_NO_BUILTIN_MODULES 2169 + #define OBJ_NAME(obj) Str("<?>") 2170 + #else 2171 + #define OBJ_NAME(obj) OBJ_GET(Str, vm->getattr(obj, __name__)) 2172 + #endif 2173 + 2174 + const int kTpIntIndex = 2; 2175 + const int kTpFloatIndex = 3; 2176 + 2177 + inline bool is_type(PyObject* obj, Type type) { 2178 + #if DEBUG_EXTRA_CHECK 2179 + if(obj == nullptr) throw std::runtime_error("is_type() called with nullptr"); 2180 + if(is_special(obj)) throw std::runtime_error("is_type() called with special object"); 2181 + #endif 2182 + switch(type.index){ 2183 + case kTpIntIndex: return is_int(obj); 2184 + case kTpFloatIndex: return is_float(obj); 2185 + default: return !is_tagged(obj) && obj->type == type; 2186 + } 2187 + } 2188 + 2189 + inline bool is_non_tagged_type(PyObject* obj, Type type) { 2190 + #if DEBUG_EXTRA_CHECK 2191 + if(obj == nullptr) throw std::runtime_error("is_non_tagged_type() called with nullptr"); 2192 + if(is_special(obj)) throw std::runtime_error("is_non_tagged_type() called with special object"); 2193 + #endif 2194 + return !is_tagged(obj) && obj->type == type; 2195 + } 2196 + 2197 + union BitsCvt { 2198 + i64 _int; 2199 + f64 _float; 2200 + BitsCvt(i64 val) : _int(val) {} 2201 + BitsCvt(f64 val) : _float(val) {} 2202 + }; 2203 + 2204 + template <typename, typename=void> struct is_py_class : std::false_type {}; 2205 + template <typename T> struct is_py_class<T, std::void_t<decltype(T::_type)>> : std::true_type {}; 2206 + 2207 + template<typename T> void _check_py_class(VM*, PyObject*); 2208 + template<typename T> T py_pointer_cast(VM*, PyObject*); 2209 + 2210 + template<typename __T> 2211 + __T py_cast(VM* vm, PyObject* obj) { 2212 + using T = std::decay_t<__T>; 2213 + if constexpr(std::is_pointer_v<T>){ 2214 + return py_pointer_cast<T>(vm, obj); 2215 + }else if constexpr(is_py_class<T>::value){ 2216 + _check_py_class<T>(vm, obj); 2217 + return OBJ_GET(T, obj); 2218 + }else { 2219 + return Discarded(); 2220 + } 2221 + } 2222 + 2223 + template<typename __T> 2224 + __T _py_cast(VM* vm, PyObject* obj) { 2225 + using T = std::decay_t<__T>; 2226 + if constexpr(std::is_pointer_v<__T>){ 2227 + return py_pointer_cast<__T>(vm, obj); 2228 + }else if constexpr(is_py_class<T>::value){ 2229 + return OBJ_GET(T, obj); 2230 + }else{ 2231 + return Discarded(); 2232 + } 2233 + } 2234 + 2235 + #define VAR(x) py_var(vm, x) 2236 + #define CAST(T, x) py_cast<T>(vm, x) 2237 + #define _CAST(T, x) _py_cast<T>(vm, x) 2238 + 2239 + /*****************************************************************/ 2240 + template<> 2241 + struct Py_<List> final: PyObject { 2242 + List _value; 2243 + void* value() override { return &_value; } 2244 + 2245 + Py_(Type type, List&& val): PyObject(type), _value(std::move(val)) {} 2246 + Py_(Type type, const List& val): PyObject(type), _value(val) {} 2247 + 2248 + void _obj_gc_mark() override { 2249 + for(PyObject* obj: _value) OBJ_MARK(obj); 2250 + } 2251 + }; 2252 + 2253 + template<> 2254 + struct Py_<Tuple> final: PyObject { 2255 + Tuple _value; 2256 + void* value() override { return &_value; } 2257 + 2258 + Py_(Type type, Tuple&& val): PyObject(type), _value(std::move(val)) {} 2259 + Py_(Type type, const Tuple& val): PyObject(type), _value(val) {} 2260 + 2261 + void _obj_gc_mark() override { 2262 + for(PyObject* obj: _value) OBJ_MARK(obj); 2263 + } 2264 + }; 2265 + 2266 + template<> 2267 + struct Py_<MappingProxy> final: PyObject { 2268 + MappingProxy _value; 2269 + void* value() override { return &_value; } 2270 + Py_(Type type, MappingProxy val): PyObject(type), _value(val) {} 2271 + void _obj_gc_mark() override { 2272 + OBJ_MARK(_value.obj); 2273 + } 2274 + }; 2275 + 2276 + template<> 2277 + struct Py_<BoundMethod> final: PyObject { 2278 + BoundMethod _value; 2279 + void* value() override { return &_value; } 2280 + Py_(Type type, BoundMethod val): PyObject(type), _value(val) {} 2281 + void _obj_gc_mark() override { 2282 + OBJ_MARK(_value.self); 2283 + OBJ_MARK(_value.func); 2284 + } 2285 + }; 2286 + 2287 + template<> 2288 + struct Py_<Slice> final: PyObject { 2289 + Slice _value; 2290 + void* value() override { return &_value; } 2291 + Py_(Type type, Slice val): PyObject(type), _value(val) {} 2292 + void _obj_gc_mark() override { 2293 + OBJ_MARK(_value.start); 2294 + OBJ_MARK(_value.stop); 2295 + OBJ_MARK(_value.step); 2296 + } 2297 + }; 2298 + 2299 + template<> 2300 + struct Py_<Function> final: PyObject { 2301 + Function _value; 2302 + void* value() override { return &_value; } 2303 + Py_(Type type, Function val): PyObject(type), _value(val) { 2304 + enable_instance_dict(); 2305 + } 2306 + void _obj_gc_mark() override { 2307 + _value.decl->_gc_mark(); 2308 + if(_value._module != nullptr) OBJ_MARK(_value._module); 2309 + if(_value._closure != nullptr) gc_mark_namedict(*_value._closure); 2310 + } 2311 + }; 2312 + 2313 + template<> 2314 + struct Py_<NativeFunc> final: PyObject { 2315 + NativeFunc _value; 2316 + void* value() override { return &_value; } 2317 + Py_(Type type, NativeFunc val): PyObject(type), _value(val) { 2318 + enable_instance_dict(); 2319 + } 2320 + void _obj_gc_mark() override {} 2321 + }; 2322 + 2323 + template<> 2324 + struct Py_<Super> final: PyObject { 2325 + Super _value; 2326 + void* value() override { return &_value; } 2327 + Py_(Type type, Super val): PyObject(type), _value(val) {} 2328 + void _obj_gc_mark() override { 2329 + OBJ_MARK(_value.first); 2330 + } 2331 + }; 2332 + 2333 + template<> 2334 + struct Py_<DummyInstance> final: PyObject { 2335 + void* value() override { return nullptr; } 2336 + Py_(Type type, DummyInstance val): PyObject(type) { 2337 + enable_instance_dict(); 2338 + } 2339 + void _obj_gc_mark() override {} 2340 + }; 2341 + 2342 + template<> 2343 + struct Py_<Type> final: PyObject { 2344 + Type _value; 2345 + void* value() override { return &_value; } 2346 + Py_(Type type, Type val): PyObject(type), _value(val) { 2347 + enable_instance_dict(kTypeAttrLoadFactor); 2348 + } 2349 + void _obj_gc_mark() override {} 2350 + }; 2351 + 2352 + template<> 2353 + struct Py_<DummyModule> final: PyObject { 2354 + void* value() override { return nullptr; } 2355 + Py_(Type type, DummyModule val): PyObject(type) { 2356 + enable_instance_dict(kTypeAttrLoadFactor); 2357 + } 2358 + void _obj_gc_mark() override {} 2359 + }; 2360 + 2361 + 2362 + } // namespace pkpy 2363 + 2364 + 2365 + namespace pkpy{ 2366 + 2367 + enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN }; 2368 + 2369 + enum Opcode { 2370 + #define OPCODE(name) OP_##name, 2371 + #ifdef OPCODE 2372 + 2373 + /**************************/ 2374 + OPCODE(NO_OP) 2375 + /**************************/ 2376 + OPCODE(POP_TOP) 2377 + OPCODE(DUP_TOP) 2378 + OPCODE(ROT_TWO) 2379 + OPCODE(PRINT_EXPR) 2380 + /**************************/ 2381 + OPCODE(LOAD_CONST) 2382 + OPCODE(LOAD_NONE) 2383 + OPCODE(LOAD_TRUE) 2384 + OPCODE(LOAD_FALSE) 2385 + OPCODE(LOAD_INTEGER) 2386 + OPCODE(LOAD_ELLIPSIS) 2387 + OPCODE(LOAD_FUNCTION) 2388 + OPCODE(LOAD_NULL) 2389 + /**************************/ 2390 + OPCODE(LOAD_FAST) 2391 + OPCODE(LOAD_NAME) 2392 + OPCODE(LOAD_NONLOCAL) 2393 + OPCODE(LOAD_GLOBAL) 2394 + OPCODE(LOAD_ATTR) 2395 + OPCODE(LOAD_METHOD) 2396 + OPCODE(LOAD_SUBSCR) 2397 + 2398 + OPCODE(STORE_FAST) 2399 + OPCODE(STORE_NAME) 2400 + OPCODE(STORE_GLOBAL) 2401 + OPCODE(STORE_ATTR) 2402 + OPCODE(STORE_SUBSCR) 2403 + 2404 + OPCODE(DELETE_FAST) 2405 + OPCODE(DELETE_NAME) 2406 + OPCODE(DELETE_GLOBAL) 2407 + OPCODE(DELETE_ATTR) 2408 + OPCODE(DELETE_SUBSCR) 2409 + /**************************/ 2410 + OPCODE(BUILD_LIST) 2411 + OPCODE(BUILD_DICT) 2412 + OPCODE(BUILD_SET) 2413 + OPCODE(BUILD_SLICE) 2414 + OPCODE(BUILD_TUPLE) 2415 + OPCODE(BUILD_STRING) 2416 + /**************************/ 2417 + OPCODE(BINARY_OP) 2418 + OPCODE(BINARY_ADD) 2419 + OPCODE(BINARY_SUB) 2420 + OPCODE(BINARY_MUL) 2421 + OPCODE(BINARY_FLOORDIV) 2422 + OPCODE(BINARY_MOD) 2423 + 2424 + OPCODE(COMPARE_LT) 2425 + OPCODE(COMPARE_LE) 2426 + OPCODE(COMPARE_EQ) 2427 + OPCODE(COMPARE_NE) 2428 + OPCODE(COMPARE_GT) 2429 + OPCODE(COMPARE_GE) 2430 + 2431 + OPCODE(BITWISE_LSHIFT) 2432 + OPCODE(BITWISE_RSHIFT) 2433 + OPCODE(BITWISE_AND) 2434 + OPCODE(BITWISE_OR) 2435 + OPCODE(BITWISE_XOR) 2436 + 2437 + OPCODE(IS_OP) 2438 + OPCODE(CONTAINS_OP) 2439 + /**************************/ 2440 + OPCODE(JUMP_ABSOLUTE) 2441 + OPCODE(POP_JUMP_IF_FALSE) 2442 + OPCODE(JUMP_IF_TRUE_OR_POP) 2443 + OPCODE(JUMP_IF_FALSE_OR_POP) 2444 + OPCODE(LOOP_CONTINUE) 2445 + OPCODE(LOOP_BREAK) 2446 + OPCODE(GOTO) 2447 + /**************************/ 2448 + OPCODE(BEGIN_CALL) 2449 + OPCODE(CALL) 2450 + OPCODE(RETURN_VALUE) 2451 + OPCODE(YIELD_VALUE) 2452 + /**************************/ 2453 + OPCODE(LIST_APPEND) 2454 + OPCODE(DICT_ADD) 2455 + OPCODE(SET_ADD) 2456 + /**************************/ 2457 + OPCODE(UNARY_NEGATIVE) 2458 + OPCODE(UNARY_NOT) 2459 + /**************************/ 2460 + OPCODE(GET_ITER) 2461 + OPCODE(FOR_ITER) 2462 + /**************************/ 2463 + OPCODE(IMPORT_NAME) 2464 + OPCODE(IMPORT_STAR) 2465 + /**************************/ 2466 + OPCODE(UNPACK_SEQUENCE) 2467 + OPCODE(UNPACK_EX) 2468 + OPCODE(UNPACK_UNLIMITED) 2469 + /**************************/ 2470 + OPCODE(BEGIN_CLASS) 2471 + OPCODE(END_CLASS) 2472 + OPCODE(STORE_CLASS_ATTR) 2473 + /**************************/ 2474 + OPCODE(WITH_ENTER) 2475 + OPCODE(WITH_EXIT) 2476 + /**************************/ 2477 + OPCODE(ASSERT) 2478 + OPCODE(EXCEPTION_MATCH) 2479 + OPCODE(RAISE) 2480 + OPCODE(RE_RAISE) 2481 + /**************************/ 2482 + OPCODE(SETUP_DOCSTRING) 2483 + OPCODE(FORMAT_STRING) 2484 + #endif 2485 + #undef OPCODE 2486 + }; 2487 + 2488 + inline const char* OP_NAMES[] = { 2489 + #define OPCODE(name) #name, 2490 + #ifdef OPCODE 2491 + 2492 + /**************************/ 2493 + OPCODE(NO_OP) 2494 + /**************************/ 2495 + OPCODE(POP_TOP) 2496 + OPCODE(DUP_TOP) 2497 + OPCODE(ROT_TWO) 2498 + OPCODE(PRINT_EXPR) 2499 + /**************************/ 2500 + OPCODE(LOAD_CONST) 2501 + OPCODE(LOAD_NONE) 2502 + OPCODE(LOAD_TRUE) 2503 + OPCODE(LOAD_FALSE) 2504 + OPCODE(LOAD_INTEGER) 2505 + OPCODE(LOAD_ELLIPSIS) 2506 + OPCODE(LOAD_FUNCTION) 2507 + OPCODE(LOAD_NULL) 2508 + /**************************/ 2509 + OPCODE(LOAD_FAST) 2510 + OPCODE(LOAD_NAME) 2511 + OPCODE(LOAD_NONLOCAL) 2512 + OPCODE(LOAD_GLOBAL) 2513 + OPCODE(LOAD_ATTR) 2514 + OPCODE(LOAD_METHOD) 2515 + OPCODE(LOAD_SUBSCR) 2516 + 2517 + OPCODE(STORE_FAST) 2518 + OPCODE(STORE_NAME) 2519 + OPCODE(STORE_GLOBAL) 2520 + OPCODE(STORE_ATTR) 2521 + OPCODE(STORE_SUBSCR) 2522 + 2523 + OPCODE(DELETE_FAST) 2524 + OPCODE(DELETE_NAME) 2525 + OPCODE(DELETE_GLOBAL) 2526 + OPCODE(DELETE_ATTR) 2527 + OPCODE(DELETE_SUBSCR) 2528 + /**************************/ 2529 + OPCODE(BUILD_LIST) 2530 + OPCODE(BUILD_DICT) 2531 + OPCODE(BUILD_SET) 2532 + OPCODE(BUILD_SLICE) 2533 + OPCODE(BUILD_TUPLE) 2534 + OPCODE(BUILD_STRING) 2535 + /**************************/ 2536 + OPCODE(BINARY_OP) 2537 + OPCODE(BINARY_ADD) 2538 + OPCODE(BINARY_SUB) 2539 + OPCODE(BINARY_MUL) 2540 + OPCODE(BINARY_FLOORDIV) 2541 + OPCODE(BINARY_MOD) 2542 + 2543 + OPCODE(COMPARE_LT) 2544 + OPCODE(COMPARE_LE) 2545 + OPCODE(COMPARE_EQ) 2546 + OPCODE(COMPARE_NE) 2547 + OPCODE(COMPARE_GT) 2548 + OPCODE(COMPARE_GE) 2549 + 2550 + OPCODE(BITWISE_LSHIFT) 2551 + OPCODE(BITWISE_RSHIFT) 2552 + OPCODE(BITWISE_AND) 2553 + OPCODE(BITWISE_OR) 2554 + OPCODE(BITWISE_XOR) 2555 + 2556 + OPCODE(IS_OP) 2557 + OPCODE(CONTAINS_OP) 2558 + /**************************/ 2559 + OPCODE(JUMP_ABSOLUTE) 2560 + OPCODE(POP_JUMP_IF_FALSE) 2561 + OPCODE(JUMP_IF_TRUE_OR_POP) 2562 + OPCODE(JUMP_IF_FALSE_OR_POP) 2563 + OPCODE(LOOP_CONTINUE) 2564 + OPCODE(LOOP_BREAK) 2565 + OPCODE(GOTO) 2566 + /**************************/ 2567 + OPCODE(BEGIN_CALL) 2568 + OPCODE(CALL) 2569 + OPCODE(RETURN_VALUE) 2570 + OPCODE(YIELD_VALUE) 2571 + /**************************/ 2572 + OPCODE(LIST_APPEND) 2573 + OPCODE(DICT_ADD) 2574 + OPCODE(SET_ADD) 2575 + /**************************/ 2576 + OPCODE(UNARY_NEGATIVE) 2577 + OPCODE(UNARY_NOT) 2578 + /**************************/ 2579 + OPCODE(GET_ITER) 2580 + OPCODE(FOR_ITER) 2581 + /**************************/ 2582 + OPCODE(IMPORT_NAME) 2583 + OPCODE(IMPORT_STAR) 2584 + /**************************/ 2585 + OPCODE(UNPACK_SEQUENCE) 2586 + OPCODE(UNPACK_EX) 2587 + OPCODE(UNPACK_UNLIMITED) 2588 + /**************************/ 2589 + OPCODE(BEGIN_CLASS) 2590 + OPCODE(END_CLASS) 2591 + OPCODE(STORE_CLASS_ATTR) 2592 + /**************************/ 2593 + OPCODE(WITH_ENTER) 2594 + OPCODE(WITH_EXIT) 2595 + /**************************/ 2596 + OPCODE(ASSERT) 2597 + OPCODE(EXCEPTION_MATCH) 2598 + OPCODE(RAISE) 2599 + OPCODE(RE_RAISE) 2600 + /**************************/ 2601 + OPCODE(SETUP_DOCSTRING) 2602 + OPCODE(FORMAT_STRING) 2603 + #endif 2604 + #undef OPCODE 2605 + }; 2606 + 2607 + struct Bytecode{ 2608 + uint16_t op; 2609 + uint16_t block; 2610 + int arg; 2611 + }; 2612 + 2613 + enum CodeBlockType { 2614 + NO_BLOCK, 2615 + FOR_LOOP, 2616 + WHILE_LOOP, 2617 + CONTEXT_MANAGER, 2618 + TRY_EXCEPT, 2619 + }; 2620 + 2621 + #define BC_NOARG -1 2622 + #define BC_KEEPLINE -1 2623 + 2624 + struct CodeBlock { 2625 + CodeBlockType type; 2626 + int parent; // parent index in blocks 2627 + int for_loop_depth; // this is used for exception handling 2628 + int start; // start index of this block in codes, inclusive 2629 + int end; // end index of this block in codes, exclusive 2630 + 2631 + CodeBlock(CodeBlockType type, int parent, int for_loop_depth, int start): 2632 + type(type), parent(parent), for_loop_depth(for_loop_depth), start(start), end(-1) {} 2633 + }; 2634 + 2635 + struct CodeObject { 2636 + shared_ptr<SourceData> src; 2637 + Str name; 2638 + bool is_generator = false; 2639 + 2640 + CodeObject(shared_ptr<SourceData> src, const Str& name): 2641 + src(src), name(name) {} 2642 + 2643 + std::vector<Bytecode> codes; 2644 + std::vector<int> lines; // line number for each bytecode 2645 + List consts; 2646 + std::vector<StrName> varnames; // local variables 2647 + NameDictInt varnames_inv; 2648 + std::set<Str> global_names; 2649 + std::vector<CodeBlock> blocks = { CodeBlock(NO_BLOCK, -1, 0, 0) }; 2650 + NameDictInt labels; 2651 + std::vector<FuncDecl_> func_decls; 2652 + 2653 + void optimize(VM* vm); 2654 + 2655 + void _gc_mark() const { 2656 + for(PyObject* v : consts) OBJ_MARK(v); 2657 + for(auto& decl: func_decls) decl->_gc_mark(); 2658 + } 2659 + }; 2660 + 2661 + } // namespace pkpy 2662 + 2663 + 2664 + namespace pkpy{ 2665 + 2666 + // weak reference fast locals 2667 + struct FastLocals{ 2668 + // this is a weak reference 2669 + const NameDictInt* varnames_inv; 2670 + PyObject** a; 2671 + 2672 + int size() const{ 2673 + return varnames_inv->size(); 2674 + } 2675 + 2676 + PyObject*& operator[](int i){ return a[i]; } 2677 + PyObject* operator[](int i) const { return a[i]; } 2678 + 2679 + FastLocals(const CodeObject* co, PyObject** a): varnames_inv(&co->varnames_inv), a(a) {} 2680 + FastLocals(const FastLocals& other): varnames_inv(other.varnames_inv), a(other.a) {} 2681 + 2682 + PyObject* try_get(StrName name){ 2683 + int index = varnames_inv->try_get(name); 2684 + if(index == -1) return nullptr; 2685 + return a[index]; 2686 + } 2687 + 2688 + bool contains(StrName name){ 2689 + return varnames_inv->contains(name); 2690 + } 2691 + 2692 + void erase(StrName name){ 2693 + int index = varnames_inv->try_get(name); 2694 + if(index == -1) FATAL_ERROR(); 2695 + a[index] = nullptr; 2696 + } 2697 + 2698 + bool try_set(StrName name, PyObject* value){ 2699 + int index = varnames_inv->try_get(name); 2700 + if(index == -1) return false; 2701 + a[index] = value; 2702 + return true; 2703 + } 2704 + 2705 + NameDict_ to_namedict(){ 2706 + NameDict_ dict = make_sp<NameDict>(); 2707 + // TODO: optimize this 2708 + // NameDict.items() is expensive 2709 + for(auto& kv: varnames_inv->items()){ 2710 + dict->set(kv.first, a[kv.second]); 2711 + } 2712 + return dict; 2713 + } 2714 + }; 2715 + 2716 + template<size_t MAX_SIZE> 2717 + struct ValueStackImpl { 2718 + // We allocate extra MAX_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`. 2719 + PyObject* _begin[MAX_SIZE + MAX_SIZE/128]; 2720 + PyObject** _sp; 2721 + PyObject** _max_end; 2722 + 2723 + ValueStackImpl(): _sp(_begin), _max_end(_begin + MAX_SIZE) {} 2724 + 2725 + PyObject*& top(){ return _sp[-1]; } 2726 + PyObject* top() const { return _sp[-1]; } 2727 + PyObject*& second(){ return _sp[-2]; } 2728 + PyObject* second() const { return _sp[-2]; } 2729 + PyObject*& third(){ return _sp[-3]; } 2730 + PyObject* third() const { return _sp[-3]; } 2731 + PyObject*& peek(int n){ return _sp[-n]; } 2732 + PyObject* peek(int n) const { return _sp[-n]; } 2733 + void push(PyObject* v){ *_sp++ = v; } 2734 + void pop(){ --_sp; } 2735 + PyObject* popx(){ return *--_sp; } 2736 + ArgsView view(int n){ return ArgsView(_sp-n, _sp); } 2737 + void shrink(int n){ _sp -= n; } 2738 + int size() const { return _sp - _begin; } 2739 + bool empty() const { return _sp == _begin; } 2740 + PyObject** begin() { return _begin; } 2741 + PyObject** end() { return _sp; } 2742 + void reset(PyObject** sp) { 2743 + #if DEBUG_EXTRA_CHECK 2744 + if(sp < _begin || sp > _begin + MAX_SIZE) FATAL_ERROR(); 2745 + #endif 2746 + _sp = sp; 2747 + } 2748 + void clear() { _sp = _begin; } 2749 + bool is_overflow() const { return _sp >= _max_end; } 2750 + 2751 + ValueStackImpl(const ValueStackImpl&) = delete; 2752 + ValueStackImpl(ValueStackImpl&&) = delete; 2753 + ValueStackImpl& operator=(const ValueStackImpl&) = delete; 2754 + ValueStackImpl& operator=(ValueStackImpl&&) = delete; 2755 + }; 2756 + 2757 + using ValueStack = ValueStackImpl<32768>; 2758 + 2759 + struct Frame { 2760 + int _ip = -1; 2761 + int _next_ip = 0; 2762 + ValueStack* _s; 2763 + // This is for unwinding only, use `actual_sp_base()` for value stack access 2764 + PyObject** _sp_base; 2765 + 2766 + const CodeObject* co; 2767 + PyObject* _module; 2768 + PyObject* _callable; 2769 + FastLocals _locals; 2770 + 2771 + NameDict& f_globals() noexcept { return _module->attr(); } 2772 + 2773 + PyObject* f_closure_try_get(StrName name){ 2774 + if(_callable == nullptr) return nullptr; 2775 + Function& fn = OBJ_GET(Function, _callable); 2776 + if(fn._closure == nullptr) return nullptr; 2777 + return fn._closure->try_get(name); 2778 + } 2779 + 2780 + Frame(ValueStack* _s, PyObject** p0, const CodeObject* co, PyObject* _module, PyObject* _callable) 2781 + : _s(_s), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, p0) { } 2782 + 2783 + Frame(ValueStack* _s, PyObject** p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) 2784 + : _s(_s), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals) { } 2785 + 2786 + Frame(ValueStack* _s, PyObject** p0, const CodeObject_& co, PyObject* _module) 2787 + : _s(_s), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0) {} 2788 + 2789 + Bytecode next_bytecode() { 2790 + _ip = _next_ip++; 2791 + #if DEBUG_EXTRA_CHECK 2792 + if(_ip >= co->codes.size()) FATAL_ERROR(); 2793 + #endif 2794 + return co->codes[_ip]; 2795 + } 2796 + 2797 + Str snapshot(){ 2798 + int line = co->lines[_ip]; 2799 + return co->src->snapshot(line); 2800 + } 2801 + 2802 + PyObject** actual_sp_base() const { return _locals.a; } 2803 + int stack_size() const { return _s->_sp - actual_sp_base(); } 2804 + ArgsView stack_view() const { return ArgsView(actual_sp_base(), _s->_sp); } 2805 + 2806 + void jump_abs(int i){ _next_ip = i; } 2807 + // void jump_rel(int i){ _next_ip += i; } 2808 + 2809 + bool jump_to_exception_handler(){ 2810 + // try to find a parent try block 2811 + int block = co->codes[_ip].block; 2812 + while(block >= 0){ 2813 + if(co->blocks[block].type == TRY_EXCEPT) break; 2814 + block = co->blocks[block].parent; 2815 + } 2816 + if(block < 0) return false; 2817 + PyObject* obj = _s->popx(); // pop exception object 2818 + // get the stack size of the try block (depth of for loops) 2819 + int _stack_size = co->blocks[block].for_loop_depth; 2820 + if(stack_size() < _stack_size) throw std::runtime_error("invalid stack size"); 2821 + _s->reset(actual_sp_base() + _stack_size); // rollback the stack 2822 + _s->push(obj); // push exception object 2823 + _next_ip = co->blocks[block].end; 2824 + return true; 2825 + } 2826 + 2827 + int _exit_block(int i){ 2828 + if(co->blocks[i].type == FOR_LOOP) _s->pop(); 2829 + return co->blocks[i].parent; 2830 + } 2831 + 2832 + void jump_abs_break(int target){ 2833 + const Bytecode& prev = co->codes[_ip]; 2834 + int i = prev.block; 2835 + _next_ip = target; 2836 + if(_next_ip >= co->codes.size()){ 2837 + while(i>=0) i = _exit_block(i); 2838 + }else{ 2839 + const Bytecode& next = co->codes[target]; 2840 + while(i>=0 && i!=next.block) i = _exit_block(i); 2841 + if(i!=next.block) throw std::runtime_error("invalid jump"); 2842 + } 2843 + } 2844 + 2845 + void _gc_mark() const { 2846 + OBJ_MARK(_module); 2847 + if(_callable != nullptr) OBJ_MARK(_callable); 2848 + co->_gc_mark(); 2849 + } 2850 + }; 2851 + 2852 + }; // namespace pkpy 2853 + 2854 + 2855 + namespace pkpy { 2856 + struct ManagedHeap{ 2857 + std::vector<PyObject*> _no_gc; 2858 + std::vector<PyObject*> gen; 2859 + VM* vm; 2860 + ManagedHeap(VM* vm): vm(vm) {} 2861 + 2862 + static const int kMinGCThreshold = 3072; 2863 + int gc_threshold = kMinGCThreshold; 2864 + int gc_counter = 0; 2865 + 2866 + /********************/ 2867 + int _gc_lock_counter = 0; 2868 + struct ScopeLock{ 2869 + ManagedHeap* heap; 2870 + ScopeLock(ManagedHeap* heap): heap(heap){ 2871 + heap->_gc_lock_counter++; 2872 + } 2873 + ~ScopeLock(){ 2874 + heap->_gc_lock_counter--; 2875 + } 2876 + }; 2877 + 2878 + ScopeLock gc_scope_lock(){ 2879 + return ScopeLock(this); 2880 + } 2881 + /********************/ 2882 + 2883 + template<typename T> 2884 + PyObject* gcnew(Type type, T&& val){ 2885 + using __T = Py_<std::decay_t<T>>; 2886 + PyObject* obj = new(pool64.alloc<__T>()) __T(type, std::forward<T>(val)); 2887 + gen.push_back(obj); 2888 + gc_counter++; 2889 + return obj; 2890 + } 2891 + 2892 + template<typename T> 2893 + PyObject* _new(Type type, T&& val){ 2894 + using __T = Py_<std::decay_t<T>>; 2895 + PyObject* obj = new(pool64.alloc<__T>()) __T(type, std::forward<T>(val)); 2896 + obj->gc.enabled = false; 2897 + _no_gc.push_back(obj); 2898 + return obj; 2899 + } 2900 + 2901 + #if DEBUG_GC_STATS 2902 + inline static std::map<Type, int> deleted; 2903 + #endif 2904 + 2905 + int sweep(){ 2906 + std::vector<PyObject*> alive; 2907 + for(PyObject* obj: gen){ 2908 + if(obj->gc.marked){ 2909 + obj->gc.marked = false; 2910 + alive.push_back(obj); 2911 + }else{ 2912 + #if DEBUG_GC_STATS 2913 + deleted[obj->type] += 1; 2914 + #endif 2915 + obj->~PyObject(), pool64.dealloc(obj); 2916 + } 2917 + } 2918 + 2919 + // clear _no_gc marked flag 2920 + for(PyObject* obj: _no_gc) obj->gc.marked = false; 2921 + 2922 + int freed = gen.size() - alive.size(); 2923 + // std::cout << "GC: " << alive.size() << "/" << gen.size() << " (" << freed << " freed)" << std::endl; 2924 + gen.clear(); 2925 + gen.swap(alive); 2926 + return freed; 2927 + } 2928 + 2929 + void _auto_collect(){ 2930 + #if !DEBUG_NO_AUTO_GC 2931 + if(_gc_lock_counter > 0) return; 2932 + if(gc_counter < gc_threshold) return; 2933 + gc_counter = 0; 2934 + collect(); 2935 + gc_threshold = gen.size() * 2; 2936 + if(gc_threshold < kMinGCThreshold) gc_threshold = kMinGCThreshold; 2937 + #endif 2938 + } 2939 + 2940 + int collect(){ 2941 + if(_gc_lock_counter > 0) FATAL_ERROR(); 2942 + mark(); 2943 + int freed = sweep(); 2944 + return freed; 2945 + } 2946 + 2947 + void mark(); 2948 + 2949 + ~ManagedHeap(){ 2950 + for(PyObject* obj: _no_gc) obj->~PyObject(), pool64.dealloc(obj); 2951 + for(PyObject* obj: gen) obj->~PyObject(), pool64.dealloc(obj); 2952 + #if DEBUG_GC_STATS 2953 + for(auto& [type, count]: deleted){ 2954 + std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl; 2955 + } 2956 + #endif 2957 + } 2958 + }; 2959 + 2960 + inline void FuncDecl::_gc_mark() const{ 2961 + code->_gc_mark(); 2962 + for(int i=0; i<kwargs.size(); i++) OBJ_MARK(kwargs[i].value); 2963 + } 2964 + 2965 + } // namespace pkpy 2966 + 2967 + 2968 + namespace pkpy{ 2969 + 2970 + /* Stack manipulation macros */ 2971 + // https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123 2972 + #define TOP() (s_data.top()) 2973 + #define SECOND() (s_data.second()) 2974 + #define THIRD() (s_data.third()) 2975 + #define PEEK(n) (s_data.peek(n)) 2976 + #define STACK_SHRINK(n) (s_data.shrink(n)) 2977 + #define PUSH(v) (s_data.push(v)) 2978 + #define POP() (s_data.pop()) 2979 + #define POPX() (s_data.popx()) 2980 + #define STACK_VIEW(n) (s_data.view(n)) 2981 + 2982 + typedef Bytes (*ReadFileCwdFunc)(const Str& name); 2983 + inline ReadFileCwdFunc _read_file_cwd = [](const Str& name) { return Bytes(); }; 2984 + inline int set_read_file_cwd(ReadFileCwdFunc func) { _read_file_cwd = func; return 0; } 2985 + 2986 + #define DEF_NATIVE_2(ctype, ptype) \ 2987 + template<> inline ctype py_cast<ctype>(VM* vm, PyObject* obj) { \ 2988 + vm->check_non_tagged_type(obj, vm->ptype); \ 2989 + return OBJ_GET(ctype, obj); \ 2990 + } \ 2991 + template<> inline ctype _py_cast<ctype>(VM* vm, PyObject* obj) { \ 2992 + return OBJ_GET(ctype, obj); \ 2993 + } \ 2994 + template<> inline ctype& py_cast<ctype&>(VM* vm, PyObject* obj) { \ 2995 + vm->check_non_tagged_type(obj, vm->ptype); \ 2996 + return OBJ_GET(ctype, obj); \ 2997 + } \ 2998 + template<> inline ctype& _py_cast<ctype&>(VM* vm, PyObject* obj) { \ 2999 + return OBJ_GET(ctype, obj); \ 3000 + } \ 3001 + inline PyObject* py_var(VM* vm, const ctype& value) { return vm->heap.gcnew(vm->ptype, value);} \ 3002 + inline PyObject* py_var(VM* vm, ctype&& value) { return vm->heap.gcnew(vm->ptype, std::move(value));} 3003 + 3004 + 3005 + class Generator final: public BaseIter { 3006 + Frame frame; 3007 + int state; // 0,1,2 3008 + List s_backup; 3009 + public: 3010 + Generator(VM* vm, Frame&& frame, ArgsView buffer): BaseIter(vm), frame(std::move(frame)), state(0) { 3011 + for(PyObject* obj: buffer) s_backup.push_back(obj); 3012 + } 3013 + 3014 + PyObject* next() override; 3015 + void _gc_mark() const; 3016 + }; 3017 + 3018 + struct PyTypeInfo{ 3019 + PyObject* obj; 3020 + Type base; 3021 + Str name; 3022 + }; 3023 + 3024 + struct FrameId{ 3025 + std::vector<pkpy::Frame>* data; 3026 + int index; 3027 + FrameId(std::vector<pkpy::Frame>* data, int index) : data(data), index(index) {} 3028 + Frame* operator->() const { return &data->operator[](index); } 3029 + }; 3030 + 3031 + typedef void(*PrintFunc)(VM*, const Str&); 3032 + 3033 + class VM { 3034 + VM* vm; // self reference for simplify code 3035 + public: 3036 + ManagedHeap heap; 3037 + ValueStack s_data; 3038 + stack< Frame > callstack; 3039 + std::vector<PyTypeInfo> _all_types; 3040 + void (*_gc_marker_ex)(VM*) = nullptr; 3041 + 3042 + NameDict _modules; // loaded modules 3043 + std::map<StrName, Str> _lazy_modules; // lazy loaded modules 3044 + 3045 + PyObject* None; 3046 + PyObject* True; 3047 + PyObject* False; 3048 + PyObject* Ellipsis; 3049 + PyObject* builtins; // builtins module 3050 + PyObject* StopIteration; 3051 + PyObject* _main; // __main__ module 3052 + 3053 + PrintFunc _stdout; 3054 + PrintFunc _stderr; 3055 + 3056 + bool _initialized; 3057 + 3058 + // for quick access 3059 + Type tp_object, tp_type, tp_int, tp_float, tp_bool, tp_str; 3060 + Type tp_list, tp_tuple; 3061 + Type tp_function, tp_native_func, tp_iterator, tp_bound_method; 3062 + Type tp_slice, tp_range, tp_module; 3063 + Type tp_super, tp_exception, tp_bytes, tp_mappingproxy; 3064 + 3065 + const bool enable_os; 3066 + 3067 + VM(bool enable_os=true) : heap(this), enable_os(enable_os) { 3068 + this->vm = this; 3069 + _stdout = [](VM* vm, const Str& s) { std::cout << s; }; 3070 + _stderr = [](VM* vm, const Str& s) { std::cerr << s; }; 3071 + callstack.reserve(8); 3072 + _initialized = false; 3073 + init_builtin_types(); 3074 + _initialized = true; 3075 + } 3076 + 3077 + FrameId top_frame() { 3078 + #if DEBUG_EXTRA_CHECK 3079 + if(callstack.empty()) FATAL_ERROR(); 3080 + #endif 3081 + return FrameId(&callstack.data(), callstack.size()-1); 3082 + } 3083 + 3084 + PyObject* asStr(PyObject* obj){ 3085 + PyObject* self; 3086 + PyObject* f = get_unbound_method(obj, __str__, &self, false); 3087 + if(self != PY_NULL) return call_method(self, f); 3088 + return asRepr(obj); 3089 + } 3090 + 3091 + PyObject* asIter(PyObject* obj){ 3092 + if(is_type(obj, tp_iterator)) return obj; 3093 + PyObject* self; 3094 + PyObject* iter_f = get_unbound_method(obj, __iter__, &self, false); 3095 + if(self != PY_NULL) return call_method(self, iter_f); 3096 + TypeError(OBJ_NAME(_t(obj)).escape() + " object is not iterable"); 3097 + return nullptr; 3098 + } 3099 + 3100 + PyObject* asList(PyObject* it){ 3101 + if(is_non_tagged_type(it, tp_list)) return it; 3102 + return call(_t(tp_list), it); 3103 + } 3104 + 3105 + PyObject* find_name_in_mro(PyObject* cls, StrName name){ 3106 + PyObject* val; 3107 + do{ 3108 + val = cls->attr().try_get(name); 3109 + if(val != nullptr) return val; 3110 + Type cls_t = OBJ_GET(Type, cls); 3111 + Type base = _all_types[cls_t].base; 3112 + if(base.index == -1) break; 3113 + cls = _all_types[base].obj; 3114 + }while(true); 3115 + return nullptr; 3116 + } 3117 + 3118 + bool isinstance(PyObject* obj, Type cls_t){ 3119 + Type obj_t = OBJ_GET(Type, _t(obj)); 3120 + do{ 3121 + if(obj_t == cls_t) return true; 3122 + Type base = _all_types[obj_t].base; 3123 + if(base.index == -1) break; 3124 + obj_t = base; 3125 + }while(true); 3126 + return false; 3127 + } 3128 + 3129 + PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr){ 3130 + if(_module == nullptr) _module = _main; 3131 + try { 3132 + CodeObject_ code = compile(source, filename, mode); 3133 + #if DEBUG_DIS_EXEC 3134 + if(_module == _main) std::cout << disassemble(code) << '\n'; 3135 + #endif 3136 + return _exec(code, _module); 3137 + }catch (const Exception& e){ 3138 + _stderr(this, e.summary() + "\n"); 3139 + } 3140 + #if !DEBUG_FULL_EXCEPTION 3141 + catch (const std::exception& e) { 3142 + _stderr(this, "An std::exception occurred! It could be a bug.\n"); 3143 + _stderr(this, e.what()); 3144 + _stderr(this, "\n"); 3145 + } 3146 + #endif 3147 + callstack.clear(); 3148 + s_data.clear(); 3149 + return nullptr; 3150 + } 3151 + 3152 + template<typename ...Args> 3153 + PyObject* _exec(Args&&... args){ 3154 + callstack.emplace(&s_data, s_data._sp, std::forward<Args>(args)...); 3155 + return _run_top_frame(); 3156 + } 3157 + 3158 + void _pop_frame(){ 3159 + Frame* frame = &callstack.top(); 3160 + s_data.reset(frame->_sp_base); 3161 + callstack.pop(); 3162 + } 3163 + 3164 + void _push_varargs(){ } 3165 + void _push_varargs(PyObject* _0){ PUSH(_0); } 3166 + void _push_varargs(PyObject* _0, PyObject* _1){ PUSH(_0); PUSH(_1); } 3167 + void _push_varargs(PyObject* _0, PyObject* _1, PyObject* _2){ PUSH(_0); PUSH(_1); PUSH(_2); } 3168 + void _push_varargs(PyObject* _0, PyObject* _1, PyObject* _2, PyObject* _3){ PUSH(_0); PUSH(_1); PUSH(_2); PUSH(_3); } 3169 + 3170 + template<typename... Args> 3171 + PyObject* call(PyObject* callable, Args&&... args){ 3172 + PUSH(callable); 3173 + PUSH(PY_NULL); 3174 + _push_varargs(args...); 3175 + return vectorcall(sizeof...(args)); 3176 + } 3177 + 3178 + template<typename... Args> 3179 + PyObject* call_method(PyObject* self, PyObject* callable, Args&&... args){ 3180 + PUSH(callable); 3181 + PUSH(self); 3182 + _push_varargs(args...); 3183 + return vectorcall(sizeof...(args)); 3184 + } 3185 + 3186 + template<typename... Args> 3187 + PyObject* call_method(PyObject* self, StrName name, Args&&... args){ 3188 + PyObject* callable = get_unbound_method(self, name, &self); 3189 + return call_method(self, callable, args...); 3190 + } 3191 + 3192 + PyObject* property(NativeFuncC fget, NativeFuncC fset=nullptr){ 3193 + PyObject* p = builtins->attr("property"); 3194 + PyObject* _0 = heap.gcnew(tp_native_func, NativeFunc(fget, 1, false)); 3195 + PyObject* _1 = vm->None; 3196 + if(fset != nullptr) _1 = heap.gcnew(tp_native_func, NativeFunc(fset, 2, false)); 3197 + return call(p, _0, _1); 3198 + } 3199 + 3200 + PyObject* new_type_object(PyObject* mod, StrName name, Type base){ 3201 + PyObject* obj = heap._new<Type>(tp_type, _all_types.size()); 3202 + PyTypeInfo info{ 3203 + obj, 3204 + base, 3205 + (mod!=nullptr && mod!=builtins) ? Str(OBJ_NAME(mod)+"."+name.sv()): name.sv() 3206 + }; 3207 + if(mod != nullptr) mod->attr().set(name, obj); 3208 + _all_types.push_back(info); 3209 + return obj; 3210 + } 3211 + 3212 + Type _new_type_object(StrName name, Type base=0) { 3213 + PyObject* obj = new_type_object(nullptr, name, base); 3214 + return OBJ_GET(Type, obj); 3215 + } 3216 + 3217 + PyObject* _find_type(const Str& type){ 3218 + PyObject* obj = builtins->attr().try_get(type); 3219 + if(obj == nullptr){ 3220 + for(auto& t: _all_types) if(t.name == type) return t.obj; 3221 + throw std::runtime_error(fmt("type not found: ", type)); 3222 + } 3223 + return obj; 3224 + } 3225 + 3226 + template<int ARGC> 3227 + void bind_func(Str type, Str name, NativeFuncC fn) { 3228 + bind_func<ARGC>(_find_type(type), name, fn); 3229 + } 3230 + 3231 + template<int ARGC> 3232 + void bind_method(Str type, Str name, NativeFuncC fn) { 3233 + bind_method<ARGC>(_find_type(type), name, fn); 3234 + } 3235 + 3236 + template<int ARGC, typename... Args> 3237 + void bind_static_method(Args&&... args) { 3238 + bind_func<ARGC>(std::forward<Args>(args)...); 3239 + } 3240 + 3241 + template<int ARGC> 3242 + void bind_builtin_func(Str name, NativeFuncC fn) { 3243 + bind_func<ARGC>(builtins, name, fn); 3244 + } 3245 + 3246 + int normalized_index(int index, int size){ 3247 + if(index < 0) index += size; 3248 + if(index < 0 || index >= size){ 3249 + IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")"); 3250 + } 3251 + return index; 3252 + } 3253 + 3254 + template<typename P> 3255 + PyObject* PyIter(P&& value) { 3256 + static_assert(std::is_base_of_v<BaseIter, std::decay_t<P>>); 3257 + return heap.gcnew<P>(tp_iterator, std::forward<P>(value)); 3258 + } 3259 + 3260 + PyObject* PyIterNext(PyObject* obj){ 3261 + if(is_non_tagged_type(obj, tp_iterator)){ 3262 + BaseIter* iter = static_cast<BaseIter*>(obj->value()); 3263 + return iter->next(); 3264 + } 3265 + return call_method(obj, __next__); 3266 + } 3267 + 3268 + /***** Error Reporter *****/ 3269 + void _error(StrName name, const Str& msg){ 3270 + _error(Exception(name, msg)); 3271 + } 3272 + 3273 + void _raise(){ 3274 + bool ok = top_frame()->jump_to_exception_handler(); 3275 + if(ok) throw HandledException(); 3276 + else throw UnhandledException(); 3277 + } 3278 + 3279 + void StackOverflowError() { _error("StackOverflowError", ""); } 3280 + void IOError(const Str& msg) { _error("IOError", msg); } 3281 + void NotImplementedError(){ _error("NotImplementedError", ""); } 3282 + void TypeError(const Str& msg){ _error("TypeError", msg); } 3283 + void ZeroDivisionError(){ _error("ZeroDivisionError", "division by zero"); } 3284 + void IndexError(const Str& msg){ _error("IndexError", msg); } 3285 + void ValueError(const Str& msg){ _error("ValueError", msg); } 3286 + void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); } 3287 + 3288 + void AttributeError(PyObject* obj, StrName name){ 3289 + // OBJ_NAME calls getattr, which may lead to a infinite recursion 3290 + _error("AttributeError", fmt("type ", OBJ_NAME(_t(obj)).escape(), " has no attribute ", name.escape())); 3291 + } 3292 + 3293 + void AttributeError(Str msg){ _error("AttributeError", msg); } 3294 + 3295 + void check_type(PyObject* obj, Type type){ 3296 + if(is_type(obj, type)) return; 3297 + TypeError("expected " + OBJ_NAME(_t(type)).escape() + ", but got " + OBJ_NAME(_t(obj)).escape()); 3298 + } 3299 + 3300 + void check_non_tagged_type(PyObject* obj, Type type){ 3301 + if(is_non_tagged_type(obj, type)) return; 3302 + TypeError("expected " + OBJ_NAME(_t(type)).escape() + ", but got " + OBJ_NAME(_t(obj)).escape()); 3303 + } 3304 + 3305 + void check_int(PyObject* obj){ 3306 + if(is_int(obj)) return; 3307 + check_type(obj, tp_int); 3308 + } 3309 + 3310 + void check_float(PyObject* obj){ 3311 + if(is_float(obj)) return; 3312 + check_type(obj, tp_float); 3313 + } 3314 + 3315 + PyObject* _t(Type t){ 3316 + return _all_types[t.index].obj; 3317 + } 3318 + 3319 + PyObject* _t(PyObject* obj){ 3320 + if(is_int(obj)) return _t(tp_int); 3321 + if(is_float(obj)) return _t(tp_float); 3322 + return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj; 3323 + } 3324 + 3325 + ~VM() { 3326 + callstack.clear(); 3327 + s_data.clear(); 3328 + _all_types.clear(); 3329 + _modules.clear(); 3330 + _lazy_modules.clear(); 3331 + } 3332 + 3333 + void _log_s_data(const char* title = nullptr); 3334 + PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false); 3335 + CodeObject_ compile(Str source, Str filename, CompileMode mode, bool unknown_global_scope=false); 3336 + PyObject* num_negated(PyObject* obj); 3337 + f64 num_to_float(PyObject* obj); 3338 + bool asBool(PyObject* obj); 3339 + i64 hash(PyObject* obj); 3340 + PyObject* asRepr(PyObject* obj); 3341 + PyObject* new_module(StrName name); 3342 + Str disassemble(CodeObject_ co); 3343 + void init_builtin_types(); 3344 + PyObject* _py_call(PyObject** sp_base, PyObject* callable, ArgsView args, ArgsView kwargs); 3345 + PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true); 3346 + PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err=true, bool fallback=false); 3347 + void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step); 3348 + PyObject* format(Str, PyObject*); 3349 + void setattr(PyObject* obj, StrName name, PyObject* value); 3350 + template<int ARGC> 3351 + void bind_method(PyObject*, Str, NativeFuncC); 3352 + template<int ARGC> 3353 + void bind_func(PyObject*, Str, NativeFuncC); 3354 + void _error(Exception); 3355 + PyObject* _run_top_frame(); 3356 + void post_init(); 3357 + }; 3358 + 3359 + inline PyObject* NativeFunc::operator()(VM* vm, ArgsView args) const{ 3360 + int args_size = args.size() - (int)method; // remove self 3361 + if(argc != -1 && args_size != argc) { 3362 + vm->TypeError(fmt("expected ", argc, " arguments, but got ", args_size)); 3363 + } 3364 + return f(vm, args); 3365 + } 3366 + 3367 + inline void CodeObject::optimize(VM* vm){ 3368 + // uint32_t base_n = (uint32_t)(names.size() / kLocalsLoadFactor + 0.5); 3369 + // perfect_locals_capacity = std::max(find_next_capacity(base_n), NameDict::__Capacity); 3370 + // perfect_hash_seed = find_perfect_hash_seed(perfect_locals_capacity, names); 3371 + } 3372 + 3373 + DEF_NATIVE_2(Str, tp_str) 3374 + DEF_NATIVE_2(List, tp_list) 3375 + DEF_NATIVE_2(Tuple, tp_tuple) 3376 + DEF_NATIVE_2(Function, tp_function) 3377 + DEF_NATIVE_2(NativeFunc, tp_native_func) 3378 + DEF_NATIVE_2(BoundMethod, tp_bound_method) 3379 + DEF_NATIVE_2(Range, tp_range) 3380 + DEF_NATIVE_2(Slice, tp_slice) 3381 + DEF_NATIVE_2(Exception, tp_exception) 3382 + DEF_NATIVE_2(Bytes, tp_bytes) 3383 + DEF_NATIVE_2(MappingProxy, tp_mappingproxy) 3384 + 3385 + #define PY_CAST_INT(T) \ 3386 + template<> inline T py_cast<T>(VM* vm, PyObject* obj){ \ 3387 + vm->check_int(obj); \ 3388 + return (T)(BITS(obj) >> 2); \ 3389 + } \ 3390 + template<> inline T _py_cast<T>(VM* vm, PyObject* obj){ \ 3391 + return (T)(BITS(obj) >> 2); \ 3392 + } 3393 + 3394 + PY_CAST_INT(char) 3395 + PY_CAST_INT(short) 3396 + PY_CAST_INT(int) 3397 + PY_CAST_INT(long) 3398 + PY_CAST_INT(long long) 3399 + PY_CAST_INT(unsigned char) 3400 + PY_CAST_INT(unsigned short) 3401 + PY_CAST_INT(unsigned int) 3402 + PY_CAST_INT(unsigned long) 3403 + PY_CAST_INT(unsigned long long) 3404 + 3405 + 3406 + template<> inline float py_cast<float>(VM* vm, PyObject* obj){ 3407 + vm->check_float(obj); 3408 + i64 bits = BITS(obj); 3409 + bits = (bits >> 2) << 2; 3410 + return BitsCvt(bits)._float; 3411 + } 3412 + template<> inline float _py_cast<float>(VM* vm, PyObject* obj){ 3413 + i64 bits = BITS(obj); 3414 + bits = (bits >> 2) << 2; 3415 + return BitsCvt(bits)._float; 3416 + } 3417 + template<> inline double py_cast<double>(VM* vm, PyObject* obj){ 3418 + vm->check_float(obj); 3419 + i64 bits = BITS(obj); 3420 + bits = (bits >> 2) << 2; 3421 + return BitsCvt(bits)._float; 3422 + } 3423 + template<> inline double _py_cast<double>(VM* vm, PyObject* obj){ 3424 + i64 bits = BITS(obj); 3425 + bits = (bits >> 2) << 2; 3426 + return BitsCvt(bits)._float; 3427 + } 3428 + 3429 + 3430 + #define PY_VAR_INT(T) \ 3431 + inline PyObject* py_var(VM* vm, T _val){ \ 3432 + i64 val = static_cast<i64>(_val); \ 3433 + if(((val << 2) >> 2) != val){ \ 3434 + vm->_error("OverflowError", std::to_string(val) + " is out of range"); \ 3435 + } \ 3436 + val = (val << 2) | 0b01; \ 3437 + return reinterpret_cast<PyObject*>(val); \ 3438 + } 3439 + 3440 + PY_VAR_INT(char) 3441 + PY_VAR_INT(short) 3442 + PY_VAR_INT(int) 3443 + PY_VAR_INT(long) 3444 + PY_VAR_INT(long long) 3445 + PY_VAR_INT(unsigned char) 3446 + PY_VAR_INT(unsigned short) 3447 + PY_VAR_INT(unsigned int) 3448 + PY_VAR_INT(unsigned long) 3449 + PY_VAR_INT(unsigned long long) 3450 + 3451 + #define PY_VAR_FLOAT(T) \ 3452 + inline PyObject* py_var(VM* vm, T _val){ \ 3453 + f64 val = static_cast<f64>(_val); \ 3454 + i64 bits = BitsCvt(val)._int; \ 3455 + bits = (bits >> 2) << 2; \ 3456 + bits |= 0b10; \ 3457 + return reinterpret_cast<PyObject*>(bits); \ 3458 + } 3459 + 3460 + PY_VAR_FLOAT(float) 3461 + PY_VAR_FLOAT(double) 3462 + 3463 + inline PyObject* py_var(VM* vm, bool val){ 3464 + return val ? vm->True : vm->False; 3465 + } 3466 + 3467 + template<> inline bool py_cast<bool>(VM* vm, PyObject* obj){ 3468 + vm->check_non_tagged_type(obj, vm->tp_bool); 3469 + return obj == vm->True; 3470 + } 3471 + template<> inline bool _py_cast<bool>(VM* vm, PyObject* obj){ 3472 + return obj == vm->True; 3473 + } 3474 + 3475 + inline PyObject* py_var(VM* vm, const char val[]){ 3476 + return VAR(Str(val)); 3477 + } 3478 + 3479 + inline PyObject* py_var(VM* vm, std::string val){ 3480 + return VAR(Str(std::move(val))); 3481 + } 3482 + 3483 + inline PyObject* py_var(VM* vm, std::string_view val){ 3484 + return VAR(Str(val)); 3485 + } 3486 + 3487 + template<typename T> 3488 + void _check_py_class(VM* vm, PyObject* obj){ 3489 + vm->check_non_tagged_type(obj, T::_type(vm)); 3490 + } 3491 + 3492 + inline PyObject* VM::num_negated(PyObject* obj){ 3493 + if (is_int(obj)){ 3494 + return VAR(-CAST(i64, obj)); 3495 + }else if(is_float(obj)){ 3496 + return VAR(-CAST(f64, obj)); 3497 + } 3498 + TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape()); 3499 + return nullptr; 3500 + } 3501 + 3502 + inline f64 VM::num_to_float(PyObject* obj){ 3503 + if(is_float(obj)){ 3504 + return CAST(f64, obj); 3505 + } else if (is_int(obj)){ 3506 + return (f64)CAST(i64, obj); 3507 + } 3508 + TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape()); 3509 + return 0; 3510 + } 3511 + 3512 + inline bool VM::asBool(PyObject* obj){ 3513 + if(is_non_tagged_type(obj, tp_bool)) return obj == True; 3514 + if(obj == None) return false; 3515 + if(is_int(obj)) return CAST(i64, obj) != 0; 3516 + if(is_float(obj)) return CAST(f64, obj) != 0.0; 3517 + PyObject* self; 3518 + PyObject* len_f = get_unbound_method(obj, __len__, &self, false); 3519 + if(self != PY_NULL){ 3520 + PyObject* ret = call_method(self, len_f); 3521 + return CAST(i64, ret) > 0; 3522 + } 3523 + return true; 3524 + } 3525 + 3526 + inline void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step){ 3527 + auto clip = [](int value, int min, int max){ 3528 + if(value < min) return min; 3529 + if(value > max) return max; 3530 + return value; 3531 + }; 3532 + if(s.step == None) step = 1; 3533 + else step = CAST(int, s.step); 3534 + if(step == 0) ValueError("slice step cannot be zero"); 3535 + if(step > 0){ 3536 + if(s.start == None){ 3537 + start = 0; 3538 + }else{ 3539 + start = CAST(int, s.start); 3540 + if(start < 0) start += length; 3541 + start = clip(start, 0, length); 3542 + } 3543 + if(s.stop == None){ 3544 + stop = length; 3545 + }else{ 3546 + stop = CAST(int, s.stop); 3547 + if(stop < 0) stop += length; 3548 + stop = clip(stop, 0, length); 3549 + } 3550 + }else{ 3551 + if(s.start == None){ 3552 + start = length - 1; 3553 + }else{ 3554 + start = CAST(int, s.start); 3555 + if(start < 0) start += length; 3556 + start = clip(start, -1, length - 1); 3557 + } 3558 + if(s.stop == None){ 3559 + stop = -1; 3560 + }else{ 3561 + stop = CAST(int, s.stop); 3562 + if(stop < 0) stop += length; 3563 + stop = clip(stop, -1, length - 1); 3564 + } 3565 + } 3566 + } 3567 + 3568 + inline i64 VM::hash(PyObject* obj){ 3569 + if (is_non_tagged_type(obj, tp_str)) return CAST(Str&, obj).hash(); 3570 + if (is_int(obj)) return CAST(i64, obj); 3571 + if (is_non_tagged_type(obj, tp_tuple)) { 3572 + i64 x = 1000003; 3573 + const Tuple& items = CAST(Tuple&, obj); 3574 + for (int i=0; i<items.size(); i++) { 3575 + i64 y = hash(items[i]); 3576 + // recommended by Github Copilot 3577 + x = x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2)); 3578 + } 3579 + return x; 3580 + } 3581 + if (is_non_tagged_type(obj, tp_type)) return BITS(obj); 3582 + if (is_non_tagged_type(obj, tp_iterator)) return BITS(obj); 3583 + if (is_non_tagged_type(obj, tp_bool)) return _CAST(bool, obj) ? 1 : 0; 3584 + if (is_float(obj)){ 3585 + f64 val = CAST(f64, obj); 3586 + return (i64)std::hash<f64>()(val); 3587 + } 3588 + TypeError("unhashable type: " + OBJ_NAME(_t(obj)).escape()); 3589 + return 0; 3590 + } 3591 + 3592 + inline PyObject* VM::asRepr(PyObject* obj){ 3593 + return call_method(obj, __repr__); 3594 + } 3595 + 3596 + inline PyObject* VM::format(Str spec, PyObject* obj){ 3597 + if(spec.empty()) return asStr(obj); 3598 + char type; 3599 + switch(spec.end()[-1]){ 3600 + case 'f': case 'd': case 's': 3601 + type = spec.end()[-1]; 3602 + spec = spec.substr(0, spec.length() - 1); 3603 + break; 3604 + default: type = ' '; break; 3605 + } 3606 + 3607 + char pad_c = ' '; 3608 + if(spec[0] == '0'){ 3609 + pad_c = '0'; 3610 + spec = spec.substr(1); 3611 + } 3612 + char align; 3613 + if(spec[0] == '>'){ 3614 + align = '>'; 3615 + spec = spec.substr(1); 3616 + }else if(spec[0] == '<'){ 3617 + align = '<'; 3618 + spec = spec.substr(1); 3619 + }else{ 3620 + if(is_int(obj) || is_float(obj)) align = '>'; 3621 + else align = '<'; 3622 + } 3623 + 3624 + int dot = spec.index("."); 3625 + int width, precision; 3626 + try{ 3627 + if(dot >= 0){ 3628 + width = Number::stoi(spec.substr(0, dot).str()); 3629 + precision = Number::stoi(spec.substr(dot+1).str()); 3630 + }else{ 3631 + width = Number::stoi(spec.str()); 3632 + precision = -1; 3633 + } 3634 + }catch(...){ 3635 + ValueError("invalid format specifer"); 3636 + } 3637 + 3638 + if(type != 'f' && dot >= 0) ValueError("precision not allowed in the format specifier"); 3639 + Str ret; 3640 + if(type == 'f'){ 3641 + f64 val = num_to_float(obj); 3642 + if(precision < 0) precision = 6; 3643 + std::stringstream ss; 3644 + ss << std::fixed << std::setprecision(precision) << val; 3645 + ret = ss.str(); 3646 + }else if(type == 'd'){ 3647 + ret = std::to_string(CAST(i64, obj)); 3648 + }else if(type == 's'){ 3649 + ret = CAST(Str&, obj); 3650 + }else{ 3651 + ret = CAST(Str&, asStr(obj)); 3652 + } 3653 + if(width > ret.length()){ 3654 + int pad = width - ret.length(); 3655 + std::string padding(pad, pad_c); 3656 + if(align == '>') ret = padding.c_str() + ret; 3657 + else ret = ret + padding.c_str(); 3658 + } 3659 + return VAR(ret); 3660 + } 3661 + 3662 + inline PyObject* VM::new_module(StrName name) { 3663 + PyObject* obj = heap._new<DummyModule>(tp_module, DummyModule()); 3664 + obj->attr().set(__name__, VAR(name.sv())); 3665 + // we do not allow override in order to avoid memory leak 3666 + // it is because Module objects are not garbage collected 3667 + if(_modules.contains(name)) FATAL_ERROR(); 3668 + _modules.set(name, obj); 3669 + return obj; 3670 + } 3671 + 3672 + inline std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){ 3673 + std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg); 3674 + switch(byte.op){ 3675 + case OP_LOAD_CONST: 3676 + if(vm != nullptr){ 3677 + argStr += fmt(" (", CAST(Str, vm->asRepr(co->consts[byte.arg])), ")"); 3678 + } 3679 + break; 3680 + case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_LOAD_NONLOCAL: case OP_STORE_GLOBAL: 3681 + case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR: 3682 + case OP_IMPORT_NAME: case OP_BEGIN_CLASS: 3683 + case OP_DELETE_GLOBAL: 3684 + argStr += fmt(" (", StrName(byte.arg).sv(), ")"); 3685 + break; 3686 + case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST: 3687 + argStr += fmt(" (", co->varnames[byte.arg].sv(), ")"); 3688 + break; 3689 + case OP_BINARY_OP: 3690 + argStr += fmt(" (", BINARY_SPECIAL_METHODS[byte.arg], ")"); 3691 + break; 3692 + case OP_LOAD_FUNCTION: 3693 + argStr += fmt(" (", co->func_decls[byte.arg]->code->name, ")"); 3694 + break; 3695 + } 3696 + return argStr; 3697 + } 3698 + 3699 + inline Str VM::disassemble(CodeObject_ co){ 3700 + auto pad = [](const Str& s, const int n){ 3701 + if(s.length() >= n) return s.substr(0, n); 3702 + return s + std::string(n - s.length(), ' '); 3703 + }; 3704 + 3705 + std::vector<int> jumpTargets; 3706 + for(auto byte : co->codes){ 3707 + if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE){ 3708 + jumpTargets.push_back(byte.arg); 3709 + } 3710 + } 3711 + std::stringstream ss; 3712 + int prev_line = -1; 3713 + for(int i=0; i<co->codes.size(); i++){ 3714 + const Bytecode& byte = co->codes[i]; 3715 + Str line = std::to_string(co->lines[i]); 3716 + if(co->lines[i] == prev_line) line = ""; 3717 + else{ 3718 + if(prev_line != -1) ss << "\n"; 3719 + prev_line = co->lines[i]; 3720 + } 3721 + 3722 + std::string pointer; 3723 + if(std::find(jumpTargets.begin(), jumpTargets.end(), i) != jumpTargets.end()){ 3724 + pointer = "-> "; 3725 + }else{ 3726 + pointer = " "; 3727 + } 3728 + ss << pad(line, 8) << pointer << pad(std::to_string(i), 3); 3729 + ss << " " << pad(OP_NAMES[byte.op], 20) << " "; 3730 + // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5); 3731 + std::string argStr = _opcode_argstr(this, byte, co.get()); 3732 + ss << pad(argStr, 40); // may overflow 3733 + ss << co->blocks[byte.block].type; 3734 + if(i != co->codes.size() - 1) ss << '\n'; 3735 + } 3736 + 3737 + for(auto& decl: co->func_decls){ 3738 + ss << "\n\n" << "Disassembly of " << decl->code->name << ":\n"; 3739 + ss << disassemble(decl->code); 3740 + } 3741 + ss << "\n"; 3742 + return Str(ss.str()); 3743 + } 3744 + 3745 + inline void VM::_log_s_data(const char* title) { 3746 + if(!_initialized) return; 3747 + if(callstack.empty()) return; 3748 + std::stringstream ss; 3749 + if(title) ss << title << " | "; 3750 + std::map<PyObject**, int> sp_bases; 3751 + for(Frame& f: callstack.data()){ 3752 + if(f._sp_base == nullptr) FATAL_ERROR(); 3753 + sp_bases[f._sp_base] += 1; 3754 + } 3755 + FrameId frame = top_frame(); 3756 + int line = frame->co->lines[frame->_ip]; 3757 + ss << frame->co->name << ":" << line << " ["; 3758 + for(PyObject** p=s_data.begin(); p!=s_data.end(); p++){ 3759 + ss << std::string(sp_bases[p], '|'); 3760 + if(sp_bases[p] > 0) ss << " "; 3761 + PyObject* obj = *p; 3762 + if(obj == nullptr) ss << "(nil)"; 3763 + else if(obj == PY_BEGIN_CALL) ss << "BEGIN_CALL"; 3764 + else if(obj == PY_NULL) ss << "NULL"; 3765 + else if(is_int(obj)) ss << CAST(i64, obj); 3766 + else if(is_float(obj)) ss << CAST(f64, obj); 3767 + else if(is_type(obj, tp_str)) ss << CAST(Str, obj).escape(); 3768 + else if(obj == None) ss << "None"; 3769 + else if(obj == True) ss << "True"; 3770 + else if(obj == False) ss << "False"; 3771 + else if(is_type(obj, tp_function)){ 3772 + auto& f = CAST(Function&, obj); 3773 + ss << f.decl->code->name << "(...)"; 3774 + } else if(is_type(obj, tp_type)){ 3775 + Type t = OBJ_GET(Type, obj); 3776 + ss << "<class " + _all_types[t].name.escape() + ">"; 3777 + } else if(is_type(obj, tp_list)){ 3778 + auto& t = CAST(List&, obj); 3779 + ss << "list(size=" << t.size() << ")"; 3780 + } else if(is_type(obj, tp_tuple)){ 3781 + auto& t = CAST(Tuple&, obj); 3782 + ss << "tuple(size=" << t.size() << ")"; 3783 + } else ss << "(" << obj_type_name(this, obj->type) << ")"; 3784 + ss << ", "; 3785 + } 3786 + std::string output = ss.str(); 3787 + if(!s_data.empty()) { 3788 + output.pop_back(); output.pop_back(); 3789 + } 3790 + output.push_back(']'); 3791 + Bytecode byte = frame->co->codes[frame->_ip]; 3792 + std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, byte, frame->co) << std::endl; 3793 + } 3794 + 3795 + inline void VM::init_builtin_types(){ 3796 + _all_types.push_back({heap._new<Type>(Type(1), Type(0)), -1, "object"}); 3797 + _all_types.push_back({heap._new<Type>(Type(1), Type(1)), 0, "type"}); 3798 + tp_object = 0; tp_type = 1; 3799 + 3800 + tp_int = _new_type_object("int"); 3801 + tp_float = _new_type_object("float"); 3802 + if(tp_int.index != kTpIntIndex || tp_float.index != kTpFloatIndex) FATAL_ERROR(); 3803 + 3804 + tp_bool = _new_type_object("bool"); 3805 + tp_str = _new_type_object("str"); 3806 + tp_list = _new_type_object("list"); 3807 + tp_tuple = _new_type_object("tuple"); 3808 + tp_slice = _new_type_object("slice"); 3809 + tp_range = _new_type_object("range"); 3810 + tp_module = _new_type_object("module"); 3811 + tp_function = _new_type_object("function"); 3812 + tp_native_func = _new_type_object("native_func"); 3813 + tp_iterator = _new_type_object("iterator"); 3814 + tp_bound_method = _new_type_object("bound_method"); 3815 + tp_super = _new_type_object("super"); 3816 + tp_exception = _new_type_object("Exception"); 3817 + tp_bytes = _new_type_object("bytes"); 3818 + tp_mappingproxy = _new_type_object("mappingproxy"); 3819 + 3820 + this->None = heap._new<Dummy>(_new_type_object("NoneType"), {}); 3821 + this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {}); 3822 + this->True = heap._new<Dummy>(tp_bool, {}); 3823 + this->False = heap._new<Dummy>(tp_bool, {}); 3824 + this->StopIteration = heap._new<Dummy>(_new_type_object("StopIterationType"), {}); 3825 + 3826 + this->builtins = new_module("builtins"); 3827 + this->_main = new_module("__main__"); 3828 + 3829 + // setup public types 3830 + builtins->attr().set("type", _t(tp_type)); 3831 + builtins->attr().set("object", _t(tp_object)); 3832 + builtins->attr().set("bool", _t(tp_bool)); 3833 + builtins->attr().set("int", _t(tp_int)); 3834 + builtins->attr().set("float", _t(tp_float)); 3835 + builtins->attr().set("str", _t(tp_str)); 3836 + builtins->attr().set("list", _t(tp_list)); 3837 + builtins->attr().set("tuple", _t(tp_tuple)); 3838 + builtins->attr().set("range", _t(tp_range)); 3839 + builtins->attr().set("bytes", _t(tp_bytes)); 3840 + builtins->attr().set("StopIteration", StopIteration); 3841 + builtins->attr().set("slice", _t(tp_slice)); 3842 + 3843 + post_init(); 3844 + for(int i=0; i<_all_types.size(); i++){ 3845 + _all_types[i].obj->attr()._try_perfect_rehash(); 3846 + } 3847 + for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash(); 3848 + } 3849 + 3850 + inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){ 3851 + bool is_varargs = ARGC == 0xFFFF; 3852 + PyObject** p0; 3853 + PyObject** p1 = s_data._sp - KWARGC*2; 3854 + if(is_varargs){ 3855 + p0 = p1 - 1; 3856 + while(*p0 != PY_BEGIN_CALL) p0--; 3857 + // [BEGIN_CALL, callable, <self>, args..., kwargs...] 3858 + // ^p0 ^p1 ^_sp 3859 + ARGC = p1 - (p0 + 3); 3860 + }else{ 3861 + p0 = p1 - ARGC - 2 - (int)is_varargs; 3862 + // [callable, <self>, args..., kwargs...] 3863 + // ^p0 ^p1 ^_sp 3864 + } 3865 + PyObject* callable = p1[-(ARGC + 2)]; 3866 + bool method_call = p1[-(ARGC + 1)] != PY_NULL; 3867 + 3868 + 3869 + // handle boundmethod, do a patch 3870 + if(is_non_tagged_type(callable, tp_bound_method)){ 3871 + if(method_call) FATAL_ERROR(); 3872 + auto& bm = CAST(BoundMethod&, callable); 3873 + callable = bm.func; // get unbound method 3874 + p1[-(ARGC + 2)] = bm.func; 3875 + p1[-(ARGC + 1)] = bm.self; 3876 + method_call = true; 3877 + // [unbound, self, args..., kwargs...] 3878 + } 3879 + 3880 + ArgsView args(p1 - ARGC - int(method_call), p1); 3881 + 3882 + if(is_non_tagged_type(callable, tp_native_func)){ 3883 + const auto& f = OBJ_GET(NativeFunc, callable); 3884 + if(KWARGC != 0) TypeError("native_func does not accept keyword arguments"); 3885 + PyObject* ret = f(this, args); 3886 + s_data.reset(p0); 3887 + return ret; 3888 + } 3889 + 3890 + ArgsView kwargs(p1, s_data._sp); 3891 + 3892 + if(is_non_tagged_type(callable, tp_function)){ 3893 + // ret is nullptr or a generator 3894 + PyObject* ret = _py_call(p0, callable, args, kwargs); 3895 + // stack resetting is handled by _py_call 3896 + if(ret != nullptr) return ret; 3897 + if(op_call) return PY_OP_CALL; 3898 + return _run_top_frame(); 3899 + } 3900 + 3901 + if(is_non_tagged_type(callable, tp_type)){ 3902 + if(method_call) FATAL_ERROR(); 3903 + // [type, NULL, args..., kwargs...] 3904 + 3905 + // TODO: derived __new__ ? 3906 + PyObject* new_f = callable->attr().try_get(__new__); 3907 + PyObject* obj; 3908 + if(new_f != nullptr){ 3909 + PUSH(new_f); 3910 + PUSH(PY_NULL); 3911 + for(PyObject* obj: args) PUSH(obj); 3912 + for(PyObject* obj: kwargs) PUSH(obj); 3913 + obj = vectorcall(ARGC, KWARGC); 3914 + if(!isinstance(obj, OBJ_GET(Type, callable))) return obj; 3915 + }else{ 3916 + obj = heap.gcnew<DummyInstance>(OBJ_GET(Type, callable), {}); 3917 + } 3918 + PyObject* self; 3919 + callable = get_unbound_method(obj, __init__, &self, false); 3920 + if (self != PY_NULL) { 3921 + // replace `NULL` with `self` 3922 + p1[-(ARGC + 2)] = callable; 3923 + p1[-(ARGC + 1)] = self; 3924 + // [init_f, self, args..., kwargs...] 3925 + vectorcall(ARGC, KWARGC); 3926 + // We just discard the return value of `__init__` 3927 + // in cpython it raises a TypeError if the return value is not None 3928 + }else{ 3929 + // manually reset the stack 3930 + s_data.reset(p0); 3931 + } 3932 + return obj; 3933 + } 3934 + 3935 + // handle `__call__` overload 3936 + PyObject* self; 3937 + PyObject* call_f = get_unbound_method(callable, __call__, &self, false); 3938 + if(self != PY_NULL){ 3939 + p1[-(ARGC + 2)] = call_f; 3940 + p1[-(ARGC + 1)] = self; 3941 + // [call_f, self, args..., kwargs...] 3942 + return vectorcall(ARGC, KWARGC, false); 3943 + } 3944 + TypeError(OBJ_NAME(_t(callable)).escape() + " object is not callable"); 3945 + return nullptr; 3946 + } 3947 + 3948 + inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args, ArgsView kwargs){ 3949 + // callable must be a `function` object 3950 + if(s_data.is_overflow()) StackOverflowError(); 3951 + 3952 + const Function& fn = CAST(Function&, callable); 3953 + const CodeObject* co = fn.decl->code.get(); 3954 + 3955 + if(args.size() < fn.argc){ 3956 + vm->TypeError(fmt( 3957 + "expected ", 3958 + fn.argc, 3959 + " positional arguments, but got ", 3960 + args.size(), 3961 + " (", fn.decl->code->name, ')' 3962 + )); 3963 + } 3964 + 3965 + // if this function is simple, a.k.a, no kwargs and no *args and not a generator 3966 + // we can use a fast path to avoid using buffer copy 3967 + if(fn.is_simple){ 3968 + if(args.size() > fn.argc) TypeError("too many positional arguments"); 3969 + int spaces = co->varnames.size() - fn.argc; 3970 + for(int j=0; j<spaces; j++) PUSH(nullptr); 3971 + callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin())); 3972 + return nullptr; 3973 + } 3974 + 3975 + int i = 0; 3976 + static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES]; 3977 + 3978 + // prepare args 3979 + for(int index: fn.decl->args) buffer[index] = args[i++]; 3980 + // set extra varnames to nullptr 3981 + for(int j=i; j<co->varnames.size(); j++) buffer[j] = nullptr; 3982 + 3983 + // prepare kwdefaults 3984 + for(auto& kv: fn.decl->kwargs) buffer[kv.key] = kv.value; 3985 + 3986 + // handle *args 3987 + if(fn.decl->starred_arg != -1){ 3988 + List vargs; // handle *args 3989 + while(i < args.size()) vargs.push_back(args[i++]); 3990 + buffer[fn.decl->starred_arg] = VAR(Tuple(std::move(vargs))); 3991 + }else{ 3992 + // kwdefaults override 3993 + for(auto& kv: fn.decl->kwargs){ 3994 + if(i < args.size()){ 3995 + buffer[kv.key] = args[i++]; 3996 + }else{ 3997 + break; 3998 + } 3999 + } 4000 + if(i < args.size()) TypeError(fmt("too many arguments", " (", fn.decl->code->name, ')')); 4001 + } 4002 + 4003 + for(int i=0; i<kwargs.size(); i+=2){ 4004 + StrName key = CAST(int, kwargs[i]); 4005 + int index = co->varnames_inv.try_get(key); 4006 + if(index<0) TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()")); 4007 + buffer[index] = kwargs[i+1]; 4008 + } 4009 + 4010 + s_data.reset(p0); 4011 + if(co->is_generator){ 4012 + PyObject* ret = PyIter(Generator( 4013 + this, 4014 + Frame(&s_data, nullptr, co, fn._module, callable), 4015 + ArgsView(buffer, buffer + co->varnames.size()) 4016 + )); 4017 + return ret; 4018 + } 4019 + 4020 + // copy buffer to stack 4021 + for(int i=0; i<co->varnames.size(); i++) PUSH(buffer[i]); 4022 + callstack.emplace(&s_data, p0, co, fn._module, callable); 4023 + return nullptr; 4024 + } 4025 + 4026 + // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance 4027 + inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err){ 4028 + PyObject* objtype = _t(obj); 4029 + // handle super() proxy 4030 + if(is_non_tagged_type(obj, tp_super)){ 4031 + const Super& super = OBJ_GET(Super, obj); 4032 + obj = super.first; 4033 + objtype = _t(super.second); 4034 + } 4035 + PyObject* cls_var = find_name_in_mro(objtype, name); 4036 + if(cls_var != nullptr){ 4037 + // handle descriptor 4038 + PyObject* descr_get = _t(cls_var)->attr().try_get(__get__); 4039 + if(descr_get != nullptr) return call_method(cls_var, descr_get, obj); 4040 + } 4041 + // handle instance __dict__ 4042 + if(!is_tagged(obj) && obj->is_attr_valid()){ 4043 + PyObject* val = obj->attr().try_get(name); 4044 + if(val != nullptr) return val; 4045 + } 4046 + if(cls_var != nullptr){ 4047 + // bound method is non-data descriptor 4048 + if(is_non_tagged_type(cls_var, tp_function) || is_non_tagged_type(cls_var, tp_native_func)){ 4049 + return VAR(BoundMethod(obj, cls_var)); 4050 + } 4051 + return cls_var; 4052 + } 4053 + if(throw_err) AttributeError(obj, name); 4054 + return nullptr; 4055 + } 4056 + 4057 + // used by OP_LOAD_METHOD 4058 + // try to load a unbound method (fallback to `getattr` if not found) 4059 + inline PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err, bool fallback){ 4060 + *self = PY_NULL; 4061 + PyObject* objtype = _t(obj); 4062 + // handle super() proxy 4063 + if(is_non_tagged_type(obj, tp_super)){ 4064 + const Super& super = OBJ_GET(Super, obj); 4065 + obj = super.first; 4066 + objtype = _t(super.second); 4067 + } 4068 + PyObject* cls_var = find_name_in_mro(objtype, name); 4069 + 4070 + if(fallback){ 4071 + if(cls_var != nullptr){ 4072 + // handle descriptor 4073 + PyObject* descr_get = _t(cls_var)->attr().try_get(__get__); 4074 + if(descr_get != nullptr) return call_method(cls_var, descr_get, obj); 4075 + } 4076 + // handle instance __dict__ 4077 + if(!is_tagged(obj) && obj->is_attr_valid()){ 4078 + PyObject* val = obj->attr().try_get(name); 4079 + if(val != nullptr) return val; 4080 + } 4081 + } 4082 + 4083 + if(cls_var != nullptr){ 4084 + if(is_non_tagged_type(cls_var, tp_function) || is_non_tagged_type(cls_var, tp_native_func)){ 4085 + *self = obj; 4086 + } 4087 + return cls_var; 4088 + } 4089 + if(throw_err) AttributeError(obj, name); 4090 + return nullptr; 4091 + } 4092 + 4093 + inline void VM::setattr(PyObject* obj, StrName name, PyObject* value){ 4094 + PyObject* objtype = _t(obj); 4095 + // handle super() proxy 4096 + if(is_non_tagged_type(obj, tp_super)){ 4097 + Super& super = OBJ_GET(Super, obj); 4098 + obj = super.first; 4099 + objtype = _t(super.second); 4100 + } 4101 + PyObject* cls_var = find_name_in_mro(objtype, name); 4102 + if(cls_var != nullptr){ 4103 + // handle descriptor 4104 + PyObject* cls_var_t = _t(cls_var); 4105 + if(cls_var_t->attr().contains(__get__)){ 4106 + PyObject* descr_set = cls_var_t->attr().try_get(__set__); 4107 + if(descr_set != nullptr){ 4108 + call_method(cls_var, descr_set, obj, value); 4109 + }else{ 4110 + TypeError(fmt("readonly attribute: ", name.escape())); 4111 + } 4112 + return; 4113 + } 4114 + } 4115 + // handle instance __dict__ 4116 + if(is_tagged(obj) || !obj->is_attr_valid()) TypeError("cannot set attribute"); 4117 + obj->attr().set(name, value); 4118 + } 4119 + 4120 + template<int ARGC> 4121 + void VM::bind_method(PyObject* obj, Str name, NativeFuncC fn) { 4122 + check_non_tagged_type(obj, tp_type); 4123 + obj->attr().set(name, VAR(NativeFunc(fn, ARGC, true))); 4124 + } 4125 + 4126 + template<int ARGC> 4127 + void VM::bind_func(PyObject* obj, Str name, NativeFuncC fn) { 4128 + obj->attr().set(name, VAR(NativeFunc(fn, ARGC, false))); 4129 + } 4130 + 4131 + inline void VM::_error(Exception e){ 4132 + if(callstack.empty()){ 4133 + e.is_re = false; 4134 + throw e; 4135 + } 4136 + PUSH(VAR(e)); 4137 + _raise(); 4138 + } 4139 + 4140 + inline void ManagedHeap::mark() { 4141 + for(PyObject* obj: _no_gc) OBJ_MARK(obj); 4142 + for(auto& frame : vm->callstack.data()) frame._gc_mark(); 4143 + for(PyObject* obj: vm->s_data) if(obj!=nullptr) OBJ_MARK(obj); 4144 + if(vm->_gc_marker_ex != nullptr) vm->_gc_marker_ex(vm); 4145 + } 4146 + 4147 + inline Str obj_type_name(VM *vm, Type type){ 4148 + return vm->_all_types[type].name; 4149 + } 4150 + 4151 + #undef PY_VAR_INT 4152 + #undef PY_VAR_FLOAT 4153 + 4154 + } // namespace pkpy 4155 + 4156 + 4157 + namespace pkpy{ 4158 + 4159 + inline PyObject* VM::_run_top_frame(){ 4160 + FrameId frame = top_frame(); 4161 + const int base_id = frame.index; 4162 + bool need_raise = false; 4163 + 4164 + // shared registers 4165 + PyObject *_0, *_1, *_2; 4166 + StrName _name; 4167 + 4168 + while(true){ 4169 + #if DEBUG_EXTRA_CHECK 4170 + if(frame.index < base_id) FATAL_ERROR(); 4171 + #endif 4172 + try{ 4173 + if(need_raise){ need_raise = false; _raise(); } 4174 + // if(s_data.is_overflow()) StackOverflowError(); 4175 + /**********************************************************************/ 4176 + /* NOTE: 4177 + * Be aware of accidental gc! 4178 + * DO NOT leave any strong reference of PyObject* in the C stack 4179 + */ 4180 + { 4181 + #define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; } 4182 + __NEXT_FRAME: 4183 + Bytecode byte = frame->next_bytecode(); 4184 + // cache 4185 + const CodeObject* co = frame->co; 4186 + const auto& co_consts = co->consts; 4187 + const auto& co_blocks = co->blocks; 4188 + 4189 + #if PK_ENABLE_COMPUTED_GOTO 4190 + static void* OP_LABELS[] = { 4191 + #define OPCODE(name) &&CASE_OP_##name, 4192 + #ifdef OPCODE 4193 + 4194 + /**************************/ 4195 + OPCODE(NO_OP) 4196 + /**************************/ 4197 + OPCODE(POP_TOP) 4198 + OPCODE(DUP_TOP) 4199 + OPCODE(ROT_TWO) 4200 + OPCODE(PRINT_EXPR) 4201 + /**************************/ 4202 + OPCODE(LOAD_CONST) 4203 + OPCODE(LOAD_NONE) 4204 + OPCODE(LOAD_TRUE) 4205 + OPCODE(LOAD_FALSE) 4206 + OPCODE(LOAD_INTEGER) 4207 + OPCODE(LOAD_ELLIPSIS) 4208 + OPCODE(LOAD_FUNCTION) 4209 + OPCODE(LOAD_NULL) 4210 + /**************************/ 4211 + OPCODE(LOAD_FAST) 4212 + OPCODE(LOAD_NAME) 4213 + OPCODE(LOAD_NONLOCAL) 4214 + OPCODE(LOAD_GLOBAL) 4215 + OPCODE(LOAD_ATTR) 4216 + OPCODE(LOAD_METHOD) 4217 + OPCODE(LOAD_SUBSCR) 4218 + 4219 + OPCODE(STORE_FAST) 4220 + OPCODE(STORE_NAME) 4221 + OPCODE(STORE_GLOBAL) 4222 + OPCODE(STORE_ATTR) 4223 + OPCODE(STORE_SUBSCR) 4224 + 4225 + OPCODE(DELETE_FAST) 4226 + OPCODE(DELETE_NAME) 4227 + OPCODE(DELETE_GLOBAL) 4228 + OPCODE(DELETE_ATTR) 4229 + OPCODE(DELETE_SUBSCR) 4230 + /**************************/ 4231 + OPCODE(BUILD_LIST) 4232 + OPCODE(BUILD_DICT) 4233 + OPCODE(BUILD_SET) 4234 + OPCODE(BUILD_SLICE) 4235 + OPCODE(BUILD_TUPLE) 4236 + OPCODE(BUILD_STRING) 4237 + /**************************/ 4238 + OPCODE(BINARY_OP) 4239 + OPCODE(BINARY_ADD) 4240 + OPCODE(BINARY_SUB) 4241 + OPCODE(BINARY_MUL) 4242 + OPCODE(BINARY_FLOORDIV) 4243 + OPCODE(BINARY_MOD) 4244 + 4245 + OPCODE(COMPARE_LT) 4246 + OPCODE(COMPARE_LE) 4247 + OPCODE(COMPARE_EQ) 4248 + OPCODE(COMPARE_NE) 4249 + OPCODE(COMPARE_GT) 4250 + OPCODE(COMPARE_GE) 4251 + 4252 + OPCODE(BITWISE_LSHIFT) 4253 + OPCODE(BITWISE_RSHIFT) 4254 + OPCODE(BITWISE_AND) 4255 + OPCODE(BITWISE_OR) 4256 + OPCODE(BITWISE_XOR) 4257 + 4258 + OPCODE(IS_OP) 4259 + OPCODE(CONTAINS_OP) 4260 + /**************************/ 4261 + OPCODE(JUMP_ABSOLUTE) 4262 + OPCODE(POP_JUMP_IF_FALSE) 4263 + OPCODE(JUMP_IF_TRUE_OR_POP) 4264 + OPCODE(JUMP_IF_FALSE_OR_POP) 4265 + OPCODE(LOOP_CONTINUE) 4266 + OPCODE(LOOP_BREAK) 4267 + OPCODE(GOTO) 4268 + /**************************/ 4269 + OPCODE(BEGIN_CALL) 4270 + OPCODE(CALL) 4271 + OPCODE(RETURN_VALUE) 4272 + OPCODE(YIELD_VALUE) 4273 + /**************************/ 4274 + OPCODE(LIST_APPEND) 4275 + OPCODE(DICT_ADD) 4276 + OPCODE(SET_ADD) 4277 + /**************************/ 4278 + OPCODE(UNARY_NEGATIVE) 4279 + OPCODE(UNARY_NOT) 4280 + /**************************/ 4281 + OPCODE(GET_ITER) 4282 + OPCODE(FOR_ITER) 4283 + /**************************/ 4284 + OPCODE(IMPORT_NAME) 4285 + OPCODE(IMPORT_STAR) 4286 + /**************************/ 4287 + OPCODE(UNPACK_SEQUENCE) 4288 + OPCODE(UNPACK_EX) 4289 + OPCODE(UNPACK_UNLIMITED) 4290 + /**************************/ 4291 + OPCODE(BEGIN_CLASS) 4292 + OPCODE(END_CLASS) 4293 + OPCODE(STORE_CLASS_ATTR) 4294 + /**************************/ 4295 + OPCODE(WITH_ENTER) 4296 + OPCODE(WITH_EXIT) 4297 + /**************************/ 4298 + OPCODE(ASSERT) 4299 + OPCODE(EXCEPTION_MATCH) 4300 + OPCODE(RAISE) 4301 + OPCODE(RE_RAISE) 4302 + /**************************/ 4303 + OPCODE(SETUP_DOCSTRING) 4304 + OPCODE(FORMAT_STRING) 4305 + #endif 4306 + #undef OPCODE 4307 + }; 4308 + 4309 + #define DISPATCH() { byte = frame->next_bytecode(); goto *OP_LABELS[byte.op];} 4310 + #define TARGET(op) CASE_OP_##op: 4311 + goto *OP_LABELS[byte.op]; 4312 + 4313 + #else 4314 + #define TARGET(op) case OP_##op: 4315 + #define DISPATCH() { byte = frame->next_bytecode(); goto __NEXT_STEP;} 4316 + 4317 + __NEXT_STEP:; 4318 + #if DEBUG_CEVAL_STEP 4319 + _log_s_data(); 4320 + #endif 4321 + #if DEBUG_CEVAL_STEP_MIN 4322 + std::cout << OP_NAMES[byte.op] << std::endl; 4323 + #endif 4324 + switch (byte.op) 4325 + { 4326 + #endif 4327 + TARGET(NO_OP) DISPATCH(); 4328 + /*****************************************/ 4329 + TARGET(POP_TOP) POP(); DISPATCH(); 4330 + TARGET(DUP_TOP) PUSH(TOP()); DISPATCH(); 4331 + TARGET(ROT_TWO) std::swap(TOP(), SECOND()); DISPATCH(); 4332 + TARGET(PRINT_EXPR) 4333 + if(TOP() != None){ 4334 + _stdout(this, CAST(Str&, asRepr(TOP()))); 4335 + _stdout(this, "\n"); 4336 + } 4337 + POP(); 4338 + DISPATCH(); 4339 + /*****************************************/ 4340 + TARGET(LOAD_CONST) 4341 + heap._auto_collect(); 4342 + PUSH(co_consts[byte.arg]); 4343 + DISPATCH(); 4344 + TARGET(LOAD_NONE) PUSH(None); DISPATCH(); 4345 + TARGET(LOAD_TRUE) PUSH(True); DISPATCH(); 4346 + TARGET(LOAD_FALSE) PUSH(False); DISPATCH(); 4347 + TARGET(LOAD_INTEGER) PUSH(VAR(byte.arg)); DISPATCH(); 4348 + TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH(); 4349 + TARGET(LOAD_FUNCTION) { 4350 + FuncDecl_ decl = co->func_decls[byte.arg]; 4351 + bool is_simple = decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator; 4352 + int argc = decl->args.size(); 4353 + PyObject* obj; 4354 + if(decl->nested){ 4355 + obj = VAR(Function({decl, is_simple, argc, frame->_module, frame->_locals.to_namedict()})); 4356 + }else{ 4357 + obj = VAR(Function({decl, is_simple, argc, frame->_module})); 4358 + } 4359 + PUSH(obj); 4360 + } DISPATCH(); 4361 + TARGET(LOAD_NULL) PUSH(PY_NULL); DISPATCH(); 4362 + /*****************************************/ 4363 + TARGET(LOAD_FAST) { 4364 + heap._auto_collect(); 4365 + _0 = frame->_locals[byte.arg]; 4366 + if(_0 == nullptr) vm->NameError(co->varnames[byte.arg]); 4367 + PUSH(_0); 4368 + } DISPATCH(); 4369 + TARGET(LOAD_NAME) 4370 + heap._auto_collect(); 4371 + _name = StrName(byte.arg); 4372 + _0 = frame->_locals.try_get(_name); 4373 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4374 + _0 = frame->f_closure_try_get(_name); 4375 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4376 + _0 = frame->f_globals().try_get(_name); 4377 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4378 + _0 = vm->builtins->attr().try_get(_name); 4379 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4380 + vm->NameError(_name); 4381 + DISPATCH(); 4382 + TARGET(LOAD_NONLOCAL) { 4383 + heap._auto_collect(); 4384 + _name = StrName(byte.arg); 4385 + _0 = frame->f_closure_try_get(_name); 4386 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4387 + _0 = frame->f_globals().try_get(_name); 4388 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4389 + _0 = vm->builtins->attr().try_get(_name); 4390 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4391 + vm->NameError(_name); 4392 + DISPATCH(); 4393 + } DISPATCH(); 4394 + TARGET(LOAD_GLOBAL) 4395 + heap._auto_collect(); 4396 + _name = StrName(byte.arg); 4397 + _0 = frame->f_globals().try_get(_name); 4398 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4399 + _0 = vm->builtins->attr().try_get(_name); 4400 + if(_0 != nullptr) { PUSH(_0); DISPATCH(); } 4401 + vm->NameError(_name); 4402 + DISPATCH(); 4403 + TARGET(LOAD_ATTR) 4404 + TOP() = getattr(TOP(), StrName(byte.arg)); 4405 + DISPATCH(); 4406 + TARGET(LOAD_METHOD) 4407 + TOP() = get_unbound_method(TOP(), StrName(byte.arg), &_0, true, true); 4408 + PUSH(_0); 4409 + DISPATCH(); 4410 + TARGET(LOAD_SUBSCR) 4411 + _1 = POPX(); 4412 + _0 = TOP(); 4413 + TOP() = call_method(_0, __getitem__, _1); 4414 + DISPATCH(); 4415 + TARGET(STORE_FAST) 4416 + frame->_locals[byte.arg] = POPX(); 4417 + DISPATCH(); 4418 + TARGET(STORE_NAME) 4419 + _name = StrName(byte.arg); 4420 + _0 = POPX(); 4421 + if(frame->_callable != nullptr){ 4422 + bool ok = frame->_locals.try_set(_name, _0); 4423 + if(!ok) vm->NameError(_name); 4424 + }else{ 4425 + frame->f_globals().set(_name, _0); 4426 + } 4427 + DISPATCH(); 4428 + TARGET(STORE_GLOBAL) 4429 + frame->f_globals().set(StrName(byte.arg), POPX()); 4430 + DISPATCH(); 4431 + TARGET(STORE_ATTR) { 4432 + _0 = TOP(); // a 4433 + _1 = SECOND(); // val 4434 + setattr(_0, StrName(byte.arg), _1); 4435 + STACK_SHRINK(2); 4436 + } DISPATCH(); 4437 + TARGET(STORE_SUBSCR) 4438 + _2 = POPX(); // b 4439 + _1 = POPX(); // a 4440 + _0 = POPX(); // val 4441 + call_method(_1, __setitem__, _2, _0); 4442 + DISPATCH(); 4443 + TARGET(DELETE_FAST) 4444 + _0 = frame->_locals[byte.arg]; 4445 + if(_0 == nullptr) vm->NameError(co->varnames[byte.arg]); 4446 + frame->_locals[byte.arg] = nullptr; 4447 + DISPATCH(); 4448 + TARGET(DELETE_NAME) 4449 + _name = StrName(byte.arg); 4450 + if(frame->_callable != nullptr){ 4451 + if(!frame->_locals.contains(_name)) vm->NameError(_name); 4452 + frame->_locals.erase(_name); 4453 + }else{ 4454 + if(!frame->f_globals().contains(_name)) vm->NameError(_name); 4455 + frame->f_globals().erase(_name); 4456 + } 4457 + DISPATCH(); 4458 + TARGET(DELETE_GLOBAL) 4459 + _name = StrName(byte.arg); 4460 + if(frame->f_globals().contains(_name)){ 4461 + frame->f_globals().erase(_name); 4462 + }else{ 4463 + NameError(_name); 4464 + } 4465 + DISPATCH(); 4466 + TARGET(DELETE_ATTR) 4467 + _0 = POPX(); 4468 + _name = StrName(byte.arg); 4469 + if(!_0->is_attr_valid()) TypeError("cannot delete attribute"); 4470 + if(!_0->attr().contains(_name)) AttributeError(_0, _name); 4471 + _0->attr().erase(_name); 4472 + DISPATCH(); 4473 + TARGET(DELETE_SUBSCR) 4474 + _1 = POPX(); 4475 + _0 = POPX(); 4476 + call_method(_0, __delitem__, _1); 4477 + DISPATCH(); 4478 + /*****************************************/ 4479 + TARGET(BUILD_LIST) 4480 + _0 = VAR(STACK_VIEW(byte.arg).to_list()); 4481 + STACK_SHRINK(byte.arg); 4482 + PUSH(_0); 4483 + DISPATCH(); 4484 + TARGET(BUILD_DICT) { 4485 + PyObject* t = VAR(STACK_VIEW(byte.arg).to_tuple()); 4486 + PyObject* obj = call(builtins->attr(m_dict), t); 4487 + STACK_SHRINK(byte.arg); 4488 + PUSH(obj); 4489 + } DISPATCH(); 4490 + TARGET(BUILD_SET) { 4491 + PyObject* t = VAR(STACK_VIEW(byte.arg).to_tuple()); 4492 + PyObject* obj = call(builtins->attr(m_set), t); 4493 + STACK_SHRINK(byte.arg); 4494 + PUSH(obj); 4495 + } DISPATCH(); 4496 + TARGET(BUILD_SLICE) 4497 + _2 = POPX(); // step 4498 + _1 = POPX(); // stop 4499 + _0 = POPX(); // start 4500 + PUSH(VAR(Slice(_0, _1, _2))); 4501 + DISPATCH(); 4502 + TARGET(BUILD_TUPLE) 4503 + _0 = VAR(STACK_VIEW(byte.arg).to_tuple()); 4504 + STACK_SHRINK(byte.arg); 4505 + PUSH(_0); 4506 + DISPATCH(); 4507 + TARGET(BUILD_STRING) { 4508 + std::stringstream ss; 4509 + auto view = STACK_VIEW(byte.arg); 4510 + for(PyObject* obj : view) ss << CAST(Str&, asStr(obj)); 4511 + STACK_SHRINK(byte.arg); 4512 + PUSH(VAR(ss.str())); 4513 + } DISPATCH(); 4514 + /*****************************************/ 4515 + TARGET(BINARY_OP) 4516 + _1 = POPX(); // b 4517 + _0 = TOP(); // a 4518 + TOP() = call_method(_0, BINARY_SPECIAL_METHODS[byte.arg], _1); 4519 + DISPATCH(); 4520 + 4521 + #define INT_BINARY_OP(op, func) \ 4522 + if(is_both_int(TOP(), SECOND())){ \ 4523 + i64 b = _CAST(i64, TOP()); \ 4524 + i64 a = _CAST(i64, SECOND()); \ 4525 + POP(); \ 4526 + TOP() = VAR(a op b); \ 4527 + }else{ \ 4528 + _1 = POPX(); \ 4529 + _0 = TOP(); \ 4530 + TOP() = call_method(_0, func, _1); \ 4531 + } 4532 + 4533 + TARGET(BINARY_ADD) 4534 + INT_BINARY_OP(+, __add__) 4535 + DISPATCH() 4536 + TARGET(BINARY_SUB) 4537 + INT_BINARY_OP(-, __sub__) 4538 + DISPATCH() 4539 + TARGET(BINARY_MUL) 4540 + INT_BINARY_OP(*, __mul__) 4541 + DISPATCH() 4542 + TARGET(BINARY_FLOORDIV) 4543 + INT_BINARY_OP(/, __floordiv__) 4544 + DISPATCH() 4545 + TARGET(BINARY_MOD) 4546 + INT_BINARY_OP(%, __mod__) 4547 + DISPATCH() 4548 + TARGET(COMPARE_LT) 4549 + INT_BINARY_OP(<, __lt__) 4550 + DISPATCH() 4551 + TARGET(COMPARE_LE) 4552 + INT_BINARY_OP(<=, __le__) 4553 + DISPATCH() 4554 + TARGET(COMPARE_EQ) 4555 + INT_BINARY_OP(==, __eq__) 4556 + DISPATCH() 4557 + TARGET(COMPARE_NE) 4558 + INT_BINARY_OP(!=, __ne__) 4559 + DISPATCH() 4560 + TARGET(COMPARE_GT) 4561 + INT_BINARY_OP(>, __gt__) 4562 + DISPATCH() 4563 + TARGET(COMPARE_GE) 4564 + INT_BINARY_OP(>=, __ge__) 4565 + DISPATCH() 4566 + TARGET(BITWISE_LSHIFT) 4567 + INT_BINARY_OP(<<, __lshift__) 4568 + DISPATCH() 4569 + TARGET(BITWISE_RSHIFT) 4570 + INT_BINARY_OP(>>, __rshift__) 4571 + DISPATCH() 4572 + TARGET(BITWISE_AND) 4573 + INT_BINARY_OP(&, __and__) 4574 + DISPATCH() 4575 + TARGET(BITWISE_OR) 4576 + INT_BINARY_OP(|, __or__) 4577 + DISPATCH() 4578 + TARGET(BITWISE_XOR) 4579 + INT_BINARY_OP(^, __xor__) 4580 + DISPATCH() 4581 + #undef INT_BINARY_OP 4582 + 4583 + TARGET(IS_OP) 4584 + _1 = POPX(); // rhs 4585 + _0 = TOP(); // lhs 4586 + if(byte.arg == 1){ 4587 + TOP() = VAR(_0 != _1); 4588 + }else{ 4589 + TOP() = VAR(_0 == _1); 4590 + } 4591 + DISPATCH(); 4592 + TARGET(CONTAINS_OP) 4593 + // a in b -> b __contains__ a 4594 + _0 = call_method(TOP(), __contains__, SECOND()); 4595 + POP(); 4596 + if(byte.arg == 1){ 4597 + TOP() = VAR(!CAST(bool, _0)); 4598 + }else{ 4599 + TOP() = VAR(CAST(bool, _0)); 4600 + } 4601 + DISPATCH(); 4602 + /*****************************************/ 4603 + TARGET(JUMP_ABSOLUTE) 4604 + frame->jump_abs(byte.arg); 4605 + DISPATCH(); 4606 + TARGET(POP_JUMP_IF_FALSE) 4607 + if(!asBool(POPX())) frame->jump_abs(byte.arg); 4608 + DISPATCH(); 4609 + TARGET(JUMP_IF_TRUE_OR_POP) 4610 + if(asBool(TOP()) == true) frame->jump_abs(byte.arg); 4611 + else POP(); 4612 + DISPATCH(); 4613 + TARGET(JUMP_IF_FALSE_OR_POP) 4614 + if(asBool(TOP()) == false) frame->jump_abs(byte.arg); 4615 + else POP(); 4616 + DISPATCH(); 4617 + TARGET(LOOP_CONTINUE) 4618 + frame->jump_abs(co_blocks[byte.block].start); 4619 + DISPATCH(); 4620 + TARGET(LOOP_BREAK) 4621 + frame->jump_abs_break(co_blocks[byte.block].end); 4622 + DISPATCH(); 4623 + TARGET(GOTO) { 4624 + StrName name(byte.arg); 4625 + int index = co->labels.try_get(name); 4626 + if(index < 0) _error("KeyError", fmt("label ", name.escape(), " not found")); 4627 + frame->jump_abs_break(index); 4628 + } DISPATCH(); 4629 + /*****************************************/ 4630 + TARGET(BEGIN_CALL) 4631 + PUSH(PY_BEGIN_CALL); 4632 + DISPATCH(); 4633 + TARGET(CALL) 4634 + _0 = vectorcall( 4635 + byte.arg & 0xFFFF, // ARGC 4636 + (byte.arg>>16) & 0xFFFF, // KWARGC 4637 + true 4638 + ); 4639 + if(_0 == PY_OP_CALL) DISPATCH_OP_CALL(); 4640 + PUSH(_0); 4641 + DISPATCH(); 4642 + TARGET(RETURN_VALUE) 4643 + _0 = POPX(); 4644 + _pop_frame(); 4645 + if(frame.index == base_id){ // [ frameBase<- ] 4646 + return _0; 4647 + }else{ 4648 + frame = top_frame(); 4649 + PUSH(_0); 4650 + goto __NEXT_FRAME; 4651 + } 4652 + TARGET(YIELD_VALUE) 4653 + return PY_OP_YIELD; 4654 + /*****************************************/ 4655 + TARGET(LIST_APPEND) 4656 + _0 = POPX(); 4657 + CAST(List&, SECOND()).push_back(_0); 4658 + DISPATCH(); 4659 + TARGET(DICT_ADD) { 4660 + _0 = POPX(); 4661 + Tuple& t = CAST(Tuple&, _0); 4662 + call_method(SECOND(), __setitem__, t[0], t[1]); 4663 + } DISPATCH(); 4664 + TARGET(SET_ADD) 4665 + _0 = POPX(); 4666 + call_method(SECOND(), m_add, _0); 4667 + DISPATCH(); 4668 + /*****************************************/ 4669 + TARGET(UNARY_NEGATIVE) 4670 + TOP() = num_negated(TOP()); 4671 + DISPATCH(); 4672 + TARGET(UNARY_NOT) 4673 + TOP() = VAR(!asBool(TOP())); 4674 + DISPATCH(); 4675 + /*****************************************/ 4676 + TARGET(GET_ITER) 4677 + TOP() = asIter(TOP()); 4678 + DISPATCH(); 4679 + TARGET(FOR_ITER) 4680 + _0 = PyIterNext(TOP()); 4681 + if(_0 != StopIteration){ 4682 + PUSH(_0); 4683 + }else{ 4684 + frame->jump_abs_break(co_blocks[byte.block].end); 4685 + } 4686 + DISPATCH(); 4687 + /*****************************************/ 4688 + TARGET(IMPORT_NAME) { 4689 + StrName name(byte.arg); 4690 + PyObject* ext_mod = _modules.try_get(name); 4691 + if(ext_mod == nullptr){ 4692 + Str source; 4693 + auto it = _lazy_modules.find(name); 4694 + if(it == _lazy_modules.end()){ 4695 + Bytes b = _read_file_cwd(fmt(name, ".py")); 4696 + if(!b) _error("ImportError", fmt("module ", name.escape(), " not found")); 4697 + source = Str(b.str()); 4698 + }else{ 4699 + source = it->second; 4700 + _lazy_modules.erase(it); 4701 + } 4702 + CodeObject_ code = compile(source, Str(name.sv())+".py", EXEC_MODE); 4703 + PyObject* new_mod = new_module(name); 4704 + _exec(code, new_mod); 4705 + new_mod->attr()._try_perfect_rehash(); 4706 + PUSH(new_mod); 4707 + }else{ 4708 + PUSH(ext_mod); 4709 + } 4710 + } DISPATCH(); 4711 + TARGET(IMPORT_STAR) { 4712 + PyObject* obj = POPX(); 4713 + for(auto& [name, value]: obj->attr().items()){ 4714 + std::string_view s = name.sv(); 4715 + if(s.empty() || s[0] == '_') continue; 4716 + frame->f_globals().set(name, value); 4717 + } 4718 + }; DISPATCH(); 4719 + /*****************************************/ 4720 + TARGET(UNPACK_SEQUENCE) 4721 + TARGET(UNPACK_EX) { 4722 + auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! 4723 + PyObject* iter = asIter(POPX()); 4724 + for(int i=0; i<byte.arg; i++){ 4725 + PyObject* item = PyIterNext(iter); 4726 + if(item == StopIteration) ValueError("not enough values to unpack"); 4727 + PUSH(item); 4728 + } 4729 + // handle extra items 4730 + if(byte.op == OP_UNPACK_EX){ 4731 + List extras; 4732 + while(true){ 4733 + PyObject* item = PyIterNext(iter); 4734 + if(item == StopIteration) break; 4735 + extras.push_back(item); 4736 + } 4737 + PUSH(VAR(extras)); 4738 + }else{ 4739 + if(PyIterNext(iter) != StopIteration) ValueError("too many values to unpack"); 4740 + } 4741 + } DISPATCH(); 4742 + TARGET(UNPACK_UNLIMITED) { 4743 + auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!! 4744 + PyObject* iter = asIter(POPX()); 4745 + _0 = PyIterNext(iter); 4746 + while(_0 != StopIteration){ 4747 + PUSH(_0); 4748 + _0 = PyIterNext(iter); 4749 + } 4750 + } DISPATCH(); 4751 + /*****************************************/ 4752 + TARGET(BEGIN_CLASS) { 4753 + StrName name(byte.arg); 4754 + PyObject* super_cls = POPX(); 4755 + if(super_cls == None) super_cls = _t(tp_object); 4756 + check_non_tagged_type(super_cls, tp_type); 4757 + PyObject* cls = new_type_object(frame->_module, name, OBJ_GET(Type, super_cls)); 4758 + PUSH(cls); 4759 + } DISPATCH(); 4760 + TARGET(END_CLASS) 4761 + _0 = POPX(); 4762 + _0->attr()._try_perfect_rehash(); 4763 + DISPATCH(); 4764 + TARGET(STORE_CLASS_ATTR) 4765 + _name = StrName(byte.arg); 4766 + _0 = POPX(); 4767 + TOP()->attr().set(_name, _0); 4768 + DISPATCH(); 4769 + /*****************************************/ 4770 + // TODO: using "goto" inside with block may cause __exit__ not called 4771 + TARGET(WITH_ENTER) 4772 + call_method(POPX(), __enter__); 4773 + DISPATCH(); 4774 + TARGET(WITH_EXIT) 4775 + call_method(POPX(), __exit__); 4776 + DISPATCH(); 4777 + /*****************************************/ 4778 + TARGET(ASSERT) { 4779 + PyObject* obj = TOP(); 4780 + Str msg; 4781 + if(is_type(obj, tp_tuple)){ 4782 + auto& t = CAST(Tuple&, obj); 4783 + if(t.size() != 2) ValueError("assert tuple must have 2 elements"); 4784 + obj = t[0]; 4785 + msg = CAST(Str&, asStr(t[1])); 4786 + } 4787 + bool ok = asBool(obj); 4788 + POP(); 4789 + if(!ok) _error("AssertionError", msg); 4790 + } DISPATCH(); 4791 + TARGET(EXCEPTION_MATCH) { 4792 + const auto& e = CAST(Exception&, TOP()); 4793 + _name = StrName(byte.arg); 4794 + PUSH(VAR(e.match_type(_name))); 4795 + } DISPATCH(); 4796 + TARGET(RAISE) { 4797 + PyObject* obj = POPX(); 4798 + Str msg = obj == None ? "" : CAST(Str, asStr(obj)); 4799 + _error(StrName(byte.arg), msg); 4800 + } DISPATCH(); 4801 + TARGET(RE_RAISE) _raise(); DISPATCH(); 4802 + /*****************************************/ 4803 + TARGET(SETUP_DOCSTRING) 4804 + TOP()->attr().set(__doc__, co_consts[byte.arg]); 4805 + DISPATCH(); 4806 + TARGET(FORMAT_STRING) { 4807 + _0 = POPX(); 4808 + const Str& spec = CAST(Str&, co_consts[byte.arg]); 4809 + PUSH(format(spec, _0)); 4810 + } DISPATCH(); 4811 + #if !PK_ENABLE_COMPUTED_GOTO 4812 + #if DEBUG_EXTRA_CHECK 4813 + default: throw std::runtime_error(fmt(OP_NAMES[byte.op], " is not implemented")); 4814 + #else 4815 + default: UNREACHABLE(); 4816 + #endif 4817 + } 4818 + #endif 4819 + } 4820 + 4821 + #undef DISPATCH 4822 + #undef TARGET 4823 + #undef DISPATCH_OP_CALL 4824 + /**********************************************************************/ 4825 + UNREACHABLE(); 4826 + }catch(HandledException& e){ 4827 + continue; 4828 + }catch(UnhandledException& e){ 4829 + PyObject* obj = POPX(); 4830 + Exception& _e = CAST(Exception&, obj); 4831 + _e.st_push(frame->snapshot()); 4832 + _pop_frame(); 4833 + if(callstack.empty()){ 4834 + #if DEBUG_FULL_EXCEPTION 4835 + std::cerr << _e.summary() << std::endl; 4836 + #endif 4837 + throw _e; 4838 + } 4839 + frame = top_frame(); 4840 + PUSH(obj); 4841 + if(frame.index < base_id) throw ToBeRaisedException(); 4842 + need_raise = true; 4843 + }catch(ToBeRaisedException& e){ 4844 + need_raise = true; 4845 + } 4846 + } 4847 + } 4848 + 4849 + #undef TOP 4850 + #undef SECOND 4851 + #undef THIRD 4852 + #undef PEEK 4853 + #undef STACK_SHRINK 4854 + #undef PUSH 4855 + #undef POP 4856 + #undef POPX 4857 + #undef STACK_VIEW 4858 + 4859 + } // namespace pkpy 4860 + 4861 + 4862 + #include <algorithm> 4863 + 4864 + namespace pkpy{ 4865 + 4866 + struct CodeEmitContext; 4867 + 4868 + struct Expr{ 4869 + int line = 0; 4870 + virtual ~Expr() = default; 4871 + virtual void emit(CodeEmitContext* ctx) = 0; 4872 + virtual std::string str() const = 0; 4873 + 4874 + virtual bool is_starred() const { return false; } 4875 + virtual bool is_literal() const { return false; } 4876 + virtual bool is_json_object() const { return false; } 4877 + virtual bool is_attrib() const { return false; } 4878 + 4879 + // for OP_DELETE_XXX 4880 + [[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; } 4881 + 4882 + // for OP_STORE_XXX 4883 + [[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; } 4884 + }; 4885 + 4886 + struct CodeEmitContext{ 4887 + VM* vm; 4888 + CodeObject_ co; 4889 + stack<Expr_> s_expr; 4890 + int level; 4891 + CodeEmitContext(VM* vm, CodeObject_ co, int level): vm(vm), co(co), level(level) {} 4892 + 4893 + int curr_block_i = 0; 4894 + bool is_compiling_class = false; 4895 + int for_loop_depth = 0; 4896 + 4897 + bool is_curr_block_loop() const { 4898 + return co->blocks[curr_block_i].type == FOR_LOOP || co->blocks[curr_block_i].type == WHILE_LOOP; 4899 + } 4900 + 4901 + void enter_block(CodeBlockType type){ 4902 + if(type == FOR_LOOP) for_loop_depth++; 4903 + co->blocks.push_back(CodeBlock( 4904 + type, curr_block_i, for_loop_depth, (int)co->codes.size() 4905 + )); 4906 + curr_block_i = co->blocks.size()-1; 4907 + } 4908 + 4909 + void exit_block(){ 4910 + if(co->blocks[curr_block_i].type == FOR_LOOP) for_loop_depth--; 4911 + co->blocks[curr_block_i].end = co->codes.size(); 4912 + curr_block_i = co->blocks[curr_block_i].parent; 4913 + if(curr_block_i < 0) FATAL_ERROR(); 4914 + } 4915 + 4916 + // clear the expression stack and generate bytecode 4917 + void emit_expr(){ 4918 + if(s_expr.size() != 1){ 4919 + throw std::runtime_error("s_expr.size() != 1\n" + _log_s_expr()); 4920 + } 4921 + Expr_ expr = s_expr.popx(); 4922 + expr->emit(this); 4923 + } 4924 + 4925 + std::string _log_s_expr(){ 4926 + std::stringstream ss; 4927 + for(auto& e: s_expr.data()) ss << e->str() << " "; 4928 + return ss.str(); 4929 + } 4930 + 4931 + int emit(Opcode opcode, int arg, int line) { 4932 + co->codes.push_back( 4933 + Bytecode{(uint16_t)opcode, (uint16_t)curr_block_i, arg} 4934 + ); 4935 + co->lines.push_back(line); 4936 + int i = co->codes.size() - 1; 4937 + if(line==BC_KEEPLINE){ 4938 + if(i>=1) co->lines[i] = co->lines[i-1]; 4939 + else co->lines[i] = 1; 4940 + } 4941 + return i; 4942 + } 4943 + 4944 + void patch_jump(int index) { 4945 + int target = co->codes.size(); 4946 + co->codes[index].arg = target; 4947 + } 4948 + 4949 + bool add_label(StrName name){ 4950 + if(co->labels.contains(name)) return false; 4951 + co->labels.set(name, co->codes.size()); 4952 + return true; 4953 + } 4954 + 4955 + int add_varname(StrName name){ 4956 + int index = co->varnames_inv.try_get(name); 4957 + if(index >= 0) return index; 4958 + co->varnames.push_back(name); 4959 + index = co->varnames.size() - 1; 4960 + co->varnames_inv.set(name, index); 4961 + return index; 4962 + } 4963 + 4964 + int add_const(PyObject* v){ 4965 + // simple deduplication, only works for int/float 4966 + for(int i=0; i<co->consts.size(); i++){ 4967 + if(co->consts[i] == v) return i; 4968 + } 4969 + co->consts.push_back(v); 4970 + return co->consts.size() - 1; 4971 + } 4972 + 4973 + int add_func_decl(FuncDecl_ decl){ 4974 + co->func_decls.push_back(decl); 4975 + return co->func_decls.size() - 1; 4976 + } 4977 + }; 4978 + 4979 + struct NameExpr: Expr{ 4980 + StrName name; 4981 + NameScope scope; 4982 + NameExpr(StrName name, NameScope scope): name(name), scope(scope) {} 4983 + 4984 + std::string str() const override { return fmt("Name(", name.escape(), ")"); } 4985 + 4986 + void emit(CodeEmitContext* ctx) override { 4987 + int index = ctx->co->varnames_inv.try_get(name); 4988 + if(scope == NAME_LOCAL && index >= 0){ 4989 + ctx->emit(OP_LOAD_FAST, index, line); 4990 + }else{ 4991 + Opcode op = ctx->level <= 1 ? OP_LOAD_GLOBAL : OP_LOAD_NONLOCAL; 4992 + // we cannot determine the scope when calling exec()/eval() 4993 + if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME; 4994 + ctx->emit(op, StrName(name).index, line); 4995 + } 4996 + } 4997 + 4998 + bool emit_del(CodeEmitContext* ctx) override { 4999 + switch(scope){ 5000 + case NAME_LOCAL: 5001 + ctx->emit(OP_DELETE_FAST, ctx->add_varname(name), line); 5002 + break; 5003 + case NAME_GLOBAL: 5004 + ctx->emit(OP_DELETE_GLOBAL, StrName(name).index, line); 5005 + break; 5006 + case NAME_GLOBAL_UNKNOWN: 5007 + ctx->emit(OP_DELETE_NAME, StrName(name).index, line); 5008 + break; 5009 + default: FATAL_ERROR(); break; 5010 + } 5011 + return true; 5012 + } 5013 + 5014 + bool emit_store(CodeEmitContext* ctx) override { 5015 + if(ctx->is_compiling_class){ 5016 + int index = StrName(name).index; 5017 + ctx->emit(OP_STORE_CLASS_ATTR, index, line); 5018 + return true; 5019 + } 5020 + switch(scope){ 5021 + case NAME_LOCAL: 5022 + ctx->emit(OP_STORE_FAST, ctx->add_varname(name), line); 5023 + break; 5024 + case NAME_GLOBAL: 5025 + ctx->emit(OP_STORE_GLOBAL, StrName(name).index, line); 5026 + break; 5027 + case NAME_GLOBAL_UNKNOWN: 5028 + ctx->emit(OP_STORE_NAME, StrName(name).index, line); 5029 + break; 5030 + default: FATAL_ERROR(); break; 5031 + } 5032 + return true; 5033 + } 5034 + }; 5035 + 5036 + struct StarredExpr: Expr{ 5037 + Expr_ child; 5038 + StarredExpr(Expr_&& child): child(std::move(child)) {} 5039 + std::string str() const override { return "Starred()"; } 5040 + 5041 + bool is_starred() const override { return true; } 5042 + 5043 + void emit(CodeEmitContext* ctx) override { 5044 + child->emit(ctx); 5045 + ctx->emit(OP_UNPACK_UNLIMITED, BC_NOARG, line); 5046 + } 5047 + 5048 + bool emit_store(CodeEmitContext* ctx) override { 5049 + // simply proxy to child 5050 + return child->emit_store(ctx); 5051 + } 5052 + }; 5053 + 5054 + 5055 + struct NotExpr: Expr{ 5056 + Expr_ child; 5057 + NotExpr(Expr_&& child): child(std::move(child)) {} 5058 + std::string str() const override { return "Not()"; } 5059 + 5060 + void emit(CodeEmitContext* ctx) override { 5061 + child->emit(ctx); 5062 + ctx->emit(OP_UNARY_NOT, BC_NOARG, line); 5063 + } 5064 + }; 5065 + 5066 + struct AndExpr: Expr{ 5067 + Expr_ lhs; 5068 + Expr_ rhs; 5069 + std::string str() const override { return "And()"; } 5070 + 5071 + void emit(CodeEmitContext* ctx) override { 5072 + lhs->emit(ctx); 5073 + int patch = ctx->emit(OP_JUMP_IF_FALSE_OR_POP, BC_NOARG, line); 5074 + rhs->emit(ctx); 5075 + ctx->patch_jump(patch); 5076 + } 5077 + }; 5078 + 5079 + struct OrExpr: Expr{ 5080 + Expr_ lhs; 5081 + Expr_ rhs; 5082 + std::string str() const override { return "Or()"; } 5083 + 5084 + void emit(CodeEmitContext* ctx) override { 5085 + lhs->emit(ctx); 5086 + int patch = ctx->emit(OP_JUMP_IF_TRUE_OR_POP, BC_NOARG, line); 5087 + rhs->emit(ctx); 5088 + ctx->patch_jump(patch); 5089 + } 5090 + }; 5091 + 5092 + // [None, True, False, ...] 5093 + struct Literal0Expr: Expr{ 5094 + TokenIndex token; 5095 + Literal0Expr(TokenIndex token): token(token) {} 5096 + std::string str() const override { return TK_STR(token); } 5097 + 5098 + void emit(CodeEmitContext* ctx) override { 5099 + switch (token) { 5100 + case TK("None"): ctx->emit(OP_LOAD_NONE, BC_NOARG, line); break; 5101 + case TK("True"): ctx->emit(OP_LOAD_TRUE, BC_NOARG, line); break; 5102 + case TK("False"): ctx->emit(OP_LOAD_FALSE, BC_NOARG, line); break; 5103 + case TK("..."): ctx->emit(OP_LOAD_ELLIPSIS, BC_NOARG, line); break; 5104 + default: FATAL_ERROR(); 5105 + } 5106 + } 5107 + 5108 + bool is_json_object() const override { return true; } 5109 + }; 5110 + 5111 + // @num, @str which needs to invoke OP_LOAD_CONST 5112 + struct LiteralExpr: Expr{ 5113 + TokenValue value; 5114 + LiteralExpr(TokenValue value): value(value) {} 5115 + std::string str() const override { 5116 + if(std::holds_alternative<i64>(value)){ 5117 + return std::to_string(std::get<i64>(value)); 5118 + } 5119 + 5120 + if(std::holds_alternative<f64>(value)){ 5121 + return std::to_string(std::get<f64>(value)); 5122 + } 5123 + 5124 + if(std::holds_alternative<Str>(value)){ 5125 + Str s = std::get<Str>(value).escape(); 5126 + return s.str(); 5127 + } 5128 + 5129 + FATAL_ERROR(); 5130 + } 5131 + 5132 + void emit(CodeEmitContext* ctx) override { 5133 + VM* vm = ctx->vm; 5134 + PyObject* obj = nullptr; 5135 + if(std::holds_alternative<i64>(value)){ 5136 + i64 _val = std::get<i64>(value); 5137 + if(_val >= INT16_MIN && _val <= INT16_MAX){ 5138 + ctx->emit(OP_LOAD_INTEGER, (int)_val, line); 5139 + return; 5140 + } 5141 + obj = VAR(_val); 5142 + } 5143 + if(std::holds_alternative<f64>(value)){ 5144 + obj = VAR(std::get<f64>(value)); 5145 + } 5146 + if(std::holds_alternative<Str>(value)){ 5147 + obj = VAR(std::get<Str>(value)); 5148 + } 5149 + if(obj == nullptr) FATAL_ERROR(); 5150 + ctx->emit(OP_LOAD_CONST, ctx->add_const(obj), line); 5151 + } 5152 + 5153 + bool is_literal() const override { return true; } 5154 + bool is_json_object() const override { return true; } 5155 + }; 5156 + 5157 + struct NegatedExpr: Expr{ 5158 + Expr_ child; 5159 + NegatedExpr(Expr_&& child): child(std::move(child)) {} 5160 + std::string str() const override { return "Negated()"; } 5161 + 5162 + void emit(CodeEmitContext* ctx) override { 5163 + VM* vm = ctx->vm; 5164 + // if child is a int of float, do constant folding 5165 + if(child->is_literal()){ 5166 + LiteralExpr* lit = static_cast<LiteralExpr*>(child.get()); 5167 + if(std::holds_alternative<i64>(lit->value)){ 5168 + i64 _val = -std::get<i64>(lit->value); 5169 + if(_val >= INT16_MIN && _val <= INT16_MAX){ 5170 + ctx->emit(OP_LOAD_INTEGER, (int)_val, line); 5171 + }else{ 5172 + ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line); 5173 + } 5174 + return; 5175 + } 5176 + if(std::holds_alternative<f64>(lit->value)){ 5177 + PyObject* obj = VAR(-std::get<f64>(lit->value)); 5178 + ctx->emit(OP_LOAD_CONST, ctx->add_const(obj), line); 5179 + return; 5180 + } 5181 + } 5182 + child->emit(ctx); 5183 + ctx->emit(OP_UNARY_NEGATIVE, BC_NOARG, line); 5184 + } 5185 + 5186 + bool is_json_object() const override { 5187 + return child->is_literal(); 5188 + } 5189 + }; 5190 + 5191 + struct SliceExpr: Expr{ 5192 + Expr_ start; 5193 + Expr_ stop; 5194 + Expr_ step; 5195 + std::string str() const override { return "Slice()"; } 5196 + 5197 + void emit(CodeEmitContext* ctx) override { 5198 + if(start){ 5199 + start->emit(ctx); 5200 + }else{ 5201 + ctx->emit(OP_LOAD_NONE, BC_NOARG, line); 5202 + } 5203 + 5204 + if(stop){ 5205 + stop->emit(ctx); 5206 + }else{ 5207 + ctx->emit(OP_LOAD_NONE, BC_NOARG, line); 5208 + } 5209 + 5210 + if(step){ 5211 + step->emit(ctx); 5212 + }else{ 5213 + ctx->emit(OP_LOAD_NONE, BC_NOARG, line); 5214 + } 5215 + 5216 + ctx->emit(OP_BUILD_SLICE, BC_NOARG, line); 5217 + } 5218 + }; 5219 + 5220 + struct DictItemExpr: Expr{ 5221 + Expr_ key; 5222 + Expr_ value; 5223 + std::string str() const override { return "DictItem()"; } 5224 + 5225 + void emit(CodeEmitContext* ctx) override { 5226 + value->emit(ctx); 5227 + key->emit(ctx); // reverse order 5228 + ctx->emit(OP_BUILD_TUPLE, 2, line); 5229 + } 5230 + }; 5231 + 5232 + struct SequenceExpr: Expr{ 5233 + std::vector<Expr_> items; 5234 + SequenceExpr(std::vector<Expr_>&& items): items(std::move(items)) {} 5235 + virtual Opcode opcode() const = 0; 5236 + 5237 + void emit(CodeEmitContext* ctx) override { 5238 + for(auto& item: items) item->emit(ctx); 5239 + ctx->emit(opcode(), items.size(), line); 5240 + } 5241 + }; 5242 + 5243 + struct ListExpr: SequenceExpr{ 5244 + using SequenceExpr::SequenceExpr; 5245 + std::string str() const override { return "List()"; } 5246 + Opcode opcode() const override { return OP_BUILD_LIST; } 5247 + 5248 + bool is_json_object() const override { return true; } 5249 + }; 5250 + 5251 + struct DictExpr: SequenceExpr{ 5252 + using SequenceExpr::SequenceExpr; 5253 + std::string str() const override { return "Dict()"; } 5254 + Opcode opcode() const override { return OP_BUILD_DICT; } 5255 + 5256 + bool is_json_object() const override { return true; } 5257 + }; 5258 + 5259 + struct SetExpr: SequenceExpr{ 5260 + using SequenceExpr::SequenceExpr; 5261 + std::string str() const override { return "Set()"; } 5262 + Opcode opcode() const override { return OP_BUILD_SET; } 5263 + }; 5264 + 5265 + struct TupleExpr: SequenceExpr{ 5266 + using SequenceExpr::SequenceExpr; 5267 + std::string str() const override { return "Tuple()"; } 5268 + Opcode opcode() const override { return OP_BUILD_TUPLE; } 5269 + 5270 + bool emit_store(CodeEmitContext* ctx) override { 5271 + // TOS is an iterable 5272 + // items may contain StarredExpr, we should check it 5273 + int starred_i = -1; 5274 + for(int i=0; i<items.size(); i++){ 5275 + if(!items[i]->is_starred()) continue; 5276 + if(starred_i == -1) starred_i = i; 5277 + else return false; // multiple StarredExpr not allowed 5278 + } 5279 + 5280 + if(starred_i == -1){ 5281 + ctx->emit(OP_UNPACK_SEQUENCE, items.size(), line); 5282 + }else{ 5283 + // starred assignment target must be in a tuple 5284 + if(items.size() == 1) return false; 5285 + // starred assignment target must be the last one (differ from cpython) 5286 + if(starred_i != items.size()-1) return false; 5287 + // a,*b = [1,2,3] 5288 + // stack is [1,2,3] -> [1,[2,3]] 5289 + ctx->emit(OP_UNPACK_EX, items.size()-1, line); 5290 + } 5291 + // do reverse emit 5292 + for(int i=items.size()-1; i>=0; i--){ 5293 + bool ok = items[i]->emit_store(ctx); 5294 + if(!ok) return false; 5295 + } 5296 + return true; 5297 + } 5298 + 5299 + bool emit_del(CodeEmitContext* ctx) override{ 5300 + for(auto& e: items){ 5301 + bool ok = e->emit_del(ctx); 5302 + if(!ok) return false; 5303 + } 5304 + return true; 5305 + } 5306 + }; 5307 + 5308 + struct CompExpr: Expr{ 5309 + Expr_ expr; // loop expr 5310 + Expr_ vars; // loop vars 5311 + Expr_ iter; // loop iter 5312 + Expr_ cond; // optional if condition 5313 + 5314 + virtual Opcode op0() = 0; 5315 + virtual Opcode op1() = 0; 5316 + 5317 + void emit(CodeEmitContext* ctx){ 5318 + ctx->emit(op0(), 0, line); 5319 + iter->emit(ctx); 5320 + ctx->emit(OP_GET_ITER, BC_NOARG, BC_KEEPLINE); 5321 + ctx->enter_block(FOR_LOOP); 5322 + ctx->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE); 5323 + bool ok = vars->emit_store(ctx); 5324 + // this error occurs in `vars` instead of this line, but...nevermind 5325 + if(!ok) FATAL_ERROR(); // TODO: raise a SyntaxError instead 5326 + if(cond){ 5327 + cond->emit(ctx); 5328 + int patch = ctx->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE); 5329 + expr->emit(ctx); 5330 + ctx->emit(op1(), BC_NOARG, BC_KEEPLINE); 5331 + ctx->patch_jump(patch); 5332 + }else{ 5333 + expr->emit(ctx); 5334 + ctx->emit(op1(), BC_NOARG, BC_KEEPLINE); 5335 + } 5336 + ctx->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE); 5337 + ctx->exit_block(); 5338 + } 5339 + }; 5340 + 5341 + struct ListCompExpr: CompExpr{ 5342 + Opcode op0() override { return OP_BUILD_LIST; } 5343 + Opcode op1() override { return OP_LIST_APPEND; } 5344 + std::string str() const override { return "ListComp()"; } 5345 + }; 5346 + 5347 + struct DictCompExpr: CompExpr{ 5348 + Opcode op0() override { return OP_BUILD_DICT; } 5349 + Opcode op1() override { return OP_DICT_ADD; } 5350 + std::string str() const override { return "DictComp()"; } 5351 + }; 5352 + 5353 + struct SetCompExpr: CompExpr{ 5354 + Opcode op0() override { return OP_BUILD_SET; } 5355 + Opcode op1() override { return OP_SET_ADD; } 5356 + std::string str() const override { return "SetComp()"; } 5357 + }; 5358 + 5359 + struct LambdaExpr: Expr{ 5360 + FuncDecl_ decl; 5361 + std::string str() const override { return "Lambda()"; } 5362 + 5363 + LambdaExpr(FuncDecl_ decl): decl(decl) {} 5364 + 5365 + void emit(CodeEmitContext* ctx) override { 5366 + int index = ctx->add_func_decl(decl); 5367 + ctx->emit(OP_LOAD_FUNCTION, index, line); 5368 + } 5369 + }; 5370 + 5371 + struct FStringExpr: Expr{ 5372 + Str src; 5373 + FStringExpr(const Str& src): src(src) {} 5374 + std::string str() const override { 5375 + return fmt("f", src.escape()); 5376 + } 5377 + 5378 + void emit(CodeEmitContext* ctx) override { 5379 + VM* vm = ctx->vm; 5380 + static const std::regex pattern(R"(\{(.*?)\})"); 5381 + std::cregex_iterator begin(src.begin(), src.end(), pattern); 5382 + std::cregex_iterator end; 5383 + int size = 0; 5384 + int i = 0; 5385 + for(auto it = begin; it != end; it++) { 5386 + std::cmatch m = *it; 5387 + if (i < m.position()) { 5388 + Str literal = src.substr(i, m.position() - i); 5389 + ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(literal)), line); 5390 + size++; 5391 + } 5392 + Str expr = m[1].str(); 5393 + int conon = expr.index(":"); 5394 + if(conon >= 0){ 5395 + ctx->emit( 5396 + OP_LOAD_NAME, 5397 + StrName(expr.substr(0, conon)).index, 5398 + line 5399 + ); 5400 + Str spec = expr.substr(conon+1); 5401 + ctx->emit(OP_FORMAT_STRING, ctx->add_const(VAR(spec)), line); 5402 + }else{ 5403 + ctx->emit(OP_LOAD_NAME, StrName(expr).index, line); 5404 + } 5405 + size++; 5406 + i = (int)(m.position() + m.length()); 5407 + } 5408 + if (i < src.length()) { 5409 + Str literal = src.substr(i, src.length() - i); 5410 + ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(literal)), line); 5411 + size++; 5412 + } 5413 + ctx->emit(OP_BUILD_STRING, size, line); 5414 + } 5415 + }; 5416 + 5417 + struct SubscrExpr: Expr{ 5418 + Expr_ a; 5419 + Expr_ b; 5420 + std::string str() const override { return "Subscr()"; } 5421 + 5422 + void emit(CodeEmitContext* ctx) override{ 5423 + a->emit(ctx); 5424 + b->emit(ctx); 5425 + ctx->emit(OP_LOAD_SUBSCR, BC_NOARG, line); 5426 + } 5427 + 5428 + bool emit_del(CodeEmitContext* ctx) override { 5429 + a->emit(ctx); 5430 + b->emit(ctx); 5431 + ctx->emit(OP_DELETE_SUBSCR, BC_NOARG, line); 5432 + return true; 5433 + } 5434 + 5435 + bool emit_store(CodeEmitContext* ctx) override { 5436 + a->emit(ctx); 5437 + b->emit(ctx); 5438 + ctx->emit(OP_STORE_SUBSCR, BC_NOARG, line); 5439 + return true; 5440 + } 5441 + }; 5442 + 5443 + struct AttribExpr: Expr{ 5444 + Expr_ a; 5445 + Str b; 5446 + AttribExpr(Expr_ a, const Str& b): a(std::move(a)), b(b) {} 5447 + AttribExpr(Expr_ a, Str&& b): a(std::move(a)), b(std::move(b)) {} 5448 + std::string str() const override { return "Attrib()"; } 5449 + 5450 + void emit(CodeEmitContext* ctx) override{ 5451 + a->emit(ctx); 5452 + int index = StrName(b).index; 5453 + ctx->emit(OP_LOAD_ATTR, index, line); 5454 + } 5455 + 5456 + bool emit_del(CodeEmitContext* ctx) override { 5457 + a->emit(ctx); 5458 + int index = StrName(b).index; 5459 + ctx->emit(OP_DELETE_ATTR, index, line); 5460 + return true; 5461 + } 5462 + 5463 + bool emit_store(CodeEmitContext* ctx) override { 5464 + a->emit(ctx); 5465 + int index = StrName(b).index; 5466 + ctx->emit(OP_STORE_ATTR, index, line); 5467 + return true; 5468 + } 5469 + 5470 + void emit_method(CodeEmitContext* ctx) { 5471 + a->emit(ctx); 5472 + int index = StrName(b).index; 5473 + ctx->emit(OP_LOAD_METHOD, index, line); 5474 + } 5475 + 5476 + bool is_attrib() const override { return true; } 5477 + }; 5478 + 5479 + struct CallExpr: Expr{ 5480 + Expr_ callable; 5481 + std::vector<Expr_> args; 5482 + std::vector<std::pair<Str, Expr_>> kwargs; 5483 + std::string str() const override { return "Call()"; } 5484 + 5485 + bool need_unpack() const { 5486 + for(auto& item: args) if(item->is_starred()) return true; 5487 + return false; 5488 + } 5489 + 5490 + void emit(CodeEmitContext* ctx) override { 5491 + VM* vm = ctx->vm; 5492 + if(need_unpack()) ctx->emit(OP_BEGIN_CALL, BC_NOARG, line); 5493 + // if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy 5494 + if(callable->is_attrib()){ 5495 + auto p = static_cast<AttribExpr*>(callable.get()); 5496 + p->emit_method(ctx); 5497 + }else{ 5498 + callable->emit(ctx); 5499 + ctx->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE); 5500 + } 5501 + // emit args 5502 + for(auto& item: args) item->emit(ctx); 5503 + // emit kwargs 5504 + for(auto& item: kwargs){ 5505 + int index = StrName::get(item.first.sv()).index; 5506 + ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(index)), line); 5507 + item.second->emit(ctx); 5508 + } 5509 + int KWARGC = (int)kwargs.size(); 5510 + int ARGC = (int)args.size(); 5511 + if(need_unpack()) ARGC = 0xFFFF; 5512 + ctx->emit(OP_CALL, (KWARGC<<16)|ARGC, line); 5513 + } 5514 + }; 5515 + 5516 + struct BinaryExpr: Expr{ 5517 + TokenIndex op; 5518 + Expr_ lhs; 5519 + Expr_ rhs; 5520 + std::string str() const override { return TK_STR(op); } 5521 + 5522 + void emit(CodeEmitContext* ctx) override { 5523 + lhs->emit(ctx); 5524 + rhs->emit(ctx); 5525 + switch (op) { 5526 + case TK("+"): ctx->emit(OP_BINARY_ADD, BC_NOARG, line); break; 5527 + case TK("-"): ctx->emit(OP_BINARY_SUB, BC_NOARG, line); break; 5528 + case TK("*"): ctx->emit(OP_BINARY_MUL, BC_NOARG, line); break; 5529 + case TK("/"): ctx->emit(OP_BINARY_OP, 3, line); break; 5530 + case TK("//"): ctx->emit(OP_BINARY_FLOORDIV, BC_NOARG, line); break; 5531 + case TK("%"): ctx->emit(OP_BINARY_MOD, BC_NOARG, line); break; 5532 + case TK("**"): ctx->emit(OP_BINARY_OP, 6, line); break; 5533 + 5534 + case TK("<"): ctx->emit(OP_COMPARE_LT, BC_NOARG, line); break; 5535 + case TK("<="): ctx->emit(OP_COMPARE_LE, BC_NOARG, line); break; 5536 + case TK("=="): ctx->emit(OP_COMPARE_EQ, BC_NOARG, line); break; 5537 + case TK("!="): ctx->emit(OP_COMPARE_NE, BC_NOARG, line); break; 5538 + case TK(">"): ctx->emit(OP_COMPARE_GT, BC_NOARG, line); break; 5539 + case TK(">="): ctx->emit(OP_COMPARE_GE, BC_NOARG, line); break; 5540 + case TK("in"): ctx->emit(OP_CONTAINS_OP, 0, line); break; 5541 + case TK("not in"): ctx->emit(OP_CONTAINS_OP, 1, line); break; 5542 + case TK("is"): ctx->emit(OP_IS_OP, 0, line); break; 5543 + case TK("is not"): ctx->emit(OP_IS_OP, 1, line); break; 5544 + 5545 + case TK("<<"): ctx->emit(OP_BITWISE_LSHIFT, BC_NOARG, line); break; 5546 + case TK(">>"): ctx->emit(OP_BITWISE_RSHIFT, BC_NOARG, line); break; 5547 + case TK("&"): ctx->emit(OP_BITWISE_AND, BC_NOARG, line); break; 5548 + case TK("|"): ctx->emit(OP_BITWISE_OR, BC_NOARG, line); break; 5549 + case TK("^"): ctx->emit(OP_BITWISE_XOR, BC_NOARG, line); break; 5550 + default: FATAL_ERROR(); 5551 + } 5552 + } 5553 + }; 5554 + 5555 + 5556 + struct TernaryExpr: Expr{ 5557 + Expr_ cond; 5558 + Expr_ true_expr; 5559 + Expr_ false_expr; 5560 + std::string str() const override { return "Ternary()"; } 5561 + 5562 + void emit(CodeEmitContext* ctx) override { 5563 + cond->emit(ctx); 5564 + int patch = ctx->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, cond->line); 5565 + true_expr->emit(ctx); 5566 + int patch_2 = ctx->emit(OP_JUMP_ABSOLUTE, BC_NOARG, true_expr->line); 5567 + ctx->patch_jump(patch); 5568 + false_expr->emit(ctx); 5569 + ctx->patch_jump(patch_2); 5570 + } 5571 + }; 5572 + 5573 + 5574 + } // namespace pkpy 5575 + 5576 + 5577 + namespace pkpy{ 5578 + 5579 + class Compiler; 5580 + typedef void (Compiler::*PrattCallback)(); 5581 + 5582 + struct PrattRule{ 5583 + PrattCallback prefix; 5584 + PrattCallback infix; 5585 + Precedence precedence; 5586 + }; 5587 + 5588 + class Compiler { 5589 + inline static PrattRule rules[kTokenCount]; 5590 + std::unique_ptr<Lexer> lexer; 5591 + stack<CodeEmitContext> contexts; 5592 + VM* vm; 5593 + bool unknown_global_scope; // for eval/exec() call 5594 + bool used; 5595 + // for parsing token stream 5596 + int i = 0; 5597 + std::vector<Token> tokens; 5598 + 5599 + const Token& prev() const{ return tokens.at(i-1); } 5600 + const Token& curr() const{ return tokens.at(i); } 5601 + const Token& next() const{ return tokens.at(i+1); } 5602 + const Token& err() const{ 5603 + if(i >= tokens.size()) return prev(); 5604 + return curr(); 5605 + } 5606 + void advance(int delta=1) { i += delta; } 5607 + 5608 + CodeEmitContext* ctx() { return &contexts.top(); } 5609 + CompileMode mode() const{ return lexer->src->mode; } 5610 + NameScope name_scope() const { 5611 + auto s = contexts.size()>1 ? NAME_LOCAL : NAME_GLOBAL; 5612 + if(unknown_global_scope && s == NAME_GLOBAL) s = NAME_GLOBAL_UNKNOWN; 5613 + return s; 5614 + } 5615 + 5616 + CodeObject_ push_global_context(){ 5617 + CodeObject_ co = make_sp<CodeObject>(lexer->src, lexer->src->filename); 5618 + contexts.push(CodeEmitContext(vm, co, contexts.size())); 5619 + return co; 5620 + } 5621 + 5622 + FuncDecl_ push_f_context(Str name){ 5623 + FuncDecl_ decl = make_sp<FuncDecl>(); 5624 + decl->code = make_sp<CodeObject>(lexer->src, name); 5625 + decl->nested = name_scope() == NAME_LOCAL; 5626 + contexts.push(CodeEmitContext(vm, decl->code, contexts.size())); 5627 + return decl; 5628 + } 5629 + 5630 + void pop_context(){ 5631 + if(!ctx()->s_expr.empty()){ 5632 + throw std::runtime_error("!ctx()->s_expr.empty()\n" + ctx()->_log_s_expr()); 5633 + } 5634 + // add a `return None` in the end as a guard 5635 + // previously, we only do this if the last opcode is not a return 5636 + // however, this is buggy...since there may be a jump to the end (out of bound) even if the last opcode is a return 5637 + ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE); 5638 + ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); 5639 + ctx()->co->optimize(vm); 5640 + if(ctx()->co->varnames.size() > PK_MAX_CO_VARNAMES){ 5641 + SyntaxError("maximum number of local variables exceeded"); 5642 + } 5643 + contexts.pop(); 5644 + } 5645 + 5646 + static void init_pratt_rules(){ 5647 + if(rules[TK(".")].precedence != PREC_NONE) return; 5648 + // http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ 5649 + #define METHOD(name) &Compiler::name 5650 + #define NO_INFIX nullptr, PREC_NONE 5651 + for(TokenIndex i=0; i<kTokenCount; i++) rules[i] = { nullptr, NO_INFIX }; 5652 + rules[TK(".")] = { nullptr, METHOD(exprAttrib), PREC_ATTRIB }; 5653 + rules[TK("(")] = { METHOD(exprGroup), METHOD(exprCall), PREC_CALL }; 5654 + rules[TK("[")] = { METHOD(exprList), METHOD(exprSubscr), PREC_SUBSCRIPT }; 5655 + rules[TK("{")] = { METHOD(exprMap), NO_INFIX }; 5656 + rules[TK("%")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; 5657 + rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM }; 5658 + rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM }; 5659 + rules[TK("*")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_FACTOR }; 5660 + rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; 5661 + rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; 5662 + rules[TK("**")] = { nullptr, METHOD(exprBinaryOp), PREC_EXPONENT }; 5663 + rules[TK(">")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; 5664 + rules[TK("<")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; 5665 + rules[TK("==")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY }; 5666 + rules[TK("!=")] = { nullptr, METHOD(exprBinaryOp), PREC_EQUALITY }; 5667 + rules[TK(">=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; 5668 + rules[TK("<=")] = { nullptr, METHOD(exprBinaryOp), PREC_COMPARISION }; 5669 + rules[TK("in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; 5670 + rules[TK("is")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; 5671 + rules[TK("<<")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT }; 5672 + rules[TK(">>")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_SHIFT }; 5673 + rules[TK("&")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_AND }; 5674 + rules[TK("|")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_OR }; 5675 + rules[TK("^")] = { nullptr, METHOD(exprBinaryOp), PREC_BITWISE_XOR }; 5676 + rules[TK("if")] = { nullptr, METHOD(exprTernary), PREC_TERNARY }; 5677 + rules[TK(",")] = { nullptr, METHOD(exprTuple), PREC_TUPLE }; 5678 + rules[TK("not in")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; 5679 + rules[TK("is not")] = { nullptr, METHOD(exprBinaryOp), PREC_TEST }; 5680 + rules[TK("and") ] = { nullptr, METHOD(exprAnd), PREC_LOGICAL_AND }; 5681 + rules[TK("or")] = { nullptr, METHOD(exprOr), PREC_LOGICAL_OR }; 5682 + rules[TK("not")] = { METHOD(exprNot), nullptr, PREC_LOGICAL_NOT }; 5683 + rules[TK("True")] = { METHOD(exprLiteral0), NO_INFIX }; 5684 + rules[TK("False")] = { METHOD(exprLiteral0), NO_INFIX }; 5685 + rules[TK("None")] = { METHOD(exprLiteral0), NO_INFIX }; 5686 + rules[TK("...")] = { METHOD(exprLiteral0), NO_INFIX }; 5687 + rules[TK("lambda")] = { METHOD(exprLambda), NO_INFIX }; 5688 + rules[TK("@id")] = { METHOD(exprName), NO_INFIX }; 5689 + rules[TK("@num")] = { METHOD(exprLiteral), NO_INFIX }; 5690 + rules[TK("@str")] = { METHOD(exprLiteral), NO_INFIX }; 5691 + rules[TK("@fstr")] = { METHOD(exprFString), NO_INFIX }; 5692 + #undef METHOD 5693 + #undef NO_INFIX 5694 + } 5695 + 5696 + bool match(TokenIndex expected) { 5697 + if (curr().type != expected) return false; 5698 + advance(); 5699 + return true; 5700 + } 5701 + 5702 + void consume(TokenIndex expected) { 5703 + if (!match(expected)){ 5704 + SyntaxError( 5705 + fmt("expected '", TK_STR(expected), "', but got '", TK_STR(curr().type), "'") 5706 + ); 5707 + } 5708 + } 5709 + 5710 + bool match_newlines_repl(){ 5711 + return match_newlines(mode()==REPL_MODE); 5712 + } 5713 + 5714 + bool match_newlines(bool repl_throw=false) { 5715 + bool consumed = false; 5716 + if (curr().type == TK("@eol")) { 5717 + while (curr().type == TK("@eol")) advance(); 5718 + consumed = true; 5719 + } 5720 + if (repl_throw && curr().type == TK("@eof")){ 5721 + throw NeedMoreLines(ctx()->is_compiling_class); 5722 + } 5723 + return consumed; 5724 + } 5725 + 5726 + bool match_end_stmt() { 5727 + if (match(TK(";"))) { match_newlines(); return true; } 5728 + if (match_newlines() || curr().type == TK("@eof")) return true; 5729 + if (curr().type == TK("@dedent")) return true; 5730 + return false; 5731 + } 5732 + 5733 + void consume_end_stmt() { 5734 + if (!match_end_stmt()) SyntaxError("expected statement end"); 5735 + } 5736 + 5737 + /*************************************************/ 5738 + 5739 + void EXPR(bool push_stack=true) { 5740 + parse_expression(PREC_TUPLE+1, push_stack); 5741 + } 5742 + 5743 + void EXPR_TUPLE(bool push_stack=true) { 5744 + parse_expression(PREC_TUPLE, push_stack); 5745 + } 5746 + 5747 + // special case for `for loop` and `comp` 5748 + Expr_ EXPR_VARS(){ 5749 + std::vector<Expr_> items; 5750 + do { 5751 + consume(TK("@id")); 5752 + items.push_back(make_expr<NameExpr>(prev().str(), name_scope())); 5753 + } while(match(TK(","))); 5754 + if(items.size()==1) return std::move(items[0]); 5755 + return make_expr<TupleExpr>(std::move(items)); 5756 + } 5757 + 5758 + template <typename T, typename... Args> 5759 + std::unique_ptr<T> make_expr(Args&&... args) { 5760 + std::unique_ptr<T> expr = std::make_unique<T>(std::forward<Args>(args)...); 5761 + expr->line = prev().line; 5762 + return expr; 5763 + } 5764 + 5765 + 5766 + void exprLiteral(){ 5767 + ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value)); 5768 + } 5769 + 5770 + 5771 + void exprFString(){ 5772 + ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value))); 5773 + } 5774 + 5775 + 5776 + void exprLambda(){ 5777 + FuncDecl_ decl = push_f_context("<lambda>"); 5778 + auto e = make_expr<LambdaExpr>(decl); 5779 + if(!match(TK(":"))){ 5780 + _compile_f_args(e->decl, false); 5781 + consume(TK(":")); 5782 + } 5783 + // https://github.com/blueloveTH/pocketpy/issues/37 5784 + parse_expression(PREC_LAMBDA + 1, false); 5785 + ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); 5786 + pop_context(); 5787 + ctx()->s_expr.push(std::move(e)); 5788 + } 5789 + 5790 + 5791 + void exprTuple(){ 5792 + std::vector<Expr_> items; 5793 + items.push_back(ctx()->s_expr.popx()); 5794 + do { 5795 + EXPR(); // NOTE: "1," will fail, "1,2" will be ok 5796 + items.push_back(ctx()->s_expr.popx()); 5797 + } while(match(TK(","))); 5798 + ctx()->s_expr.push(make_expr<TupleExpr>( 5799 + std::move(items) 5800 + )); 5801 + } 5802 + 5803 + 5804 + void exprOr(){ 5805 + auto e = make_expr<OrExpr>(); 5806 + e->lhs = ctx()->s_expr.popx(); 5807 + parse_expression(PREC_LOGICAL_OR + 1); 5808 + e->rhs = ctx()->s_expr.popx(); 5809 + ctx()->s_expr.push(std::move(e)); 5810 + } 5811 + 5812 + 5813 + void exprAnd(){ 5814 + auto e = make_expr<AndExpr>(); 5815 + e->lhs = ctx()->s_expr.popx(); 5816 + parse_expression(PREC_LOGICAL_AND + 1); 5817 + e->rhs = ctx()->s_expr.popx(); 5818 + ctx()->s_expr.push(std::move(e)); 5819 + } 5820 + 5821 + 5822 + void exprTernary(){ 5823 + auto e = make_expr<TernaryExpr>(); 5824 + e->true_expr = ctx()->s_expr.popx(); 5825 + // cond 5826 + parse_expression(PREC_TERNARY + 1); 5827 + e->cond = ctx()->s_expr.popx(); 5828 + consume(TK("else")); 5829 + // if false 5830 + parse_expression(PREC_TERNARY + 1); 5831 + e->false_expr = ctx()->s_expr.popx(); 5832 + ctx()->s_expr.push(std::move(e)); 5833 + } 5834 + 5835 + 5836 + void exprBinaryOp(){ 5837 + auto e = make_expr<BinaryExpr>(); 5838 + e->op = prev().type; 5839 + e->lhs = ctx()->s_expr.popx(); 5840 + parse_expression(rules[e->op].precedence + 1); 5841 + e->rhs = ctx()->s_expr.popx(); 5842 + ctx()->s_expr.push(std::move(e)); 5843 + } 5844 + 5845 + 5846 + void exprNot() { 5847 + parse_expression(PREC_LOGICAL_NOT + 1); 5848 + ctx()->s_expr.push(make_expr<NotExpr>(ctx()->s_expr.popx())); 5849 + } 5850 + 5851 + 5852 + void exprUnaryOp(){ 5853 + TokenIndex op = prev().type; 5854 + parse_expression(PREC_UNARY + 1); 5855 + switch(op){ 5856 + case TK("-"): 5857 + ctx()->s_expr.push(make_expr<NegatedExpr>(ctx()->s_expr.popx())); 5858 + break; 5859 + case TK("*"): 5860 + ctx()->s_expr.push(make_expr<StarredExpr>(ctx()->s_expr.popx())); 5861 + break; 5862 + default: FATAL_ERROR(); 5863 + } 5864 + } 5865 + 5866 + 5867 + void exprGroup(){ 5868 + match_newlines_repl(); 5869 + EXPR_TUPLE(); // () is just for change precedence 5870 + match_newlines_repl(); 5871 + consume(TK(")")); 5872 + } 5873 + 5874 + 5875 + template<typename T> 5876 + void _consume_comp(Expr_ expr){ 5877 + static_assert(std::is_base_of<CompExpr, T>::value); 5878 + std::unique_ptr<CompExpr> ce = make_expr<T>(); 5879 + ce->expr = std::move(expr); 5880 + ce->vars = EXPR_VARS(); 5881 + consume(TK("in")); 5882 + parse_expression(PREC_TERNARY + 1); 5883 + ce->iter = ctx()->s_expr.popx(); 5884 + match_newlines_repl(); 5885 + if(match(TK("if"))){ 5886 + parse_expression(PREC_TERNARY + 1); 5887 + ce->cond = ctx()->s_expr.popx(); 5888 + } 5889 + ctx()->s_expr.push(std::move(ce)); 5890 + match_newlines_repl(); 5891 + } 5892 + 5893 + 5894 + void exprList() { 5895 + int line = prev().line; 5896 + std::vector<Expr_> items; 5897 + do { 5898 + match_newlines_repl(); 5899 + if (curr().type == TK("]")) break; 5900 + EXPR(); 5901 + items.push_back(ctx()->s_expr.popx()); 5902 + match_newlines_repl(); 5903 + if(items.size()==1 && match(TK("for"))){ 5904 + _consume_comp<ListCompExpr>(std::move(items[0])); 5905 + consume(TK("]")); 5906 + return; 5907 + } 5908 + match_newlines_repl(); 5909 + } while (match(TK(","))); 5910 + consume(TK("]")); 5911 + auto e = make_expr<ListExpr>(std::move(items)); 5912 + e->line = line; // override line 5913 + ctx()->s_expr.push(std::move(e)); 5914 + } 5915 + 5916 + 5917 + void exprMap() { 5918 + bool parsing_dict = false; // {...} may be dict or set 5919 + std::vector<Expr_> items; 5920 + do { 5921 + match_newlines_repl(); 5922 + if (curr().type == TK("}")) break; 5923 + EXPR(); 5924 + if(curr().type == TK(":")) parsing_dict = true; 5925 + if(parsing_dict){ 5926 + consume(TK(":")); 5927 + EXPR(); 5928 + auto dict_item = make_expr<DictItemExpr>(); 5929 + dict_item->key = ctx()->s_expr.popx(); 5930 + dict_item->value = ctx()->s_expr.popx(); 5931 + items.push_back(std::move(dict_item)); 5932 + }else{ 5933 + items.push_back(ctx()->s_expr.popx()); 5934 + } 5935 + match_newlines_repl(); 5936 + if(items.size()==1 && match(TK("for"))){ 5937 + if(parsing_dict) _consume_comp<DictCompExpr>(std::move(items[0])); 5938 + else _consume_comp<SetCompExpr>(std::move(items[0])); 5939 + consume(TK("}")); 5940 + return; 5941 + } 5942 + match_newlines_repl(); 5943 + } while (match(TK(","))); 5944 + consume(TK("}")); 5945 + if(items.size()==0 || parsing_dict){ 5946 + auto e = make_expr<DictExpr>(std::move(items)); 5947 + ctx()->s_expr.push(std::move(e)); 5948 + }else{ 5949 + auto e = make_expr<SetExpr>(std::move(items)); 5950 + ctx()->s_expr.push(std::move(e)); 5951 + } 5952 + } 5953 + 5954 + 5955 + void exprCall() { 5956 + auto e = make_expr<CallExpr>(); 5957 + e->callable = ctx()->s_expr.popx(); 5958 + do { 5959 + match_newlines_repl(); 5960 + if (curr().type==TK(")")) break; 5961 + if(curr().type==TK("@id") && next().type==TK("=")) { 5962 + consume(TK("@id")); 5963 + Str key = prev().str(); 5964 + consume(TK("=")); 5965 + EXPR(); 5966 + e->kwargs.push_back({key, ctx()->s_expr.popx()}); 5967 + } else{ 5968 + if(!e->kwargs.empty()) SyntaxError("positional argument follows keyword argument"); 5969 + EXPR(); 5970 + e->args.push_back(ctx()->s_expr.popx()); 5971 + } 5972 + match_newlines_repl(); 5973 + } while (match(TK(","))); 5974 + consume(TK(")")); 5975 + if(e->args.size() > 32767) SyntaxError("too many positional arguments"); 5976 + if(e->kwargs.size() > 32767) SyntaxError("too many keyword arguments"); 5977 + ctx()->s_expr.push(std::move(e)); 5978 + } 5979 + 5980 + 5981 + void exprName(){ 5982 + Str name = prev().str(); 5983 + NameScope scope = name_scope(); 5984 + if(ctx()->co->global_names.count(name)){ 5985 + scope = NAME_GLOBAL; 5986 + } 5987 + ctx()->s_expr.push(make_expr<NameExpr>(name, scope)); 5988 + } 5989 + 5990 + 5991 + void exprAttrib() { 5992 + consume(TK("@id")); 5993 + ctx()->s_expr.push( 5994 + make_expr<AttribExpr>(ctx()->s_expr.popx(), prev().str()) 5995 + ); 5996 + } 5997 + 5998 + 5999 + void exprSubscr() { 6000 + auto e = make_expr<SubscrExpr>(); 6001 + e->a = ctx()->s_expr.popx(); 6002 + auto slice = make_expr<SliceExpr>(); 6003 + bool is_slice = false; 6004 + // a[<0> <state:1> : state<3> : state<5>] 6005 + int state = 0; 6006 + do{ 6007 + switch(state){ 6008 + case 0: 6009 + if(match(TK(":"))){ 6010 + is_slice=true; 6011 + state=2; 6012 + break; 6013 + } 6014 + if(match(TK("]"))) SyntaxError(); 6015 + EXPR_TUPLE(); 6016 + slice->start = ctx()->s_expr.popx(); 6017 + state=1; 6018 + break; 6019 + case 1: 6020 + if(match(TK(":"))){ 6021 + is_slice=true; 6022 + state=2; 6023 + break; 6024 + } 6025 + if(match(TK("]"))) goto __SUBSCR_END; 6026 + SyntaxError("expected ':' or ']'"); 6027 + break; 6028 + case 2: 6029 + if(match(TK(":"))){ 6030 + state=4; 6031 + break; 6032 + } 6033 + if(match(TK("]"))) goto __SUBSCR_END; 6034 + EXPR_TUPLE(); 6035 + slice->stop = ctx()->s_expr.popx(); 6036 + state=3; 6037 + break; 6038 + case 3: 6039 + if(match(TK(":"))){ 6040 + state=4; 6041 + break; 6042 + } 6043 + if(match(TK("]"))) goto __SUBSCR_END; 6044 + SyntaxError("expected ':' or ']'"); 6045 + break; 6046 + case 4: 6047 + if(match(TK("]"))) goto __SUBSCR_END; 6048 + EXPR_TUPLE(); 6049 + slice->step = ctx()->s_expr.popx(); 6050 + state=5; 6051 + break; 6052 + case 5: consume(TK("]")); goto __SUBSCR_END; 6053 + } 6054 + }while(true); 6055 + __SUBSCR_END: 6056 + if(is_slice){ 6057 + e->b = std::move(slice); 6058 + }else{ 6059 + if(state != 1) FATAL_ERROR(); 6060 + e->b = std::move(slice->start); 6061 + } 6062 + ctx()->s_expr.push(std::move(e)); 6063 + } 6064 + 6065 + 6066 + void exprLiteral0() { 6067 + ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type)); 6068 + } 6069 + 6070 + void compile_block_body() { 6071 + consume(TK(":")); 6072 + if(curr().type!=TK("@eol") && curr().type!=TK("@eof")){ 6073 + compile_stmt(); // inline block 6074 + return; 6075 + } 6076 + if(!match_newlines(mode()==REPL_MODE)){ 6077 + SyntaxError("expected a new line after ':'"); 6078 + } 6079 + consume(TK("@indent")); 6080 + while (curr().type != TK("@dedent")) { 6081 + match_newlines(); 6082 + compile_stmt(); 6083 + match_newlines(); 6084 + } 6085 + consume(TK("@dedent")); 6086 + } 6087 + 6088 + Str _compile_import() { 6089 + if(name_scope() != NAME_GLOBAL) SyntaxError("import statement should be used in global scope"); 6090 + consume(TK("@id")); 6091 + Str name = prev().str(); 6092 + ctx()->emit(OP_IMPORT_NAME, StrName(name).index, prev().line); 6093 + return name; 6094 + } 6095 + 6096 + // import a as b 6097 + void compile_normal_import() { 6098 + do { 6099 + Str name = _compile_import(); 6100 + if (match(TK("as"))) { 6101 + consume(TK("@id")); 6102 + name = prev().str(); 6103 + } 6104 + ctx()->emit(OP_STORE_GLOBAL, StrName(name).index, prev().line); 6105 + } while (match(TK(","))); 6106 + consume_end_stmt(); 6107 + } 6108 + 6109 + // from a import b as c, d as e 6110 + void compile_from_import() { 6111 + _compile_import(); 6112 + consume(TK("import")); 6113 + if (match(TK("*"))) { 6114 + ctx()->emit(OP_IMPORT_STAR, BC_NOARG, prev().line); 6115 + consume_end_stmt(); 6116 + return; 6117 + } 6118 + do { 6119 + ctx()->emit(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE); 6120 + consume(TK("@id")); 6121 + Str name = prev().str(); 6122 + ctx()->emit(OP_LOAD_ATTR, StrName(name).index, prev().line); 6123 + if (match(TK("as"))) { 6124 + consume(TK("@id")); 6125 + name = prev().str(); 6126 + } 6127 + ctx()->emit(OP_STORE_GLOBAL, StrName(name).index, prev().line); 6128 + } while (match(TK(","))); 6129 + ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); 6130 + consume_end_stmt(); 6131 + } 6132 + 6133 + void parse_expression(int precedence, bool push_stack=true) { 6134 + advance(); 6135 + PrattCallback prefix = rules[prev().type].prefix; 6136 + if (prefix == nullptr) SyntaxError(Str("expected an expression, but got ") + TK_STR(prev().type)); 6137 + (this->*prefix)(); 6138 + while (rules[curr().type].precedence >= precedence) { 6139 + TokenIndex op = curr().type; 6140 + advance(); 6141 + PrattCallback infix = rules[op].infix; 6142 + if(infix == nullptr) throw std::runtime_error("(infix == nullptr) is true"); 6143 + (this->*infix)(); 6144 + } 6145 + if(!push_stack) ctx()->emit_expr(); 6146 + } 6147 + 6148 + 6149 + void compile_if_stmt() { 6150 + EXPR(false); // condition 6151 + int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line); 6152 + compile_block_body(); 6153 + if (match(TK("elif"))) { 6154 + int exit_patch = ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, prev().line); 6155 + ctx()->patch_jump(patch); 6156 + compile_if_stmt(); 6157 + ctx()->patch_jump(exit_patch); 6158 + } else if (match(TK("else"))) { 6159 + int exit_patch = ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, prev().line); 6160 + ctx()->patch_jump(patch); 6161 + compile_block_body(); 6162 + ctx()->patch_jump(exit_patch); 6163 + } else { 6164 + ctx()->patch_jump(patch); 6165 + } 6166 + } 6167 + 6168 + 6169 + void compile_while_loop() { 6170 + ctx()->enter_block(WHILE_LOOP); 6171 + EXPR(false); // condition 6172 + int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line); 6173 + compile_block_body(); 6174 + ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE); 6175 + ctx()->patch_jump(patch); 6176 + ctx()->exit_block(); 6177 + } 6178 + 6179 + 6180 + void compile_for_loop() { 6181 + Expr_ vars = EXPR_VARS(); 6182 + consume(TK("in")); 6183 + EXPR_TUPLE(false); 6184 + ctx()->emit(OP_GET_ITER, BC_NOARG, BC_KEEPLINE); 6185 + ctx()->enter_block(FOR_LOOP); 6186 + ctx()->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE); 6187 + bool ok = vars->emit_store(ctx()); 6188 + if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind 6189 + compile_block_body(); 6190 + ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE); 6191 + ctx()->exit_block(); 6192 + } 6193 + 6194 + void compile_try_except() { 6195 + ctx()->enter_block(TRY_EXCEPT); 6196 + compile_block_body(); 6197 + std::vector<int> patches = { 6198 + ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE) 6199 + }; 6200 + ctx()->exit_block(); 6201 + do { 6202 + consume(TK("except")); 6203 + if(match(TK("@id"))){ 6204 + ctx()->emit(OP_EXCEPTION_MATCH, StrName(prev().str()).index, prev().line); 6205 + }else{ 6206 + ctx()->emit(OP_LOAD_TRUE, BC_NOARG, BC_KEEPLINE); 6207 + } 6208 + int patch = ctx()->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE); 6209 + // pop the exception on match 6210 + ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); 6211 + compile_block_body(); 6212 + patches.push_back(ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)); 6213 + ctx()->patch_jump(patch); 6214 + }while(curr().type == TK("except")); 6215 + // no match, re-raise 6216 + ctx()->emit(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE); 6217 + for (int patch : patches) ctx()->patch_jump(patch); 6218 + } 6219 + 6220 + void compile_decorated(){ 6221 + std::vector<Expr_> decorators; 6222 + do{ 6223 + EXPR(); 6224 + decorators.push_back(ctx()->s_expr.popx()); 6225 + if(!match_newlines_repl()) SyntaxError(); 6226 + }while(match(TK("@"))); 6227 + consume(TK("def")); 6228 + compile_function(decorators); 6229 + } 6230 + 6231 + bool try_compile_assignment(){ 6232 + Expr* lhs_p = ctx()->s_expr.top().get(); 6233 + bool inplace; 6234 + switch (curr().type) { 6235 + case TK("+="): case TK("-="): case TK("*="): case TK("/="): case TK("//="): case TK("%="): 6236 + case TK("<<="): case TK(">>="): case TK("&="): case TK("|="): case TK("^="): { 6237 + if(ctx()->is_compiling_class) SyntaxError(); 6238 + inplace = true; 6239 + advance(); 6240 + auto e = make_expr<BinaryExpr>(); 6241 + e->op = prev().type - 1; // -1 to remove = 6242 + e->lhs = ctx()->s_expr.popx(); 6243 + EXPR_TUPLE(); 6244 + e->rhs = ctx()->s_expr.popx(); 6245 + ctx()->s_expr.push(std::move(e)); 6246 + } break; 6247 + case TK("="): 6248 + inplace = false; 6249 + advance(); 6250 + EXPR_TUPLE(); 6251 + break; 6252 + default: return false; 6253 + } 6254 + // std::cout << ctx()->_log_s_expr() << std::endl; 6255 + Expr_ rhs = ctx()->s_expr.popx(); 6256 + 6257 + if(lhs_p->is_starred() || rhs->is_starred()){ 6258 + SyntaxError("can't use starred expression here"); 6259 + } 6260 + 6261 + rhs->emit(ctx()); 6262 + bool ok = lhs_p->emit_store(ctx()); 6263 + if(!ok) SyntaxError(); 6264 + if(!inplace) ctx()->s_expr.pop(); 6265 + return true; 6266 + } 6267 + 6268 + void compile_stmt() { 6269 + advance(); 6270 + int kw_line = prev().line; // backup line number 6271 + switch(prev().type){ 6272 + case TK("break"): 6273 + if (!ctx()->is_curr_block_loop()) SyntaxError("'break' outside loop"); 6274 + ctx()->emit(OP_LOOP_BREAK, BC_NOARG, kw_line); 6275 + consume_end_stmt(); 6276 + break; 6277 + case TK("continue"): 6278 + if (!ctx()->is_curr_block_loop()) SyntaxError("'continue' not properly in loop"); 6279 + ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, kw_line); 6280 + consume_end_stmt(); 6281 + break; 6282 + case TK("yield"): 6283 + if (contexts.size() <= 1) SyntaxError("'yield' outside function"); 6284 + EXPR_TUPLE(false); 6285 + // if yield present, mark the function as generator 6286 + ctx()->co->is_generator = true; 6287 + ctx()->emit(OP_YIELD_VALUE, BC_NOARG, kw_line); 6288 + consume_end_stmt(); 6289 + break; 6290 + case TK("yield from"): 6291 + if (contexts.size() <= 1) SyntaxError("'yield from' outside function"); 6292 + EXPR_TUPLE(false); 6293 + // if yield from present, mark the function as generator 6294 + ctx()->co->is_generator = true; 6295 + ctx()->emit(OP_GET_ITER, BC_NOARG, kw_line); 6296 + ctx()->enter_block(FOR_LOOP); 6297 + ctx()->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE); 6298 + ctx()->emit(OP_YIELD_VALUE, BC_NOARG, BC_KEEPLINE); 6299 + ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE); 6300 + ctx()->exit_block(); 6301 + consume_end_stmt(); 6302 + break; 6303 + case TK("return"): 6304 + if (contexts.size() <= 1) SyntaxError("'return' outside function"); 6305 + if(match_end_stmt()){ 6306 + ctx()->emit(OP_LOAD_NONE, BC_NOARG, kw_line); 6307 + }else{ 6308 + EXPR_TUPLE(false); 6309 + consume_end_stmt(); 6310 + } 6311 + ctx()->emit(OP_RETURN_VALUE, BC_NOARG, kw_line); 6312 + break; 6313 + /*************************************************/ 6314 + case TK("if"): compile_if_stmt(); break; 6315 + case TK("while"): compile_while_loop(); break; 6316 + case TK("for"): compile_for_loop(); break; 6317 + case TK("import"): compile_normal_import(); break; 6318 + case TK("from"): compile_from_import(); break; 6319 + case TK("def"): compile_function(); break; 6320 + case TK("@"): compile_decorated(); break; 6321 + case TK("try"): compile_try_except(); break; 6322 + case TK("pass"): consume_end_stmt(); break; 6323 + /*************************************************/ 6324 + case TK("assert"): 6325 + EXPR_TUPLE(false); 6326 + ctx()->emit(OP_ASSERT, BC_NOARG, kw_line); 6327 + consume_end_stmt(); 6328 + break; 6329 + case TK("global"): 6330 + do { 6331 + consume(TK("@id")); 6332 + ctx()->co->global_names.insert(prev().str()); 6333 + } while (match(TK(","))); 6334 + consume_end_stmt(); 6335 + break; 6336 + case TK("raise"): { 6337 + consume(TK("@id")); 6338 + int dummy_t = StrName(prev().str()).index; 6339 + if(match(TK("(")) && !match(TK(")"))){ 6340 + EXPR(false); consume(TK(")")); 6341 + }else{ 6342 + ctx()->emit(OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE); 6343 + } 6344 + ctx()->emit(OP_RAISE, dummy_t, kw_line); 6345 + consume_end_stmt(); 6346 + } break; 6347 + case TK("del"): { 6348 + EXPR_TUPLE(); 6349 + Expr_ e = ctx()->s_expr.popx(); 6350 + bool ok = e->emit_del(ctx()); 6351 + if(!ok) SyntaxError(); 6352 + consume_end_stmt(); 6353 + } break; 6354 + case TK("with"): { 6355 + EXPR(false); 6356 + consume(TK("as")); 6357 + consume(TK("@id")); 6358 + StrName name(prev().str()); 6359 + ctx()->emit(OP_STORE_NAME, name.index, prev().line); 6360 + ctx()->emit(OP_LOAD_NAME, name.index, prev().line); 6361 + ctx()->emit(OP_WITH_ENTER, BC_NOARG, prev().line); 6362 + compile_block_body(); 6363 + ctx()->emit(OP_LOAD_NAME, name.index, prev().line); 6364 + ctx()->emit(OP_WITH_EXIT, BC_NOARG, prev().line); 6365 + } break; 6366 + /*************************************************/ 6367 + case TK("$label"): { 6368 + if(mode()!=EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE"); 6369 + consume(TK("@id")); 6370 + bool ok = ctx()->add_label(prev().str()); 6371 + if(!ok) SyntaxError("label " + prev().str().escape() + " already exists"); 6372 + consume_end_stmt(); 6373 + } break; 6374 + case TK("$goto"): 6375 + if(mode()!=EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE"); 6376 + consume(TK("@id")); 6377 + ctx()->emit(OP_GOTO, StrName(prev().str()).index, prev().line); 6378 + consume_end_stmt(); 6379 + break; 6380 + /*************************************************/ 6381 + // handle dangling expression or assignment 6382 + default: { 6383 + advance(-1); // do revert since we have pre-called advance() at the beginning 6384 + EXPR_TUPLE(); 6385 + if(!try_compile_assignment()){ 6386 + ctx()->emit_expr(); 6387 + if(mode()==REPL_MODE && name_scope()==NAME_GLOBAL){ 6388 + ctx()->emit(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE); 6389 + }else{ 6390 + ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); 6391 + } 6392 + } 6393 + consume_end_stmt(); 6394 + } 6395 + } 6396 + } 6397 + 6398 + 6399 + void compile_class(){ 6400 + consume(TK("@id")); 6401 + int namei = StrName(prev().str()).index; 6402 + int super_namei = -1; 6403 + if(match(TK("(")) && match(TK("@id"))){ 6404 + super_namei = StrName(prev().str()).index; 6405 + consume(TK(")")); 6406 + } 6407 + if(super_namei == -1) ctx()->emit(OP_LOAD_NONE, BC_NOARG, prev().line); 6408 + else ctx()->emit(OP_LOAD_GLOBAL, super_namei, prev().line); 6409 + ctx()->emit(OP_BEGIN_CLASS, namei, BC_KEEPLINE); 6410 + ctx()->is_compiling_class = true; 6411 + compile_block_body(); 6412 + ctx()->is_compiling_class = false; 6413 + ctx()->emit(OP_END_CLASS, BC_NOARG, BC_KEEPLINE); 6414 + } 6415 + 6416 + void _compile_f_args(FuncDecl_ decl, bool enable_type_hints){ 6417 + int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs 6418 + do { 6419 + if(state == 3) SyntaxError("**kwargs should be the last argument"); 6420 + match_newlines(); 6421 + if(match(TK("*"))){ 6422 + if(state < 1) state = 1; 6423 + else SyntaxError("*args should be placed before **kwargs"); 6424 + } 6425 + else if(match(TK("**"))){ 6426 + state = 3; 6427 + } 6428 + consume(TK("@id")); 6429 + StrName name = prev().str(); 6430 + 6431 + // check duplicate argument name 6432 + for(int i: decl->args){ 6433 + if(decl->code->varnames[i] == name) { 6434 + SyntaxError("duplicate argument name"); 6435 + } 6436 + } 6437 + if(decl->starred_arg!=-1 && decl->code->varnames[decl->starred_arg] == name){ 6438 + SyntaxError("duplicate argument name"); 6439 + } 6440 + for(auto& kv: decl->kwargs){ 6441 + if(decl->code->varnames[kv.key] == name){ 6442 + SyntaxError("duplicate argument name"); 6443 + } 6444 + } 6445 + 6446 + // eat type hints 6447 + if(enable_type_hints && match(TK(":"))) consume(TK("@id")); 6448 + if(state == 0 && curr().type == TK("=")) state = 2; 6449 + int index = ctx()->add_varname(name); 6450 + switch (state) 6451 + { 6452 + case 0: 6453 + decl->args.push_back(index); 6454 + break; 6455 + case 1: 6456 + decl->starred_arg = index; 6457 + state+=1; 6458 + break; 6459 + case 2: { 6460 + consume(TK("=")); 6461 + PyObject* value = read_literal(); 6462 + if(value == nullptr){ 6463 + SyntaxError(Str("expect a literal, not ") + TK_STR(curr().type)); 6464 + } 6465 + decl->kwargs.push_back(FuncDecl::KwArg{index, value}); 6466 + } break; 6467 + case 3: SyntaxError("**kwargs is not supported yet"); break; 6468 + } 6469 + } while (match(TK(","))); 6470 + } 6471 + 6472 + void compile_function(const std::vector<Expr_>& decorators={}){ 6473 + Str obj_name; 6474 + Str decl_name; 6475 + consume(TK("@id")); 6476 + decl_name = prev().str(); 6477 + if(!ctx()->is_compiling_class && match(TK("@"))){ 6478 + consume(TK("@id")); 6479 + obj_name = decl_name; 6480 + decl_name = prev().str(); 6481 + } 6482 + FuncDecl_ decl = push_f_context(decl_name); 6483 + consume(TK("(")); 6484 + if (!match(TK(")"))) { 6485 + _compile_f_args(decl, true); 6486 + consume(TK(")")); 6487 + } 6488 + if(match(TK("->"))){ 6489 + if(!match(TK("None"))) consume(TK("@id")); 6490 + } 6491 + compile_block_body(); 6492 + pop_context(); 6493 + 6494 + PyObject* docstring = nullptr; 6495 + if(decl->code->codes.size()>=2 && decl->code->codes[0].op == OP_LOAD_CONST && decl->code->codes[1].op == OP_POP_TOP){ 6496 + PyObject* c = decl->code->consts[decl->code->codes[0].arg]; 6497 + if(is_type(c, vm->tp_str)){ 6498 + decl->code->codes[0].op = OP_NO_OP; 6499 + decl->code->codes[1].op = OP_NO_OP; 6500 + docstring = c; 6501 + } 6502 + } 6503 + ctx()->emit(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line); 6504 + if(docstring != nullptr){ 6505 + ctx()->emit(OP_SETUP_DOCSTRING, ctx()->add_const(docstring), prev().line); 6506 + } 6507 + // add decorators 6508 + for(auto it=decorators.rbegin(); it!=decorators.rend(); ++it){ 6509 + (*it)->emit(ctx()); 6510 + ctx()->emit(OP_ROT_TWO, BC_NOARG, (*it)->line); 6511 + ctx()->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE); 6512 + ctx()->emit(OP_ROT_TWO, BC_NOARG, BC_KEEPLINE); 6513 + ctx()->emit(OP_CALL, 1, (*it)->line); 6514 + } 6515 + if(!ctx()->is_compiling_class){ 6516 + if(obj_name.empty()){ 6517 + auto e = make_expr<NameExpr>(decl_name, name_scope()); 6518 + e->emit_store(ctx()); 6519 + } else { 6520 + ctx()->emit(OP_LOAD_GLOBAL, StrName(obj_name).index, prev().line); 6521 + int index = StrName(decl_name).index; 6522 + ctx()->emit(OP_STORE_ATTR, index, prev().line); 6523 + } 6524 + }else{ 6525 + int index = StrName(decl_name).index; 6526 + ctx()->emit(OP_STORE_CLASS_ATTR, index, prev().line); 6527 + } 6528 + } 6529 + 6530 + PyObject* to_object(const TokenValue& value){ 6531 + PyObject* obj = nullptr; 6532 + if(std::holds_alternative<i64>(value)){ 6533 + obj = VAR(std::get<i64>(value)); 6534 + } 6535 + if(std::holds_alternative<f64>(value)){ 6536 + obj = VAR(std::get<f64>(value)); 6537 + } 6538 + if(std::holds_alternative<Str>(value)){ 6539 + obj = VAR(std::get<Str>(value)); 6540 + } 6541 + if(obj == nullptr) FATAL_ERROR(); 6542 + return obj; 6543 + } 6544 + 6545 + PyObject* read_literal(){ 6546 + advance(); 6547 + switch(prev().type){ 6548 + case TK("-"): { 6549 + consume(TK("@num")); 6550 + PyObject* val = to_object(prev().value); 6551 + return vm->num_negated(val); 6552 + } 6553 + case TK("@num"): return to_object(prev().value); 6554 + case TK("@str"): return to_object(prev().value); 6555 + case TK("True"): return VAR(true); 6556 + case TK("False"): return VAR(false); 6557 + case TK("None"): return vm->None; 6558 + case TK("..."): return vm->Ellipsis; 6559 + default: break; 6560 + } 6561 + return nullptr; 6562 + } 6563 + 6564 + void SyntaxError(Str msg){ lexer->throw_err("SyntaxError", msg, err().line, err().start); } 6565 + void SyntaxError(){ lexer->throw_err("SyntaxError", "invalid syntax", err().line, err().start); } 6566 + void IndentationError(Str msg){ lexer->throw_err("IndentationError", msg, err().line, err().start); } 6567 + 6568 + public: 6569 + Compiler(VM* vm, const Str& source, const Str& filename, CompileMode mode, bool unknown_global_scope=false){ 6570 + this->vm = vm; 6571 + this->used = false; 6572 + this->unknown_global_scope = unknown_global_scope; 6573 + this->lexer = std::make_unique<Lexer>( 6574 + make_sp<SourceData>(source, filename, mode) 6575 + ); 6576 + init_pratt_rules(); 6577 + } 6578 + 6579 + CodeObject_ compile(){ 6580 + if(used) FATAL_ERROR(); 6581 + used = true; 6582 + 6583 + tokens = lexer->run(); 6584 + // if(lexer->src->filename == "<stdin>"){ 6585 + // for(auto& t: tokens) std::cout << t.info() << std::endl; 6586 + // } 6587 + 6588 + CodeObject_ code = push_global_context(); 6589 + 6590 + advance(); // skip @sof, so prev() is always valid 6591 + match_newlines(); // skip possible leading '\n' 6592 + 6593 + if(mode()==EVAL_MODE) { 6594 + EXPR_TUPLE(false); 6595 + consume(TK("@eof")); 6596 + ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); 6597 + pop_context(); 6598 + return code; 6599 + }else if(mode()==JSON_MODE){ 6600 + EXPR(); 6601 + Expr_ e = ctx()->s_expr.popx(); 6602 + if(!e->is_json_object()) SyntaxError("expect a JSON object, literal or array"); 6603 + consume(TK("@eof")); 6604 + e->emit(ctx()); 6605 + ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); 6606 + pop_context(); 6607 + return code; 6608 + } 6609 + 6610 + while (!match(TK("@eof"))) { 6611 + if (match(TK("class"))) { 6612 + compile_class(); 6613 + } else { 6614 + compile_stmt(); 6615 + } 6616 + match_newlines(); 6617 + } 6618 + pop_context(); 6619 + return code; 6620 + } 6621 + }; 6622 + 6623 + } // namespace pkpy 6624 + 6625 + 6626 + #ifdef _WIN32 6627 + #define WIN32_LEAN_AND_MEAN 6628 + #include <Windows.h> 6629 + #endif 6630 + 6631 + namespace pkpy{ 6632 + 6633 + #ifdef _WIN32 6634 + 6635 + inline std::string getline(bool* eof=nullptr) { 6636 + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); 6637 + std::wstringstream wss; 6638 + WCHAR buf; 6639 + DWORD read; 6640 + while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') { 6641 + if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z 6642 + wss << buf; 6643 + } 6644 + std::wstring wideInput = wss.str(); 6645 + int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL); 6646 + std::string output; 6647 + output.resize(length); 6648 + WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL); 6649 + if(!output.empty() && output.back() == '\r') output.pop_back(); 6650 + return output; 6651 + } 6652 + 6653 + #else 6654 + 6655 + inline std::string getline(bool* eof=nullptr){ 6656 + std::string line; 6657 + if(!std::getline(std::cin, line)){ 6658 + if(eof) *eof = true; 6659 + } 6660 + return line; 6661 + } 6662 + 6663 + #endif 6664 + 6665 + class REPL { 6666 + protected: 6667 + int need_more_lines = 0; 6668 + std::string buffer; 6669 + VM* vm; 6670 + public: 6671 + REPL(VM* vm) : vm(vm){ 6672 + vm->_stdout(vm, "pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); 6673 + vm->_stdout(vm, fmt("[", sizeof(void*)*8, " bit]" "\n")); 6674 + vm->_stdout(vm, "https://github.com/blueloveTH/pocketpy" "\n"); 6675 + vm->_stdout(vm, "Type \"exit()\" to exit." "\n"); 6676 + } 6677 + 6678 + bool input(std::string line){ 6679 + CompileMode mode = REPL_MODE; 6680 + if(need_more_lines){ 6681 + buffer += line; 6682 + buffer += '\n'; 6683 + int n = buffer.size(); 6684 + if(n>=need_more_lines){ 6685 + for(int i=buffer.size()-need_more_lines; i<buffer.size(); i++){ 6686 + // no enough lines 6687 + if(buffer[i] != '\n') return true; 6688 + } 6689 + need_more_lines = 0; 6690 + line = buffer; 6691 + buffer.clear(); 6692 + mode = EXEC_MODE; 6693 + }else{ 6694 + return true; 6695 + } 6696 + } 6697 + 6698 + try{ 6699 + vm->exec(line, "<stdin>", mode); 6700 + }catch(NeedMoreLines& ne){ 6701 + buffer += line; 6702 + buffer += '\n'; 6703 + need_more_lines = ne.is_compiling_class ? 3 : 2; 6704 + if (need_more_lines) return true; 6705 + } 6706 + return false; 6707 + } 6708 + }; 6709 + 6710 + } // namespace pkpy 6711 + 6712 + // generated on 2023-05-08 20:47:05 6713 + #include <map> 6714 + #include <string> 6715 + 6716 + namespace pkpy{ 6717 + inline static std::map<std::string, const char*> kPythonLibs = { 6718 + {"collections", "\x63\x6c\x61\x73\x73\x20\x5f\x4c\x69\x6e\x6b\x65\x64\x4c\x69\x73\x74\x4e\x6f\x64\x65\x3a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x6e\x69\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x70\x72\x65\x76\x2c\x20\x6e\x65\x78\x74\x2c\x20\x76\x61\x6c\x75\x65\x29\x20\x2d\x3e\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x70\x72\x65\x76\x20\x3d\x20\x70\x72\x65\x76\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x6e\x65\x78\x74\x20\x3d\x20\x6e\x65\x78\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x76\x61\x6c\x75\x65\x20\x3d\x20\x76\x61\x6c\x75\x65\x0a\x0a\x63\x6c\x61\x73\x73\x20\x64\x65\x71\x75\x65\x3a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x6e\x69\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3d\x4e\x6f\x6e\x65\x29\x20\x2d\x3e\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x20\x3d\x20\x5f\x4c\x69\x6e\x6b\x65\x64\x4c\x69\x73\x74\x4e\x6f\x64\x65\x28\x4e\x6f\x6e\x65\x2c\x20\x4e\x6f\x6e\x65\x2c\x20\x4e\x6f\x6e\x65\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x20\x3d\x20\x5f\x4c\x69\x6e\x6b\x65\x64\x4c\x69\x73\x74\x4e\x6f\x64\x65\x28\x4e\x6f\x6e\x65\x2c\x20\x4e\x6f\x6e\x65\x2c\x20\x4e\x6f\x6e\x65\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x20\x3d\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x2e\x70\x72\x65\x76\x20\x3d\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x73\x69\x7a\x65\x20\x3d\x20\x30\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x20\x69\x73\x20\x6e\x6f\x74\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x76\x61\x6c\x75\x65\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x61\x70\x70\x65\x6e\x64\x28\x76\x61\x6c\x75\x65\x29\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x61\x70\x70\x65\x6e\x64\x28\x73\x65\x6c\x66\x2c\x20\x76\x61\x6c\x75\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x6f\x64\x65\x20\x3d\x20\x5f\x4c\x69\x6e\x6b\x65\x64\x4c\x69\x73\x74\x4e\x6f\x64\x65\x28\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x2e\x70\x72\x65\x76\x2c\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x2c\x20\x76\x61\x6c\x75\x65\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x2e\x70\x72\x65\x76\x2e\x6e\x65\x78\x74\x20\x3d\x20\x6e\x6f\x64\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x2e\x70\x72\x65\x76\x20\x3d\x20\x6e\x6f\x64\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x73\x69\x7a\x65\x20\x2b\x3d\x20\x31\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x61\x70\x70\x65\x6e\x64\x6c\x65\x66\x74\x28\x73\x65\x6c\x66\x2c\x20\x76\x61\x6c\x75\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x6f\x64\x65\x20\x3d\x20\x5f\x4c\x69\x6e\x6b\x65\x64\x4c\x69\x73\x74\x4e\x6f\x64\x65\x28\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2c\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x2c\x20\x76\x61\x6c\x75\x65\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x2e\x70\x72\x65\x76\x20\x3d\x20\x6e\x6f\x64\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x20\x3d\x20\x6e\x6f\x64\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x73\x69\x7a\x65\x20\x2b\x3d\x20\x31\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x70\x6f\x70\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x73\x73\x65\x72\x74\x20\x73\x65\x6c\x66\x2e\x73\x69\x7a\x65\x20\x3e\x20\x30\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x6f\x64\x65\x20\x3d\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x2e\x70\x72\x65\x76\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x6f\x64\x65\x2e\x70\x72\x65\x76\x2e\x6e\x65\x78\x74\x20\x3d\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x2e\x70\x72\x65\x76\x20\x3d\x20\x6e\x6f\x64\x65\x2e\x70\x72\x65\x76\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x73\x69\x7a\x65\x20\x2d\x3d\x20\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6e\x6f\x64\x65\x2e\x76\x61\x6c\x75\x65\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x70\x6f\x70\x6c\x65\x66\x74\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x73\x73\x65\x72\x74\x20\x73\x65\x6c\x66\x2e\x73\x69\x7a\x65\x20\x3e\x20\x30\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x6f\x64\x65\x20\x3d\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x6f\x64\x65\x2e\x6e\x65\x78\x74\x2e\x70\x72\x65\x76\x20\x3d\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x20\x3d\x20\x6e\x6f\x64\x65\x2e\x6e\x65\x78\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x73\x69\x7a\x65\x20\x2d\x3d\x20\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6e\x6f\x64\x65\x2e\x76\x61\x6c\x75\x65\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x63\x6f\x70\x79\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x65\x77\x5f\x6c\x69\x73\x74\x20\x3d\x20\x64\x65\x71\x75\x65\x28\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x76\x61\x6c\x75\x65\x20\x69\x6e\x20\x73\x65\x6c\x66\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x65\x77\x5f\x6c\x69\x73\x74\x2e\x61\x70\x70\x65\x6e\x64\x28\x76\x61\x6c\x75\x65\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6e\x65\x77\x5f\x6c\x69\x73\x74\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x6c\x65\x6e\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x73\x69\x7a\x65\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x74\x65\x72\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x6f\x64\x65\x20\x3d\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x6e\x6f\x64\x65\x20\x69\x73\x20\x6e\x6f\x74\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x69\x65\x6c\x64\x20\x6e\x6f\x64\x65\x2e\x76\x61\x6c\x75\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x6f\x64\x65\x20\x3d\x20\x6e\x6f\x64\x65\x2e\x6e\x65\x78\x74\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x72\x65\x70\x72\x5f\x5f\x28\x73\x65\x6c\x66\x29\x20\x2d\x3e\x20\x73\x74\x72\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x66\x22\x64\x65\x71\x75\x65\x28\x7b\x6c\x69\x73\x74\x28\x73\x65\x6c\x66\x29\x7d\x29\x22\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x65\x71\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x5f\x5f\x6f\x3a\x20\x6f\x62\x6a\x65\x63\x74\x29\x20\x2d\x3e\x20\x62\x6f\x6f\x6c\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6e\x6f\x74\x20\x69\x73\x69\x6e\x73\x74\x61\x6e\x63\x65\x28\x5f\x5f\x6f\x2c\x20\x64\x65\x71\x75\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x20\x21\x3d\x20\x6c\x65\x6e\x28\x5f\x5f\x6f\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x74\x31\x2c\x20\x74\x32\x20\x3d\x20\x73\x65\x6c\x66\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x2c\x20\x5f\x5f\x6f\x2e\x68\x65\x61\x64\x2e\x6e\x65\x78\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x74\x31\x20\x69\x73\x20\x6e\x6f\x74\x20\x73\x65\x6c\x66\x2e\x74\x61\x69\x6c\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x74\x31\x2e\x76\x61\x6c\x75\x65\x20\x21\x3d\x20\x74\x32\x2e\x76\x61\x6c\x75\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x74\x31\x2c\x20\x74\x32\x20\x3d\x20\x74\x31\x2e\x6e\x65\x78\x74\x2c\x20\x74\x32\x2e\x6e\x65\x78\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x54\x72\x75\x65\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x6e\x65\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x5f\x5f\x6f\x3a\x20\x6f\x62\x6a\x65\x63\x74\x29\x20\x2d\x3e\x20\x62\x6f\x6f\x6c\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6e\x6f\x74\x20\x73\x65\x6c\x66\x20\x3d\x3d\x20\x5f\x5f\x6f\x0a\x0a\x0a\x64\x65\x66\x20\x43\x6f\x75\x6e\x74\x65\x72\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x3a\x0a\x20\x20\x20\x20\x61\x20\x3d\x20\x7b\x7d\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x78\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x78\x20\x69\x6e\x20\x61\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x61\x5b\x78\x5d\x20\x2b\x3d\x20\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x65\x6c\x73\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x61\x5b\x78\x5d\x20\x3d\x20\x31\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x61"}, 6719 + {"requests", "\x63\x6c\x61\x73\x73\x20\x52\x65\x73\x70\x6f\x6e\x73\x65\x3a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x6e\x69\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x73\x74\x61\x74\x75\x73\x5f\x63\x6f\x64\x65\x2c\x20\x72\x65\x61\x73\x6f\x6e\x2c\x20\x63\x6f\x6e\x74\x65\x6e\x74\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x73\x74\x61\x74\x75\x73\x5f\x63\x6f\x64\x65\x20\x3d\x20\x73\x74\x61\x74\x75\x73\x5f\x63\x6f\x64\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x72\x65\x61\x73\x6f\x6e\x20\x3d\x20\x72\x65\x61\x73\x6f\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x63\x6f\x6e\x74\x65\x6e\x74\x20\x3d\x20\x63\x6f\x6e\x74\x65\x6e\x74\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x73\x73\x65\x72\x74\x20\x74\x79\x70\x65\x28\x73\x65\x6c\x66\x2e\x73\x74\x61\x74\x75\x73\x5f\x63\x6f\x64\x65\x29\x20\x69\x73\x20\x69\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x73\x73\x65\x72\x74\x20\x74\x79\x70\x65\x28\x73\x65\x6c\x66\x2e\x72\x65\x61\x73\x6f\x6e\x29\x20\x69\x73\x20\x73\x74\x72\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x73\x73\x65\x72\x74\x20\x74\x79\x70\x65\x28\x73\x65\x6c\x66\x2e\x63\x6f\x6e\x74\x65\x6e\x74\x29\x20\x69\x73\x20\x62\x79\x74\x65\x73\x0a\x0a\x20\x20\x20\x20\x40\x70\x72\x6f\x70\x65\x72\x74\x79\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x74\x65\x78\x74\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x63\x6f\x6e\x74\x65\x6e\x74\x2e\x64\x65\x63\x6f\x64\x65\x28\x29\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x72\x65\x70\x72\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x63\x6f\x64\x65\x20\x3d\x20\x73\x65\x6c\x66\x2e\x73\x74\x61\x74\x75\x73\x5f\x63\x6f\x64\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x66\x27\x3c\x52\x65\x73\x70\x6f\x6e\x73\x65\x20\x5b\x7b\x63\x6f\x64\x65\x7d\x5d\x3e\x27\x0a\x0a\x64\x65\x66\x20\x5f\x70\x61\x72\x73\x65\x5f\x68\x28\x68\x65\x61\x64\x65\x72\x73\x29\x3a\x0a\x20\x20\x20\x20\x69\x66\x20\x68\x65\x61\x64\x65\x72\x73\x20\x69\x73\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x5b\x5d\x0a\x20\x20\x20\x20\x69\x66\x20\x74\x79\x70\x65\x28\x68\x65\x61\x64\x65\x72\x73\x29\x20\x69\x73\x20\x64\x69\x63\x74\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6c\x69\x73\x74\x28\x68\x65\x61\x64\x65\x72\x73\x2e\x69\x74\x65\x6d\x73\x28\x29\x29\x0a\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x56\x61\x6c\x75\x65\x45\x72\x72\x6f\x72\x28\x27\x68\x65\x61\x64\x65\x72\x73\x20\x6d\x75\x73\x74\x20\x62\x65\x20\x64\x69\x63\x74\x20\x6f\x72\x20\x4e\x6f\x6e\x65\x27\x29\x0a\x0a\x64\x65\x66\x20\x67\x65\x74\x28\x75\x72\x6c\x2c\x20\x68\x65\x61\x64\x65\x72\x73\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x68\x65\x61\x64\x65\x72\x73\x20\x3d\x20\x5f\x70\x61\x72\x73\x65\x5f\x68\x28\x68\x65\x61\x64\x65\x72\x73\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x5f\x72\x65\x71\x75\x65\x73\x74\x28\x27\x47\x45\x54\x27\x2c\x20\x75\x72\x6c\x2c\x20\x68\x65\x61\x64\x65\x72\x73\x2c\x20\x4e\x6f\x6e\x65\x29\x0a\x0a\x64\x65\x66\x20\x70\x6f\x73\x74\x28\x75\x72\x6c\x2c\x20\x64\x61\x74\x61\x3a\x20\x62\x79\x74\x65\x73\x2c\x20\x68\x65\x61\x64\x65\x72\x73\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x68\x65\x61\x64\x65\x72\x73\x20\x3d\x20\x5f\x70\x61\x72\x73\x65\x5f\x68\x28\x68\x65\x61\x64\x65\x72\x73\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x5f\x72\x65\x71\x75\x65\x73\x74\x28\x27\x50\x4f\x53\x54\x27\x2c\x20\x75\x72\x6c\x2c\x20\x68\x65\x61\x64\x65\x72\x73\x2c\x20\x64\x61\x74\x61\x29\x0a\x0a\x64\x65\x66\x20\x70\x75\x74\x28\x75\x72\x6c\x2c\x20\x64\x61\x74\x61\x3a\x20\x62\x79\x74\x65\x73\x2c\x20\x68\x65\x61\x64\x65\x72\x73\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x68\x65\x61\x64\x65\x72\x73\x20\x3d\x20\x5f\x70\x61\x72\x73\x65\x5f\x68\x28\x68\x65\x61\x64\x65\x72\x73\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x5f\x72\x65\x71\x75\x65\x73\x74\x28\x27\x50\x55\x54\x27\x2c\x20\x75\x72\x6c\x2c\x20\x68\x65\x61\x64\x65\x72\x73\x2c\x20\x64\x61\x74\x61\x29\x0a\x0a\x64\x65\x66\x20\x64\x65\x6c\x65\x74\x65\x28\x75\x72\x6c\x2c\x20\x68\x65\x61\x64\x65\x72\x73\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x68\x65\x61\x64\x65\x72\x73\x20\x3d\x20\x5f\x70\x61\x72\x73\x65\x5f\x68\x28\x68\x65\x61\x64\x65\x72\x73\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x5f\x72\x65\x71\x75\x65\x73\x74\x28\x27\x44\x45\x4c\x45\x54\x45\x27\x2c\x20\x75\x72\x6c\x2c\x20\x68\x65\x61\x64\x65\x72\x73\x2c\x20\x4e\x6f\x6e\x65\x29"}, 6720 + {"this", "\x70\x72\x69\x6e\x74\x28\x22\x22\x22\x54\x68\x65\x20\x5a\x65\x6e\x20\x6f\x66\x20\x50\x79\x74\x68\x6f\x6e\x2c\x20\x62\x79\x20\x54\x69\x6d\x20\x50\x65\x74\x65\x72\x73\x0a\x0a\x42\x65\x61\x75\x74\x69\x66\x75\x6c\x20\x69\x73\x20\x62\x65\x74\x74\x65\x72\x20\x74\x68\x61\x6e\x20\x75\x67\x6c\x79\x2e\x0a\x45\x78\x70\x6c\x69\x63\x69\x74\x20\x69\x73\x20\x62\x65\x74\x74\x65\x72\x20\x74\x68\x61\x6e\x20\x69\x6d\x70\x6c\x69\x63\x69\x74\x2e\x0a\x53\x69\x6d\x70\x6c\x65\x20\x69\x73\x20\x62\x65\x74\x74\x65\x72\x20\x74\x68\x61\x6e\x20\x63\x6f\x6d\x70\x6c\x65\x78\x2e\x0a\x43\x6f\x6d\x70\x6c\x65\x78\x20\x69\x73\x20\x62\x65\x74\x74\x65\x72\x20\x74\x68\x61\x6e\x20\x63\x6f\x6d\x70\x6c\x69\x63\x61\x74\x65\x64\x2e\x0a\x46\x6c\x61\x74\x20\x69\x73\x20\x62\x65\x74\x74\x65\x72\x20\x74\x68\x61\x6e\x20\x6e\x65\x73\x74\x65\x64\x2e\x0a\x53\x70\x61\x72\x73\x65\x20\x69\x73\x20\x62\x65\x74\x74\x65\x72\x20\x74\x68\x61\x6e\x20\x64\x65\x6e\x73\x65\x2e\x0a\x52\x65\x61\x64\x61\x62\x69\x6c\x69\x74\x79\x20\x63\x6f\x75\x6e\x74\x73\x2e\x0a\x53\x70\x65\x63\x69\x61\x6c\x20\x63\x61\x73\x65\x73\x20\x61\x72\x65\x6e\x27\x74\x20\x73\x70\x65\x63\x69\x61\x6c\x20\x65\x6e\x6f\x75\x67\x68\x20\x74\x6f\x20\x62\x72\x65\x61\x6b\x20\x74\x68\x65\x20\x72\x75\x6c\x65\x73\x2e\x0a\x41\x6c\x74\x68\x6f\x75\x67\x68\x20\x70\x72\x61\x63\x74\x69\x63\x61\x6c\x69\x74\x79\x20\x62\x65\x61\x74\x73\x20\x70\x75\x72\x69\x74\x79\x2e\x0a\x45\x72\x72\x6f\x72\x73\x20\x73\x68\x6f\x75\x6c\x64\x20\x6e\x65\x76\x65\x72\x20\x70\x61\x73\x73\x20\x73\x69\x6c\x65\x6e\x74\x6c\x79\x2e\x0a\x55\x6e\x6c\x65\x73\x73\x20\x65\x78\x70\x6c\x69\x63\x69\x74\x6c\x79\x20\x73\x69\x6c\x65\x6e\x63\x65\x64\x2e\x0a\x49\x6e\x20\x74\x68\x65\x20\x66\x61\x63\x65\x20\x6f\x66\x20\x61\x6d\x62\x69\x67\x75\x69\x74\x79\x2c\x20\x72\x65\x66\x75\x73\x65\x20\x74\x68\x65\x20\x74\x65\x6d\x70\x74\x61\x74\x69\x6f\x6e\x20\x74\x6f\x20\x67\x75\x65\x73\x73\x2e\x0a\x54\x68\x65\x72\x65\x20\x73\x68\x6f\x75\x6c\x64\x20\x62\x65\x20\x6f\x6e\x65\x2d\x2d\x20\x61\x6e\x64\x20\x70\x72\x65\x66\x65\x72\x61\x62\x6c\x79\x20\x6f\x6e\x6c\x79\x20\x6f\x6e\x65\x20\x2d\x2d\x6f\x62\x76\x69\x6f\x75\x73\x20\x77\x61\x79\x20\x74\x6f\x20\x64\x6f\x20\x69\x74\x2e\x0a\x41\x6c\x74\x68\x6f\x75\x67\x68\x20\x74\x68\x61\x74\x20\x77\x61\x79\x20\x6d\x61\x79\x20\x6e\x6f\x74\x20\x62\x65\x20\x6f\x62\x76\x69\x6f\x75\x73\x20\x61\x74\x20\x66\x69\x72\x73\x74\x20\x75\x6e\x6c\x65\x73\x73\x20\x79\x6f\x75\x27\x72\x65\x20\x44\x75\x74\x63\x68\x2e\x0a\x4e\x6f\x77\x20\x69\x73\x20\x62\x65\x74\x74\x65\x72\x20\x74\x68\x61\x6e\x20\x6e\x65\x76\x65\x72\x2e\x0a\x41\x6c\x74\x68\x6f\x75\x67\x68\x20\x6e\x65\x76\x65\x72\x20\x69\x73\x20\x6f\x66\x74\x65\x6e\x20\x62\x65\x74\x74\x65\x72\x20\x74\x68\x61\x6e\x20\x2a\x72\x69\x67\x68\x74\x2a\x20\x6e\x6f\x77\x2e\x0a\x49\x66\x20\x74\x68\x65\x20\x69\x6d\x70\x6c\x65\x6d\x65\x6e\x74\x61\x74\x69\x6f\x6e\x20\x69\x73\x20\x68\x61\x72\x64\x20\x74\x6f\x20\x65\x78\x70\x6c\x61\x69\x6e\x2c\x20\x69\x74\x27\x73\x20\x61\x20\x62\x61\x64\x20\x69\x64\x65\x61\x2e\x0a\x49\x66\x20\x74\x68\x65\x20\x69\x6d\x70\x6c\x65\x6d\x65\x6e\x74\x61\x74\x69\x6f\x6e\x20\x69\x73\x20\x65\x61\x73\x79\x20\x74\x6f\x20\x65\x78\x70\x6c\x61\x69\x6e\x2c\x20\x69\x74\x20\x6d\x61\x79\x20\x62\x65\x20\x61\x20\x67\x6f\x6f\x64\x20\x69\x64\x65\x61\x2e\x0a\x4e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x20\x61\x72\x65\x20\x6f\x6e\x65\x20\x68\x6f\x6e\x6b\x69\x6e\x67\x20\x67\x72\x65\x61\x74\x20\x69\x64\x65\x61\x20\x2d\x2d\x20\x6c\x65\x74\x27\x73\x20\x64\x6f\x20\x6d\x6f\x72\x65\x20\x6f\x66\x20\x74\x68\x6f\x73\x65\x21\x22\x22\x22\x29"}, 6721 + {"heapq", "\x23\x20\x48\x65\x61\x70\x20\x71\x75\x65\x75\x65\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x28\x61\x2e\x6b\x2e\x61\x2e\x20\x70\x72\x69\x6f\x72\x69\x74\x79\x20\x71\x75\x65\x75\x65\x29\x0a\x64\x65\x66\x20\x68\x65\x61\x70\x70\x75\x73\x68\x28\x68\x65\x61\x70\x2c\x20\x69\x74\x65\x6d\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x50\x75\x73\x68\x20\x69\x74\x65\x6d\x20\x6f\x6e\x74\x6f\x20\x68\x65\x61\x70\x2c\x20\x6d\x61\x69\x6e\x74\x61\x69\x6e\x69\x6e\x67\x20\x74\x68\x65\x20\x68\x65\x61\x70\x20\x69\x6e\x76\x61\x72\x69\x61\x6e\x74\x2e\x22\x22\x22\x0a\x20\x20\x20\x20\x68\x65\x61\x70\x2e\x61\x70\x70\x65\x6e\x64\x28\x69\x74\x65\x6d\x29\x0a\x20\x20\x20\x20\x5f\x73\x69\x66\x74\x64\x6f\x77\x6e\x28\x68\x65\x61\x70\x2c\x20\x30\x2c\x20\x6c\x65\x6e\x28\x68\x65\x61\x70\x29\x2d\x31\x29\x0a\x0a\x64\x65\x66\x20\x68\x65\x61\x70\x70\x6f\x70\x28\x68\x65\x61\x70\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x50\x6f\x70\x20\x74\x68\x65\x20\x73\x6d\x61\x6c\x6c\x65\x73\x74\x20\x69\x74\x65\x6d\x20\x6f\x66\x66\x20\x74\x68\x65\x20\x68\x65\x61\x70\x2c\x20\x6d\x61\x69\x6e\x74\x61\x69\x6e\x69\x6e\x67\x20\x74\x68\x65\x20\x68\x65\x61\x70\x20\x69\x6e\x76\x61\x72\x69\x61\x6e\x74\x2e\x22\x22\x22\x0a\x20\x20\x20\x20\x6c\x61\x73\x74\x65\x6c\x74\x20\x3d\x20\x68\x65\x61\x70\x2e\x70\x6f\x70\x28\x29\x20\x20\x20\x20\x23\x20\x72\x61\x69\x73\x65\x73\x20\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x49\x6e\x64\x65\x78\x45\x72\x72\x6f\x72\x20\x69\x66\x20\x68\x65\x61\x70\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x0a\x20\x20\x20\x20\x69\x66\x20\x68\x65\x61\x70\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x69\x74\x65\x6d\x20\x3d\x20\x68\x65\x61\x70\x5b\x30\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x68\x65\x61\x70\x5b\x30\x5d\x20\x3d\x20\x6c\x61\x73\x74\x65\x6c\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x5f\x73\x69\x66\x74\x75\x70\x28\x68\x65\x61\x70\x2c\x20\x30\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x74\x75\x72\x6e\x69\x74\x65\x6d\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6c\x61\x73\x74\x65\x6c\x74\x0a\x0a\x64\x65\x66\x20\x68\x65\x61\x70\x72\x65\x70\x6c\x61\x63\x65\x28\x68\x65\x61\x70\x2c\x20\x69\x74\x65\x6d\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x50\x6f\x70\x20\x61\x6e\x64\x20\x72\x65\x74\x75\x72\x6e\x20\x74\x68\x65\x20\x63\x75\x72\x72\x65\x6e\x74\x20\x73\x6d\x61\x6c\x6c\x65\x73\x74\x20\x76\x61\x6c\x75\x65\x2c\x20\x61\x6e\x64\x20\x61\x64\x64\x20\x74\x68\x65\x20\x6e\x65\x77\x20\x69\x74\x65\x6d\x2e\x0a\x0a\x20\x20\x20\x20\x54\x68\x69\x73\x20\x69\x73\x20\x6d\x6f\x72\x65\x20\x65\x66\x66\x69\x63\x69\x65\x6e\x74\x20\x74\x68\x61\x6e\x20\x68\x65\x61\x70\x70\x6f\x70\x28\x29\x20\x66\x6f\x6c\x6c\x6f\x77\x65\x64\x20\x62\x79\x20\x68\x65\x61\x70\x70\x75\x73\x68\x28\x29\x2c\x20\x61\x6e\x64\x20\x63\x61\x6e\x20\x62\x65\x0a\x20\x20\x20\x20\x6d\x6f\x72\x65\x20\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x77\x68\x65\x6e\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x66\x69\x78\x65\x64\x2d\x73\x69\x7a\x65\x20\x68\x65\x61\x70\x2e\x20\x20\x4e\x6f\x74\x65\x20\x74\x68\x61\x74\x20\x74\x68\x65\x20\x76\x61\x6c\x75\x65\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x65\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x69\x74\x65\x6d\x21\x20\x20\x54\x68\x61\x74\x20\x63\x6f\x6e\x73\x74\x72\x61\x69\x6e\x73\x20\x72\x65\x61\x73\x6f\x6e\x61\x62\x6c\x65\x20\x75\x73\x65\x73\x20\x6f\x66\x0a\x20\x20\x20\x20\x74\x68\x69\x73\x20\x72\x6f\x75\x74\x69\x6e\x65\x20\x75\x6e\x6c\x65\x73\x73\x20\x77\x72\x69\x74\x74\x65\x6e\x20\x61\x73\x20\x70\x61\x72\x74\x20\x6f\x66\x20\x61\x20\x63\x6f\x6e\x64\x69\x74\x69\x6f\x6e\x61\x6c\x20\x72\x65\x70\x6c\x61\x63\x65\x6d\x65\x6e\x74\x3a\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x69\x74\x65\x6d\x20\x3e\x20\x68\x65\x61\x70\x5b\x30\x5d\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x74\x65\x6d\x20\x3d\x20\x68\x65\x61\x70\x72\x65\x70\x6c\x61\x63\x65\x28\x68\x65\x61\x70\x2c\x20\x69\x74\x65\x6d\x29\x0a\x20\x20\x20\x20\x22\x22\x22\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x69\x74\x65\x6d\x20\x3d\x20\x68\x65\x61\x70\x5b\x30\x5d\x20\x20\x20\x20\x23\x20\x72\x61\x69\x73\x65\x73\x20\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x49\x6e\x64\x65\x78\x45\x72\x72\x6f\x72\x20\x69\x66\x20\x68\x65\x61\x70\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x0a\x20\x20\x20\x20\x68\x65\x61\x70\x5b\x30\x5d\x20\x3d\x20\x69\x74\x65\x6d\x0a\x20\x20\x20\x20\x5f\x73\x69\x66\x74\x75\x70\x28\x68\x65\x61\x70\x2c\x20\x30\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x74\x75\x72\x6e\x69\x74\x65\x6d\x0a\x0a\x64\x65\x66\x20\x68\x65\x61\x70\x70\x75\x73\x68\x70\x6f\x70\x28\x68\x65\x61\x70\x2c\x20\x69\x74\x65\x6d\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x46\x61\x73\x74\x20\x76\x65\x72\x73\x69\x6f\x6e\x20\x6f\x66\x20\x61\x20\x68\x65\x61\x70\x70\x75\x73\x68\x20\x66\x6f\x6c\x6c\x6f\x77\x65\x64\x20\x62\x79\x20\x61\x20\x68\x65\x61\x70\x70\x6f\x70\x2e\x22\x22\x22\x0a\x20\x20\x20\x20\x69\x66\x20\x68\x65\x61\x70\x20\x61\x6e\x64\x20\x68\x65\x61\x70\x5b\x30\x5d\x20\x3c\x20\x69\x74\x65\x6d\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x74\x65\x6d\x2c\x20\x68\x65\x61\x70\x5b\x30\x5d\x20\x3d\x20\x68\x65\x61\x70\x5b\x30\x5d\x2c\x20\x69\x74\x65\x6d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x5f\x73\x69\x66\x74\x75\x70\x28\x68\x65\x61\x70\x2c\x20\x30\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x69\x74\x65\x6d\x0a\x0a\x64\x65\x66\x20\x68\x65\x61\x70\x69\x66\x79\x28\x78\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x20\x6c\x69\x73\x74\x20\x69\x6e\x74\x6f\x20\x61\x20\x68\x65\x61\x70\x2c\x20\x69\x6e\x2d\x70\x6c\x61\x63\x65\x2c\x20\x69\x6e\x20\x4f\x28\x6c\x65\x6e\x28\x78\x29\x29\x20\x74\x69\x6d\x65\x2e\x22\x22\x22\x0a\x20\x20\x20\x20\x6e\x20\x3d\x20\x6c\x65\x6e\x28\x78\x29\x0a\x20\x20\x20\x20\x23\x20\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x20\x62\x6f\x74\x74\x6f\x6d\x2d\x75\x70\x2e\x20\x20\x54\x68\x65\x20\x6c\x61\x72\x67\x65\x73\x74\x20\x69\x6e\x64\x65\x78\x20\x74\x68\x65\x72\x65\x27\x73\x20\x61\x6e\x79\x20\x70\x6f\x69\x6e\x74\x20\x74\x6f\x20\x6c\x6f\x6f\x6b\x69\x6e\x67\x20\x61\x74\x0a\x20\x20\x20\x20\x23\x20\x69\x73\x20\x74\x68\x65\x20\x6c\x61\x72\x67\x65\x73\x74\x20\x77\x69\x74\x68\x20\x61\x20\x63\x68\x69\x6c\x64\x20\x69\x6e\x64\x65\x78\x20\x69\x6e\x2d\x72\x61\x6e\x67\x65\x2c\x20\x73\x6f\x20\x6d\x75\x73\x74\x20\x68\x61\x76\x65\x20\x32\x2a\x69\x20\x2b\x20\x31\x20\x3c\x20\x6e\x2c\x0a\x20\x20\x20\x20\x23\x20\x6f\x72\x20\x69\x20\x3c\x20\x28\x6e\x2d\x31\x29\x2f\x32\x2e\x20\x20\x49\x66\x20\x6e\x20\x69\x73\x20\x65\x76\x65\x6e\x20\x3d\x20\x32\x2a\x6a\x2c\x20\x74\x68\x69\x73\x20\x69\x73\x20\x28\x32\x2a\x6a\x2d\x31\x29\x2f\x32\x20\x3d\x20\x6a\x2d\x31\x2f\x32\x20\x73\x6f\x0a\x20\x20\x20\x20\x23\x20\x6a\x2d\x31\x20\x69\x73\x20\x74\x68\x65\x20\x6c\x61\x72\x67\x65\x73\x74\x2c\x20\x77\x68\x69\x63\x68\x20\x69\x73\x20\x6e\x2f\x2f\x32\x20\x2d\x20\x31\x2e\x20\x20\x49\x66\x20\x6e\x20\x69\x73\x20\x6f\x64\x64\x20\x3d\x20\x32\x2a\x6a\x2b\x31\x2c\x20\x74\x68\x69\x73\x20\x69\x73\x0a\x20\x20\x20\x20\x23\x20\x28\x32\x2a\x6a\x2b\x31\x2d\x31\x29\x2f\x32\x20\x3d\x20\x6a\x20\x73\x6f\x20\x6a\x2d\x31\x20\x69\x73\x20\x74\x68\x65\x20\x6c\x61\x72\x67\x65\x73\x74\x2c\x20\x61\x6e\x64\x20\x74\x68\x61\x74\x27\x73\x20\x61\x67\x61\x69\x6e\x20\x6e\x2f\x2f\x32\x2d\x31\x2e\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x72\x65\x76\x65\x72\x73\x65\x64\x28\x72\x61\x6e\x67\x65\x28\x6e\x2f\x2f\x32\x29\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x5f\x73\x69\x66\x74\x75\x70\x28\x78\x2c\x20\x69\x29\x0a\x0a\x23\x20\x27\x68\x65\x61\x70\x27\x20\x69\x73\x20\x61\x20\x68\x65\x61\x70\x20\x61\x74\x20\x61\x6c\x6c\x20\x69\x6e\x64\x69\x63\x65\x73\x20\x3e\x3d\x20\x73\x74\x61\x72\x74\x70\x6f\x73\x2c\x20\x65\x78\x63\x65\x70\x74\x20\x70\x6f\x73\x73\x69\x62\x6c\x79\x20\x66\x6f\x72\x20\x70\x6f\x73\x2e\x20\x20\x70\x6f\x73\x0a\x23\x20\x69\x73\x20\x74\x68\x65\x20\x69\x6e\x64\x65\x78\x20\x6f\x66\x20\x61\x20\x6c\x65\x61\x66\x20\x77\x69\x74\x68\x20\x61\x20\x70\x6f\x73\x73\x69\x62\x6c\x79\x20\x6f\x75\x74\x2d\x6f\x66\x2d\x6f\x72\x64\x65\x72\x20\x76\x61\x6c\x75\x65\x2e\x20\x20\x52\x65\x73\x74\x6f\x72\x65\x20\x74\x68\x65\x0a\x23\x20\x68\x65\x61\x70\x20\x69\x6e\x76\x61\x72\x69\x61\x6e\x74\x2e\x0a\x64\x65\x66\x20\x5f\x73\x69\x66\x74\x64\x6f\x77\x6e\x28\x68\x65\x61\x70\x2c\x20\x73\x74\x61\x72\x74\x70\x6f\x73\x2c\x20\x70\x6f\x73\x29\x3a\x0a\x20\x20\x20\x20\x6e\x65\x77\x69\x74\x65\x6d\x20\x3d\x20\x68\x65\x61\x70\x5b\x70\x6f\x73\x5d\x0a\x20\x20\x20\x20\x23\x20\x46\x6f\x6c\x6c\x6f\x77\x20\x74\x68\x65\x20\x70\x61\x74\x68\x20\x74\x6f\x20\x74\x68\x65\x20\x72\x6f\x6f\x74\x2c\x20\x6d\x6f\x76\x69\x6e\x67\x20\x70\x61\x72\x65\x6e\x74\x73\x20\x64\x6f\x77\x6e\x20\x75\x6e\x74\x69\x6c\x20\x66\x69\x6e\x64\x69\x6e\x67\x20\x61\x20\x70\x6c\x61\x63\x65\x0a\x20\x20\x20\x20\x23\x20\x6e\x65\x77\x69\x74\x65\x6d\x20\x66\x69\x74\x73\x2e\x0a\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x70\x6f\x73\x20\x3e\x20\x73\x74\x61\x72\x74\x70\x6f\x73\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x70\x61\x72\x65\x6e\x74\x70\x6f\x73\x20\x3d\x20\x28\x70\x6f\x73\x20\x2d\x20\x31\x29\x20\x3e\x3e\x20\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x70\x61\x72\x65\x6e\x74\x20\x3d\x20\x68\x65\x61\x70\x5b\x70\x61\x72\x65\x6e\x74\x70\x6f\x73\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6e\x65\x77\x69\x74\x65\x6d\x20\x3c\x20\x70\x61\x72\x65\x6e\x74\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x68\x65\x61\x70\x5b\x70\x6f\x73\x5d\x20\x3d\x20\x70\x61\x72\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x70\x6f\x73\x20\x3d\x20\x70\x61\x72\x65\x6e\x74\x70\x6f\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x63\x6f\x6e\x74\x69\x6e\x75\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x62\x72\x65\x61\x6b\x0a\x20\x20\x20\x20\x68\x65\x61\x70\x5b\x70\x6f\x73\x5d\x20\x3d\x20\x6e\x65\x77\x69\x74\x65\x6d\x0a\x0a\x64\x65\x66\x20\x5f\x73\x69\x66\x74\x75\x70\x28\x68\x65\x61\x70\x2c\x20\x70\x6f\x73\x29\x3a\x0a\x20\x20\x20\x20\x65\x6e\x64\x70\x6f\x73\x20\x3d\x20\x6c\x65\x6e\x28\x68\x65\x61\x70\x29\x0a\x20\x20\x20\x20\x73\x74\x61\x72\x74\x70\x6f\x73\x20\x3d\x20\x70\x6f\x73\x0a\x20\x20\x20\x20\x6e\x65\x77\x69\x74\x65\x6d\x20\x3d\x20\x68\x65\x61\x70\x5b\x70\x6f\x73\x5d\x0a\x20\x20\x20\x20\x23\x20\x42\x75\x62\x62\x6c\x65\x20\x75\x70\x20\x74\x68\x65\x20\x73\x6d\x61\x6c\x6c\x65\x72\x20\x63\x68\x69\x6c\x64\x20\x75\x6e\x74\x69\x6c\x20\x68\x69\x74\x74\x69\x6e\x67\x20\x61\x20\x6c\x65\x61\x66\x2e\x0a\x20\x20\x20\x20\x63\x68\x69\x6c\x64\x70\x6f\x73\x20\x3d\x20\x32\x2a\x70\x6f\x73\x20\x2b\x20\x31\x20\x20\x20\x20\x23\x20\x6c\x65\x66\x74\x6d\x6f\x73\x74\x20\x63\x68\x69\x6c\x64\x20\x70\x6f\x73\x69\x74\x69\x6f\x6e\x0a\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x63\x68\x69\x6c\x64\x70\x6f\x73\x20\x3c\x20\x65\x6e\x64\x70\x6f\x73\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x23\x20\x53\x65\x74\x20\x63\x68\x69\x6c\x64\x70\x6f\x73\x20\x74\x6f\x20\x69\x6e\x64\x65\x78\x20\x6f\x66\x20\x73\x6d\x61\x6c\x6c\x65\x72\x20\x63\x68\x69\x6c\x64\x2e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x69\x67\x68\x74\x70\x6f\x73\x20\x3d\x20\x63\x68\x69\x6c\x64\x70\x6f\x73\x20\x2b\x20\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x72\x69\x67\x68\x74\x70\x6f\x73\x20\x3c\x20\x65\x6e\x64\x70\x6f\x73\x20\x61\x6e\x64\x20\x6e\x6f\x74\x20\x68\x65\x61\x70\x5b\x63\x68\x69\x6c\x64\x70\x6f\x73\x5d\x20\x3c\x20\x68\x65\x61\x70\x5b\x72\x69\x67\x68\x74\x70\x6f\x73\x5d\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x63\x68\x69\x6c\x64\x70\x6f\x73\x20\x3d\x20\x72\x69\x67\x68\x74\x70\x6f\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x23\x20\x4d\x6f\x76\x65\x20\x74\x68\x65\x20\x73\x6d\x61\x6c\x6c\x65\x72\x20\x63\x68\x69\x6c\x64\x20\x75\x70\x2e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x68\x65\x61\x70\x5b\x70\x6f\x73\x5d\x20\x3d\x20\x68\x65\x61\x70\x5b\x63\x68\x69\x6c\x64\x70\x6f\x73\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x70\x6f\x73\x20\x3d\x20\x63\x68\x69\x6c\x64\x70\x6f\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x63\x68\x69\x6c\x64\x70\x6f\x73\x20\x3d\x20\x32\x2a\x70\x6f\x73\x20\x2b\x20\x31\x0a\x20\x20\x20\x20\x23\x20\x54\x68\x65\x20\x6c\x65\x61\x66\x20\x61\x74\x20\x70\x6f\x73\x20\x69\x73\x20\x65\x6d\x70\x74\x79\x20\x6e\x6f\x77\x2e\x20\x20\x50\x75\x74\x20\x6e\x65\x77\x69\x74\x65\x6d\x20\x74\x68\x65\x72\x65\x2c\x20\x61\x6e\x64\x20\x62\x75\x62\x62\x6c\x65\x20\x69\x74\x20\x75\x70\x0a\x20\x20\x20\x20\x23\x20\x74\x6f\x20\x69\x74\x73\x20\x66\x69\x6e\x61\x6c\x20\x72\x65\x73\x74\x69\x6e\x67\x20\x70\x6c\x61\x63\x65\x20\x28\x62\x79\x20\x73\x69\x66\x74\x69\x6e\x67\x20\x69\x74\x73\x20\x70\x61\x72\x65\x6e\x74\x73\x20\x64\x6f\x77\x6e\x29\x2e\x0a\x20\x20\x20\x20\x68\x65\x61\x70\x5b\x70\x6f\x73\x5d\x20\x3d\x20\x6e\x65\x77\x69\x74\x65\x6d\x0a\x20\x20\x20\x20\x5f\x73\x69\x66\x74\x64\x6f\x77\x6e\x28\x68\x65\x61\x70\x2c\x20\x73\x74\x61\x72\x74\x70\x6f\x73\x2c\x20\x70\x6f\x73\x29"}, 6722 + {"bisect", "\x22\x22\x22\x42\x69\x73\x65\x63\x74\x69\x6f\x6e\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x73\x2e\x22\x22\x22\x0a\x0a\x64\x65\x66\x20\x69\x6e\x73\x6f\x72\x74\x5f\x72\x69\x67\x68\x74\x28\x61\x2c\x20\x78\x2c\x20\x6c\x6f\x3d\x30\x2c\x20\x68\x69\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x49\x6e\x73\x65\x72\x74\x20\x69\x74\x65\x6d\x20\x78\x20\x69\x6e\x20\x6c\x69\x73\x74\x20\x61\x2c\x20\x61\x6e\x64\x20\x6b\x65\x65\x70\x20\x69\x74\x20\x73\x6f\x72\x74\x65\x64\x20\x61\x73\x73\x75\x6d\x69\x6e\x67\x20\x61\x20\x69\x73\x20\x73\x6f\x72\x74\x65\x64\x2e\x0a\x0a\x20\x20\x20\x20\x49\x66\x20\x78\x20\x69\x73\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x69\x6e\x20\x61\x2c\x20\x69\x6e\x73\x65\x72\x74\x20\x69\x74\x20\x74\x6f\x20\x74\x68\x65\x20\x72\x69\x67\x68\x74\x20\x6f\x66\x20\x74\x68\x65\x20\x72\x69\x67\x68\x74\x6d\x6f\x73\x74\x20\x78\x2e\x0a\x0a\x20\x20\x20\x20\x4f\x70\x74\x69\x6f\x6e\x61\x6c\x20\x61\x72\x67\x73\x20\x6c\x6f\x20\x28\x64\x65\x66\x61\x75\x6c\x74\x20\x30\x29\x20\x61\x6e\x64\x20\x68\x69\x20\x28\x64\x65\x66\x61\x75\x6c\x74\x20\x6c\x65\x6e\x28\x61\x29\x29\x20\x62\x6f\x75\x6e\x64\x20\x74\x68\x65\x0a\x20\x20\x20\x20\x73\x6c\x69\x63\x65\x20\x6f\x66\x20\x61\x20\x74\x6f\x20\x62\x65\x20\x73\x65\x61\x72\x63\x68\x65\x64\x2e\x0a\x20\x20\x20\x20\x22\x22\x22\x0a\x0a\x20\x20\x20\x20\x6c\x6f\x20\x3d\x20\x62\x69\x73\x65\x63\x74\x5f\x72\x69\x67\x68\x74\x28\x61\x2c\x20\x78\x2c\x20\x6c\x6f\x2c\x20\x68\x69\x29\x0a\x20\x20\x20\x20\x61\x2e\x69\x6e\x73\x65\x72\x74\x28\x6c\x6f\x2c\x20\x78\x29\x0a\x0a\x64\x65\x66\x20\x62\x69\x73\x65\x63\x74\x5f\x72\x69\x67\x68\x74\x28\x61\x2c\x20\x78\x2c\x20\x6c\x6f\x3d\x30\x2c\x20\x68\x69\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x52\x65\x74\x75\x72\x6e\x20\x74\x68\x65\x20\x69\x6e\x64\x65\x78\x20\x77\x68\x65\x72\x65\x20\x74\x6f\x20\x69\x6e\x73\x65\x72\x74\x20\x69\x74\x65\x6d\x20\x78\x20\x69\x6e\x20\x6c\x69\x73\x74\x20\x61\x2c\x20\x61\x73\x73\x75\x6d\x69\x6e\x67\x20\x61\x20\x69\x73\x20\x73\x6f\x72\x74\x65\x64\x2e\x0a\x0a\x20\x20\x20\x20\x54\x68\x65\x20\x72\x65\x74\x75\x72\x6e\x20\x76\x61\x6c\x75\x65\x20\x69\x20\x69\x73\x20\x73\x75\x63\x68\x20\x74\x68\x61\x74\x20\x61\x6c\x6c\x20\x65\x20\x69\x6e\x20\x61\x5b\x3a\x69\x5d\x20\x68\x61\x76\x65\x20\x65\x20\x3c\x3d\x20\x78\x2c\x20\x61\x6e\x64\x20\x61\x6c\x6c\x20\x65\x20\x69\x6e\x0a\x20\x20\x20\x20\x61\x5b\x69\x3a\x5d\x20\x68\x61\x76\x65\x20\x65\x20\x3e\x20\x78\x2e\x20\x20\x53\x6f\x20\x69\x66\x20\x78\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x61\x70\x70\x65\x61\x72\x73\x20\x69\x6e\x20\x74\x68\x65\x20\x6c\x69\x73\x74\x2c\x20\x61\x2e\x69\x6e\x73\x65\x72\x74\x28\x78\x29\x20\x77\x69\x6c\x6c\x0a\x20\x20\x20\x20\x69\x6e\x73\x65\x72\x74\x20\x6a\x75\x73\x74\x20\x61\x66\x74\x65\x72\x20\x74\x68\x65\x20\x72\x69\x67\x68\x74\x6d\x6f\x73\x74\x20\x78\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x74\x68\x65\x72\x65\x2e\x0a\x0a\x20\x20\x20\x20\x4f\x70\x74\x69\x6f\x6e\x61\x6c\x20\x61\x72\x67\x73\x20\x6c\x6f\x20\x28\x64\x65\x66\x61\x75\x6c\x74\x20\x30\x29\x20\x61\x6e\x64\x20\x68\x69\x20\x28\x64\x65\x66\x61\x75\x6c\x74\x20\x6c\x65\x6e\x28\x61\x29\x29\x20\x62\x6f\x75\x6e\x64\x20\x74\x68\x65\x0a\x20\x20\x20\x20\x73\x6c\x69\x63\x65\x20\x6f\x66\x20\x61\x20\x74\x6f\x20\x62\x65\x20\x73\x65\x61\x72\x63\x68\x65\x64\x2e\x0a\x20\x20\x20\x20\x22\x22\x22\x0a\x0a\x20\x20\x20\x20\x69\x66\x20\x6c\x6f\x20\x3c\x20\x30\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x56\x61\x6c\x75\x65\x45\x72\x72\x6f\x72\x28\x27\x6c\x6f\x20\x6d\x75\x73\x74\x20\x62\x65\x20\x6e\x6f\x6e\x2d\x6e\x65\x67\x61\x74\x69\x76\x65\x27\x29\x0a\x20\x20\x20\x20\x69\x66\x20\x68\x69\x20\x69\x73\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x68\x69\x20\x3d\x20\x6c\x65\x6e\x28\x61\x29\x0a\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x6c\x6f\x20\x3c\x20\x68\x69\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6d\x69\x64\x20\x3d\x20\x28\x6c\x6f\x2b\x68\x69\x29\x2f\x2f\x32\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x78\x20\x3c\x20\x61\x5b\x6d\x69\x64\x5d\x3a\x20\x68\x69\x20\x3d\x20\x6d\x69\x64\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x65\x6c\x73\x65\x3a\x20\x6c\x6f\x20\x3d\x20\x6d\x69\x64\x2b\x31\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6c\x6f\x0a\x0a\x64\x65\x66\x20\x69\x6e\x73\x6f\x72\x74\x5f\x6c\x65\x66\x74\x28\x61\x2c\x20\x78\x2c\x20\x6c\x6f\x3d\x30\x2c\x20\x68\x69\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x49\x6e\x73\x65\x72\x74\x20\x69\x74\x65\x6d\x20\x78\x20\x69\x6e\x20\x6c\x69\x73\x74\x20\x61\x2c\x20\x61\x6e\x64\x20\x6b\x65\x65\x70\x20\x69\x74\x20\x73\x6f\x72\x74\x65\x64\x20\x61\x73\x73\x75\x6d\x69\x6e\x67\x20\x61\x20\x69\x73\x20\x73\x6f\x72\x74\x65\x64\x2e\x0a\x0a\x20\x20\x20\x20\x49\x66\x20\x78\x20\x69\x73\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x69\x6e\x20\x61\x2c\x20\x69\x6e\x73\x65\x72\x74\x20\x69\x74\x20\x74\x6f\x20\x74\x68\x65\x20\x6c\x65\x66\x74\x20\x6f\x66\x20\x74\x68\x65\x20\x6c\x65\x66\x74\x6d\x6f\x73\x74\x20\x78\x2e\x0a\x0a\x20\x20\x20\x20\x4f\x70\x74\x69\x6f\x6e\x61\x6c\x20\x61\x72\x67\x73\x20\x6c\x6f\x20\x28\x64\x65\x66\x61\x75\x6c\x74\x20\x30\x29\x20\x61\x6e\x64\x20\x68\x69\x20\x28\x64\x65\x66\x61\x75\x6c\x74\x20\x6c\x65\x6e\x28\x61\x29\x29\x20\x62\x6f\x75\x6e\x64\x20\x74\x68\x65\x0a\x20\x20\x20\x20\x73\x6c\x69\x63\x65\x20\x6f\x66\x20\x61\x20\x74\x6f\x20\x62\x65\x20\x73\x65\x61\x72\x63\x68\x65\x64\x2e\x0a\x20\x20\x20\x20\x22\x22\x22\x0a\x0a\x20\x20\x20\x20\x6c\x6f\x20\x3d\x20\x62\x69\x73\x65\x63\x74\x5f\x6c\x65\x66\x74\x28\x61\x2c\x20\x78\x2c\x20\x6c\x6f\x2c\x20\x68\x69\x29\x0a\x20\x20\x20\x20\x61\x2e\x69\x6e\x73\x65\x72\x74\x28\x6c\x6f\x2c\x20\x78\x29\x0a\x0a\x0a\x64\x65\x66\x20\x62\x69\x73\x65\x63\x74\x5f\x6c\x65\x66\x74\x28\x61\x2c\x20\x78\x2c\x20\x6c\x6f\x3d\x30\x2c\x20\x68\x69\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x22\x22\x22\x52\x65\x74\x75\x72\x6e\x20\x74\x68\x65\x20\x69\x6e\x64\x65\x78\x20\x77\x68\x65\x72\x65\x20\x74\x6f\x20\x69\x6e\x73\x65\x72\x74\x20\x69\x74\x65\x6d\x20\x78\x20\x69\x6e\x20\x6c\x69\x73\x74\x20\x61\x2c\x20\x61\x73\x73\x75\x6d\x69\x6e\x67\x20\x61\x20\x69\x73\x20\x73\x6f\x72\x74\x65\x64\x2e\x0a\x0a\x20\x20\x20\x20\x54\x68\x65\x20\x72\x65\x74\x75\x72\x6e\x20\x76\x61\x6c\x75\x65\x20\x69\x20\x69\x73\x20\x73\x75\x63\x68\x20\x74\x68\x61\x74\x20\x61\x6c\x6c\x20\x65\x20\x69\x6e\x20\x61\x5b\x3a\x69\x5d\x20\x68\x61\x76\x65\x20\x65\x20\x3c\x20\x78\x2c\x20\x61\x6e\x64\x20\x61\x6c\x6c\x20\x65\x20\x69\x6e\x0a\x20\x20\x20\x20\x61\x5b\x69\x3a\x5d\x20\x68\x61\x76\x65\x20\x65\x20\x3e\x3d\x20\x78\x2e\x20\x20\x53\x6f\x20\x69\x66\x20\x78\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x61\x70\x70\x65\x61\x72\x73\x20\x69\x6e\x20\x74\x68\x65\x20\x6c\x69\x73\x74\x2c\x20\x61\x2e\x69\x6e\x73\x65\x72\x74\x28\x78\x29\x20\x77\x69\x6c\x6c\x0a\x20\x20\x20\x20\x69\x6e\x73\x65\x72\x74\x20\x6a\x75\x73\x74\x20\x62\x65\x66\x6f\x72\x65\x20\x74\x68\x65\x20\x6c\x65\x66\x74\x6d\x6f\x73\x74\x20\x78\x20\x61\x6c\x72\x65\x61\x64\x79\x20\x74\x68\x65\x72\x65\x2e\x0a\x0a\x20\x20\x20\x20\x4f\x70\x74\x69\x6f\x6e\x61\x6c\x20\x61\x72\x67\x73\x20\x6c\x6f\x20\x28\x64\x65\x66\x61\x75\x6c\x74\x20\x30\x29\x20\x61\x6e\x64\x20\x68\x69\x20\x28\x64\x65\x66\x61\x75\x6c\x74\x20\x6c\x65\x6e\x28\x61\x29\x29\x20\x62\x6f\x75\x6e\x64\x20\x74\x68\x65\x0a\x20\x20\x20\x20\x73\x6c\x69\x63\x65\x20\x6f\x66\x20\x61\x20\x74\x6f\x20\x62\x65\x20\x73\x65\x61\x72\x63\x68\x65\x64\x2e\x0a\x20\x20\x20\x20\x22\x22\x22\x0a\x0a\x20\x20\x20\x20\x69\x66\x20\x6c\x6f\x20\x3c\x20\x30\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x56\x61\x6c\x75\x65\x45\x72\x72\x6f\x72\x28\x27\x6c\x6f\x20\x6d\x75\x73\x74\x20\x62\x65\x20\x6e\x6f\x6e\x2d\x6e\x65\x67\x61\x74\x69\x76\x65\x27\x29\x0a\x20\x20\x20\x20\x69\x66\x20\x68\x69\x20\x69\x73\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x68\x69\x20\x3d\x20\x6c\x65\x6e\x28\x61\x29\x0a\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x6c\x6f\x20\x3c\x20\x68\x69\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6d\x69\x64\x20\x3d\x20\x28\x6c\x6f\x2b\x68\x69\x29\x2f\x2f\x32\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x61\x5b\x6d\x69\x64\x5d\x20\x3c\x20\x78\x3a\x20\x6c\x6f\x20\x3d\x20\x6d\x69\x64\x2b\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x65\x6c\x73\x65\x3a\x20\x68\x69\x20\x3d\x20\x6d\x69\x64\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6c\x6f\x0a\x0a\x23\x20\x43\x72\x65\x61\x74\x65\x20\x61\x6c\x69\x61\x73\x65\x73\x0a\x62\x69\x73\x65\x63\x74\x20\x3d\x20\x62\x69\x73\x65\x63\x74\x5f\x72\x69\x67\x68\x74\x0a\x69\x6e\x73\x6f\x72\x74\x20\x3d\x20\x69\x6e\x73\x6f\x72\x74\x5f\x72\x69\x67\x68\x74\x0a"}, 6723 + {"random", "\x5f\x69\x6e\x73\x74\x20\x3d\x20\x52\x61\x6e\x64\x6f\x6d\x28\x29\x0a\x0a\x73\x65\x65\x64\x20\x3d\x20\x5f\x69\x6e\x73\x74\x2e\x73\x65\x65\x64\x0a\x72\x61\x6e\x64\x6f\x6d\x20\x3d\x20\x5f\x69\x6e\x73\x74\x2e\x72\x61\x6e\x64\x6f\x6d\x0a\x75\x6e\x69\x66\x6f\x72\x6d\x20\x3d\x20\x5f\x69\x6e\x73\x74\x2e\x75\x6e\x69\x66\x6f\x72\x6d\x0a\x72\x61\x6e\x64\x69\x6e\x74\x20\x3d\x20\x5f\x69\x6e\x73\x74\x2e\x72\x61\x6e\x64\x69\x6e\x74\x0a\x0a\x64\x65\x66\x20\x73\x68\x75\x66\x66\x6c\x65\x28\x4c\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x72\x61\x6e\x67\x65\x28\x6c\x65\x6e\x28\x4c\x29\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6a\x20\x3d\x20\x72\x61\x6e\x64\x69\x6e\x74\x28\x69\x2c\x20\x6c\x65\x6e\x28\x4c\x29\x20\x2d\x20\x31\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x4c\x5b\x69\x5d\x2c\x20\x4c\x5b\x6a\x5d\x20\x3d\x20\x4c\x5b\x6a\x5d\x2c\x20\x4c\x5b\x69\x5d\x0a\x0a\x64\x65\x66\x20\x63\x68\x6f\x69\x63\x65\x28\x4c\x29\x3a\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x4c\x5b\x72\x61\x6e\x64\x69\x6e\x74\x28\x30\x2c\x20\x6c\x65\x6e\x28\x4c\x29\x20\x2d\x20\x31\x29\x5d"}, 6724 + {"functools", "\x64\x65\x66\x20\x63\x61\x63\x68\x65\x28\x66\x29\x3a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x77\x72\x61\x70\x70\x65\x72\x28\x2a\x61\x72\x67\x73\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6e\x6f\x74\x20\x68\x61\x73\x61\x74\x74\x72\x28\x66\x2c\x20\x27\x63\x61\x63\x68\x65\x27\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x66\x2e\x63\x61\x63\x68\x65\x20\x3d\x20\x7b\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6b\x65\x79\x20\x3d\x20\x61\x72\x67\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6b\x65\x79\x20\x6e\x6f\x74\x20\x69\x6e\x20\x66\x2e\x63\x61\x63\x68\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x66\x2e\x63\x61\x63\x68\x65\x5b\x6b\x65\x79\x5d\x20\x3d\x20\x66\x28\x2a\x61\x72\x67\x73\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x66\x2e\x63\x61\x63\x68\x65\x5b\x6b\x65\x79\x5d\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x77\x72\x61\x70\x70\x65\x72"}, 6725 + {"_dict", "\x63\x6c\x61\x73\x73\x20\x64\x69\x63\x74\x3a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x6e\x69\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6d\x61\x70\x70\x69\x6e\x67\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x63\x61\x70\x61\x63\x69\x74\x79\x20\x3d\x20\x31\x36\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x20\x3d\x20\x5b\x4e\x6f\x6e\x65\x5d\x20\x2a\x20\x73\x65\x6c\x66\x2e\x5f\x63\x61\x70\x61\x63\x69\x74\x79\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x6c\x65\x6e\x20\x3d\x20\x30\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6d\x61\x70\x70\x69\x6e\x67\x20\x69\x73\x20\x6e\x6f\x74\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x2c\x76\x20\x69\x6e\x20\x6d\x61\x70\x70\x69\x6e\x67\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x5b\x6b\x5d\x20\x3d\x20\x76\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x6c\x65\x6e\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x6c\x65\x6e\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x70\x72\x6f\x62\x65\x28\x73\x65\x6c\x66\x2c\x20\x6b\x65\x79\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x20\x3d\x20\x68\x61\x73\x68\x28\x6b\x65\x79\x29\x20\x25\x20\x73\x65\x6c\x66\x2e\x5f\x63\x61\x70\x61\x63\x69\x74\x79\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x69\x5d\x20\x69\x73\x20\x6e\x6f\x74\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x69\x5d\x5b\x30\x5d\x20\x3d\x3d\x20\x6b\x65\x79\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x54\x72\x75\x65\x2c\x20\x69\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x20\x3d\x20\x28\x69\x20\x2b\x20\x31\x29\x20\x25\x20\x73\x65\x6c\x66\x2e\x5f\x63\x61\x70\x61\x63\x69\x74\x79\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x2c\x20\x69\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6b\x65\x79\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x6b\x2c\x20\x69\x20\x3d\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x70\x72\x6f\x62\x65\x28\x6b\x65\x79\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6e\x6f\x74\x20\x6f\x6b\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x4b\x65\x79\x45\x72\x72\x6f\x72\x28\x72\x65\x70\x72\x28\x6b\x65\x79\x29\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x69\x5d\x5b\x31\x5d\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x63\x6f\x6e\x74\x61\x69\x6e\x73\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6b\x65\x79\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x6b\x2c\x20\x69\x20\x3d\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x70\x72\x6f\x62\x65\x28\x6b\x65\x79\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6f\x6b\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x73\x65\x74\x69\x74\x65\x6d\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6b\x65\x79\x2c\x20\x76\x61\x6c\x75\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x6b\x2c\x20\x69\x20\x3d\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x70\x72\x6f\x62\x65\x28\x6b\x65\x79\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6f\x6b\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x69\x5d\x5b\x31\x5d\x20\x3d\x20\x76\x61\x6c\x75\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x65\x6c\x73\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x69\x5d\x20\x3d\x20\x5b\x6b\x65\x79\x2c\x20\x76\x61\x6c\x75\x65\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x6c\x65\x6e\x20\x2b\x3d\x20\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x73\x65\x6c\x66\x2e\x5f\x6c\x65\x6e\x20\x3e\x20\x73\x65\x6c\x66\x2e\x5f\x63\x61\x70\x61\x63\x69\x74\x79\x20\x2a\x20\x30\x2e\x36\x37\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x63\x61\x70\x61\x63\x69\x74\x79\x20\x2a\x3d\x20\x32\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x72\x65\x68\x61\x73\x68\x28\x29\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x64\x65\x6c\x69\x74\x65\x6d\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6b\x65\x79\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x6b\x2c\x20\x69\x20\x3d\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x70\x72\x6f\x62\x65\x28\x6b\x65\x79\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6e\x6f\x74\x20\x6f\x6b\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x4b\x65\x79\x45\x72\x72\x6f\x72\x28\x72\x65\x70\x72\x28\x6b\x65\x79\x29\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x69\x5d\x20\x3d\x20\x4e\x6f\x6e\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x6c\x65\x6e\x20\x2d\x3d\x20\x31\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x72\x65\x68\x61\x73\x68\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x6c\x64\x5f\x61\x20\x3d\x20\x73\x65\x6c\x66\x2e\x5f\x61\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x20\x3d\x20\x5b\x4e\x6f\x6e\x65\x5d\x20\x2a\x20\x73\x65\x6c\x66\x2e\x5f\x63\x61\x70\x61\x63\x69\x74\x79\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x6c\x65\x6e\x20\x3d\x20\x30\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x76\x20\x69\x6e\x20\x6f\x6c\x64\x5f\x61\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6b\x76\x20\x69\x73\x20\x6e\x6f\x74\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x5b\x6b\x76\x5b\x30\x5d\x5d\x20\x3d\x20\x6b\x76\x5b\x31\x5d\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x67\x65\x74\x28\x73\x65\x6c\x66\x2c\x20\x6b\x65\x79\x2c\x20\x64\x65\x66\x61\x75\x6c\x74\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x6b\x2c\x20\x69\x20\x3d\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x70\x72\x6f\x62\x65\x28\x6b\x65\x79\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6f\x6b\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x69\x5d\x5b\x31\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x64\x65\x66\x61\x75\x6c\x74\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x6b\x65\x79\x73\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x76\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6b\x76\x20\x69\x73\x20\x6e\x6f\x74\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x69\x65\x6c\x64\x20\x6b\x76\x5b\x30\x5d\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x76\x61\x6c\x75\x65\x73\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x76\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6b\x76\x20\x69\x73\x20\x6e\x6f\x74\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x69\x65\x6c\x64\x20\x6b\x76\x5b\x31\x5d\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x69\x74\x65\x6d\x73\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x76\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6b\x76\x20\x69\x73\x20\x6e\x6f\x74\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x69\x65\x6c\x64\x20\x6b\x76\x5b\x30\x5d\x2c\x20\x6b\x76\x5b\x31\x5d\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x63\x6c\x65\x61\x72\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x20\x3d\x20\x5b\x4e\x6f\x6e\x65\x5d\x20\x2a\x20\x73\x65\x6c\x66\x2e\x5f\x63\x61\x70\x61\x63\x69\x74\x79\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x6c\x65\x6e\x20\x3d\x20\x30\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x75\x70\x64\x61\x74\x65\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x2c\x20\x76\x20\x69\x6e\x20\x6f\x74\x68\x65\x72\x2e\x69\x74\x65\x6d\x73\x28\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x5b\x6b\x5d\x20\x3d\x20\x76\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x63\x6f\x70\x79\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x64\x20\x3d\x20\x64\x69\x63\x74\x28\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x76\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6b\x76\x20\x69\x73\x20\x6e\x6f\x74\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x64\x5b\x6b\x76\x5b\x30\x5d\x5d\x20\x3d\x20\x6b\x76\x5b\x31\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x64\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x72\x65\x70\x72\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x20\x3d\x20\x5b\x72\x65\x70\x72\x28\x6b\x29\x2b\x27\x3a\x20\x27\x2b\x72\x65\x70\x72\x28\x76\x29\x20\x66\x6f\x72\x20\x6b\x2c\x76\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x69\x74\x65\x6d\x73\x28\x29\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x27\x7b\x27\x2b\x20\x27\x2c\x20\x27\x2e\x6a\x6f\x69\x6e\x28\x61\x29\x20\x2b\x20\x27\x7d\x27\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x6a\x73\x6f\x6e\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x61\x20\x3d\x20\x5b\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x2c\x76\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x69\x74\x65\x6d\x73\x28\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x74\x79\x70\x65\x28\x6b\x29\x20\x69\x73\x20\x6e\x6f\x74\x20\x73\x74\x72\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x54\x79\x70\x65\x45\x72\x72\x6f\x72\x28\x27\x6a\x73\x6f\x6e\x20\x6b\x65\x79\x73\x20\x6d\x75\x73\x74\x20\x62\x65\x20\x73\x74\x72\x69\x6e\x67\x73\x2c\x20\x67\x6f\x74\x20\x27\x20\x2b\x20\x72\x65\x70\x72\x28\x6b\x29\x20\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x61\x2e\x61\x70\x70\x65\x6e\x64\x28\x6b\x2e\x5f\x5f\x6a\x73\x6f\x6e\x5f\x5f\x28\x29\x2b\x27\x3a\x20\x27\x2b\x76\x2e\x5f\x5f\x6a\x73\x6f\x6e\x5f\x5f\x28\x29\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x27\x7b\x27\x2b\x20\x27\x2c\x20\x27\x2e\x6a\x6f\x69\x6e\x28\x61\x29\x20\x2b\x20\x27\x7d\x27\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x65\x71\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x5f\x5f\x6f\x3a\x20\x6f\x62\x6a\x65\x63\x74\x29\x20\x2d\x3e\x20\x62\x6f\x6f\x6c\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x74\x79\x70\x65\x28\x5f\x5f\x6f\x29\x20\x69\x73\x20\x6e\x6f\x74\x20\x64\x69\x63\x74\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x20\x21\x3d\x20\x6c\x65\x6e\x28\x5f\x5f\x6f\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x6b\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x6b\x65\x79\x73\x28\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6b\x20\x6e\x6f\x74\x20\x69\x6e\x20\x5f\x5f\x6f\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x73\x65\x6c\x66\x5b\x6b\x5d\x20\x21\x3d\x20\x5f\x5f\x6f\x5b\x6b\x5d\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x54\x72\x75\x65\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x6e\x65\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x5f\x5f\x6f\x3a\x20\x6f\x62\x6a\x65\x63\x74\x29\x20\x2d\x3e\x20\x62\x6f\x6f\x6c\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6e\x6f\x74\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x65\x71\x5f\x5f\x28\x5f\x5f\x6f\x29"}, 6726 + {"builtins", "\x69\x6d\x70\x6f\x72\x74\x20\x73\x79\x73\x20\x61\x73\x20\x5f\x73\x79\x73\x0a\x0a\x64\x65\x66\x20\x70\x72\x69\x6e\x74\x28\x2a\x61\x72\x67\x73\x2c\x20\x73\x65\x70\x3d\x27\x20\x27\x2c\x20\x65\x6e\x64\x3d\x27\x5c\x6e\x27\x29\x3a\x0a\x20\x20\x20\x20\x73\x20\x3d\x20\x73\x65\x70\x2e\x6a\x6f\x69\x6e\x28\x5b\x73\x74\x72\x28\x69\x29\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x61\x72\x67\x73\x5d\x29\x0a\x20\x20\x20\x20\x5f\x73\x79\x73\x2e\x73\x74\x64\x6f\x75\x74\x2e\x77\x72\x69\x74\x65\x28\x73\x20\x2b\x20\x65\x6e\x64\x29\x0a\x0a\x64\x65\x66\x20\x72\x6f\x75\x6e\x64\x28\x78\x2c\x20\x6e\x64\x69\x67\x69\x74\x73\x3d\x30\x29\x3a\x0a\x20\x20\x20\x20\x61\x73\x73\x65\x72\x74\x20\x6e\x64\x69\x67\x69\x74\x73\x20\x3e\x3d\x20\x30\x0a\x20\x20\x20\x20\x69\x66\x20\x6e\x64\x69\x67\x69\x74\x73\x20\x3d\x3d\x20\x30\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x69\x6e\x74\x28\x78\x20\x2b\x20\x30\x2e\x35\x29\x20\x69\x66\x20\x78\x20\x3e\x3d\x20\x30\x20\x65\x6c\x73\x65\x20\x69\x6e\x74\x28\x78\x20\x2d\x20\x30\x2e\x35\x29\x0a\x20\x20\x20\x20\x69\x66\x20\x78\x20\x3e\x3d\x20\x30\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x69\x6e\x74\x28\x78\x20\x2a\x20\x31\x30\x2a\x2a\x6e\x64\x69\x67\x69\x74\x73\x20\x2b\x20\x30\x2e\x35\x29\x20\x2f\x20\x31\x30\x2a\x2a\x6e\x64\x69\x67\x69\x74\x73\x0a\x20\x20\x20\x20\x65\x6c\x73\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x69\x6e\x74\x28\x78\x20\x2a\x20\x31\x30\x2a\x2a\x6e\x64\x69\x67\x69\x74\x73\x20\x2d\x20\x30\x2e\x35\x29\x20\x2f\x20\x31\x30\x2a\x2a\x6e\x64\x69\x67\x69\x74\x73\x0a\x0a\x64\x65\x66\x20\x61\x62\x73\x28\x78\x29\x3a\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x2d\x78\x20\x69\x66\x20\x78\x20\x3c\x20\x30\x20\x65\x6c\x73\x65\x20\x78\x0a\x0a\x64\x65\x66\x20\x6d\x61\x78\x28\x61\x2c\x20\x62\x29\x3a\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x61\x20\x69\x66\x20\x61\x20\x3e\x20\x62\x20\x65\x6c\x73\x65\x20\x62\x0a\x0a\x64\x65\x66\x20\x6d\x69\x6e\x28\x61\x2c\x20\x62\x29\x3a\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x61\x20\x69\x66\x20\x61\x20\x3c\x20\x62\x20\x65\x6c\x73\x65\x20\x62\x0a\x0a\x64\x65\x66\x20\x61\x6c\x6c\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6e\x6f\x74\x20\x69\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x54\x72\x75\x65\x0a\x0a\x64\x65\x66\x20\x61\x6e\x79\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x69\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x54\x72\x75\x65\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x0a\x64\x65\x66\x20\x65\x6e\x75\x6d\x65\x72\x61\x74\x65\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x2c\x20\x73\x74\x61\x72\x74\x3d\x30\x29\x3a\x0a\x20\x20\x20\x20\x6e\x20\x3d\x20\x73\x74\x61\x72\x74\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x79\x69\x65\x6c\x64\x20\x6e\x2c\x20\x65\x6c\x65\x6d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6e\x20\x2b\x3d\x20\x31\x0a\x0a\x64\x65\x66\x20\x73\x75\x6d\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x3a\x0a\x20\x20\x20\x20\x72\x65\x73\x20\x3d\x20\x30\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x73\x20\x2b\x3d\x20\x69\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x73\x0a\x0a\x64\x65\x66\x20\x6d\x61\x70\x28\x66\x2c\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x79\x69\x65\x6c\x64\x20\x66\x28\x69\x29\x0a\x0a\x64\x65\x66\x20\x66\x69\x6c\x74\x65\x72\x28\x66\x2c\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x66\x28\x69\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x69\x65\x6c\x64\x20\x69\x0a\x0a\x64\x65\x66\x20\x7a\x69\x70\x28\x61\x2c\x20\x62\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x72\x61\x6e\x67\x65\x28\x6d\x69\x6e\x28\x6c\x65\x6e\x28\x61\x29\x2c\x20\x6c\x65\x6e\x28\x62\x29\x29\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x79\x69\x65\x6c\x64\x20\x28\x61\x5b\x69\x5d\x2c\x20\x62\x5b\x69\x5d\x29\x0a\x0a\x64\x65\x66\x20\x72\x65\x76\x65\x72\x73\x65\x64\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x3a\x0a\x20\x20\x20\x20\x61\x20\x3d\x20\x6c\x69\x73\x74\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x0a\x20\x20\x20\x20\x61\x2e\x72\x65\x76\x65\x72\x73\x65\x28\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x61\x0a\x0a\x64\x65\x66\x20\x73\x6f\x72\x74\x65\x64\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x2c\x20\x72\x65\x76\x65\x72\x73\x65\x3d\x46\x61\x6c\x73\x65\x29\x3a\x0a\x20\x20\x20\x20\x61\x20\x3d\x20\x6c\x69\x73\x74\x28\x69\x74\x65\x72\x61\x62\x6c\x65\x29\x0a\x20\x20\x20\x20\x61\x2e\x73\x6f\x72\x74\x28\x72\x65\x76\x65\x72\x73\x65\x3d\x72\x65\x76\x65\x72\x73\x65\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x61\x0a\x0a\x23\x23\x23\x23\x23\x20\x73\x74\x72\x20\x23\x23\x23\x23\x23\x0a\x0a\x73\x74\x72\x2e\x5f\x5f\x6d\x75\x6c\x5f\x5f\x20\x3d\x20\x6c\x61\x6d\x62\x64\x61\x20\x73\x65\x6c\x66\x2c\x20\x6e\x3a\x20\x27\x27\x2e\x6a\x6f\x69\x6e\x28\x5b\x73\x65\x6c\x66\x20\x66\x6f\x72\x20\x5f\x20\x69\x6e\x20\x72\x61\x6e\x67\x65\x28\x6e\x29\x5d\x29\x0a\x0a\x64\x65\x66\x20\x73\x74\x72\x40\x73\x70\x6c\x69\x74\x28\x73\x65\x6c\x66\x2c\x20\x73\x65\x70\x29\x3a\x0a\x20\x20\x20\x20\x69\x66\x20\x73\x65\x70\x20\x3d\x3d\x20\x22\x22\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6c\x69\x73\x74\x28\x73\x65\x6c\x66\x29\x0a\x20\x20\x20\x20\x72\x65\x73\x20\x3d\x20\x5b\x5d\x0a\x20\x20\x20\x20\x69\x20\x3d\x20\x30\x0a\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x69\x20\x3c\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x73\x65\x6c\x66\x5b\x69\x3a\x69\x2b\x6c\x65\x6e\x28\x73\x65\x70\x29\x5d\x20\x3d\x3d\x20\x73\x65\x70\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x73\x2e\x61\x70\x70\x65\x6e\x64\x28\x73\x65\x6c\x66\x5b\x3a\x69\x5d\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x20\x3d\x20\x73\x65\x6c\x66\x5b\x69\x2b\x6c\x65\x6e\x28\x73\x65\x70\x29\x3a\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x20\x3d\x20\x30\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x65\x6c\x73\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x20\x2b\x3d\x20\x31\x0a\x20\x20\x20\x20\x72\x65\x73\x2e\x61\x70\x70\x65\x6e\x64\x28\x73\x65\x6c\x66\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x73\x0a\x0a\x64\x65\x66\x20\x73\x74\x72\x40\x66\x6f\x72\x6d\x61\x74\x28\x73\x65\x6c\x66\x2c\x20\x2a\x61\x72\x67\x73\x29\x3a\x0a\x20\x20\x20\x20\x69\x66\x20\x27\x7b\x7d\x27\x20\x69\x6e\x20\x73\x65\x6c\x66\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x72\x61\x6e\x67\x65\x28\x6c\x65\x6e\x28\x61\x72\x67\x73\x29\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x20\x3d\x20\x73\x65\x6c\x66\x2e\x72\x65\x70\x6c\x61\x63\x65\x28\x27\x7b\x7d\x27\x2c\x20\x73\x74\x72\x28\x61\x72\x67\x73\x5b\x69\x5d\x29\x2c\x20\x31\x29\x0a\x20\x20\x20\x20\x65\x6c\x73\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x72\x61\x6e\x67\x65\x28\x6c\x65\x6e\x28\x61\x72\x67\x73\x29\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x20\x3d\x20\x73\x65\x6c\x66\x2e\x72\x65\x70\x6c\x61\x63\x65\x28\x27\x7b\x27\x2b\x73\x74\x72\x28\x69\x29\x2b\x27\x7d\x27\x2c\x20\x73\x74\x72\x28\x61\x72\x67\x73\x5b\x69\x5d\x29\x29\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x0a\x0a\x64\x65\x66\x20\x73\x74\x72\x40\x73\x74\x72\x69\x70\x28\x73\x65\x6c\x66\x2c\x20\x63\x68\x61\x72\x73\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x63\x68\x61\x72\x73\x20\x3d\x20\x63\x68\x61\x72\x73\x20\x6f\x72\x20\x27\x20\x5c\x74\x5c\x6e\x5c\x72\x27\x0a\x20\x20\x20\x20\x69\x20\x3d\x20\x30\x0a\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x69\x20\x3c\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x20\x61\x6e\x64\x20\x73\x65\x6c\x66\x5b\x69\x5d\x20\x69\x6e\x20\x63\x68\x61\x72\x73\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x20\x2b\x3d\x20\x31\x0a\x20\x20\x20\x20\x6a\x20\x3d\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x20\x2d\x20\x31\x0a\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x6a\x20\x3e\x3d\x20\x30\x20\x61\x6e\x64\x20\x73\x65\x6c\x66\x5b\x6a\x5d\x20\x69\x6e\x20\x63\x68\x61\x72\x73\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6a\x20\x2d\x3d\x20\x31\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x5b\x69\x3a\x6a\x2b\x31\x5d\x0a\x0a\x23\x23\x23\x23\x23\x20\x6c\x69\x73\x74\x20\x23\x23\x23\x23\x23\x0a\x0a\x6c\x69\x73\x74\x2e\x5f\x5f\x6e\x65\x77\x5f\x5f\x20\x3d\x20\x6c\x61\x6d\x62\x64\x61\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x20\x5b\x78\x20\x66\x6f\x72\x20\x78\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x5d\x0a\x6c\x69\x73\x74\x2e\x5f\x5f\x72\x65\x70\x72\x5f\x5f\x20\x3d\x20\x6c\x61\x6d\x62\x64\x61\x20\x73\x65\x6c\x66\x3a\x20\x27\x5b\x27\x20\x2b\x20\x27\x2c\x20\x27\x2e\x6a\x6f\x69\x6e\x28\x5b\x72\x65\x70\x72\x28\x69\x29\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x73\x65\x6c\x66\x5d\x29\x20\x2b\x20\x27\x5d\x27\x0a\x74\x75\x70\x6c\x65\x2e\x5f\x5f\x72\x65\x70\x72\x5f\x5f\x20\x3d\x20\x6c\x61\x6d\x62\x64\x61\x20\x73\x65\x6c\x66\x3a\x20\x27\x28\x27\x20\x2b\x20\x27\x2c\x20\x27\x2e\x6a\x6f\x69\x6e\x28\x5b\x72\x65\x70\x72\x28\x69\x29\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x73\x65\x6c\x66\x5d\x29\x20\x2b\x20\x27\x29\x27\x0a\x6c\x69\x73\x74\x2e\x5f\x5f\x6a\x73\x6f\x6e\x5f\x5f\x20\x3d\x20\x6c\x61\x6d\x62\x64\x61\x20\x73\x65\x6c\x66\x3a\x20\x27\x5b\x27\x20\x2b\x20\x27\x2c\x20\x27\x2e\x6a\x6f\x69\x6e\x28\x5b\x69\x2e\x5f\x5f\x6a\x73\x6f\x6e\x5f\x5f\x28\x29\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x73\x65\x6c\x66\x5d\x29\x20\x2b\x20\x27\x5d\x27\x0a\x74\x75\x70\x6c\x65\x2e\x5f\x5f\x6a\x73\x6f\x6e\x5f\x5f\x20\x3d\x20\x6c\x61\x6d\x62\x64\x61\x20\x73\x65\x6c\x66\x3a\x20\x27\x5b\x27\x20\x2b\x20\x27\x2c\x20\x27\x2e\x6a\x6f\x69\x6e\x28\x5b\x69\x2e\x5f\x5f\x6a\x73\x6f\x6e\x5f\x5f\x28\x29\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x73\x65\x6c\x66\x5d\x29\x20\x2b\x20\x27\x5d\x27\x0a\x0a\x64\x65\x66\x20\x5f\x5f\x71\x73\x6f\x72\x74\x28\x61\x3a\x20\x6c\x69\x73\x74\x2c\x20\x4c\x3a\x20\x69\x6e\x74\x2c\x20\x52\x3a\x20\x69\x6e\x74\x29\x3a\x0a\x20\x20\x20\x20\x69\x66\x20\x4c\x20\x3e\x3d\x20\x52\x3a\x20\x72\x65\x74\x75\x72\x6e\x3b\x0a\x20\x20\x20\x20\x6d\x69\x64\x20\x3d\x20\x61\x5b\x28\x52\x2b\x4c\x29\x2f\x2f\x32\x5d\x3b\x0a\x20\x20\x20\x20\x69\x2c\x20\x6a\x20\x3d\x20\x4c\x2c\x20\x52\x0a\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x69\x3c\x3d\x6a\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x61\x5b\x69\x5d\x3c\x6d\x69\x64\x3a\x20\x69\x2b\x3d\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x77\x68\x69\x6c\x65\x20\x61\x5b\x6a\x5d\x3e\x6d\x69\x64\x3a\x20\x6a\x2d\x3d\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x69\x3c\x3d\x6a\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x61\x5b\x69\x5d\x2c\x20\x61\x5b\x6a\x5d\x20\x3d\x20\x61\x5b\x6a\x5d\x2c\x20\x61\x5b\x69\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x2b\x3d\x31\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6a\x2d\x3d\x31\x0a\x20\x20\x20\x20\x5f\x5f\x71\x73\x6f\x72\x74\x28\x61\x2c\x20\x4c\x2c\x20\x6a\x29\x0a\x20\x20\x20\x20\x5f\x5f\x71\x73\x6f\x72\x74\x28\x61\x2c\x20\x69\x2c\x20\x52\x29\x0a\x0a\x64\x65\x66\x20\x6c\x69\x73\x74\x40\x73\x6f\x72\x74\x28\x73\x65\x6c\x66\x2c\x20\x72\x65\x76\x65\x72\x73\x65\x3d\x46\x61\x6c\x73\x65\x29\x3a\x0a\x20\x20\x20\x20\x5f\x5f\x71\x73\x6f\x72\x74\x28\x73\x65\x6c\x66\x2c\x20\x30\x2c\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x2d\x31\x29\x0a\x20\x20\x20\x20\x69\x66\x20\x72\x65\x76\x65\x72\x73\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x72\x65\x76\x65\x72\x73\x65\x28\x29\x0a\x0a\x64\x65\x66\x20\x6c\x69\x73\x74\x40\x72\x65\x6d\x6f\x76\x65\x28\x73\x65\x6c\x66\x2c\x20\x76\x61\x6c\x75\x65\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x72\x61\x6e\x67\x65\x28\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x73\x65\x6c\x66\x5b\x69\x5d\x20\x3d\x3d\x20\x76\x61\x6c\x75\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x64\x65\x6c\x20\x73\x65\x6c\x66\x5b\x69\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x0a\x20\x20\x20\x20\x76\x61\x6c\x75\x65\x20\x3d\x20\x72\x65\x70\x72\x28\x76\x61\x6c\x75\x65\x29\x0a\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x56\x61\x6c\x75\x65\x45\x72\x72\x6f\x72\x28\x66\x27\x7b\x76\x61\x6c\x75\x65\x7d\x20\x69\x73\x20\x6e\x6f\x74\x20\x69\x6e\x20\x6c\x69\x73\x74\x27\x29\x0a\x0a\x64\x65\x66\x20\x6c\x69\x73\x74\x40\x69\x6e\x64\x65\x78\x28\x73\x65\x6c\x66\x2c\x20\x76\x61\x6c\x75\x65\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x72\x61\x6e\x67\x65\x28\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x73\x65\x6c\x66\x5b\x69\x5d\x20\x3d\x3d\x20\x76\x61\x6c\x75\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x69\x0a\x20\x20\x20\x20\x76\x61\x6c\x75\x65\x20\x3d\x20\x72\x65\x70\x72\x28\x76\x61\x6c\x75\x65\x29\x0a\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x56\x61\x6c\x75\x65\x45\x72\x72\x6f\x72\x28\x66\x27\x7b\x76\x61\x6c\x75\x65\x7d\x20\x69\x73\x20\x6e\x6f\x74\x20\x69\x6e\x20\x6c\x69\x73\x74\x27\x29\x0a\x0a\x64\x65\x66\x20\x6c\x69\x73\x74\x40\x70\x6f\x70\x28\x73\x65\x6c\x66\x2c\x20\x69\x3d\x2d\x31\x29\x3a\x0a\x20\x20\x20\x20\x72\x65\x73\x20\x3d\x20\x73\x65\x6c\x66\x5b\x69\x5d\x0a\x20\x20\x20\x20\x64\x65\x6c\x20\x73\x65\x6c\x66\x5b\x69\x5d\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x73\x0a\x0a\x64\x65\x66\x20\x6c\x69\x73\x74\x40\x5f\x5f\x65\x71\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x69\x66\x20\x74\x79\x70\x65\x28\x73\x65\x6c\x66\x29\x20\x69\x73\x20\x6e\x6f\x74\x20\x74\x79\x70\x65\x28\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x69\x66\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x20\x21\x3d\x20\x6c\x65\x6e\x28\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x72\x61\x6e\x67\x65\x28\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x73\x65\x6c\x66\x5b\x69\x5d\x20\x21\x3d\x20\x6f\x74\x68\x65\x72\x5b\x69\x5d\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x54\x72\x75\x65\x0a\x74\x75\x70\x6c\x65\x2e\x5f\x5f\x65\x71\x5f\x5f\x20\x3d\x20\x6c\x69\x73\x74\x2e\x5f\x5f\x65\x71\x5f\x5f\x0a\x6c\x69\x73\x74\x2e\x5f\x5f\x6e\x65\x5f\x5f\x20\x3d\x20\x6c\x61\x6d\x62\x64\x61\x20\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x3a\x20\x6e\x6f\x74\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x65\x71\x5f\x5f\x28\x6f\x74\x68\x65\x72\x29\x0a\x74\x75\x70\x6c\x65\x2e\x5f\x5f\x6e\x65\x5f\x5f\x20\x3d\x20\x6c\x61\x6d\x62\x64\x61\x20\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x3a\x20\x6e\x6f\x74\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x65\x71\x5f\x5f\x28\x6f\x74\x68\x65\x72\x29\x0a\x0a\x64\x65\x66\x20\x6c\x69\x73\x74\x40\x63\x6f\x75\x6e\x74\x28\x73\x65\x6c\x66\x2c\x20\x78\x29\x3a\x0a\x20\x20\x20\x20\x72\x65\x73\x20\x3d\x20\x30\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x73\x65\x6c\x66\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x69\x20\x3d\x3d\x20\x78\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x73\x20\x2b\x3d\x20\x31\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x73\x0a\x74\x75\x70\x6c\x65\x2e\x63\x6f\x75\x6e\x74\x20\x3d\x20\x6c\x69\x73\x74\x2e\x63\x6f\x75\x6e\x74\x0a\x0a\x64\x65\x66\x20\x6c\x69\x73\x74\x40\x5f\x5f\x63\x6f\x6e\x74\x61\x69\x6e\x73\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x69\x74\x65\x6d\x29\x3a\x0a\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x73\x65\x6c\x66\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x69\x20\x3d\x3d\x20\x69\x74\x65\x6d\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x54\x72\x75\x65\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x46\x61\x6c\x73\x65\x0a\x74\x75\x70\x6c\x65\x2e\x5f\x5f\x63\x6f\x6e\x74\x61\x69\x6e\x73\x5f\x5f\x20\x3d\x20\x6c\x69\x73\x74\x2e\x5f\x5f\x63\x6f\x6e\x74\x61\x69\x6e\x73\x5f\x5f\x0a\x0a\x0a\x63\x6c\x61\x73\x73\x20\x70\x72\x6f\x70\x65\x72\x74\x79\x3a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x6e\x69\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x66\x67\x65\x74\x2c\x20\x66\x73\x65\x74\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x66\x67\x65\x74\x20\x3d\x20\x66\x67\x65\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x66\x73\x65\x74\x20\x3d\x20\x66\x73\x65\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x68\x61\x73\x61\x74\x74\x72\x28\x66\x67\x65\x74\x2c\x20\x27\x5f\x5f\x64\x6f\x63\x5f\x5f\x27\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x64\x6f\x63\x5f\x5f\x20\x3d\x20\x66\x67\x65\x74\x2e\x5f\x5f\x64\x6f\x63\x5f\x5f\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x67\x65\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x62\x6a\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x66\x67\x65\x74\x28\x6f\x62\x6a\x29\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x73\x65\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x62\x6a\x2c\x20\x76\x61\x6c\x75\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x73\x65\x6c\x66\x2e\x66\x73\x65\x74\x20\x69\x73\x20\x4e\x6f\x6e\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x61\x69\x73\x65\x20\x41\x74\x74\x72\x69\x62\x75\x74\x65\x45\x72\x72\x6f\x72\x28\x22\x72\x65\x61\x64\x6f\x6e\x6c\x79\x20\x70\x72\x6f\x70\x65\x72\x74\x79\x22\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x66\x73\x65\x74\x28\x6f\x62\x6a\x2c\x20\x76\x61\x6c\x75\x65\x29\x0a\x0a\x63\x6c\x61\x73\x73\x20\x73\x74\x61\x74\x69\x63\x6d\x65\x74\x68\x6f\x64\x3a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x6e\x69\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x66\x20\x3d\x20\x66\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x67\x65\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x62\x6a\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x66\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x63\x61\x6c\x6c\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x2a\x61\x72\x67\x73\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x66\x28\x2a\x61\x72\x67\x73\x29\x0a\x20\x20\x20\x20\x0a\x64\x65\x66\x20\x74\x79\x70\x65\x40\x5f\x5f\x72\x65\x70\x72\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x22\x3c\x63\x6c\x61\x73\x73\x20\x27\x22\x20\x2b\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x6e\x61\x6d\x65\x5f\x5f\x20\x2b\x20\x22\x27\x3e\x22\x0a\x0a\x64\x65\x66\x20\x68\x65\x6c\x70\x28\x6f\x62\x6a\x29\x3a\x0a\x20\x20\x20\x20\x69\x66\x20\x68\x61\x73\x61\x74\x74\x72\x28\x6f\x62\x6a\x2c\x20\x27\x5f\x5f\x66\x75\x6e\x63\x5f\x5f\x27\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x62\x6a\x20\x3d\x20\x6f\x62\x6a\x2e\x5f\x5f\x66\x75\x6e\x63\x5f\x5f\x0a\x20\x20\x20\x20\x69\x66\x20\x68\x61\x73\x61\x74\x74\x72\x28\x6f\x62\x6a\x2c\x20\x27\x5f\x5f\x64\x6f\x63\x5f\x5f\x27\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x70\x72\x69\x6e\x74\x28\x6f\x62\x6a\x2e\x5f\x5f\x64\x6f\x63\x5f\x5f\x29\x0a\x20\x20\x20\x20\x65\x6c\x73\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x70\x72\x69\x6e\x74\x28\x22\x4e\x6f\x20\x64\x6f\x63\x73\x74\x72\x69\x6e\x67\x20\x66\x6f\x75\x6e\x64\x22\x29\x0a"}, 6727 + {"_set", "\x63\x6c\x61\x73\x73\x20\x73\x65\x74\x3a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x6e\x69\x74\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3d\x4e\x6f\x6e\x65\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x20\x3d\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x20\x6f\x72\x20\x5b\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x20\x3d\x20\x7b\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x69\x74\x65\x6d\x20\x69\x6e\x20\x69\x74\x65\x72\x61\x62\x6c\x65\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x61\x64\x64\x28\x69\x74\x65\x6d\x29\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x61\x64\x64\x28\x73\x65\x6c\x66\x2c\x20\x65\x6c\x65\x6d\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x65\x6c\x65\x6d\x5d\x20\x3d\x20\x4e\x6f\x6e\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x64\x69\x73\x63\x61\x72\x64\x28\x73\x65\x6c\x66\x2c\x20\x65\x6c\x65\x6d\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x64\x65\x6c\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x65\x6c\x65\x6d\x5d\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x72\x65\x6d\x6f\x76\x65\x28\x73\x65\x6c\x66\x2c\x20\x65\x6c\x65\x6d\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x64\x65\x6c\x20\x73\x65\x6c\x66\x2e\x5f\x61\x5b\x65\x6c\x65\x6d\x5d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x63\x6c\x65\x61\x72\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x5f\x61\x2e\x63\x6c\x65\x61\x72\x28\x29\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x75\x70\x64\x61\x74\x65\x28\x73\x65\x6c\x66\x2c\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x6f\x74\x68\x65\x72\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x65\x6c\x66\x2e\x61\x64\x64\x28\x65\x6c\x65\x6d\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x6c\x65\x6e\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x2e\x5f\x61\x29\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x63\x6f\x70\x79\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x74\x28\x73\x65\x6c\x66\x2e\x5f\x61\x2e\x6b\x65\x79\x73\x28\x29\x29\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x61\x6e\x64\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x20\x3d\x20\x73\x65\x74\x28\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x73\x65\x6c\x66\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x6f\x74\x68\x65\x72\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x2e\x61\x64\x64\x28\x65\x6c\x65\x6d\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x74\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x6f\x72\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x20\x3d\x20\x73\x65\x6c\x66\x2e\x63\x6f\x70\x79\x28\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x6f\x74\x68\x65\x72\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x2e\x61\x64\x64\x28\x65\x6c\x65\x6d\x29\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x74\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x73\x75\x62\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x20\x3d\x20\x73\x65\x74\x28\x29\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x73\x65\x6c\x66\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x65\x6c\x65\x6d\x20\x6e\x6f\x74\x20\x69\x6e\x20\x6f\x74\x68\x65\x72\x3a\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x2e\x61\x64\x64\x28\x65\x6c\x65\x6d\x29\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x74\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x78\x6f\x72\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x20\x3d\x20\x73\x65\x74\x28\x29\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x73\x65\x6c\x66\x3a\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x65\x6c\x65\x6d\x20\x6e\x6f\x74\x20\x69\x6e\x20\x6f\x74\x68\x65\x72\x3a\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x2e\x61\x64\x64\x28\x65\x6c\x65\x6d\x29\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x66\x6f\x72\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x6f\x74\x68\x65\x72\x3a\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x65\x6c\x65\x6d\x20\x6e\x6f\x74\x20\x69\x6e\x20\x73\x65\x6c\x66\x3a\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x2e\x61\x64\x64\x28\x65\x6c\x65\x6d\x29\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x74\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x75\x6e\x69\x6f\x6e\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x20\x7c\x20\x6f\x74\x68\x65\x72\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x69\x6e\x74\x65\x72\x73\x65\x63\x74\x69\x6f\x6e\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x20\x26\x20\x6f\x74\x68\x65\x72\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x64\x69\x66\x66\x65\x72\x65\x6e\x63\x65\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x20\x2d\x20\x6f\x74\x68\x65\x72\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x73\x79\x6d\x6d\x65\x74\x72\x69\x63\x5f\x64\x69\x66\x66\x65\x72\x65\x6e\x63\x65\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x20\x5e\x20\x6f\x74\x68\x65\x72\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x65\x71\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x78\x6f\x72\x5f\x5f\x28\x6f\x74\x68\x65\x72\x29\x2e\x5f\x5f\x6c\x65\x6e\x5f\x5f\x28\x29\x20\x3d\x3d\x20\x30\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x6e\x65\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x78\x6f\x72\x5f\x5f\x28\x6f\x74\x68\x65\x72\x29\x2e\x5f\x5f\x6c\x65\x6e\x5f\x5f\x28\x29\x20\x21\x3d\x20\x30\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x69\x73\x64\x69\x73\x6a\x6f\x69\x6e\x74\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x61\x6e\x64\x5f\x5f\x28\x6f\x74\x68\x65\x72\x29\x2e\x5f\x5f\x6c\x65\x6e\x5f\x5f\x28\x29\x20\x3d\x3d\x20\x30\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x69\x73\x73\x75\x62\x73\x65\x74\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x5f\x73\x75\x62\x5f\x5f\x28\x6f\x74\x68\x65\x72\x29\x2e\x5f\x5f\x6c\x65\x6e\x5f\x5f\x28\x29\x20\x3d\x3d\x20\x30\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x69\x73\x73\x75\x70\x65\x72\x73\x65\x74\x28\x73\x65\x6c\x66\x2c\x20\x6f\x74\x68\x65\x72\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x6f\x74\x68\x65\x72\x2e\x5f\x5f\x73\x75\x62\x5f\x5f\x28\x73\x65\x6c\x66\x29\x2e\x5f\x5f\x6c\x65\x6e\x5f\x5f\x28\x29\x20\x3d\x3d\x20\x30\x0a\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x63\x6f\x6e\x74\x61\x69\x6e\x73\x5f\x5f\x28\x73\x65\x6c\x66\x2c\x20\x65\x6c\x65\x6d\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x65\x6c\x65\x6d\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x72\x65\x70\x72\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x6c\x65\x6e\x28\x73\x65\x6c\x66\x29\x20\x3d\x3d\x20\x30\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x27\x73\x65\x74\x28\x29\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x27\x7b\x27\x2b\x20\x27\x2c\x20\x27\x2e\x6a\x6f\x69\x6e\x28\x5b\x72\x65\x70\x72\x28\x69\x29\x20\x66\x6f\x72\x20\x69\x20\x69\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x2e\x6b\x65\x79\x73\x28\x29\x5d\x29\x20\x2b\x20\x27\x7d\x27\x0a\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x64\x65\x66\x20\x5f\x5f\x69\x74\x65\x72\x5f\x5f\x28\x73\x65\x6c\x66\x29\x3a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x73\x65\x6c\x66\x2e\x5f\x61\x2e\x6b\x65\x79\x73\x28\x29"}, 6728 + 6729 + }; 6730 + } // namespace pkpy 6731 + 6732 + 6733 + 6734 + namespace pkpy{ 6735 + 6736 + class RangeIter final: public BaseIter { 6737 + i64 current; 6738 + Range r; // copy by value, so we don't need to keep ref 6739 + public: 6740 + RangeIter(VM* vm, PyObject* ref) : BaseIter(vm) { 6741 + this->r = OBJ_GET(Range, ref); 6742 + this->current = r.start; 6743 + } 6744 + 6745 + bool _has_next(){ 6746 + return r.step > 0 ? current < r.stop : current > r.stop; 6747 + } 6748 + 6749 + PyObject* next(){ 6750 + if(!_has_next()) return vm->StopIteration; 6751 + current += r.step; 6752 + return VAR(current-r.step); 6753 + } 6754 + }; 6755 + 6756 + template <typename T> 6757 + class ArrayIter final: public BaseIter { 6758 + PyObject* ref; 6759 + T* array; 6760 + int index; 6761 + public: 6762 + ArrayIter(VM* vm, PyObject* ref) : BaseIter(vm), ref(ref) { 6763 + array = &OBJ_GET(T, ref); 6764 + index = 0; 6765 + } 6766 + 6767 + PyObject* next() override{ 6768 + if(index >= array->size()) return vm->StopIteration; 6769 + return array->operator[](index++); 6770 + } 6771 + 6772 + void _gc_mark() const{ 6773 + OBJ_MARK(ref); 6774 + } 6775 + }; 6776 + 6777 + class StringIter final: public BaseIter { 6778 + PyObject* ref; 6779 + int index; 6780 + public: 6781 + StringIter(VM* vm, PyObject* ref) : BaseIter(vm), ref(ref), index(0) {} 6782 + 6783 + PyObject* next() override{ 6784 + // TODO: optimize this to use iterator 6785 + // operator[] is O(n) complexity 6786 + Str* str = &OBJ_GET(Str, ref); 6787 + if(index == str->u8_length()) return vm->StopIteration; 6788 + return VAR(str->u8_getitem(index++)); 6789 + } 6790 + 6791 + void _gc_mark() const{ 6792 + OBJ_MARK(ref); 6793 + } 6794 + }; 6795 + 6796 + inline PyObject* Generator::next(){ 6797 + if(state == 2) return vm->StopIteration; 6798 + // reset frame._sp_base 6799 + frame._sp_base = frame._s->_sp; 6800 + frame._locals.a = frame._s->_sp; 6801 + // restore the context 6802 + for(PyObject* obj: s_backup) frame._s->push(obj); 6803 + s_backup.clear(); 6804 + vm->callstack.push(std::move(frame)); 6805 + PyObject* ret = vm->_run_top_frame(); 6806 + if(ret == PY_OP_YIELD){ 6807 + // backup the context 6808 + frame = std::move(vm->callstack.top()); 6809 + PyObject* ret = frame._s->popx(); 6810 + for(PyObject* obj: frame.stack_view()) s_backup.push_back(obj); 6811 + vm->_pop_frame(); 6812 + state = 1; 6813 + if(ret == vm->StopIteration) state = 2; 6814 + return ret; 6815 + }else{ 6816 + state = 2; 6817 + return vm->StopIteration; 6818 + } 6819 + } 6820 + 6821 + inline void Generator::_gc_mark() const{ 6822 + frame._gc_mark(); 6823 + for(PyObject* obj: s_backup) OBJ_MARK(obj); 6824 + } 6825 + 6826 + } // namespace pkpy 6827 + 6828 + 6829 + namespace pkpy { 6830 + 6831 + // https://github.com/zhicheng/base64/blob/master/base64.c 6832 + 6833 + #define BASE64_PAD '=' 6834 + #define BASE64DE_FIRST '+' 6835 + #define BASE64DE_LAST 'z' 6836 + 6837 + /* BASE 64 encode table */ 6838 + static const char base64en[] = { 6839 + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 6840 + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 6841 + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 6842 + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 6843 + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 6844 + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 6845 + 'w', 'x', 'y', 'z', '0', '1', '2', '3', 6846 + '4', '5', '6', '7', '8', '9', '+', '/', 6847 + }; 6848 + 6849 + /* ASCII order for BASE 64 decode, 255 in unused character */ 6850 + static const unsigned char base64de[] = { 6851 + /* nul, soh, stx, etx, eot, enq, ack, bel, */ 6852 + 255, 255, 255, 255, 255, 255, 255, 255, 6853 + 6854 + /* bs, ht, nl, vt, np, cr, so, si, */ 6855 + 255, 255, 255, 255, 255, 255, 255, 255, 6856 + 6857 + /* dle, dc1, dc2, dc3, dc4, nak, syn, etb, */ 6858 + 255, 255, 255, 255, 255, 255, 255, 255, 6859 + 6860 + /* can, em, sub, esc, fs, gs, rs, us, */ 6861 + 255, 255, 255, 255, 255, 255, 255, 255, 6862 + 6863 + /* sp, '!', '"', '#', '$', '%', '&', ''', */ 6864 + 255, 255, 255, 255, 255, 255, 255, 255, 6865 + 6866 + /* '(', ')', '*', '+', ',', '-', '.', '/', */ 6867 + 255, 255, 255, 62, 255, 255, 255, 63, 6868 + 6869 + /* '0', '1', '2', '3', '4', '5', '6', '7', */ 6870 + 52, 53, 54, 55, 56, 57, 58, 59, 6871 + 6872 + /* '8', '9', ':', ';', '<', '=', '>', '?', */ 6873 + 60, 61, 255, 255, 255, 255, 255, 255, 6874 + 6875 + /* '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', */ 6876 + 255, 0, 1, 2, 3, 4, 5, 6, 6877 + 6878 + /* 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', */ 6879 + 7, 8, 9, 10, 11, 12, 13, 14, 6880 + 6881 + /* 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', */ 6882 + 15, 16, 17, 18, 19, 20, 21, 22, 6883 + 6884 + /* 'X', 'Y', 'Z', '[', '\', ']', '^', '_', */ 6885 + 23, 24, 25, 255, 255, 255, 255, 255, 6886 + 6887 + /* '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', */ 6888 + 255, 26, 27, 28, 29, 30, 31, 32, 6889 + 6890 + /* 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', */ 6891 + 33, 34, 35, 36, 37, 38, 39, 40, 6892 + 6893 + /* 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', */ 6894 + 41, 42, 43, 44, 45, 46, 47, 48, 6895 + 6896 + /* 'x', 'y', 'z', '{', '|', '}', '~', del, */ 6897 + 49, 50, 51, 255, 255, 255, 255, 255 6898 + }; 6899 + 6900 + unsigned int 6901 + base64_encode(const unsigned char *in, unsigned int inlen, char *out) 6902 + { 6903 + int s; 6904 + unsigned int i; 6905 + unsigned int j; 6906 + unsigned char c; 6907 + unsigned char l; 6908 + 6909 + s = 0; 6910 + l = 0; 6911 + for (i = j = 0; i < inlen; i++) { 6912 + c = in[i]; 6913 + 6914 + switch (s) { 6915 + case 0: 6916 + s = 1; 6917 + out[j++] = base64en[(c >> 2) & 0x3F]; 6918 + break; 6919 + case 1: 6920 + s = 2; 6921 + out[j++] = base64en[((l & 0x3) << 4) | ((c >> 4) & 0xF)]; 6922 + break; 6923 + case 2: 6924 + s = 0; 6925 + out[j++] = base64en[((l & 0xF) << 2) | ((c >> 6) & 0x3)]; 6926 + out[j++] = base64en[c & 0x3F]; 6927 + break; 6928 + } 6929 + l = c; 6930 + } 6931 + 6932 + switch (s) { 6933 + case 1: 6934 + out[j++] = base64en[(l & 0x3) << 4]; 6935 + out[j++] = BASE64_PAD; 6936 + out[j++] = BASE64_PAD; 6937 + break; 6938 + case 2: 6939 + out[j++] = base64en[(l & 0xF) << 2]; 6940 + out[j++] = BASE64_PAD; 6941 + break; 6942 + } 6943 + 6944 + out[j] = 0; 6945 + 6946 + return j; 6947 + } 6948 + 6949 + unsigned int 6950 + base64_decode(const char *in, unsigned int inlen, unsigned char *out) 6951 + { 6952 + unsigned int i; 6953 + unsigned int j; 6954 + unsigned char c; 6955 + 6956 + if (inlen & 0x3) { 6957 + return 0; 6958 + } 6959 + 6960 + for (i = j = 0; i < inlen; i++) { 6961 + if (in[i] == BASE64_PAD) { 6962 + break; 6963 + } 6964 + if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { 6965 + return 0; 6966 + } 6967 + 6968 + c = base64de[(unsigned char)in[i]]; 6969 + if (c == 255) { 6970 + return 0; 6971 + } 6972 + 6973 + switch (i & 0x3) { 6974 + case 0: 6975 + out[j] = (c << 2) & 0xFF; 6976 + break; 6977 + case 1: 6978 + out[j++] |= (c >> 4) & 0x3; 6979 + out[j] = (c & 0xF) << 4; 6980 + break; 6981 + case 2: 6982 + out[j++] |= (c >> 2) & 0xF; 6983 + out[j] = (c & 0x3) << 6; 6984 + break; 6985 + case 3: 6986 + out[j++] |= c; 6987 + break; 6988 + } 6989 + } 6990 + 6991 + return j; 6992 + } 6993 + 6994 + void add_module_base64(VM* vm){ 6995 + PyObject* mod = vm->new_module("base64"); 6996 + 6997 + // b64encode 6998 + vm->bind_static_method<1>(mod, "b64encode", [](VM* vm, ArgsView args){ 6999 + Bytes& b = CAST(Bytes&, args[0]); 7000 + std::vector<char> out(b.size() * 2); 7001 + int size = base64_encode((const unsigned char*)b.data(), b.size(), out.data()); 7002 + out.resize(size); 7003 + return VAR(Bytes(std::move(out))); 7004 + }); 7005 + 7006 + // b64decode 7007 + vm->bind_static_method<1>(mod, "b64decode", [](VM* vm, ArgsView args){ 7008 + Bytes& b = CAST(Bytes&, args[0]); 7009 + std::vector<char> out(b.size()); 7010 + int size = base64_decode(b.data(), b.size(), (unsigned char*)out.data()); 7011 + out.resize(size); 7012 + return VAR(Bytes(std::move(out))); 7013 + }); 7014 + } 7015 + 7016 + } // namespace pkpy 7017 + 7018 + 7019 + namespace pkpy { 7020 + 7021 + #define PY_CLASS(T, mod, name) \ 7022 + static Type _type(VM* vm) { \ 7023 + static const StrName __x0(#mod); \ 7024 + static const StrName __x1(#name); \ 7025 + return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \ 7026 + } \ 7027 + static PyObject* register_class(VM* vm, PyObject* mod) { \ 7028 + PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \ 7029 + if(OBJ_NAME(mod) != #mod) { \ 7030 + auto msg = fmt("register_class() failed: ", OBJ_NAME(mod), " != ", #mod); \ 7031 + throw std::runtime_error(msg); \ 7032 + } \ 7033 + T::_register(vm, mod, type); \ 7034 + type->attr()._try_perfect_rehash(); \ 7035 + return type; \ 7036 + } 7037 + 7038 + #define VAR_T(T, ...) vm->heap.gcnew<T>(T::_type(vm), T(__VA_ARGS__)) 7039 + 7040 + 7041 + struct VoidP{ 7042 + PY_CLASS(VoidP, c, void_p) 7043 + 7044 + void* ptr; 7045 + VoidP(void* ptr): ptr(ptr){} 7046 + 7047 + static void _register(VM* vm, PyObject* mod, PyObject* type){ 7048 + vm->bind_static_method<1>(type, "__new__", CPP_NOT_IMPLEMENTED()); 7049 + 7050 + vm->bind_static_method<1>(type, "__repr__", [](VM* vm, ArgsView args){ 7051 + VoidP& self = CAST(VoidP&, args[0]); 7052 + std::stringstream ss; 7053 + ss << "<void* at " << self.ptr << ">"; 7054 + return VAR(ss.str()); 7055 + }); 7056 + } 7057 + }; 7058 + 7059 + inline void add_module_c(VM* vm){ 7060 + PyObject* mod = vm->new_module("c"); 7061 + VoidP::register_class(vm, mod); 7062 + } 7063 + 7064 + inline PyObject* py_var(VM* vm, void* p){ 7065 + return VAR_T(VoidP, p); 7066 + } 7067 + 7068 + inline PyObject* py_var(VM* vm, char* p){ 7069 + return VAR_T(VoidP, p); 7070 + } 7071 + /***********************************************/ 7072 + 7073 + template<typename T> 7074 + struct _pointer { 7075 + static constexpr int level = 0; 7076 + using baseT = T; 7077 + }; 7078 + 7079 + template<typename T> 7080 + struct _pointer<T*> { 7081 + static constexpr int level = _pointer<T>::level + 1; 7082 + using baseT = typename _pointer<T>::baseT; 7083 + }; 7084 + 7085 + template<typename T> 7086 + struct pointer { 7087 + static constexpr int level = _pointer<std::decay_t<T>>::level; 7088 + using baseT = typename _pointer<std::decay_t<T>>::baseT; 7089 + }; 7090 + 7091 + template<typename T> 7092 + T py_pointer_cast(VM* vm, PyObject* var){ 7093 + static_assert(std::is_pointer_v<T>); 7094 + VoidP& p = CAST(VoidP&, var); 7095 + return reinterpret_cast<T>(p.ptr); 7096 + } 7097 + } // namespace pkpy 7098 + 7099 + 7100 + #if __has_include("httplib.h") 7101 + #include "httplib.h" 7102 + 7103 + namespace pkpy { 7104 + 7105 + inline void add_module_requests(VM* vm){ 7106 + static StrName m_requests("requests"); 7107 + static StrName m_Response("Response"); 7108 + PyObject* mod = vm->new_module(m_requests); 7109 + CodeObject_ code = vm->compile(kPythonLibs["requests"], "requests.py", EXEC_MODE); 7110 + vm->_exec(code, mod); 7111 + 7112 + vm->bind_func<4>(mod, "_request", [](VM* vm, ArgsView args){ 7113 + Str method = CAST(Str&, args[0]); 7114 + Str url = CAST(Str&, args[1]); 7115 + PyObject* headers = args[2]; // a dict object 7116 + PyObject* body = args[3]; // a bytes object 7117 + 7118 + if(url.index("http://") != 0){ 7119 + vm->ValueError("url must start with http://"); 7120 + } 7121 + 7122 + for(char c: url){ 7123 + switch(c){ 7124 + case '.': 7125 + case '-': 7126 + case '_': 7127 + case '~': 7128 + case ':': 7129 + case '/': 7130 + break; 7131 + default: 7132 + if(!isalnum(c)){ 7133 + vm->ValueError(fmt("invalid character in url: '", c, "'")); 7134 + } 7135 + } 7136 + } 7137 + 7138 + int slash = url.index("/", 7); 7139 + Str path = "/"; 7140 + if(slash != -1){ 7141 + path = url.substr(slash); 7142 + url = url.substr(0, slash); 7143 + if(path.empty()) path = "/"; 7144 + } 7145 + 7146 + httplib::Client client(url.str()); 7147 + 7148 + httplib::Headers h; 7149 + if(headers != vm->None){ 7150 + List list = CAST(List&, headers); 7151 + for(auto& item : list){ 7152 + Tuple t = CAST(Tuple&, item); 7153 + Str key = CAST(Str&, t[0]); 7154 + Str value = CAST(Str&, t[1]); 7155 + h.emplace(key.str(), value.str()); 7156 + } 7157 + } 7158 + 7159 + auto _to_resp = [=](const httplib::Result& res){ 7160 + return vm->call( 7161 + vm->_modules[m_requests]->attr(m_Response), 7162 + VAR(res->status), 7163 + VAR(res->reason), 7164 + VAR(Bytes(res->body)) 7165 + ); 7166 + }; 7167 + 7168 + if(method == "GET"){ 7169 + httplib::Result res = client.Get(path.str(), h); 7170 + return _to_resp(res); 7171 + }else if(method == "POST"){ 7172 + Bytes b = CAST(Bytes&, body); 7173 + httplib::Result res = client.Post(path.str(), h, b.data(), b.size(), "application/octet-stream"); 7174 + return _to_resp(res); 7175 + }else if(method == "PUT"){ 7176 + Bytes b = CAST(Bytes&, body); 7177 + httplib::Result res = client.Put(path.str(), h, b.data(), b.size(), "application/octet-stream"); 7178 + return _to_resp(res); 7179 + }else if(method == "DELETE"){ 7180 + httplib::Result res = client.Delete(path.str(), h); 7181 + return _to_resp(res); 7182 + }else{ 7183 + vm->ValueError("invalid method"); 7184 + } 7185 + UNREACHABLE(); 7186 + }); 7187 + } 7188 + 7189 + } // namespace pkpy 7190 + 7191 + #else 7192 + 7193 + inline void add_module_requests(void* vm){ } 7194 + 7195 + #endif 7196 + 7197 + 7198 + #if PK_ENABLE_OS 7199 + 7200 + #include <filesystem> 7201 + #include <cstdio> 7202 + 7203 + namespace pkpy{ 7204 + 7205 + inline int _ = set_read_file_cwd([](const Str& name){ 7206 + std::filesystem::path path(name.sv()); 7207 + bool exists = std::filesystem::exists(path); 7208 + if(!exists) return Bytes(); 7209 + std::string cname = name.str(); 7210 + FILE* fp = fopen(cname.c_str(), "rb"); 7211 + if(!fp) return Bytes(); 7212 + fseek(fp, 0, SEEK_END); 7213 + std::vector<char> buffer(ftell(fp)); 7214 + fseek(fp, 0, SEEK_SET); 7215 + fread(buffer.data(), 1, buffer.size(), fp); 7216 + fclose(fp); 7217 + return Bytes(std::move(buffer)); 7218 + }); 7219 + 7220 + struct FileIO { 7221 + PY_CLASS(FileIO, io, FileIO) 7222 + 7223 + Str file; 7224 + Str mode; 7225 + FILE* fp; 7226 + 7227 + bool is_text() const { return mode != "rb" && mode != "wb" && mode != "ab"; } 7228 + 7229 + FileIO(VM* vm, std::string file, std::string mode): file(file), mode(mode) { 7230 + fp = fopen(file.c_str(), mode.c_str()); 7231 + if(!fp) vm->IOError(strerror(errno)); 7232 + } 7233 + 7234 + void close(){ 7235 + if(fp == nullptr) return; 7236 + fclose(fp); 7237 + fp = nullptr; 7238 + } 7239 + 7240 + static void _register(VM* vm, PyObject* mod, PyObject* type){ 7241 + vm->bind_static_method<2>(type, "__new__", [](VM* vm, ArgsView args){ 7242 + return VAR_T(FileIO, 7243 + vm, CAST(Str&, args[0]).str(), CAST(Str&, args[1]).str() 7244 + ); 7245 + }); 7246 + 7247 + vm->bind_method<0>(type, "read", [](VM* vm, ArgsView args){ 7248 + FileIO& io = CAST(FileIO&, args[0]); 7249 + fseek(io.fp, 0, SEEK_END); 7250 + std::vector<char> buffer(ftell(io.fp)); 7251 + fseek(io.fp, 0, SEEK_SET); 7252 + fread(buffer.data(), 1, buffer.size(), io.fp); 7253 + Bytes b(std::move(buffer)); 7254 + if(io.is_text()) return VAR(Str(b.str())); 7255 + return VAR(std::move(b)); 7256 + }); 7257 + 7258 + vm->bind_method<1>(type, "write", [](VM* vm, ArgsView args){ 7259 + FileIO& io = CAST(FileIO&, args[0]); 7260 + if(io.is_text()){ 7261 + Str& s = CAST(Str&, args[1]); 7262 + fwrite(s.data, 1, s.length(), io.fp); 7263 + }else{ 7264 + Bytes& buffer = CAST(Bytes&, args[1]); 7265 + fwrite(buffer.data(), 1, buffer.size(), io.fp); 7266 + } 7267 + return vm->None; 7268 + }); 7269 + 7270 + vm->bind_method<0>(type, "close", [](VM* vm, ArgsView args){ 7271 + FileIO& io = CAST(FileIO&, args[0]); 7272 + io.close(); 7273 + return vm->None; 7274 + }); 7275 + 7276 + vm->bind_method<0>(type, "__exit__", [](VM* vm, ArgsView args){ 7277 + FileIO& io = CAST(FileIO&, args[0]); 7278 + io.close(); 7279 + return vm->None; 7280 + }); 7281 + 7282 + vm->bind_method<0>(type, "__enter__", CPP_LAMBDA(vm->None)); 7283 + } 7284 + }; 7285 + 7286 + inline void add_module_io(VM* vm){ 7287 + PyObject* mod = vm->new_module("io"); 7288 + FileIO::register_class(vm, mod); 7289 + vm->bind_builtin_func<2>("open", [](VM* vm, ArgsView args){ 7290 + static StrName m_io("io"); 7291 + static StrName m_FileIO("FileIO"); 7292 + return vm->call(vm->_modules[m_io]->attr(m_FileIO), args[0], args[1]); 7293 + }); 7294 + } 7295 + 7296 + inline void add_module_os(VM* vm){ 7297 + PyObject* mod = vm->new_module("os"); 7298 + PyObject* path_obj = vm->heap.gcnew<DummyInstance>(vm->tp_object, {}); 7299 + mod->attr().set("path", path_obj); 7300 + 7301 + // Working directory is shared by all VMs!! 7302 + vm->bind_func<0>(mod, "getcwd", [](VM* vm, ArgsView args){ 7303 + return VAR(std::filesystem::current_path().string()); 7304 + }); 7305 + 7306 + vm->bind_func<1>(mod, "chdir", [](VM* vm, ArgsView args){ 7307 + std::filesystem::path path(CAST(Str&, args[0]).sv()); 7308 + std::filesystem::current_path(path); 7309 + return vm->None; 7310 + }); 7311 + 7312 + vm->bind_func<1>(mod, "listdir", [](VM* vm, ArgsView args){ 7313 + std::filesystem::path path(CAST(Str&, args[0]).sv()); 7314 + std::filesystem::directory_iterator di; 7315 + try{ 7316 + di = std::filesystem::directory_iterator(path); 7317 + }catch(std::filesystem::filesystem_error& e){ 7318 + std::string msg = e.what(); 7319 + auto pos = msg.find_last_of(":"); 7320 + if(pos != std::string::npos) msg = msg.substr(pos + 1); 7321 + vm->IOError(Str(msg).lstrip()); 7322 + } 7323 + List ret; 7324 + for(auto& p: di) ret.push_back(VAR(p.path().filename().string())); 7325 + return VAR(ret); 7326 + }); 7327 + 7328 + vm->bind_func<1>(mod, "remove", [](VM* vm, ArgsView args){ 7329 + std::filesystem::path path(CAST(Str&, args[0]).sv()); 7330 + bool ok = std::filesystem::remove(path); 7331 + if(!ok) vm->IOError("operation failed"); 7332 + return vm->None; 7333 + }); 7334 + 7335 + vm->bind_func<1>(mod, "mkdir", [](VM* vm, ArgsView args){ 7336 + std::filesystem::path path(CAST(Str&, args[0]).sv()); 7337 + bool ok = std::filesystem::create_directory(path); 7338 + if(!ok) vm->IOError("operation failed"); 7339 + return vm->None; 7340 + }); 7341 + 7342 + vm->bind_func<1>(mod, "rmdir", [](VM* vm, ArgsView args){ 7343 + std::filesystem::path path(CAST(Str&, args[0]).sv()); 7344 + bool ok = std::filesystem::remove(path); 7345 + if(!ok) vm->IOError("operation failed"); 7346 + return vm->None; 7347 + }); 7348 + 7349 + vm->bind_func<-1>(path_obj, "join", [](VM* vm, ArgsView args){ 7350 + std::filesystem::path path; 7351 + for(int i=0; i<args.size(); i++){ 7352 + path /= CAST(Str&, args[i]).sv(); 7353 + } 7354 + return VAR(path.string()); 7355 + }); 7356 + 7357 + vm->bind_func<1>(path_obj, "exists", [](VM* vm, ArgsView args){ 7358 + std::filesystem::path path(CAST(Str&, args[0]).sv()); 7359 + bool exists = std::filesystem::exists(path); 7360 + return VAR(exists); 7361 + }); 7362 + 7363 + vm->bind_func<1>(path_obj, "basename", [](VM* vm, ArgsView args){ 7364 + std::filesystem::path path(CAST(Str&, args[0]).sv()); 7365 + return VAR(path.filename().string()); 7366 + }); 7367 + } 7368 + 7369 + } // namespace pkpy 7370 + 7371 + 7372 + #else 7373 + 7374 + namespace pkpy{ 7375 + inline void add_module_io(void* vm){} 7376 + inline void add_module_os(void* vm){} 7377 + } // namespace pkpy 7378 + 7379 + #endif 7380 + 7381 + 7382 + namespace pkpy { 7383 + 7384 + inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode, bool unknown_global_scope) { 7385 + Compiler compiler(this, source, filename, mode, unknown_global_scope); 7386 + try{ 7387 + return compiler.compile(); 7388 + }catch(Exception& e){ 7389 + #if DEBUG_FULL_EXCEPTION 7390 + std::cerr << e.summary() << std::endl; 7391 + #endif 7392 + _error(e); 7393 + return nullptr; 7394 + } 7395 + } 7396 + 7397 + #define BIND_NUM_ARITH_OPT(name, op) \ 7398 + _vm->bind_method<1>("int", #name, [](VM* vm, ArgsView args){ \ 7399 + if(is_int(args[1])){ \ 7400 + return VAR(_CAST(i64, args[0]) op _CAST(i64, args[1])); \ 7401 + }else{ \ 7402 + return VAR(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \ 7403 + } \ 7404 + }); \ 7405 + _vm->bind_method<1>("float", #name, [](VM* vm, ArgsView args){ \ 7406 + return VAR(_CAST(f64, args[0]) op vm->num_to_float(args[1])); \ 7407 + }); 7408 + 7409 + 7410 + 7411 + #define BIND_NUM_LOGICAL_OPT(name, op, is_eq) \ 7412 + _vm->bind_method<1>("int", #name, [](VM* vm, ArgsView args){ \ 7413 + if(is_int(args[1])) return VAR(_CAST(i64, args[0]) op _CAST(i64, args[1])); \ 7414 + if(is_float(args[1])) return VAR(vm->num_to_float(args[0]) op _CAST(f64, args[1])); \ 7415 + if constexpr(is_eq) return VAR(args[0] op args[1]); \ 7416 + vm->TypeError("unsupported operand type(s) for " #op ); \ 7417 + return vm->None; \ 7418 + }); \ 7419 + _vm->bind_method<1>("float", #name, [](VM* vm, ArgsView args){ \ 7420 + if(is_float(args[1])) return VAR(_CAST(f64, args[0]) op _CAST(f64, args[1])); \ 7421 + if(is_int(args[1])) return VAR(_CAST(f64, args[0]) op _CAST(i64, args[1])); \ 7422 + if constexpr(is_eq) return VAR(args[0] op args[1]); \ 7423 + vm->TypeError("unsupported operand type(s) for " #op ); \ 7424 + return vm->None; \ 7425 + }); 7426 + 7427 + 7428 + inline void init_builtins(VM* _vm) { 7429 + BIND_NUM_ARITH_OPT(__add__, +) 7430 + BIND_NUM_ARITH_OPT(__sub__, -) 7431 + BIND_NUM_ARITH_OPT(__mul__, *) 7432 + 7433 + BIND_NUM_LOGICAL_OPT(__lt__, <, false) 7434 + BIND_NUM_LOGICAL_OPT(__le__, <=, false) 7435 + BIND_NUM_LOGICAL_OPT(__gt__, >, false) 7436 + BIND_NUM_LOGICAL_OPT(__ge__, >=, false) 7437 + BIND_NUM_LOGICAL_OPT(__eq__, ==, true) 7438 + BIND_NUM_LOGICAL_OPT(__ne__, !=, true) 7439 + 7440 + #undef BIND_NUM_ARITH_OPT 7441 + #undef BIND_NUM_LOGICAL_OPT 7442 + 7443 + _vm->bind_builtin_func<2>("super", [](VM* vm, ArgsView args) { 7444 + vm->check_non_tagged_type(args[0], vm->tp_type); 7445 + Type type = OBJ_GET(Type, args[0]); 7446 + if(!vm->isinstance(args[1], type)){ 7447 + Str _0 = obj_type_name(vm, OBJ_GET(Type, vm->_t(args[1]))); 7448 + Str _1 = obj_type_name(vm, type); 7449 + vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape()); 7450 + } 7451 + Type base = vm->_all_types[type].base; 7452 + return vm->heap.gcnew(vm->tp_super, Super(args[1], base)); 7453 + }); 7454 + 7455 + _vm->bind_builtin_func<2>("isinstance", [](VM* vm, ArgsView args) { 7456 + vm->check_non_tagged_type(args[1], vm->tp_type); 7457 + Type type = OBJ_GET(Type, args[1]); 7458 + return VAR(vm->isinstance(args[0], type)); 7459 + }); 7460 + 7461 + _vm->bind_builtin_func<0>("globals", [](VM* vm, ArgsView args) { 7462 + PyObject* mod = vm->top_frame()->_module; 7463 + return VAR(MappingProxy(mod)); 7464 + }); 7465 + 7466 + _vm->bind_builtin_func<1>("id", [](VM* vm, ArgsView args) { 7467 + PyObject* obj = args[0]; 7468 + if(is_tagged(obj)) return VAR((i64)0); 7469 + return VAR(BITS(obj)); 7470 + }); 7471 + 7472 + _vm->bind_builtin_func<2>("divmod", [](VM* vm, ArgsView args) { 7473 + i64 lhs = CAST(i64, args[0]); 7474 + i64 rhs = CAST(i64, args[1]); 7475 + if(rhs == 0) vm->ZeroDivisionError(); 7476 + return VAR(Tuple({VAR(lhs/rhs), VAR(lhs%rhs)})); 7477 + }); 7478 + 7479 + _vm->bind_builtin_func<1>("eval", [](VM* vm, ArgsView args) { 7480 + CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<eval>", EVAL_MODE, true); 7481 + FrameId frame = vm->top_frame(); 7482 + return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals); 7483 + }); 7484 + 7485 + _vm->bind_builtin_func<1>("exec", [](VM* vm, ArgsView args) { 7486 + CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<exec>", EXEC_MODE, true); 7487 + FrameId frame = vm->top_frame(); 7488 + vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals); 7489 + return vm->None; 7490 + }); 7491 + 7492 + _vm->bind_builtin_func<-1>("exit", [](VM* vm, ArgsView args) { 7493 + if(args.size() == 0) std::exit(0); 7494 + else if(args.size() == 1) std::exit(CAST(int, args[0])); 7495 + else vm->TypeError("exit() takes at most 1 argument"); 7496 + return vm->None; 7497 + }); 7498 + 7499 + _vm->bind_builtin_func<1>("repr", CPP_LAMBDA(vm->asRepr(args[0]))); 7500 + _vm->bind_builtin_func<1>("len", [](VM* vm, ArgsView args){ 7501 + return vm->call_method(args[0], __len__); 7502 + }); 7503 + 7504 + _vm->bind_builtin_func<1>("hash", [](VM* vm, ArgsView args){ 7505 + i64 value = vm->hash(args[0]); 7506 + if(((value << 2) >> 2) != value) value >>= 2; 7507 + return VAR(value); 7508 + }); 7509 + 7510 + _vm->bind_builtin_func<1>("chr", [](VM* vm, ArgsView args) { 7511 + i64 i = CAST(i64, args[0]); 7512 + if (i < 0 || i > 128) vm->ValueError("chr() arg not in range(128)"); 7513 + return VAR(std::string(1, (char)i)); 7514 + }); 7515 + 7516 + _vm->bind_builtin_func<1>("ord", [](VM* vm, ArgsView args) { 7517 + const Str& s = CAST(Str&, args[0]); 7518 + if (s.length()!=1) vm->TypeError("ord() expected an ASCII character"); 7519 + return VAR((i64)(s[0])); 7520 + }); 7521 + 7522 + _vm->bind_builtin_func<2>("hasattr", [](VM* vm, ArgsView args) { 7523 + return VAR(vm->getattr(args[0], CAST(Str&, args[1]), false) != nullptr); 7524 + }); 7525 + 7526 + _vm->bind_builtin_func<3>("setattr", [](VM* vm, ArgsView args) { 7527 + vm->setattr(args[0], CAST(Str&, args[1]), args[2]); 7528 + return vm->None; 7529 + }); 7530 + 7531 + _vm->bind_builtin_func<2>("getattr", [](VM* vm, ArgsView args) { 7532 + const Str& name = CAST(Str&, args[1]); 7533 + return vm->getattr(args[0], name); 7534 + }); 7535 + 7536 + _vm->bind_builtin_func<1>("hex", [](VM* vm, ArgsView args) { 7537 + std::stringstream ss; 7538 + ss << std::hex << CAST(i64, args[0]); 7539 + return VAR("0x" + ss.str()); 7540 + }); 7541 + 7542 + _vm->bind_builtin_func<1>("iter", [](VM* vm, ArgsView args) { 7543 + return vm->asIter(args[0]); 7544 + }); 7545 + 7546 + _vm->bind_builtin_func<1>("next", [](VM* vm, ArgsView args) { 7547 + return vm->PyIterNext(args[0]); 7548 + }); 7549 + 7550 + _vm->bind_builtin_func<1>("dir", [](VM* vm, ArgsView args) { 7551 + std::set<StrName> names; 7552 + if(args[0]->is_attr_valid()){ 7553 + std::vector<StrName> keys = args[0]->attr().keys(); 7554 + names.insert(keys.begin(), keys.end()); 7555 + } 7556 + const NameDict& t_attr = vm->_t(args[0])->attr(); 7557 + std::vector<StrName> keys = t_attr.keys(); 7558 + names.insert(keys.begin(), keys.end()); 7559 + List ret; 7560 + for (StrName name : names) ret.push_back(VAR(name.sv())); 7561 + return VAR(std::move(ret)); 7562 + }); 7563 + 7564 + _vm->bind_method<0>("object", "__repr__", [](VM* vm, ArgsView args) { 7565 + PyObject* self = args[0]; 7566 + if(is_tagged(self)) self = nullptr; 7567 + std::stringstream ss; 7568 + ss << "<" << OBJ_NAME(vm->_t(self)) << " object at " << std::hex << self << ">"; 7569 + return VAR(ss.str()); 7570 + }); 7571 + 7572 + _vm->bind_method<1>("object", "__eq__", CPP_LAMBDA(VAR(args[0] == args[1]))); 7573 + _vm->bind_method<1>("object", "__ne__", CPP_LAMBDA(VAR(args[0] != args[1]))); 7574 + 7575 + _vm->bind_static_method<1>("type", "__new__", CPP_LAMBDA(vm->_t(args[0]))); 7576 + _vm->bind_static_method<-1>("range", "__new__", [](VM* vm, ArgsView args) { 7577 + Range r; 7578 + switch (args.size()) { 7579 + case 1: r.stop = CAST(i64, args[0]); break; 7580 + case 2: r.start = CAST(i64, args[0]); r.stop = CAST(i64, args[1]); break; 7581 + case 3: r.start = CAST(i64, args[0]); r.stop = CAST(i64, args[1]); r.step = CAST(i64, args[2]); break; 7582 + default: vm->TypeError("expected 1-3 arguments, but got " + std::to_string(args.size())); 7583 + } 7584 + return VAR(r); 7585 + }); 7586 + 7587 + _vm->bind_method<0>("range", "__iter__", CPP_LAMBDA( 7588 + vm->PyIter(RangeIter(vm, args[0])) 7589 + )); 7590 + 7591 + _vm->bind_method<0>("NoneType", "__repr__", CPP_LAMBDA(VAR("None"))); 7592 + _vm->bind_method<0>("NoneType", "__json__", CPP_LAMBDA(VAR("null"))); 7593 + 7594 + _vm->bind_method<1>("int", "__truediv__", [](VM* vm, ArgsView args) { 7595 + f64 rhs = vm->num_to_float(args[1]); 7596 + if (rhs == 0) vm->ZeroDivisionError(); 7597 + return VAR(_CAST(i64, args[0]) / rhs); 7598 + }); 7599 + 7600 + _vm->bind_method<1>("float", "__truediv__", [](VM* vm, ArgsView args) { 7601 + f64 rhs = vm->num_to_float(args[1]); 7602 + if (rhs == 0) vm->ZeroDivisionError(); 7603 + return VAR(_CAST(f64, args[0]) / rhs); 7604 + }); 7605 + 7606 + auto py_number_pow = [](VM* vm, ArgsView args) { 7607 + if(is_both_int(args[0], args[1])){ 7608 + i64 lhs = _CAST(i64, args[0]); 7609 + i64 rhs = _CAST(i64, args[1]); 7610 + bool flag = false; 7611 + if(rhs < 0) {flag = true; rhs = -rhs;} 7612 + i64 ret = 1; 7613 + while(rhs){ 7614 + if(rhs & 1) ret *= lhs; 7615 + lhs *= lhs; 7616 + rhs >>= 1; 7617 + } 7618 + if(flag) return VAR((f64)(1.0 / ret)); 7619 + return VAR(ret); 7620 + }else{ 7621 + return VAR((f64)std::pow(vm->num_to_float(args[0]), vm->num_to_float(args[1]))); 7622 + } 7623 + }; 7624 + 7625 + _vm->bind_method<1>("int", "__pow__", py_number_pow); 7626 + _vm->bind_method<1>("float", "__pow__", py_number_pow); 7627 + 7628 + /************ PyInt ************/ 7629 + _vm->bind_static_method<1>("int", "__new__", [](VM* vm, ArgsView args) { 7630 + if (is_type(args[0], vm->tp_float)) return VAR((i64)CAST(f64, args[0])); 7631 + if (is_type(args[0], vm->tp_int)) return args[0]; 7632 + if (is_type(args[0], vm->tp_bool)) return VAR(_CAST(bool, args[0]) ? 1 : 0); 7633 + if (is_type(args[0], vm->tp_str)) { 7634 + const Str& s = CAST(Str&, args[0]); 7635 + try{ 7636 + size_t parsed = 0; 7637 + i64 val = Number::stoi(s.str(), &parsed, 10); 7638 + if(parsed != s.length()) throw std::invalid_argument("<?>"); 7639 + return VAR(val); 7640 + }catch(std::invalid_argument&){ 7641 + vm->ValueError("invalid literal for int(): " + s.escape()); 7642 + } 7643 + } 7644 + vm->TypeError("int() argument must be a int, float, bool or str"); 7645 + return vm->None; 7646 + }); 7647 + 7648 + _vm->bind_method<1>("int", "__floordiv__", [](VM* vm, ArgsView args) { 7649 + i64 rhs = CAST(i64, args[1]); 7650 + if(rhs == 0) vm->ZeroDivisionError(); 7651 + return VAR(CAST(i64, args[0]) / rhs); 7652 + }); 7653 + 7654 + _vm->bind_method<1>("int", "__mod__", [](VM* vm, ArgsView args) { 7655 + i64 rhs = CAST(i64, args[1]); 7656 + if(rhs == 0) vm->ZeroDivisionError(); 7657 + return VAR(CAST(i64, args[0]) % rhs); 7658 + }); 7659 + 7660 + _vm->bind_method<0>("int", "__repr__", CPP_LAMBDA(VAR(std::to_string(CAST(i64, args[0]))))); 7661 + _vm->bind_method<0>("int", "__json__", CPP_LAMBDA(VAR(std::to_string(CAST(i64, args[0]))))); 7662 + 7663 + #define INT_BITWISE_OP(name,op) \ 7664 + _vm->bind_method<1>("int", #name, CPP_LAMBDA(VAR(CAST(i64, args[0]) op CAST(i64, args[1])))); 7665 + 7666 + INT_BITWISE_OP(__lshift__, <<) 7667 + INT_BITWISE_OP(__rshift__, >>) 7668 + INT_BITWISE_OP(__and__, &) 7669 + INT_BITWISE_OP(__or__, |) 7670 + INT_BITWISE_OP(__xor__, ^) 7671 + 7672 + #undef INT_BITWISE_OP 7673 + 7674 + /************ PyFloat ************/ 7675 + _vm->bind_static_method<1>("float", "__new__", [](VM* vm, ArgsView args) { 7676 + if (is_type(args[0], vm->tp_int)) return VAR((f64)CAST(i64, args[0])); 7677 + if (is_type(args[0], vm->tp_float)) return args[0]; 7678 + if (is_type(args[0], vm->tp_bool)) return VAR(_CAST(bool, args[0]) ? 1.0 : 0.0); 7679 + if (is_type(args[0], vm->tp_str)) { 7680 + const Str& s = CAST(Str&, args[0]); 7681 + if(s == "inf") return VAR(INFINITY); 7682 + if(s == "-inf") return VAR(-INFINITY); 7683 + try{ 7684 + f64 val = Number::stof(s.str()); 7685 + return VAR(val); 7686 + }catch(std::invalid_argument&){ 7687 + vm->ValueError("invalid literal for float(): '" + s + "'"); 7688 + } 7689 + } 7690 + vm->TypeError("float() argument must be a int, float, bool or str"); 7691 + return vm->None; 7692 + }); 7693 + 7694 + _vm->bind_method<0>("float", "__repr__", [](VM* vm, ArgsView args) { 7695 + f64 val = CAST(f64, args[0]); 7696 + if(std::isinf(val) || std::isnan(val)) return VAR(std::to_string(val)); 7697 + std::stringstream ss; 7698 + ss << std::setprecision(std::numeric_limits<f64>::max_digits10-1-2) << val; 7699 + std::string s = ss.str(); 7700 + if(std::all_of(s.begin()+1, s.end(), isdigit)) s += ".0"; 7701 + return VAR(s); 7702 + }); 7703 + 7704 + _vm->bind_method<0>("float", "__json__", [](VM* vm, ArgsView args) { 7705 + f64 val = CAST(f64, args[0]); 7706 + if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'"); 7707 + return VAR(std::to_string(val)); 7708 + }); 7709 + 7710 + /************ PyString ************/ 7711 + _vm->bind_static_method<1>("str", "__new__", CPP_LAMBDA(vm->asStr(args[0]))); 7712 + 7713 + _vm->bind_method<1>("str", "__add__", [](VM* vm, ArgsView args) { 7714 + const Str& lhs = _CAST(Str&, args[0]); 7715 + const Str& rhs = CAST(Str&, args[1]); 7716 + return VAR(lhs + rhs); 7717 + }); 7718 + 7719 + _vm->bind_method<0>("str", "__len__", [](VM* vm, ArgsView args) { 7720 + const Str& self = _CAST(Str&, args[0]); 7721 + return VAR(self.u8_length()); 7722 + }); 7723 + 7724 + _vm->bind_method<1>("str", "__contains__", [](VM* vm, ArgsView args) { 7725 + const Str& self = _CAST(Str&, args[0]); 7726 + const Str& other = CAST(Str&, args[1]); 7727 + return VAR(self.index(other) != -1); 7728 + }); 7729 + 7730 + _vm->bind_method<0>("str", "__str__", CPP_LAMBDA(args[0])); 7731 + _vm->bind_method<0>("str", "__iter__", CPP_LAMBDA(vm->PyIter(StringIter(vm, args[0])))); 7732 + 7733 + _vm->bind_method<0>("str", "__repr__", [](VM* vm, ArgsView args) { 7734 + const Str& self = _CAST(Str&, args[0]); 7735 + return VAR(self.escape()); 7736 + }); 7737 + 7738 + _vm->bind_method<0>("str", "__json__", [](VM* vm, ArgsView args) { 7739 + const Str& self = _CAST(Str&, args[0]); 7740 + return VAR(self.escape(false)); 7741 + }); 7742 + 7743 + _vm->bind_method<1>("str", "__eq__", [](VM* vm, ArgsView args) { 7744 + const Str& self = _CAST(Str&, args[0]); 7745 + if(!is_type(args[1], vm->tp_str)) return VAR(false); 7746 + return VAR(self == CAST(Str&, args[1])); 7747 + }); 7748 + 7749 + _vm->bind_method<1>("str", "__ne__", [](VM* vm, ArgsView args) { 7750 + const Str& self = _CAST(Str&, args[0]); 7751 + if(!is_type(args[1], vm->tp_str)) return VAR(true); 7752 + return VAR(self != CAST(Str&, args[1])); 7753 + }); 7754 + 7755 + _vm->bind_method<1>("str", "__getitem__", [](VM* vm, ArgsView args) { 7756 + const Str& self = _CAST(Str&, args[0]); 7757 + 7758 + if(is_type(args[1], vm->tp_slice)){ 7759 + const Slice& s = _CAST(Slice&, args[1]); 7760 + int start, stop, step; 7761 + vm->parse_int_slice(s, self.u8_length(), start, stop, step); 7762 + return VAR(self.u8_slice(start, stop, step)); 7763 + } 7764 + 7765 + int index = CAST(int, args[1]); 7766 + index = vm->normalized_index(index, self.u8_length()); 7767 + return VAR(self.u8_getitem(index)); 7768 + }); 7769 + 7770 + _vm->bind_method<1>("str", "__gt__", [](VM* vm, ArgsView args) { 7771 + const Str& self = _CAST(Str&, args[0]); 7772 + const Str& obj = CAST(Str&, args[1]); 7773 + return VAR(self > obj); 7774 + }); 7775 + 7776 + _vm->bind_method<1>("str", "__lt__", [](VM* vm, ArgsView args) { 7777 + const Str& self = _CAST(Str&, args[0]); 7778 + const Str& obj = CAST(Str&, args[1]); 7779 + return VAR(self < obj); 7780 + }); 7781 + 7782 + _vm->bind_method<-1>("str", "replace", [](VM* vm, ArgsView args) { 7783 + if(args.size() != 1+2 && args.size() != 1+3) vm->TypeError("replace() takes 2 or 3 arguments"); 7784 + const Str& self = _CAST(Str&, args[0]); 7785 + const Str& old = CAST(Str&, args[1]); 7786 + const Str& new_ = CAST(Str&, args[2]); 7787 + int count = args.size()==1+3 ? CAST(int, args[3]) : -1; 7788 + return VAR(self.replace(old, new_, count)); 7789 + }); 7790 + 7791 + _vm->bind_method<1>("str", "index", [](VM* vm, ArgsView args) { 7792 + const Str& self = _CAST(Str&, args[0]); 7793 + const Str& sub = CAST(Str&, args[1]); 7794 + int index = self.index(sub); 7795 + if(index == -1) vm->ValueError("substring not found"); 7796 + return VAR(index); 7797 + }); 7798 + 7799 + _vm->bind_method<1>("str", "startswith", [](VM* vm, ArgsView args) { 7800 + const Str& self = _CAST(Str&, args[0]); 7801 + const Str& prefix = CAST(Str&, args[1]); 7802 + return VAR(self.index(prefix) == 0); 7803 + }); 7804 + 7805 + _vm->bind_method<1>("str", "endswith", [](VM* vm, ArgsView args) { 7806 + const Str& self = _CAST(Str&, args[0]); 7807 + const Str& suffix = CAST(Str&, args[1]); 7808 + int offset = self.length() - suffix.length(); 7809 + if(offset < 0) return vm->False; 7810 + bool ok = memcmp(self.data+offset, suffix.data, suffix.length()) == 0; 7811 + return VAR(ok); 7812 + }); 7813 + 7814 + _vm->bind_method<0>("str", "encode", [](VM* vm, ArgsView args) { 7815 + const Str& self = _CAST(Str&, args[0]); 7816 + std::vector<char> buffer(self.length()); 7817 + memcpy(buffer.data(), self.data, self.length()); 7818 + return VAR(Bytes(std::move(buffer))); 7819 + }); 7820 + 7821 + _vm->bind_method<1>("str", "join", [](VM* vm, ArgsView args) { 7822 + const Str& self = _CAST(Str&, args[0]); 7823 + FastStrStream ss; 7824 + PyObject* obj = vm->asList(args[1]); 7825 + const List& list = CAST(List&, obj); 7826 + for (int i = 0; i < list.size(); ++i) { 7827 + if (i > 0) ss << self; 7828 + ss << CAST(Str&, list[i]); 7829 + } 7830 + return VAR(ss.str()); 7831 + }); 7832 + 7833 + /************ PyList ************/ 7834 + _vm->bind_method<1>("list", "append", [](VM* vm, ArgsView args) { 7835 + List& self = _CAST(List&, args[0]); 7836 + self.push_back(args[1]); 7837 + return vm->None; 7838 + }); 7839 + 7840 + _vm->bind_method<1>("list", "extend", [](VM* vm, ArgsView args) { 7841 + List& self = _CAST(List&, args[0]); 7842 + PyObject* obj = vm->asList(args[1]); 7843 + const List& list = CAST(List&, obj); 7844 + self.extend(list); 7845 + return vm->None; 7846 + }); 7847 + 7848 + _vm->bind_method<0>("list", "reverse", [](VM* vm, ArgsView args) { 7849 + List& self = _CAST(List&, args[0]); 7850 + std::reverse(self.begin(), self.end()); 7851 + return vm->None; 7852 + }); 7853 + 7854 + _vm->bind_method<1>("list", "__mul__", [](VM* vm, ArgsView args) { 7855 + const List& self = _CAST(List&, args[0]); 7856 + int n = CAST(int, args[1]); 7857 + List result; 7858 + result.reserve(self.size() * n); 7859 + for(int i = 0; i < n; i++) result.extend(self); 7860 + return VAR(std::move(result)); 7861 + }); 7862 + 7863 + _vm->bind_method<2>("list", "insert", [](VM* vm, ArgsView args) { 7864 + List& self = _CAST(List&, args[0]); 7865 + int index = CAST(int, args[1]); 7866 + if(index < 0) index += self.size(); 7867 + if(index < 0) index = 0; 7868 + if(index > self.size()) index = self.size(); 7869 + self.insert(index, args[2]); 7870 + return vm->None; 7871 + }); 7872 + 7873 + _vm->bind_method<0>("list", "clear", [](VM* vm, ArgsView args) { 7874 + _CAST(List&, args[0]).clear(); 7875 + return vm->None; 7876 + }); 7877 + 7878 + _vm->bind_method<0>("list", "copy", CPP_LAMBDA(VAR(_CAST(List, args[0])))); 7879 + 7880 + _vm->bind_method<1>("list", "__add__", [](VM* vm, ArgsView args) { 7881 + const List& self = _CAST(List&, args[0]); 7882 + const List& other = CAST(List&, args[1]); 7883 + List new_list(self); // copy construct 7884 + new_list.extend(other); 7885 + return VAR(std::move(new_list)); 7886 + }); 7887 + 7888 + _vm->bind_method<0>("list", "__len__", [](VM* vm, ArgsView args) { 7889 + const List& self = _CAST(List&, args[0]); 7890 + return VAR(self.size()); 7891 + }); 7892 + 7893 + _vm->bind_method<0>("list", "__iter__", [](VM* vm, ArgsView args) { 7894 + return vm->PyIter(ArrayIter<List>(vm, args[0])); 7895 + }); 7896 + 7897 + _vm->bind_method<1>("list", "__getitem__", [](VM* vm, ArgsView args) { 7898 + const List& self = _CAST(List&, args[0]); 7899 + 7900 + if(is_type(args[1], vm->tp_slice)){ 7901 + const Slice& s = _CAST(Slice&, args[1]); 7902 + int start, stop, step; 7903 + vm->parse_int_slice(s, self.size(), start, stop, step); 7904 + List new_list; 7905 + for(int i=start; step>0?i<stop:i>stop; i+=step) new_list.push_back(self[i]); 7906 + return VAR(std::move(new_list)); 7907 + } 7908 + 7909 + int index = CAST(int, args[1]); 7910 + index = vm->normalized_index(index, self.size()); 7911 + return self[index]; 7912 + }); 7913 + 7914 + _vm->bind_method<2>("list", "__setitem__", [](VM* vm, ArgsView args) { 7915 + List& self = _CAST(List&, args[0]); 7916 + int index = CAST(int, args[1]); 7917 + index = vm->normalized_index(index, self.size()); 7918 + self[index] = args[2]; 7919 + return vm->None; 7920 + }); 7921 + 7922 + _vm->bind_method<1>("list", "__delitem__", [](VM* vm, ArgsView args) { 7923 + List& self = _CAST(List&, args[0]); 7924 + int index = CAST(int, args[1]); 7925 + index = vm->normalized_index(index, self.size()); 7926 + self.erase(index); 7927 + return vm->None; 7928 + }); 7929 + 7930 + /************ PyTuple ************/ 7931 + _vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, ArgsView args) { 7932 + List list = CAST(List, vm->asList(args[0])); 7933 + return VAR(Tuple(std::move(list))); 7934 + }); 7935 + 7936 + _vm->bind_method<0>("tuple", "__iter__", [](VM* vm, ArgsView args) { 7937 + return vm->PyIter(ArrayIter<Tuple>(vm, args[0])); 7938 + }); 7939 + 7940 + _vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, ArgsView args) { 7941 + const Tuple& self = _CAST(Tuple&, args[0]); 7942 + 7943 + if(is_type(args[1], vm->tp_slice)){ 7944 + const Slice& s = _CAST(Slice&, args[1]); 7945 + int start, stop, step; 7946 + vm->parse_int_slice(s, self.size(), start, stop, step); 7947 + List new_list; 7948 + for(int i=start; step>0?i<stop:i>stop; i+=step) new_list.push_back(self[i]); 7949 + return VAR(Tuple(std::move(new_list))); 7950 + } 7951 + 7952 + int index = CAST(int, args[1]); 7953 + index = vm->normalized_index(index, self.size()); 7954 + return self[index]; 7955 + }); 7956 + 7957 + _vm->bind_method<0>("tuple", "__len__", [](VM* vm, ArgsView args) { 7958 + const Tuple& self = _CAST(Tuple&, args[0]); 7959 + return VAR(self.size()); 7960 + }); 7961 + 7962 + /************ bool ************/ 7963 + _vm->bind_static_method<1>("bool", "__new__", CPP_LAMBDA(VAR(vm->asBool(args[0])))); 7964 + 7965 + _vm->bind_method<0>("bool", "__repr__", [](VM* vm, ArgsView args) { 7966 + bool val = _CAST(bool, args[0]); 7967 + return VAR(val ? "True" : "False"); 7968 + }); 7969 + 7970 + _vm->bind_method<0>("bool", "__json__", [](VM* vm, ArgsView args) { 7971 + bool val = _CAST(bool, args[0]); 7972 + return VAR(val ? "true" : "false"); 7973 + }); 7974 + 7975 + _vm->bind_method<1>("bool", "__xor__", [](VM* vm, ArgsView args) { 7976 + bool self = _CAST(bool, args[0]); 7977 + bool other = CAST(bool, args[1]); 7978 + return VAR(self ^ other); 7979 + }); 7980 + 7981 + _vm->bind_method<0>("ellipsis", "__repr__", CPP_LAMBDA(VAR("Ellipsis"))); 7982 + 7983 + /************ bytes ************/ 7984 + _vm->bind_static_method<1>("bytes", "__new__", [](VM* vm, ArgsView args){ 7985 + List& list = CAST(List&, args[0]); 7986 + std::vector<char> buffer(list.size()); 7987 + for(int i=0; i<list.size(); i++){ 7988 + i64 b = CAST(i64, list[i]); 7989 + if(b<0 || b>255) vm->ValueError("byte must be in range[0, 256)"); 7990 + buffer[i] = (char)b; 7991 + } 7992 + return VAR(Bytes(std::move(buffer))); 7993 + }); 7994 + 7995 + _vm->bind_method<1>("bytes", "__getitem__", [](VM* vm, ArgsView args) { 7996 + const Bytes& self = _CAST(Bytes&, args[0]); 7997 + int index = CAST(int, args[1]); 7998 + index = vm->normalized_index(index, self.size()); 7999 + return VAR(self[index]); 8000 + }); 8001 + 8002 + _vm->bind_method<0>("bytes", "__repr__", [](VM* vm, ArgsView args) { 8003 + const Bytes& self = _CAST(Bytes&, args[0]); 8004 + std::stringstream ss; 8005 + ss << "b'"; 8006 + for(int i=0; i<self.size(); i++){ 8007 + ss << "\\x" << std::hex << std::setw(2) << std::setfill('0') << self[i]; 8008 + } 8009 + ss << "'"; 8010 + return VAR(ss.str()); 8011 + }); 8012 + 8013 + _vm->bind_method<0>("bytes", "__len__", [](VM* vm, ArgsView args) { 8014 + const Bytes& self = _CAST(Bytes&, args[0]); 8015 + return VAR(self.size()); 8016 + }); 8017 + 8018 + _vm->bind_method<0>("bytes", "decode", [](VM* vm, ArgsView args) { 8019 + const Bytes& self = _CAST(Bytes&, args[0]); 8020 + // TODO: check encoding is utf-8 8021 + return VAR(Str(self.str())); 8022 + }); 8023 + 8024 + _vm->bind_method<1>("bytes", "__eq__", [](VM* vm, ArgsView args) { 8025 + const Bytes& self = _CAST(Bytes&, args[0]); 8026 + if(!is_type(args[1], vm->tp_bytes)) return VAR(false); 8027 + const Bytes& other = CAST(Bytes&, args[1]); 8028 + return VAR(self == other); 8029 + }); 8030 + 8031 + _vm->bind_method<1>("bytes", "__ne__", [](VM* vm, ArgsView args) { 8032 + const Bytes& self = _CAST(Bytes&, args[0]); 8033 + if(!is_type(args[1], vm->tp_bytes)) return VAR(true); 8034 + const Bytes& other = CAST(Bytes&, args[1]); 8035 + return VAR(self != other); 8036 + }); 8037 + 8038 + /************ slice ************/ 8039 + _vm->bind_static_method<3>("slice", "__new__", [](VM* vm, ArgsView args) { 8040 + return VAR(Slice(args[0], args[1], args[2])); 8041 + }); 8042 + 8043 + _vm->bind_method<0>("slice", "__repr__", [](VM* vm, ArgsView args) { 8044 + const Slice& self = _CAST(Slice&, args[0]); 8045 + std::stringstream ss; 8046 + ss << "slice("; 8047 + ss << CAST(Str, vm->asRepr(self.start)) << ", "; 8048 + ss << CAST(Str, vm->asRepr(self.stop)) << ", "; 8049 + ss << CAST(Str, vm->asRepr(self.step)) << ")"; 8050 + return VAR(ss.str()); 8051 + }); 8052 + 8053 + /************ MappingProxy ************/ 8054 + _vm->bind_method<0>("mappingproxy", "keys", [](VM* vm, ArgsView args) { 8055 + MappingProxy& self = _CAST(MappingProxy&, args[0]); 8056 + List keys; 8057 + for(StrName name : self.attr().keys()) keys.push_back(VAR(name.sv())); 8058 + return VAR(std::move(keys)); 8059 + }); 8060 + 8061 + _vm->bind_method<0>("mappingproxy", "values", [](VM* vm, ArgsView args) { 8062 + MappingProxy& self = _CAST(MappingProxy&, args[0]); 8063 + List values; 8064 + for(auto& item : self.attr().items()) values.push_back(item.second); 8065 + return VAR(std::move(values)); 8066 + }); 8067 + 8068 + _vm->bind_method<0>("mappingproxy", "items", [](VM* vm, ArgsView args) { 8069 + MappingProxy& self = _CAST(MappingProxy&, args[0]); 8070 + List items; 8071 + for(auto& item : self.attr().items()){ 8072 + PyObject* t = VAR(Tuple({VAR(item.first.sv()), item.second})); 8073 + items.push_back(std::move(t)); 8074 + } 8075 + return VAR(std::move(items)); 8076 + }); 8077 + 8078 + _vm->bind_method<0>("mappingproxy", "__len__", [](VM* vm, ArgsView args) { 8079 + MappingProxy& self = _CAST(MappingProxy&, args[0]); 8080 + return VAR(self.attr().size()); 8081 + }); 8082 + 8083 + _vm->bind_method<1>("mappingproxy", "__getitem__", [](VM* vm, ArgsView args) { 8084 + MappingProxy& self = _CAST(MappingProxy&, args[0]); 8085 + StrName key = CAST(Str&, args[1]); 8086 + PyObject* ret = self.attr().try_get(key); 8087 + if(ret == nullptr) vm->AttributeError(key.sv()); 8088 + return ret; 8089 + }); 8090 + 8091 + _vm->bind_method<0>("mappingproxy", "__repr__", [](VM* vm, ArgsView args) { 8092 + MappingProxy& self = _CAST(MappingProxy&, args[0]); 8093 + std::stringstream ss; 8094 + ss << "mappingproxy({"; 8095 + bool first = true; 8096 + for(auto& item : self.attr().items()){ 8097 + if(!first) ss << ", "; 8098 + first = false; 8099 + ss << item.first.escape() << ": " << CAST(Str, vm->asRepr(item.second)); 8100 + } 8101 + ss << "})"; 8102 + return VAR(ss.str()); 8103 + }); 8104 + 8105 + _vm->bind_method<1>("mappingproxy", "__contains__", [](VM* vm, ArgsView args) { 8106 + MappingProxy& self = _CAST(MappingProxy&, args[0]); 8107 + StrName key = CAST(Str&, args[1]); 8108 + return VAR(self.attr().contains(key)); 8109 + }); 8110 + } 8111 + 8112 + #ifdef _WIN32 8113 + #define __EXPORT __declspec(dllexport) inline 8114 + #elif __APPLE__ 8115 + #define __EXPORT __attribute__((visibility("default"))) __attribute__((used)) inline 8116 + #elif __EMSCRIPTEN__ 8117 + #include <emscripten.h> 8118 + #define __EXPORT EMSCRIPTEN_KEEPALIVE inline 8119 + #else 8120 + #define __EXPORT inline 8121 + #endif 8122 + 8123 + inline void add_module_time(VM* vm){ 8124 + PyObject* mod = vm->new_module("time"); 8125 + vm->bind_func<0>(mod, "time", [](VM* vm, ArgsView args) { 8126 + auto now = std::chrono::high_resolution_clock::now(); 8127 + return VAR(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0); 8128 + }); 8129 + } 8130 + 8131 + inline void add_module_sys(VM* vm){ 8132 + PyObject* mod = vm->new_module("sys"); 8133 + vm->setattr(mod, "version", VAR(PK_VERSION)); 8134 + 8135 + PyObject* stdout_ = vm->heap.gcnew<DummyInstance>(vm->tp_object, {}); 8136 + PyObject* stderr_ = vm->heap.gcnew<DummyInstance>(vm->tp_object, {}); 8137 + vm->setattr(mod, "stdout", stdout_); 8138 + vm->setattr(mod, "stderr", stderr_); 8139 + 8140 + vm->bind_func<1>(stdout_, "write", [](VM* vm, ArgsView args) { 8141 + vm->_stdout(vm, CAST(Str&, args[0])); 8142 + return vm->None; 8143 + }); 8144 + 8145 + vm->bind_func<1>(stderr_, "write", [](VM* vm, ArgsView args) { 8146 + vm->_stderr(vm, CAST(Str&, args[0])); 8147 + return vm->None; 8148 + }); 8149 + } 8150 + 8151 + inline void add_module_json(VM* vm){ 8152 + PyObject* mod = vm->new_module("json"); 8153 + vm->bind_func<1>(mod, "loads", [](VM* vm, ArgsView args) { 8154 + const Str& expr = CAST(Str&, args[0]); 8155 + CodeObject_ code = vm->compile(expr, "<json>", JSON_MODE); 8156 + return vm->_exec(code, vm->top_frame()->_module); 8157 + }); 8158 + 8159 + vm->bind_func<1>(mod, "dumps", CPP_LAMBDA(vm->call_method(args[0], __json__))); 8160 + } 8161 + 8162 + inline void add_module_math(VM* vm){ 8163 + PyObject* mod = vm->new_module("math"); 8164 + mod->attr().set("pi", VAR(3.1415926535897932384)); 8165 + mod->attr().set("e" , VAR(2.7182818284590452354)); 8166 + 8167 + vm->bind_func<1>(mod, "log", CPP_LAMBDA(VAR(std::log(vm->num_to_float(args[0]))))); 8168 + vm->bind_func<1>(mod, "log10", CPP_LAMBDA(VAR(std::log10(vm->num_to_float(args[0]))))); 8169 + vm->bind_func<1>(mod, "log2", CPP_LAMBDA(VAR(std::log2(vm->num_to_float(args[0]))))); 8170 + vm->bind_func<1>(mod, "sin", CPP_LAMBDA(VAR(std::sin(vm->num_to_float(args[0]))))); 8171 + vm->bind_func<1>(mod, "cos", CPP_LAMBDA(VAR(std::cos(vm->num_to_float(args[0]))))); 8172 + vm->bind_func<1>(mod, "tan", CPP_LAMBDA(VAR(std::tan(vm->num_to_float(args[0]))))); 8173 + vm->bind_func<1>(mod, "isnan", CPP_LAMBDA(VAR(std::isnan(vm->num_to_float(args[0]))))); 8174 + vm->bind_func<1>(mod, "isinf", CPP_LAMBDA(VAR(std::isinf(vm->num_to_float(args[0]))))); 8175 + vm->bind_func<1>(mod, "fabs", CPP_LAMBDA(VAR(std::fabs(vm->num_to_float(args[0]))))); 8176 + vm->bind_func<1>(mod, "floor", CPP_LAMBDA(VAR((i64)std::floor(vm->num_to_float(args[0]))))); 8177 + vm->bind_func<1>(mod, "ceil", CPP_LAMBDA(VAR((i64)std::ceil(vm->num_to_float(args[0]))))); 8178 + vm->bind_func<1>(mod, "sqrt", CPP_LAMBDA(VAR(std::sqrt(vm->num_to_float(args[0]))))); 8179 + vm->bind_func<2>(mod, "gcd", [](VM* vm, ArgsView args) { 8180 + i64 a = CAST(i64, args[0]); 8181 + i64 b = CAST(i64, args[1]); 8182 + if(a < 0) a = -a; 8183 + if(b < 0) b = -b; 8184 + while(b != 0){ 8185 + i64 t = b; 8186 + b = a % b; 8187 + a = t; 8188 + } 8189 + return VAR(a); 8190 + }); 8191 + } 8192 + 8193 + inline void add_module_dis(VM* vm){ 8194 + PyObject* mod = vm->new_module("dis"); 8195 + vm->bind_func<1>(mod, "dis", [](VM* vm, ArgsView args) { 8196 + PyObject* f = args[0]; 8197 + if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, args[0]).func; 8198 + CodeObject_ code = CAST(Function&, f).decl->code; 8199 + vm->_stdout(vm, vm->disassemble(code)); 8200 + return vm->None; 8201 + }); 8202 + } 8203 + 8204 + struct ReMatch { 8205 + PY_CLASS(ReMatch, re, Match) 8206 + 8207 + i64 start; 8208 + i64 end; 8209 + std::cmatch m; 8210 + ReMatch(i64 start, i64 end, std::cmatch m) : start(start), end(end), m(m) {} 8211 + 8212 + static void _register(VM* vm, PyObject* mod, PyObject* type){ 8213 + vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED()); 8214 + vm->bind_method<0>(type, "start", CPP_LAMBDA(VAR(_CAST(ReMatch&, args[0]).start))); 8215 + vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(_CAST(ReMatch&, args[0]).end))); 8216 + 8217 + vm->bind_method<0>(type, "span", [](VM* vm, ArgsView args) { 8218 + auto& self = _CAST(ReMatch&, args[0]); 8219 + return VAR(Tuple({VAR(self.start), VAR(self.end)})); 8220 + }); 8221 + 8222 + vm->bind_method<1>(type, "group", [](VM* vm, ArgsView args) { 8223 + auto& self = _CAST(ReMatch&, args[0]); 8224 + int index = CAST(int, args[1]); 8225 + index = vm->normalized_index(index, self.m.size()); 8226 + return VAR(self.m[index].str()); 8227 + }); 8228 + } 8229 + }; 8230 + 8231 + inline PyObject* _regex_search(const Str& pattern, const Str& string, bool from_start, VM* vm){ 8232 + std::regex re(pattern.begin(), pattern.end()); 8233 + std::cmatch m; 8234 + if(std::regex_search(string.begin(), string.end(), m, re)){ 8235 + if(from_start && m.position() != 0) return vm->None; 8236 + i64 start = string._byte_index_to_unicode(m.position()); 8237 + i64 end = string._byte_index_to_unicode(m.position() + m.length()); 8238 + return VAR_T(ReMatch, start, end, m); 8239 + } 8240 + return vm->None; 8241 + }; 8242 + 8243 + inline void add_module_re(VM* vm){ 8244 + PyObject* mod = vm->new_module("re"); 8245 + ReMatch::register_class(vm, mod); 8246 + 8247 + vm->bind_func<2>(mod, "match", [](VM* vm, ArgsView args) { 8248 + const Str& pattern = CAST(Str&, args[0]); 8249 + const Str& string = CAST(Str&, args[1]); 8250 + return _regex_search(pattern, string, true, vm); 8251 + }); 8252 + 8253 + vm->bind_func<2>(mod, "search", [](VM* vm, ArgsView args) { 8254 + const Str& pattern = CAST(Str&, args[0]); 8255 + const Str& string = CAST(Str&, args[1]); 8256 + return _regex_search(pattern, string, false, vm); 8257 + }); 8258 + 8259 + vm->bind_func<3>(mod, "sub", [](VM* vm, ArgsView args) { 8260 + const Str& pattern = CAST(Str&, args[0]); 8261 + const Str& repl = CAST(Str&, args[1]); 8262 + const Str& string = CAST(Str&, args[2]); 8263 + std::regex re(pattern.begin(), pattern.end()); 8264 + return VAR(std::regex_replace(string.str(), re, repl.str())); 8265 + }); 8266 + 8267 + vm->bind_func<2>(mod, "split", [](VM* vm, ArgsView args) { 8268 + const Str& pattern = CAST(Str&, args[0]); 8269 + const Str& string = CAST(Str&, args[1]); 8270 + std::regex re(pattern.begin(), pattern.end()); 8271 + std::cregex_token_iterator it(string.begin(), string.end(), re, -1); 8272 + std::cregex_token_iterator end; 8273 + List vec; 8274 + for(; it != end; ++it){ 8275 + vec.push_back(VAR(it->str())); 8276 + } 8277 + return VAR(vec); 8278 + }); 8279 + } 8280 + 8281 + struct Random{ 8282 + PY_CLASS(Random, random, Random) 8283 + std::mt19937 gen; 8284 + 8285 + Random(){ 8286 + gen.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count()); 8287 + } 8288 + 8289 + static void _register(VM* vm, PyObject* mod, PyObject* type){ 8290 + vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random))); 8291 + 8292 + vm->bind_method<1>(type, "seed", [](VM* vm, ArgsView args) { 8293 + Random& self = _CAST(Random&, args[0]); 8294 + self.gen.seed(CAST(i64, args[1])); 8295 + return vm->None; 8296 + }); 8297 + 8298 + vm->bind_method<2>(type, "randint", [](VM* vm, ArgsView args) { 8299 + Random& self = _CAST(Random&, args[0]); 8300 + i64 a = CAST(i64, args[1]); 8301 + i64 b = CAST(i64, args[2]); 8302 + std::uniform_int_distribution<i64> dis(a, b); 8303 + return VAR(dis(self.gen)); 8304 + }); 8305 + 8306 + vm->bind_method<0>(type, "random", [](VM* vm, ArgsView args) { 8307 + Random& self = _CAST(Random&, args[0]); 8308 + std::uniform_real_distribution<f64> dis(0.0, 1.0); 8309 + return VAR(dis(self.gen)); 8310 + }); 8311 + 8312 + vm->bind_method<2>(type, "uniform", [](VM* vm, ArgsView args) { 8313 + Random& self = _CAST(Random&, args[0]); 8314 + f64 a = CAST(f64, args[1]); 8315 + f64 b = CAST(f64, args[2]); 8316 + std::uniform_real_distribution<f64> dis(a, b); 8317 + return VAR(dis(self.gen)); 8318 + }); 8319 + } 8320 + }; 8321 + 8322 + inline void add_module_random(VM* vm){ 8323 + PyObject* mod = vm->new_module("random"); 8324 + Random::register_class(vm, mod); 8325 + CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE); 8326 + vm->_exec(code, mod); 8327 + } 8328 + 8329 + inline void add_module_gc(VM* vm){ 8330 + PyObject* mod = vm->new_module("gc"); 8331 + vm->bind_func<0>(mod, "collect", CPP_LAMBDA(VAR(vm->heap.collect()))); 8332 + } 8333 + 8334 + inline void VM::post_init(){ 8335 + init_builtins(this); 8336 + #if !DEBUG_NO_BUILTIN_MODULES 8337 + add_module_sys(this); 8338 + add_module_time(this); 8339 + add_module_json(this); 8340 + add_module_math(this); 8341 + add_module_re(this); 8342 + add_module_dis(this); 8343 + add_module_c(this); 8344 + add_module_gc(this); 8345 + add_module_random(this); 8346 + add_module_base64(this); 8347 + 8348 + for(const char* name: {"this", "functools", "collections", "heapq", "bisect"}){ 8349 + _lazy_modules[name] = kPythonLibs[name]; 8350 + } 8351 + 8352 + CodeObject_ code = compile(kPythonLibs["builtins"], "<builtins>", EXEC_MODE); 8353 + this->_exec(code, this->builtins); 8354 + code = compile(kPythonLibs["_dict"], "<dict>", EXEC_MODE); 8355 + this->_exec(code, this->builtins); 8356 + code = compile(kPythonLibs["_set"], "<set>", EXEC_MODE); 8357 + this->_exec(code, this->builtins); 8358 + 8359 + // property is defined in builtins.py so we need to add it after builtins is loaded 8360 + _t(tp_object)->attr().set(__class__, property(CPP_LAMBDA(vm->_t(args[0])))); 8361 + _t(tp_type)->attr().set(__base__, property([](VM* vm, ArgsView args){ 8362 + const PyTypeInfo& info = vm->_all_types[OBJ_GET(Type, args[0])]; 8363 + return info.base.index == -1 ? vm->None : vm->_all_types[info.base].obj; 8364 + })); 8365 + _t(tp_type)->attr().set(__name__, property([](VM* vm, ArgsView args){ 8366 + const PyTypeInfo& info = vm->_all_types[OBJ_GET(Type, args[0])]; 8367 + return VAR(info.name); 8368 + })); 8369 + 8370 + _t(tp_bound_method)->attr().set("__self__", property([](VM* vm, ArgsView args){ 8371 + return CAST(BoundMethod&, args[0]).self; 8372 + })); 8373 + _t(tp_bound_method)->attr().set("__func__", property([](VM* vm, ArgsView args){ 8374 + return CAST(BoundMethod&, args[0]).func; 8375 + })); 8376 + 8377 + vm->bind_method<1>(_t(tp_bound_method), "__eq__", [](VM* vm, ArgsView args){ 8378 + if(!is_non_tagged_type(args[1], vm->tp_bound_method)) return vm->False; 8379 + bool ok = _CAST(BoundMethod&, args[0]) == _CAST(BoundMethod&, args[1]); 8380 + return VAR(ok); 8381 + }); 8382 + 8383 + vm->bind_method<1>(_t(tp_bound_method), "__ne__", [](VM* vm, ArgsView args){ 8384 + if(!is_non_tagged_type(args[1], vm->tp_bound_method)) return vm->True; 8385 + bool ok = _CAST(BoundMethod&, args[0]) != _CAST(BoundMethod&, args[1]); 8386 + return VAR(ok); 8387 + }); 8388 + 8389 + _t(tp_slice)->attr().set("start", property([](VM* vm, ArgsView args){ 8390 + return CAST(Slice&, args[0]).start; 8391 + })); 8392 + _t(tp_slice)->attr().set("stop", property([](VM* vm, ArgsView args){ 8393 + return CAST(Slice&, args[0]).stop; 8394 + })); 8395 + _t(tp_slice)->attr().set("step", property([](VM* vm, ArgsView args){ 8396 + return CAST(Slice&, args[0]).step; 8397 + })); 8398 + _t(tp_object)->attr().set("__dict__", property([](VM* vm, ArgsView args){ 8399 + if(is_tagged(args[0]) || !args[0]->is_attr_valid()){ 8400 + vm->AttributeError("__dict__"); 8401 + } 8402 + return VAR(MappingProxy(args[0])); 8403 + })); 8404 + 8405 + if(enable_os){ 8406 + add_module_io(this); 8407 + add_module_os(this); 8408 + add_module_requests(this); 8409 + } 8410 + #endif 8411 + } 8412 + 8413 + } // namespace pkpy 8414 + 8415 + /*************************GLOBAL NAMESPACE*************************/ 8416 + static std::map<void*, void(*)(void*)> _pk_deleter_map; 8417 + 8418 + extern "C" { 8419 + __EXPORT 8420 + void pkpy_delete(void* p){ 8421 + auto it = _pk_deleter_map.find(p); 8422 + if(it != _pk_deleter_map.end()){ 8423 + it->second(p); 8424 + }else{ 8425 + free(p); 8426 + } 8427 + } 8428 + 8429 + __EXPORT 8430 + void pkpy_vm_exec(pkpy::VM* vm, const char* source){ 8431 + vm->exec(source, "main.py", pkpy::EXEC_MODE); 8432 + } 8433 + 8434 + __EXPORT 8435 + char* pkpy_vm_get_global(pkpy::VM* vm, const char* name){ 8436 + pkpy::PyObject* val = vm->_main->attr().try_get(name); 8437 + if(val == nullptr) return nullptr; 8438 + try{ 8439 + pkpy::Str repr = pkpy::CAST(pkpy::Str&, vm->asRepr(val)); 8440 + return repr.c_str_dup(); 8441 + }catch(...){ 8442 + return nullptr; 8443 + } 8444 + } 8445 + 8446 + __EXPORT 8447 + char* pkpy_vm_eval(pkpy::VM* vm, const char* source){ 8448 + pkpy::PyObject* ret = vm->exec(source, "<eval>", pkpy::EVAL_MODE); 8449 + if(ret == nullptr) return nullptr; 8450 + try{ 8451 + pkpy::Str repr = pkpy::CAST(pkpy::Str&, vm->asRepr(ret)); 8452 + return repr.c_str_dup(); 8453 + }catch(...){ 8454 + return nullptr; 8455 + } 8456 + } 8457 + 8458 + __EXPORT 8459 + pkpy::REPL* pkpy_new_repl(pkpy::VM* vm){ 8460 + pkpy::REPL* p = new pkpy::REPL(vm); 8461 + _pk_deleter_map[p] = [](void* p){ delete (pkpy::REPL*)p; }; 8462 + return p; 8463 + } 8464 + 8465 + __EXPORT 8466 + bool pkpy_repl_input(pkpy::REPL* r, const char* line){ 8467 + return r->input(line); 8468 + } 8469 + 8470 + __EXPORT 8471 + void pkpy_vm_add_module(pkpy::VM* vm, const char* name, const char* source){ 8472 + vm->_lazy_modules[name] = source; 8473 + } 8474 + 8475 + __EXPORT 8476 + pkpy::VM* pkpy_new_vm(bool enable_os=true){ 8477 + pkpy::VM* p = new pkpy::VM(enable_os); 8478 + _pk_deleter_map[p] = [](void* p){ delete (pkpy::VM*)p; }; 8479 + return p; 8480 + } 8481 + } 8482 + 8483 + #endif // POCKETPY_H
+578
vendor/pocketpy/pocketpy_c.cpp
··· 1 + #include "pocketpy.h" 2 + #include "pocketpy_c.h" 3 + 4 + using namespace pkpy; 5 + 6 + #define PKPY_STACK_SIZE 32 7 + 8 + #define SAFEGUARD_OPEN try { \ 9 + 10 + #define SAFEGUARD_CLOSE \ 11 + } catch(std::exception& e) { \ 12 + std::cerr << "ERROR: a std::exception " \ 13 + << "this probably means pocketpy itself has a bug!\n" \ 14 + << e.what() << "\n"; \ 15 + exit(2); \ 16 + } catch(...) { \ 17 + std::cerr << "ERROR: a unknown exception was thrown from " << __func__ \ 18 + << "\nthis probably means pocketpy itself has a bug!\n"; \ 19 + exit(2); \ 20 + } 21 + 22 + 23 + #define ERRHANDLER_OPEN SAFEGUARD_OPEN \ 24 + try { \ 25 + if (vm->c_data->size() > 0 && vm->c_data->top() == nullptr) \ 26 + return false; \ 27 + 28 + #define ERRHANDLER_CLOSE \ 29 + } catch( Exception e ) { \ 30 + vm->c_data->push(py_var(vm, e)); \ 31 + vm->c_data->push(NULL); \ 32 + return false; \ 33 + } \ 34 + SAFEGUARD_CLOSE \ 35 + 36 + 37 + 38 + class CVM : public VM { 39 + public : 40 + 41 + ValueStackImpl<PKPY_STACK_SIZE>* c_data; 42 + CVM(bool enable_os=true) : VM(enable_os) { 43 + c_data = new ValueStackImpl<PKPY_STACK_SIZE>(); 44 + } 45 + 46 + ~CVM() { 47 + c_data->clear(); 48 + delete c_data; 49 + } 50 + }; 51 + 52 + 53 + //for now I will unpack a tuple automatically, we may not want to handle 54 + //it this way, not sure 55 + //it is more lua like, but maybe not python like 56 + static void unpack_return(CVM* vm, PyObject* ret) { 57 + if (is_type(ret, vm->tp_tuple)) { 58 + Tuple& t = py_cast<Tuple&>(vm, ret); 59 + for (int i = 0; i < t.size(); i++) 60 + vm->c_data->push(t[i]); 61 + } else if (ret == vm->None) { 62 + //do nothing here 63 + //having to pop the stack after every call that returns none is annoying 64 + //lua does not do this 65 + // 66 + //so for now we will not push none on the stack when it is the sole thing returned 67 + //if this becomes a problem we can change it 68 + // 69 + //you can still check if it returned none by comparing stack size before 70 + //and after if you have to 71 + } else 72 + vm->c_data->push(ret); 73 + 74 + } 75 + 76 + 77 + bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) { 78 + CVM* vm = (CVM*) vm_handle; 79 + SAFEGUARD_OPEN 80 + 81 + if (vm->c_data->size() == 0 || vm->c_data->top() != nullptr) 82 + return false; 83 + 84 + vm->c_data->pop(); 85 + Exception& e = py_cast<Exception&>(vm, vm->c_data->top()); 86 + if (message != nullptr) 87 + *message = e.summary().c_str_dup(); 88 + else 89 + std::cerr << "ERROR: " << e.summary() << "\n"; 90 + 91 + vm->c_data->clear(); 92 + vm->callstack.clear(); 93 + vm->s_data.clear(); 94 + return true; 95 + 96 + SAFEGUARD_CLOSE 97 + } 98 + 99 + void gc_marker_ex(CVM* vm) { 100 + for(PyObject* obj: *vm->c_data) if(obj!=nullptr) OBJ_MARK(obj); 101 + } 102 + 103 + 104 + static void noop_output_handler(VM* vm, const Str& str) { 105 + (void) vm; 106 + (void) str; 107 + } 108 + 109 + pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os) { 110 + 111 + CVM* vm = new CVM(enable_os); 112 + vm->c_data = new ValueStackImpl<PKPY_STACK_SIZE>(); 113 + vm->_gc_marker_ex = (void (*)(VM*)) gc_marker_ex; 114 + 115 + if (!use_stdio) { 116 + vm->_stdout = noop_output_handler; 117 + vm->_stderr = noop_output_handler; 118 + } 119 + 120 + return (pkpy_vm*) vm; 121 + } 122 + 123 + bool pkpy_vm_run(pkpy_vm* vm_handle, const char* source) { 124 + CVM* vm = (CVM*) vm_handle; 125 + ERRHANDLER_OPEN 126 + 127 + CodeObject_ code = vm->compile(source, "<c-bound>", EXEC_MODE); 128 + PyObject* result = vm->_exec(code, vm->_main); 129 + 130 + //unpack_return(w, result); 131 + //NOTE: it seems like vm->_exec should return whatever the last command it 132 + //ran returned but instead it seems to pretty much always return None 133 + //so I guess uncomment this line if that every changes 134 + 135 + return true; 136 + ERRHANDLER_CLOSE 137 + } 138 + 139 + void pkpy_vm_destroy(pkpy_vm* vm_handle) { 140 + CVM* vm = (CVM*) vm_handle; 141 + delete vm; 142 + } 143 + 144 + static void propagate_if_errored(CVM* vm, ValueStackImpl<PKPY_STACK_SIZE>* stored_stack) { 145 + try { 146 + if (vm->c_data->size() == 0 || vm->c_data->top() != nullptr) 147 + return; 148 + 149 + vm->c_data->pop(); 150 + Exception& e = py_cast<Exception&>(vm, vm->c_data->top()); 151 + vm->c_data->pop(); 152 + 153 + vm->c_data = stored_stack; 154 + 155 + throw e; 156 + } catch(Exception& e) { 157 + throw; 158 + } catch(...) { 159 + std::cerr << "ERROR: a non pocketpy exeception was thrown " 160 + << "this probably means pocketpy itself has a bug!\n"; 161 + exit(2); 162 + } 163 + } 164 + 165 + PyObject* c_function_wrapper(VM* vm, ArgsView args) { 166 + LuaStyleFuncC f = py_cast<NativeFunc&>(vm, args[-2])._lua_f; 167 + CVM* cvm = (CVM*) vm; 168 + 169 + //setup c stack 170 + ValueStackImpl<PKPY_STACK_SIZE> local_stack; 171 + 172 + for (int i = 0; i < args.size(); i++) 173 + local_stack.push(args[i]); 174 + 175 + ValueStackImpl<PKPY_STACK_SIZE>* stored_stack = cvm->c_data; 176 + cvm->c_data = &local_stack; 177 + 178 + int retc = f(cvm); 179 + 180 + propagate_if_errored(cvm, stored_stack); 181 + cvm->c_data = stored_stack; 182 + 183 + PyObject* ret = cvm->None; 184 + 185 + if (retc == 1) 186 + ret = local_stack.top(); 187 + else if (retc > 1) { 188 + Tuple t(retc); 189 + 190 + for (int i = 0; i < retc; i++) { 191 + int stack_index = (local_stack.size() - retc) + i; 192 + t[i] = local_stack.begin()[stack_index]; 193 + } 194 + 195 + ret = py_var(cvm, t); 196 + } 197 + 198 + return ret; 199 + } 200 + 201 + bool pkpy_push_function(pkpy_vm* vm_handle, pkpy_function f) { 202 + CVM* vm = (CVM*) vm_handle; 203 + ERRHANDLER_OPEN 204 + 205 + //TODO right now we just treat all c bound functions a varargs functions 206 + //do we want to change that? 207 + NativeFunc nf = NativeFunc(c_function_wrapper, -1, 0); 208 + nf._lua_f = (LuaStyleFuncC) f; 209 + 210 + vm->c_data->push(py_var(vm, nf)); 211 + 212 + return true; 213 + ERRHANDLER_CLOSE 214 + } 215 + 216 + bool pkpy_push_int(pkpy_vm* vm_handle, int value) { 217 + CVM* vm = (CVM*) vm_handle; 218 + ERRHANDLER_OPEN 219 + 220 + vm->c_data->push(py_var(vm, value)); 221 + 222 + return true; 223 + ERRHANDLER_CLOSE 224 + } 225 + 226 + bool pkpy_push_float(pkpy_vm* vm_handle, double value) { 227 + CVM* vm = (CVM*) vm_handle; 228 + ERRHANDLER_OPEN 229 + vm->c_data->push(py_var(vm, value)); 230 + 231 + return true; 232 + ERRHANDLER_CLOSE 233 + } 234 + 235 + bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) { 236 + CVM* vm = (CVM*) vm_handle; 237 + ERRHANDLER_OPEN 238 + vm->c_data->push(py_var(vm, value)); 239 + 240 + return true; 241 + ERRHANDLER_CLOSE 242 + } 243 + 244 + bool pkpy_push_string(pkpy_vm* vm_handle, const char* value) { 245 + CVM* vm = (CVM*) vm_handle; 246 + ERRHANDLER_OPEN 247 + vm->c_data->push(py_var(vm, value)); 248 + 249 + return true; 250 + ERRHANDLER_CLOSE 251 + } 252 + 253 + bool pkpy_push_stringn(pkpy_vm* vm_handle, const char* value, int length) { 254 + CVM* vm = (CVM*) vm_handle; 255 + ERRHANDLER_OPEN 256 + 257 + Str s = Str(value, length); 258 + vm->c_data->push(py_var(vm, s)); 259 + 260 + return true; 261 + ERRHANDLER_CLOSE 262 + } 263 + 264 + bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) { 265 + CVM* vm = (CVM*) vm_handle; 266 + ERRHANDLER_OPEN 267 + vm->c_data->push(py_var(vm, value)); 268 + 269 + return true; 270 + ERRHANDLER_CLOSE 271 + } 272 + 273 + bool pkpy_push_none(pkpy_vm* vm_handle) { 274 + CVM* vm = (CVM*) vm_handle; 275 + ERRHANDLER_OPEN 276 + vm->c_data->push(vm->None); 277 + 278 + return true; 279 + ERRHANDLER_CLOSE 280 + } 281 + 282 + 283 + 284 + bool pkpy_set_global(pkpy_vm* vm_handle, const char* name) { 285 + CVM* vm = (CVM*) vm_handle; 286 + ERRHANDLER_OPEN 287 + 288 + vm->_main->attr().set(name, vm->c_data->top()); 289 + 290 + vm->c_data->pop(); 291 + 292 + return true; 293 + ERRHANDLER_CLOSE 294 + } 295 + 296 + //get global will also get bulitins 297 + bool pkpy_get_global(pkpy_vm* vm_handle, const char* name) { 298 + CVM* vm = (CVM*) vm_handle; 299 + ERRHANDLER_OPEN 300 + 301 + PyObject* o = vm->_main->attr().try_get(name); 302 + if (o == nullptr) { 303 + o = vm->builtins->attr().try_get(name); 304 + if (o == nullptr) 305 + throw Exception("NameError", "could not find requested global"); 306 + } 307 + 308 + vm->c_data->push(o); 309 + 310 + return true; 311 + ERRHANDLER_CLOSE 312 + } 313 + 314 + 315 + bool pkpy_call(pkpy_vm* vm_handle, int argc) { 316 + CVM* vm = (CVM*) vm_handle; 317 + ERRHANDLER_OPEN 318 + 319 + int callable_index = vm->c_data->size() - argc - 1; 320 + 321 + PyObject* callable = vm->c_data->begin()[callable_index]; 322 + 323 + vm->s_data.push(callable); 324 + vm->s_data.push(PY_NULL); 325 + 326 + for (int i = 0; i < argc; i++) 327 + vm->s_data.push(vm->c_data->begin()[callable_index + i + 1]); 328 + 329 + PyObject* o = vm->vectorcall(argc); 330 + 331 + vm->c_data->shrink(argc + 1); 332 + 333 + unpack_return(vm, o); 334 + 335 + return true; 336 + ERRHANDLER_CLOSE 337 + } 338 + 339 + bool pkpy_call_method(pkpy_vm* vm_handle, const char* name, int argc) { 340 + CVM* vm = (CVM*) vm_handle; 341 + ERRHANDLER_OPEN 342 + 343 + int self_index = vm->c_data->size() - argc - 1; 344 + PyObject* self = vm->c_data->begin()[self_index]; 345 + 346 + PyObject* callable = vm->get_unbound_method(self, name, &self); 347 + 348 + vm->s_data.push(callable); 349 + vm->s_data.push(self); 350 + 351 + for (int i = 0; i < argc; i++) 352 + vm->s_data.push(vm->c_data->begin()[self_index + i + 1]); 353 + 354 + PyObject* o = vm->vectorcall(argc); 355 + 356 + vm->c_data->shrink(argc + 1); 357 + 358 + unpack_return(vm, o); 359 + 360 + return true; 361 + ERRHANDLER_CLOSE 362 + } 363 + 364 + 365 + 366 + static int lua_to_cstack_index(int index, int size) { 367 + if (index < 0) 368 + index = size + index; 369 + return index; 370 + } 371 + 372 + bool pkpy_to_int(pkpy_vm* vm_handle, int index, int* ret) { 373 + CVM* vm = (CVM*) vm_handle; 374 + ERRHANDLER_OPEN 375 + 376 + index = lua_to_cstack_index(index, vm->c_data->size()); 377 + 378 + PyObject* o = vm->c_data->begin()[index]; 379 + 380 + if (!is_type(o, vm->tp_int)) 381 + throw Exception("TypeError", "pkpy_to_int on non int object"); 382 + 383 + if (ret != nullptr) 384 + *ret = py_cast<int>(vm, o); 385 + 386 + return true; 387 + ERRHANDLER_CLOSE 388 + } 389 + 390 + bool pkpy_to_float(pkpy_vm* vm_handle, int index, double* ret) { 391 + CVM* vm = (CVM*) vm_handle; 392 + ERRHANDLER_OPEN 393 + 394 + index = lua_to_cstack_index(index, vm->c_data->size()); 395 + 396 + PyObject* o = vm->c_data->begin()[index]; 397 + 398 + if (!is_type(o, vm->tp_float)) 399 + throw Exception("TypeError", "pkpy_to_float on non float object"); 400 + 401 + if (ret != nullptr) 402 + *ret = py_cast<double>(vm, o); 403 + 404 + return true; 405 + ERRHANDLER_CLOSE 406 + } 407 + 408 + bool pkpy_to_bool(pkpy_vm* vm_handle, int index, bool* ret) { 409 + CVM* vm = (CVM*) vm_handle; 410 + ERRHANDLER_OPEN 411 + 412 + index = lua_to_cstack_index(index, vm->c_data->size()); 413 + 414 + PyObject* o = vm->c_data->begin()[index]; 415 + if (!is_type(o, vm->tp_bool)) 416 + throw Exception("TypeError", "pkpy_to_bool on non bool object"); 417 + 418 + if (ret != nullptr) 419 + *ret = py_cast<bool>(vm, o); 420 + 421 + return true; 422 + ERRHANDLER_CLOSE 423 + } 424 + 425 + bool pkpy_to_voidp(pkpy_vm* vm_handle, int index, void** ret) { 426 + CVM* vm = (CVM*) vm_handle; 427 + ERRHANDLER_OPEN 428 + 429 + index = lua_to_cstack_index(index, vm->c_data->size()); 430 + 431 + PyObject* o = vm->c_data->begin()[index]; 432 + if (!is_type(o, VoidP::_type(vm))) 433 + throw Exception("TypeError", "pkpy_to_voidp on non void* object"); 434 + 435 + if (ret != nullptr) 436 + *ret = py_cast<void*>(vm, o); 437 + 438 + return true; 439 + ERRHANDLER_CLOSE 440 + } 441 + 442 + bool pkpy_to_string(pkpy_vm* vm_handle, int index, char** ret) { 443 + CVM* vm = (CVM*) vm_handle; 444 + ERRHANDLER_OPEN 445 + 446 + index = lua_to_cstack_index(index, vm->c_data->size()); 447 + 448 + PyObject* o = vm->c_data->begin()[index]; 449 + if (!is_type(o, vm->tp_str)) 450 + throw Exception("TypeError", "pkpy_to_string on non string object"); 451 + 452 + if (ret != nullptr) { 453 + Str& s = py_cast<Str&>(vm, o); 454 + *ret = s.c_str_dup(); 455 + } 456 + 457 + return true; 458 + ERRHANDLER_CLOSE 459 + } 460 + 461 + bool pkpy_to_stringn(pkpy_vm* vm_handle, int index, const char** ret, int* size) { 462 + CVM* vm = (CVM*) vm_handle; 463 + ERRHANDLER_OPEN 464 + 465 + index = lua_to_cstack_index(index, vm->c_data->size()); 466 + 467 + PyObject* o = vm->c_data->begin()[index]; 468 + if (ret != nullptr) { 469 + std::string_view sv = py_cast<Str&>(vm, o).sv(); 470 + *ret = sv.data(); 471 + *size = sv.size(); 472 + } 473 + 474 + return true; 475 + ERRHANDLER_CLOSE 476 + } 477 + 478 + 479 + bool pkpy_is_int(pkpy_vm* vm_handle, int index) { 480 + CVM* vm = (CVM*) vm_handle; 481 + index = lua_to_cstack_index(index, vm->c_data->size()); 482 + PyObject* o = vm->c_data->begin()[index]; 483 + 484 + return is_type(o, vm->tp_int); 485 + } 486 + bool pkpy_is_float(pkpy_vm* vm_handle, int index) { 487 + CVM* vm = (CVM*) vm_handle; 488 + index = lua_to_cstack_index(index, vm->c_data->size()); 489 + PyObject* o = vm->c_data->begin()[index]; 490 + 491 + return is_type(o, vm->tp_float); 492 + } 493 + bool pkpy_is_bool(pkpy_vm* vm_handle, int index) { 494 + CVM* vm = (CVM*) vm_handle; 495 + index = lua_to_cstack_index(index, vm->c_data->size()); 496 + PyObject* o = vm->c_data->begin()[index]; 497 + 498 + return is_type(o, vm->tp_bool); 499 + } 500 + bool pkpy_is_string(pkpy_vm* vm_handle, int index) { 501 + CVM* vm = (CVM*) vm_handle; 502 + index = lua_to_cstack_index(index, vm->c_data->size()); 503 + PyObject* o = vm->c_data->begin()[index]; 504 + 505 + return is_type(o, vm->tp_str); 506 + } 507 + bool pkpy_is_voidp(pkpy_vm* vm_handle, int index) { 508 + CVM* vm = (CVM*) vm_handle; 509 + index = lua_to_cstack_index(index, vm->c_data->size()); 510 + PyObject* o = vm->c_data->begin()[index]; 511 + 512 + return is_type(o, VoidP::_type(vm)); 513 + } 514 + 515 + bool pkpy_is_none(pkpy_vm* vm_handle, int index) { 516 + CVM* vm = (CVM*) vm_handle; 517 + index = lua_to_cstack_index(index, vm->c_data->size()); 518 + PyObject* o = vm->c_data->begin()[index]; 519 + 520 + return o == vm->None; 521 + } 522 + 523 + bool pkpy_check_global(pkpy_vm* vm_handle, const char* name) { 524 + CVM* vm = (CVM*) vm_handle; 525 + SAFEGUARD_OPEN 526 + PyObject* o = vm->_main->attr().try_get(name); 527 + if (o == nullptr) { 528 + o = vm->builtins->attr().try_get(name); 529 + if (o == nullptr) 530 + return false; 531 + } 532 + return true; 533 + 534 + SAFEGUARD_CLOSE 535 + } 536 + 537 + bool pkpy_check_error(pkpy_vm* vm_handle) { 538 + CVM* vm = (CVM*) vm_handle; 539 + SAFEGUARD_OPEN 540 + if (vm->c_data->size() > 0 && vm->c_data->top() == nullptr) 541 + return true; 542 + return false; 543 + SAFEGUARD_CLOSE 544 + } 545 + 546 + 547 + bool pkpy_check_stack(pkpy_vm* vm_handle, int free) { 548 + CVM* vm = (CVM*) vm_handle; 549 + return free + vm->c_data->size() <= PKPY_STACK_SIZE; 550 + } 551 + 552 + int pkpy_stack_size(pkpy_vm* vm_handle) { 553 + CVM* vm = (CVM*) vm_handle; 554 + return vm->c_data->size(); 555 + } 556 + 557 + bool pkpy_pop(pkpy_vm* vm_handle, int n) { 558 + CVM* vm = (CVM*) vm_handle; 559 + vm->c_data->shrink(n); 560 + return true; 561 + } 562 + 563 + 564 + bool pkpy_push(pkpy_vm* vm_handle, int index) { 565 + CVM* vm = (CVM*) vm_handle; 566 + index = lua_to_cstack_index(index, vm->c_data->size()); 567 + vm->c_data->push(vm->c_data->begin()[index]); 568 + return true; 569 + } 570 + 571 + 572 + bool pkpy_error(pkpy_vm* vm_handle, const char* message) { 573 + CVM* vm = (CVM*) vm_handle; 574 + ERRHANDLER_OPEN 575 + throw Exception("CBindingError", message); 576 + ERRHANDLER_CLOSE 577 + } 578 +
+115
vendor/pocketpy/pocketpy_c.h
··· 1 + #ifndef POCKETPY_C_H 2 + #define POCKETPY_C_H 3 + 4 + #ifdef __cplusplus 5 + extern "C" { 6 + #endif 7 + 8 + #include <stdbool.h> 9 + #include <stdint.h> 10 + 11 + typedef struct pkpy_vm_handle pkpy_vm; 12 + 13 + //we we take a lot of inspiration from the lua api for these bindings 14 + //the key difference being most methods return a bool, 15 + //true if it succeeded false if it did not 16 + 17 + //if a method returns false call the pkpy_clear_error method to check the error and clear it 18 + //if pkpy_clear_error returns false it means that no error was set, and it takes no action 19 + //if pkpy_clear_error returns true it means there was an error and it was cleared, 20 + //it will provide a string summary of the error in the message parameter (if it is not NULL) 21 + //if null is passed in as message, and it will just print the message to stderr 22 + bool pkpy_clear_error(pkpy_vm*, char** message); 23 + //NOTE you are responsible for freeing message 24 + 25 + //this will cause the vm to enter an error state and report the given message 26 + //when queried 27 + //note that at the moment this is more like a panic than throwing an error 28 + //the user will not be able to catch it with python code 29 + bool pkpy_error(pkpy_vm*, const char* message); 30 + 31 + 32 + pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os); 33 + bool pkpy_vm_run(pkpy_vm*, const char* source); 34 + void pkpy_vm_destroy(pkpy_vm*); 35 + 36 + typedef int (*pkpy_function)(pkpy_vm*); 37 + 38 + bool pkpy_pop(pkpy_vm*, int n); 39 + 40 + //push the item at index onto the top of the stack (as well as leaving it where 41 + //it is on the stack) 42 + bool pkpy_push(pkpy_vm*, int index); 43 + 44 + bool pkpy_push_function(pkpy_vm*, pkpy_function); 45 + bool pkpy_push_int(pkpy_vm*, int); 46 + bool pkpy_push_float(pkpy_vm*, double); 47 + bool pkpy_push_bool(pkpy_vm*, bool); 48 + bool pkpy_push_string(pkpy_vm*, const char*); 49 + bool pkpy_push_stringn(pkpy_vm*, const char*, int length); 50 + bool pkpy_push_voidp(pkpy_vm*, void*); 51 + bool pkpy_push_none(pkpy_vm*); 52 + 53 + bool pkpy_set_global(pkpy_vm*, const char* name); 54 + bool pkpy_get_global(pkpy_vm*, const char* name); 55 + 56 + //first push callable you want to call 57 + //then push the arguments to send 58 + //argc is the number of arguments that was pushed (not counting the callable) 59 + bool pkpy_call(pkpy_vm*, int argc); 60 + 61 + //first push the object the method belongs to (self) 62 + //then push the the argments 63 + //argc is the number of arguments that was pushed (not counting the callable or self) 64 + //name is the name of the method to call on the object 65 + bool pkpy_call_method(pkpy_vm*, const char* name, int argc); 66 + 67 + 68 + //we will break with the lua api here 69 + //lua uses 1 as the index to the first pushed element for all of these functions 70 + //but we will start counting at zero to match python 71 + //we will allow negative numbers to count backwards from the top 72 + bool pkpy_to_int(pkpy_vm*, int index, int* ret); 73 + bool pkpy_to_float(pkpy_vm*, int index, double* ret); 74 + bool pkpy_to_bool(pkpy_vm*, int index, bool* ret); 75 + bool pkpy_to_voidp(pkpy_vm*, int index, void** ret); 76 + 77 + //this method provides a strong reference, you are responsible for freeing the 78 + //string when you are done with it 79 + bool pkpy_to_string(pkpy_vm*, int index, char** ret); 80 + 81 + //this method provides a weak reference, it is only valid until the 82 + //next api call 83 + //it is not null terminated 84 + bool pkpy_to_stringn(pkpy_vm*, int index, const char** ret, int* size); 85 + 86 + 87 + //these do not follow the same error semantics as above, their return values 88 + //just say whether the check succeeded or not, or else return the value asked for 89 + 90 + bool pkpy_is_int(pkpy_vm*, int index); 91 + bool pkpy_is_float(pkpy_vm*, int index); 92 + bool pkpy_is_bool(pkpy_vm*, int index); 93 + bool pkpy_is_string(pkpy_vm*, int index); 94 + bool pkpy_is_voidp(pkpy_vm*, int index); 95 + bool pkpy_is_none(pkpy_vm*, int index); 96 + 97 + 98 + //will return true if global exists 99 + bool pkpy_check_global(pkpy_vm*, const char* name); 100 + 101 + //will return true if the vm is currently in an error state 102 + bool pkpy_check_error(pkpy_vm*); 103 + 104 + //will return true if at least free empty slots remain on the stack 105 + bool pkpy_check_stack(pkpy_vm*, int free); 106 + 107 + //returns the number of elements on the stack 108 + int pkpy_stack_size(pkpy_vm*); 109 + 110 + 111 + #ifdef __cplusplus 112 + } 113 + #endif 114 + 115 + #endif