tree-sitter-ucode 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +49 -58
  2. package/grammar.js +214 -28
  3. package/markup/grammar.js +1057 -0
  4. package/markup/queries/folds.scm +20 -0
  5. package/markup/queries/highlights.scm +38 -0
  6. package/markup/queries/indents.scm +51 -0
  7. package/markup/queries/injections.scm +40 -0
  8. package/markup/queries/locals.scm +107 -0
  9. package/markup/queries/tags.scm +65 -0
  10. package/markup/queries/textobjects.scm +56 -0
  11. package/markup/src/grammar.json +5786 -0
  12. package/markup/src/node-types.json +3211 -0
  13. package/markup/src/parser.c +134461 -0
  14. package/markup/src/scanner.c +22 -0
  15. package/package.json +8 -7
  16. package/prebuilds/darwin-arm64/tree-sitter-ucode.node +0 -0
  17. package/prebuilds/linux-arm64/tree-sitter-ucode.node +0 -0
  18. package/prebuilds/linux-x64/tree-sitter-ucode.node +0 -0
  19. package/prebuilds/win32-x64/tree-sitter-ucode.node +0 -0
  20. package/queries/folds.scm +38 -0
  21. package/queries/highlights.scm +6 -0
  22. package/queries/indents.scm +63 -0
  23. package/queries/locals.scm +1 -0
  24. package/queries/textobjects.scm +84 -0
  25. package/scripts/generate-markup-grammar.js +93 -0
  26. package/src/grammar.json +1069 -226
  27. package/src/node-types.json +662 -8
  28. package/src/parser.c +106401 -25117
  29. package/src/scanner.c +16 -193
  30. package/src/scanner_impl.h +494 -0
  31. package/tree-sitter-ucode.wasm +0 -0
  32. package/tree-sitter-ucode_markup.wasm +0 -0
  33. package/tree-sitter.json +24 -12
  34. package/tmpl/grammar.js +0 -67
  35. package/tmpl/queries/highlights.scm +0 -23
  36. package/tmpl/queries/injections.scm +0 -8
  37. package/tmpl/queries/locals.scm +0 -3
  38. package/tmpl/src/grammar.json +0 -243
  39. package/tmpl/src/node-types.json +0 -230
  40. package/tmpl/src/parser.c +0 -707
  41. package/tmpl/src/scanner.c +0 -169
  42. package/tree-sitter-ucode_tmpl.wasm +0 -0
  43. /package/{tmpl → markup}/src/tree_sitter/alloc.h +0 -0
  44. /package/{tmpl → markup}/src/tree_sitter/array.h +0 -0
  45. /package/{tmpl → markup}/src/tree_sitter/parser.h +0 -0
@@ -0,0 +1,22 @@
1
+ /*
2
+ * External scanner for the ucode_markup grammar.
3
+ *
4
+ * All implementation lives in src/scanner_impl.h (static functions). This
5
+ * file only exports the five tree_sitter_ucode_markup_external_scanner_*
6
+ * entry points — no ucode_* symbols leak into this shared library.
7
+ */
8
+
9
+ #include "../../src/scanner_impl.h"
10
+
11
+ void *tree_sitter_ucode_markup_external_scanner_create(void) { return NULL; }
12
+ void tree_sitter_ucode_markup_external_scanner_destroy(void *p) { (void)p; }
13
+ unsigned tree_sitter_ucode_markup_external_scanner_serialize(void *p, char *b) { (void)p; (void)b; return 0; }
14
+ void tree_sitter_ucode_markup_external_scanner_deserialize(void *p, const char *b, unsigned n) {
15
+ (void)p; (void)b; (void)n;
16
+ }
17
+
18
+ bool tree_sitter_ucode_markup_external_scanner_scan(
19
+ void *payload, TSLexer *lexer, const bool *valid_symbols
20
+ ) {
21
+ return ucode_scanner_scan(payload, lexer, valid_symbols);
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter-ucode",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Ucode grammar for tree-sitter",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,9 +24,10 @@
24
24
  "bindings/node/*",
25
25
  "queries/*",
26
26
  "src/**",
27
- "tmpl/grammar.js",
28
- "tmpl/src/**",
29
- "tmpl/queries/*",
27
+ "markup/grammar.js",
28
+ "markup/src/**",
29
+ "markup/queries/*",
30
+ "scripts/generate-markup-grammar.js",
30
31
  "*.wasm"
31
32
  ],
32
33
  "dependencies": {
@@ -35,7 +36,7 @@
35
36
  },
