silentmatt / expr-eval

Mathematical expression evaluator in JavaScript
http://silentmatt.com/javascript-expression-evaluator/
MIT License
1.17k stars 241 forks source link

parser().evaluate() Function arguments? #234

Open DragonOsman opened 3 years ago

DragonOsman commented 3 years ago

Hi, everyone.

Is it okay to call that function without arguments if I don't have a variable to evaluate? How do I get the library to operate on the expression and return its value?

silentmatt commented 3 years ago

Yes, the scope object is optional, so you can call it like this:

var instance = new Parser();
var exp = instance.parse('3+4');
console.log(exp.evaluate()); // prints 7

// Or, with variables
exp = instance.parse('sqrt(x)');
// Throws an exception because x is not defined: console.log(exp.evaluate());
console.log(exp.evaluate({ x: 16 })); // prints 4
DragonOsman commented 3 years ago

I got this error:

Error: unexpected TEOF: EOF

from here (React code):

// calculate the result for the current
  // value and display it, then reset the
  // stored value to empty string
  const parser = new exprEval.Parser();
  const handleEqualsButtonClick = event => {
    if (!(event.target.textContent === "=")) {
      return null;
    } else {
      wasEqualsClicked = true;
      if (event.target.textContent === "=") {
        setStoredValue(storedValue.concat(currentValue));
        setCurrentValue(parser.parse(storedValue).evaluate());
        setStoredValue("");
      }
    }
  };

Rest of the code from the file is like this:

import React, { useState, useEffect } from "react";
import exprEval from "expr-eval";
import Keypad from "./Keypad";
import Display from "./Display";

const buttons = [{
  name: "memory-clear",
  value: "MC",
  type: "memory-function",
  id: "memory-clear",
  className: "memory-function"
}, {
  name: "memory-recall",
  value: "MR",
  type: "memory-function",
  id: "memory-recall",
  className: "memory-function"
}, {
  name: "memory-add",
  value: "M+",
  type: "memory-function",
  id: "memory-add",
  className: "memory-function"
}, {
  name: "memory-subtract",
  value: "M-",
  type: "memory-function",
  id: "memory-subtract",
  className: "memory-function"
}, {
  name: "memory-store",
  value: "MS",
  type: "memory-function",
  id: "memory-store",
  className: "memory-function"
}, {
  name: "memory", // brings up a dropdown showing the number stored in memory
  value: "M▾",
  type: "memory-function",
  id: "memory",
  className: "memory-function"
}, {
  name: "percentage",
  value: "%",
  type: "function",
  id: "percentage",
  className: "function"
}, {
  name: "clear-entry",
  value: "CE",
  type: "effect",
  id: "clear-everything",
  className: "effect"
}, {
  name: "clear",
  value: "C",
  type: "effect",
  id: "clear",
  className: "effect"
}, {
  name: "backspace",
  value: "\u232b",
  type: "effect",
  id: "backspace",
  className: "effect"
}, {
  name: "reciprocal-function",
  value: "1/𝑥",
  type: "function",
  id: "reciprocal",
  className: "function"
}, {
  name: "square-function",
  value: "𝑥²",
  type: "function",
  id: "square",
  className: "function"
}, {
  name: "square-root-function",
  value: "²√𝑥",
  type: "function",
  id: "square-root",
  className: "function"
}, {
  name: "divide",
  value: "÷",
  type: "operator",
  id: "divide",
  className: "operator"
}, {
  name: "number-button",
  value: "7",
  type: "number",
  id: "seven",
  className: "number"
}, {
  name: "number-button",
  value: "8",
  type: "number",
  id: "eight",
  className: "number"
}, {
  name: "number-button",
  value: "9",
  type: "number",
  id: "nine",
  className: "number"
}, {
  name: "multiply",
  value: "×",
  type: "operator",
  id: "multiply",
  className: "operator"
}, {
  name: "number-button",
  value: "4",
  type: "number",
  id: "four",
  className: "number"
}, {
  name: "number-button",
  value: "5",
  type: "number",
  id: "five",
  className: "number"
}, {
  name: "number-button",
  value: "6",
  type: "number",
  id: "six",
  className: "number"
}, {
  name: "minus",
  value: "-",
  type: "operator",
  id: "subtract",
  className: "operator"
}, {
  name: "number-button",
  value: "1",
  type: "number",
  id: "one",
  className: "number"
}, {
  name: "number-button",
  value: "2",
  type: "number",
  id: "two",
  className: "number"
}, {
  name: "number-button",
  value: "3",
  type: "number",
  id: "three",
  className: "number"
}, {
  name: "add",
  value: "+",
  type: "operator",
  id: "add",
  className: "operator"
}, {
  name: "sign-switch",
  value: "±",
  type: "effect",
  id: "sign-switch",
  className: "number-helper"
}, {
  name: "number-button",
  value: "0",
  type: "number",
  id: "zero",
  className: "number"
}, {
  name: "decimal",
  value: ".",
  type: "effect",
  id: "decimal",
  className: "number-helper"
}, {
  name: "equals",
  value: "=",
  type: "calculation-submit",
  id: "equals",
  className: "calculation-submit"
}];

