A generic conversion system that uses a single transformer rule and a callback to dynamically look up conversion factors stored in variables.

ID: 1355

				
					using uCalcSoftware;

var uc = new uCalc();

static void ConvertUnits(uCalc.Callback cb) {
   var  value = cb.Arg(1);
   var fromUnit = cb.ArgStr(2);
   var toUnit = cb.ArgStr(3);

   // Construct the variable names for direct and inverse factors
   var factorName = fromUnit + "_to_" + toUnit;
   var inverseFactorName = toUnit + "_to_" + fromUnit;

   var uc_instance = cb.uCalc;

   // Try to find the direct conversion factor
   var factorItem = uc_instance.ItemOf(factorName);
   if (factorItem.NotEmpty()) {
      cb.Return(Math.Round(value * factorItem.Value(), 4));
      return;
   }

   // If not found, try to find the inverse factor and use its reciprocal
   var inverseFactorItem = uc_instance.ItemOf(inverseFactorName);
   if (inverseFactorItem.NotEmpty()) {
      cb.Return(value / inverseFactorItem.Value());
      return;
   }

   // If no factor is found, raise an error
   cb.Error.Raise("Conversion factor not found for " + fromUnit + " to " + toUnit);
}

// Define the conversion factors as variables
uc.DefineVariable("in_to_cm = 2.54");
uc.DefineVariable("km_to_miles = 0.621371");

// Define a custom function for temperature, since it's not a simple multiplication
uc.DefineFunction("ConvertTempFToC(val) = (val - 32) * 5.0/9.0");

// Register our generic conversion callback
uc.DefineFunction("Convert(val, fromUnit As String, toUnit As String)", ConvertUnits);

// Create generic rules in the expression transformer
var t = uc.ExpressionTransformer;
t.FromTo("{@Number:val} {@Alpha:from} to {@Alpha:to}", "Convert({val}, '{from}', '{to}')");
// A specific rule for Fahrenheit to Celsius since it's more complex (higher precedence because it's defined last)
t.FromTo("{@Number:val} F to C", "ConvertTempFToC({val})");

Console.WriteLine($"10 in to cm = {uc.Eval("10 in to cm")}");
Console.WriteLine($"100 km to miles = {uc.Eval("100 km to miles")}");

// Test the inverse conversion, which the callback handles automatically
Console.WriteLine($"254 cm to in = {uc.Eval("254 cm to in")}");
Console.WriteLine($"98.6 F to C = {uc.Eval("98.6 F to C")}");
				
			
10 in to cm = 25.4
100 km to miles = 62.1371
254 cm to in = 100
98.6 F to C = 37
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

