This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git


The following commit(s) were added to refs/heads/main by this push:
     new 1007269  [FEAT] Streamline AccessPath/AccessStep print format (#598)
1007269 is described below

commit 1007269cd9e243fc9a20a2026a79503ab30e2b58
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu May 28 13:33:31 2026 -0400

    [FEAT] Streamline AccessPath/AccessStep print format (#598)
    
    ## Summary
    
    Register a custom `__ffi_repr__` for `ffi::reflection::AccessPath` and
    `AccessStep` so their formatted output is a concise, human-readable path
    expression:
    
    ```
    <root>.config.layers[0][<missing:"weights">]
    ```
    
    Per-step rendering:
    - root: `<root>`
    - attr: `.name`
    - array item: `[index]`
    - map item: `[<repr(key)>]` (string keys quoted)
    - missing attr: `[<missing:"name">]`
    - missing array: `[<missing:index>]`
    - missing map: `[<missing:<repr(key)>>]`
    
    The formatter delegates key quoting to the existing `EscapedStringPy`
    path via `fn_repr(step->key)`, so non-string map keys are also handled
    robustly.
---
 src/ffi/extra/reflection_extra.cc        | 50 ++++++++++++++++++++++++++++++++
 tests/cpp/extra/test_access_path_repr.cc | 41 ++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/src/ffi/extra/reflection_extra.cc 
b/src/ffi/extra/reflection_extra.cc
index 08b6511..f3930de 100644
--- a/src/ffi/extra/reflection_extra.cc
+++ b/src/ffi/extra/reflection_extra.cc
@@ -26,6 +26,8 @@
 #include <tvm/ffi/reflection/accessor.h>
 #include <tvm/ffi/reflection/registry.h>
 
+#include <sstream>
+
 namespace tvm {
 namespace ffi {
 namespace reflection {
@@ -104,6 +106,41 @@ inline void AccessStepRegisterReflection() {
   refl::ObjectDef<AccessStepObj>(refl::init(false))
       .def_ro("kind", &AccessStepObj::kind)
       .def_ro("key", &AccessStepObj::key);
+  // Register __ffi_repr__ for AccessStep: format one step fragment.
+  //   kAttr             -> ".name"
+  //   kArrayItem        -> "[index]"
+  //   kMapItem          -> "[<repr(key)>]"    (string keys are quoted via 
fn_repr)
+  //   kAttrMissing      -> "[<missing:"name">]"
+  //   kArrayItemMissing -> "[<missing:index>]"
+  //   kMapItemMissing   -> "[<missing:<repr(key)>>]"
+  refl::TypeAttrDef<AccessStepObj>().def(
+      refl::type_attr::kRepr,
+      [](const AccessStep& step, const ffi::Function& fn_repr) -> ffi::String {
+        std::ostringstream os;
+        switch (step->kind) {
+          case AccessKind::kAttr:
+            os << "." << step->key.cast<ffi::String>();
+            break;
+          case AccessKind::kArrayItem:
+            os << "[" << step->key.cast<int64_t>() << "]";
+            break;
+          case AccessKind::kMapItem:
+            os << "[" << fn_repr(step->key).cast<ffi::String>() << "]";
+            break;
+          case AccessKind::kAttrMissing:
+            os << "[<missing:" << fn_repr(step->key).cast<ffi::String>() << 
">]";
+            break;
+          case AccessKind::kArrayItemMissing:
+            os << "[<missing:" << step->key.cast<int64_t>() << ">]";
+            break;
+          case AccessKind::kMapItemMissing:
+            os << "[<missing:" << fn_repr(step->key).cast<ffi::String>() << 
">]";
+            break;
+          default:
+            TVM_FFI_UNREACHABLE();
+        }
+        return os.str();
+      });
 }
 
 inline void AccessPathRegisterReflection() {
@@ -125,6 +162,19 @@ inline void AccessPathRegisterReflection() {
       .def("_to_steps", &AccessPathObj::ToSteps)
       .def("_path_equal",
            [](const AccessPath& self, const AccessPath& other) { return 
self->PathEqual(other); });
+  // Register __ffi_repr__ for AccessPath: flatten via ToSteps() and walk the 
resulting vector.
+  // Root (depth == 0) emits "<root>"; non-root nodes concatenate each step's 
fragment.
+  refl::TypeAttrDef<AccessPathObj>().def(
+      refl::type_attr::kRepr,
+      [](const AccessPath& path, const ffi::Function& fn_repr) -> ffi::String {
+        Array<AccessStep> steps = path->ToSteps();
+        std::ostringstream os;
+        os << "<root>";
+        for (const AccessStep& step : steps) {
+          os << fn_repr(step).cast<ffi::String>();
+        }
+        return os.str();
+      });
 }
 
 int64_t StructuralKeyHash(const Any& key) {
diff --git a/tests/cpp/extra/test_access_path_repr.cc 
b/tests/cpp/extra/test_access_path_repr.cc
new file mode 100644
index 0000000..c6cde05
--- /dev/null
+++ b/tests/cpp/extra/test_access_path_repr.cc
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <gtest/gtest.h>
+#include <tvm/ffi/extra/dataclass.h>
+#include <tvm/ffi/reflection/access_path.h>
+
+namespace {
+
+TEST(AccessPathRepr, StreamlinedFormat) {
+  using namespace tvm::ffi;
+  using namespace tvm::ffi::reflection;
+  AccessPath p = AccessPath::Root()
+                     ->Attr("config")
+                     ->Attr("layers")
+                     ->ArrayItem(0)
+                     ->MapItem(String("name"))
+                     ->AttrMissing("weights")
+                     ->ArrayItemMissing(3)
+                     ->MapItemMissing(String("bias"));
+  EXPECT_EQ(std::string(ReprPrint(Any(p)).c_str()),
+            "<root>.config.layers[0][\"name\"]"
+            "[<missing:\"weights\">][<missing:3>][<missing:\"bias\">]");
+}
+
+}  // namespace

Reply via email to