148 lines
4.8 KiB
TypeScript
148 lines
4.8 KiB
TypeScript
import { getChatVar, getGlobalChatVar } from "../parser";
|
|
|
|
function toRPN(expression:string) {
|
|
let outputQueue = '';
|
|
let operatorStack = [];
|
|
let operators = {
|
|
'+': {precedence: 2, associativity: 'Left'},
|
|
'-': {precedence: 2, associativity: 'Left'},
|
|
'*': {precedence: 3, associativity: 'Left'},
|
|
'/': {precedence: 3, associativity: 'Left'},
|
|
'^': {precedence: 4, associativity: 'Left'},
|
|
'%': {precedence: 3, associativity: 'Left'},
|
|
'<': {precedence: 1, associativity: 'Left'},
|
|
'>': {precedence: 1, associativity: 'Left'},
|
|
'|': {precedence: 1, associativity: 'Left'},
|
|
'&': {precedence: 1, associativity: 'Left'},
|
|
'≤': {precedence: 1, associativity: 'Left'},
|
|
'≥': {precedence: 1, associativity: 'Left'},
|
|
'=': {precedence: 1, associativity: 'Left'},
|
|
'!': {precedence: 5, associativity: 'Right'},
|
|
};
|
|
const operatorsKeys = Object.keys(operators);
|
|
|
|
expression = expression.replace(/\s+/g, '');
|
|
let expression2 = []
|
|
|
|
let lastToken = ''
|
|
|
|
for(let i = 0; i < expression.length; i++) {
|
|
if(operatorsKeys.includes(expression[i])) {
|
|
if(lastToken !== '') {
|
|
expression2.push(lastToken)
|
|
}
|
|
else{
|
|
expression2.push('0')
|
|
}
|
|
lastToken = ''
|
|
expression2.push(expression[i])
|
|
}
|
|
else{
|
|
lastToken += expression[i]
|
|
}
|
|
}
|
|
|
|
if(lastToken !== '') {
|
|
expression2.push(lastToken)
|
|
}
|
|
else{
|
|
expression2.push('0')
|
|
}
|
|
|
|
expression2.forEach(token => {
|
|
if (parseFloat(token) || token === '0') {
|
|
outputQueue += token + ' ';
|
|
} else if (operatorsKeys.includes(token)) {
|
|
while (operatorStack.length > 0 &&
|
|
((operators[token].associativity === 'Left' &&
|
|
operators[token].precedence <= operators[operatorStack[operatorStack.length - 1]].precedence) ||
|
|
(operators[token].associativity === 'Right' &&
|
|
operators[token].precedence < operators[operatorStack[operatorStack.length - 1]].precedence))) {
|
|
outputQueue += operatorStack.pop() + ' ';
|
|
}
|
|
|
|
operatorStack.push(token);
|
|
}
|
|
});
|
|
|
|
while (operatorStack.length > 0) {
|
|
outputQueue += operatorStack.pop() + ' ';
|
|
}
|
|
|
|
return outputQueue.trim();
|
|
}
|
|
|
|
function calculateRPN(expression:string) {
|
|
let stack:number[] = [];
|
|
|
|
expression.split(' ').forEach(token => {
|
|
if (parseFloat(token) || token === '0') {
|
|
stack.push(parseFloat(token));
|
|
} else {
|
|
let [b, a] = [stack.pop(), stack.pop()];
|
|
switch (token) {
|
|
case '+': stack.push(a + b); break;
|
|
case '-': stack.push(a - b); break;
|
|
case '*': stack.push(a * b); break;
|
|
case '/': stack.push(a / b); break;
|
|
case '^': stack.push(a ** b); break;
|
|
case '%': stack.push(a % b); break;
|
|
case '<': stack.push(a < b ? 1 : 0); break;
|
|
case '>': stack.push(a > b ? 1 : 0); break;
|
|
case '|': stack.push(a || b); break;
|
|
case '&': stack.push(a && b); break;
|
|
case '≤': stack.push(a <= b ? 1 : 0); break;
|
|
case '≥': stack.push(a >= b ? 1 : 0); break;
|
|
case '=': stack.push(a === b ? 1 : 0); break;
|
|
case '!': stack.push(b ? 0 : 1); break;
|
|
}
|
|
}
|
|
});
|
|
|
|
if(stack.length === 0){
|
|
return 0
|
|
}
|
|
|
|
return stack.pop()
|
|
}
|
|
|
|
function executeRPNCalculation(text:string) {
|
|
text = text.replace(/\$([a-zA-Z0-9_]+)/g, (_, p1) => {
|
|
const v = getChatVar(p1)
|
|
const parsed = parseFloat(v)
|
|
if(isNaN(parsed)){
|
|
return "0"
|
|
}
|
|
return parsed.toString()
|
|
}).replace(/\@([a-zA-Z0-9_]+)/g, (_, p1) => {
|
|
const v = getGlobalChatVar(p1)
|
|
const parsed = parseFloat(v)
|
|
if(isNaN(parsed)){
|
|
return "0"
|
|
}
|
|
return parsed.toString()
|
|
}).replace(/&&/g, '&').replace(/\|\|/g, '|').replace(/<=/g, '≤').replace(/>=/g, '≥').replace(/==/g, '=').replace(/null/gi, '0')
|
|
const expression = toRPN(text);
|
|
const evaluated = calculateRPN(expression);
|
|
return evaluated
|
|
}
|
|
|
|
export function calcString(text:string) {
|
|
let depthText:string[] = ['']
|
|
|
|
for(let i = 0; i < text.length; i++) {
|
|
if(text[i] === '(') {
|
|
depthText.push('')
|
|
}
|
|
else if(text[i] === ')' && depthText.length > 1) {
|
|
let result = executeRPNCalculation(depthText.pop())
|
|
depthText[depthText.length - 1] += result
|
|
}
|
|
else {
|
|
depthText[depthText.length - 1] += text[i]
|
|
}
|
|
}
|
|
|
|
return executeRPNCalculation(depthText.join(''))
|
|
}
|