void ucalc_call ConvertUnits(uCalcBase::Callback cb) {
   auto  value = cb.Arg(1);
   auto fromUnit = cb.ArgStr(2);
   auto toUnit = cb.ArgStr(3);

   // Construct the variable names for direct and inverse factors
   auto factorName = fromUnit + "_to_" + toUnit;
   auto inverseFactorName = toUnit + "_to_" + fromUnit;

   auto uc_instance = cb.uCalc();

   // Try to find the direct conversion factor
   auto factorItem = uc_instance.ItemOf(factorName);
   if (factorItem.NotEmpty()) {
      cb.Return(value * factorItem.Value());
      return;
   }

   // If not found, try to find the inverse factor and use its reciprocal
   auto inverseFactorItem = uc_instance.ItemOf(inverseFactorName);
   if (inverseFactorItem.NotEmpty()) {
      cb.Return(value / inverseFactorItem.Value());
      return;
   }

   // If no factor is found, raise an error
   cb.Error().Raise("Conversion factor not found for " + fromUnit + " to " + toUnit);
}
int main() {
   uCalc uc;
   // Define the conversion factors as variables
   uc.DefineVariable("in_to_cm = 2.54");
   uc.DefineVariable("km_to_miles = 0.621371");

   // Define a custom function for temperature, since it's not a simple multiplication
   uc.DefineFunction("ConvertTempFToC(val) = (val - 32) * 5.0/9.0");

   // Register our generic conversion callback
   uc.DefineFunction("Convert(val, fromUnit As String, toUnit As String)", ConvertUnits);

   // Create generic rules in the expression transformer
   auto t = uc.ExpressionTransformer();
   t.FromTo("{@Number:val} {@Alpha:from} to {@Alpha:to}", "Convert({val}, '{from}', '{to}')");
   // A specific rule for Fahrenheit to Celsius since it's more complex (higher precedence because it's defined last)
   t.FromTo("{@Number:val} F to C", "ConvertTempFToC({val})");

   cout << "10 in to cm = " << uc.Eval("10 in to cm") << endl;
   cout << "100 km to miles = " << uc.Eval("100 km to miles") << endl;

   // Test the inverse conversion, which the callback handles automatically
   cout << "254 cm to in = " << uc.Eval("254 cm to in") << endl;
   cout << "98.6 F to C = " << uc.Eval("98.6 F to C") << endl;
}
				
			
10 in to cm = 25.4
100 km to miles = 62.1371
254 cm to in = 100
98.6 F to C = 37
				
					Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub ConvertUnits(ByVal cb As uCalc.Callback)
      Dim  value = cb.Arg(1)
      Dim fromUnit = cb.ArgStr(2)
      Dim toUnit = cb.ArgStr(3)
      
      '// Construct the variable names for direct and inverse factors
      Dim factorName = fromUnit + "_to_" + toUnit
      Dim inverseFactorName = toUnit + "_to_" + fromUnit
      
      Dim uc_instance = cb.uCalc
      
      '// Try to find the direct conversion factor
      Dim factorItem = uc_instance.ItemOf(factorName)
      If factorItem.NotEmpty() Then
         cb.Return(Math.Round(value * factorItem.Value(), 4))
         return
      End If
      
      '// If not found, try to find the inverse factor and use its reciprocal
      Dim inverseFactorItem = uc_instance.ItemOf(inverseFactorName)
      If inverseFactorItem.NotEmpty() Then
         cb.Return(value / inverseFactorItem.Value())
         return
      End If
      
      '// If no factor is found, raise an error
      cb.Error.Raise("Conversion factor not found for " + fromUnit + " to " + toUnit)
   End Sub
   Public Sub Main()
      Dim uc As New uCalc()
      '// Define the conversion factors as variables
      uc.DefineVariable("in_to_cm = 2.54")
      uc.DefineVariable("km_to_miles = 0.621371")
      
      '// Define a custom function for temperature, since it's not a simple multiplication
      uc.DefineFunction("ConvertTempFToC(val) = (val - 32) * 5.0/9.0")
      
      '// Register our generic conversion callback
      uc.DefineFunction("Convert(val, fromUnit As String, toUnit As String)", AddressOf ConvertUnits)
      
      '// Create generic rules in the expression transformer
      Dim t = uc.ExpressionTransformer
      t.FromTo("{@Number:val} {@Alpha:from} to {@Alpha:to}", "Convert({val}, '{from}', '{to}')")
      '// A specific rule for Fahrenheit to Celsius since it's more complex (higher precedence because it's defined last)
      t.FromTo("{@Number:val} F to C", "ConvertTempFToC({val})")
      
      Console.WriteLine($"10 in to cm = {uc.Eval("10 in to cm")}")
      Console.WriteLine($"100 km to miles = {uc.Eval("100 km to miles")}")
      
      '// Test the inverse conversion, which the callback handles automatically
      Console.WriteLine($"254 cm to in = {uc.Eval("254 cm to in")}")
      Console.WriteLine($"98.6 F to C = {uc.Eval("98.6 F to C")}")
   End Sub
End Module
				
			
10 in to cm = 25.4
100 km to miles = 62.1371
254 cm to in = 100
98.6 F to C = 37