feat: add builtin types/functions to diagnostics and completions

Files Modified/Created:
- src/builtin_instructions.lua - NEW: Contains all TIA Portal built-in types, FBs, and functions
- src/diagnostics.lua - Added missing data types + builtin instruction checking
- src/main.lua - Added completion support for built-in types/F Bs/functions
- src/plc_json.lua - Added .db file parsing + BOM handling fixes
- lua/scl/blink_cmp_source.lua - Extended completion with all built-in types/F Bs/functions
- src/node-types.json - Added node types for parser
- AGENTS.md - Updated documentation
Features Added:
1. Diagnostics - No more false "Unknown data type" warnings for:
   - All elementary types (USINT, SINT, UINT, UDINT, LINT, ULINT, TOD, DTL, etc.)
   - Timer/counter types (IEC_TON, TOF, TP, CTU, CTD, CTUD)
   - TIA Portal built-in FBs and functions
2. Auto-completion - Shows in VAR section after ::
   - 28 elementary data types
   - 23 built-in function blocks (TON, TOF, TP, CTU, CTD, CTUD, R_TRIG, F_TRIG, etc.)
   - 80+ built-in functions (ADD, SUB, MUL, DIV, SIN, COS, SQRT, etc.)
This commit is contained in:
2026-02-20 13:08:28 +01:00
parent 625646176c
commit dfa4ef3381
6 changed files with 425 additions and 6 deletions
+68 -2
View File
@@ -85,24 +85,33 @@ local function parse_scl_type_file(content)
local current_type_name = nil
local pending_type_name = nil
content = content:gsub("^([\239\187\191]+)", "")
local lines = {}
for line in content:gmatch("[^\n]+") do table.insert(lines, line) end
for i, line in ipairs(lines) do
local trimmed = line:gsub("^%s+", ""):gsub("%s+$", "")
if trimmed:match("^TYPE%s*:?%s*$") then
if trimmed:match("^TYPE%s") or trimmed:match('^TYPE"') or trimmed == "TYPE" then
in_type = true
in_struct = false
current_type_name = nil
pending_type_name = nil
local type_name = trimmed:match('TYPE%s+"([^"]+)"') or trimmed:match("^TYPE%s+(%w+)")
if type_name then
pending_type_name = type_name
end
in_struct = false
current_type_name = nil
pending_type_name = nil
elseif trimmed:match("^END_TYPE") then
in_type = false
in_struct = false
current_type_name = nil
pending_type_name = nil
elseif in_type then
if trimmed:match("^END_STRUCT") then
if trimmed:match("^END_STRUCT") or trimmed:match("^END_STRUCT;") then
in_struct = false
current_type_name = nil
pending_type_name = nil
@@ -144,6 +153,48 @@ local function parse_scl_type_file(content)
return types
end
local function parse_db_file(content)
local types = {}
local in_var = false
local current_type_name = nil
content = content:gsub("^([\239\187\191]+)", "")
local lines = {}
for line in content:gmatch("[^\n]+") do table.insert(lines, line) end
for i, line in ipairs(lines) do
local trimmed = line:gsub("^%s+", ""):gsub("%s+$", "")
if trimmed:match('^DATA_BLOCK%s+"([^"]+)"') then
current_type_name = trimmed:match('^DATA_BLOCK%s+"([^"]+)"')
types[current_type_name] = {
name = current_type_name,
kind = "struct",
fields = {},
source = "db_file",
}
elseif trimmed:match("^END_VAR") then
in_var = false
elseif trimmed:match("^VAR%s*$") or trimmed:match("^VAR ") then
in_var = true
elseif in_var and current_type_name and types[current_type_name] and trimmed ~= "" and not trimmed:match("^//") then
local field_name = line:match("^%s*(%w+)%s*:")
if field_name then
local field_type = line:match(":%s*([%w_]+)")
if field_type then
table.insert(types[current_type_name].fields, {
name = field_name,
type = field_type,
})
end
end
end
end
return types
end
function M.load_types_from_workspace(root_dir)
local types = {}
@@ -213,6 +264,21 @@ function M.load_types_from_workspace(root_dir)
end
end
-- Also scan for .db files
local db_files = scan_files_recursive(root_dir, "*.db")
for _, filepath in ipairs(db_files) do
local content = run_command("cat " .. filepath:gsub(" ", "\\ "))
if content then
local db_types = parse_db_file(content)
for name, typ in pairs(db_types) do
typ.source = "db_file"
if not types[name] then
types[name] = typ
end
end
end
end
return types
end