@algosail/parser 0.0.1

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/lib/types.js ADDED
@@ -0,0 +1,148 @@
1
+ import { field, children, childrenOfField } from './utils.js'
2
+ import {
3
+ moduleGroupRef,
4
+ groupRef,
5
+ mapRef,
6
+ moduleMapRef,
7
+ effectAdd,
8
+ effectRemove,
9
+ } from './tokens.js'
10
+
11
+ export function litType(node) {
12
+ return {
13
+ kind: 'lit',
14
+ name: node.text,
15
+ }
16
+ }
17
+
18
+ export function varType(node) {
19
+ return {
20
+ kind: 'var',
21
+ name: node.text,
22
+ }
23
+ }
24
+
25
+ export function spreadType(node) {
26
+ return {
27
+ kind: 'spread',
28
+ name: node.text,
29
+ }
30
+ }
31
+
32
+ export function mapType(node) {
33
+ return {
34
+ kind: 'map',
35
+ map: mapRef(node),
36
+ }
37
+ }
38
+
39
+ export function moduleMapType(node) {
40
+ return {
41
+ kind: 'map',
42
+ ...(moduleMapRef(node) || {}),
43
+ }
44
+ }
45
+
46
+ export function groupType(node) {
47
+ const parseGroup = (node) => {
48
+ const groupField = field(node, 'group')
49
+
50
+ if (groupField.type === 'module_group_ref') {
51
+ return moduleGroupRef(groupField)
52
+ }
53
+
54
+ return { group: groupRef(groupField) }
55
+ }
56
+
57
+ const parseParam = (node) => {
58
+ switch (node.type) {
59
+ case 'group_type':
60
+ return groupType(node)
61
+ case 'map_ref':
62
+ return mapType(node)
63
+ case 'module_map_ref':
64
+ return moduleMapType(node)
65
+ default:
66
+ return litType(node)
67
+ }
68
+ }
69
+
70
+ const group = parseGroup(node)
71
+ const params = childrenOfField(node, 'params').map(parseParam)
72
+
73
+ return { kind: 'group', ...group, params }
74
+ }
75
+
76
+ export function effectAddType(node) {
77
+ return {
78
+ kind: 'effect_add',
79
+ effect: effectAdd(node),
80
+ }
81
+ }
82
+
83
+ export function effectRemoveType(node) {
84
+ return {
85
+ kind: 'effect_remove',
86
+ effect: effectRemove(node),
87
+ }
88
+ }
89
+
90
+ export function listType(node) {
91
+ return {
92
+ kind: 'quotation',
93
+ inputs: [],
94
+ outputs: children(node).map(sigItemType),
95
+ addEffects: [],
96
+ removeEffects: [],
97
+ }
98
+ }
99
+
100
+ export function sigItemType(node) {
101
+ switch (node.type) {
102
+ case 'effect_add':
103
+ return effectAddType(node)
104
+ case 'effect_remove':
105
+ return effectRemoveType(node)
106
+ case 'sig_list':
107
+ return listType(node)
108
+ case 'sig_quotation':
109
+ return sigType(node)
110
+ case 'group_type':
111
+ return groupType(node)
112
+ case 'map_ref':
113
+ return mapType(node)
114
+ case 'module_map_ref':
115
+ return moduleMapType(node)
116
+ case 'spread':
117
+ return spreadType(node)
118
+ case 'type_var':
119
+ return varType(node)
120
+ default:
121
+ return litType(node)
122
+ }
123
+ }
124
+
125
+ export function sigType(node) {
126
+ if (!node) return null
127
+
128
+ const items = children(node)
129
+
130
+ const arrowIdx = items.findIndex((item) => item.type === 'sig_arrow')
131
+
132
+ const inputsNode = arrowIdx >= 0 ? items.slice(0, arrowIdx) : items
133
+ const outputsNode = arrowIdx >= 0 ? items.slice(arrowIdx + 1) : []
134
+
135
+ const isEffect = (n) => n.type === 'effect_add' || n.type === 'effect_remove'
136
+ const isNoteEffect = (n) => !isEffect(n)
137
+
138
+ const isAddEffect = (n) => n.type === 'effect_add'
139
+ const isRemoveEffect = (n) => n.type === 'effect_remove'
140
+
141
+ return {
142
+ kind: 'quotation',
143
+ inputs: inputsNode.filter(isNoteEffect).map(sigItemType),
144
+ outputs: outputsNode.filter(isNoteEffect).map(sigItemType),
145
+ addEffects: outputsNode.filter(isAddEffect).map(effectAddType),
146
+ removeEffects: outputsNode.filter(isRemoveEffect).map(effectRemoveType),
147
+ }
148
+ }
package/lib/utils.js ADDED
@@ -0,0 +1,16 @@
1
+ export const capture = (captures, name) => captures.find((c) => c.name === name)?.node ?? null
2
+
3
+ export const field = (node, name) => {
4
+ if (Array.isArray(name)) {
5
+ return name.reduce((res, n) => (res && res.childForFieldName(n)) ?? null, node)
6
+ }
7
+ return node.childForFieldName(name) ?? null
8
+ }
9
+
10
+ export const fieldText = (node, name) => field(node, name)?.text ?? null
11
+
12
+ export const children = (node) => node.namedChildren
13
+ export const childrenOfType = (node, type) => node.namedChildren.filter((c) => c.type === type)
14
+ export const childrenOfField = (node, field) => node.childrenForFieldName(field)
15
+
16
+ export const firstOfType = (node, type) => node.namedChildren.find((c) => c.type === type) ?? null
package/lib/word.js ADDED
@@ -0,0 +1,141 @@
1
+ import { Query } from 'web-tree-sitter'
2
+ import { capture, field, childrenOfField, children } from './utils.js'
3
+ import {
4
+ wordDef,
5
+ wordRef,
6
+ moduleWordRef,
7
+ tagRef,
8
+ moduleTagRef,
9
+ tagPattern,
10
+ moduleTagPattern,
11
+ fieldRef,
12
+ moduleFieldRef,
13
+ comment,
14
+ slotWrite,
15
+ slotRead,
16
+ rawString,
17
+ rawValue,
18
+ } from './tokens.js'
19
+ import { sigType } from './types.js'
20
+
21
+ export function getWordNodes(rootNode, language) {
22
+ const query = new Query(language, `(word) @word`)
23
+ const matches = query.matches(rootNode)
24
+ const words = matches
25
+ .map((match) => capture(match.captures, 'word'))
26
+ .filter(Boolean)
27
+ .map(parseWord)
28
+
29
+ return { words }
30
+ }
31
+
32
+ function parseWord(node) {
33
+ const name = wordDef(field(node, 'name_def'))
34
+ const signature = sigType(field(node, 'sig'))
35
+ const body = childrenOfField(node, 'body').map(step).filter(Boolean)
36
+
37
+ return {
38
+ name,
39
+ doc: comment(field(node, 'doc')),
40
+ signature,
41
+ body,
42
+ }
43
+ }
44
+
45
+ function step(node) {
46
+ switch (node.type) {
47
+ case 'quotation':
48
+ return quotation(node)
49
+ case 'builtin_word':
50
+ return builtinWord(node)
51
+ case 'word_ref':
52
+ return word(node)
53
+ case 'module_word_ref':
54
+ return moduleWord(node)
55
+ case 'tag_ref':
56
+ return tagConstructor(node)
57
+ case 'module_tag_ref':
58
+ return moduleTagConstructor(node)
59
+ case 'tag_pattern':
60
+ return patternTag(node)
61
+ case 'module_tag_pattern':
62
+ return patternModuleTag(node)
63
+ case 'default_pattern':
64
+ return patternDefault(node)
65
+ case 'field_ref':
66
+ return fieldLens(node)
67
+ case 'module_field_ref':
68
+ return moduleFieldLens(node)
69
+ case 'slot_write':
70
+ return writeSlot(node)
71
+ case 'slot_read':
72
+ return readSlot(node)
73
+ case 'raw_string':
74
+ return rawFromString(node)
75
+ case 'raw_value':
76
+ return raw(node)
77
+ default:
78
+ return null
79
+ }
80
+ }
81
+
82
+ function quotation(node) {
83
+ const body = children(node).map(step).filter(Boolean)
84
+ return { type: 'quotation', body }
85
+ }
86
+
87
+ function builtinWord(node) {
88
+ return { type: 'builtin_word', word: node.text }
89
+ }
90
+
91
+ function word(node) {
92
+ return { type: 'word', word: wordRef(node) }
93
+ }
94
+
95
+ function moduleWord(node) {
96
+ return { type: 'word', ...(moduleWordRef(node) || {}) }
97
+ }
98
+
99
+ function tagConstructor(node) {
100
+ return { type: 'tag', tag: tagRef(node) }
101
+ }
102
+
103
+ function moduleTagConstructor(node) {
104
+ return { type: 'tag', ...(moduleTagRef(node) || {}) }
105
+ }
106
+
107
+ function patternTag(node) {
108
+ return { type: 'pattern_tag', tag: tagPattern(node) }
109
+ }
110
+
111
+ function patternModuleTag(node) {
112
+ return { type: 'pattern_tag', ...(moduleTagPattern(node) || {}) }
113
+ }
114
+
115
+ function patternDefault(_node) {
116
+ return { type: 'pattern_default' }
117
+ }
118
+
119
+ function fieldLens(node) {
120
+ return { type: 'field_lens', field: fieldRef(node) }
121
+ }
122
+
123
+ function moduleFieldLens(node) {
124
+ return { type: 'field_lens', ...(moduleFieldRef(node) || {}) }
125
+ }
126
+
127
+ function writeSlot(node) {
128
+ return { type: 'slot_write', value: slotWrite(node) }
129
+ }
130
+
131
+ function readSlot(node) {
132
+ return { type: 'slot_read', value: slotRead(node) }
133
+ }
134
+
135
+ function rawFromString(node) {
136
+ return { type: 'raw', value: rawString(node) }
137
+ }
138
+
139
+ function raw(node) {
140
+ return { type: 'raw', value: rawValue(node) }
141
+ }
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@algosail/parser",
3
+ "version": "0.0.1",
4
+ "description": "Parser for Sail language.",
5
+ "license": "MIT",
6
+ "author": "algosail",
7
+ "type": "module",
8
+ "main": "index.js",
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "dependencies": {
13
+ "@algosail/tree-sitter": "^0.1.6",
14
+ "tree-sitter-javascript": "^0.25.0",
15
+ "web-tree-sitter": "^0.26.7"
16
+ },
17
+ "devDependencies": {
18
+ "brittle": "^3.19.1"
19
+ }
20
+ }