| 1486 | } |
| 1487 | |
| 1488 | static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity *pstruct) |
| 1489 | { |
| 1490 | Lua::StackUnwinder base{state}; |
| 1491 | |
| 1492 | // metatable |
| 1493 | lua_newtable(state); |
| 1494 | int ix_meta = lua_gettop(state); |
| 1495 | |
| 1496 | // field info table (name -> struct_field_info*) |
| 1497 | lua_newtable(state); |
| 1498 | int ix_fieldinfo = lua_gettop(state); |
| 1499 | |
| 1500 | // field iter table (int <-> name) |
| 1501 | lua_newtable(state); |
| 1502 | int ix_fielditer = lua_gettop(state); |
| 1503 | IndexFields(state, base, pstruct, IndexFieldsFlags::RAW); |
| 1504 | |
| 1505 | PushStructMethod(state, ix_meta, ix_fielditer, meta_fieldinfo_next); |
| 1506 | // change upvalue 1 to the field info table since we don't need the original |
| 1507 | lua_pushvalue(state, ix_fieldinfo); |
| 1508 | lua_setupvalue(state, -2, 1); |
| 1509 | SetPairsMethod(state, ix_meta, "__pairs"); |
| 1510 | |
| 1511 | // field table (name -> table representation of struct_field_info) |
| 1512 | lua_newtable(state); |
| 1513 | int ix_fields = lua_gettop(state); |
| 1514 | |
| 1515 | // wrapper table (empty, indexes into field table with metamethods) |
| 1516 | lua_newtable(state); |
| 1517 | int ix_wrapper = lua_gettop(state); |
| 1518 | |
| 1519 | // set up metatable for the wrapper |
| 1520 | // use field table for __index |
| 1521 | lua_pushstring(state, "__index"); |
| 1522 | lua_pushvalue(state, ix_fieldinfo); |
| 1523 | lua_pushcclosure(state, meta_fieldinfo_index, 1); |
| 1524 | lua_settable(state, ix_meta); |
| 1525 | |
| 1526 | // use change_error() for __newindex |
| 1527 | lua_pushstring(state, "__newindex"); |
| 1528 | lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_CHANGEERROR_NAME); |
| 1529 | lua_settable(state, ix_meta); |
| 1530 | |
| 1531 | lua_pushvalue(state, ix_meta); |
| 1532 | lua_setmetatable(state, ix_wrapper); |
| 1533 | |
| 1534 | // convert field info table (struct_field_info) to field table (lua tables) |
| 1535 | lua_pushnil(state); // initial key for next() |
| 1536 | while (lua_next(state, ix_fieldinfo)) { |
| 1537 | auto field = static_cast<const struct_field_info*>(lua_touserdata(state, -1)); |
| 1538 | lua_pushvalue(state, -2); // field name |
| 1539 | PushFieldInfoSubTable(state, field); |
| 1540 | lua_settable(state, ix_fields); |
| 1541 | lua_pop(state, 1); // struct_field_info |
| 1542 | } |
| 1543 | |
| 1544 | // lua_pushvalue(state, ix_fields); |
| 1545 | // freeze_table(state); // TODO: figure out why this creates an __index cycle for nonexistent fields |
no test coverage detected