Auto: twincat-1.5 — ENUM/ALIAS discovery
Resolve TwinCAT symbol data types via the IDataType chain instead of a flat name match. ALIAS chains walk BaseType recursively (depth-capped at 16 against pathological cycles); ENUM surfaces its underlying integer base type. POINTER / REFERENCE / INTERFACE / UNION / STRUCT / ARRAY / FB remain explicitly out of scope and surface as null. Closes #309
This commit is contained in:
@@ -272,12 +272,50 @@ internal sealed class AdsTwinCATClient : ITwinCATClient
|
||||
foreach (ISymbol symbol in loader.Symbols)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) yield break;
|
||||
var mapped = MapSymbolTypeName(symbol.DataType?.Name);
|
||||
var mapped = ResolveSymbolDataType(symbol.DataType);
|
||||
var readOnly = !IsSymbolWritable(symbol);
|
||||
yield return new TwinCATDiscoveredSymbol(symbol.InstancePath, mapped, readOnly);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolve an IEC atomic <see cref="TwinCATDataType"/> for a TwinCAT symbol's data type.
|
||||
/// ENUMs surface as their underlying integer (the enum's <c>BaseType</c>); ALIAS chains
|
||||
/// are walked recursively via <see cref="IAliasType.BaseType"/> until an atomic primitive
|
||||
/// is reached. POINTER / REFERENCE / INTERFACE / UNION / STRUCT / FB / array types remain
|
||||
/// out of scope and surface as <c>null</c> so the caller skips them.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Recursion is bounded at <see cref="MaxAliasDepth"/> as a defence against pathological
|
||||
/// cycles in the type graph — TwinCAT shouldn't emit those, but this is cheap insurance.
|
||||
/// </remarks>
|
||||
internal const int MaxAliasDepth = 16;
|
||||
|
||||
internal static TwinCATDataType? ResolveSymbolDataType(IDataType? dataType)
|
||||
{
|
||||
var current = dataType;
|
||||
for (var depth = 0; current is not null && depth < MaxAliasDepth; depth++)
|
||||
{
|
||||
switch (current.Category)
|
||||
{
|
||||
case DataTypeCategory.Primitive:
|
||||
case DataTypeCategory.String:
|
||||
return MapSymbolTypeName(current.Name);
|
||||
case DataTypeCategory.Enum:
|
||||
case DataTypeCategory.Alias:
|
||||
// IEnumType : IAliasType, so BaseType walk handles both. For an enum the
|
||||
// base type is the underlying integer; for alias chains it's the next link.
|
||||
if (current is IAliasType alias) { current = alias.BaseType; continue; }
|
||||
return null;
|
||||
default:
|
||||
// POINTER / REFERENCE / INTERFACE / UNION / STRUCT / ARRAY / FB / Program —
|
||||
// explicitly out of scope at this PR.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TwinCATDataType? MapSymbolTypeName(string? typeName) => typeName switch
|
||||
{
|
||||
"BOOL" or "BIT" => TwinCATDataType.Bool,
|
||||
|
||||
Reference in New Issue
Block a user