diff --git a/src/language/ASTBuilder.cpp b/src/language/ASTBuilder.cpp
index e8c81778fe53470bc1bf22185f1fde0f7a8a43d8..984ed5cba1f69098527296d196f966cf3d5918d5 100644
--- a/src/language/ASTBuilder.cpp
+++ b/src/language/ASTBuilder.cpp
@@ -201,60 +201,63 @@ struct ASTBuilder::simplify_stream_statement : parse_tree::apply<ASTBuilder::sim
 };
 
 template <typename Rule>
-using selector =
-  parse_tree::selector<Rule,
-                       parse_tree::store_content::on<true_kw,
-                                                     false_kw,
-                                                     integer,
-                                                     real,
-                                                     literal,
-                                                     name,
-                                                     B_set,
-                                                     N_set,
-                                                     Z_set,
-                                                     R_set,
-                                                     string_type,
-                                                     cout_kw,
-                                                     cerr_kw,
-                                                     clog_kw,
-                                                     declaration,
-                                                     if_statement,
-                                                     do_while_statement,
-                                                     while_statement,
-                                                     for_statement,
-                                                     break_kw,
-                                                     continue_kw>,
-                       ASTBuilder::rearrange::on<product, affectation, expression>,
-                       ASTBuilder::simplify_unary::on<unary_minus, unary_plus, unary_not, unary_expression>,
-                       parse_tree::remove_content::on<plus_op,
-                                                      minus_op,
-                                                      multiply_op,
-                                                      divide_op,
-                                                      lesser_op,
-                                                      lesser_or_eq_op,
-                                                      greater_op,
-                                                      greater_or_eq_op,
-                                                      eqeq_op,
-                                                      not_eq_op,
-                                                      and_op,
-                                                      or_op,
-                                                      xor_op,
-                                                      eq_op,
-                                                      multiplyeq_op,
-                                                      divideeq_op,
-                                                      pluseq_op,
-                                                      minuseq_op,
-                                                      unary_plusplus,
-                                                      unary_minusminus,
-                                                      post_minusminus,
-                                                      post_plusplus>,
-                       ASTBuilder::simplify_for_statement_block::on<for_statement_block>,
-                       parse_tree::discard_empty::on<ignored, semicol, block>,
-                       ASTBuilder::simplify_statement_block::on<statement_block>,
-                       ASTBuilder::simplify_for_init::on<for_init>,
-                       ASTBuilder::simplify_for_test::on<for_test>,
-                       ASTBuilder::simplify_for_post::on<for_post>,
-                       ASTBuilder::simplify_stream_statement::on<ostream_statement>>;
+using selector = parse_tree::selector<
+  Rule,
+  parse_tree::store_content::on<true_kw,
+                                false_kw,
+                                integer,
+                                real,
+                                literal,
+                                name,
+                                B_set,
+                                N_set,
+                                Z_set,
+                                R_set,
+                                string_type,
+                                cout_kw,
+                                cerr_kw,
+                                clog_kw,
+                                declaration,
+                                let_declaration,
+                                function_domain_mapping,
+                                function_definition,
+                                if_statement,
+                                do_while_statement,
+                                while_statement,
+                                for_statement,
+                                break_kw,
+                                continue_kw>,
+  ASTBuilder::rearrange::on<product, affectation, expression>,
+  ASTBuilder::simplify_unary::on<unary_minus, unary_plus, unary_not, function_evaluation, unary_expression>,
+  parse_tree::remove_content::on<plus_op,
+                                 minus_op,
+                                 multiply_op,
+                                 divide_op,
+                                 lesser_op,
+                                 lesser_or_eq_op,
+                                 greater_op,
+                                 greater_or_eq_op,
+                                 eqeq_op,
+                                 not_eq_op,
+                                 and_op,
+                                 or_op,
+                                 xor_op,
+                                 eq_op,
+                                 multiplyeq_op,
+                                 divideeq_op,
+                                 pluseq_op,
+                                 minuseq_op,
+                                 unary_plusplus,
+                                 unary_minusminus,
+                                 post_minusminus,
+                                 post_plusplus>,
+  ASTBuilder::simplify_for_statement_block::on<for_statement_block>,
+  parse_tree::discard_empty::on<ignored, semicol, block>,
+  ASTBuilder::simplify_statement_block::on<statement_block>,
+  ASTBuilder::simplify_for_init::on<for_init>,
+  ASTBuilder::simplify_for_test::on<for_test>,
+  ASTBuilder::simplify_for_post::on<for_post>,
+  ASTBuilder::simplify_stream_statement::on<ostream_statement>>;
 
 template <typename InputT>
 std::unique_ptr<ASTNode>
