feat: improve tree-sitter syntax highlighting with named nodes
- Add aliases for keywords (VAR_INPUT, BEGIN, IF, etc.) as named nodes - Add aliases for built-in types (INT, BOOL, STRING, etc.) as type_builtin - Add aliases for constants (TRUE, FALSE) - Add aliases for operators (AND, OR, NOT, MOD) - Add prefix node for # variable prefix highlighting - Highlight FB instance names in calls - Highlight FB parameter names as properties - Update README with detailed syntax highlighting features - Update .gitignore for *.wasm files
This commit is contained in:
+118
-46
@@ -85,6 +85,13 @@ local function parse_scl_type_file(content)
|
||||
local current_type_name = nil
|
||||
local pending_type_name = nil
|
||||
|
||||
local in_fb = false
|
||||
local fb_name = nil
|
||||
local fb_inputs = {}
|
||||
local fb_outputs = {}
|
||||
local fb_inouts = {}
|
||||
local current_fb_section = nil
|
||||
|
||||
content = content:gsub("^([\239\187\191]+)", "")
|
||||
|
||||
local lines = {}
|
||||
@@ -93,58 +100,123 @@ local function parse_scl_type_file(content)
|
||||
for i, line in ipairs(lines) do
|
||||
local trimmed = line:gsub("^%s+", ""):gsub("%s+$", "")
|
||||
|
||||
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
|
||||
local fb_match = trimmed:match('^FUNCTION_BLOCK%s+"([^"]+)"') or trimmed:match("^FUNCTION_BLOCK%s+(%w+)")
|
||||
if fb_match then
|
||||
in_fb = true
|
||||
fb_name = fb_match
|
||||
fb_inputs = {}
|
||||
fb_outputs = {}
|
||||
fb_inouts = {}
|
||||
current_fb_section = nil
|
||||
elseif in_fb and trimmed:match("^END_FUNCTION_BLOCK") then
|
||||
if fb_name and (#fb_inputs > 0 or #fb_outputs > 0 or #fb_inouts > 0) then
|
||||
types[fb_name] = {
|
||||
name = fb_name,
|
||||
kind = "function_block",
|
||||
inputs = fb_inputs,
|
||||
outputs = fb_outputs,
|
||||
inouts = fb_inouts,
|
||||
source = "scl_file"
|
||||
}
|
||||
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") or trimmed:match("^END_STRUCT;") then
|
||||
in_fb = false
|
||||
fb_name = nil
|
||||
fb_inputs = {}
|
||||
fb_outputs = {}
|
||||
fb_inouts = {}
|
||||
current_fb_section = nil
|
||||
elseif in_fb then
|
||||
if trimmed:match("^VAR_INPUT") then
|
||||
current_fb_section = "input"
|
||||
elseif trimmed:match("^VAR_OUTPUT") then
|
||||
current_fb_section = "output"
|
||||
elseif trimmed:match("^VAR_IN_OUT") then
|
||||
current_fb_section = "inout"
|
||||
elseif trimmed:match("^VAR%s") or trimmed:match("^VAR%s*$") then
|
||||
current_fb_section = nil
|
||||
elseif trimmed:match("^VAR_TEMP") then
|
||||
current_fb_section = nil
|
||||
elseif trimmed:match("^END_VAR") then
|
||||
current_fb_section = nil
|
||||
elseif current_fb_section then
|
||||
local field_name = line:match("^%s*(%w+)")
|
||||
if field_name and not trimmed:match("^%(%*") then
|
||||
local field_type = line:match(":%s*([^;]+)")
|
||||
if field_type then
|
||||
local attr_match = field_type:match("%{%s*[^%}]+%%s*%}%s*:%s*(.+)$")
|
||||
if attr_match then
|
||||
field_type = attr_match
|
||||
end
|
||||
field_type = field_type:gsub("%s*;.*$", "")
|
||||
field_type = field_type:gsub("^%s+", ""):gsub("%s+$", "")
|
||||
local field_comment = line:match("//%s*(.+)$") or line:match("%(%*(.-)%*%)")
|
||||
local field = { name = field_name, type = field_type, comment = field_comment }
|
||||
if current_fb_section == "input" then
|
||||
table.insert(fb_inputs, field)
|
||||
elseif current_fb_section == "output" then
|
||||
table.insert(fb_outputs, field)
|
||||
elseif current_fb_section == "inout" then
|
||||
table.insert(fb_inouts, field)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not in_fb 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
|
||||
elseif trimmed:match("^STRUCT") then
|
||||
if pending_type_name then
|
||||
current_type_name = pending_type_name
|
||||
in_struct = true
|
||||
types[pending_type_name] = { name = pending_type_name, kind = "struct", fields = {}, source = "data_types_folder" }
|
||||
pending_type_name = nil
|
||||
end
|
||||
elseif not in_struct and trimmed:match("^%w+%s*:") and not trimmed:match("^STRUCT") then
|
||||
local type_name = trimmed:match("^(%w+)%s*:")
|
||||
local type_name = trimmed:match('TYPE%s+"([^"]+)"') or trimmed:match("^TYPE%s+(%w+)")
|
||||
if type_name then
|
||||
local next_line = lines[i + 1]
|
||||
local next_trimmed = next_line and next_line:gsub("^%s+", ""):gsub("%s+$", "")
|
||||
if next_trimmed and next_trimmed:match("^STRUCT") then
|
||||
pending_type_name = type_name
|
||||
else
|
||||
pending_type_name = nil
|
||||
current_type_name = nil
|
||||
in_struct = false
|
||||
local base_type = trimmed:match(":%s*([%w_]+)")
|
||||
types[type_name] = { name = type_name, kind = "alias", base_type = base_type or "UNKNOWN", source = "data_types_folder" }
|
||||
end
|
||||
pending_type_name = type_name
|
||||
end
|
||||
elseif in_struct and current_type_name and types[current_type_name] then
|
||||
local field_name = line:match("^%s*(%w+)%s*:")
|
||||
if field_name and field_name ~= "END_STRUCT" then
|
||||
local field_type = line:match(":%s*([%w_]+)")
|
||||
table.insert(types[current_type_name].fields, {
|
||||
name = field_name,
|
||||
type = field_type or "unknown",
|
||||
})
|
||||
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") or trimmed:match("^END_STRUCT;") then
|
||||
in_struct = false
|
||||
current_type_name = nil
|
||||
pending_type_name = nil
|
||||
elseif trimmed:match("^STRUCT") then
|
||||
if pending_type_name then
|
||||
current_type_name = pending_type_name
|
||||
in_struct = true
|
||||
types[pending_type_name] = { name = pending_type_name, kind = "struct", fields = {}, source = "data_types_folder" }
|
||||
pending_type_name = nil
|
||||
end
|
||||
elseif not in_struct and trimmed:match("^%w+%s*:") and not trimmed:match("^STRUCT") then
|
||||
local type_name = trimmed:match("^(%w+)%s*:")
|
||||
if type_name then
|
||||
local next_line = lines[i + 1]
|
||||
local next_trimmed = next_line and next_line:gsub("^%s+", ""):gsub("%s+$", "")
|
||||
if next_trimmed and next_trimmed:match("^STRUCT") then
|
||||
pending_type_name = type_name
|
||||
else
|
||||
pending_type_name = nil
|
||||
current_type_name = nil
|
||||
in_struct = false
|
||||
local base_type = trimmed:match(":%s*([%w_]+)")
|
||||
types[type_name] = { name = type_name, kind = "alias", base_type = base_type or "UNKNOWN", source = "data_types_folder" }
|
||||
end
|
||||
end
|
||||
elseif in_struct and current_type_name and types[current_type_name] then
|
||||
local field_name = line:match("^%s*(%w+)%s*:")
|
||||
if field_name and field_name ~= "END_STRUCT" then
|
||||
local field_type = line:match(":%s*([%w_]+)")
|
||||
table.insert(types[current_type_name].fields, {
|
||||
name = field_name,
|
||||
type = field_type or "unknown",
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user