const App = props => {
  const [currentValue, setCurrentValue] = useState("0");
  // const [currentMemoryValue, setMemory] = useState("");
  const [storedValue, setStoredValue] = useState("");

  let wasOperatorClicked = false;
  let wasEqualsClicked = false;

  const handleNumberButtonClick = event => {
    if (!wasOperatorClicked || !wasEqualsClicked) {
      if (event.target.name === "number-button") {
        if (currentValue === "0") {
          setCurrentValue(event.target.textContent);
        } else {
          setCurrentValue(currentValue.concat(event.target.textContent));
        }
      }
    } else if (wasEqualsClicked) {
      if (event.target.name === "number-button") {
        setCurrentValue(event.target.textContent);
      }
    } else if (wasOperatorClicked) {
      setStoredValue(storedValue.concat(event.target.textContent));
      setCurrentValue(event.target.textContent);
    }
  };

  const handleOperatorButtonClick = event => {
    if (!(event.target.name === "add" || event.target.name === "minus" ||
    event.target.name === "multipy" || event.target.name === "divide")) {
      return null;
    } else {
      wasOperatorClicked = true;
      if (event.target.name === "add" || event.target.name === "minus" ||
          event.target.name === "multipy" || event.target.name === "divide") {
        setStoredValue(`${currentValue} ${event.target.textContent} `);
      }
    }
  };

  // calculate the result for the current
  // value and display it, then reset the
  // stored value to empty string
  const parser = new exprEval.Parser();
  const handleEqualsButtonClick = event => {
    if (!(event.target.textContent === "=")) {
      return null;
    } else {
      wasEqualsClicked = true;
      if (event.target.textContent === "=") {
        setStoredValue(storedValue.concat(currentValue));
        setCurrentValue(parser.parse(storedValue).evaluate());
        setStoredValue("");
      }
    }
  };

  useEffect(() => {
    document.addEventListener("click", handleEqualsButtonClick);
    document.addEventListener("click", handleNumberButtonClick);
    document.addEventListener("click", handleOperatorButtonClick);

    return () => {
      document.removeEventListener("click", handleNumberButtonClick);
      document.removeEventListener("click", handleEqualsButtonClick);
      document.removeEventListener("click", handleOperatorButtonClick);
    };
  });

  return (
    <React.Fragment>
      <Display
        storedValue={storedValue}
        currentValue={currentValue}
      />
      {buttons.map((object, index) =>
        <Keypad
          key={index}
          className={object.className}
          id={object.id}
          name={object.name}
          value={object.value}
        />
      )}
    </React.Fragment>
  );
};

export default App;

Full code is on GitHub here.