feat(functions): add logical functions
This commit is contained in:
1 parent
6442c8f575
commit
a6d92df088
1 file changed
+110
@@ -0,0 +1,110 @@
|
||||
import '../evaluator.dart';
|
||||
import '../values.dart';
|
||||
import 'helpers.dart';
|
||||
|
||||
void registerLogical(Map<String, CellFunction> registry) {
|
||||
registry['IF'] = (args, ctx) {
|
||||
arity(args, 2, 3);
|
||||
if (ctx.asBoolean(ctx.eval(args[0]))) return ctx.eval(args[1]);
|
||||
if (args.length == 3) return ctx.eval(args[2]);
|
||||
return const BooleanValue(false);
|
||||
};
|
||||
|
||||
registry['IFS'] = (args, ctx) {
|
||||
arity(args, 2);
|
||||
if (args.length.isOdd) throw const EvalException(ErrorValue(ErrorKind.value));
|
||||
for (var i = 0; i < args.length; i += 2) {
|
||||
if (ctx.asBoolean(ctx.eval(args[i]))) return ctx.eval(args[i + 1]);
|
||||
}
|
||||
throw const EvalException(ErrorValue(ErrorKind.na));
|
||||
};
|
||||
|
||||
registry['SWITCH'] = (args, ctx) {
|
||||
arity(args, 3);
|
||||
final subject = ctx.eval(args[0]);
|
||||
var i = 1;
|
||||
while (i + 1 < args.length) {
|
||||
if (ctx.compare(subject, ctx.eval(args[i])) == 0) return ctx.eval(args[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
if (i < args.length) return ctx.eval(args[i]);
|
||||
throw const EvalException(ErrorValue(ErrorKind.na));
|
||||
};
|
||||
|
||||
registry['AND'] = (args, ctx) {
|
||||
arity(args, 1);
|
||||
var seen = false;
|
||||
var accumulated = true;
|
||||
for (final value in ctx.flatten(args)) {
|
||||
if (value is BlankValue) continue;
|
||||
accumulated = accumulated && ctx.asBoolean(value);
|
||||
seen = true;
|
||||
}
|
||||
if (!seen) throw const EvalException(ErrorValue(ErrorKind.value));
|
||||
return BooleanValue(accumulated);
|
||||
};
|
||||
|
||||
registry['OR'] = (args, ctx) {
|
||||
arity(args, 1);
|
||||
var seen = false;
|
||||
var accumulated = false;
|
||||
for (final value in ctx.flatten(args)) {
|
||||
if (value is BlankValue) continue;
|
||||
accumulated = accumulated || ctx.asBoolean(value);
|
||||
seen = true;
|
||||
}
|
||||
if (!seen) throw const EvalException(ErrorValue(ErrorKind.value));
|
||||
return BooleanValue(accumulated);
|
||||
};
|
||||
|
||||
registry['XOR'] = (args, ctx) {
|
||||
arity(args, 1);
|
||||
var trueCount = 0;
|
||||
var seen = false;
|
||||
for (final value in ctx.flatten(args)) {
|
||||
if (value is BlankValue) continue;
|
||||
if (ctx.asBoolean(value)) trueCount++;
|
||||
seen = true;
|
||||
}
|
||||
if (!seen) throw const EvalException(ErrorValue(ErrorKind.value));
|
||||
return BooleanValue(trueCount.isOdd);
|
||||
};
|
||||
|
||||
registry['NOT'] = (args, ctx) {
|
||||
arity(args, 1, 1);
|
||||
return BooleanValue(!ctx.asBoolean(ctx.eval(args[0])));
|
||||
};
|
||||
|
||||
registry['TRUE'] = (args, ctx) {
|
||||
arity(args, 0, 0);
|
||||
return const BooleanValue(true);
|
||||
};
|
||||
|
||||
registry['FALSE'] = (args, ctx) {
|
||||
arity(args, 0, 0);
|
||||
return const BooleanValue(false);
|
||||
};
|
||||
|
||||
registry['IFERROR'] = (args, ctx) {
|
||||
arity(args, 2, 2);
|
||||
try {
|
||||
final value = ctx.eval(args[0]);
|
||||
if (value is ErrorValue) return ctx.eval(args[1]);
|
||||
return value;
|
||||
} on EvalException {
|
||||
return ctx.eval(args[1]);
|
||||
}
|
||||
};
|
||||
|
||||
registry['IFNA'] = (args, ctx) {
|
||||
arity(args, 2, 2);
|
||||
try {
|
||||
final value = ctx.eval(args[0]);
|
||||
if (value is ErrorValue && value.kind == ErrorKind.na) return ctx.eval(args[1]);
|
||||
return value;
|
||||
} on EvalException catch (error) {
|
||||
if (error.kind == ErrorKind.na) return ctx.eval(args[1]);
|
||||
rethrow;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user