Open Lexikos opened 7 months ago
Thanks for the detailed debugging.
I am currently creating an evaluation process and will refer to it.
I completely agree that the existsProperty and safeFetchProperty are unnecessary.
Prototype and Class may have been the target of the process because the source of the bug was not fully understood.
I was not aware of a way to work around the problem by setting depth to 0 to get the type. It would be a good workaround for a specific version as well as a good solution for other problems.
I am currently writing the evaluation process (For convenience, I refer to this evaluation machine as AELL for short for AutoHotkey Expression Like Language.), but I made some of the same mistakes because I was using a general evaluation method.
I should only do my own evaluation for things that property_get does not support, such as `a[ “k” “e” “y” ], and only need to do property_get once for everything else.
This report also brought a lot of inspiration. I thank you. I will do my best for a better debugger environment.
I am working on a transformer to optimise AELL ASTs in order to reduce the use of the property_get command as much as possible.
I then noticed two differences.
When retrieving a child element of a nested object, such as a.b.c
, the traditional method of retrieving it incrementally as a
, a.b
and a.b.c
results in the fullname
being a.b.c
and the name
as c
.
But if I get a.b.c
directly with property_get, both fullname
and name
are a.b.c
.
Is this difference a specification?
Property names are not part of the DBGp spec; they are language-specific.
fullname
is what you should pass back to property_get -n
to query the property.
name
has no real meaning. "This is the short part of the name, and is meant to be displayed in the IDE's UI." You can display whatever you want; the DBGp spec has no say in how you implement your UI.
If you are displaying properties in a hierarchal layout such as a tree, you probably want the short names c
, b
, a
. However, you don't get b
or a
by querying property_get -n a.b.c
.
If you were querying a property for a watch list or hover, you're probably going to display the full name a.b.c
, which is what property_get -n a.b.c
returns in name
.
Either way, you know which property you are querying and can display whatever you want without relying on fullname
or name
. Oftentimes, the property is already being displayed and there is no reason to consider getting its name from the response.
When property_get -n a
returns two levels of child properties, name
is the property name or index/key, and fullname
is derived from the caller-provided property name (a
) and the name
of each child property. By contrast, when you query property_get -n a.b.c
, the engine has only a.b.c
and no need to parse the short name from that. If it did choose some suffix as the short name, you would still need to make assumptions about the property name syntax (which is not formally defined) in order to determine the parent name.
Thank you for the explanation. I am convinced.
I didn't have a problem, but I didn't know if it was a bug or a specification, so I asked the question.
PS
I thought it was today's message, but now I realise I missed the notification...
There are several cases where the extension fails to get a property's value:
The last two are not supported in v2.0.13 or v2.1-alpha.9, but if they are supported by the engine, v1.11.0 of the extension still fails to show their values. The rest are supported by
property_get
and work correctly in other debug clients.v2.1-alpha.10 will be changing the debugger to enumerate inherited properties, but will omit
Base
and__Class
. When these properties are omitted, v1.11.0 of the extension fails to retrieve their values, even though the engine supports it.The current process for property evaluation is far less efficient than it should be. Due to the presence of dynamic properties, it can also have more side-effects than necessary. I did not fully understand what I was seeing at first, so did extensive debugging.
When a property value is requested, the extension currently appears to do the following:
context_names
command. AutoHotkey returns a constant string (regardless of the stack), but maybe there is some reason not to cache the result with AutoHotkey_H, or maybe not. If not, it is just adding latency for nothing, but this is not the main concern.x
, it returns true without sending any commands.x.y
, the loop iterates once and queriesx
. This causes the engine to enumerate own properties ofx
and evaluate all enumerated dynamic properties.y
exists as a child ofx
, the function returns true, the property exists. The property value, which was already evaluated by the engine and returned to the extension, is discarded.y
does not exist as a child ofx
, fetchInheritedProperty is called to recursively searchx.<base>
,x.<base>.<base>
, etc. Again, this causes the engine to evaluate all enumerated dynamic properties.x.y.z
orx.y[1]
, this process is repeated for the second component if it was determined thaty
exists withinx
.x
inx.y
orx.y
inx.y[1]
) is retrieved to determine its type, even though it was already retrieved by existsProperty.Auto-execute thread
stack frame, fetchProperty fetches the property (from context 0 first due to howevaluate
works) and then discards it.context
first and avoid callingsendPropertyGetCommand
if the workaround is to be applied.existsProperty
up to this point is wasted. It would be even better to perform the check at the beginning of the iteration inevaluate
, wherecontext
is retrieved fromcontexts
.Map.Prototype.Count
will correctly fail, as willA_Args.base.Length
both in script and by the debugger. If the user is hovering over something like that which attempts to evaluate a property on a prototype, applying the workaround to get a non-error result would be incorrect.Value
,VarType
, etc.) can be retrieved with this workaround, but I am unsure that there is ever a need to directly retrieve them. They can be considered like attributes of the parent COM object. They cannot be evaluated by script, so for instance,comObj.Value
should just invoke object, like withproperty_get -n comObj.Value
.The essence of the issue is that the extension uses a roundabout method to determine whether a property exists before querying it, instead of just querying the property, which in almost all cases will give the right answer (even if the answer is
undefined
).To demonstrate what I mean about evaluation of dynamic properties, this simple case prints
3
, buta
is 4 if the variable list is updated."Dynamic properties" include methods without getters. If
{x.a}
above is changed to{x.y}
(which is undefined), the following dynamic properties are evaluated by invoking the object (withObject::Invoke
, an internal virtual method similar in nature toIDispatch::Invoke
):Most of these cases just return the function object, but think about what happens if the bases have more dynamic properties. All I'm trying to do is retrieve the value of
x.y
, whichproperty_get -n x.y
gives. Maybe it is defined sometimes, or maybe I made a typo. (Side note: Perhaps there should be an option or format specifier to provide replacement text forunset
in the event that a property is undefined. Another side note: Maybe in future you will support hovering overx?.y
and similar.)I had one case where a property was being evaluated 10 times instead of once; or it might have been a separate property that shouldn't have been evaluated at all. I do not remember what combination of inheritance, property getters, debug directives and console, etc. triggered this.
If you wish to work around the fact that some properties cannot be retrieved directly, I suggest this approach:
.name[]
or[]
and query again with depth = 0 to determine its type. This will avoid executing any property getters.I suppose that it would only be needed if hovering over something like
match.Pos[2]
in v1. Actually, v2 hasmatch.Pos[2]
but doesn't return it in the parent property.property_get
will be able to retrieve it in v2.0.14 and v2.1-alpha.10.