[TW5] (Tobias Beer) calc macro does not handle zero properly

121 views
Skip to first unread message

Evan Balster

unread,
Sep 17, 2015, 1:27:08 AM9/17/15
to TiddlyWiki
I'm running into a most perplexing bug with Tobias' calc macro.

"<<calc 1 -1>>"

This code, run in Tobias Beer's own wiki (version 5.1.7), will yield a result of "0".

Run in an empty TiddlyWiki based on version 5.1.9 (but with calc installed), in the same browser, it returns an empty string.  Expressions evaluating to positive or negative numbers return normal results in both wikis.

Notably, I needed to add "plugin-type" (in place of the older module-type) in order to integrate the macro -- but I don't understand why this would affect the output.  I'm looking over the JavaScript code and I'm just completely baffled by this behavior.  What's going on?
calc-macro-bug.html.zip

Evan Balster

unread,
Sep 17, 2015, 1:49:10 AM9/17/15
to TiddlyWiki
I managed to fix it, although probably not in the best way...

The issue seems to arise from zero making it to the return statement as a number.  I can surmise earlier versions of TiddlyWiki had a check for this case and a string conversion...  But this does not occur here.

Here is the revised code:  (The only change is to the final return line)

/*\
title: $:/.tb/macros/calc.js
type: application/javascript
module-type: macro

Computes a (Field) value +,-,*,/ a provided value.

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

/*
Information about this macro
*/

exports.name = "calc";

exports.params = [
{name: "value"},
{name: "operation"},
{name: "until"},
{name: "beyond"},
{name: "decimals"},
{name: "tiddler"}
];

/*
Run the macro
*/
exports.run = function(value, operation, until, beyond, decimals, tiddler) {
if(!value) {
return;
}
if("" == operation){
operation = "0";
}

var 
curr,dec,op,r,result,val,
ops = ["+","-","*","/"];

curr = parseFloat(
0 > value.indexOf('!!') ?
value :
this.wiki.getTextReference(value, "NaN", tiddler || this.getVariable("currentTiddler"))
);

until = parseFloat(until);
decimals = parseInt(decimals);

op = operation.charAt(0);
val = parseFloat(0 > ops.indexOf(op) ? operation : operation.substr(1));
op = 0 > ops.indexOf(op) ? "+" : op;

if(isNaN(curr)) {
result = "NaN";
} else {
switch (op){
case "-": result = curr - val; break;
case "*": result = curr * val; break;
case "/": result = curr / val; break;
case "+":
default: result = curr + val;
}
if(!isNaN(until)) {
if (!(
"+" == op || "*" == op ?
result <= until :
result >= until
)) {
if("true" == beyond) {
result = true;
} else {
result = until;
}
}
if(beyond && result !== true) {
result = false;
}
}
}

if(!isNaN(result)){
r = result.toString();
dec = r.indexOf('.');
if(dec > -1){
dec = r.substr(dec).length;
if(
!isNaN(decimals) && dec > decimals ||
isNaN(decimals) && dec > 2
){
result = result.toFixed(isNaN(decimals) ? 2 : decimals);
}
}
}
return result.toString();
};

})();

Tobias Beer

unread,
Sep 17, 2015, 2:29:48 AM9/17/15
to tiddl...@googlegroups.com
Hi Evan,

Thanks for both reporting and fixing. I have updated calc...

calc @ tb5

The issue seems to arise from zero making it to the return statement as a number. 
I can surmise earlier versions of TiddlyWiki had a check for this case and a string conversion. 
But this does not occur here.

I fail to understand due to what string conversion is of need.
Can anyone explain? ...perhaps also what has changed in the core and maybe why?

Best wishes,

— tb

Evan Balster

unread,
Sep 17, 2015, 2:32:56 AM9/17/15
to TiddlyWiki
There's some path of execution where the value of "result" is still a number on the last line -- if I had to guess, due to the fixed-point conversion.  Older versions of TiddlyWiki, including 5.1.7, must forcefully convert non-string types returned from macros, while newer versions do not.  And fortunately my .toString() has no effect on a value which is already a string.

I invite you to re-write your code more elegantly than I have with my limited understanding.


On Thursday, 17 September 2015 01:29:48 UTC-5, Tobias Beer wrote:
Hi Evan,

Thanks for both reporting and fixing. I have updated calc...

The issue seems to arise from zero making it to the return statement as a number. 
I can surmise earlier versions of TiddlyWiki had a check for this case and a string conversion. 
But this does not occur here.

I fail to understand due to what string conversion is of need.
Can anyone explain? ...perhaps also what has changed in the core and why?

Best wishes,

— tb

Tobias Beer

unread,
Sep 17, 2015, 3:06:57 AM9/17/15
to TiddlyWiki
Hi Evan,
 
I invite you to re-write your code more elegantly than I have with my limited understanding.

Tbh, as you can see from my question above,
my understanding, more often than not, likewise is rather limited. ^_^

For now, I am happy to see you have helped fix this
and I will remember something about returning strings in js macros
...for reasons yet to be demystified.

With what purpose would you wish (some part) of this little macro to be rewritten?

Best wishes,

— tb

Evan Balster

unread,
Sep 17, 2015, 11:55:47 AM9/17/15
to TiddlyWiki
The toString() in the return statement could probably be eliminated if the path resulting in a number at that point could be corrected.  I suspect the problem occurs when the "toFixed" conversion is made, because no further conversion turns that into a string.
Reply all
Reply to author
Forward
0 new messages