simple-squiggle

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

AccessorNode.js (6815B)


      1 "use strict";
      2 
      3 Object.defineProperty(exports, "__esModule", {
      4   value: true
      5 });
      6 exports.createAccessorNode = void 0;
      7 
      8 var _is = require("../../utils/is.js");
      9 
     10 var _customs = require("../../utils/customs.js");
     11 
     12 var _factory = require("../../utils/factory.js");
     13 
     14 var _access = require("./utils/access.js");
     15 
     16 var name = 'AccessorNode';
     17 var dependencies = ['subset', 'Node'];
     18 var createAccessorNode = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
     19   var subset = _ref.subset,
     20       Node = _ref.Node;
     21   var access = (0, _access.accessFactory)({
     22     subset: subset
     23   });
     24   /**
     25    * @constructor AccessorNode
     26    * @extends {Node}
     27    * Access an object property or get a matrix subset
     28    *
     29    * @param {Node} object                 The object from which to retrieve
     30    *                                      a property or subset.
     31    * @param {IndexNode} index             IndexNode containing ranges
     32    */
     33 
     34   function AccessorNode(object, index) {
     35     if (!(this instanceof AccessorNode)) {
     36       throw new SyntaxError('Constructor must be called with the new operator');
     37     }
     38 
     39     if (!(0, _is.isNode)(object)) {
     40       throw new TypeError('Node expected for parameter "object"');
     41     }
     42 
     43     if (!(0, _is.isIndexNode)(index)) {
     44       throw new TypeError('IndexNode expected for parameter "index"');
     45     }
     46 
     47     this.object = object || null;
     48     this.index = index; // readonly property name
     49 
     50     Object.defineProperty(this, 'name', {
     51       get: function () {
     52         if (this.index) {
     53           return this.index.isObjectProperty() ? this.index.getObjectProperty() : '';
     54         } else {
     55           return this.object.name || '';
     56         }
     57       }.bind(this),
     58       set: function set() {
     59         throw new Error('Cannot assign a new name, name is read-only');
     60       }
     61     });
     62   }
     63 
     64   AccessorNode.prototype = new Node();
     65   AccessorNode.prototype.type = 'AccessorNode';
     66   AccessorNode.prototype.isAccessorNode = true;
     67   /**
     68    * Compile a node into a JavaScript function.
     69    * This basically pre-calculates as much as possible and only leaves open
     70    * calculations which depend on a dynamic scope with variables.
     71    * @param {Object} math     Math.js namespace with functions and constants.
     72    * @param {Object} argNames An object with argument names as key and `true`
     73    *                          as value. Used in the SymbolNode to optimize
     74    *                          for arguments from user assigned functions
     75    *                          (see FunctionAssignmentNode) or special symbols
     76    *                          like `end` (see IndexNode).
     77    * @return {function} Returns a function which can be called like:
     78    *                        evalNode(scope: Object, args: Object, context: *)
     79    */
     80 
     81   AccessorNode.prototype._compile = function (math, argNames) {
     82     var evalObject = this.object._compile(math, argNames);
     83 
     84     var evalIndex = this.index._compile(math, argNames);
     85 
     86     if (this.index.isObjectProperty()) {
     87       var prop = this.index.getObjectProperty();
     88       return function evalAccessorNode(scope, args, context) {
     89         // get a property from an object evaluated using the scope.
     90         return (0, _customs.getSafeProperty)(evalObject(scope, args, context), prop);
     91       };
     92     } else {
     93       return function evalAccessorNode(scope, args, context) {
     94         var object = evalObject(scope, args, context);
     95         var index = evalIndex(scope, args, object); // we pass object here instead of context
     96 
     97         return access(object, index);
     98       };
     99     }
    100   };
    101   /**
    102    * Execute a callback for each of the child nodes of this node
    103    * @param {function(child: Node, path: string, parent: Node)} callback
    104    */
    105 
    106 
    107   AccessorNode.prototype.forEach = function (callback) {
    108     callback(this.object, 'object', this);
    109     callback(this.index, 'index', this);
    110   };
    111   /**
    112    * Create a new AccessorNode having it's childs be the results of calling
    113    * the provided callback function for each of the childs of the original node.
    114    * @param {function(child: Node, path: string, parent: Node): Node} callback
    115    * @returns {AccessorNode} Returns a transformed copy of the node
    116    */
    117 
    118 
    119   AccessorNode.prototype.map = function (callback) {
    120     return new AccessorNode(this._ifNode(callback(this.object, 'object', this)), this._ifNode(callback(this.index, 'index', this)));
    121   };
    122   /**
    123    * Create a clone of this node, a shallow copy
    124    * @return {AccessorNode}
    125    */
    126 
    127 
    128   AccessorNode.prototype.clone = function () {
    129     return new AccessorNode(this.object, this.index);
    130   };
    131   /**
    132    * Get string representation
    133    * @param {Object} options
    134    * @return {string}
    135    */
    136 
    137 
    138   AccessorNode.prototype._toString = function (options) {
    139     var object = this.object.toString(options);
    140 
    141     if (needParenthesis(this.object)) {
    142       object = '(' + object + ')';
    143     }
    144 
    145     return object + this.index.toString(options);
    146   };
    147   /**
    148    * Get HTML representation
    149    * @param {Object} options
    150    * @return {string}
    151    */
    152 
    153 
    154   AccessorNode.prototype.toHTML = function (options) {
    155     var object = this.object.toHTML(options);
    156 
    157     if (needParenthesis(this.object)) {
    158       object = '<span class="math-parenthesis math-round-parenthesis">(</span>' + object + '<span class="math-parenthesis math-round-parenthesis">)</span>';
    159     }
    160 
    161     return object + this.index.toHTML(options);
    162   };
    163   /**
    164    * Get LaTeX representation
    165    * @param {Object} options
    166    * @return {string}
    167    */
    168 
    169 
    170   AccessorNode.prototype._toTex = function (options) {
    171     var object = this.object.toTex(options);
    172 
    173     if (needParenthesis(this.object)) {
    174       object = '\\left(\' + object + \'\\right)';
    175     }
    176 
    177     return object + this.index.toTex(options);
    178   };
    179   /**
    180    * Get a JSON representation of the node
    181    * @returns {Object}
    182    */
    183 
    184 
    185   AccessorNode.prototype.toJSON = function () {
    186     return {
    187       mathjs: 'AccessorNode',
    188       object: this.object,
    189       index: this.index
    190     };
    191   };
    192   /**
    193    * Instantiate an AccessorNode from its JSON representation
    194    * @param {Object} json  An object structured like
    195    *                       `{"mathjs": "AccessorNode", object: ..., index: ...}`,
    196    *                       where mathjs is optional
    197    * @returns {AccessorNode}
    198    */
    199 
    200 
    201   AccessorNode.fromJSON = function (json) {
    202     return new AccessorNode(json.object, json.index);
    203   };
    204   /**
    205    * Are parenthesis needed?
    206    * @private
    207    */
    208 
    209 
    210   function needParenthesis(node) {
    211     // TODO: maybe make a method on the nodes which tells whether they need parenthesis?
    212     return !((0, _is.isAccessorNode)(node) || (0, _is.isArrayNode)(node) || (0, _is.isConstantNode)(node) || (0, _is.isFunctionNode)(node) || (0, _is.isObjectNode)(node) || (0, _is.isParenthesisNode)(node) || (0, _is.isSymbolNode)(node));
    213   }
    214 
    215   return AccessorNode;
    216 }, {
    217   isClass: true,
    218   isNode: true
    219 });
    220 exports.createAccessorNode = createAccessorNode;