Skip to content

String representation of Expression in Node.js #256

Open
@n-riesco

Description

@n-riesco

This issue was originally reported in n-riesco/ijavascript#240 .

The Node.js CLI doesn't use toString to show objects as a string. This makes the use of expr-eval in the Node.js CLI somewhat cumbersome. For example:

Click to expand example
$ node
Welcome to Node.js v14.13.0.
Type ".help" for more information.

> var Parser = require('expr-eval').Parser;
undefined

> expr = Parser.parse("2 * x + 1");
Expression {
  tokens: [
    Instruction { type: 'INUMBER', value: 2 },
    Instruction { type: 'IVAR', value: 'x' },
    Instruction { type: 'IOP2', value: '*' },
    Instruction { type: 'INUMBER', value: 1 },
    Instruction { type: 'IOP2', value: '+' }
  ],
  parser: Parser {
    options: {},
    unaryOps: {
      sin: [Function: sin],
      cos: [Function: cos],
      tan: [Function: tan],
      asin: [Function: asin],
      acos: [Function: acos],
      atan: [Function: atan],
      sinh: [Function: sinh],
      cosh: [Function: cosh],
      tanh: [Function: tanh],
      asinh: [Function: asinh],
      acosh: [Function: acosh],
      atanh: [Function: atanh],
      sqrt: [Function: sqrt],
      cbrt: [Function: cbrt],
      log: [Function: log],
      log2: [Function: log2],
      ln: [Function: log],
      lg: [Function: log10],
      log10: [Function: log10],
      expm1: [Function: expm1],
      log1p: [Function: log1p],
      abs: [Function: abs],
      ceil: [Function: ceil],
      floor: [Function: floor],
      round: [Function: round],
      trunc: [Function: trunc],
      '-': [Function: neg],
      '+': [Function: Number],
      exp: [Function: exp],
      not: [Function: not],
      length: [Function: stringOrArrayLength],
      '!': [Function: factorial],
      sign: [Function: sign]
    },
    binaryOps: {
      '+': [Function: add],
      '-': [Function: sub],
      '*': [Function: mul],
      '/': [Function: div],
      '%': [Function: mod],
      '^': [Function: pow],
      '||': [Function: concat],
      '==': [Function: equal],
      '!=': [Function: notEqual],
      '>': [Function: greaterThan],
      '<': [Function: lessThan],
      '>=': [Function: greaterThanEqual],
      '<=': [Function: lessThanEqual],
      and: [Function: andOperator],
      or: [Function: orOperator],
      in: [Function: inOperator],
      '=': [Function: setVar],
      '[': [Function: arrayIndex]
    },
    ternaryOps: { '?': [Function: condition] },
    functions: {
      random: [Function: random],
      fac: [Function: factorial],
      min: [Function: min],
      max: [Function: max],
      hypot: [Function: hypot],
      pyt: [Function: hypot],
      pow: [Function: pow],
      atan2: [Function: atan2],
      if: [Function: condition],
      gamma: [Function: gamma],
      roundTo: [Function: roundTo],
      map: [Function: arrayMap],
      fold: [Function: arrayFold],
      filter: [Function: arrayFilter],
      indexOf: [Function: stringOrArrayIndexOf],
      join: [Function: arrayJoin]
    },
    consts: {
      E: 2.718281828459045,
      PI: 3.141592653589793,
      true: true,
      false: false
    }
  },
  unaryOps: {
    sin: [Function: sin],
    cos: [Function: cos],
    tan: [Function: tan],
    asin: [Function: asin],
    acos: [Function: acos],
    atan: [Function: atan],
    sinh: [Function: sinh],
    cosh: [Function: cosh],
    tanh: [Function: tanh],
    asinh: [Function: asinh],
    acosh: [Function: acosh],
    atanh: [Function: atanh],
    sqrt: [Function: sqrt],
    cbrt: [Function: cbrt],
    log: [Function: log],
    log2: [Function: log2],
    ln: [Function: log],
    lg: [Function: log10],
    log10: [Function: log10],
    expm1: [Function: expm1],
    log1p: [Function: log1p],
    abs: [Function: abs],
    ceil: [Function: ceil],
    floor: [Function: floor],
    round: [Function: round],
    trunc: [Function: trunc],
    '-': [Function: neg],
    '+': [Function: Number],
    exp: [Function: exp],
    not: [Function: not],
    length: [Function: stringOrArrayLength],
    '!': [Function: factorial],
    sign: [Function: sign]
  },
  binaryOps: {
    '+': [Function: add],
    '-': [Function: sub],
    '*': [Function: mul],
    '/': [Function: div],
    '%': [Function: mod],
    '^': [Function: pow],
    '||': [Function: concat],
    '==': [Function: equal],
    '!=': [Function: notEqual],
    '>': [Function: greaterThan],
    '<': [Function: lessThan],
    '>=': [Function: greaterThanEqual],
    '<=': [Function: lessThanEqual],
    and: [Function: andOperator],
    or: [Function: orOperator],
    in: [Function: inOperator],
    '=': [Function: setVar],
    '[': [Function: arrayIndex]
  },
  ternaryOps: { '?': [Function: condition] },
  functions: {
    random: [Function: random],
    fac: [Function: factorial],
    min: [Function: min],
    max: [Function: max],
    hypot: [Function: hypot],
    pyt: [Function: hypot],
    pow: [Function: pow],
    atan2: [Function: atan2],
    if: [Function: condition],
    gamma: [Function: gamma],
    roundTo: [Function: roundTo],
    map: [Function: arrayMap],
    fold: [Function: arrayFold],
    filter: [Function: arrayFilter],
    indexOf: [Function: stringOrArrayIndexOf],
    join: [Function: arrayJoin]
  }
}

