forked from PostFixJS/PostFixJS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtokenUtils.js
More file actions
147 lines (139 loc) · 4.25 KB
/
tokenUtils.js
File metadata and controls
147 lines (139 loc) · 4.25 KB
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
/**
* Get the tokens of a parameter list from an array of tokens.
* @param {object[]} tokens Array of tokens
* @param {number} i Index of a PARAM_LIST_START token
* @returns {object|bool} Index of the first and last token (inclusive) of the parameter list or false if no parameter list is found
*/
function readParamsList (tokens, i) {
if (tokens[i] && tokens[i].tokenType === 'PARAM_LIST_START') {
const firstToken = i
i++
while (i < tokens.length && tokens[i - 1].tokenType !== 'PARAM_LIST_END') {
i++
}
return {
firstToken,
lastToken: i - 1
}
}
return false
}
/**
* Parse the given tokens into lists of parameters and return values.
* @param {object[]} paramsList Tokens of the parameter list, including the brackets
* @returns {object} Parameters and return values, with names and types
*/
function parseParamsList (paramsList) {
let rightArrowPosition = paramsList.findIndex((token) => token.tokenType === 'RIGHT_ARROW')
if (rightArrowPosition < 0) {
rightArrowPosition = paramsList.length - 1
}
const params = []
let lastComment = null
for (let i = 1; i < rightArrowPosition; i++) {
const value = paramsList[i].token
if (value[0] === ':' || value[value.length - 1] === ':') {
if (params.length > 0) {
// this is a symbol
params[params.length - 1].type = normalizeSymbol(value, true)
}
} else if (isCommentToken(paramsList[i])) {
// this is a comment
if (paramsList[i].tokenType === 'BLOCK_COMMENT') {
lastComment = paramsList[i]
}
} else {
// this is a parameter name
params.push({
name: value,
type: undefined,
doc: lastComment != null && lastComment.endLine === paramsList[i].line - 1 ? lastComment.token : undefined
})
lastComment = undefined
}
}
const returns = rightArrowPosition >= 0 ? paramsList.slice(rightArrowPosition + 1, -1).map((token) => token.token) : []
return { params, returns }
}
/**
* Get the tokens of an array from an array of tokens.
* @param {object[]} tokens Array of tokens
* @param {number} i Index of a ARR_START token
* @returns {object|bool} Index of the first and last token (inclusive) of the array or false if no array is found
*/
function readArray (tokens, i) {
let depth = 0
if (tokens[i] && tokens[i].tokenType === 'ARR_START') {
const firstToken = i
while (i < tokens.length) {
if (tokens[i].tokenType === 'ARR_START') {
depth++
} else if (tokens[i].tokenType === 'ARR_END') {
depth--
if (depth === 0) {
return {
firstToken,
lastToken: i
}
}
}
i++
}
}
return false
}
/**
* Get the tokens of an executable array from an array of tokens.
* @param {object[]} tokens Array of tokens
* @param {number} i Index of a ARR_START token
* @returns {object|bool} Index of the first and last token (inclusive) of the array or false if no array is found
*/
function readExecutableArray (tokens, i) {
let depth = 0
if (tokens[i] && tokens[i].tokenType === 'EXEARR_START') {
const firstToken = i
while (i < tokens.length) {
if (tokens[i].tokenType === 'EXEARR_START') {
depth++
} else if (tokens[i].tokenType === 'EXEARR_END') {
depth--
if (depth === 0) {
return {
firstToken,
lastToken: i
}
}
}
i++
}
}
return false
}
/**
* Check if the given token is a comment.
* @param {object} token Token
* @returns True if the token is a comment token, false otherwise
*/
function isCommentToken (token) {
return token.tokenType === 'BLOCK_COMMENT' || token.tokenType === 'LINE_COMMENT'
}
/**
* Normalize a symbol name.
* @param {string} name Symbol name (with or without colon)
* @param {boolean} withColon True to prefix the symbol with a colon, false to omit them
* @returns Normalized symbol (with or without leading colon)
*/
function normalizeSymbol (name, withColon = false) {
const cleanName = name.indexOf(':') === 0
? name.substr(1)
: name.substr(0, name.length - 1)
return withColon ? `:${cleanName}` : cleanName
}
module.exports = {
readParamsList,
parseParamsList,
readArray,
readExecutableArray,
isCommentToken,
normalizeSymbol
}