diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2025-12-08 00:33:14 -0700 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2025-12-08 00:33:14 -0700 |
| commit | 4ec9d71f89e2cdc80ec57b7da99b17f0f9d6ec8f (patch) | |
| tree | df872660dfb68772660634e9003adabc5c5c62b1 /vim | |
| parent | 8d5ebd16125af02902a4e437f9295ad732c4dd1f (diff) | |
| download | fiddle-4ec9d71f89e2cdc80ec57b7da99b17f0f9d6ec8f.tar.gz fiddle-4ec9d71f89e2cdc80ec57b7da99b17f0f9d6ec8f.tar.bz2 fiddle-4ec9d71f89e2cdc80ec57b7da99b17f0f9d6ec8f.zip | |
Add tree sitter grammar for Fiddle.
Diffstat (limited to 'vim')
| -rw-r--r-- | vim/ftdetect/fiddle.vim | 1 | ||||
| -rw-r--r-- | vim/plugin/ts.vim | 14 | ||||
| -rw-r--r-- | vim/queries/fiddle/highlights.scm | 38 | ||||
| -rw-r--r-- | vim/treesitter/grammar.js | 240 | ||||
| -rw-r--r-- | vim/treesitter/package.json | 49 |
5 files changed, 342 insertions, 0 deletions
diff --git a/vim/ftdetect/fiddle.vim b/vim/ftdetect/fiddle.vim new file mode 100644 index 0000000..ddd2d16 --- /dev/null +++ b/vim/ftdetect/fiddle.vim @@ -0,0 +1 @@ +au BufRead,BufNewFile *.fiddle,*.fdl set filetype=fiddle diff --git a/vim/plugin/ts.vim b/vim/plugin/ts.vim new file mode 100644 index 0000000..c64a265 --- /dev/null +++ b/vim/plugin/ts.vim @@ -0,0 +1,14 @@ + +lua <<EOF + local parser_config = require("nvim-treesitter.parsers").get_parser_configs() + + parser_config.fiddle = { + install_info = { + url = "/home/rahm/Projects/fiddle/tree-sitter-fiddle", -- adjust to where the folder lives + files = { "src/parser.c" }, + generate_requires_npm = true, + requires_generate_from_grammar = true, + }, + filetype = "fiddle", + } +EOF diff --git a/vim/queries/fiddle/highlights.scm b/vim/queries/fiddle/highlights.scm new file mode 100644 index 0000000..57b2611 --- /dev/null +++ b/vim/queries/fiddle/highlights.scm @@ -0,0 +1,38 @@ +; Keywords +[ + "package" "import" "using" "option" "location" "bits" "type" "instance" "at" + "struct" "union" "enum" "reg" "reserved" "assert_pos" "skip_to" "buffer" + "ro" "rw" "wo" +] @keyword + +; Keep directives preproc-colored and suppress nested captures +((directive) @attribute (#set! "priority" 120)) +((directive (directive_element) @none) (#set! "priority" 121)) +((directive (directive_element (identifier) @none)) (#set! "priority" 121)) +((directive (directive_element (directive_value (string) @none))) (#set! "priority" 121)) +((directive (directive_element (directive_value (number) @none))) (#set! "priority" 121)) + +[ + "(" ")" "[" "]" "{" "}" ";" +] @punctuation.bracket + +[ + ":" "," "." "=" ";" +] @punctuation.delimiter + +"@" @operator + +(identifier) @variable +(name (identifier) @type) + +(string) @string +(number) @number + +(line_comment) @comment +(doc_comment) @comment.documentation + +(bits_decl name: (identifier) @type) +(type_decl name: (identifier) @type) +(instance_decl name: (identifier) @variable) +(register_decl name: (identifier) @function) +(register_bits_decl name: (identifier) @field) diff --git a/vim/treesitter/grammar.js b/vim/treesitter/grammar.js new file mode 100644 index 0000000..6644f81 --- /dev/null +++ b/vim/treesitter/grammar.js @@ -0,0 +1,240 @@ +// Tree-sitter grammar for the Fiddle hardware layout DSL. +// Mirrors the language accepted by src/Language/Fiddle/Parser.hs. + +const commaSep1 = (rule) => seq(rule, repeat(seq(',', rule))); +const commaSep = (rule) => optional(commaSep1(rule)); + +module.exports = grammar({ + name: 'fiddle', + + extras: ($) => [/\s/, $.line_comment, $.doc_comment], + + word: ($) => $.identifier, + + rules: { + source_file: ($) => repeat($.declaration), + + declaration: ($) => + seq(repeat($.directive), choice( + $.option_decl, + $.package_decl, + $.using_decl, + $.import_decl, + $.location_decl, + $.bits_decl, + $.type_decl, + $.instance_decl + ), ';'), + + option_decl: ($) => + seq( + 'option', + field('name', $.identifier), + field('value', $.identifier) + ), + + package_decl: ($) => + seq( + 'package', + field('name', $.name), + field('body', $.package_body) + ), + + package_body: ($) => + seq( + '{', + repeat(seq(repeat($.directive), choice( + $.option_decl, + $.using_decl, + $.import_decl, + $.location_decl, + $.bits_decl, + $.type_decl, + $.instance_decl + ), ';')), + '}' + ), + + import_decl: ($) => + seq( + 'import', + field('path', $.string), + field('list', optional($.import_list)) + ), + + import_list: ($) => seq('(', commaSep1($.identifier), ')'), + + using_decl: ($) => seq('using', field('name', $.name)), + + location_decl: ($) => + seq( + 'location', + field('name', $.identifier), + '=', + field('value', $.const_expression) + ), + + bits_decl: ($) => + seq( + 'bits', + field('name', $.identifier), + ':', + field('type', $.bit_type) + ), + + bit_type: ($) => + choice( + seq('(', field('width', $.expression), ')'), + seq('enum', field('width', $.expr_paren), field('body', $.enum_body)) + ), + + enum_body: ($) => + seq('{', commaSep(seq(repeat($.directive), $.enum_constant)), optional(','), '}'), + + enum_constant: ($) => + choice( + seq('reserved', '=', field('value', $.expression)), + seq(field('name', $.identifier), '=', field('value', $.const_expression)) + ), + + type_decl: ($) => + seq( + 'type', + field('name', $.identifier), + ':', + field('kind', $.body_type), + field('body', $.obj_type_body) + ), + + instance_decl: ($) => + seq( + 'instance', + field('name', $.identifier), + 'at', + field('address', $.expression), + ':', + field('type', $.obj_type) + ), + + obj_type: ($) => + seq( + field('base', choice( + $.name, + seq(field('kind', $.body_type), field('body', $.obj_type_body)) + )), + repeat($.array_extent) + ), + + obj_type_body: ($) => + seq( + '{', + repeat(seq(repeat($.directive), $.obj_type_decl, ';')), + '}' + ), + + obj_type_decl: ($) => + choice( + seq('assert_pos', field('target', $.expr_paren)), + seq('skip_to', field('offset', $.expr_paren)), + seq('buffer', field('name', optional($.identifier)), field('size', $.expr_paren)), + seq('reserved', field('size', $.expr_paren)), + seq(field('kind', $.body_type), field('body', $.obj_type_body), field('name', optional($.identifier))), + $.register_decl + ), + + register_decl: ($) => + seq( + field('modifier', optional($.modifier)), + 'reg', + field('name', optional($.identifier)), + field('width', $.expr_paren), + field('position', optional(seq('@', $.number))), + field('body', optional(seq(':', $.register_body))) + ), + + modifier: ($) => choice('ro', 'rw', 'wo'), + + register_body: ($) => + seq( + field('kind', $.bit_body_type), + field('body', $.register_bits_body) + ), + + bit_body_type: ($) => choice('struct', 'union'), + + register_bits_body: ($) => + seq( + '{', + repeat(seq(repeat($.directive), $.register_bits_decl, ';')), + '}' + ), + + register_bits_decl: ($) => + choice( + seq('reserved', field('size', $.expr_paren)), + seq( + field('modifier', optional($.modifier)), + choice( + seq(field('body', $.register_body), field('name', optional($.identifier))), + seq( + field('name', $.identifier), + ':', + field('type', $.register_bits_type_ref) + ) + ) + ) + ), + + register_bits_type_ref: ($) => + seq( + field('base', choice( + $.register_bits_width, + $.anonymous_bits_type, + $.name + )), + repeat($.array_extent) + ), + + register_bits_width: ($) => seq('(', field('width', $.const_expression), ')'), + + anonymous_bits_type: ($) => seq('enum', field('width', $.expr_paren), field('body', $.enum_body)), + + expr_paren: ($) => seq('(', $.expression, ')'), + + array_extent: ($) => seq('[', field('size', $.const_expression), ']'), + + body_type: ($) => choice('struct', 'union'), + + const_expression: ($) => $.expression, + + expression: ($) => choice($.number, $.name), + + name: ($) => seq($.identifier, repeat(seq('.', $.identifier))), + + directive: ($) => seq('[[', commaSep($.directive_element), ']]'), + + directive_element: ($) => + choice( + seq( + field('backend', $.identifier), + ':', + field('key', $.identifier), + optional(seq('=', field('value', $.directive_value))) + ), + seq(field('key', $.identifier), '=', field('value', $.directive_value)), + field('key', $.identifier) + ), + + directive_value: ($) => choice($.string, $.number), + + identifier: ($) => token(prec(-1, /[A-Za-z_][A-Za-z0-9_]*/)), + + number: ($) => token(/[0-9][0-9A-Za-z_]*/), + + string: ($) => token(seq('"', repeat(choice(/[^"\\]/, /\\./)), '"')), + + line_comment: ($) => token(seq('//', /.*/)), + + doc_comment: ($) => token(seq('/**', /[^*]*\*+(?:[^/*][^*]*\*+)*/, '/')), + }, +}); diff --git a/vim/treesitter/package.json b/vim/treesitter/package.json new file mode 100644 index 0000000..cb5c80d --- /dev/null +++ b/vim/treesitter/package.json @@ -0,0 +1,49 @@ +{ + "name": "tree-sitter-fiddle", + "version": "0.1.0", + "private": true, + "description": "Tree-sitter grammar for the Fiddle hardware memory layout DSL.", + "main": "grammar.js", + "types": "bindings/node", + "scripts": { + "generate": "tree-sitter generate", + "test": "tree-sitter test", + "install": "node-gyp-build", + "prebuildify": "prebuildify --napi --strip" + }, + "keywords": [ + "tree-sitter", + "fiddle", + "syntax", + "parser" + ], + "files": [ + "grammar.js", + "binding.gyp", + "prebuilds/**", + "bindings/node/*", + "queries/*", + "src/**" + ], + "devDependencies": { + "tree-sitter-cli": "^0.22.0", + "prebuildify": "^6.0.0" + }, + "dependencies": { + "node-gyp-build": "^4.8.0" + }, + "peerDependencies": { + "tree-sitter": "^0.21.0" + }, + "peerDependenciesMeta": { + "tree_sitter": { + "optional": true + } + }, + "tree-sitter": [ + { + "scope": "source.fiddle", + "injection-regex": "^fiddle$" + } + ] +} |