linny-r 2.0.12 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -319,7 +319,7 @@ function compareTailFirst(a, b, tail) {
319
319
  }
320
320
 
321
321
  function endsWithDigits(str) {
322
- // Returns trailing digts of `str` (empty string will evaluate as FALSE)
322
+ // Return trailing digts of `str` (empty string will evaluate as FALSE).
323
323
  let i = str.length - 1,
324
324
  c = str[i],
325
325
  d = '';
@@ -332,8 +332,8 @@ function endsWithDigits(str) {
332
332
  }
333
333
 
334
334
  function indexOfMatchingBracket(str, offset) {
335
- // Returns index of closing bracket, ignoring matched [...] inside
336
- // NOTE: starts at offset + 1, assuming that character at offset = '['
335
+ // Return index of closing bracket, ignoring matched [...] inside.
336
+ // NOTE: Start at offset + 1, assuming that character at offset = '['.
337
337
  let ob = 0, c;
338
338
  for(let i = offset + 1; i < str.length; i++) {
339
339
  c = str.charAt(i);
@@ -347,12 +347,12 @@ function indexOfMatchingBracket(str, offset) {
347
347
  }
348
348
  }
349
349
  }
350
- // No matching bracket => return -1
350
+ // No matching bracket => return -1.
351
351
  return -1;
352
352
  }
353
353
 
