-
Notifications
You must be signed in to change notification settings - Fork 33
/
parser.js
139 lines (120 loc) · 3.58 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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
class Parser {
/**
* Creates an instance of Parser.
* @param {String} text The text to parse
* @param {Function} afterCmdCallback Function to execute after the commands are executed
* @memberof Parser
*/
constructor(text, afterCmdCallback,offset = 0) {
if (!text) text = '';
this.text = text.trimRight();
this.index = 0;
this.afterCmdCallback = afterCmdCallback
this.offset = offset;
}
/**
* Private method
*
* @returns Boolean If the index has surpased the length of the text or not.
* @memberof Parser
*/
remainingTokens() {
return this.index < this.text.length;
}
/**
* Private method
*
* @returns String The next token after the actual index.
* @memberof Parser
*/
nextToken() {
let regWhitespace = /\s/;
while (regWhitespace.test(this.text.charAt(this.index)) && this.remainingTokens()) this.index++;
let firstChar = this.text.charAt(this.index);
let token = '';
let isTokenList = false;
let depth = 0;
if (firstChar === '[') {
this.index++;
depth++;
isTokenList = true;
}
let actualChar = this.text.charAt(this.index);
while (((regWhitespace.test(actualChar) && isTokenList) || !regWhitespace.test(actualChar)) && this.remainingTokens()) {
this.index++;
if (isTokenList) {
if (actualChar === '[') depth++;
else if (actualChar === ']') depth--;
if (actualChar === ']' && depth === 0) return token;
}
token += actualChar;
actualChar = this.text.charAt(this.index);
}
return token;
}
getArgs() {
let ret = this.nextToken();
let temp = this.index;
let next = this.nextToken();
if (next == '/' || next == '*' || next == '+' || next == '-') {
return ret + ' ' + next + ' ' + this.getArgs();
}
else {
this.index = temp;
return ret;
}
}
/**
* Public method
*
* @returns [CommandExecutor] Parsed text converted into CommandExecutors
* ready to be executed.
* @memberof Parser
*/
parse() {
let cmdsExecutors = [];
while (this.remainingTokens()) {
let cmdStrat = this.index;
let token = this.nextToken();
let cmd = commandLookUp.get(token);
let args = [];
if (cmd) {
for (let i = 0; i < cmd.argsTemplate.length; i++) {
let startIndex = this.index;
let arg = cmd.argsTemplate[i];
let theArgToken = this.getArgs();
let endIndex = this.index + 1;
if (arg.validator !== undefined) {
let valid;
if(arg.type == ARGUMENT_TYPES.COMMANDS)
{
while(this.text.length>startIndex && this.text[startIndex++]!='[');
console.log({arg:theArgToken,offset:startIndex});
valid = arg.validator(theArgToken,startIndex+this.offset)
}else
valid = arg.validator(theArgToken);
if (!valid) {
console.error(`Argument number ${i} (${theArgToken}) is invalid for command ${token} parser offset ${this.offset}`);
throw {
startIndex: startIndex+this.offset,
endIndex: endIndex+this.offset
}
}
args.push(theArgToken);
}
else {
args.push(theArgToken);
}
}
cmdsExecutors.push(new CommandExecutor(cmd, args, this.afterCmdCallback));
}else {
let endIndex = this.index + 1;
throw {
startIndex: cmdStrat+this.offset,
endIndex: endIndex+this.offset
}
}
}
return cmdsExecutors;
}
}