diff --git a/src/language/ASTNodeDataType.cpp b/src/language/ASTNodeDataType.cpp
index 855a3e04a0337f7bbc8cbe08ef17b1fd2aa2968a..1220df563cc9ec5685bc68dfaaa791062c086efb 100644
--- a/src/language/ASTNodeDataType.cpp
+++ b/src/language/ASTNodeDataType.cpp
@@ -26,6 +26,9 @@ dataTypeName(const ASTNodeDataType& data_type)
   case ASTNodeDataType::typename_t:
     name = "typename";
     break;
+  case ASTNodeDataType::function_t:
+    name = "function";
+    break;
   case ASTNodeDataType::void_t:
     name = "void";
     break;
diff --git a/src/language/ASTNodeDataType.hpp b/src/language/ASTNodeDataType.hpp
index d6153c101347459c2958d9a816c4737969888d67..daabf0c0ec78ab9bf22c4f0dc52f1f20b78bcbf9 100644
--- a/src/language/ASTNodeDataType.hpp
+++ b/src/language/ASTNodeDataType.hpp
@@ -13,6 +13,7 @@ enum class ASTNodeDataType : int32_t
   double_t       = 3,
   string_t       = 5,
   typename_t     = 10,
+  function_t     = 11,
   void_t         = std::numeric_limits<int32_t>::max()
 };
 
diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp
index 020e7baeddea0752916c9e24cf4fefb9385a8db4..cfdc0187c0564c9f73b022cac5bb84977d555ccc 100644
--- a/src/language/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ASTNodeDataTypeBuilder.cpp
@@ -51,6 +51,46 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n)
         Assert(found);
         i_symbol->second.setDataType(data_type);
         n.m_data_type = data_type;
+      } else if (n.is<language::let_declaration>()) {
+        n.children[0]->m_data_type = ASTNodeDataType::function_t;
+
+        n.children[1]->children[0]->m_data_type = ASTNodeDataType::typename_t;
+        n.children[1]->children[1]->m_data_type = ASTNodeDataType::typename_t;
+
+        {   // Function data type
+          const std::string& symbol = n.children[0]->string();
+
+          std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
+
+          auto [i_symbol, found] = symbol_table->find(symbol, n.children[0]->begin());
+          Assert(found);
+          i_symbol->second.setDataType(n.children[0]->m_data_type);
+        }
+        auto& type_node = *(n.children[1]->children[0]);
+        ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
+        if (type_node.is<language::B_set>()) {
+          data_type = ASTNodeDataType::bool_t;
+        } else if (type_node.is<language::Z_set>()) {
+          data_type = ASTNodeDataType::int_t;
+        } else if (type_node.is<language::N_set>()) {
+          data_type = ASTNodeDataType::unsigned_int_t;
+        } else if (type_node.is<language::R_set>()) {
+          data_type = ASTNodeDataType::double_t;
+        } else if (type_node.is<language::string_type>()) {
+          data_type = ASTNodeDataType::string_t;
+        }
+
+        Assert(data_type != ASTNodeDataType::undefined_t);   // LCOV_EXCL_LINE
+
+        n.children[2]->children[0]->m_data_type = data_type;
+        const std::string& symbol               = n.children[2]->children[0]->string();
+
+        std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
+
+        auto [i_symbol, found] = symbol_table->find(symbol, n.children[2]->children[0]->begin());
+        Assert(found);
+        i_symbol->second.setDataType(data_type);
+        n.m_data_type = ASTNodeDataType::void_t;
       } else if (n.is<language::name>()) {
         std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
 
@@ -68,6 +108,8 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n)
     } else if (n.is<language::eq_op>() or n.is<language::multiplyeq_op>() or n.is<language::divideeq_op>() or
                n.is<language::pluseq_op>() or n.is<language::minuseq_op>()) {
       n.m_data_type = n.children[0]->m_data_type;
+    } else if (n.is<language::function_domain_mapping>() or n.is<language::function_definition>()) {
+      n.m_data_type = ASTNodeDataType::void_t;
     } else if (n.is<language::for_post>() or n.is<language::for_init>() or n.is<language::for_statement_block>()) {
       n.m_data_type = ASTNodeDataType::void_t;
     } else if (n.is<language::for_test>()) {
diff --git a/src/language/ASTNodeExpressionBuilder.cpp b/src/language/ASTNodeExpressionBuilder.cpp
index e6dd686c6ee9db5104b343ecd2bdc5ebe8a3ef3d..f7157005e6d209fcc0ca23481285b3b83b5ac3aa 100644
--- a/src/language/ASTNodeExpressionBuilder.cpp
+++ b/src/language/ASTNodeExpressionBuilder.cpp
@@ -27,6 +27,11 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n)
               n.is<language::pluseq_op>() or n.is<language::minuseq_op>())) {
     ASTNodeAffectationExpressionBuilder{n};
 
+  } else if (n.is<language::let_declaration>()) {
+    std::cerr << rang::fgB::red << "\"Let expression\" is not defined correctly" << rang::style::reset << '\n';
+    n.m_node_processor = std::make_unique<FakeProcessor>();
+    return;
+
   } else if (n.is<language::real>()) {
     n.m_node_processor = std::make_unique<FakeProcessor>();
   } else if (n.is<language::integer>()) {
diff --git a/src/language/ASTSymbolInitializationChecker.cpp b/src/language/ASTSymbolInitializationChecker.cpp
index 06b0e9975b53b48bb943f4de5d2cacb98ff493af..1c75f86a46a3dd868d582e2e421c4b2a6a5cc638 100644
--- a/src/language/ASTSymbolInitializationChecker.cpp
+++ b/src/language/ASTSymbolInitializationChecker.cpp
@@ -15,6 +15,20 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
       this->_checkSymbolInitialization(*node.children[2]);
       i_symbol->second.setIsInitialized();
     }
