MCPcopy Create free account
hub / github.com/dylan-sutton-chavez/edge-python / resolve_attr

Method resolve_attr

compiler/src/modules/vm/handlers/methods.rs:107–224  ·  view source on GitHub ↗

`obj. ` resolution shared by `handle_load_attr` and `exec_call_method`.

(&self, obj: Val, name: &str)

Source from the content-addressed store, hash-verified

105
106 // `obj.<name>` resolution shared by `handle_load_attr` and `exec_call_method`.
107 pub(crate) fn resolve_attr(&self, obj: Val, name: &str) -> Result<AttrLookup, VmErr> {
108 let bare = crate::modules::parser::ssa_strip(name);
109
110 // Module attr: linear scan; the table is sized for around 30 entries.
111 if obj.is_heap()
112 && let HeapObj::Module(mod_name, attrs) = self.heap.get(obj) {
113 if let Some((_, v)) = attrs.iter().find(|(n, _)| n == bare) {
114 return Ok(AttrLookup::ModuleAttr(*v));
115 }
116 return Err(VmErr::Attribute(s!("module '", str mod_name, "' has no attribute '", str bare, "'")));
117 }
118
119 // ExcInstance attr: only `e.args` is defined.
120 if obj.is_heap()
121 && let HeapObj::ExcInstance(_, args) = self.heap.get(obj) {
122 if bare == "args" { return Ok(AttrLookup::ExcArgs(args.clone())); }
123 let ty = self.type_name(obj);
124 return Err(VmErr::Attribute(s!("'", str ty, "' object has no attribute '", str bare, "'")));
125 }
126
127 // `__name__` on callables and types resolves to their declared name.
128 if obj.is_heap() && bare == "__name__" {
129 let resolved = match self.heap.get(obj) {
130 HeapObj::Func(fi, _, _) => self.function_names.get(*fi).cloned(),
131 HeapObj::Type(n) => Some(n.clone()),
132 HeapObj::Class(n, _, _) => Some(n.clone()),
133 _ => None,
134 };
135 if let Some(n) = resolved { return Ok(AttrLookup::Name(n)); }
136 }
137
138 // Class attr: `MyClass.method` returns the unbound function (no `self` prepended).
139 if obj.is_heap()
140 && let HeapObj::Class(cls_name, _, _) = self.heap.get(obj) {
141 if let Some((v, _)) = self.lookup_class_member(obj, bare) {
142 // `staticmethod` accessed on the class itself unwraps to the plain function.
143 if v.is_heap() && let HeapObj::StaticMethod(func) = self.heap.get(v) {
144 return Ok(AttrLookup::ClassMember(*func));
145 }
146 return Ok(AttrLookup::ClassMember(v));
147 }
148 let cls_name = cls_name.clone();
149 return Err(VmErr::Attribute(s!("type object '", str &cls_name, "' has no attribute '", str bare, "'")));
150 }
151
152 // Instance attribute lookup: check `__dict__` first, then the class chain (direct + bases).
153 if obj.is_heap()
154 && let HeapObj::Instance(cls_val, attrs) = self.heap.get(obj) {
155 let cls_val = *cls_val;
156 let found = attrs.borrow().entries.iter()
157 .find(|(k, _)| k.is_heap() && matches!(self.heap.get(*k), HeapObj::Str(s) if s == name))
158 .map(|(_, v)| *v);
159 if let Some(v) = found { return Ok(AttrLookup::InstanceField(v)); }
160 if let Some((mv, defining)) = self.lookup_class_member(cls_val, bare) {
161 // Guard on is_heap before heap.get: a non-heap data member (e.g. a wide int) would otherwise be read as a heap pointer and index a garbage slot.
162 if mv.is_heap() {
163 match self.heap.get(mv) {
164 // A Property member triggers getter invocation in `handle_load_attr`.

Callers 2

exec_call_methodMethod · 0.80
handle_load_attrMethod · 0.80

Calls 9

ssa_stripFunction · 0.85
lookup_methodFunction · 0.85
is_heapMethod · 0.80
type_nameMethod · 0.80
lookup_class_memberMethod · 0.80
borrowMethod · 0.80
getMethod · 0.45
iterMethod · 0.45

Tested by

no test coverage detected