• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const OperatorLevels = {
17  '+': 0,
18  '-': 0,
19  '*': 1,
20  '/': 1,
21}
22
23const OperatorHandlers = {
24  '+': (firstOperand, secondOperand) => (parseFloat(firstOperand) + parseFloat(secondOperand)).toFixed(getFloatNum(firstOperand, secondOperand, '+')),
25  '-': (firstOperand, secondOperand) => (firstOperand - secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '-')),
26  '*': (firstOperand, secondOperand) => (firstOperand * secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '*')),
27  '/': (firstOperand, secondOperand) => (firstOperand / secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '/')),
28}
29
30function getFloatNum(firstOperand, secondOperand, oprate) {
31  let result = 0
32  let oneString = (new String(firstOperand)).toString()
33  let otherString = (new String(secondOperand)).toString()
34  let firstNum = 0
35  if (oneString.indexOf('.') !== -1) {
36    firstNum = oneString.split('.')[1].length
37  }
38  let secondNum = 0
39  if (otherString.indexOf('.') !== -1) {
40    secondNum = otherString.split('.')[1].length
41  }
42  if (oprate === '+' || oprate === '-') {
43    result = Math.max(firstNum, secondNum)
44  }
45  if (oprate === '*') {
46    result = firstNum + secondNum
47  }
48  if (oprate === '/') {
49    result = (firstNum + otherString.length) > 3 ? (firstNum + otherString.length) : 3
50  }
51  return result
52}
53
54function calcSuffixExpression(expression) {
55  const numberStack = []
56
57
58  while (expression.length) {
59    let element = expression.shift()
60    if (!isOperator(element)) {
61      numberStack.push(element)
62    } else {
63      const firstStackElement = numberStack.pop()
64      const secondStackElement = numberStack.pop()
65      const result = OperatorHandlers[element](secondStackElement, firstStackElement)
66      if (result.length > 15) {
67        numberStack.push(parseFloat(result).toExponential())
68      } else {
69        numberStack.push(result)
70      }
71    }
72  }
73  return numberStack[0]
74}
75
76function toSuffixExpression(expression) {
77  const operatorStack = []
78  const suffixExpression = []
79  let topOperator
80  for (let index = 0, size = expression.length; index < size; ++index) {
81    const element = expression[index]
82    if (element === '(') {
83      operatorStack.push(element)
84      continue
85    }
86    if (element === ')') {
87      if (operatorStack.length) {
88        let operator = operatorStack.pop()
89        while (operator !== '(') {
90          suffixExpression.push(operator)
91          operator = operatorStack.pop()
92        }
93      }
94      continue
95    }
96    if (isOperator(element)) {
97      if (!operatorStack.length) {
98        operatorStack.push(element)
99      } else {
100        topOperator = operatorStack[operatorStack.length - 1]
101        if (!isGrouping(topOperator) && !isPrioritized(element, topOperator)) {
102          while (operatorStack.length) {
103            suffixExpression.push(operatorStack.pop())
104          }
105        }
106        operatorStack.push(element)
107      }
108      continue
109    }
110    suffixExpression.push(element)
111  }
112  while (operatorStack.length) {
113    suffixExpression.push(operatorStack.pop())
114  }
115  return suffixExpression
116}
117
118function parseInfixExpression(inputContent) {
119  const size = inputContent.length
120  const lastIndex = size - 1
121  let singleChar = ''
122  const expression = []
123  for (let index = 0; index < size; index++) {
124    const element = inputContent[index]
125    if (isGrouping(element)) {
126      if (singleChar !== '') {
127        expression.push(singleChar)
128        singleChar = ''
129      }
130      expression.push(element)
131    } else if (isOperator(element)) {
132      if (isSymbol(element) && (index === 0 || inputContent[index - 1] === '(')) {
133        singleChar += element
134      } else {
135        if (singleChar !== '') {
136          expression.push(singleChar)
137          singleChar = ''
138        }
139        if (index !== lastIndex) {
140          expression.push(element)
141        }
142      }
143    } else {
144      singleChar += element
145    }
146    if (index === lastIndex && singleChar !== '') {
147      expression.push(singleChar)
148    }
149  }
150  return expression
151}
152
153function isPrioritized(firstOperator, secondOperator) {
154  return OperatorLevels[firstOperator] > OperatorLevels[secondOperator]
155}
156
157export function isOperator(operator) {
158  return (
159    operator === '+' || operator === '-' || operator === '*' || operator === '/'
160  )
161}
162
163function isSymbol(symbol) {
164  return symbol === '+' || symbol === '-'
165}
166
167function isGrouping(operator) {
168  return operator === '(' || operator === ')'
169}
170
171export function calc(inputContent) {
172  const infixExpression = parseInfixExpression(inputContent)
173  const suffixExpression = toSuffixExpression(infixExpression)
174  return calcSuffixExpression(suffixExpression)
175}