forked from sergioramos/jsctags
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.js
122 lines (97 loc) · 2.92 KB
/
parser.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
var interpolate = require('util').format;
var condense = require('./condenser');
module.exports = function (file, dir, content, callback) {
condense(dir, file, content, function (e, condense) {
if (e) throw e;
var types = {};
var tags = [];
parse(content, condense, tags, types);
callback(null, tags.sort(function (tag1, tag2) {
return tag1.lineno - tag2.lineno;
}));
});
};
module.exports.ctags = require('./ctags');
var parse = function (file, condense, tags, types) {
Object.keys(condense).forEach(function (name) {
tagger(file, condense[name], tags, types, [], condense)(name);
});
};
var kind = function (type) {
if (type.match(/^fn/)) {
return 'f';
}
return 'v';
};
var returns = function (type) {
var returns = type.match(/-> (.*?)$/);
if (returns) {
returns = returns.pop();
} else {
return 'void';
}
if (returns && returns.match(/^\[/)) {
return 'Array';
}
return returns;
};
var typeFn = function (type, define) {
var args = type.match(/^fn\((.*?)\)/);
if (args) {
args = args.pop().split(',').map(function (arg) {
var type = arg.match(/^.*?\: (.*?)$/);
if (type) type = type.pop();
if (define[type] && define[type]['!type']) {
return typeFn(define[type]['!type'], define);
}
if (type && type.match(/^\[/)) {
return 'Array'.concat(type);
} else {
return type;
}
}).filter(function (type) {
return !!type;
});
}
return interpolate('%s function(%s)', returns(type), args ? args.join(', ') : '');
};
var type = function (type, define) {
if (type.match(/^bool/)) return 'boolean';
if (type.match(/^number/)) return 'number';
if (type.match(/^fn/)) return typeFn(type, define);
return type;
};
var addr = function (span, file) {
var pos = span.match(/^(\d*?)\[\d*?\:\d*?\]-(\d*?)\[\d*?\:\d*?\]$/);
var end = pos.pop();
var start = pos.pop();
var blob = file.slice(start, end);
return new RegExp(blob.split(/\n/).shift().replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'));
};
var lineno = function (span) {
return Number(span.match(/^\d*?\[(\d*?)\:\d*?\]-\d*?\[\d*?\:\d*?\]$/).pop()) + 1;
};
var tagger = function (file, condense, tags, types, parent, root) {
var define = root['!define'] || {};
return function (name) {
if (typeof condense !== 'object' || name.match(/^\!/)) return 0;
var _type = condense['!type'];
var _span = condense['!span'];
Object.keys(condense).forEach(function (key) {
if (key.match(/^\!/)) return 0;
var p = parent.slice();
p.push(name);
tagger(file, condense[key], tags, types, p, root)(key);
});
if (!_span || !_type) return 0;
var tag = {
name: name,
addr: addr(_span, file).toString(),
kind: kind(_type),
type: type(_type, define),
lineno: lineno(_span)
};
if (parent.length) tag.namespace = parent.join('.');
return tags.push(tag);
};
};