This repository was archived by the owner on Jul 18, 2023. It is now read-only.
forked from rescript-lang/rescript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnode_types.js
160 lines (153 loc) · 4.01 KB
/
node_types.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//@ts-check
class Node {
/**
*
* @param {string} type
* @param {string} text
* @param {Node[]} children
*/
constructor(type, text, children) {
this.type = type;
this.text = text;
this.children = children;
}
get mainText() {
return this.children[0].text;
}
get firstChild() {
return this.children[0];
}
get lastChild() {
return this.children[this.children.length - 1];
}
}
/**
*
* @param {*} node
* @returns {Node}
*/
function nodeToObject(node) {
const namedChildren = node.children.filter((x) => {
var isNamed = typeof x.isNamed === "function" ? x.isNamed() : x.isNamed;
return isNamed && x.type !== "comment";
});
var children = [...namedChildren.map((x) => nodeToObject(x))];
return new Node(node.type, node.text, children);
}
/**
*
* @param {*} parseOutput
* @typedef {{all : Set<string>, excludes : Set<string>}} Names
* @typedef { {types : {name:string; def : Node}[], names : Names}} Type
* @returns {Type[]}
*/
function getTypeDefs(parseOutput) {
var rootNode = parseOutput.rootNode;
var compilationUnit = nodeToObject(rootNode);
var type_definitions = compilationUnit.children;
// filter toplevel types has item_attribute
var has_deriving_type_definitions = type_definitions.filter(
(type_defintion) => {
// var children = type_defintion.children;
var last = type_defintion.lastChild.lastChild;
return last.type === "item_attribute";
}
);
var typedefs = has_deriving_type_definitions.map((type_definition) => {
var excludes = new Set(extractExcludes(type_definition));
var all = new Set(type_definition.children.map((x) => x.mainText));
return {
names: { all, excludes },
types: type_definition.children.map((x) => {
var children = x.children;
// var len = children.length;
return {
name: children[0].text, // we ask no type parameter redefined
def: children[1], // there maybe trailing attributes
// params: children.slice(0, len - 2),
};
}),
};
});
// .reduce((x, y) => x.concat(y));
return typedefs;
}
/**
* @typedef { {kind : 'exclude', name : string} | { kind : 'yes', name : string} | {kind: 'no'}} Support
* @param {Node} def
* @param {Names} names
* @returns {Support}
*
* Note visitor may have different requirements against
* `to_string` where more information is appreciated
*
* Here the case when it is not supported:
* - It is an external type: M.t
* - it is an foreign type : xx (xx does not belong to recursive types)
*/
function isSupported(def, names) {
var { all: allNames, excludes } = names;
if (def.children.length === 1) {
var basic = def.mainText;
if (allNames.has(basic)) {
if (excludes.has(basic)) {
return { kind: "exclude", name: basic };
}
return { kind: "yes", name: basic };
}
return { kind: "no" };
}
return { kind: "no" };
}
/**
* @template T
* @param {number} n
* @param {(_ : number) => T} fn
* @returns {T[]}
*/
function init(n, fn) {
return Array.from({ length: n }, (_, i) => fn(i));
}
/**
* @param {Node} node
* @returns {string[]}
*/
function extractExcludes(node) {
try {
return node.lastChild.lastChild.children[1].children[0].children[0].children[0].children[1].children // attribute_payload // expression_item // record_expression // filed_expression
.map((x) => x.text);
} catch {
return [];
}
}
/**
* @param {(_:Type)=>string}make
* @param {Type[]} typedefs
*
*/
function maker(make, typedefs) {
return typedefs.map((x) => make(x)).reduce((x, y) => x + y);
}
/**
*
* @param {Set<string>} x
* @param {Set<string>} y
* @return {string[]}
*/
function setDiff(x, y) {
var output = [];
for (let e of x) {
if (!y.has(e)) {
output.push(e);
}
}
return output;
}
exports.setDiff = setDiff;
exports.extractExcludes = extractExcludes;
exports.maker = maker;
exports.init = init;
exports.isSupported = isSupported;
exports.getTypedefs = getTypeDefs;
exports.nodeToObject = nodeToObject;
exports.Node = Node;