354
354
  function monoSpaced(vbl) {
355
- // Removes all non-essential spaces from variable reference `vbl`.
355
+ // Remove all non-essential spaces from variable reference `vbl`.
356
356
  // First reduce all whitespace to a single space.
357
357
  return vbl.replace(/\s+/g, ' ')
358
358
  // Then remove spaces after the opening bracket.
@@ -834,13 +834,11 @@ function customizeXML(str) {
834
834
  // and then load it again for the customization to be performed.
835
835
  if(str.indexOf('!!CUSTOMIZE</name><author>') >= 0) {
836
836
  // Modify `str` -- by default, do nothing, but typical modifications
837
- // will replace RexEx patterns by other strings.
838
-
839
- /*
837
+ // will replace RexEx patterns by other strings.
838
+
840
839
  const
841
- re = /xyz/gi,
842
- r = 'abc';
843
- */
840
+ re = /pattern/g,
841
+ r = 'replacement';
844
842
 
845
843
  // Trace the changes to the console.
846
844
  console.log('Customizing:', re, r);
@@ -868,8 +866,8 @@ function cleanXML(node) {
868
866
  }
869
867
 
870
868
  function parseXML(xml) {
871
- // Parses string `xml` into an XML document, and returns its root node
872
- // (or null if errors)
869
+ // Parse string `xml` into an XML document, and returns its root node
870
+ // (or null if errors).
873
871
  xml = XML_PARSER.parseFromString(customizeXML(xml), 'application/xml');
874
872
  const
875
873
  de = xml.documentElement,
@@ -880,8 +878,8 @@ function parseXML(xml) {
880
878
  }
881
879
 
882
880
  function childNodeByTag(node, tag) {
883
- // Returns the XML child node of `node` having node name `tag`, or NULL if
884
- // no such child node exists
881
+ // Return the XML child node of `node` having node name `tag`, or NULL if
882
+ // no such child node exists.
885
883
  let cn = null;
886
884
  for (let i = 0; i < node.childNodes.length; i++) {
887
885
  if(node.childNodes[i].tagName === tag) {
@@ -893,19 +891,19 @@ function childNodeByTag(node, tag) {
893
891
  }
894
892
 
895
893
  function nodeContentByTag(node, tag) {
896
- // Returns the text content of the child node of `node` having name `tag`,
897
- // or the empty string if no such node exists
894
+ // Return the text content of the child node of `node` having name `tag`,
895
+ // or the empty string if no such node exists.
898
896
  return nodeContent(childNodeByTag(node, tag));
899
897
  }
900
898
 
901
899
  function nodeContent(node) {
902
- // Returns the text content of XML element `node`
900
+ // Return the text content of XML element `node`.
903
901
  if(node) {
904
- // For text nodes, return their value
902
+ // For text nodes, return their value.
905
903
  if(node.nodeType === 3) return node.nodeValue;
906
- // For empty nodes, return empty string
904
+ // For empty nodes, return empty string.
907
905
  if(node.childNodes.length === 0) return '';
908
- // If first child is text, return its value
906
+ // If first child is text, return its value.
909
907
  const fcn = node.childNodes.item(0);
910
908
  if(fcn && fcn.nodeType === 3) return fcn.nodeValue;
911
909
  console.log('UNEXPECTED XML', fcn.nodeType, node);
@@ -914,8 +912,8 @@ function nodeContent(node) {
914
912
  }
915
913
 
916
914
  function nodeParameterValue(node, param) {
917
- // Returns the value of parameter `param` as string if `node` has
918
- // this parameter, otherwise the empty string
915
+ // Return the value of parameter `param` as string if `node` has
916
+ // this parameter, otherwise the empty string.
919
917
  const a = node.getAttribute(param);
920
918
  return a || '';
921
919
  }
@@ -309,7 +309,7 @@ class Expression {
309
309
  if(DEBUGGING) {
310
310
  // Show the "time step stack" for --START and --STOP
311
311
  if(action.startsWith('--') || action.startsWith('"')) {
312
- action = `[${step.join(', ')}] ${action}`;
312
+ action = `[${this.step.join(', ')}] ${action}`;
313
313
  }
314
314
  console.log(action);
315
315
  }
@@ -2903,7 +2903,11 @@ class VirtualMachine {
2903
2903
  vlist = [],
2904
2904
  xlist = [];
2905
2905
  for(const x of this.call_stack) {
2906
- vlist.push(x.object.displayName + '|' + x.attribute);
2906
+ // For equations, only show the attribute.
2907
+ const ons = (x.object === MODEL.equations_dataset ?
2908
+ (x.attribute.startsWith(':') ? x.method_object_prefix : '') :
2909
+ x.object.displayName + '|');
2910
+ vlist.push(ons + x.attribute);
2907
2911
  // Trim spaces around all object-attribute separators in the
2908
2912
  // expression as entered by the modeler.
2909
2913
  xlist.push(x.text.replace(/\s*\|\s*/g, '|'));
@@ -6933,7 +6937,8 @@ function VMI_push_method(x, args) {
6933
6937
  // and possibly also the entity to be used as its object.
6934
6938
  // NOTE: Methods can only be called "as is" (without prefix) in a
6935
6939
  // method expression. The object of such "as is" method calls is
6936
- // the object of the calling method expression `x`.
6940
+ // the object of the calling method expression `x`, or for chart
6941
+ // variables the method object selected for the chart.
6937
6942
  const
6938
6943
  method = args[0].meq,
6939
6944
  mex = method.expression,
@@ -7675,7 +7680,13 @@ function VMI_add(x) {
7675
7680
  const d = x.pop();
7676
7681
  if(d !== false) {
7677
7682
  if(DEBUGGING) console.log('ADD (' + d.join(', ') + ')');
7678
- x.retop(d[0] + d[1]);
7683
+ if(Math.abs(d[0]) === VM.PLUS_INFINITY) {
7684
+ x.retop(d[0]);
7685
+ } else if(Math.abs(d[1]) === VM.PLUS_INFINITY) {
7686
+ x.retop(d[1]);
7687
+ } else {
7688
+ x.retop(d[0] + d[1]);
7689
+ }
7679
7690
  }
7680
7691
  }
7681
7692
 
@@ -7685,17 +7696,27 @@ function VMI_sub(x) {
7685
7696
  const d = x.pop();
7686
7697
  if(d !== false) {
7687
7698
  if(DEBUGGING) console.log('SUB (' + d.join(', ') + ')');
7688
- x.retop(d[0] - d[1]);
7699
+ if(d[0] === VM.PLUS_INFINITY || d[1] === VM.MINUS_INFINITY) {
7700
+ x.retop(VM.PLUS_INFINITY);
7701
+ } else if(d[0] === VM.MINUS_INFINITY || d[1] === VM.PLUS_INFINITY) {
7702
+ x.retop(VM.MINUS_INFINITY);
7703
+ } else {
7704
+ x.retop(d[0] + d[1]);
7705
+ }
7689
7706
  }
7690
7707
  }
7691
7708
 
7692
7709
  function VMI_mul(x) {
7693
7710
  // Pop the top number on the stack, and multiply it with the new
7694
- // top number
7711
+ // top number.
7695
7712
  const d = x.pop();
7696
7713
  if(d !== false) {
7697
7714
  if(DEBUGGING) console.log('MUL (' + d.join(', ') + ')');
7698
- x.retop(d[0] * d[1]);
7715
+ if(Math.abs(d[0]) === VM.PLUS_INFINITY || Math.abs(d[1]) === VM.PLUS_INFINITY) {
7716
+ x.retop(VM.PLUS_INFINITY * Math.sign(d[0] * d[1]));
7717
+ } else {
7718
+ x.retop(d[0] * d[1]);
7719
+ }
7699
7720
  }
7700
7721
  }
7701
7722
 
@@ -7707,7 +7728,19 @@ function VMI_div(x) {
7707
7728
  if(DEBUGGING) console.log('DIV (' + d.join(', ') + ')');
7708
7729
  if(Math.abs(d[1]) <= VM.NEAR_ZERO) {
7709
7730
  x.retop(VM.DIV_ZERO);
7731
+ } else if(Math.abs(d[0]) === VM.PLUS_INFINITY) {
7732
+ if(Math.abs(d[1]) === VM.PLUS_INFINITY) {
7733
+ // Treat INF / INF as 1.
7734
+ x.retop(Math.sign(d[0]) * Math.sign(d[1]));
7735
+ } else {
7736
+ // Push the + or - infinity value.
7737
+ x.retop(d[0]);
7738
+ }
7739
+ } else if(Math.abs(d[1]) === VM.PLUS_INFINITY) {
7740
+ // Treat N / Infinity as 0 for any non-infinite value of N.
7741
+ x.retop(0);
7710
7742
  } else {
7743
+ // Standard division.
7711
7744
  x.retop(d[0] / d[1]);
7712
7745
  }
7713
7746
  }
@@ -7722,7 +7755,19 @@ function VMI_div_zero(x) {
7722
7755
  if(DEBUGGING) console.log('DIV-ZERO (' + d.join(', ') + ')');
7723
7756
  if(Math.abs(d[1]) <= VM.NEAR_ZERO) {
7724
7757
  x.retop(d[0]);
7758
+ } else if(Math.abs(d[0]) === VM.PLUS_INFINITY) {
7759
+ if(Math.abs(d[1]) === VM.PLUS_INFINITY) {
7760
+ // Treat INF / INF as 1.
7761
+ x.retop(Math.sign(d[0]) * Math.sign(d[1]));
7762
+ } else {
7763
+ // Push the + or - infinity value.
7764
+ x.retop(d[0]);
7765
+ }
7766
+ } else if(Math.abs(d[1]) === VM.PLUS_INFINITY) {
7767
+ // Treat N / Infinity as 0 for any non-infinite value of N.
7768
+ x.retop(0);
7725
7769
  } else {
7770
+ // Standard division.
7726
7771
  x.retop(d[0] / d[1]);
7727
7772
  }
7728
7773
  }
@@ -7738,6 +7783,9 @@ function VMI_mod(x) {
7738
7783
  if(DEBUGGING) console.log('DIV (' + d.join(', ') + ')');
7739
7784
  if(Math.abs(d[1]) <= VM.NEAR_ZERO) {
7740
7785
  x.retop(VM.DIV_ZERO);
7786
+ } else if(Math.abs(d[0]) === VM.PLUS_INFINITY || Math.abs(d[1]) === VM.PLUS_INFINITY) {
7787
+ // If either operand is infinite, return 0 as remainder.
7788
+ x.retop(0);
7741
7789
  } else {
7742
7790
  x.retop(d[0] % d[1]); // % is the modulo operator in JavaScript.
7743
7791
  }
@@ -7759,7 +7807,16 @@ function VMI_power(x) {
7759
7807
  const d = x.pop();
7760
7808
  if(d !== false) {
7761
7809
  if(DEBUGGING) console.log('POWER (' + d.join(', ') + ')');
7762
- x.retop(Math.pow(d[0], d[1]));
7810
+ const r = Math.pow(d[0], d[1]);
7811
+ if(isNaN(r)) {
7812
+ x.retop(VM.BAD_CALC);
7813
+ } else if(r >= VM.PLUS_INFINITY) {
7814
+ x.retop(VM.PLUS_INFINITY);
7815
+ } else if(r <= VM.MINUS_INFINITY) {
7816
+ x.retop(VM.MINUS_INFINITY);
7817
+ } else {
7818
+ x.retop(r);
7819
+ }
7763
7820
  }
7764
7821
  }
7765
7822
 
@@ -7771,6 +7828,8 @@ function VMI_sqrt(x) {
7771
7828
  if(DEBUGGING) console.log('SQRT ' + d);
7772
7829
  if(d < 0) {
7773
7830
  x.retop(VM.BAD_CALC);
7831
+ } else if (d === VM.PLUS_INFINITY) {
7832
+ x.retop(VM.PLUS_INFINITY);
7774
7833
  } else {
7775
7834
  x.retop(Math.sqrt(d));
7776
7835
  }
@@ -7782,7 +7841,12 @@ function VMI_sin(x) {
7782
7841
  const d = x.top();
7783
7842
  if(d !== false) {
7784
7843
  if(DEBUGGING) console.log('SIN ' + d);
7785
- x.retop(Math.sin(d));
7844
+ const r = Math.sin(d);
7845
+ if(isNaN(r) || Math.abs(d) === VM.PLUS_INFINITY) {
7846
+ x.retop(VM.BAD_CALC);
7847
+ } else {
7848
+ x.retop(r);
7849
+ }
7786
7850
  }
7787
7851
  }
7788
7852
 
@@ -7791,7 +7855,12 @@ function VMI_cos(x) {
7791
7855
  const d = x.top();
7792
7856
  if(d !== false) {
7793
7857
  if(DEBUGGING) console.log('COS ' + d);
7794
- x.retop(Math.cos(d));
7858
+ const r = Math.cos(d);
7859
+ if(isNaN(r) || Math.abs(d) === VM.PLUS_INFINITY) {
7860
+ x.retop(VM.BAD_CALC);
7861
+ } else {
7862
+ x.retop(r);
7863
+ }
7795
7864
  }
7796
7865
  }
7797
7866
 
@@ -7800,7 +7869,12 @@ function VMI_atan(x) {
7800
7869
  const d = x.top();
7801
7870
  if(d !== false) {
7802
7871
  if(DEBUGGING) console.log('ATAN ' + d);
7803
- x.retop(Math.atan(d));
7872
+ const r = Math.atan(d);
7873
+ if(isNaN(r) || Math.abs(d) === VM.PLUS_INFINITY) {
7874
+ x.retop(VM.BAD_CALC);
7875
+ } else {
7876
+ x.retop(r);
7877
+ }
7804
7878
  }
7805
7879
  }
7806
7880
 
@@ -7812,6 +7886,8 @@ function VMI_ln(x) {
7812
7886
  if(DEBUGGING) console.log('LN ' + d);
7813
7887
  if(d < 0) {
7814
7888
  x.retop(VM.BAD_CALC);
7889
+ } else if(d === VM.PLUS_INFINITY) {
7890
+ x.retop(VM.PLUS_INFINITY);
7815
7891
  } else {
7816
7892
  x.retop(Math.log(d));
7817
7893
  }
@@ -7823,7 +7899,13 @@ function VMI_exp(x) {
7823
7899
  const d = x.top();
7824
7900
  if(d !== false) {
7825
7901
  if(DEBUGGING) console.log('EXP ' + d);
7826
- x.retop(Math.exp(d));
7902
+ if(d === VM.PLUS_INFINITY) {
7903
+ x.retop(VM.PLUS_INFINITY);
7904
+ } else if(d === VM.MINUS_INFINITY) {
7905
+ x.retop(0);
7906
+ } else {
7907
+ x.retop(Math.exp(d));
7908
+ }
7827
7909
  }
7828
7910
  }
7829
7911
 
@@ -7833,12 +7915,16 @@ function VMI_log(x) {
7833
7915
  let d = x.pop();
7834
7916
  if(d !== false) {
7835
7917
  if(DEBUGGING) console.log('LOG (' + d.join(', ') + ')');
7836
- try {
7837
- d = Math.log(d[1]) / Math.log(d[0]);
7838
- } catch(err) {
7839
- d = VM.BAD_CALC;
7918
+ if(Math.abs(d[0]) === VM.PLUS_INFINITY || Math.abs(d[1]) === VM.PLUS_INFINITY) {
7919
+ x.retop(VM.BAD_CALC);
7920
+ } else {
7921
+ try {
7922
+ d = Math.log(d[1]) / Math.log(d[0]);
7923
+ } catch(err) {
7924
+ d = VM.BAD_CALC;
7925
+ }
7926
+ x.retop(d);
7840
7927
  }
7841
- x.retop(d);
7842
7928
  }
7843
7929
  }
7844
7930