• 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 */
15const OPERATORLEVELS = {
16  '+': 0,
17  '-': 0,
18  '*': 1,
19  '/': 1,
20}
21
22const OPERATORHANDLERS = {
23  '+': (firstOperand, secondOperand) => (parseFloat(firstOperand) + parseFloat(secondOperand)).toFixed(getFloatNum(firstOperand, secondOperand, '+')),
24  '-': (firstOperand, secondOperand) => (firstOperand - secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '-')),
25  '*': (firstOperand, secondOperand) => (firstOperand * secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '*')),
26  '/': (firstOperand, secondOperand) => (firstOperand / secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '/')),
27}
28
29function getFloatNum(firstOperand, secondOperand, oprate) {
30  let result = 0
31  let oneString = (new String(firstOperand)).toString()
32  let otherString = (new String(secondOperand)).toString()
33  let firstNum = 0
34  if (oneString.indexOf('.') !== -1) {
35    firstNum = oneString.split('.')[1].length
36  }
37  let secondNum = 0
38  if (otherString.indexOf('.') !== -1) {
39    secondNum = otherString.split('.')[1].length
40  }
41  if (oprate === '+' || oprate === '-') {
42    result = Math.max(firstNum, secondNum)
43  }
44  if (oprate === '*') {
45    result = firstNum + secondNum
46  }
47  if (oprate === '/') {
48    result = (firstNum + otherString.length) > 3 ? (firstNum + otherString.length) : 3
49  }
50  return result
51}
52
53function calcSuffixExpression(expression) {
54  const numberStack = []
55  while (expression.length) {
56    let element = expression.shift()
57    if (!isOperator(element)) {
58      numberStack.push(element)
59    } else {
60      const firstStackElement = numberStack.pop()
61      const secondStackElement = numberStack.pop()
62      const result = OPERATORHANDLERS[element](secondStackElement, firstStackElement)
63      if (result.length > 15) {
64        numberStack.push(parseFloat(result).toExponential())
65      } else {
66        numberStack.push(result)
67      }
68    }
69  }
70  return numberStack[0]
71}
72
73function toSuffixExpression(expression) {
74  const operatorStack = []
75  const suffixExpression = []
76  let topOperator
77  for (let index = 0, size = expression.length; index < size; ++index) {
78    const element = expression[index]
79    if (element === '(') {
80      operatorStack.push(element)
81      continue
82    }
83    if (element === ')') {
84      if (operatorStack.length) {
85        let operator = operatorStack.pop()
86        while (operator !== '(') {
87          suffixExpression.push(operator)
88          operator = operatorStack.pop()
89        }
90      }
91      continue
92    }
93    if (isOperator(element)) {
94      if (!operatorStack.length) {
95        operatorStack.push(element)
96      } else {
97        topOperator = operatorStack[operatorStack.length - 1]
98        if (!isGrouping(topOperator) && !isPrioritized(element, topOperator)) {
99          while (operatorStack.length && !isPrioritized(element, operatorStack[operatorStack.length - 1])) {
100            suffixExpression.push(operatorStack.pop())
101          }
102        }
103        operatorStack.push(element)
104      }
105      continue
106    }
107    suffixExpression.push(element)
108  }
109  while (operatorStack.length) {
110    suffixExpression.push(operatorStack.pop())
111  }
112  return suffixExpression
113}
114
115function parseInfixExpression(inputContent) {
116  const size = inputContent.length
117  const lastIndex = size - 1
118  let singleChar = ''
119  const expression = []
120  for (let index = 0; index < size; index++) {
121    const element = inputContent[index]
122    if (isGrouping(element)) {
123      if (singleChar !== '') {
124        expression.push(singleChar)
125        singleChar = ''
126      }
127      expression.push(element)
128    } else if (isOperator(element)) {
129      if (isSymbol(element) && (index === 0 || inputContent[index - 1] === '(')) {
130        singleChar += element
131      } else {
132        if (singleChar !== '') {
133          expression.push(singleChar)
134          singleChar = ''
135        }
136        if (index !== lastIndex) {
137          expression.push(element)
138        }
139      }
140    } else {
141      singleChar += element
142    }
143    if (index === lastIndex && singleChar !== '') {
144      expression.push(singleChar)
145    }
146  }
147  return expression
148}
149
150function isPrioritized(firstOperator, secondOperator) {
151  return OPERATORLEVELS[firstOperator] > OPERATORLEVELS[secondOperator]
152}
153
154export function isOperator(operator) {
155  return (
156    operator === '+' || operator === '-' || operator === '*' || operator === '/'
157  )
158}
159
160function isSymbol(symbol) {
161  return symbol === '+' || symbol === '-'
162}
163
164function isGrouping(operator) {
165  return operator === '(' || operator === ')'
166}
167
168export function calc(inputContent) {
169  const infixExpression = parseInfixExpression(inputContent)
170  const suffixExpression = toSuffixExpression(infixExpression)
171  return calcSuffixExpression(suffixExpression)
172}