From 80d6c7d0dfafab05696996d62372b6bedc59a695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Gonz=C3=A1lez?= Date: Mon, 22 Sep 2025 13:35:18 +0200 Subject: [PATCH] feat: use Math namespace for pow function in formulas --- lib/defaults/formulas.d4rt | 8 ++--- lib/formula_evaluator.dart | 72 +++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/lib/defaults/formulas.d4rt b/lib/defaults/formulas.d4rt index 5f0880c..c6e6001 100644 --- a/lib/defaults/formulas.d4rt +++ b/lib/defaults/formulas.d4rt @@ -17,7 +17,7 @@ Where: {"name": "g", "unit": "meters per second"} // Gravitational acceleration ], "output": {"name": "h", "unit": "meter"}, // Height in meters - "d4rtCode": "h = 0.5 * g * pow(t, 2);", + "d4rtCode": "h = 0.5 * g * Math.pow(t, 2);", "tags": ["physics", "kinematics"] }, @@ -41,7 +41,7 @@ Where: {"name": "r", "unit": "meter"} // Distance between masses ], "output": {"name": "F", "unit": "newton"}, // Force in newtons - "d4rtCode": "F = (6.67430e-11 * m1 * m2) / pow(r, 2);", + "d4rtCode": "F = (6.67430e-11 * m1 * m2) / Math.pow(r, 2);", "tags": ["physics", "astronomy", "gravity"] }, @@ -63,7 +63,7 @@ Where: {"name": "v", "unit": "meters per second"} // Velocity ], "output": {"name": "KE", "unit": "joule"}, // Energy in joules - "d4rtCode": "KE = 0.5 * m * pow(v, 2);", + "d4rtCode": "KE = 0.5 * m * Math.pow(v, 2);", "tags": ["physics", "energy", "mechanics"] }, @@ -82,7 +82,7 @@ Where: {"name": "θ", "unit": "degree"} // Launch angle ], "output": {"name": "R", "unit": "meter"}, // Horizontal distance - "d4rtCode": "R = (pow(v, 2) * sin(2 * radians(θ))) / 9.80665;", + "d4rtCode": "R = (Math.pow(v, 2) * sin(2 * radians(θ))) / 9.80665;", "tags": ["physics", "kinematics", "projectile"] }, diff --git a/lib/formula_evaluator.dart b/lib/formula_evaluator.dart index eac4cc6..9b5b0a4 100644 --- a/lib/formula_evaluator.dart +++ b/lib/formula_evaluator.dart @@ -1,7 +1,13 @@ +import 'dart:math' as Math; import 'package:d4rt/d4rt.dart'; import 'formula_models.dart'; + + + + + /// Exception thrown when formula evaluation fails class FormulaEvaluationException implements Exception { final String message; @@ -14,34 +20,39 @@ class FormulaEvaluationException implements Exception { '${cause != null ? ' (caused by: $cause)' : ''}'; } -/// Evaluates formulas using the d4rt interpreter +class MyMath{ + static Number log(Number x) => Math.log(x); + static Number pow(Number b, Number e) => Math.pow(b,e) as Number; +} + class FormulaEvaluator { final D4rt _interpreter; - /// Creates a new formula evaluator with an optional d4rt interpreter instance. - /// If no interpreter is provided, a new one will be created. - FormulaEvaluator([D4rt? interpreter]) : _interpreter = interpreter ?? D4rt(); + FormulaEvaluator([D4rt? interpreter]) : _interpreter = interpreter ?? D4rt(){ + prepareInterpreter(_interpreter); + } - /// Evaluates a formula with the given input values. - /// - /// The [formula] must have exactly one output variable (validated during construction). - /// The [inputValues] map must contain values for all input variables defined - /// in the formula. - /// - /// The formula's d4rt_code should define a main function that uses the input - /// variable names directly. The evaluator will inject variable declarations - /// before the formula code. For example: - /// ``` - /// main() { - /// return m * a; // Returns Force = mass * acceleration - /// } - /// ``` - /// - /// Returns the computed value of the single output variable. - /// - /// Throws [FormulaEvaluationException] if: - /// - Required input variables are missing - /// - The d4rt code execution fails + Number getNumberValueOf(String s){ + return double.parse(s); + } + + void prepareInterpreter(D4rt interpreter){ + final myMathDefinition = BridgedClass( + nativeType: MyMath, + name: 'Math', + staticMethods: { + 'pow': (visitor, positionalArgs, namedArgs) { + final Number base = getNumberValueOf( positionalArgs[0].toString() ); + final Number exp = getNumberValueOf( positionalArgs[1].toString() ); + return MyMath.pow(base,exp); + }, + } + ); + + interpreter.registerBridgedClass(myMathDefinition, 'package:myapp/my_math.dart'); + } + + dynamic evaluate(Formula formula, Map inputValues) { _validateInputValues(formula, inputValues); @@ -61,7 +72,6 @@ class FormulaEvaluator { } } - /// Validates that all required input variables are provided void _validateInputValues(Formula formula, Map inputValues) { final missingVars = []; @@ -79,47 +89,37 @@ class FormulaEvaluator { } } - /// Gets the name of the single output variable from the formula String getOutputVariableName(Formula formula) { return formula.output.name; } - /// Gets the magnitude of the single output variable from the formula String getOutputVariableMagnitude(Formula formula) { - // Formula construction already ensures exactly one output variable return formula.output.unit; } - /// Gets the ordered list of input variable names (alphabetically sorted) List getInputVariableOrder(Formula formula) { return formula.inputVarNames()..sort(); } - /// Builds the complete d4rt source code by injecting variable declarations - /// before the formula's d4rt code String _buildCompleteSource(Formula formula, Map inputValues) { final buffer = StringBuffer(); + buffer.writeln("import 'package:myapp/my_math.dart';"); buffer.writeln("main(){"); - // Add variable declarations for all input variables for (final entry in inputValues.entries) { final varName = entry.key; final value = entry.value; - // Handle different value types appropriately for d4rt if (value is String) { - // Escape quotes in string values final escapedValue = value.replaceAll('"', '\\"'); buffer.writeln('var $varName = "$escapedValue";'); } else { - // For numbers and other types, use direct representation buffer.writeln('var $varName = $value;'); } } buffer.writeln("late var ${getOutputVariableName(formula)};"); - // Add the formula's d4rt code buffer.writeln(formula.d4rtCode); buffer.writeln("return ${getOutputVariableName(formula)};"); buffer.writeln("}");