App-SocialCalc-Multiplayer
view release on metacpan or search on metacpan
socialcalc/formula1.js view on Meta::CPAN
else { // text maybe mixed with numbers or blank
tostype = value1.type.charAt(0);
tostype2 = value2.type.charAt(0);
if (tostype == "n") {
value1.value = format_number_for_display(value1.value, "n", "");
}
else if (tostype == "b") {
value1.value = "";
}
if (tostype2 == "n") {
value2.value = format_number_for_display(value2.value, "n", "");
}
else if (tostype2 == "b") {
value2.value = "";
}
cond = 0;
value1.value = value1.value.toLowerCase(); // ignore case
value2.value = value2.value.toLowerCase();
if (ttext == "<") { cond = value1.value < value2.value ? 1 : 0; }
else if (ttext == "L") { cond = value1.value <= value2.value ? 1 : 0; }
else if (ttext == "=") { cond = value1.value == value2.value ? 1 : 0; }
else if (ttext == "G") { cond = value1.value >= value2.value ? 1 : 0; }
else if (ttext == ">") { cond = value1.value > value2.value ? 1 : 0; }
else if (ttext == "N") { cond = value1.value != value2.value ? 1 : 0; }
PushOperand("nl", cond);
}
}
// Normal infix arithmethic operators: +, -. *, /, ^
else { // what's left are the normal infix arithmetic operators
if (operand.length <= 1) { // Need at least two things on the stack...
errortext = scc.s_parseerrmissingoperand; // remember error
break;
}
value2 = operand_as_number(sheet, operand);
value1 = operand_as_number(sheet, operand);
if (ttext == '+') {
resulttype = lookup_result_type(value1.type, value2.type, typelookup.plus);
PushOperand(resulttype, value1.value + value2.value);
}
else if (ttext == '-') {
resulttype = lookup_result_type(value1.type, value2.type, typelookup.plus);
PushOperand(resulttype, value1.value - value2.value);
}
else if (ttext == '*') {
resulttype = lookup_result_type(value1.type, value2.type, typelookup.plus);
PushOperand(resulttype, value1.value * value2.value);
}
else if (ttext == '/') {
if (value2.value != 0) {
PushOperand("n", value1.value / value2.value); // gives plain numeric result type
}
else {
PushOperand("e#DIV/0!", 0);
}
}
else if (ttext == '^') {
value1.value = Math.pow(value1.value, value2.value);
value1.type = "n"; // gives plain numeric result type
if (isNaN(value1.value)) {
value1.value = 0;
value1.type = "e#NUM!";
}
PushOperand(value1.type, value1.value);
}
}
}
// function or name
else if (ttype == tokentype.name) {
errortext = scf.CalculateFunction(ttext, operand, sheet);
if (errortext) break;
}
else {
errortext = scc.s_InternalError+"Unknown token "+ttype+" ("+ttext+"). ";
break;
}
}
// look at final value and handle special cases
value = operand[0] ? operand[0].value : "";
tostype = operand[0] ? operand[0].type : "";
if (tostype == "name") { // name - expand it
value1 = SocialCalc.Formula.LookupName(sheet, value);
value = value1.value;
tostype = value1.type;
errortext = errortext || value1.error;
}
if (tostype == "coord") { // the value is a coord reference, get its value and type
value1 = operand_value_and_type(sheet, operand);
value = value1.value;
tostype = value1.type;
if (tostype == "b") {
tostype = "n";
value = 0;
}
}
if (operand.length > 1 && !errortext) { // something left - error
errortext += scc.s_parseerrerrorinformula;
}
// set return type
valuetype = tostype;
if (tostype.charAt(0) == "e") { // error value
errortext = errortext || tostype.substring(1) || scc.s_calcerrerrorvalueinformula;
}
else if (tostype == "range") {
vmatch = value.match(/^(.*)\|(.*)\|/);
smatch = vmatch[1].indexOf("!");
if (smatch>=0) { // swap sheetname
vmatch[1] = vmatch[1].substring(smatch+1) + "!" + vmatch[1].substring(0, smatch).toUpperCase();
}
else {
vmatch[1] = vmatch[1].toUpperCase();
}
value = vmatch[1] + ":" + vmatch[2].toUpperCase();
if (!allowrangereturn) {
errortext = scc.s_formularangeresult+" "+value;
}
}
if (errortext && valuetype.charAt(0) != "e") {
value = errortext;
valuetype = "e";
}
// look for overflow
if (valuetype.charAt(0) == "n" && (isNaN(value) || !isFinite(value))) {
value = 0;
valuetype = "e#NUM!";
errortext = isNaN(value) ? scc.s_calcerrnumericnan: scc.s_calcerrnumericoverflow;
}
return ({value: value, type: valuetype, error: errortext});
}
/*
#
# resulttype = SocialCalc.Formula.LookupResultType(type1, type2, typelookup);
#
# typelookup has values of the following form:
#
# typelookup{"typespec1"} = "|typespec2A:resultA|typespec2B:resultB|..."
#
# First type1 is looked up. If no match, then the first letter (major type) of type1 plus "*" is looked up
# resulttype is type1 if result is "1", type2 if result is "2", otherwise the value of result.
#
*/
SocialCalc.Formula.LookupResultType = function(type1, type2, typelookup) {
var pos1, pos2, result;
var table1 = typelookup[type1];
if (!table1) {
table1 = typelookup[type1.charAt(0)+'*'];
if (!table1) {
return "e#VALUE! (internal error, missing LookupResultType "+type1.charAt(0)+"*)"; // missing from table -- please add it
}
}
pos1 = table1.indexOf("|"+type2+":");
if (pos1 >= 0) {
pos2 = table1.indexOf("|", pos1+1);
if (pos2<0) return "e#VALUE! (internal error, incorrect LookupResultType "+table1+")";
result = table1.substring(pos1+type2.length+2, pos2);
if (result == "1") return type1;
if (result == "2") return type2;
return result;
}
pos1 = table1.indexOf("|"+type2.charAt(0)+"*:");
if (pos1 >= 0) {
pos2 = table1.indexOf("|", pos1+1);
if (pos2<0) return "e#VALUE! (internal error, incorrect LookupResultType "+table1+")";
result = table1.substring(pos1+4, pos2);
if (result == "1") return type1;
if (result == "2") return type2;
return result;
}
return "e#VALUE!";
}
/*
#
# operandinfo = SocialCalc.Formula.TopOfStackValueAndType(sheet, operand)
#
# Returns top of stack value and type and then pops the stack.
# The result is {value: value, type: type, error: "only if bad error"}
socialcalc/formula1.js view on Meta::CPAN
operand.push(result);
return null;
}
// Add to function list
SocialCalc.Formula.FunctionList["ABS"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["ACOS"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["ASIN"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["ATAN"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["COS"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["DEGREES"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["EVEN"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["EXP"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["FACT"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["INT"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["LN"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["LOG10"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["ODD"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["RADIANS"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["SIN"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["SQRT"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
SocialCalc.Formula.FunctionList["TAN"] = [SocialCalc.Formula.Math1Functions, 1, "v", "", "math"];
/*
#
# ATAN2(x, y)
# MOD(a, b)
# POWER(a, b)
# TRUNC(value, precision)
#
*/
SocialCalc.Formula.Math2Functions = function(fname, operand, foperand, sheet) {
var xval, yval, value, quotient, decimalscale, i;
var result = {};
var scf = SocialCalc.Formula;
xval = scf.OperandAsNumber(sheet, foperand);
yval = scf.OperandAsNumber(sheet, foperand);
value = 0;
result.type = scf.LookupResultType(xval.type, yval.type, scf.TypeLookupTable.twoargnumeric);
if (result.type == "n") {
switch (fname) {
case "ATAN2":
if (xval.value == 0 && yval.value == 0) {
result.type = "e#DIV/0!";
}
else {
result.value = Math.atan2(yval.value, xval.value);
}
break;
case "POWER":
result.value = Math.pow(xval.value, yval.value);
if (isNaN(result.value)) {
result.value = 0;
result.type = "e#NUM!";
}
break;
case "MOD": // en.wikipedia.org/wiki/Modulo_operation, etc.
if (yval.value == 0) {
result.type = "e#DIV/0!";
}
else {
quotient = xval.value/yval.value;
quotient = Math.floor(quotient);
result.value = xval.value - (quotient * yval.value);
}
break;
case "TRUNC":
decimalscale = 1; // cut down to required number of decimal digits
if (yval.value >= 0) {
yval.value = Math.floor(yval.value);
for (i=0; i<yval.value; i++) {
decimalscale *= 10;
}
result.value = Math.floor(Math.abs(xval.value) * decimalscale) / decimalscale;
}
else if (yval.value < 0) {
yval.value = Math.floor(-yval.value);
for (i=0; i<yval.value; i++) {
decimalscale *= 10;
}
result.value = Math.floor(Math.abs(xval.value) / decimalscale) * decimalscale;
}
if (xval.value < 0) {
result.value = -result.value;
}
}
}
operand.push(result);
return null;
}
// Add to function list
SocialCalc.Formula.FunctionList["ATAN2"] = [SocialCalc.Formula.Math2Functions, 2, "xy", "", "math"];
SocialCalc.Formula.FunctionList["MOD"] = [SocialCalc.Formula.Math2Functions, 2, "", "", "math"];
SocialCalc.Formula.FunctionList["POWER"] = [SocialCalc.Formula.Math2Functions, 2, "", "", "math"];
SocialCalc.Formula.FunctionList["TRUNC"] = [SocialCalc.Formula.Math2Functions, 2, "valpre", "", "math"];
/*
#
# LOG(value,[base])
#
*/
SocialCalc.Formula.LogFunction = function(fname, operand, foperand, sheet) {
var value, value2;
var result = {};
( run in 1.339 second using v1.01-cache-2.11-cpan-5a3173703d6 )