-
Notifications
You must be signed in to change notification settings - Fork 8
/
jsExtractionUtil.js
176 lines (154 loc) · 6.76 KB
/
jsExtractionUtil.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Author: Michael Pradel
// Adapted from https://github.com/michaelpradel/DeepBugs
(function() {
const acorn = require("acorn");
const maxLengthOfTokens = 200;
function getTokens(code) {
try {
const tokenizer = acorn.tokenizer(code, {locations:true});
const tokens = [];
let nextToken = tokenizer.getToken();
while (nextToken.type !== acorn.tokTypes.eof) {
tokens.push(nextToken);
nextToken = tokenizer.getToken();
}
return tokens;
} catch (e) {
}
}
function getAST(code, noLocations) {
try {
if (noLocations) return acorn.parse(code);
else return acorn.parse(code, {locations:true});
} catch (e) {
}
}
function getNameOfASTNode(node) {
if (node.type === "Identifier") return "ID:" + node.name;
else if (node.type === "CallExpression") return getNameOfASTNode(node.callee);
else if (node.type === "MemberExpression" && node.computed === true) return getNameOfASTNode(node.object);
else if (node.type === "MemberExpression" && node.computed === false) return getNameOfASTNode(node.property);
else if (node.type === "Literal") return "LIT:" + String(node.value);
else if (node.type === "ThisExpression") return "LIT:this";
else if (node.type === "UpdateExpression") return getNameOfASTNode(node.argument);
}
function getKindOfASTNode(node) {
if (node.type === "Identifier") return "ID";
else if (node.type === "CallExpression") return getKindOfASTNode(node.callee);
else if (node.type === "MemberExpression" && node.computed === true) return getKindOfASTNode(node.object);
else if (node.type === "MemberExpression" && node.computed === false) return getKindOfASTNode(node.property);
else if (node.type === "Literal") return "LIT";
else if (node.type === "ThisExpression") return "LIT";
}
function getTypeOfASTNode(node) {
if (node.type === "Literal") {
if (node.hasOwnProperty("regex")) return "regex";
else if (node.value === null) return "null";
else return typeof node.value;
} else if (node.type === "ThisExpression") return "object";
else if (node.type === "Identifier" && node.name === "undefined") return "undefined";
else return "unknown";
}
function nodeToString(node) {
let result;
if (node.type === "Identifier") {
result = "ID:" + node.name;
} else if (node.type === "Literal") {
result = "LIT:" + node.value;
} else if (Array.isArray(node)) {
result = "Array";
} else if (typeof node.type === "string") {
result = node.type;
} else {
throw "Unexpected node type: " + JSON.stringify(node);
}
return result.slice(0, maxLengthOfTokens);
}
const identifierTokenType = "name";
const literalTokenTypes = ["num", "regexp", "string", "null", "true", "false"];
function tokenToString(t) {
let result;
if (t.type.label === identifierTokenType) {
result = "ID:";
} else if (literalTokenTypes.indexOf(t.type.label) != -1) {
result = "LIT:";
} else {
result = "STD:";
}
if (typeof t.value === "undefined") result += t.type.label;
else if (typeof t.value === "string" || typeof t.value === "number") result += String(t.value);
else if (t.type.label === "regexp") result += String(t.value.value);
else {
console.log("Unexpected token:\n" + JSON.stringify(t, 0, 2));
}
return result.slice(0, maxLengthOfTokens);
}
function tokensToStrings(tokens) {
return tokens.map(tokenToString);
}
function isIdLit(token) {
return isId(token) || isLit(token)
}
function isId(token) {
return token.type.label === "name";
}
function isLit(token) {
return token.type.label === "num" || token.type.label === "regexp" || token.type.label === "string"
}
function computeLocationMap(tokens) {
// maps line-column-based location to character-based location
const lcLocationToCharLocation = {};
for (let i = 0; i < tokens.length; i++) {
const t = tokens[i];
const lcStartLocation = t.loc.start.line + ":" + t.loc.start.column;
const lcEndLocation = t.loc.end.line + ":" + t.loc.end.column;
lcLocationToCharLocation[lcStartLocation] = t.start;
lcLocationToCharLocation[lcEndLocation] = t.end;
}
return lcLocationToCharLocation;
}
function getLocationOfASTNode(node, lcLocationToCharLocation) {
const lcStartLocation = node.loc.start.line + ":" + node.loc.start.column;
const lcEndLocation = node.loc.end.line + ":" + node.loc.end.column;
const start = lcLocationToCharLocation[lcStartLocation];
const end = lcLocationToCharLocation[lcEndLocation];
const diff = end-start;
return nbToPaddedStr(start, 6) + nbToPaddedStr(diff, 4);
}
function nbToPaddedStr(nb, length) {
let str = String(nb);
while (str.length < length) {
str = "0" + str;
}
return str;
}
function getNameOfFunction(functionNode, parentNode) {
if (functionNode.id && functionNode.id.name) return "ID:"+functionNode.id.name;
if (parentNode.type === "AssignmentExpression") {
if (parentNode.left.type === "Identifier") return "ID:"+parentNode.left.name;
if (parentNode.left.type === "MemberExpression" &&
parentNode.left.property.type === "Identifier") return "ID:"+parentNode.left.property.name;
}
if (parentNode.type === "VariableDeclarator") {
if (parentNode.id.type === "Identifier") return "ID:"+parentNode.id.name;
}
if (parentNode.type === "Property") {
if (parentNode.key.type === "Identifier") return "ID:"+parentNode.key.name;
}
}
module.exports.getTokens = getTokens;
module.exports.getAST = getAST;
module.exports.getNameOfASTNode = getNameOfASTNode;
module.exports.getKindOfASTNode = getKindOfASTNode;
module.exports.getTypeOfASTNode = getTypeOfASTNode;
module.exports.nodeToString = nodeToString;
module.exports.tokenToString = tokenToString;
module.exports.tokensToStrings = tokensToStrings;
module.exports.isId = isId;
module.exports.isLit = isLit;
module.exports.isIdLit = isIdLit;
module.exports.nbToPaddedStr = nbToPaddedStr;
module.exports.computeLocationMap = computeLocationMap;
module.exports.getLocationOfASTNode = getLocationOfASTNode;
module.exports.getNameOfFunction = getNameOfFunction;
})();