add atid operation
diff --git a/include/inja/function_storage.hpp b/include/inja/function_storage.hpp
index e0d740f..7767f9b 100644
--- a/include/inja/function_storage.hpp
+++ b/include/inja/function_storage.hpp
@@ -36,6 +36,7 @@
     Division,
     Power,
     Modulo,
+    AtId,
     At,
     Default,
     DivisibleBy,
diff --git a/include/inja/lexer.hpp b/include/inja/lexer.hpp
index 5b218b8..d93aafc 100644
--- a/include/inja/lexer.hpp
+++ b/include/inja/lexer.hpp
@@ -108,6 +108,8 @@
       return make_token(Token::Kind::Power);
     case '%':
       return make_token(Token::Kind::Percent);
+    case '.':
+      return make_token(Token::Kind::Dot);
     case ',':
       return make_token(Token::Kind::Comma);
     case ':':
diff --git a/include/inja/node.hpp b/include/inja/node.hpp
index 62707f8..6247d12 100644
--- a/include/inja/node.hpp
+++ b/include/inja/node.hpp
@@ -141,7 +141,7 @@
   size_t number_args;
   CallbackFunction callback;
 
-  explicit FunctionNode(nonstd::string_view name, size_t pos) : ExpressionNode(pos), precedence(5), associativity(Associativity::Left), operation(Op::Callback), name(name), number_args(1) { }
+  explicit FunctionNode(nonstd::string_view name, size_t pos) : ExpressionNode(pos), precedence(8), associativity(Associativity::Left), operation(Op::Callback), name(name), number_args(1) { }
   explicit FunctionNode(Op operation, size_t pos) : ExpressionNode(pos), operation(operation), number_args(1) {
     switch (operation) {
       case Op::Not: {
@@ -208,6 +208,10 @@
         precedence = 4;
         associativity = Associativity::Left;
       } break;
+      case Op::AtId: {
+        precedence = 8;
+        associativity = Associativity::Left;
+      } break;
       default: {
         precedence = 1;
         associativity = Associativity::Left;
diff --git a/include/inja/parser.hpp b/include/inja/parser.hpp
index ae7b7a1..c6d46a3 100644
--- a/include/inja/parser.hpp
+++ b/include/inja/parser.hpp
@@ -166,7 +166,8 @@
       case Token::Kind::Times:
       case Token::Kind::Slash:
       case Token::Kind::Power:
-      case Token::Kind::Percent: {
+      case Token::Kind::Percent:
+      case Token::Kind::Dot: {
 
   parse_operator:
         FunctionStorage::Operation operation;
@@ -220,6 +221,9 @@
         case Token::Kind::Percent: {
           operation = FunctionStorage::Operation::Modulo;
         } break;
+        case Token::Kind::Dot: {
+          operation = FunctionStorage::Operation::AtId;
+        } break;
         default: {
           throw_parser_error("unknown operator in parser.");
         }
diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp
index 9a4dae0..5427c3d 100644
--- a/include/inja/renderer.hpp
+++ b/include/inja/renderer.hpp
@@ -311,6 +311,16 @@
       json_tmp_stack.push_back(result_ptr);
       json_eval_stack.push(result_ptr.get());
     } break;
+    case Op::AtId: {
+      json_eval_stack.pop(); // Pop id nullptr
+      auto container = get_arguments<1, false>(node)[0];
+      if (not_found_stack.empty()) {
+        throw_renderer_error("could not find element with given name", node);
+      }
+      auto id_node = not_found_stack.top();
+      not_found_stack.pop();
+      json_eval_stack.push(&container->at(id_node->name));
+    } break;
     case Op::At: {
       auto args = get_arguments<2>(node);
       json_eval_stack.push(&args[0]->at(args[1]->get<int>()));
diff --git a/include/inja/token.hpp b/include/inja/token.hpp
index 00df042..c000138 100644
--- a/include/inja/token.hpp
+++ b/include/inja/token.hpp
@@ -33,6 +33,7 @@
     Percent,            // %
     Power,              // ^
     Comma,              // ,
+    Dot,                // .
     Colon,              // :
     LeftParen,          // (
     RightParen,         // )
diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp
index 755827b..b1119db 100644
--- a/single_include/inja/inja.hpp
+++ b/single_include/inja/inja.hpp
@@ -1550,6 +1550,7 @@
     Division,
     Power,
     Modulo,
+    AtId,
     At,
     Default,
     DivisibleBy,
@@ -1770,6 +1771,7 @@
     Percent,            // %
     Power,              // ^
     Comma,              // ,
+    Dot,                // .
     Colon,              // :
     LeftParen,          // (
     RightParen,         // )
@@ -1984,6 +1986,8 @@
       return make_token(Token::Kind::Power);
     case '%':
       return make_token(Token::Kind::Percent);
+    case '.':
+      return make_token(Token::Kind::Dot);
     case ',':
       return make_token(Token::Kind::Comma);
     case ':':
@@ -2849,7 +2853,8 @@
       case Token::Kind::Times:
       case Token::Kind::Slash:
       case Token::Kind::Power:
-      case Token::Kind::Percent: {
+      case Token::Kind::Percent:
+      case Token::Kind::Dot: {
 
   parse_operator:
         FunctionStorage::Operation operation;
@@ -2903,6 +2908,10 @@
         case Token::Kind::Percent: {
           operation = FunctionStorage::Operation::Modulo;
         } break;
+        case Token::Kind::Dot: {
+          std::cout << "test" << std::endl;
+          operation = FunctionStorage::Operation::AtId;
+        } break;
         default: {
           throw_parser_error("unknown operator in parser.");
         }
@@ -3553,6 +3562,21 @@
       json_tmp_stack.push_back(result_ptr);
       json_eval_stack.push(result_ptr.get());
     } break;
+    case Op::AtId: {
+      std::cout << "test" << std::endl;
+      auto container = get_arguments<1, false>(node)[0];
+      auto id = get_arguments<1, false>(node)[0];
+      if (id == nullptr) {
+        auto id_node = not_found_stack.top();
+        not_found_stack.pop();
+
+        auto ptr = json::json_pointer(id_node->ptr);
+        json_eval_stack.push(&container->at(ptr));
+      
+      } else {
+        json_eval_stack.push(id);
+      }
+    } break;
     case Op::At: {
       auto args = get_arguments<2>(node);
       json_eval_stack.push(&args[0]->at(args[1]->get<int>()));
diff --git a/test/test-functions.cpp b/test/test-functions.cpp
index b846446..def0c6d 100644
--- a/test/test-functions.cpp
+++ b/test/test-functions.cpp
@@ -254,6 +254,7 @@
   data["brother"]["daughters"] = {"Maria", "Helen"};
   data["brother"]["daughter0"] = {{"name", "Maria"}};
   data["is_happy"] = true;
+  data["list_of_objects"] = {{{"a", 2}}, {{"b", 3}}, {{"c", 4}}, {{"d", 5}}};
 
   CHECK(env.render("{% if upper(\"Peter\") == \"PETER\" %}TRUE{% endif %}", data) == "TRUE");
   CHECK(env.render("{% if lower(upper(name)) == \"peter\" %}TRUE{% endif %}", data) == "TRUE");
@@ -263,4 +264,7 @@
   CHECK(env.render("{{ upper(first(sort(brother.daughters)) + \"_test\") }}", data) == "HELEN_TEST");
   CHECK(env.render("{% for i in range(3) %}{{ at(names, i) }}{% endfor %}", data) == "JeffSebChris");
   CHECK(env.render("{% if not is_happy or age > 26 %}TRUE{% endif %}", data) == "TRUE");
+  CHECK(env.render("{{ last(list_of_objects).d * 2}}", data) == "10");
+  CHECK(env.render("{{ last(range(5)) * 2 }}", data) == "8");
+  CHECK(env.render("{{ last(range(5 * 2)) }}", data) == "9");
 }