diff --git a/src/language/ASTNodeCFunctionExpressionBuilder.cpp b/src/language/ASTNodeCFunctionExpressionBuilder.cpp
index d42420b70640364567109eac8c92782f776158f1..24821a00420590b776b67674414a89630a1b39a1 100644
--- a/src/language/ASTNodeCFunctionExpressionBuilder.cpp
+++ b/src/language/ASTNodeCFunctionExpressionBuilder.cpp
@@ -26,7 +26,9 @@ ASTNodeCFunctionExpressionBuilder::_storeArgumentProcessor(const size_t argument
 
 PUGS_INLINE
 void
-ASTNodeCFunctionExpressionBuilder::_buildArgumentProcessors(ASTNode& node, CFunctionProcessor& c_function_processor)
+ASTNodeCFunctionExpressionBuilder::_buildArgumentProcessors(ASTNode& node,
+                                                            const std::vector<ASTNodeDataType>& argument_type_list,
+                                                            CFunctionProcessor& c_function_processor)
 {
   ASTNode& argument_nodes = *node.children[1];
 
@@ -34,8 +36,7 @@ ASTNodeCFunctionExpressionBuilder::_buildArgumentProcessors(ASTNode& node, CFunc
 
   c_function_processor.setNumberOfArguments(arguments_number);
 
-#warning use the correct number of parameters_domain_node
-  const size_t parameters_number = 1;
+  const size_t parameters_number = argument_type_list.size();
 
   if (arguments_number != parameters_number) {
     std::ostringstream error_message;
@@ -60,22 +61,21 @@ ASTNodeCFunctionExpressionBuilder::ASTNodeCFunctionExpressionBuilder(ASTNode& no
   Assert(found);
   Assert(i_function_symbol->attributes().dataType() == ASTNodeDataType::c_function_t);
 
-#warning use the correct arguments type
-  const ASTNodeDataType c_function_argument_type = ASTNodeDataType::double_t;
+  uint64_t c_function_id = std::get<uint64_t>(i_function_symbol->attributes().value());
 
-  std::unique_ptr c_function_processor = std::make_unique<CFunctionProcessor>();
+  CFunctionEmbedderTable& c_function_embedder_table = node.m_symbol_table->cFunctionEbedderTable();
+  std::shared_ptr c_function_embedder               = c_function_embedder_table[c_function_id];
 
-  this->_buildArgumentProcessors(node, *c_function_processor);
+  std::vector<ASTNodeDataType> c_function_argument_type_list = c_function_embedder->getArgumentDataTypes();
 
-  uint64_t c_function_id = std::get<uint64_t>(i_function_symbol->attributes().value());
+  std::unique_ptr c_function_processor = std::make_unique<CFunctionProcessor>();
 
-  CFunctionEmbedderTable& c_function_embedder_table = node.m_symbol_table->cFunctionEbedderTable();
+  this->_buildArgumentProcessors(node, c_function_argument_type_list, *c_function_processor);
 
   c_function_processor->setFunctionExpressionProcessor(
-    std::make_unique<CFunctionExpressionProcessor<double, double>>(node, c_function_embedder_table[c_function_id],
-                                                                   c_function_processor->argumentValues()));
+    std::make_unique<CFunctionExpressionProcessor>(node, c_function_embedder, c_function_processor->argumentValues()));
 
-  ASTNodeDataType c_function_return_type = ASTNodeDataType::double_t;
+  ASTNodeDataType c_function_return_type = c_function_embedder->getReturnDataType();
 
   node.m_node_processor = std::move(c_function_processor);
 }
diff --git a/src/language/ASTNodeCFunctionExpressionBuilder.hpp b/src/language/ASTNodeCFunctionExpressionBuilder.hpp
index f3b78a8edadf4ea56845120ff59eb72fda2fb1ea..82b37ec7c7665c9df871338dec736a3a23ee143b 100644
--- a/src/language/ASTNodeCFunctionExpressionBuilder.hpp
+++ b/src/language/ASTNodeCFunctionExpressionBuilder.hpp
@@ -17,7 +17,9 @@ class ASTNodeCFunctionExpressionBuilder
                                CFunctionProcessor& c_function_processor);
 
   PUGS_INLINE
-  void _buildArgumentProcessors(ASTNode& node, CFunctionProcessor& c_function_processor);
+  void _buildArgumentProcessors(ASTNode& node,
+                                const std::vector<ASTNodeDataType>& argument_type_list,
+                                CFunctionProcessor& c_function_processor);
 
  public:
   ASTNodeCFunctionExpressionBuilder(ASTNode& node);
diff --git a/src/language/CFunctionEmbedder.hpp b/src/language/CFunctionEmbedder.hpp
index e5208d9016ea97356070f5827b2aa41ee01c8bcf..3ba93bbb4f056b9b6e6b620b63b002a701ae8510 100644
--- a/src/language/CFunctionEmbedder.hpp
+++ b/src/language/CFunctionEmbedder.hpp
@@ -4,6 +4,7 @@
 #include <PugsAssert.hpp>
 #include <PugsMacros.hpp>
 
+#include <ASTNodeDataType.hpp>
 #include <ASTNodeDataVariant.hpp>
 
 #include <cmath>
@@ -12,10 +13,16 @@
 #include <tuple>
 #include <vector>
 
+#include <type_traits>
+
 class ICFunctionEmbedder
 {
  public:
-  virtual void apply(const std::vector<ASTNodeDataVariant>& x, double& f_x) = 0;
+  virtual void apply(const std::vector<ASTNodeDataVariant>& x, ASTNodeDataVariant& f_x) = 0;
+
+  virtual ASTNodeDataType getReturnDataType() const = 0;
+
+  virtual std::vector<ASTNodeDataType> getArgumentDataTypes() const = 0;
 
   virtual ~ICFunctionEmbedder() = default;
 };
@@ -51,9 +58,57 @@ class CFunctionEmbedder : public ICFunctionEmbedder
     (_copy_value<I>(t, v), ...);
   }
 
+  template <typename T>
+  [[deprecated("displace this code along with ASTNodeDataType definition")]] ASTNodeDataType
+  _getASTNodeDataTypeFromPOD() const
+  {
+    if constexpr (std::is_same_v<bool, std::decay<T>>) {
+      return ASTNodeDataType::bool_t;
+    } else if constexpr (std::is_same_v<int64_t, std::decay<T>>) {
+      return ASTNodeDataType::int_t;
+    } else if constexpr (std::is_same_v<uint64_t, std::decay<T>>) {
+      return ASTNodeDataType::unsigned_int_t;
+    } else if constexpr (std::is_same_v<double, std::decay<T>>) {
+      return ASTNodeDataType::double_t;
+    } else {
+      return ASTNodeDataType::undefined_t;
+    }
+  }
+
+  template <size_t I>
+  PUGS_INLINE ASTNodeDataType
+  _getOneArgumentDataType(ArgsTuple& t) const
+  {
+    return _getASTNodeDataTypeFromPOD<std::decay<decltype(std::get<I>(t))>>();
+  }
+
+  template <size_t... I>
+  PUGS_INLINE std::vector<ASTNodeDataType>
+  _getArgumentDataTypes(ArgsTuple t, std::index_sequence<I...>) const
+  {
+    std::vector<ASTNodeDataType> argument_type_list;
+    (argument_type_list.push_back(this->_getOneArgumentDataType<I>(t)), ...);
+    return argument_type_list;
+  }
+
  public:
-  PUGS_INLINE
-  size_t
+  ASTNodeDataType
+  getReturnDataType() const
+  {
+    return this->_getASTNodeDataTypeFromPOD<FX>();
+  }
+
+  std::vector<ASTNodeDataType>
+  getArgumentDataTypes() const final
+  {
+    constexpr size_t N = std::tuple_size_v<ArgsTuple>;
+    ArgsTuple t;
+    using IndexSequence = std::make_index_sequence<N>;
+
+    return this->_getArgumentDataTypes(t, IndexSequence{});
+  }
+
+  PUGS_INLINE constexpr size_t
   numberOfArguments() const
   {
     return sizeof...(Args);
@@ -61,7 +116,7 @@ class CFunctionEmbedder : public ICFunctionEmbedder
 
   PUGS_INLINE
   void
-  apply(const std::vector<ASTNodeDataVariant>& x, FX& f_x) final
+  apply(const std::vector<ASTNodeDataVariant>& x, ASTNodeDataVariant& f_x) final
   {
     constexpr size_t N = std::tuple_size_v<ArgsTuple>;
     ArgsTuple t;
diff --git a/src/language/CMathModule.cpp b/src/language/CMathModule.cpp
index ec37707b96f8d15d68cda6234c010e321a5a44cb..46d2f1f94faf2ef674f626501925603be50f20a7 100644
--- a/src/language/CMathModule.cpp
+++ b/src/language/CMathModule.cpp
@@ -16,9 +16,37 @@ CMathModule::_addFunction(const std::string& name, std::shared_ptr<ICFunctionEmb
 
 CMathModule::CMathModule()
 {
+  this->_addFunction("sqrt", std::make_shared<CFunctionEmbedder<double, double>>(
+                               std::function<double(double)>{[](double x) -> double { return std::sqrt(x); }}));
+
+  this->_addFunction("abs", std::make_shared<CFunctionEmbedder<double, double>>(
+                              std::function<double(double)>{[](double x) -> double { return std::abs(x); }}));
+
   this->_addFunction("sin", std::make_shared<CFunctionEmbedder<double, double>>(
                               std::function<double(double)>{[](double x) -> double { return std::sin(x); }}));
 
   this->_addFunction("cos", std::make_shared<CFunctionEmbedder<double, double>>(
                               std::function<double(double)>{[](double x) -> double { return std::cos(x); }}));
+
+  this->_addFunction("tan", std::make_shared<CFunctionEmbedder<double, double>>(
+                              std::function<double(double)>{[](double x) -> double { return std::tan(x); }}));
+
+  this->_addFunction("asin", std::make_shared<CFunctionEmbedder<double, double>>(
+                               std::function<double(double)>{[](double x) -> double { return std::asin(x); }}));
+
+  this->_addFunction("acos", std::make_shared<CFunctionEmbedder<double, double>>(
+                               std::function<double(double)>{[](double x) -> double { return std::acos(x); }}));
+
+  this->_addFunction("atan", std::make_shared<CFunctionEmbedder<double, double>>(
+                               std::function<double(double)>{[](double x) -> double { return std::atan(x); }}));
+
+  this->_addFunction("exp", std::make_shared<CFunctionEmbedder<double, double>>(
+                              std::function<double(double)>{[](double x) -> double { return std::exp(x); }}));
+
+  this->_addFunction("log", std::make_shared<CFunctionEmbedder<double, double>>(
+                              std::function<double(double)>{[](double x) -> double { return std::log(x); }}));
+
+  this->_addFunction("pow",
+                     std::make_shared<CFunctionEmbedder<double, double, double>>(std::function<double(double, double)>{
+                       [](double x, double y) -> double { return std::pow(x, y); }}));
 }
diff --git a/src/language/node_processor/CFunctionProcessor.hpp b/src/language/node_processor/CFunctionProcessor.hpp
index 0b587afed45d8e991bd355ab6c5c4edc9d55dad4..a5b253072f98e78345700f37905ce52e51adf4eb 100644
--- a/src/language/node_processor/CFunctionProcessor.hpp
+++ b/src/language/node_processor/CFunctionProcessor.hpp
@@ -32,7 +32,6 @@ class CFunctionArgumentProcessor final : public INodeProcessor
   {}
 };
 
-template <typename ReturnType, typename ExpressionValueType>
 class CFunctionExpressionProcessor final : public INodeProcessor
 {
  private:
@@ -45,13 +44,7 @@ class CFunctionExpressionProcessor final : public INodeProcessor
   void
   execute(ExecUntilBreakOrContinue&)
   {
-    ReturnType result;
-    m_embedded_c_function->apply(m_argument_values, result);
-    if constexpr (std::is_same_v<ReturnType, ExpressionValueType>) {
-      m_node.m_value = result;
-    } else {
-      m_node.m_value = static_cast<ExpressionValueType>(result);
-    }
+    m_embedded_c_function->apply(m_argument_values, m_node.m_value);
   }
 
   CFunctionExpressionProcessor(ASTNode& node,