36
37
  "devDependencies": {
37
38
  "prebuildify": "^6.0.1",
38
- "tree-sitter-cli": "^0.26.0"
39
+ "tree-sitter-cli": "0.26.9"
39
40
  },
40
41
  "peerDependencies": {
41
42
  "tree-sitter": "^0.22.0"
@@ -47,8 +48,8 @@
47
48
  },
48
49
  "scripts": {
49
50
  "install": "node-gyp-build",
50
- "build": "tree-sitter generate && tree-sitter generate tmpl/grammar.js --output tmpl/src && node-gyp-build && tree-sitter build --output ucode.so . && tree-sitter build --output ucode_tmpl.so ./tmpl",
51
- "test": "tree-sitter test && tree-sitter test -p tmpl",
51
+ "build": "node scripts/generate-markup-grammar.js && tree-sitter generate && tree-sitter generate markup/grammar.js --output markup/src && node-gyp-build && tree-sitter build --output ucode.so . && tree-sitter build --output ucode_markup.so ./markup",
52
+ "test": "node scripts/run-tests.js",
52
53
  "prestart": "tree-sitter build --wasm",
53
54
  "start": "tree-sitter playground"
54
55
  }
@@ -0,0 +1,38 @@
1
+ ; Fold queries for ucode.
2
+ ; Each captured node becomes a collapsible fold region.
3
+
4
+ ; -------------------------------------------------------------------------
5
+ ; Brace-delimited blocks
6
+ ;
7
+ ; statement_block covers brace-body function_declaration, function_expression,
8
+ ; and arrow_function bodies — the signature line stays visible because the
9
+ ; fold starts at '{', not at the 'function' keyword.
10
+ ; -------------------------------------------------------------------------
11
+
12
+ [
13
+ (statement_block)
14
+ (switch_body)
15
+ (object)
16
+ (array)
17
+ ] @fold
18
+
19
+ ; -------------------------------------------------------------------------
20
+ ; Alternative (colon/endif) syntax — fold the entire construct
21
+ ; -------------------------------------------------------------------------
22
+
23
+ [
24
+ (if_alt_statement)
25
+ (for_alt_statement)
26
+ (for_in_alt_statement)
27
+ (while_alt_statement)
28
+ ] @fold
29
+
30
+ ; -------------------------------------------------------------------------
31
+ ; Colon-body function declaration (function f(): ... endfunction)
32
+ ;
33
+ ; Brace-body function declarations are folded via (statement_block) above.
34
+ ; The colon form has no statement_block, so we fold the whole declaration.
35
+ ; We filter on "endfunction" so this pattern only matches the colon form.
36
+ ; -------------------------------------------------------------------------
37
+
38
+ (function_declaration "endfunction") @fold
@@ -119,6 +119,12 @@
119
119
  ["import" "export"] @keyword.import
120
120
  ["as" "from"] @keyword.import
121
121
 
122
+ ; 'default' in export context is a module keyword, not a conditional.
123
+ ; These patterns are more specific than the generic ["switch" "case" "default"]
124
+ ; below, so they take priority for 'default' tokens inside export constructs.
125
+ (export_statement "default" @keyword.import)
126
+ (export_specifier "default" @keyword.import)
127
+
122
128
  ; -------------------------------------------------------------------------
123
129
  ; Keywords — storage / operators
124
130
  ; -------------------------------------------------------------------------
