@gram-data/tree-sitter-gram 0.2.6 → 0.3.3

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.
package/README.md CHANGED
@@ -3,34 +3,93 @@
3
3
  A [tree-sitter](https://tree-sitter.github.io/tree-sitter/) grammar
4
4
  for [gram](https://gram-data.github.io) notation.
5
5
 
6
- Gram is a subject-based notation for structured data.
6
+ ## About Gram
7
7
 
8
- If this is an object:
9
- ```
10
- {
11
- "name":"Andreas",
12
- "roles":["author"]
8
+ Gram is a pattern-based notation for structured data.
9
+
10
+ ### Patterns and Subjects
11
+
12
+ A **pattern** is a generic data structure with a value and nested elements:
13
+
14
+ ```ts
15
+ interface Pattern<V> {
16
+ value: V;
17
+ elements: Pattern<V>[];
13
18
  }
14
19
  ```
15
20
 
16
- Implicitly the object is a person. To become a subject, the implicit
17
- information can be explicit.
21
+ Gram patterns are always `Pattern<Subject>` patterns where values are **subjects**.
22
+ A **subject** is content combining an optional identifier, labels, and/or a record of properties.
23
+
24
+ ### Pattern Elements
25
+
26
+ The `gram_pattern` (top-level structure) consists of a sequence of patterns. Syntactically, `subject_pattern`, `node_pattern`, `relationship_pattern`, and `annotated_pattern` are peers.
18
27
 
19
- As a subject:
28
+ They correlate to the underlying data structure based on the number of elements:
29
+
30
+ - **Node Pattern** `()`: A pattern with **0 elements**.
31
+ - **Annotated Pattern** `@a (b)`: A pattern with **1 element**.
32
+ - **Relationship Pattern** `(a)-->(b)`: A pattern with **2 elements**.
33
+ - **Subject Pattern** `[ s | ... ]`: A pattern with an **arbitrary number of elements**.
34
+
35
+ #### Path Flattening
36
+
37
+ A path is a flattened tree of relationships. For example:
38
+
39
+ ```gram
40
+ (a)-[r1]->(b)-[r2]->(c)
41
+ // is equivalent to:
42
+ [ | [r1 | (a), (b)], [r2 | (b),(c)] ]
20
43
  ```
21
- (:Person {
22
- name: "Andreas",
23
- roles: ["author"]
24
- })
44
+
45
+ #### Subject Pattern Notation
46
+
47
+ The subject pattern notation uses `[ subject | elements ]` to explicitly show pattern structure:
48
+
49
+ ```gram
50
+ // A team with members as elements
51
+ [devrel:Team {name: "Developer Relations"} | abk, adam, alex]
52
+
53
+ // A simple atomic pattern (no elements)
54
+ [:Person {name: "Andreas", roles: ["author"]}]
25
55
  ```
26
56
 
27
- Gram files support comments using `//` syntax for line-based and end-of-line comments:
57
+ #### Node Notation (Syntactic Sugar)
58
+
59
+ Parentheses `( subject )` provide familiar graph node syntax:
60
+
61
+ ```gram
62
+ () // Empty node
63
+ (a) // Node with identifier
64
+ (a:Person) // Node with identifier and label
65
+ (a:Person {name: "Alice"}) // Node with identifier, label, and properties
28
66
  ```
67
+
68
+ #### Relationship Notation (Syntactic Sugar)
69
+
70
+ Arrows connect nodes to express graph relationships:
71
+
72
+ ```gram
73
+ // Path notation for graph relationships
74
+ (a:Person)-[:KNOWS]->(b:Person)
75
+
76
+ // Subject Pattern notation can contain path patterns
77
+ [social:Graph |
78
+ (a:Person {name: "Alice"}),
79
+ (b:Person {name: "Bob"}),
80
+ (a)-[:KNOWS]->(b)
81
+ ]
82
+ ```
83
+
84
+ ### Comments
85
+
86
+ Gram files support comments using `//` syntax:
87
+ ```gram
29
88
  // This is a line comment
30
89
  (hello)-->(world) // End-of-line comment
31
90
  ```
32
91
 
33
- Learn more about `gram` at the [gram-data github org](https://github.com/gram-data) notation.
92
+ Learn more about `gram` at the [gram-data github org](https://github.com/gram-data).
34
93
 
35
94
  ## Editor Support
36
95
 
@@ -7,3 +7,31 @@ test("can load grammar", () => {
7
7
  const parser = new (require("tree-sitter"))();
8
8
  assert.doesNotThrow(() => parser.setLanguage(require(".")));
9
9
  });
10
+
11
+ test("annotation node kinds: identified_annotation and property_annotation", () => {
12
+ const Parser = require("tree-sitter");
13
+ const GramLang = require(".");
14
+ const parser = new Parser();
15
+ parser.setLanguage(GramLang);
16
+
17
+ const annotated = (root) => root.child(0) ?? null;
18
+
19
+ const withIdentified = parser.parse("@@p (a)");
20
+ const ap1 = annotated(withIdentified.rootNode);
21
+ assert(ap1?.type === "annotated_pattern", "root should have annotated_pattern child");
22
+ const annotations1 = ap1.childForFieldName("annotations");
23
+ assert(annotations1, "annotations node should exist");
24
+ const first1 = annotations1.child(0);
25
+ assert.strictEqual(first1?.type, "identified_annotation", "@@ form should be identified_annotation");
26
+ assert(first1?.childForFieldName("identifier"), "identified_annotation should have identifier field");
27
+
28
+ const withProperty = parser.parse("@x(1) ()");
29
+ const ap2 = annotated(withProperty.rootNode);
30
+ assert(ap2?.type === "annotated_pattern", "root should have annotated_pattern child");
31
+ const annotations2 = ap2.childForFieldName("annotations");
32
+ assert(annotations2, "annotations node should exist");
33
+ const first2 = annotations2.child(0);
34
+ assert.strictEqual(first2?.type, "property_annotation", "@ form should be property_annotation");
35
+ assert(first2?.childForFieldName("key"), "property_annotation should have key field");
36
+ assert(first2?.childForFieldName("value"), "property_annotation should have value field");
37
+ });
package/editors/README.md CHANGED
@@ -25,7 +25,7 @@ The Zed integration provides full syntax highlighting and language support for G
25
25
 
26
26
  **Features:**
27
27
  - Syntax highlighting for all Gram constructs
28
- - Bracket matching for `()`, `[]`, and `{}`
28
+ - Subject Pattern matching for `()`, `[]`, and `{}`
29
29
  - Automatic file type detection for `.gram` files
30
30
  - Proper indentation handling
31
31
 
@@ -5,7 +5,7 @@ A [Zed](https://zed.dev) extension providing syntax highlighting and language su
5
5
  ## Features
6
6
 
7
7
  - **Syntax Highlighting**: Full syntax highlighting for all Gram constructs including subjects, nodes, relationships, and data types
8
- - **Bracket Matching**: Automatic matching for `()`, `[]`, and `{}`
8
+ - **Subject Pattern Matching**: Automatic matching for `()`, `[]`, and `{}`
9
9
  - **File Type Detection**: Automatic recognition of `.gram` files
10
10
  - **Smart Indentation**: Proper indentation handling for nested structures
11
11
 
@@ -53,7 +53,7 @@ Once installed, the extension automatically provides syntax highlighting for any
53
53
  })
54
54
 
55
55
  // Relationships between nodes
56
- (alice:Person {name: "Alice"})->(bob:Person {name: "Bob"})
56
+ (alice:Person {name: "Alice"})-->(bob:Person {name: "Bob"})
57
57
 
58
58
  // Complex subject with annotations
59
59
  @type("Employee")
@@ -80,7 +80,7 @@ Once installed, the extension automatically provides syntax highlighting for any
80
80
 
81
81
  The extension provides highlighting for:
82
82
 
83
- - **Brackets**: `[...]` and `[:type ...]` bracket notation (containing subjects)
83
+ - **Subject Patterns**: `[...]` and `[:type ...]` subject pattern notation (containing subjects)
84
84
  - **Nodes**: `(...)` parentheses
85
85
  - **Relationships**: `->`, `--`, `<-`, `<-->`, etc.
86
86
  - **Strings**: Single, double, and backtick quoted strings
@@ -1,6 +1,6 @@
1
1
  id = "gram"
2
2
  name = "Gram Language Support"
3
- version = "0.2.6"
3
+ version = "0.3.3"
4
4
  schema_version = 1
5
5
  authors = ["Gram Data Contributors"]
6
6
  description = "Support for Gram notation - a subject-oriented notation for structured data"
@@ -8,4 +8,4 @@ description = "Support for Gram notation - a subject-oriented notation for struc
8
8
  # path = "grammars/tree-sitter-gram"
9
9
  [grammars.gram]
10
10
  repository = "https://github.com/gram-data/tree-sitter-gram"
11
- rev = "7385463cf814f2e880e99c3e1372b4c0765820ad"
11
+ rev = "78fba591ce4e3ca86ae77c871cfc9e87205c8e2b"
@@ -23,7 +23,7 @@
23
23
  "::"
24
24
  ] @operator
25
25
 
26
- ; Brackets and delimiters
26
+ ; Subject Patterns and delimiters
27
27
  [
28
28
  "["
29
29
  "]"
@@ -46,10 +46,12 @@
46
46
  (map_entry key: (string_literal) @property)
47
47
  (map_entry key: (integer) @property)
48
48
 
49
- ; Annotation keys
50
- (annotation key: (symbol) @attribute)
49
+ ; Annotation keys (property-style) and headers (identified/label-style)
50
+ (property_annotation key: (symbol) @attribute)
51
+ (identified_annotation identifier: (_) @attribute)
52
+ (identified_annotation labels: (_) @attribute)
51
53
 
52
- ; Bracket notation (special highlighting)
54
+ ; Subject Pattern notation (special highlighting)
53
55
  (subject_pattern) @type
54
56
 
55
57
  ; Node with labels
package/grammar.js CHANGED
@@ -7,16 +7,15 @@ module.exports = grammar({
7
7
  ],
8
8
 
9
9
  rules: {
10
- // top-level rule, forming an outer pattern shaped like `[ record | sequence-of-top-level-elements ]`
11
- gram: ($) => seq(field("root", optional($.record)), repeat($.annotated_pattern)),
10
+ gram_pattern: ($) => seq(field("root", optional($.record)), repeat($._top_level_pattern)),
11
+
12
+ _top_level_pattern: ($) => choice($.annotated_pattern, $.subject_pattern,$.node_pattern, $.relationship_pattern),
12
13
 
13
- // top-level elements are annotated patterns shaped like `[annotation-record | pattern-elements]`
14
14
  annotated_pattern: ($) =>
15
15
  seq(
16
- field("annotations", optional($.annotations)),
17
- field("elements", commaSep1($._annotated_pattern_element)),
16
+ field("annotations", $.annotations),
17
+ field("elements", choice($.subject_pattern, $._path_pattern)),
18
18
  ),
19
- _annotated_pattern_element: ($) => choice($.subject_pattern, $._path_pattern),
20
19
 
21
20
  subject_pattern: ($) =>
22
21
  seq(
@@ -30,11 +29,28 @@ module.exports = grammar({
30
29
 
31
30
  _subject_pattern_element: ($) => choice($.subject_pattern, $._path_pattern, $.pattern_reference),
32
31
 
33
- annotations: ($) => repeat1($.annotation),
32
+ annotations: ($) =>
33
+ choice(
34
+ seq($.identified_annotation, repeat($.property_annotation)),
35
+ repeat1($.property_annotation),
36
+ ),
34
37
 
35
- annotation: ($) =>
38
+ property_annotation: ($) =>
36
39
  seq("@", field("key", $.symbol), "(", field("value", $._value), ")"),
37
40
 
41
+ identified_annotation: ($) =>
42
+ seq(
43
+ "@@",
44
+ choice(
45
+ field("identifier", $._identifier),
46
+ field("labels", $.labels),
47
+ seq(
48
+ field("identifier", $._identifier),
49
+ field("labels", $.labels),
50
+ ),
51
+ ),
52
+ ),
53
+
38
54
  _path_pattern: ($) => choice($.relationship_pattern, $.node_pattern),
39
55
 
40
56
  node_pattern: ($) =>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gram-data/tree-sitter-gram",
3
- "version": "0.2.6",
3
+ "version": "0.3.3",
4
4
  "description": "subject-oriented notation for structured data",
5
5
  "homepage": "https://gram-data.github.io",
6
6
  "repository": {
@@ -12,6 +12,7 @@
12
12
  "scripts": {
13
13
  "install": "node-gyp-build",
14
14
  "prestart": "tree-sitter build --wasm",
15
+ "build": "tree-sitter build --wasm",
15
16
  "start": "tree-sitter playground",
16
17
  "test": "node --test bindings/node/*_test.js",
17
18
  "zed:dev": "ZED_REPO_MODE=dev bash scripts/prepare-zed-extension.sh",
@@ -28,12 +29,14 @@
28
29
  ],
29
30
  "files": [
30
31
  "grammar.js",
32
+ "tree-sitter.json",
31
33
  "binding.gyp",
32
34
  "prebuilds/**",
33
35
  "bindings/node/*",
34
36
  "queries/*",
35
37
  "src/**",
36
- "editors/**"
38
+ "editors/**",
39
+ "*.wasm"
37
40
  ],
38
41
  "author": "",
39
42
  "license": "ISC",
@@ -51,8 +54,8 @@
51
54
  },
52
55
  "devDependencies": {
53
56
  "eslint": "^9.37.0",
54
- "node-gyp": "^11.4.2",
55
57
  "prebuildify": "^6.0.1",
56
- "tree-sitter-cli": "^0.25.10"
58
+ "tree-sitter": "^0.25.0",
59
+ "tree-sitter-cli": "^0.26.5"
57
60
  }
58
61
  }
@@ -23,7 +23,7 @@
23
23
  "::"
24
24
  ] @operator
25
25
 
26
- ; Brackets and delimiters
26
+ ; Subject Patterns and delimiters
27
27
  [
28
28
  "["
29
29
  "]"
@@ -46,10 +46,12 @@
46
46
  (map_entry key: (string_literal) @property)
47
47
  (map_entry key: (integer) @property)
48
48
 
49
- ; Annotation keys
50
- (annotation key: (symbol) @attribute)
49
+ ; Annotation keys (property-style) and headers (identified/label-style)
50
+ (property_annotation key: (symbol) @attribute)
51
+ (identified_annotation identifier: (_) @attribute)
52
+ (identified_annotation labels: (_) @attribute)
51
53
 
52
- ; Bracket notation (special highlighting)
54
+ ; Subject Pattern notation (special highlighting)
53
55
  (subject_pattern) @type
54
56
 
55
57
  ; Node with labels
package/src/grammar.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/grammar.schema.json",
3
3
  "name": "gram",
4
4
  "rules": {
5
- "gram": {
5
+ "gram_pattern": {
6
6
  "type": "SEQ",
7
7
  "members": [
8
8
  {
@@ -25,11 +25,32 @@
25
25
  "type": "REPEAT",
26
26
  "content": {
27
27
  "type": "SYMBOL",
28
- "name": "annotated_pattern"
28
+ "name": "_top_level_pattern"
29
29
  }
30
30
  }
31
31
  ]
32
32
  },
33
+ "_top_level_pattern": {
34
+ "type": "CHOICE",
35
+ "members": [
36
+ {
37
+ "type": "SYMBOL",
38
+ "name": "annotated_pattern"
39
+ },
40
+ {
41
+ "type": "SYMBOL",
42
+ "name": "subject_pattern"
43
+ },
44
+ {
45
+ "type": "SYMBOL",
46
+ "name": "node_pattern"
47
+ },
48
+ {
49
+ "type": "SYMBOL",
50
+ "name": "relationship_pattern"
51
+ }
52
+ ]
53
+ },
33
54
  "annotated_pattern": {
34
55
  "type": "SEQ",
35
56
  "members": [
@@ -37,62 +58,29 @@
37
58
  "type": "FIELD",
38
59
  "name": "annotations",
39
60
  "content": {
40
- "type": "CHOICE",
41
- "members": [
42
- {
43
- "type": "SYMBOL",
44
- "name": "annotations"
45
- },
46
- {
47
- "type": "BLANK"
48
- }
49
- ]
61
+ "type": "SYMBOL",
62
+ "name": "annotations"
50
63
  }
51
64
  },
52
65
  {
53
66
  "type": "FIELD",
54
67
  "name": "elements",
55
68
  "content": {
56
- "type": "SEQ",
69
+ "type": "CHOICE",
57
70
  "members": [
58
71
  {
59
72
  "type": "SYMBOL",
60
- "name": "_annotated_pattern_element"
73
+ "name": "subject_pattern"
61
74
  },
62
75
  {
63
- "type": "REPEAT",
64
- "content": {
65
- "type": "SEQ",
66
- "members": [
67
- {
68
- "type": "STRING",
69
- "value": ","
70
- },
71
- {
72
- "type": "SYMBOL",
73
- "name": "_annotated_pattern_element"
74
- }
75
- ]
76
- }
76
+ "type": "SYMBOL",
77
+ "name": "_path_pattern"
77
78
  }
78
79
  ]
79
80
  }
80
81
  }
81
82
  ]
82
83
  },
83
- "_annotated_pattern_element": {
84
- "type": "CHOICE",
85
- "members": [
86
- {
87
- "type": "SYMBOL",
88
- "name": "subject_pattern"
89
- },
90
- {
91
- "type": "SYMBOL",
92
- "name": "_path_pattern"
93
- }
94
- ]
95
- },
96
84
  "subject_pattern": {
97
85
  "type": "SEQ",
98
86
  "members": [
@@ -190,13 +178,34 @@
190
178
  ]
191
179
  },
192
180
  "annotations": {
193
- "type": "REPEAT1",
194
- "content": {
195
- "type": "SYMBOL",
196
- "name": "annotation"
197
- }
181
+ "type": "CHOICE",
182
+ "members": [
183
+ {
184
+ "type": "SEQ",
185
+ "members": [
186
+ {
187
+ "type": "SYMBOL",
188
+ "name": "identified_annotation"
189
+ },
190
+ {
191
+ "type": "REPEAT",
192
+ "content": {
193
+ "type": "SYMBOL",
194
+ "name": "property_annotation"
195
+ }
196
+ }
197
+ ]
198
+ },
199
+ {
200
+ "type": "REPEAT1",
201
+ "content": {
202
+ "type": "SYMBOL",
203
+ "name": "property_annotation"
204
+ }
205
+ }
206
+ ]
198
207
  },
199
- "annotation": {
208
+ "property_annotation": {
200
209
  "type": "SEQ",
201
210
  "members": [
202
211
  {
@@ -229,6 +238,57 @@
229
238
  }
230
239
  ]
231
240
  },
241
+ "identified_annotation": {
242
+ "type": "SEQ",
243
+ "members": [
244
+ {
245
+ "type": "STRING",
246
+ "value": "@@"
247
+ },
248
+ {
249
+ "type": "CHOICE",
250
+ "members": [
251
+ {
252
+ "type": "FIELD",
253
+ "name": "identifier",
254
+ "content": {
255
+ "type": "SYMBOL",
256
+ "name": "_identifier"
257
+ }
258
+ },
259
+ {
260
+ "type": "FIELD",
261
+ "name": "labels",
262
+ "content": {
263
+ "type": "SYMBOL",
264
+ "name": "labels"
265
+ }
266
+ },
267
+ {
268
+ "type": "SEQ",
269
+ "members": [
270
+ {
271
+ "type": "FIELD",
272
+ "name": "identifier",
273
+ "content": {
274
+ "type": "SYMBOL",
275
+ "name": "_identifier"
276
+ }
277
+ },
278
+ {
279
+ "type": "FIELD",
280
+ "name": "labels",
281
+ "content": {
282
+ "type": "SYMBOL",
283
+ "name": "labels"
284
+ }
285
+ }
286
+ ]
287
+ }
288
+ ]
289
+ }
290
+ ]
291
+ },
232
292
  "_path_pattern": {
233
293
  "type": "CHOICE",
234
294
  "members": [