179 lines
5.4 KiB
JavaScript
179 lines
5.4 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const VParserTypes = {
|
||
|
content: 0,
|
||
|
variable: 1,
|
||
|
for: 2,
|
||
|
forEach: 3,
|
||
|
forContent: 4,
|
||
|
forEnd: 5,
|
||
|
if: 6,
|
||
|
ifContent: 7,
|
||
|
ifEnd: 8,
|
||
|
assign: 9,
|
||
|
none: -1,
|
||
|
|
||
|
// operators
|
||
|
'!=': 100,
|
||
|
'==': 101,
|
||
|
'&&': 102,
|
||
|
'||': 103,
|
||
|
'>=': 104,
|
||
|
'<=': 105,
|
||
|
'>': 106,
|
||
|
'<': 107,
|
||
|
'+': 108,
|
||
|
'-': 109,
|
||
|
'*': 110,
|
||
|
'/': 111,
|
||
|
'%': 112
|
||
|
};
|
||
|
|
||
|
|
||
|
class VTpeLParser {
|
||
|
constructor(name, content) {
|
||
|
let self = this;
|
||
|
self.name = name;
|
||
|
self.legex = content;
|
||
|
self.index = 0;
|
||
|
self.content = '';
|
||
|
self.parsed = [];
|
||
|
self.contexts = [0];
|
||
|
self.allowedOperators = ['!=', '==', '&&', '||', '>=', '<=', '>', '<', '+', '-', '*', '/', '%']
|
||
|
}
|
||
|
|
||
|
tokenize() {
|
||
|
let self = this;
|
||
|
for (self.index = 0; self.index < self.legex.length; self.index++) {
|
||
|
let i = self.index,
|
||
|
char = self.legex.charAt(i);
|
||
|
if (self.nextContains('/*', i, true)) {
|
||
|
self.extract('*/', VParserTypes.none)
|
||
|
} else if (self.nextContains('//', i, true)) {
|
||
|
self.extract('\n', VParserTypes.none);
|
||
|
} else if (self.nextContains('<!--', i, true)) {
|
||
|
self.extract('-->', VParserTypes.none);
|
||
|
} else if (self.nextContains('{for(', i, true)) {
|
||
|
self.extract(')}', VParserTypes.for);
|
||
|
self.contexts.push(VParserTypes.for);
|
||
|
} else if (self.nextContains('{foreach(', i, true)) {
|
||
|
self.extract(')}', VParserTypes.forEach);
|
||
|
self.contexts.push(VParserTypes.forEach);
|
||
|
} else if (self.nextContains('{/for}', i, true)) {
|
||
|
self.addType(VParserTypes.forEnd);
|
||
|
self.contexts.pop();
|
||
|
} else if (self.nextContains('{if(', i, true)) {
|
||
|
self.extract(')}', VParserTypes.if);
|
||
|
self.contexts.push(VParserTypes.if);
|
||
|
} else if (self.nextContains('{/if}', i, true)) {
|
||
|
self.addType(VParserTypes.ifEnd);
|
||
|
self.contexts.pop();
|
||
|
} else if (self.nextContains('$${', i, true)) {
|
||
|
self.extract('}', VParserTypes.assign);
|
||
|
} else if (self.nextContains('${', i, true)) {
|
||
|
self.extract('}', VParserTypes.variable);
|
||
|
} else {
|
||
|
self.content += char;
|
||
|
}
|
||
|
}
|
||
|
self.addType(VParserTypes.content);
|
||
|
return self.parsed;
|
||
|
}
|
||
|
|
||
|
addType(type) {
|
||
|
let self = this;
|
||
|
let content = self.content.trim(),
|
||
|
instructions = self.findInstructions(type);
|
||
|
self.content = '';
|
||
|
if (type !== VParserTypes.none) {
|
||
|
if (type === VParserTypes.content && content === '') {
|
||
|
return null;
|
||
|
}
|
||
|
return self.parsed.push({
|
||
|
content: content,
|
||
|
type: type,
|
||
|
context: self.contexts[self.contexts.length - 1],
|
||
|
instructions: instructions
|
||
|
});
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
nextContains(find, index, add = false) {
|
||
|
let count = this.nextContainsRaw(this.legex, find, index);
|
||
|
if (add && count > 0) {
|
||
|
this.index += count;
|
||
|
}
|
||
|
return count > 0 || count === -1;
|
||
|
}
|
||
|
|
||
|
nextContainsRaw(raw, find, index) {
|
||
|
if (typeof find === "string") {
|
||
|
find = find.split("");
|
||
|
}
|
||
|
let count = find.length;
|
||
|
if (count < 1) {
|
||
|
return -1;
|
||
|
}
|
||
|
for (let i = 0; i < count; i++) {
|
||
|
let nc = raw.charAt(index + i);
|
||
|
if ((find[i] === '\n' && nc === undefined)) {
|
||
|
return count;
|
||
|
}
|
||
|
if (find[i] !== nc) {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
extract(findUntil = '}', type = 1) {
|
||
|
let self = this;
|
||
|
self.addType(0);
|
||
|
findUntil = findUntil.split("")
|
||
|
let content = '',
|
||
|
index = self.index,
|
||
|
legex = self.legex,
|
||
|
firstFind = findUntil.shift();
|
||
|
for (let i = self.index; i < legex.length; i++) {
|
||
|
let char = legex.charAt(i);
|
||
|
if (char === firstFind && self.nextContains(findUntil, i + 1)) {
|
||
|
console.debug(`[Parser][${index} > ${i}] >> ${content}`);
|
||
|
self.index = i + findUntil.length;
|
||
|
self.content = content;
|
||
|
self.addType(type);
|
||
|
return;
|
||
|
}
|
||
|
content += char;
|
||
|
}
|
||
|
throw 'Template variable at Position: ' + index + ' not closed!';
|
||
|
}
|
||
|
|
||
|
// @todo implement split... is needed for if statements and math stuff or get it stupid!
|
||
|
getOperator(string) {
|
||
|
let operators = [];
|
||
|
for (let i = 0; i < string.length; i++) {
|
||
|
if (this.nextContainsRaw(string, "(", i)) {
|
||
|
let innerCon = '';
|
||
|
for (let x = 0; x < string.length; x++) {
|
||
|
let char = string.charAt(i + x);
|
||
|
if (char === ')') {
|
||
|
break;
|
||
|
}
|
||
|
innerCon += char;
|
||
|
}
|
||
|
operators = [...operators, this.getOperator(innerCon)];
|
||
|
} else {
|
||
|
}
|
||
|
}
|
||
|
return operators;
|
||
|
}
|
||
|
|
||
|
findInstructions(type) {
|
||
|
if (type === VParserTypes.if) {
|
||
|
return this.getOperator(this.content);
|
||
|
}
|
||
|
return [];
|
||
|
}
|
||
|
}
|