simple-squiggle

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

SymbolNode.js (6372B)


      1 "use strict";
      2 
      3 Object.defineProperty(exports, "__esModule", {
      4   value: true
      5 });
      6 exports.createSymbolNode = void 0;
      7 
      8 var _string = require("../../utils/string.js");
      9 
     10 var _customs = require("../../utils/customs.js");
     11 
     12 var _factory = require("../../utils/factory.js");
     13 
     14 var _latex = require("../../utils/latex.js");
     15 
     16 var name = 'SymbolNode';
     17 var dependencies = ['math', '?Unit', 'Node'];
     18 var createSymbolNode = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
     19   var math = _ref.math,
     20       Unit = _ref.Unit,
     21       Node = _ref.Node;
     22 
     23   /**
     24    * Check whether some name is a valueless unit like "inch".
     25    * @param {string} name
     26    * @return {boolean}
     27    */
     28   function isValuelessUnit(name) {
     29     return Unit ? Unit.isValuelessUnit(name) : false;
     30   }
     31   /**
     32    * @constructor SymbolNode
     33    * @extends {Node}
     34    * A symbol node can hold and resolve a symbol
     35    * @param {string} name
     36    * @extends {Node}
     37    */
     38 
     39 
     40   function SymbolNode(name) {
     41     if (!(this instanceof SymbolNode)) {
     42       throw new SyntaxError('Constructor must be called with the new operator');
     43     } // validate input
     44 
     45 
     46     if (typeof name !== 'string') throw new TypeError('String expected for parameter "name"');
     47     this.name = name;
     48   }
     49 
     50   SymbolNode.prototype = new Node();
     51   SymbolNode.prototype.type = 'SymbolNode';
     52   SymbolNode.prototype.isSymbolNode = true;
     53   /**
     54    * Compile a node into a JavaScript function.
     55    * This basically pre-calculates as much as possible and only leaves open
     56    * calculations which depend on a dynamic scope with variables.
     57    * @param {Object} math     Math.js namespace with functions and constants.
     58    * @param {Object} argNames An object with argument names as key and `true`
     59    *                          as value. Used in the SymbolNode to optimize
     60    *                          for arguments from user assigned functions
     61    *                          (see FunctionAssignmentNode) or special symbols
     62    *                          like `end` (see IndexNode).
     63    * @return {function} Returns a function which can be called like:
     64    *                        evalNode(scope: Object, args: Object, context: *)
     65    */
     66 
     67   SymbolNode.prototype._compile = function (math, argNames) {
     68     var name = this.name;
     69 
     70     if (argNames[name] === true) {
     71       // this is a FunctionAssignment argument
     72       // (like an x when inside the expression of a function assignment `f(x) = ...`)
     73       return function (scope, args, context) {
     74         return args[name];
     75       };
     76     } else if (name in math) {
     77       return function (scope, args, context) {
     78         return scope.has(name) ? scope.get(name) : (0, _customs.getSafeProperty)(math, name);
     79       };
     80     } else {
     81       var isUnit = isValuelessUnit(name);
     82       return function (scope, args, context) {
     83         return scope.has(name) ? scope.get(name) : isUnit ? new Unit(null, name) : SymbolNode.onUndefinedSymbol(name);
     84       };
     85     }
     86   };
     87   /**
     88    * Execute a callback for each of the child nodes of this node
     89    * @param {function(child: Node, path: string, parent: Node)} callback
     90    */
     91 
     92 
     93   SymbolNode.prototype.forEach = function (callback) {// nothing to do, we don't have childs
     94   };
     95   /**
     96    * Create a new SymbolNode having it's childs be the results of calling
     97    * the provided callback function for each of the childs of the original node.
     98    * @param {function(child: Node, path: string, parent: Node) : Node} callback
     99    * @returns {SymbolNode} Returns a clone of the node
    100    */
    101 
    102 
    103   SymbolNode.prototype.map = function (callback) {
    104     return this.clone();
    105   };
    106   /**
    107    * Throws an error 'Undefined symbol {name}'
    108    * @param {string} name
    109    */
    110 
    111 
    112   SymbolNode.onUndefinedSymbol = function (name) {
    113     throw new Error('Undefined symbol ' + name);
    114   };
    115   /**
    116    * Create a clone of this node, a shallow copy
    117    * @return {SymbolNode}
    118    */
    119 
    120 
    121   SymbolNode.prototype.clone = function () {
    122     return new SymbolNode(this.name);
    123   };
    124   /**
    125    * Get string representation
    126    * @param {Object} options
    127    * @return {string} str
    128    * @override
    129    */
    130 
    131 
    132   SymbolNode.prototype._toString = function (options) {
    133     return this.name;
    134   };
    135   /**
    136    * Get HTML representation
    137    * @param {Object} options
    138    * @return {string} str
    139    * @override
    140    */
    141 
    142 
    143   SymbolNode.prototype.toHTML = function (options) {
    144     var name = (0, _string.escape)(this.name);
    145 
    146     if (name === 'true' || name === 'false') {
    147       return '<span class="math-symbol math-boolean">' + name + '</span>';
    148     } else if (name === 'i') {
    149       return '<span class="math-symbol math-imaginary-symbol">' + name + '</span>';
    150     } else if (name === 'Infinity') {
    151       return '<span class="math-symbol math-infinity-symbol">' + name + '</span>';
    152     } else if (name === 'NaN') {
    153       return '<span class="math-symbol math-nan-symbol">' + name + '</span>';
    154     } else if (name === 'null') {
    155       return '<span class="math-symbol math-null-symbol">' + name + '</span>';
    156     } else if (name === 'undefined') {
    157       return '<span class="math-symbol math-undefined-symbol">' + name + '</span>';
    158     }
    159 
    160     return '<span class="math-symbol">' + name + '</span>';
    161   };
    162   /**
    163    * Get a JSON representation of the node
    164    * @returns {Object}
    165    */
    166 
    167 
    168   SymbolNode.prototype.toJSON = function () {
    169     return {
    170       mathjs: 'SymbolNode',
    171       name: this.name
    172     };
    173   };
    174   /**
    175    * Instantiate a SymbolNode from its JSON representation
    176    * @param {Object} json  An object structured like
    177    *                       `{"mathjs": "SymbolNode", name: "x"}`,
    178    *                       where mathjs is optional
    179    * @returns {SymbolNode}
    180    */
    181 
    182 
    183   SymbolNode.fromJSON = function (json) {
    184     return new SymbolNode(json.name);
    185   };
    186   /**
    187    * Get LaTeX representation
    188    * @param {Object} options
    189    * @return {string} str
    190    * @override
    191    */
    192 
    193 
    194   SymbolNode.prototype._toTex = function (options) {
    195     var isUnit = false;
    196 
    197     if (typeof math[this.name] === 'undefined' && isValuelessUnit(this.name)) {
    198       isUnit = true;
    199     }
    200 
    201     var symbol = (0, _latex.toSymbol)(this.name, isUnit);
    202 
    203     if (symbol[0] === '\\') {
    204       // no space needed if the symbol starts with '\'
    205       return symbol;
    206     } // the space prevents symbols from breaking stuff like '\cdot' if it's written right before the symbol
    207 
    208 
    209     return ' ' + symbol;
    210   };
    211 
    212   return SymbolNode;
    213 }, {
    214   isClass: true,
    215   isNode: true
    216 });
    217 exports.createSymbolNode = createSymbolNode;