@@ -0,0 +1,63 @@
1
+ ; Indentation queries for ucode.
2
+ ; Capture names follow the nvim-treesitter standard.
3
+
4
+ ; -------------------------------------------------------------------------
5
+ ; Brace-delimited constructs — increase indent inside
6
+ ; -------------------------------------------------------------------------
7
+
8
+ [
9
+ (statement_block)
10
+ (switch_body)
11
+ (object)
12
+ (array)
13
+ (arguments)
14
+ (formal_parameters)
15
+ ] @indent.begin
16
+
17
+ ; Closing delimiters — decrease indent
18
+ [
19
+ "}"
20
+ "]"
21
+ ")"
22
+ ] @indent.end
23
+
24
+ ; -------------------------------------------------------------------------
25
+ ; Alternative (colon/endif) syntax
26
+ ; -------------------------------------------------------------------------
27
+
28
+ ; The ':' after the condition opens the body
29
+ (if_alt_statement ":" @indent.begin)
30
+ (elif_clause ":" @indent.begin)
31
+ (for_alt_statement ":" @indent.begin)
32
+ (for_in_alt_statement ":" @indent.begin)
33
+ (while_alt_statement ":" @indent.begin)
34
+ (function_declaration ":" @indent.begin)
35
+
36
+ ; Closing keywords close the body
37
+ [
38
+ "endif"
39
+ "endfor"
40
+ "endwhile"
41
+ "endfunction"
42
+ ] @indent.end
43
+
44
+ ; -------------------------------------------------------------------------
45
+ ; Branch keywords (else/elif) — dedent keyword, indent following body
46
+ ; -------------------------------------------------------------------------
47
+
48
+ (else_clause "else") @indent.branch
49
+ (else_alt_clause "else") @indent.branch
50
+ (elif_clause "elif") @indent.branch
51
+
52
+ ; else_alt_clause has no ':' delimiter (grammar: 'else' repeat(statement)),
53
+ ; so @indent.branch alone only dedents the 'else' keyword — it does not
54
+ ; open an indent scope for the body. Add @indent.begin on the whole node
55
+ ; so the body statements are indented one level relative to 'else'.
56
+ (else_alt_clause) @indent.begin
57
+
58
+ ; -------------------------------------------------------------------------
59
+ ; Switch
60
+ ; -------------------------------------------------------------------------
61
+
62
+ (switch_case "case") @indent.branch
63
+ (switch_default "default") @indent.branch
@@ -5,6 +5,7 @@
5
5
  ; Scopes
6
6
  ; -------------------------------------------------------------------------
7
7
 
8
+ (program) @local.scope
8
9
  (function_declaration) @local.scope
9
10
  (function_expression) @local.scope
10
11
  (arrow_function) @local.scope
