simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

parsing.md (7332B)


      1 # Expression parsing and evaluation
      2 
      3 Expressions can be parsed and evaluated in various ways:
      4 
      5 - Using the function [`math.evaluate(expr [,scope])`](#evaluate).
      6 - Using the function [`math.compile(expr)`](#compile).
      7 - Using the function [`math.parse(expr)`](#parse).
      8 - By creating a [parser](#parser), `math.parser()`, which contains a method
      9   `evaluate` and keeps a scope with assigned variables in memory.
     10 
     11 
     12 ## Evaluate
     13 
     14 Math.js comes with a function `math.evaluate` to evaluate expressions. Syntax:
     15 
     16 ```js
     17 math.evaluate(expr)
     18 math.evaluate(expr, scope)
     19 math.evaluate([expr1, expr2, expr3, ...])
     20 math.evaluate([expr1, expr2, expr3, ...], scope)
     21 ```
     22 
     23 Function `evaluate` accepts a single expression or an array with
     24 expressions as the first argument and has an optional second argument
     25 containing a scope with variables and functions. The scope can be a regular
     26 JavaScript Object, or Map. The scope will be used to resolve symbols, and to write
     27 assigned variables or function.
     28 
     29 The following code demonstrates how to evaluate expressions.
     30 
     31 ```js
     32 // evaluate expressions
     33 math.evaluate('sqrt(3^2 + 4^2)')        // 5
     34 math.evaluate('sqrt(-4)')               // 2i
     35 math.evaluate('2 inch to cm')           // 5.08 cm
     36 math.evaluate('cos(45 deg)')            // 0.7071067811865476
     37 
     38 // provide a scope
     39 let scope = {
     40     a: 3,
     41     b: 4
     42 }
     43 math.evaluate('a * b', scope)           // 12
     44 math.evaluate('c = 2.3 + 4.5', scope)   // 6.8
     45 scope.c                                 // 6.8
     46 ```
     47 
     48 
     49 ## Compile
     50 
     51 Math.js contains a function `math.compile` which compiles expressions
     52 into JavaScript code. This is a shortcut for first [parsing](#parse) and then
     53 compiling an expression. The syntax is:
     54 
     55 ```js
     56 math.compile(expr)
     57 math.compile([expr1, expr2, expr3, ...])
     58 ```
     59 
     60 Function `compile` accepts a single expression or an array with
     61 expressions as the argument. Function `compile` returns an object with a function
     62 `evaluate([scope])`, which can be executed to evaluate the expression against an
     63 (optional) scope:
     64 
     65 ```js
     66 const code = math.compile(expr)       // compile an expression
     67 const result = code.evaluate([scope]) // evaluate the code with an optional scope
     68 ```
     69 
     70 An expression needs to be compiled only once, after which the
     71 expression can be evaluated repeatedly and against different scopes.
     72 The optional scope is used to resolve symbols and to write assigned
     73 variables or functions. Parameter [`scope`](#scope) can be a regular Object, or Map.
     74 
     75 Example usage:
     76 
     77 ```js
     78 // parse an expression into a node, and evaluate the node
     79 const code1 = math.compile('sqrt(3^2 + 4^2)')
     80 code1.evaluate()  // 5
     81 ```
     82 
     83 
     84 ## Parse
     85 
     86 Math.js contains a function `math.parse` to parse expressions into an
     87 [expression tree](expression_trees.md). The syntax is:
     88 
     89 ```js
     90 math.parse(expr)
     91 math.parse([expr1, expr2, expr3, ...])
     92 ```
     93 
     94 Function `parse` accepts a single expression or an array with
     95 expressions as the argument. Function `parse` returns a the root node of the tree,
     96 which can be successively compiled and evaluated:
     97 
     98 ```js
     99 const node = math.parse(expr)         // parse expression into a node tree
    100 const code = node.compile()           // compile the node tree
    101 const result = code.evaluate([scope]) // evaluate the code with an optional scope
    102 ```
    103 
    104 The API of nodes is described in detail on the page
    105 [Expression trees](expression_trees.md).
    106 
    107 An expression needs to be parsed and compiled only once, after which the
    108 expression can be evaluated repeatedly. On evaluation, an optional scope
    109 can be provided, which is used to resolve symbols and to write assigned
    110 variables or functions. Parameter [`scope`](#scope) is a regular Object or Map.
    111 
    112 Example usage:
    113 
    114 ```js
    115 // parse an expression into a node, and evaluate the node
    116 const node1 = math.parse('sqrt(3^2 + 4^2)')
    117 const code1 = node1.compile()
    118 code1.evaluate() // 5
    119 
    120 // provide a scope
    121 const node2 = math.parse('x^a')
    122 const code2 = node2.compile()
    123 let scope = {
    124     x: 3,
    125     a: 2
    126 }
    127 code2.evaluate(scope) // 9
    128 
    129 // change a value in the scope and re-evaluate the node
    130 scope.a = 3
    131 code2.evaluate(scope) // 27
    132 ```
    133 
    134 Parsed expressions can be exported to text using `node.toString()`, and can
    135 be exported to LaTeX using `node.toTex()`. The LaTeX export can be used to
    136 pretty print an expression in the browser with a library like
    137 [MathJax](https://www.mathjax.org/). Example usage:
    138 
    139 ```js
    140 // parse an expression
    141 const node = math.parse('sqrt(x/x+1)')
    142 node.toString()   // returns 'sqrt((x / x) + 1)'
    143 node.toTex()      // returns '\sqrt{ {\frac{x}{x} }+{1} }'
    144 ```
    145 
    146 
    147 ## Parser
    148 
    149 In addition to the static functions [`math.evaluate`](#evaluate) and
    150 [`math.parse`](#parse), math.js contains a parser with functions `evaluate` and
    151 `parse`, which automatically keeps a scope with assigned variables in memory.
    152 The parser also contains some convenience functions to get, set, and remove
    153 variables from memory.
    154 
    155 A parser can be created by:
    156 
    157 ```js
    158 const parser = math.parser()
    159 ```
    160 
    161 The parser contains the following functions:
    162 
    163 - `clear()`
    164   Completely clear the parser's scope.
    165 - `evaluate(expr)`
    166   Evaluate an expression. Returns the result of the expression.
    167 - `get(name)`
    168   Retrieve a variable or function from the parser's scope.
    169 - `getAll()`
    170   Retrieve a map with all defined a variables from the parser's scope.
    171 - `remove(name)`
    172   Remove a variable or function from the parser's scope.
    173 - `set(name, value)`
    174   Set a variable or function in the parser's scope.
    175 
    176 The following code shows how to create and use a parser.
    177 
    178 ```js
    179 // create a parser
    180 const parser = math.parser()
    181 
    182 // evaluate expressions
    183 parser.evaluate('sqrt(3^2 + 4^2)')      // 5
    184 parser.evaluate('sqrt(-4)')             // 2i
    185 parser.evaluate('2 inch to cm')         // 5.08 cm
    186 parser.evaluate('cos(45 deg)')          // 0.7071067811865476
    187 
    188 // define variables and functions
    189 parser.evaluate('x = 7 / 2')            // 3.5
    190 parser.evaluate('x + 3')                // 6.5
    191 parser.evaluate('f(x, y) = x^y')        // f(x, y)
    192 parser.evaluate('f(2, 3)')              // 8
    193 
    194 // get and set variables and functions
    195 const x = parser.get('x')               // x = 7
    196 const f = parser.get('f')               // function
    197 const g = f(3, 3)                       // g = 27
    198 parser.set('h', 500)
    199 parser.evaluate('h / 2')                // 250
    200 parser.set('hello', function (name) {
    201     return 'hello, ' + name + '!'
    202 })
    203 parser.evaluate('hello("user")')        // "hello, user!"
    204 
    205 // clear defined functions and variables
    206 parser.clear()
    207 ```
    208 
    209 ## Scope
    210 
    211 The scope is a data-structure used to store and lookup variables and functions defined and used by expressions.
    212 
    213 It is passed to mathjs via calls to [`math.evaluate`](#evaluate) or `simplify`.
    214 
    215 For ease of use, it can be a Plain Javascript Object; for safety it can be a plain `Map` and for flexibility, any object that has
    216 the methods `get`/`set`/`has`/`keys`, seen on `Map`.
    217 
    218 Some care is taken to mutate the same object that is passed into mathjs, so they can collect the definitions from mathjs scripts and expressions.
    219 
    220 `evaluate` will fail if the expression uses a blacklisted symbol, preventing mathjs expressions to escape into Javascript. This is enforced by access to the scope.
    221 
    222 For less reliance on this blacklist, scope can also be a `Map`, which allows mathjs expressions to define variables and functions of any name.
    223 
    224 For more, see [examples of custom scopes](../../examples/advanced/custom_scope_objects.js).