> expr2 = expr.substitute("x", "4 * x");
Expression {
  tokens: [
    Instruction { type: 'INUMBER', value: 2 },
    Instruction { type: 'INUMBER', value: 4 },
    Instruction { type: 'IVAR', value: 'x' },
    Instruction { type: 'IOP2', value: '*' },
    Instruction { type: 'IOP2', value: '*' },
    Instruction { type: 'INUMBER', value: 1 },
    Instruction { type: 'IOP2', value: '+' }
  ],
  parser: Parser {
    options: {},
    unaryOps: {
      sin: [Function: sin],
      cos: [Function: cos],
      tan: [Function: tan],
      asin: [Function: asin],
      acos: [Function: acos],
      atan: [Function: atan],
      sinh: [Function: sinh],
      cosh: [Function: cosh],
      tanh: [Function: tanh],
      asinh: [Function: asinh],
      acosh: [Function: acosh],
      atanh: [Function: atanh],
      sqrt: [Function: sqrt],
      cbrt: [Function: cbrt],
      log: [Function: log],
      log2: [Function: log2],
      ln: [Function: log],
      lg: [Function: log10],
      log10: [Function: log10],
      expm1: [Function: expm1],
      log1p: [Function: log1p],
      abs: [Function: abs],
      ceil: [Function: ceil],
      floor: [Function: floor],
      round: [Function: round],
      trunc: [Function: trunc],
      '-': [Function: neg],
      '+': [Function: Number],
      exp: [Function: exp],
      not: [Function: not],
      length: [Function: stringOrArrayLength],
      '!': [Function: factorial],
      sign: [Function: sign]
    },
    binaryOps: {
      '+': [Function: add],
      '-': [Function: sub],
      '*': [Function: mul],
      '/': [Function: div],
      '%': [Function: mod],
      '^': [Function: pow],
      '||': [Function: concat],
      '==': [Function: equal],
      '!=': [Function: notEqual],
      '>': [Function: greaterThan],
      '<': [Function: lessThan],
      '>=': [Function: greaterThanEqual],
      '<=': [Function: lessThanEqual],
      and: [Function: andOperator],
      or: [Function: orOperator],
      in: [Function: inOperator],
      '=': [Function: setVar],
      '[': [Function: arrayIndex]
    },
    ternaryOps: { '?': [Function: condition] },
    functions: {
      random: [Function: random],
      fac: [Function: factorial],
      min: [Function: min],
      max: [Function: max],
      hypot: [Function: hypot],
      pyt: [Function: hypot],
      pow: [Function: pow],
      atan2: [Function: atan2],
      if: [Function: condition],
      gamma: [Function: gamma],
      roundTo: [Function: roundTo],
      map: [Function: arrayMap],
      fold: [Function: arrayFold],
      filter: [Function: arrayFilter],
      indexOf: [Function: stringOrArrayIndexOf],
      join: [Function: arrayJoin]
    },
    consts: {
      E: 2.718281828459045,
      PI: 3.141592653589793,
      true: true,
      false: false
    }
  },
  unaryOps: {
    sin: [Function: sin],
    cos: [Function: cos],
    tan: [Function: tan],
    asin: [Function: asin],
    acos: [Function: acos],
    atan: [Function: atan],
    sinh: [Function: sinh],
    cosh: [Function: cosh],
    tanh: [Function: tanh],
    asinh: [Function: asinh],
    acosh: [Function: acosh],
    atanh: [Function: atanh],
    sqrt: [Function: sqrt],
    cbrt: [Function: cbrt],
    log: [Function: log],
    log2: [Function: log2],
    ln: [Function: log],
    lg: [Function: log10],
    log10: [Function: log10],
    expm1: [Function: expm1],
    log1p: [Function: log1p],
    abs: [Function: abs],
    ceil: [Function: ceil],
    floor: [Function: floor],
    round: [Function: round],
    trunc: [Function: trunc],
    '-': [Function: neg],
    '+': [Function: Number],
    exp: [Function: exp],
    not: [Function: not],
    length: [Function: stringOrArrayLength],
    '!': [Function: factorial],
    sign: [Function: sign]
  },
  binaryOps: {
    '+': [Function: add],
    '-': [Function: sub],
    '*': [Function: mul],
    '/': [Function: div],
    '%': [Function: mod],
    '^': [Function: pow],
    '||': [Function: concat],
    '==': [Function: equal],
    '!=': [Function: notEqual],
    '>': [Function: greaterThan],
    '<': [Function: lessThan],
    '>=': [Function: greaterThanEqual],
    '<=': [Function: lessThanEqual],
    and: [Function: andOperator],
    or: [Function: orOperator],
    in: [Function: inOperator],
    '=': [Function: setVar],
    '[': [Function: arrayIndex]
  },
  ternaryOps: { '?': [Function: condition] },
  functions: {
    random: [Function: random],
    fac: [Function: factorial],
    min: [Function: min],
    max: [Function: max],
    hypot: [Function: hypot],
    pyt: [Function: hypot],
    pow: [Function: pow],
    atan2: [Function: atan2],
    if: [Function: condition],
    gamma: [Function: gamma],
    roundTo: [Function: roundTo],
    map: [Function: arrayMap],
    fold: [Function: arrayFold],
    filter: [Function: arrayFilter],
    indexOf: [Function: stringOrArrayIndexOf],
    join: [Function: arrayJoin]
  }
}
> expr2.evaluate({ x: 3 });
25

The Node,js CLI uses util.inspect instead, that can be customised by defining util.inspect.custom. For example:

$ node
Welcome to Node.js v14.13.0.
Type ".help" for more information.

> var Parser = require('expr-eval').Parser;
undefined

> require('expr-eval').Expression.prototype[Symbol.for('nodejs.util.inspect.custom')] = function inspect(_depth, _opts) { return this.toString(); };
[Function: inspect]

> expr = Parser.parse("2 * x + 1");
((2 * x) + 1)

I can submit a PR, if you're interested in having this functionality added to Expression.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions