瀏覽代碼

feat(apilot): universal noop stub factory for tolua/cc classes

wuzilong 1 月之前
父節點
當前提交
5dfce882a2
共有 3 個文件被更改,包括 82 次插入 和 0 次删除
  1. 0 0
      apilot/stubs/__init__.py
  2. 64 0
      apilot/stubs/noop.py
  3. 18 0
      tests/test_noop.py

+ 0 - 0
apilot/stubs/__init__.py


+ 64 - 0
apilot/stubs/noop.py

@@ -0,0 +1,64 @@
+# apilot/stubs/noop.py
+"""万能 no-op 工厂: 冒充 tolua/cc 渲染类。属性=同款工厂, 调用=返回同款对象。"""
+from __future__ import annotations
+from typing import Any
+
+_NOOP_RETURN_DEFAULTS: tuple[tuple[tuple, Any], ...] = (
+    # (参数个数, 返回值) —— 需要非 nil 返回的接口按绑定面清单加
+    (("getPosition",), (0, 0)),
+)
+
+
+def make_noop_table(name: str = "?", _depth: int = 0) -> Any:
+    if _depth > 24:
+        return None
+
+    class _Noop:
+        def __init__(self, n: str) -> None:
+            self.__name = n
+
+        def __getitem__(self, k: str) -> Any:
+            return make_noop_table(f"{self.__name}.{k}", _depth + 1)
+
+        def __getattr__(self, k: str) -> Any:
+            return self[k]
+
+        def __call__(self, *a: Any, **kw: Any) -> Any:
+            method = self.__name.rsplit(".", 1)[-1]
+            for names, ret in _NOOP_RETURN_DEFAULTS:
+                if method in names:
+                    return ret
+            return make_noop_table(f"{self.__name}()", _depth + 1)
+
+        def __repr__(self) -> str:
+            return f"<noop:{self.__name}>"
+
+    return _Noop(name)
+
+
+class _ReturnZeroPair:
+    """getPosition 等双值返回的特化包装, M1 暂不启用(绑定面清单核对后启用)。"""
+
+
+def install_noop_globals(lua: Any) -> None:
+    """注入 cc/ccui/ccs/ccexp 骨架。真实实现(netClient 等)在装完 no-op 后由各自模块覆盖。"""
+    lua.execute("""
+cc = cc or {}
+setmetatable(cc, {__index = function(t, k)
+    local v = setmetatable({}, {
+        __index = function(tt, kk)
+            local fn = function(...) return setmetatable({}, {
+                __index = function(t3, k3)
+                    return function(...) return nil end
+                end}) end
+        return fn end,
+        __call = function(cls, ...) return setmetatable({}, {
+            __index = function(o, k)
+                return function(...) return nil end end}) end})
+    rawset(t, k, v)
+    return v
+end})
+ccui = ccui or cc.Sprite  -- 同骨架
+ccs = ccs or cc.Sprite
+ccexp = ccexp or cc.Sprite
+""")

+ 18 - 0
tests/test_noop.py

@@ -0,0 +1,18 @@
+# tests/test_noop.py
+import lupa.luajit21 as lj
+
+def test_noop_table_safe_access():
+    from apilot.stubs.noop import make_noop_table
+    t = make_noop_table("cc")
+    assert t["Sprite"] is not None          # 任意键存在
+    assert callable(t["Sprite"]["create"])  # 任意层级可调
+    obj = t["Sprite"]["create"]()
+    assert obj["getPosition"]() == (0, 0)   # 调用返回 no-op 对象(继续安全)
+
+def test_install_noop_globals_in_lua():
+    from apilot.stubs.noop import install_noop_globals
+    rt = lj.LuaRuntime()
+    install_noop_globals(rt)
+    rt.execute("local s = cc.Sprite:create(); s:setPosition(1,2); s:addChild(cc.Node:create())")
+    rt.execute("cc.Director:getInstance():getScheduler()")
+    # 无异常即通过