@@ -0,0 +1,84 @@
1
+ ; Text-object queries for nvim-treesitter-textobjects.
2
+ ; Provides @function, @parameter, @conditional, @loop, @call, and @block
3
+ ; text objects for ucode source files.
4
+
5
+ ; -------------------------------------------------------------------------
6
+ ; Functions
7
+ ; -------------------------------------------------------------------------
8
+
9
+ ; Brace-body function declaration
10
+ (function_declaration
11
+ body: (statement_block) @function.inner) @function.outer
12
+
13
+ ; Colon-body function declaration — outer only; no block node to target for inner
14
+ (function_declaration "endfunction") @function.outer
15
+
16
+ (function_expression
17
+ body: (statement_block) @function.inner) @function.outer
18
+
19
+ (arrow_function
20
+ body: (statement_block) @function.inner) @function.outer
21
+
22
+ ; Arrow function with expression body (no braces).
23
+ ; Uses the 'expression' supertype so all expression forms are matched
24
+ ; without an explicit enumeration — including update_expression (x => x++),
25
+ ; assignment_expression (x => y = 1), and any type added to the grammar later.
26
+ (arrow_function
27
+ body: (expression) @function.inner) @function.outer
28
+
29
+ ; -------------------------------------------------------------------------
30
+ ; Parameters
31
+ ;
32
+ ; @parameter.inner — the parameter node itself
33
+ ; @parameter.outer — same node; nvim-treesitter-textobjects extends the
34
+ ; selection to absorb adjacent ',' delimiters automatically when the
35
+ ; capture name ends in .outer
36
+ ; -------------------------------------------------------------------------
37
+
38
+ (formal_parameters (_) @parameter.inner)
39
+ (formal_parameters (_) @parameter.outer)
40
+
41
+ ; -------------------------------------------------------------------------
42
+ ; Conditionals
43
+ ; -------------------------------------------------------------------------
44
+
45
+ (if_statement
46
+ consequence: (statement_block) @conditional.inner) @conditional.outer
47
+
48
+ (if_alt_statement) @conditional.outer
49
+
50
+ ; -------------------------------------------------------------------------
51
+ ; Loops
52
+ ; -------------------------------------------------------------------------
53
+
54
+ (for_statement
55
+ body: (statement_block) @loop.inner) @loop.outer
56
+
57
+ (for_in_statement
58
+ body: (statement_block) @loop.inner) @loop.outer
59
+
60
+ (while_statement
61
+ body: (statement_block) @loop.inner) @loop.outer
62
+
63
+ (for_alt_statement) @loop.outer
64
+ (for_in_alt_statement) @loop.outer
65
+ (while_alt_statement) @loop.outer
66
+
67
+ ; -------------------------------------------------------------------------
68
+ ; Calls
69
+ ; -------------------------------------------------------------------------
70
+
71
+ (call_expression
72
+ arguments: (arguments) @call.inner) @call.outer
73
+
74
+ ; -------------------------------------------------------------------------
75
+ ; Blocks
76
+ ;
77
+ ; @block.outer — the full statement_block including braces
78
+ ; @block.inner — named children only; nvim-treesitter-textobjects selects
79
+ ; from the first to the last captured child, covering the block interior
80
+ ; without needing the deprecated #make-range! predicate
81
+ ; -------------------------------------------------------------------------
82
+
83
+ (statement_block) @block.outer
84
+ (statement_block (_) @block.inner)
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Generate markup/grammar.js from grammar.js.
4
+ *
5
+ * The main grammar has `program` as the first (start) rule so that `.uc`
6
+ * files work. For `.uc.tmpl` files we need `markup` to be the
7
+ * start rule. This script produces markup/grammar.js by:
8
+ *
9
+ * 1. Changing the grammar name from 'ucode' to 'ucode_markup'
10
+ * 2. Swapping the `markup` and `program` rule definitions so `markup`
11
+ * appears first (tree-sitter uses the first rule as the start rule)
12
+ *
13
+ * The generated file is checked in and rebuilt whenever grammar.js changes.
14
+ * Run via `npm run generate-markup` or as part of `npm run build`.
15
+ */
16
+
17
+ 'use strict';
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+
22
+ const srcPath = path.resolve(__dirname, '..', 'grammar.js');
23
+ const dstPath = path.resolve(__dirname, '..', 'markup', 'grammar.js');
24
+
25
+ let src = fs.readFileSync(srcPath, 'utf8');
26
+
27
+ // 1. Rename the grammar
28
+ src = src.replace(/name:\s*'ucode'/, "name: 'ucode_markup'");
29
+
30
+ // 2. Locate the `program` and `markup` rule definitions inside `rules: { ... }`.
31
+ // Each top-level rule starts with "\n <ident>: $ =>".
32
+ // We need to swap the two so `markup` comes first.
33
+
34
+ // Find the position of each rule's leading newline+spaces
35
+ const programMatch = src.match(/\n program: \$/);
36
+ const markupMatch = src.match(/\n markup: \$/);
37
+
38
+ if (!programMatch || !markupMatch) {
39
+ console.error('Could not locate program or markup rule in grammar.js');
40
+ process.exit(1);
41
+ }
42
+
43
+ const programIdx = src.indexOf('\n program: $');
44
+ const markupIdx = src.indexOf('\n markup: $');
45
+
46
+ if (programIdx === markupIdx) {
47
+ console.error('program and markup are at the same position?');
48
+ process.exit(1);
49
+ }
50
+
51
+ // Determine which comes first in the file
52
+ const firstIdx = Math.min(programIdx, markupIdx);
53
+ const secondIdx = Math.max(programIdx, markupIdx);
54
+
55
+ // Extract each rule: from its start up to the start of the next rule (or end-of-rules).
56
+ // A top-level rule starts at "\n <ident>: $" and ends just before the next "\n <ident>: $".
57
+ // We need the SPANS of the two rules to swap them.
58
+
59
+ function findNextRuleStart(text, from) {
60
+ // Match "\n <word>: $ =>" — the arrow function syntax uniquely identifies
61
+ // rule definitions vs. object properties at the same indentation level.
62
+ const re = /\n \w+: \$ =>/g;
63
+ re.lastIndex = from + 1; // skip the current match
64
+ const m = re.exec(text);
65
+ return m ? m.index : text.length;
66
+ }
67
+
68
+ const firstEnd = findNextRuleStart(src, firstIdx);
69
+ const secondEnd = findNextRuleStart(src, secondIdx);
70
+
71
+ const firstRule = src.slice(firstIdx, firstEnd);
72
+ const secondRule = src.slice(secondIdx, secondEnd);
73
+
74
+ // Reconstruct: everything before firstIdx, then the rule that was second,
75
+ // then everything between the two rules, then the rule that was first,
76
+ // then everything after secondEnd.
77
+ const between = src.slice(firstEnd, secondIdx);
78
+
79
+ const swapped =
80
+ src.slice(0, firstIdx) +
81
+ secondRule +
82
+ between +
83
+ firstRule +
84
+ src.slice(secondEnd);
85
+
86
+ // 3. Add a header comment noting this is generated
87
+ const header = '// GENERATED by scripts/generate-markup-grammar.js — do not edit by hand.\n';
88
+ const output = header + swapped;
89
+
90
+ fs.mkdirSync(path.dirname(dstPath), { recursive: true });
91
+ fs.writeFileSync(dstPath, output, 'utf8');
92
+
93
+ console.log(`Wrote ${path.relative(process.cwd(), dstPath)}`);