+  } else if (node.is<language::let_declaration>()) {
+    const std::string& symbol = node.children[0]->string();
+    auto [i_symbol, found]    = node.m_symbol_table->find(symbol, node.children[0]->begin());
+    Assert(found, "unexpected error, should have been detected through declaration checking");
+    if (node.children.size() == 3) {
+      this->_checkSymbolInitialization(*node.children[2]);
+      i_symbol->second.setIsInitialized();
+    }
+  } else if (node.is<language::function_definition>()) {
+    const std::string& symbol = node.children[0]->string();
+    auto [i_symbol, found]    = node.m_symbol_table->find(symbol, node.children[0]->begin());
+    Assert(found, "unexpected error, should have been detected through declaration checking");
+    i_symbol->second.setIsInitialized();
+    this->_checkSymbolInitialization(*node.children[1]);
   } else if (node.is<language::eq_op>()) {
     // first checks for right hand side
     this->_checkSymbolInitialization(*node.children[1]);
diff --git a/src/language/ASTSymbolTableBuilder.cpp b/src/language/ASTSymbolTableBuilder.cpp
index 5fadaf4e0cdd585a3a1e1a2adc9d0a077d24a34d..0d3c082326d037c801e7ea5391816087c11dd695 100644
--- a/src/language/ASTSymbolTableBuilder.cpp
+++ b/src/language/ASTSymbolTableBuilder.cpp
@@ -25,6 +25,22 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>
           error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << '\'' << " was already defined!";
           throw parse_error(error_message.str(), std::vector{n.begin()});
         }
