fix: UDT type parsing and member access hover

- Fix UDT TYPE parsing: don't clear pending_type_name on VERSION/TITLE lines
- Fix UDT field type extraction: handle attribute blocks before colon
- Add comment capture for UDT type definitions
- Add better error messages when member resolution fails
- Handle quoted type names in field declarations
This commit is contained in:
2026-02-21 00:51:27 +01:00
parent d56ea306af
commit 99cf5d7732
+26 -9
View File
@@ -84,6 +84,7 @@ local function parse_scl_type_file(content)
local in_struct = false local in_struct = false
local current_type_name = nil local current_type_name = nil
local pending_type_name = nil local pending_type_name = nil
local pending_type_comment = nil
local in_fb = false local in_fb = false
local fb_name = nil local fb_name = nil
@@ -132,7 +133,7 @@ local function parse_scl_type_file(content)
current_fb_section = "output" current_fb_section = "output"
elseif trimmed:match("^VAR_IN_OUT") then elseif trimmed:match("^VAR_IN_OUT") then
current_fb_section = "inout" current_fb_section = "inout"
elseif trimmed:match("^VAR%s") or trimmed:match("^VAR%s*$") then elseif trimmed:match("^VAR%s") or trimmed:match("^VAR%s$") then
current_fb_section = nil current_fb_section = nil
elseif trimmed:match("^VAR_TEMP") then elseif trimmed:match("^VAR_TEMP") then
current_fb_section = nil current_fb_section = nil
@@ -169,33 +170,42 @@ local function parse_scl_type_file(content)
in_struct = false in_struct = false
current_type_name = nil current_type_name = nil
pending_type_name = nil pending_type_name = nil
pending_type_comment = nil
local type_name = trimmed:match('TYPE%s+"([^"]+)"') or trimmed:match("^TYPE%s+(%w+)") local type_name = trimmed:match('TYPE%s+"([^"]+)"') or trimmed:match("^TYPE%s+(%w+)")
if type_name then if type_name then
pending_type_name = type_name pending_type_name = type_name
end end
in_struct = false
current_type_name = nil
pending_type_name = nil
elseif trimmed:match("^END_TYPE") then elseif trimmed:match("^END_TYPE") then
in_type = false in_type = false
in_struct = false in_struct = false
current_type_name = nil current_type_name = nil
pending_type_name = nil pending_type_name = nil
pending_type_comment = nil
elseif in_type then elseif in_type then
if trimmed:match("^END_STRUCT") or trimmed:match("^END_STRUCT;") then -- Capture comments before STRUCT
if trimmed:match("^//") then
local comment = trimmed:match("^//%s*(.+)$")
if comment and pending_type_name then
pending_type_comment = comment
end
elseif trimmed:match("^END_STRUCT") or trimmed:match("^END_STRUCT;") then
in_struct = false in_struct = false
current_type_name = nil current_type_name = nil
pending_type_name = nil pending_type_name = nil
pending_type_comment = nil
elseif trimmed:match("^STRUCT") then elseif trimmed:match("^STRUCT") then
if pending_type_name then if pending_type_name then
current_type_name = pending_type_name current_type_name = pending_type_name
in_struct = true in_struct = true
types[pending_type_name] = { name = pending_type_name, kind = "struct", fields = {}, source = "data_types_folder" } types[pending_type_name] = { name = pending_type_name, kind = "struct", fields = {}, source = "data_types_folder", comment = pending_type_comment }
pending_type_name = nil pending_type_name = nil
pending_type_comment = nil
end end
elseif not in_struct and trimmed:match("^%w+%s*:") and not trimmed:match("^STRUCT") then elseif not in_struct and trimmed:match("^%w+%s*:") and not trimmed:match("^STRUCT") then
-- This is an alias type declaration (TypeName : BaseType;)
-- NOT VERSION, TITLE, etc.
local type_name = trimmed:match("^(%w+)%s*:") local type_name = trimmed:match("^(%w+)%s*:")
if type_name then if type_name and type_name ~= "VERSION" and type_name ~= "TITLE" then
local next_line = lines[i + 1] local next_line = lines[i + 1]
local next_trimmed = next_line and next_line:gsub("^%s+", ""):gsub("%s+$", "") local next_trimmed = next_line and next_line:gsub("^%s+", ""):gsub("%s+$", "")
if next_trimmed and next_trimmed:match("^STRUCT") then if next_trimmed and next_trimmed:match("^STRUCT") then
@@ -209,9 +219,16 @@ local function parse_scl_type_file(content)
end end
end end
elseif in_struct and current_type_name and types[current_type_name] then elseif in_struct and current_type_name and types[current_type_name] then
local field_name = line:match("^%s*(%w+)%s*:") local field_name = line:match("^%s*(%w+)%s*{") or line:match("^%s*(%w+)%s*:")
if field_name and field_name ~= "END_STRUCT" then if field_name and field_name ~= "END_STRUCT" then
local field_type = line:match(":%s*([%w_]+)") -- Remove attribute blocks before extracting type
local clean_line = line:gsub("%b{}", "")
-- Extract field type - handle both quoted and unquoted types
local field_type = clean_line:match(':%s*"([^"]+)"') or clean_line:match(":%s*([%w_]+)")
-- Also handle array types
if not field_type then
field_type = clean_line:match(":%s*(ARRAY.+)")
end
local field_comment = line:match("//%s*(.+)$") or line:match("%(%*(.-)%*%)") local field_comment = line:match("//%s*(.+)$") or line:match("%(%*(.-)%*%)")
table.insert(types[current_type_name].fields, { table.insert(types[current_type_name].fields, {
name = field_name, name = field_name,