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:
+163
-86
@@ -13,6 +13,8 @@ module.exports = grammar({
|
||||
[$.region_statement],
|
||||
[$.region_name],
|
||||
[$.case_statement],
|
||||
[$.fb_call, $.function_call],
|
||||
[$.fb_parameter, $.parameter],
|
||||
[$.var_declaration, $.var_temp_declaration],
|
||||
[$.var_declaration, $.var_constant_declaration],
|
||||
[$.var_declaration, $.var_retain_declaration],
|
||||
@@ -31,36 +33,36 @@ module.exports = grammar({
|
||||
),
|
||||
|
||||
organization_block: $ => seq(
|
||||
'ORGANIZATION_BLOCK',
|
||||
alias('ORGANIZATION_BLOCK', $.keyword),
|
||||
field('name', $.string),
|
||||
optional(seq('TITLE', '=', choice($.string, $.identifier))),
|
||||
optional(seq(alias('TITLE', $.keyword), '=', choice($.string, $.identifier))),
|
||||
optional($.attribute_list),
|
||||
optional(seq('VERSION', ':', $.number)),
|
||||
optional(seq(alias('VERSION', $.keyword), ':', $.number)),
|
||||
repeat($.var_declaration),
|
||||
'BEGIN',
|
||||
alias('BEGIN', $.keyword),
|
||||
repeat($.statement),
|
||||
'END_ORGANIZATION_BLOCK'
|
||||
alias('END_ORGANIZATION_BLOCK', $.keyword)
|
||||
),
|
||||
|
||||
function_block: $ => seq(
|
||||
'FUNCTION_BLOCK',
|
||||
alias('FUNCTION_BLOCK', $.keyword),
|
||||
field('name', $.string),
|
||||
optional(seq('TITLE', '=', choice($.string, $.identifier))),
|
||||
optional(seq(alias('TITLE', $.keyword), '=', choice($.string, $.identifier))),
|
||||
optional($.attribute_list),
|
||||
optional(seq('VERSION', ':', $.number)),
|
||||
optional(seq(alias('VERSION', $.keyword), ':', $.number)),
|
||||
repeat($.var_declaration),
|
||||
'BEGIN',
|
||||
alias('BEGIN', $.keyword),
|
||||
repeat($.statement),
|
||||
'END_FUNCTION_BLOCK'
|
||||
alias('END_FUNCTION_BLOCK', $.keyword)
|
||||
),
|
||||
|
||||
function: $ => seq(
|
||||
'FUNCTION',
|
||||
alias('FUNCTION', $.keyword),
|
||||
field('name', $.string),
|
||||
optional(seq(':', $.type)),
|
||||
optional(seq('TITLE', '=', choice($.string, $.identifier))),
|
||||
optional(seq(alias('TITLE', $.keyword), '=', choice($.string, $.identifier))),
|
||||
optional($.attribute_list),
|
||||
optional(seq('VERSION', ':', $.number)),
|
||||
optional(seq(alias('VERSION', $.keyword), ':', $.number)),
|
||||
repeat(choice(
|
||||
$.var_declaration,
|
||||
$.var_temp_declaration,
|
||||
@@ -69,9 +71,9 @@ module.exports = grammar({
|
||||
$.var_non_retain_declaration,
|
||||
$.block_comment
|
||||
)),
|
||||
'BEGIN',
|
||||
alias('BEGIN', $.keyword),
|
||||
repeat($.statement),
|
||||
'END_FUNCTION'
|
||||
alias('END_FUNCTION', $.keyword)
|
||||
),
|
||||
|
||||
attribute_list: $ => seq(
|
||||
@@ -90,59 +92,60 @@ module.exports = grammar({
|
||||
|
||||
attribute_value: $ => choice(
|
||||
$.string,
|
||||
'TRUE', 'FALSE',
|
||||
alias('TRUE', $.constant),
|
||||
alias('FALSE', $.constant),
|
||||
$.identifier
|
||||
),
|
||||
|
||||
var_declaration: $ => seq(
|
||||
choice(
|
||||
'VAR_INPUT',
|
||||
'VAR_OUTPUT',
|
||||
'VAR_IN_OUT',
|
||||
'VAR',
|
||||
'VAR_TEMP',
|
||||
seq('VAR', 'CONSTANT'),
|
||||
seq('VAR', 'RETAIN'),
|
||||
seq('VAR', 'NON_RETAIN'),
|
||||
'VAR_CONSTANT',
|
||||
'VAR_RETAIN',
|
||||
'VAR_NON_RETAIN'
|
||||
alias('VAR_INPUT', $.keyword),
|
||||
alias('VAR_OUTPUT', $.keyword),
|
||||
alias('VAR_IN_OUT', $.keyword),
|
||||
alias('VAR', $.keyword),
|
||||
alias('VAR_TEMP', $.keyword),
|
||||
seq(alias('VAR', $.keyword), alias('CONSTANT', $.keyword)),
|
||||
seq(alias('VAR', $.keyword), alias('RETAIN', $.keyword)),
|
||||
seq(alias('VAR', $.keyword), alias('NON_RETAIN', $.keyword)),
|
||||
alias('VAR_CONSTANT', $.keyword),
|
||||
alias('VAR_RETAIN', $.keyword),
|
||||
alias('VAR_NON_RETAIN', $.keyword)
|
||||
),
|
||||
repeat(choice($.var_item, $.block_comment)),
|
||||
'END_VAR'
|
||||
alias('END_VAR', $.keyword)
|
||||
),
|
||||
|
||||
var_temp_declaration: $ => seq(
|
||||
'VAR_TEMP',
|
||||
alias('VAR_TEMP', $.keyword),
|
||||
repeat(choice($.var_item, $.block_comment)),
|
||||
'END_VAR'
|
||||
alias('END_VAR', $.keyword)
|
||||
),
|
||||
|
||||
var_constant_declaration: $ => seq(
|
||||
choice(
|
||||
seq('VAR', 'CONSTANT'),
|
||||
'VAR_CONSTANT'
|
||||
seq(alias('VAR', $.keyword), alias('CONSTANT', $.keyword)),
|
||||
alias('VAR_CONSTANT', $.keyword)
|
||||
),
|
||||
repeat(choice($.var_item, $.block_comment)),
|
||||
'END_VAR'
|
||||
alias('END_VAR', $.keyword)
|
||||
),
|
||||
|
||||
var_retain_declaration: $ => seq(
|
||||
choice(
|
||||
seq('VAR', 'RETAIN'),
|
||||
'VAR_RETAIN'
|
||||
seq(alias('VAR', $.keyword), alias('RETAIN', $.keyword)),
|
||||
alias('VAR_RETAIN', $.keyword)
|
||||
),
|
||||
repeat(choice($.var_item, $.block_comment)),
|
||||
'END_VAR'
|
||||
alias('END_VAR', $.keyword)
|
||||
),
|
||||
|
||||
var_non_retain_declaration: $ => seq(
|
||||
choice(
|
||||
seq('VAR', 'NON_RETAIN'),
|
||||
'VAR_NON_RETAIN'
|
||||
seq(alias('VAR', $.keyword), alias('NON_RETAIN', $.keyword)),
|
||||
alias('VAR_NON_RETAIN', $.keyword)
|
||||
),
|
||||
repeat(choice($.var_item, $.block_comment)),
|
||||
'END_VAR'
|
||||
alias('END_VAR', $.keyword)
|
||||
),
|
||||
|
||||
var_item: $ => seq(
|
||||
@@ -155,33 +158,69 @@ module.exports = grammar({
|
||||
),
|
||||
|
||||
type: $ => choice(
|
||||
'BOOL', 'Bool',
|
||||
'INT', 'Int', 'int',
|
||||
'DINT', 'DInt', 'dint',
|
||||
'SINT', 'SInt', 'sint',
|
||||
'USINT', 'USInt', 'usint',
|
||||
'UINT', 'UInt', 'uint',
|
||||
'WORD', 'Word', 'word',
|
||||
'DWORD', 'DWord', 'dword',
|
||||
'BYTE', 'Byte', 'byte',
|
||||
'REAL', 'Real', 'real',
|
||||
'LREAL', 'LReal', 'lreal',
|
||||
'TIME', 'Time', 'time',
|
||||
'TOD', 'Tod', 'tod',
|
||||
'DT', 'Dt', 'dt',
|
||||
'String', 'STRING', 'string',
|
||||
seq(choice('String', 'STRING', 'string'), '[', $.number, ']'),
|
||||
'WString', 'WSTRING', 'wstring',
|
||||
seq(choice('WString', 'WSTRING', 'wstring'), '[', $.number, ']'),
|
||||
'Char', 'CHAR', 'char',
|
||||
'WChar', 'WCHAR', 'wchar',
|
||||
seq('ARRAY', '[', $.number, '..', $.number, ']', 'OF', $.type),
|
||||
alias('BOOL', $.type_builtin),
|
||||
alias('Bool', $.type_builtin),
|
||||
alias('INT', $.type_builtin),
|
||||
alias('Int', $.type_builtin),
|
||||
alias('int', $.type_builtin),
|
||||
alias('DINT', $.type_builtin),
|
||||
alias('DInt', $.type_builtin),
|
||||
alias('dint', $.type_builtin),
|
||||
alias('SINT', $.type_builtin),
|
||||
alias('SInt', $.type_builtin),
|
||||
alias('sint', $.type_builtin),
|
||||
alias('USINT', $.type_builtin),
|
||||
alias('USInt', $.type_builtin),
|
||||
alias('usint', $.type_builtin),
|
||||
alias('UINT', $.type_builtin),
|
||||
alias('UInt', $.type_builtin),
|
||||
alias('uint', $.type_builtin),
|
||||
alias('WORD', $.type_builtin),
|
||||
alias('Word', $.type_builtin),
|
||||
alias('word', $.type_builtin),
|
||||
alias('DWORD', $.type_builtin),
|
||||
alias('DWord', $.type_builtin),
|
||||
alias('dword', $.type_builtin),
|
||||
alias('BYTE', $.type_builtin),
|
||||
alias('Byte', $.type_builtin),
|
||||
alias('byte', $.type_builtin),
|
||||
alias('REAL', $.type_builtin),
|
||||
alias('Real', $.type_builtin),
|
||||
alias('real', $.type_builtin),
|
||||
alias('LREAL', $.type_builtin),
|
||||
alias('LReal', $.type_builtin),
|
||||
alias('lreal', $.type_builtin),
|
||||
alias('TIME', $.type_builtin),
|
||||
alias('Time', $.type_builtin),
|
||||
alias('time', $.type_builtin),
|
||||
alias('TOD', $.type_builtin),
|
||||
alias('Tod', $.type_builtin),
|
||||
alias('tod', $.type_builtin),
|
||||
alias('DT', $.type_builtin),
|
||||
alias('Dt', $.type_builtin),
|
||||
alias('dt', $.type_builtin),
|
||||
alias('String', $.type_builtin),
|
||||
alias('STRING', $.type_builtin),
|
||||
alias('string', $.type_builtin),
|
||||
seq(choice(alias('String', $.type_builtin), alias('STRING', $.type_builtin), alias('string', $.type_builtin)), '[', $.number, ']'),
|
||||
alias('WString', $.type_builtin),
|
||||
alias('WSTRING', $.type_builtin),
|
||||
alias('wstring', $.type_builtin),
|
||||
seq(choice(alias('WString', $.type_builtin), alias('WSTRING', $.type_builtin), alias('wstring', $.type_builtin)), '[', $.number, ']'),
|
||||
alias('Char', $.type_builtin),
|
||||
alias('CHAR', $.type_builtin),
|
||||
alias('char', $.type_builtin),
|
||||
alias('WChar', $.type_builtin),
|
||||
alias('WCHAR', $.type_builtin),
|
||||
alias('wchar', $.type_builtin),
|
||||
seq(alias('ARRAY', $.keyword), '[', $.number, '..', $.number, ']', alias('OF', $.keyword), $.type),
|
||||
$.identifier,
|
||||
$.string
|
||||
),
|
||||
|
||||
statement: $ => choice(
|
||||
$.assignment,
|
||||
$.fb_call,
|
||||
$.if_statement,
|
||||
$.case_statement,
|
||||
$.for_statement,
|
||||
@@ -200,6 +239,26 @@ module.exports = grammar({
|
||||
),
|
||||
|
||||
empty_statement: $ => ';',
|
||||
|
||||
fb_call: $ => seq(
|
||||
field('instance', choice($.prefixed_identifier, $.identifier)),
|
||||
'(',
|
||||
optional(seq(
|
||||
$.fb_parameter_list
|
||||
)),
|
||||
')'
|
||||
),
|
||||
|
||||
fb_parameter_list: $ => seq(
|
||||
$.fb_parameter,
|
||||
repeat(seq(',', $.fb_parameter))
|
||||
),
|
||||
|
||||
fb_parameter: $ => seq(
|
||||
field('name', $.identifier),
|
||||
choice(':=', '=>'),
|
||||
$.expression
|
||||
),
|
||||
|
||||
assignment: $ => seq(
|
||||
field('target', $.lvalue),
|
||||
@@ -218,63 +277,83 @@ module.exports = grammar({
|
||||
|
||||
function_name: $ => $.string,
|
||||
|
||||
prefixed_identifier: $ => seq('#', $.identifier),
|
||||
prefixed_identifier: $ => seq(alias('#', $.prefix), $.identifier),
|
||||
|
||||
field_access: $ => seq($.lvalue, '.', choice($.identifier, $.prefixed_identifier)),
|
||||
|
||||
array_access: $ => seq($.lvalue, '[', $.expression, ']'),
|
||||
|
||||
if_statement: $ => seq(
|
||||
'IF', $.expression, 'THEN',
|
||||
alias('IF', $.keyword),
|
||||
$.expression,
|
||||
alias('THEN', $.keyword),
|
||||
repeat($.statement),
|
||||
repeat($.elsif_clause),
|
||||
optional($.else_clause),
|
||||
'END_IF'
|
||||
alias('END_IF', $.keyword)
|
||||
),
|
||||
|
||||
elsif_clause: $ => seq(
|
||||
'ELSIF', $.expression, 'THEN', repeat($.statement)
|
||||
alias('ELSIF', $.keyword),
|
||||
$.expression,
|
||||
alias('THEN', $.keyword),
|
||||
repeat($.statement)
|
||||
),
|
||||
|
||||
else_clause: $ => seq('ELSE', repeat($.statement)),
|
||||
else_clause: $ => seq(alias('ELSE', $.keyword), repeat($.statement)),
|
||||
|
||||
case_statement: $ => seq(
|
||||
'CASE', $.expression, 'OF',
|
||||
alias('CASE', $.keyword),
|
||||
$.expression,
|
||||
alias('OF', $.keyword),
|
||||
repeat($.case_item),
|
||||
optional($.else_clause),
|
||||
'END_CASE',
|
||||
alias('END_CASE', $.keyword),
|
||||
optional(';')
|
||||
),
|
||||
|
||||
case_item: $ => seq(
|
||||
choice($.number, $.identifier, $.prefixed_identifier, $.range),
|
||||
':', repeat($.statement)
|
||||
':',
|
||||
repeat($.statement)
|
||||
),
|
||||
|
||||
range: $ => seq($.number, '..', $.number),
|
||||
|
||||
for_statement: $ => seq(
|
||||
'FOR', $.identifier, ':=', $.expression, 'TO', $.expression, optional(seq('BY', $.expression)), 'DO',
|
||||
alias('FOR', $.keyword),
|
||||
$.identifier,
|
||||
':=',
|
||||
$.expression,
|
||||
alias('TO', $.keyword),
|
||||
$.expression,
|
||||
optional(seq(alias('BY', $.keyword), $.expression)),
|
||||
alias('DO', $.keyword),
|
||||
repeat($.statement),
|
||||
'END_FOR'
|
||||
alias('END_FOR', $.keyword)
|
||||
),
|
||||
|
||||
while_statement: $ => seq(
|
||||
'WHILE', $.expression, 'DO',
|
||||
alias('WHILE', $.keyword),
|
||||
$.expression,
|
||||
alias('DO', $.keyword),
|
||||
repeat($.statement),
|
||||
'END_WHILE'
|
||||
alias('END_WHILE', $.keyword)
|
||||
),
|
||||
|
||||
repeat_statement: $ => seq(
|
||||
'REPEAT',
|
||||
alias('REPEAT', $.keyword),
|
||||
repeat($.statement),
|
||||
'UNTIL', $.expression, 'END_REPEAT'
|
||||
alias('UNTIL', $.keyword),
|
||||
$.expression,
|
||||
alias('END_REPEAT', $.keyword)
|
||||
),
|
||||
|
||||
region_statement: $ => seq(
|
||||
'REGION', $.region_name,
|
||||
alias('REGION', $.keyword),
|
||||
$.region_name,
|
||||
repeat($.statement),
|
||||
'END_REGION',
|
||||
alias('END_REGION', $.keyword),
|
||||
optional($.region_name)
|
||||
),
|
||||
|
||||
@@ -320,19 +399,19 @@ module.exports = grammar({
|
||||
),
|
||||
|
||||
unary_expression: $ => prec.right(10, choice(
|
||||
seq('NOT', $.expression),
|
||||
seq(alias('NOT', $.operator), $.expression),
|
||||
seq('+', $.expression),
|
||||
seq('-', $.expression)
|
||||
)),
|
||||
|
||||
binary_expression: $ => choice(
|
||||
prec.left(2, seq($.expression, 'OR', $.expression)),
|
||||
prec.left(3, seq($.expression, 'XOR', $.expression)),
|
||||
prec.left(4, seq($.expression, 'AND', $.expression)),
|
||||
prec.left(2, seq($.expression, alias('OR', $.operator), $.expression)),
|
||||
prec.left(3, seq($.expression, alias('XOR', $.operator), $.expression)),
|
||||
prec.left(4, seq($.expression, alias('AND', $.operator), $.expression)),
|
||||
prec.left(5, seq($.expression, choice('=', '<>'), $.expression)),
|
||||
prec.left(6, seq($.expression, choice('<', '>', '<=', '>='), $.expression)),
|
||||
prec.left(7, seq($.expression, choice('+', '-'), $.expression)),
|
||||
prec.left(8, seq($.expression, choice('*', '/', 'MOD'), $.expression))
|
||||
prec.left(8, seq($.expression, choice('*', '/', alias('MOD', $.operator)), $.expression))
|
||||
),
|
||||
|
||||
number: $ => token(/\d+(\.\d+)?/),
|
||||
@@ -346,13 +425,11 @@ module.exports = grammar({
|
||||
seq('"', repeat(choice(/[^"\n]/, '""')), '"')
|
||||
),
|
||||
|
||||
// Support for STRING type with length: STRING[80]
|
||||
string_type: $ => seq(
|
||||
choice('STRING', 'String', 'string', 'WSTRING', 'WString', 'wstring'),
|
||||
choice(alias('STRING', $.type_builtin), alias('String', $.type_builtin), alias('string', $.type_builtin), alias('WSTRING', $.type_builtin), alias('WString', $.type_builtin), alias('wstring', $.type_builtin)),
|
||||
optional(seq('[', $.number, ']'))
|
||||
),
|
||||
|
||||
// Support for SCL character literals: 'A', WCHAR#'B'
|
||||
char_literal: $ => choice(
|
||||
seq("'", /[^']/, "'"),
|
||||
seq('WCHAR#', "'", /[^']/, "'")
|
||||
@@ -374,9 +451,9 @@ module.exports = grammar({
|
||||
'*/)'
|
||||
)),
|
||||
|
||||
exit_statement: $ => 'EXIT',
|
||||
exit_statement: $ => alias('EXIT', $.keyword),
|
||||
|
||||
continue_statement: $ => 'CONTINUE'
|
||||
continue_statement: $ => alias('CONTINUE', $.keyword)
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user