+      } else if (n.is<language::let_declaration>()) {
+        const std::string& symbol = n.children[0]->string();
+        auto [i_symbol, success]  = symbol_table->add(symbol, n.children[0]->begin());
+        if (not success) {
+          std::ostringstream error_message;
+          error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << '\'' << " was already defined!";
+          throw parse_error(error_message.str(), std::vector{n.begin()});
+        }
+      } else if (n.is<language::function_definition>()) {
+        const std::string& symbol = n.children[0]->string();
+        auto [i_symbol, success]  = symbol_table->add(symbol, n.children[0]->begin());
+        if (not success) {
+          std::ostringstream error_message;
+          error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << '\'' << " was already defined!";
+          throw parse_error(error_message.str(), std::vector{n.begin()});
+        }
       } else if (n.is<language::name>()) {
         auto [i_symbol, found] = symbol_table->find(n.string(), n.begin());
         if (not found) {
diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp
index 0c308405d92b25c785e59e93428fe51268a526bc..3a8eda150e722ef607106065adb580a162eab7ea 100644
--- a/src/language/PEGGrammar.hpp
+++ b/src/language/PEGGrammar.hpp
@@ -56,8 +56,6 @@ struct literal : if_must< one< '"' >, until< one< '"' >, character > > {};
 
 struct LITERAL : seq< literal, ignored >{};
 
-struct semicol : one< ';' >{};
-
 struct REAL : seq< real, ignored >{};
 
 struct B_set : one< 'B' >{};
@@ -82,6 +80,9 @@ struct false_kw :  TAO_PEGTL_KEYWORD("false") {};
 
 struct BOOL : seq< sor<true_kw, false_kw>, ignored > {};
 
+struct let_kw : TAO_PEGTL_KEYWORD("let") {};
+struct LET : seq < let_kw, ignored > {};
+
 struct do_kw : TAO_PEGTL_KEYWORD("do") {};
 struct DO : seq < do_kw, ignored > {};
 
@@ -109,18 +110,30 @@ struct clog_kw : TAO_PEGTL_KEYWORD("clog") {};
 
 struct keywork : sor < basic_type, true_kw, false_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {};
 
-struct name : minus< identifier, keywork >  {};
+struct name : minus< identifier, keywork > {};
 struct NAME : seq < name, ignored > {};
 
+struct right_arrow_kw : seq< one< '-' >, one< '>' > > {};
+struct RIGHT_ARROW : seq< right_arrow_kw, ignored > {};
+
+struct semicol : one< ';' > {};
 struct SEMICOL : seq< semicol , ignored > {};
 
+struct column : one< ':' > {};
+struct COLUMN : seq< column , ignored > {};
+
+struct comma : one< ',' > {};
+struct COMMA : seq< comma , ignored > {};
+
 struct open_parent : seq< one< '(' >, ignored > {};
 struct close_parent : seq< one< ')' >, ignored > {};
 
 struct expression;
 struct parented_expression : if_must< open_parent, expression, close_parent > {};
 
-struct primary_expression : sor< BOOL, REAL, INTEGER, LITERAL, NAME, parented_expression > {};
+struct function_evaluation : seq< NAME, parented_expression > {};
+
+struct primary_expression : sor< BOOL, REAL, INTEGER, LITERAL, function_evaluation, NAME, parented_expression > {};
 
 struct unary_plusplus : TAO_PEGTL_STRING("++") {};
 struct unary_minusminus : TAO_PEGTL_STRING("--") {};
@@ -188,7 +201,12 @@ struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op
 
 struct affectation : seq< NAME , if_must< affect_op, expression > >{};
 
-struct declaration : if_must<TYPESPECIFIER, NAME, opt<if_must<seq<one<'='>,ignored>, expression>> >{};
+struct declaration : if_must< TYPESPECIFIER, NAME, opt< if_must< seq< one< '=' >, ignored >, expression > > >{};
+
+struct function_domain_mapping : seq< TYPESPECIFIER, RIGHT_ARROW, TYPESPECIFIER >{};
+struct function_definition : seq< NAME, RIGHT_ARROW, expression >{};
+
+struct let_declaration : if_must< LET, NAME, COLUMN, function_domain_mapping, COMMA, function_definition >{};
 
 struct open_brace : seq< one< '{' >, ignored >{};
 struct close_brace : seq< one< '}' >, ignored >{};
@@ -198,7 +216,7 @@ struct instruction_list;
 struct braced_instruction_list
     :  sor<try_catch< open_brace, instruction_list, close_brace >,
            // non matching braces management
-           if_must< at< one< '{' > >, raise<open_brace>, until<eof> > >{};
+           if_must< at< one< '{' > >, raise< open_brace >, until< eof > > >{};
 
 struct block : braced_instruction_list {};
 
@@ -222,7 +240,8 @@ struct ostream_object : seq< sor< cout_kw, cerr_kw, clog_kw >, ignored >{};
 struct ostream_statement : seq< ostream_object, star< if_must< shift_left_op, expression, ignored > > >{};
 
 struct instruction
-    : sor<if_must< declaration, semicol >,
+    : sor<if_must< let_declaration, semicol >,
+          if_must< declaration, semicol >,
           if_must< affectation, semicol >,
           if_statement,
           if_must<do_while_statement, semicol>,
diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp
index 3c5b8ec4c86774f2071dfd9dde552d1d14ec5cc2..13c16e22362cd19bde2f883fe4738295d7363511 100644
--- a/src/language/PugsParser.cpp
+++ b/src/language/PugsParser.cpp
@@ -56,6 +56,7 @@ parser(const std::string& filename)
 
     ASTSymbolInitializationChecker{*root_node};
 
+    ASTNodeDataTypeBuilder{*root_node};
     {
       std::string dot_filename{"parse_tree.dot"};
       std::ofstream fout(dot_filename);
@@ -64,7 +65,6 @@ parser(const std::string& filename)
       std::cout << "   AST dot file: " << dot_filename << '\n';
     }
 
-    ASTNodeDataTypeBuilder{*root_node};
     ASTNodeDataTypeChecker{*root_node};
 
     ASTNodeValueBuilder{*root_node};