2025-08-24 09:52:34 +00:00
|
|
|
import 'package:d4rt/d4rt.dart';
|
2025-08-28 10:34:49 +00:00
|
|
|
import 'package:collection/collection.dart';
|
2025-08-21 15:15:00 +00:00
|
|
|
|
2025-09-07 11:59:03 +00:00
|
|
|
abstract class SetUtils {
|
|
|
|
|
static Object safeGet(Map<Object?, Object?> map, String key) {
|
|
|
|
|
if (!map.containsKey(key)) {
|
|
|
|
|
throw ArgumentError("Key not found: $key -- $map");
|
|
|
|
|
}
|
|
|
|
|
return map[key] ?? "Not possible!!!";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static String stringValue(Map<Object?, Object?> map, String key) {
|
|
|
|
|
return safeGet(map, key).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static List<Object?> listValue(Map<Object?, Object?> map, String key) {
|
|
|
|
|
return safeGet(map, key) as List<Object?>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Number numberValue(Map<Object?, Object?> map, String key) {
|
|
|
|
|
return double.parse(stringValue(map, key));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef Number = double;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UnitSpec {
|
|
|
|
|
final String name;
|
|
|
|
|
final String baseUnit;
|
|
|
|
|
final String symbol;
|
|
|
|
|
final Number? factorFromUnitToBase;
|
|
|
|
|
final String? codeFromUnitToBase;
|
|
|
|
|
final String? codeFromBaseToUnit;
|
|
|
|
|
|
|
|
|
|
UnitSpec({
|
|
|
|
|
required this.name,
|
|
|
|
|
required this.baseUnit,
|
|
|
|
|
required this.symbol,
|
|
|
|
|
this.factorFromUnitToBase,
|
|
|
|
|
this.codeFromBaseToUnit,
|
|
|
|
|
this.codeFromUnitToBase,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
factory UnitSpec.fromSet(Map<Object?, Object?> theSet) {
|
|
|
|
|
String name = SetUtils.stringValue(theSet, "name");
|
|
|
|
|
String symbol = SetUtils.stringValue(theSet, "symbol");
|
|
|
|
|
|
|
|
|
|
if( theSet.containsKey("isBase") ){
|
2025-09-07 12:04:42 +00:00
|
|
|
return UnitSpec(name: name, baseUnit: name, symbol: symbol, factorFromUnitToBase: 1);
|
2025-09-07 11:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String baseUnit = SetUtils.stringValue(theSet, "baseUnit");
|
|
|
|
|
|
|
|
|
|
if (theSet.containsKey("factor")) {
|
|
|
|
|
Number factorFromUnitToBase = SetUtils.numberValue(theSet, "factor");
|
|
|
|
|
return UnitSpec(
|
|
|
|
|
name: name,
|
|
|
|
|
baseUnit: baseUnit,
|
|
|
|
|
symbol: symbol,
|
|
|
|
|
factorFromUnitToBase: factorFromUnitToBase,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else if( theSet.containsKey("toBase")) {
|
|
|
|
|
String codeFromBaseToUnit = SetUtils.stringValue(
|
|
|
|
|
theSet,
|
|
|
|
|
"fromBase",
|
|
|
|
|
);
|
|
|
|
|
String codeFromUnitToBase = SetUtils.stringValue(
|
|
|
|
|
theSet,
|
|
|
|
|
"toBase",
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return UnitSpec(name: name,
|
|
|
|
|
baseUnit: baseUnit,
|
|
|
|
|
symbol: symbol,
|
|
|
|
|
codeFromBaseToUnit: codeFromBaseToUnit,
|
|
|
|
|
codeFromUnitToBase: codeFromUnitToBase);
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
throw ArgumentError( "Need factor or toBase/fromBase");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static List<UnitSpec> fromArrayStringLiteral(String arrayStringLiteral) {
|
|
|
|
|
var d4rt = D4rt();
|
|
|
|
|
final buffer = StringBuffer();
|
|
|
|
|
buffer.write("main(){ return $arrayStringLiteral; }");
|
|
|
|
|
final code = buffer.toString();
|
|
|
|
|
|
|
|
|
|
final List<Object?> list = d4rt.execute(source: code);
|
|
|
|
|
|
|
|
|
|
final units = list.map((set) => UnitSpec.fromSet(set as Map));
|
|
|
|
|
|
|
|
|
|
return units.toList(growable: false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-24 09:52:34 +00:00
|
|
|
class VariableSpec {
|
|
|
|
|
final String name;
|
|
|
|
|
final String magnitude;
|
|
|
|
|
static final MAGNITUDELESS = "magnitudeless";
|
2025-08-21 15:15:00 +00:00
|
|
|
|
2025-08-24 09:52:34 +00:00
|
|
|
VariableSpec({required this.name, required this.magnitude});
|
2025-08-21 15:15:00 +00:00
|
|
|
|
|
|
|
|
@override
|
2025-08-24 09:52:34 +00:00
|
|
|
String toString() => 'var($name: $magnitude)';
|
2025-08-21 15:15:00 +00:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
bool operator ==(Object other) =>
|
|
|
|
|
identical(this, other) ||
|
|
|
|
|
other is VariableSpec &&
|
|
|
|
|
runtimeType == other.runtimeType &&
|
2025-08-24 09:52:34 +00:00
|
|
|
magnitude == other.magnitude &&
|
|
|
|
|
name == other.name;
|
2025-08-21 15:15:00 +00:00
|
|
|
|
|
|
|
|
@override
|
2025-08-24 09:52:34 +00:00
|
|
|
int get hashCode => Object.hash(magnitude, name);
|
2025-08-21 15:15:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Formula {
|
|
|
|
|
final String name;
|
2025-08-24 09:52:34 +00:00
|
|
|
final List<VariableSpec> input;
|
|
|
|
|
final VariableSpec output;
|
2025-08-21 15:15:00 +00:00
|
|
|
final String d4rtCode;
|
|
|
|
|
|
2025-08-22 15:47:06 +00:00
|
|
|
Formula({
|
2025-08-21 15:15:00 +00:00
|
|
|
required this.name,
|
|
|
|
|
required this.input,
|
|
|
|
|
required this.output,
|
|
|
|
|
required this.d4rtCode,
|
2025-08-26 14:37:28 +00:00
|
|
|
}) {
|
2025-08-22 15:47:06 +00:00
|
|
|
validate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
validate() {
|
|
|
|
|
if (name.trim().isEmpty) {
|
|
|
|
|
throw ArgumentError('Formula name cannot be empty');
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-21 15:15:00 +00:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
String toString() =>
|
|
|
|
|
'Formula(name: $name, input: $input, output: $output, d4rtCode: $d4rtCode)';
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
bool operator ==(Object other) =>
|
|
|
|
|
identical(this, other) ||
|
|
|
|
|
other is Formula &&
|
|
|
|
|
runtimeType == other.runtimeType &&
|
|
|
|
|
name == other.name &&
|
2025-08-24 09:52:34 +00:00
|
|
|
output == other.output &&
|
|
|
|
|
ListEquality().equals(input, other.input) &&
|
2025-08-21 15:15:00 +00:00
|
|
|
d4rtCode == other.d4rtCode;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
int get hashCode =>
|
2025-08-24 09:52:34 +00:00
|
|
|
Object.hash(name, ListEquality().hash(input), output, d4rtCode);
|
2025-08-21 15:15:00 +00:00
|
|
|
|
2025-08-26 14:37:28 +00:00
|
|
|
List<String> inputVarNames() =>
|
|
|
|
|
input.map((v) => v.name).toList(growable: false);
|
2025-08-24 10:33:21 +00:00
|
|
|
|
2025-09-07 11:59:03 +00:00
|
|
|
factory Formula.fromStringLiteral(String setStringLiteral) {
|
2025-08-26 14:54:35 +00:00
|
|
|
var d4rt = D4rt();
|
|
|
|
|
final buffer = StringBuffer();
|
2025-09-07 11:59:03 +00:00
|
|
|
buffer.write("main(){ return $setStringLiteral; }");
|
2025-08-26 14:54:35 +00:00
|
|
|
final code = buffer.toString();
|
|
|
|
|
|
|
|
|
|
final Map<Object?, Object?> setLiteral = d4rt.execute(source: code);
|
|
|
|
|
|
|
|
|
|
return Formula.fromSet(setLiteral);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-07 11:59:03 +00:00
|
|
|
static List<Formula> fromArrayStringLiteral(String arrayStringLiteral) {
|
2025-08-26 15:17:42 +00:00
|
|
|
var d4rt = D4rt();
|
|
|
|
|
final buffer = StringBuffer();
|
2025-09-07 11:59:03 +00:00
|
|
|
buffer.write("main(){ return $arrayStringLiteral; }");
|
2025-08-26 15:17:42 +00:00
|
|
|
final code = buffer.toString();
|
|
|
|
|
|
|
|
|
|
final List<Object?> list = d4rt.execute(source: code);
|
|
|
|
|
|
2025-09-07 11:59:03 +00:00
|
|
|
final formulas = list.map((set) => Formula.fromSet(set as Map));
|
2025-08-26 15:17:42 +00:00
|
|
|
|
2025-09-05 16:53:06 +00:00
|
|
|
return formulas.toList(growable: false);
|
2025-08-26 15:17:42 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-26 14:37:28 +00:00
|
|
|
factory Formula.fromSet(Map<Object?, Object?> theSet) {
|
|
|
|
|
VariableSpec parseVar(Map<Object?, Object?> varSpec) {
|
2025-09-07 11:59:03 +00:00
|
|
|
String name = SetUtils.stringValue(varSpec, "name");
|
|
|
|
|
String magnitude = SetUtils.stringValue(varSpec, "magnitude");
|
2025-08-26 14:37:28 +00:00
|
|
|
return VariableSpec(name: name, magnitude: magnitude);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-07 11:59:03 +00:00
|
|
|
String name = SetUtils.stringValue(theSet, "name");
|
|
|
|
|
final List<Object?> inputSet = SetUtils.listValue(theSet, "input");
|
|
|
|
|
List<VariableSpec> input = inputSet
|
|
|
|
|
.map((v) => parseVar(v as Map))
|
|
|
|
|
.toList(growable: false);
|
2025-08-26 14:37:28 +00:00
|
|
|
Map<Object?, Object?> outputSet = theSet.get("output");
|
|
|
|
|
VariableSpec output = parseVar(outputSet);
|
2025-09-07 11:59:03 +00:00
|
|
|
String d4rtCode = SetUtils.stringValue(theSet, "d4rtCode");
|
2025-08-26 14:37:28 +00:00
|
|
|
|
2025-09-05 16:53:06 +00:00
|
|
|
return Formula(
|
2025-08-26 14:37:28 +00:00
|
|
|
name: name,
|
|
|
|
|
input: input,
|
|
|
|
|
output: output,
|
|
|
|
|
d4rtCode: d4rtCode,
|
|
|
|
|
);
|
2025-08-24 10:33:21 +00:00
|
|
|
}
|
2025-08-21 15:15:00 +00:00
|
|
|
}
|