Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(408)

Unified Diff: samples/total/client/Functions.dart

Issue 10635015: Delete proxy and total samples, which have bit-rotted. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « samples/total/client/Formula.dart ('k') | samples/total/client/GeneralCommand.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: samples/total/client/Functions.dart
===================================================================
--- samples/total/client/Functions.dart (revision 9011)
+++ samples/total/client/Functions.dart (working copy)
@@ -1,977 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Functions implemented:
-//
-// ABS ACOS ACOSH AND ASIN ASINH ATAN ATAN2 ATANH COLUMNS COMBIN CONCATENATE COS COSH COUNTA DATE
-// DAY DEGREES EVEN EXP FACT FACTDOUBLE FALSE GCD HLOOKUP HOUR IF INT LARGE LCM LEN LN LOG
-// LOG10 MATCH MAX MID MIN MINUTE MOD MONTH MULTINOMIAL NOT NOW ODD OFFSET OR PI POWER
-// PRODUCT QUOTIENT RADIANS RAND RANDBETWEEN RIGHT ROUND SECOND SERIESSUM SIGN
-// SIN SINH SMALL SQRT SQRTPI SUM SUMSQ TAN TANH TIME TODAY TRUE TRUNC VALUE VLOOKUP YEAR
-
-// Some functions to be implemented:
-// Math: CEILING, FLOOR, MROUND, ROUNDDOWN, ROUNDUP, SUBTOTAL, SUMIF
-// Date: DATEVALUE, DAYS360, EDATE, EMONTH, EOMONTH, NETWORKDAYS, TIMEVALUE,
-// WEEKDAY, WEEKNUM, WORKDAY, YEARFRAC
-// Lists: SUMPRODUCT, SUMX2MY2, SUMX2PY2, SUMXMY2
-// Matrix: MDETERM, MINVERSE, MMULT
-// String: ROMAN
-
-typedef void NumericFunction(CellLocation location, List<Value> stack, int top, int nargs);
-typedef double AggregateFunction(double accum, double value);
-
-// A built-in function, encapsulating the function name, number of arguments, output datatype,
-class SpreadsheetFunction {
- NumericFunction _func;
- String _name;
- int _nargs;
-
- // void func(List<Value> stack, int top, int nargs)
- // args are in stack[top], stack[top + 1], ..., stack[top + nargs - 1]
- // result should be placed in stack[top]
- NumericFunction get func() => _func;
-
- String get name() => _name;
-
- int get nargs() => _nargs;
-
- SpreadsheetFunction(this._name, this._nargs, this._func) { }
-}
-
-class Functions {
- static final double DEGREES_TO_RADIANS = Math.PI / 180.0;
- static final double RADIANS_TO_DEGREES = 180.0 / Math.PI;
-
- // FIXME: replace getter below with static const field.
- static double get LOG_10_FACTOR() { return 1.0 / Math.log(10.0); }
-
- static double _choose(double n, double k) {
- double r = 1.0;
- for (int d = 1; d <= k; d++) {
- // Avoid intermediate overflow
- double g = _gcd(r, d.toDouble());
- var div;
- if (g > 1.0) {
- // FIXME: replace with /= when supported by VM.
- r = r / g;
- div = d / g;
- } else {
- div = d;
- }
- r *= n--;
- // FIXME: replace with /= when supported by VM.
- r = r / div;
- }
- return r;
- }
-
- static int _countCellsInRange(CellRange range, int countCell(Cell cell)) {
- int count = 0;
- range.forEach(_(CellLocation cl) {
- RowCol rowCol = cl.rowCol;
- // Values outside the spreadsheet are ignored, empty cells are treated as 0.0
- if (rowCol.row >= 1 && rowCol.col >= 1) {
- Cell cell = range.spreadsheet.getCell(rowCol);
- if (cell != null) {
- count += countCell(cell);
- }
- }
- });
-
- return count;
- }
-
- static double _exp(double x) => Math.pow(Math.E, x);
-
- // Assume arguments are positive
- // FIXME: GCD should not work on doubles.
- static double _gcd(double a, double b) {
- if (b == 0) {
- return a;
- }
- return _gcd(b, a % b);
- }
-
- static List<double> _getValues(CellRange range) {
- int count = range.rows * range.columns;
- List<double> values = new List<double>();
- range.forEach(_(CellLocation cl) {
- RowCol rowCol = cl.rowCol;
- // Values outside the spreadsheet are ignored, empty cells are treated as 0.0
- if (rowCol.row >= 1 && rowCol.col >= 1) {
- Cell cell = range.spreadsheet.getCell(rowCol);
- if (cell != null) {
- double value = cell.getDoubleValue();
- values.add(value);
- } else {
- values.add(0.0);
- }
- }
- });
-
- return values;
- }
-
- static double _lcm(double a, double b) => (a * b) / _gcd(a, b);
-
- // Function name ==> double func(double accum, double newValue)
- Map<String, AggregateFunction> _aggregateFunctions;
- // Initial value for aggregation (e.g., 0 for sums, 1 for products)
- Map<String, double> _aggregateInitialValues;
- // Functions that should be evaluated for every recalculation
- Set<String> _alwaysRecalculateFunctions;
- // Functions by name
- Map<String, SpreadsheetFunction> _functions;
-
- Functions() {
- _functions = new Map<String, SpreadsheetFunction>();
- _alwaysRecalculateFunctions = new Set<String>();
-
- // Nullary (zero-arg) functions
- _newFunc("FALSE", 0, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- stack[top] = new BooleanValue(false);
- });
- _newFunc("NOW", 0, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- stack[top] = new DateTimeValue(DateUtils.now());
- });
- _alwaysRecalculateFunctions.add("NOW");
- _newFunc("PI", 0, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- stack[top] = new DoubleValue(Math.PI);
- });
- _newFunc("RAND", 0, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- stack[top] = new DoubleValue(Math.random());
- });
- _alwaysRecalculateFunctions.add("RAND");
- _newFunc("TODAY", 0, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- stack[top] = new DateValue(DateUtils.today());
- });
- _alwaysRecalculateFunctions.add("TODAY");
- _newFunc("TRUE", 0, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- stack[top] = new BooleanValue(true);
- });
-
- // Unary functions
- _newFunc("ABS", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- double val;
- if (x < 0.0) {
- val = -x;
- } else {
- val = x;
- }
- stack[top] = new DoubleValue(val);
- });
- _newFunc("ACOS", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(Math.acos(x));
- });
- _newFunc("ACOSH", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(2.0 * Math.log(Math.sqrt((x + 1.0) / 2.0)
- + Math.sqrt((x - 1.0) / 2.0)));
- });
- _newFunc("ASIN", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(Math.asin(x));
- });
- _newFunc("ASINH", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(Math.log(x + Math.sqrt(1.0 + x * x)));
- });
- _newFunc("ATAN", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(Math.atan(x));
- });
- _newFunc("ATANH", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue((Math.log(1.0 + x) - Math.log(1.0 - x)) / 2.0);
- });
- _newFunc("COLUMNS", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
-
- RangeToken range = stack[top].asRangeToken();
- int cols = range.endRef.getCol(location) - range.startRef.getCol(location) + 1;
- stack[top] = new DoubleValue(cols.toDouble());
- });
- _newFunc("COS", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(Math.cos(x));
- });
- _newFunc("COSH", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue((_exp(x) + _exp(-x)) * 0.5);
- });
- _newFunc("DAY", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- Date dateTime = DateUtils.getDateTime(x);
- stack[top] = new DoubleValue(dateTime.day.toDouble());
- });
- _newFunc("DEGREES", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(x * RADIANS_TO_DEGREES);
- });
- _newFunc("EVEN", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- bool neg = false;
- if (x < 0) {
- x = -x;
- neg = true;
- }
- double val = x.ceil();
- if (val % 2 == 1) {
- val++;
- }
- stack[top] = new DoubleValue(neg ? -val : val);
- });
- _newFunc("EXP", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(Math.pow(Math.E, x));
- });
- _newFunc("FACT", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- if (x < 0.0) {
- throw new NumberException();
- }
- double ix = x.floor();
- double fact = 1.0;
- for (int i = 2; i <= ix; i++) {
- fact *= i;
- }
- stack[top] = new DoubleValue(fact);
- });
- _newFunc("FACTDOUBLE", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- if (x < 0.0) {
- throw new NumberException();
- }
- int ix = x.floor().toInt();
- int start = (ix % 2) + 2;
- double fact = 1.0;
- for (int i = start; i <= ix; i += 2) {
- fact *= i;
- }
- stack[top] = new DoubleValue(fact);
- });
- _newFunc("HOUR", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double time = stack[top].asDouble(location);
- time -= time.floor();
- stack[top] = new DoubleValue((time * 24.0).floor());
- });
- _newFunc("INT", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(x.floor());
- });
- _newFunc("LEN", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- String s = stack[top].asString(location);
- stack[top] = new DoubleValue(s.length.toDouble());
- });
- _newFunc("LN", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- if (x <= 0.0) {
- throw new NumberException();
- }
- stack[top] = new DoubleValue(Math.log(x));
- });
- _newFunc("LOG10", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- if (x <= 0.0) {
- throw new NumberException();
- }
- stack[top] = new DoubleValue(Math.log(x) * LOG_10_FACTOR);
- });
- _newFunc("MINUTE", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double time = stack[top].asDouble(location);
- time *= 24.0;
- time -= time.floor();
- stack[top] = new DoubleValue((time * 60.0).floor());
- });
- _newFunc("MONTH", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- Date dateTime = DateUtils.getDateTime(x);
- stack[top] = new DoubleValue(dateTime.month.toDouble());
- });
- _newFunc("NOT", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new BooleanValue(x == 0.0);
- });
- _newFunc("ODD", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- bool neg = false;
- if (x < 0) {
- x = -x;
- neg = true;
- }
- double val = x.ceil();
- if (val % 2 == 0) {
- val++;
- }
- stack[top] = new DoubleValue(neg ? -val : val);
- });
- _newFunc("RADIANS", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(x * DEGREES_TO_RADIANS);
- });
- _newFunc("ROWS", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- RangeToken range = stack[top].asRangeToken();
- int rows = range.endRef.getRow(location) - range.startRef.getRow(location) + 1;
- stack[top] = new DoubleValue(rows.toDouble());
- });
- _newFunc("SECOND", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double time = stack[top].asDouble(location);
- time *= 24.0 * 60.0;
- time -= time.floor();
- stack[top] = new DoubleValue((time * 60.0).floor());
- });
- _newFunc("SIGN", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- double val;
- if (x < 0.0) {
- val = -1.0;
- } else if (x > 0.0) {
- val = 1.0;
- } else {
- val = 0.0;
- }
- stack[top] = new DoubleValue(val);
- });
- _newFunc("SIN", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(Math.sin(x));
- });
- _newFunc("SINH", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue((_exp(x) - _exp(-x)) * 0.5);
- });
- _newFunc("SQRT", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- if (x < 0.0) {
- throw new NumberException();
- }
- stack[top] = new DoubleValue(Math.sqrt(x));
- });
- _newFunc("SQRTPI", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- if (x < 0.0) {
- throw new NumberException();
- }
- stack[top] = new DoubleValue(Math.sqrt(x * Math.PI));
- });
- _newFunc("TAN", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- stack[top] = new DoubleValue(Math.tan(x));
- });
- _newFunc("TANH", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- x = _exp(2.0 * x);
- stack[top] = new DoubleValue((x - 1.0) / (x + 1.0));
- });
- _newFunc("VALUE", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- Value v = stack[top];
- if (v.isString(location)) {
- String s = stack[top].asString(location);
- try {
- double x = Math.parseDouble(s);
- stack[top] = new DoubleValue(x);
- } catch (BadNumberFormatException e) {
- throw new ValueException();
- }
- } else {
- stack[top] = new DoubleValue(v.asDouble(location));
- }
- });
- _newFunc("YEAR", 1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- Date dateTime = DateUtils.getDateTime(x);
- stack[top] = new DoubleValue(dateTime.year.toDouble());
- });
-
- // Binary functions
- _newFunc("ATAN2", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- double y = stack[top + 1].asDouble(location);
- stack[top] = new DoubleValue(Math.atan2(x, y));
- });
- _newFunc("COMBIN", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double n = stack[top].asDouble(location).floor();
- double k = stack[top + 1].asDouble(location).floor();
- if (n < 0 || k < 0 || n < k) {
- throw new NumberException();
- }
- stack[top] = new DoubleValue(_choose(n, k));
- });
- _newFunc("LARGE", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- RangeToken rt = stack[top].asRangeToken();
- CellRange range = rt.getCellRange(location);
- int count = range.rows * range.columns;
-
- List<double> values = _getValues(range);
- int k = stack[top + 1].asDouble(location).floor().toInt();
- if (k < 1 || k > values.length) {
- throw new NumberException();
- }
-
- stack[top] = new DoubleValue(_find(values, values.length - k));
- });
- _newFunc("LOG", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double value = stack[top].asDouble(location);
- double base = stack[top + 1].asDouble(location);
- if (value <= 0.0 || base <= 0.0) {
- throw new NumberException();
- }
- stack[top] = new DoubleValue(Math.log(value) / Math.log(base));
- });
- _newFunc("MOD", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double number = stack[top].asDouble(location);
- double divisor = stack[top + 1].asDouble(location);
- if (divisor == 0.0) {
- throw new DivByZeroException();
- }
- stack[top] = new DoubleValue(number - divisor * (number / divisor).floor());
- });
- _newFunc("POWER", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double base = stack[top].asDouble(location);
- double exponent = stack[top + 1].asDouble(location);
- stack[top] = new DoubleValue(Math.pow(base, exponent));
- });
- _newFunc("QUOTIENT", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double numerator = stack[top].asDouble(location);
- double denominator = stack[top + 1].asDouble(location);
- if (denominator < 0.0) {
- numerator = -numerator;
- denominator = -denominator;
- }
- double val;
- if (numerator < 0.0) {
- val = -(((-numerator) / denominator).floor());
- } else {
- val = (numerator / denominator).floor();
- }
- stack[top] = new DoubleValue(val);
- });
- _newFunc("RANDBETWEEN", 2,
- void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double b = stack[top].asDouble(location).floor();
- double t = stack[top + 1].asDouble(location).floor();
- if (b > t) {
- throw new NumberException();
- }
- stack[top] = new DoubleValue(b + (Math.random() * (t - b + 1)).floor());
- });
- _alwaysRecalculateFunctions.add("RANDBETWEEN");
- _newFunc("REPT", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- String text = stack[top].asString(location);
- double number = stack[top + 1].asDouble(location);
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < number; i++) {
- sb.add(text);
- }
- stack[top] = new StringValue(sb.toString());
- });
- _newFunc("ROUND", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double value = stack[top].asDouble(location);
- double precision = stack[top + 1].asDouble(location);
- if (precision < 0.0) {
- throw new NumberException();
- }
- precision = precision.floor();
- double prec = Math.pow(10.0, precision);
- stack[top] = new DoubleValue((value * prec).round() / prec);
- });
- _newFunc("SMALL", 2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- RangeToken rt = stack[top].asRangeToken();
- CellRange range = rt.getCellRange(location);
- int count = range.rows * range.columns;
-
- List<double> values = _getValues(range);
- int k = stack[top + 1].asDouble(location).floor().toInt();
- if (k <= 0 || k > values.length) {
- throw new NumberException();
- }
-
- stack[top] = new DoubleValue(_find(values, k - 1));
- });
- _newFunc("LEFT", -1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- String s = stack[top].asString(location);
- int chars = 1;
- if (nargs == 2) {
- chars = stack[top + 1].asDouble(location).floor().toInt();
- }
- stack[top] = new StringValue(s.substring(0, Math.min(chars, s.length)));
- });
- _newFunc("RIGHT", -1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- String s = stack[top].asString(location);
- int chars = 1;
- if (nargs == 2) {
- chars = stack[top + 1].asDouble(location).floor().toInt();
- }
- stack[top] = new StringValue(s.substring(Math.max(s.length - chars, 0), s.length));
- });
- _newFunc("TRUNC", -1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double number = stack[top].asDouble(location);
- bool neg = false;
- if (number < 0.0) {
- neg = true;
- number = -number;
- }
- double val;
- if (nargs == 1) {
- val = number.floor();
- } else if (nargs == 2) {
- double prec = Math.pow(10.0, stack[top + 1].asDouble(location));
- val = (number * prec).floor() / prec;
- } else {
- throw new NumArgsException();
- }
- stack[top] = new DoubleValue(neg ? -val : val);
- });
- _newFunc("DATE", 3, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- int year = stack[top].asDouble(location).floor().toInt();
- int month = stack[top + 1].asDouble(location).floor().toInt();
- int day = stack[top + 2].asDouble(location).floor().toInt();
- stack[top] = new DateValue(DateUtils.getDate(year, month, day));
- });
- _newFunc("MID", 3, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- String s = stack[top].asString(location);
- int start = stack[top + 1].asDouble(location).floor().toInt();
- int chars = stack[top + 2].asDouble(location).floor().toInt();
-
- if (start >= s.length) {
- stack[top] = new StringValue("");
- return;
- }
- if (start < 1) {
- throw new NumberException();
- }
- if (chars < 0) {
- throw new NumberException();
- }
- stack[top] = new StringValue(s.substring(start - 1, Math.min(start + chars - 1, s.length)));
- });
- _newFunc("TIME", 3, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- int hour = stack[top].asDouble(location).floor().toInt();
- int minute = stack[top + 1].asDouble(location).floor().toInt();
- int second = stack[top + 2].asDouble(location).floor().toInt();
- stack[top] = new TimeValue(DateUtils.getTime(hour, minute, second));
- });
- _newFunc("OFFSET", 5, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- RangeToken rt = stack[top].asRangeToken();
- int rows = stack[top + 1].asDouble(location).floor().toInt();
- int columns = stack[top + 2].asDouble(location).floor().toInt();
- int height = stack[top + 3].asDouble(location).floor().toInt();
- int width = stack[top + 4].asDouble(location).floor().toInt();
-
- CellRefToken startRef = new CellRefToken.offset(rt.startRef, columns, rows);
- CellRefToken endRef = new CellRefToken.offset(rt.startRef,
- columns + width - 1, rows + height - 1);
-
- RangeTokenValue result = new RangeTokenValue(new RangeToken(startRef, endRef));
- stack[top] = result;
- });
- // Always recalculate the dependents of an OFFSET since the OFFSET may produce an
- // otherwise unknown dependency
- _alwaysRecalculateFunctions.add("OFFSET");
-
- // N-ary functions
- _newFunc("AND", -1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- for (int i = 0; i < nargs; i++) {
- if (stack[top + i].asDouble(location) == 0.0) {
- stack[top] = new BooleanValue(false);
- return;
- }
- }
- stack[top] = new BooleanValue(true);
- });
- _newFunc("CONCATENATE", -2,
- void _(CellLocation location, List<Value> stack, int top, int nargs) {
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < nargs; i++) {
- sb.add(stack[top + i].asString(location));
- }
- stack[top] = new StringValue(sb.toString());
- });
- _newFunc("COUNT", -1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- int count = 0;
- for (int i = 0; i < nargs; i++) {
- Value value = stack[top + i];
- if (value.datatype == Value.TYPE_CELLREF || value.datatype == Value.TYPE_RANGE) {
- count += _countCellsInRange(value.asRangeToken().getCellRange(location),
- int __(Cell cell) { return cell.isNumeric() ? 1 : 0; });
- } else if (value.datatype == Value.TYPE_DOUBLE) {
- count++;
- }
- }
- stack[top] = new DoubleValue(count.toDouble());
- });
- _newFunc("COUNTA", -1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- int count = 0;
- for (int i = 0; i < nargs; i++) {
- Value value = stack[top + i];
- if (value.datatype == Value.TYPE_CELLREF || value.datatype == Value.TYPE_RANGE) {
- count += _countCellsInRange(value.asRangeToken().getCellRange(location),
- int __(Cell cell) { return cell.isEmpty() ? 0 : 1; });
- } else {
- count++;
- }
- }
- stack[top] = new DoubleValue(count.toDouble());
- });
- _newFunc("GCD", -2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- for (int i = 0; i < nargs; i++) {
- if (stack[top + i].asDouble(location) < 0.0) {
- throw new NumberException();
- }
- }
- double gcd = _gcd(stack[top].asDouble(location), stack[top + 1].asDouble(location));
- for (int i = 2; i < nargs; i++) {
- gcd = _gcd(gcd, stack[top + i].asDouble(location));
- }
- stack[top] = new DoubleValue(gcd);
- });
- // Inherit datatype from stack[top + 1]
- _newFunc("IF", -2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double expr = stack[top].asDouble(location);
- if (expr == 1.0) {
- stack[top] = stack[top + 1];
- } else {
- if (nargs > 2) {
- stack[top] = stack[top + 2];
- } else {
- stack[top] = new BooleanValue(false); // IF(1>0, onearg) returns FALSE
- }
- }
- });
- _newFunc("LCM", -2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- for (int i = 0; i < nargs; i++) {
- if (stack[top + i].asDouble(location) < 0.0) {
- throw new NumberException();
- }
- }
- double lcm = _lcm(stack[top].asDouble(location), stack[top + 1].asDouble(location));
- for (int i = 2; i < nargs; i++) {
- lcm = _lcm(lcm, stack[top + i].asDouble(location));
- }
- stack[top] = new DoubleValue(lcm);
- });
- _newFunc("MAX", -1,
- void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double max = stack[top].asDouble(location);
- for (int i = 1; i < nargs; i++) {
- double x = stack[top + 1].asDouble(location);
- if (x > max) {
- max = x;
- }
- }
- stack[top] = new DoubleValue(max);
- });
- _newFunc("MIN", -1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double min = stack[top].asDouble(location);
- for (int i = 1; i < nargs; i++) {
- double x = stack[top + 1].asDouble(location);
- if (x < min) {
- min = x;
- }
- }
- stack[top] = new DoubleValue(min);
- });
- _newFunc("MULTINOMIAL", -1,
- void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double sumN = stack[top].asDouble(location) + stack[top + 1].asDouble(location);
- double sumK = stack[top].asDouble(location);
- double product = 1.0;
- for (int i = 1; i < nargs; i++) {
- product *= _choose(sumN, sumK);
- sumN += stack[top + i + 1].asDouble(location);
- sumK += stack[top + i].asDouble(location);
- }
- stack[top] = new DoubleValue(product);
- });
- _newFunc("OR", -1, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- for (int i = 0; i < nargs; i++) {
- if (stack[top + i].asDouble(location) == 1.0) {
- stack[top] = new BooleanValue(true);
- return;
- }
- }
- stack[top] = new BooleanValue(false);
- });
- _newFunc("SERIESSUM", -3, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double x = stack[top].asDouble(location);
- double n = stack[top + 1].asDouble(location);
- double m = stack[top + 2].asDouble(location);
- double xpow = Math.pow(x, n);
- double xstep = Math.pow(x, m);
- double sum = 0.0;
- for (int i = 3; i < nargs; i++) {
- sum += xpow * stack[top + i].asDouble(location);
- xpow *= xstep;
- }
- stack[top] = new DoubleValue(sum);
- });
-
- _newFunc("MATCH", -2, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- double value = stack[top].asDouble(location);
- RangeToken rt = stack[top + 1].asRangeToken();
- CellRange range = rt.getCellRange(location);
-
- int matchType = 1;
- if (nargs > 2) {
- matchType = stack[top + 2].asDouble(location).floor().toInt();
- }
-
- // The range must be 1xN or Nx1
- if (range.rows > 1 && range.columns > 1) {
- throw new NumberException();
- }
-
- int index = 1;
- double bestValue = matchType == 1 ? -1.0e100 : 1.0e100;
- int bestIndex = -1;
- range.forEach(__(CellLocation loc) {
- Cell cell = loc.getCell();
- if (cell != null) {
- double d = cell.getDoubleValue();
- if (d == value) {
- bestIndex = index;
- return;
- } else if (matchType == 1 && d < value && d > bestValue) {
- bestValue = d;
- bestIndex = index;
- } else if (matchType == -1 && d > value && d < bestValue) {
- bestValue = d;
- bestIndex = index;
- }
- }
- index++;
- });
- if (bestIndex == -1) {
- throw new NumberException();
- }
-
- stack[top] = new DoubleValue(bestIndex.toDouble());
- });
-
- _newFunc("HLOOKUP", -3, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- _lookup(location, stack, top, nargs, true);
- });
- _newFunc("VLOOKUP", -3, void _(CellLocation location, List<Value> stack, int top, int nargs) {
- _lookup(location, stack, top, nargs, false);
- });
-
- // Functions that operate over ranges
- _aggregateFunctions = new Map<String, AggregateFunction>();
- _aggregateInitialValues = new Map<String, double>();
- _aggregateFunctions["SUM"] = double _(double accum, double value) => accum + value;
- _aggregateInitialValues["SUM"] = 0.0;
- _aggregateFunctions["SUMSQ"] = double _(double accum, double value) => accum + value * value;
- _aggregateInitialValues["SUMSQ"] = 0.0;
- _aggregateFunctions["PRODUCT"] = double _(double accum, double value) => accum * value;
- _aggregateInitialValues["PRODUCT"] = 1.0;
- }
-
- bool alwaysRecalculate(String functionName) => _alwaysRecalculateFunctions.contains(functionName);
-
- // TODO: implement a visitor pattern in order to reduce redundant code in datatype() and
- // evaluate()
-
- // Evaluate a function at a given position within a spreadsheet,
- Value evaluate(CellLocation location, List<Token> tokens) {
- List<Value> stack = new List<Value>();
- int top = 0;
-
- tokens.forEach((Token t) {
- if (t is NumberToken) {
- NumberToken nt = t;
- _growValues(stack, top);
- stack[top++] = new DoubleValue(nt.value);
- } else if (t is StringToken) {
- StringToken st = t;
- _growValues(stack, top);
- stack[top++] = new StringValue(st.value);
- } else if (t is CellRefToken) {
- CellRefToken crt = t;
- CellLocation refLocation = crt.getCellLocation(location);
- if (!refLocation.isValidCell()) {
- throw new RefException();
- }
- _growValues(stack, top);
- stack[top++] = new CellRefTokenValue(crt);
- } else if (t is RangeToken) {
- RangeToken rt = t;
- _growValues(stack, top);
- stack[top++] = new RangeTokenValue(rt);
- } else if (t is OperatorToken) {
- OperatorToken ot = t;
- Value right = stack[--top];
- Value left = stack[--top];
- left = left.lookup(location);
- right = right.lookup(location);
- Value result = ot.operate(left, right);
- stack[top++] = result;
- } else if (t is FunctionNameToken) {
- FunctionNameToken fnt = t;
- String name = fnt.name;
- double nargs = stack[--top].asDouble(location);
-
- AggregateFunction aggregate = _aggregateFunctions[name];
- if (aggregate != null) {
- if (nargs != 1) {
- throw new NumArgsException();
- }
- double initialValue = _aggregateInitialValues[name];
- RangeToken range = stack[--top].asRangeToken();
- double value = _aggregate(range, location, initialValue, aggregate);
- stack[top++] = new DoubleValue(value);
- } else {
- SpreadsheetFunction f = _functions[name];
- if (f == null) {
- throw new FunctionException();
- }
- int argsNeeded = f.nargs; // -x means at least x varargs
- if (argsNeeded >= 0 && argsNeeded != nargs) {
- throw new NumArgsException();
- } else if (argsNeeded < 0 && nargs < -argsNeeded) {
- throw new NumArgsException();
- }
- top -= nargs.toInt();
- Function func = f.func;
- func(location, stack, top++, nargs.toInt());
- }
- } else if (t is InvalidCellRefToken) {
- throw new RefException();
- }
- });
-
- Value result = stack[0].lookup(location);
- return result;
- }
-
- // accum = initialValue; for each cell C in range: accum = f(accum, value of C)
- double _aggregate(RangeToken range, CellLocation location, double initialValue,
- AggregateFunction f) {
- CellRefToken startRef = range.startRef;
- CellRefToken endRef = range.endRef;
-
- int startRow = startRef.getRow(location);
- int endRow = endRef.getRow(location);
- int startCol = startRef.getCol(location);
- int endCol = endRef.getCol(location);
-
- int minRow = startRow < endRow ? startRow : endRow;
- int maxRow = startRow > endRow ? startRow : endRow;
- int minCol = startCol < endCol ? startCol : endCol;
- int maxCol = startCol > endCol ? startCol : endCol;
- if (minRow < 1 || minCol < 1) {
- throw new RefException();
- }
-
- double accum = initialValue;
- for (int row = minRow; row <= maxRow; row++) {
- for (int col = minCol; col <= maxCol; col++) {
- accum = f(accum, range.spreadsheet.getValue(new RowCol(row, col)).asDouble(null));
- }
- }
-
- return accum;
- }
-
- // Returns the kth smallest value in the input list
- // Based on C. A. R. Hoare, CACM 14 (1971) pp. 39-45
- double _find(List<double> values, int k) {
- int m = 0;
- int n = values.length - 1;
- while (m < n) {
- double r = values[k];
- int i = m;
- int j = n;
- while (i <= j) {
- while (values[i] < r) {
- i++;
- }
- while (r < values[j]) {
- j--;
- }
- if (i <= j) {
- double w = values[i];
- values[i] = values[j];
- values[j] = w;
- i++;
- j--;
- }
- }
- if (k <= j) {
- n = j;
- } else if (i <= k) {
- m = i;
- } else {
- break;
- }
- }
-
- return values[k];
- }
-
- void _growInt(List<int> array, int top) {
- while (array.length < top + 1) {
- array.add(0);
- }
- }
-
- void _growValues(List<Value> list, int top) {
- while (list.length < top + 1) {
- list.add(null);
- }
- }
-
- bool _isDate(int datatype) => datatype == Value.TYPE_DATE || datatype == Value.TYPE_TIME ||
- datatype == Value.TYPE_DATE_TIME;
-
- // TODO: bounds checking
- void _lookup(CellLocation location, List<Value> stack, int top, int nargs, bool horizontal) {
- double value = stack[top].asDouble(location);
- RangeToken rt = stack[top + 1].asRangeToken();
- CellRange range = rt.getCellRange(location);
-
- int index = stack[top + 2].asDouble(location).floor().toInt();
- if (index < 1 || index > (horizontal ? range.rows : range.columns)) {
- throw new NumberException();
- }
- bool exact = false;
- if (nargs > 3) {
- exact = stack[top + 3].asDouble(location) == 0.0;
- }
-
- int min = horizontal ? rt.startRef.getCol(location) : rt.startRef.getRow(location);
- int max = horizontal ? rt.endRef.getCol(location) : rt.endRef.getRow(location);
- int rowCol = horizontal ? rt.startRef.getRow(location) : rt.startRef.getCol(location);
- int outRowCol = rowCol + index - 1;
-
- double bestVal = -1.0e100;
- int bestIndex;
- for (int x = min; x <= max; x++) {
- Cell cell = range.spreadsheet.getCell(horizontal ?
- new RowCol(rowCol, x) : new RowCol(x, rowCol));
- double val = cell == null ? 0.0 : cell.getDoubleValue();
- if (val == value) {
- Cell resultCell = range.spreadsheet.getCell(horizontal ?
- new RowCol(outRowCol, x) : new RowCol(x, outRowCol));
- stack[top] = new DoubleValue(resultCell == null ? 0.0 : resultCell.getDoubleValue());
- return;
- }
- if (!exact && val < value && value > bestVal) {
- bestVal = val;
- bestIndex = x;
- }
- }
- if (exact) {
- throw new NumberException(); // TODO: should display "#N/A"
- } else {
- Cell resultCell = range.spreadsheet.getCell(horizontal ?
- new RowCol(outRowCol, bestIndex) : new RowCol(bestIndex, outRowCol));
- stack[top] = new DoubleValue(resultCell == null ? 0.0 : resultCell.getDoubleValue());
- }
- }
-
- void _newFunc(String name, int nargs, NumericFunction f) {
- _functions[name] = new SpreadsheetFunction(name, nargs, f);
- }
-}
« no previous file with comments | « samples/total/client/Formula.dart ('k') | samples/total/client/GeneralCommand.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698