correct parser
diff --git a/README.md b/README.md
index a3f3031..7ac3a85 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
 # Inja
 
-A Template Engine for Modern C++
\ No newline at end of file
+A Template Engine for Modern C++
+
+[![Github Issues](https://img.shields.io/github/issues/pantor/inja.svg)](http://github.com/pantor/inja/issues)
+[![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/pantor/inja/master/LICENSE.MIT)
\ No newline at end of file
diff --git a/src/inja.hpp b/src/inja.hpp
index bbc4421..31802a6 100644
--- a/src/inja.hpp
+++ b/src/inja.hpp
@@ -12,151 +12,402 @@
 using string = std::string;
 
 
-
-template<class BidirIt, class Traits, class CharT, class UnaryFunction>
-std::basic_string<CharT> regex_replace(BidirIt first, BidirIt last,
-	const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
-{
-	std::basic_string<CharT> s;
-
-	typename std::match_results<BidirIt>::difference_type positionOfLastMatch = 0;
-	auto endOfLastMatch = first;
-
-	auto callback = [&](const std::match_results<BidirIt>& match)
+string join_strings(std::vector<string> vector, string delimiter) {
+	std::stringstream ss;
+	for (size_t i = 0; i < vector.size(); ++i)
 	{
-		auto positionOfThisMatch = match.position(0);
-		auto diff = positionOfThisMatch - positionOfLastMatch;
-
-		auto startOfThisMatch = endOfLastMatch;
-		std::advance(startOfThisMatch, diff);
-
-		s.append(endOfLastMatch, startOfThisMatch);
-		s.append(f(match));
-
-		auto lengthOfMatch = match.length(0);
-
-		positionOfLastMatch = positionOfThisMatch + lengthOfMatch;
-
-		endOfLastMatch = startOfThisMatch;
-		std::advance(endOfLastMatch, lengthOfMatch);
-	};
-
-	std::sregex_iterator begin(first, last, re), end;
-	std::for_each(begin, end, callback);
-
-	s.append(endOfLastMatch, last);
-
-	return s;
+		if (i != 0) ss << delimiter;
+		ss << vector[i];
+	}
+	return ss.str();
 }
 
-template<class Traits, class CharT, class UnaryFunction>
-std::string regex_replace(const std::string& s,
-	const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
-{
-	return regex_replace(s.cbegin(), s.cend(), re, f);
+
+struct SearchMatch {
+	SearchMatch() { }
+	
+	SearchMatch(std::smatch match, size_t offset): SearchMatch(match, offset, 1, -1) { }
+	
+	SearchMatch(std::smatch match, size_t offset, int inner_group, int regex_number): inner_group(inner_group), regex_number(regex_number) {
+		position = offset + match.position();
+		length = match.length();
+		end_position = position + length;
+		found = !match.empty();
+		outer = match[0].str();
+		inner = match[inner_group].str();
+		prefix = match.prefix();
+		suffix = match.suffix();
+	}
+	
+	string outer, inner, prefix, suffix;
+	size_t position, end_position;
+	int length;
+	bool found = false;
+	int regex_number = -1, inner_group = 1;
+};
+
+struct SearchClosedMatch {
+	SearchClosedMatch() { }
+	
+	SearchClosedMatch(string input, SearchMatch open_match, SearchMatch close_match): open_match(open_match), close_match(close_match) {
+		position = open_match.position;
+		length = close_match.end_position - open_match.position;
+		end_position = close_match.end_position;
+		found = open_match.found && close_match.found;
+		outer = input.substr(position, length);
+		inner = input.substr(open_match.end_position, close_match.position - open_match.end_position);
+		prefix = open_match.prefix;
+		suffix = close_match.suffix;
+	}
+	
+	string outer, inner, prefix, suffix;
+	size_t position, end_position;
+	int length;
+	bool found = false;
+	
+	SearchMatch open_match, close_match;
+};
+
+SearchMatch search(string input, std::regex regex, size_t position) {
+	auto first = input.cbegin();
+	auto last = input.cend();
+	
+	if (position >= input.length()) {
+		return SearchMatch();
+	}
+				
+	std::smatch match;
+	std::regex_search(first + position, last, match, regex);
+	return SearchMatch(match, position);
 }
 
+SearchMatch search(string input, std::vector<string> regex_patterns, size_t position) {
+	auto first = input.cbegin();
+	auto last = input.cend();
+	
+	string regex_pattern = "(" + join_strings(regex_patterns, ")|(") + ")";
+	std::regex regex(regex_pattern);
+		
+	if (position >= input.length()) {
+		return SearchMatch();
+	}
+	
+	// Vector of id vs groups
+	std::vector<int> regex_mark_counts;
+	for (int i = 0; i < regex_patterns.size(); i++) {
+		for (int j = 0; j < std::regex(regex_patterns[i]).mark_count() + 1; j++) {
+			regex_mark_counts.push_back(i);
+		}
+	}
+		
+	std::smatch match;
+	std::regex_search(first + position, last, match, regex);
+	
+	int number_regex = -1;
+	int number_inner = 1;
+	for (int i = 1; i < match.size(); i++) {
+		if (match.length(i) > 0) {
+			number_inner = i + 1;
+			number_regex = regex_mark_counts[i];
+			break;
+		}
+	}
+			
+	return SearchMatch(match, position, number_inner, number_regex);
+}
+
+SearchClosedMatch search_on_level(string input, std::regex regex_statement, std::regex regex_level_up, std::regex regex_level_down, std::regex regex_search, SearchMatch open_match) {
+		
+	int level = 0;
+	size_t current_position = open_match.end_position;
+	SearchMatch statement_match = search(input, regex_statement, current_position);
+	while (statement_match.found) {
+		current_position = statement_match.end_position;
+		
+		if (level == 0 && std::regex_match(statement_match.inner, regex_search)) break;
+		if (std::regex_match(statement_match.inner, regex_level_up)) level += 1;
+		else if (std::regex_match(statement_match.inner, regex_level_down)) level -= 1;
+			
+		statement_match = search(input, regex_statement, current_position);
+	}
+	
+	return SearchClosedMatch(input, open_match, statement_match);
+}
+
+SearchClosedMatch search_close(string input, std::regex regex_statement, std::regex regex_open, std::regex regex_close, SearchMatch open_match) {
+	return search_on_level(input, regex_statement, regex_open, regex_close, regex_close, open_match);
+}
+	
+	
+
 
 
 class Environment {
-	
-	
+	std::regex regex_statement;
+	std::regex regex_line_statement;
+	std::regex regex_expression;
+	std::regex regex_comment;
+	std::vector<string> regex_pattern_delimiters;
 	
 		
 public:
 	Environment() {
-			
+		const string regex_pattern_statement = "\\(\\%\\s*(.+?)\\s*\\%\\)";
+		// const string regex_pattern_line_statement = "^## (.*)$";
+		const string regex_pattern_expression = "\\{\\{\\s*(.+?)\\s*\\}\\}";
+		const string regex_pattern_comment = "\\{#\\s*(.*?)\\s*#\\}";
+		
+		regex_statement = std::regex(regex_pattern_statement);
+		// regex_line_statement = std::regex(regex_pattern_line_statement);
+		regex_expression = std::regex(regex_pattern_expression);
+		regex_comment = std::regex(regex_pattern_comment);
+		regex_pattern_delimiters = { regex_pattern_statement, regex_pattern_expression, regex_pattern_comment };
 	}
 	
-	json get_variable_data(string variable_name, json data) {
-		// Json Raw Data
-		if ( json::accept(variable_name) ) {
-			return json::parse(variable_name);
-		}
-		
-		// Implement range function
-		std::regex range_regex("^range\\((\\d+)\\)$");
-		std::smatch range_match;
-		if (std::regex_match(variable_name, range_match, range_regex)) {
-			int counter = std::stoi(range_match[1].str());
-			std::vector<int> range(counter);
-			std::iota(range.begin(), range.end(), 0);
-			return range;
-		}
 
-		if (variable_name[0] != '/') {
-			variable_name = "/" + variable_name;
-		}
+	json parse_level(string input) {
+		json result;
 		
-		json::json_pointer ptr(variable_name);
-		json result = data[ptr];
-		if (result.is_null()) {
-			throw std::runtime_error("JSON pointer found no element.");
-		}
-		return result;
-	}
-	
-	
-	string render(string template_input, json data) {
-		return render(template_input, data, "./");
-	}
-		
-	string render(string template_input, json data, string template_path) {
-		string result = template_input;
-		
-		const std::regex include_regex("\\(\\% include \"(.*)\" \\%\\)");
-		result = inja::regex_replace(result, include_regex,
-			[this, template_path](const std::smatch& match) {
-				string filename = template_path + match[1].str();
-				return load_template(filename);
+		size_t current_position = 0;
+		SearchMatch statement_match = search(input, regex_pattern_delimiters, current_position);
+		while (statement_match.found) {
+			current_position = statement_match.end_position;
+			if (!statement_match.prefix.empty()) {
+				result.push_back({{"type", "string"}, {"text", statement_match.prefix}});
 			}
-		);
-		
-		const std::regex loop_regex("\\(\\% for (\\w+) in (.+) \\%\\)(.*)\\(\\% endfor \\%\\)");
-		result = inja::regex_replace(result, loop_regex,
-			[this, data](const std::smatch& match) {
-				string result = "";
-				string entry_name = match[1].str();
-				string list_name = match[2].str();
-				string inner_string = match[3].str();
-				json list = get_variable_data(list_name, data);
-				if (!list.is_array()) throw std::runtime_error("JSON variable is not a list.");
+			
+			// Regex matched a statement "(% ... %)"
+			if (statement_match.regex_number == 0) {
+				const std::regex regex_loop_open("for (.*)");
+				const std::regex regex_loop_close("endfor");
 				
-				for (int i = 0; i < list.size(); i++) {
-					const std::regex entry_regex("\\{\\{.*" + entry_name + ".*\\}\\}");
-					result += inja::regex_replace(inner_string, entry_regex,
-						[list_name, i](const std::smatch& match) {
-							return "{{ " + list_name + "/" + std::to_string(i) + " }}";
-						}
-					);					
+				const std::regex regex_include("include \"(.*)\"");
+				
+				const std::regex regex_condition_open("if (.*)");
+				const std::regex regex_condition_else_if("else if (.*)");
+				const std::regex regex_condition_else("else");
+				const std::regex regex_condition_close("endif");
+				
+				std::smatch inner_statement_match;
+				if (std::regex_match(statement_match.inner, inner_statement_match, regex_loop_open)) {
+					SearchClosedMatch loop_match = search_close(input, regex_statement, regex_loop_open, regex_loop_close, statement_match);
+					
+					current_position = loop_match.end_position;
+					string loop_command = inner_statement_match[0].str();
+					result.push_back({{"type", "loop"}, {"command", loop_command}, {"inner", loop_match.inner}});
 				}
-				return result;
-			}
-		);
-		
-		const std::regex condition_regex("\\(\\% if (\\w+) \\%\\)(.*)\\(\\% endif \\%\\)");
-		result = inja::regex_replace(result, condition_regex,
-			[this, data](const std::smatch& match) {
-				string condition_variable_name = match[1].str();
-				string inner_string = match[2].str();
-				if (get_variable_data(condition_variable_name, data)) {
-					return inner_string;
+				else if (std::regex_match(statement_match.inner, inner_statement_match, regex_include)) {
+					string include_command = inner_statement_match[0].str();
+					string filename = inner_statement_match[1].str();
+					result.push_back({{"type", "include"}, {"filename", filename}});
 				}
-				return string("");
+				else if (std::regex_match(statement_match.inner, inner_statement_match, regex_condition_open)) {
+					string if_command = inner_statement_match[0].str();
+					json condition_result = {{"type", "condition"}, {"children", json::array()}};
+					
+					
+					SearchMatch condition_match = statement_match;
+					
+					SearchClosedMatch else_if_match = search_on_level(input, regex_statement, regex_condition_open, regex_condition_close, regex_condition_else_if, condition_match);
+					while (else_if_match.found) {
+						condition_match = else_if_match.close_match;
+						
+						condition_result["children"].push_back({{"type", "condition_branch"}, {"command", else_if_match.open_match.inner}, {"inner", else_if_match.inner}});
+							
+						else_if_match = search_on_level(input, regex_statement, regex_condition_open, regex_condition_close, regex_condition_else_if, condition_match);
+					}
+					
+					SearchClosedMatch else_match = search_on_level(input, regex_statement, regex_condition_open, regex_condition_close, regex_condition_else, condition_match);
+					if (else_match.found) {
+						condition_match = else_match.close_match;
+						
+						condition_result["children"].push_back({{"type", "condition_branch"}, {"command", else_match.open_match.inner}, {"inner", else_match.inner}});
+					}
+					
+					SearchClosedMatch last_if_match = search_close(input, regex_statement, regex_condition_open, regex_condition_close, condition_match);
+
+					condition_result["children"].push_back({{"type", "condition_branch"}, {"command", last_if_match.open_match.inner}, {"inner", last_if_match.inner}});
+					
+					current_position = last_if_match.end_position;
+					result.push_back(condition_result);
+				}
 			}
-		);
-		
-		const std::regex variable_regex("\\{\\{\\s*([^\\}]*[^\\s])\\s*\\}\\}");
-		result = inja::regex_replace(result, variable_regex,
-			[this, data](const std::smatch& match) {
-				string variable_name = match[1].str(); 
-				return get_variable_data(variable_name, data);
+			// Regex matched an expression "{{ ... }}"
+			else if (statement_match.regex_number == 1) {
+				result.push_back({{"type", "variable"}, {"command", statement_match.inner}});
 			}
-		);
+			// Regex matched an comment "{# ... #}"
+			else if (statement_match.regex_number == 2) {
+				result.push_back({{"type", "comment"}, {"text", statement_match.inner}});
+			}
+			
+			statement_match = search(input, regex_pattern_delimiters, current_position);
+		}
+		if (current_position < input.length()) {
+			result.push_back({{"type", "string"}, {"text", input.substr(current_position)}});
+		}
 		
 		return result;
 	}
 	
+	json parse_tree(json current_element) {
+		if (current_element.find("inner") != current_element.end()) {
+			current_element["children"] = parse_level(current_element["inner"]);
+			current_element.erase("inner");
+		}
+		if (current_element.find("children") != current_element.end()) {
+			for (auto& child: current_element["children"]) {
+				child = parse_tree(child);
+			}
+		}
+		return current_element;
+	}
+	
+	json parse(string input) {
+		return parse_tree({{"inner", input}})["children"];
+	}
+	
+	
+	json parse_variable(string input, json data) {
+		// Json Raw Data
+		if ( json::accept(input) ) {
+			return json::parse(input);
+		}
+		
+		// TODO Implement filter and functions
+
+		if (input[0] != '/') input.insert(0, "/");
+		
+		json::json_pointer ptr(input);
+		json result = data[ptr];
+		
+		if (result.is_null()) throw std::runtime_error("JSON pointer found no element.");
+		return result;
+	}
+	
+	bool parse_condition(string condition, json data) {
+		const std::regex regex_condition_equal("(.*) == (.*)");
+		const std::regex regex_condition_greater("(.*) > (.*)");
+		const std::regex regex_condition_less("(.*) < (.*)");
+		const std::regex regex_condition_greater_equal("(.*) >= (.*)");
+		const std::regex regex_condition_less_equal("(.*) <= (.*)");
+		const std::regex regex_condition_different("(.*) != (.*)");
+		const std::regex regex_condition_in("(.*) in (.*)");
+		
+		std::smatch match_condition;
+		if (std::regex_match(condition, match_condition, regex_condition_equal)) {
+			json comp1 = parse_variable(match_condition[1].str(), data);
+			json comp2 = parse_variable(match_condition[2].str(), data);
+			return comp1 == comp2;
+		} else if (std::regex_match(condition, match_condition, regex_condition_greater)) {
+			json comp1 = parse_variable(match_condition[1].str(), data);
+			json comp2 = parse_variable(match_condition[2].str(), data);
+			return comp1 > comp2;
+		} else if (std::regex_match(condition, match_condition, regex_condition_less)) {
+			json comp1 = parse_variable(match_condition[1].str(), data);
+			json comp2 = parse_variable(match_condition[2].str(), data);
+			return comp1 < comp2;
+		} else if (std::regex_match(condition, match_condition, regex_condition_greater_equal)) {
+			json comp1 = parse_variable(match_condition[1].str(), data);
+			json comp2 = parse_variable(match_condition[2].str(), data);
+			return comp1 >= comp2;
+		} else if (std::regex_match(condition, match_condition, regex_condition_less_equal)) {
+			json comp1 = parse_variable(match_condition[1].str(), data);
+			json comp2 = parse_variable(match_condition[2].str(), data);
+			return comp1 <= comp2;
+		} else if (std::regex_match(condition, match_condition, regex_condition_different)) {
+			json comp1 = parse_variable(match_condition[1].str(), data);
+			json comp2 = parse_variable(match_condition[2].str(), data);
+			return comp1 != comp2;
+		} else if (std::regex_match(condition, match_condition, regex_condition_in)) {
+			json item = parse_variable(match_condition[1].str(), data);
+			json list = parse_variable(match_condition[2].str(), data);
+			return (std::find(list.begin(), list.end(), item) != list.end());
+		}
+		
+		try {
+			return parse_variable(condition, data);
+		}
+		catch (...) {
+			return false;
+		}
+	}
+	
+	string render_json(json data) {
+		if (data.is_string()) {
+			return data;
+		} else {
+			std::stringstream ss;
+			ss << data;
+			return ss.str();
+		}
+	}
+	
+	string render_tree(json input, json data, string path) {		
+		string result = "";		
+		for (auto element: input) {
+			if (element["type"] == "string") {
+				result += element["text"];
+			}
+			else if (element["type"] == "variable") {
+				json variable = parse_variable(element["command"], data);
+				result += render_json(variable);
+			}
+			else if (element["type"] == "include") {
+				result += render_template(path + element["filename"].get<string>(), data);
+			}
+			else if (element["type"] == "loop") {				
+				const std::regex regex_loop_list("for (\\w+) in (.+)");
+				
+				string command = element["command"].get<string>();
+				std::smatch match_command;
+				if (std::regex_match(command, match_command, regex_loop_list)) {
+					string item_name = match_command[1].str();
+					string list_name = match_command[2].str();
+					
+					json list = parse_variable(list_name, data);
+					for (int i = 0; i < list.size(); i++) {
+						json data_loop = data;
+						data_loop[item_name] = list[i];
+						data_loop["index"] = i;
+						data_loop["is_first"] = (i == 0);
+						data_loop["is_last"] = (i == list.size() - 1);
+						result += render_tree(element["children"], data_loop, path);
+					}
+				}
+			}
+			else if (element["type"] == "condition") {				
+				const std::regex regex_condition("(if|else if|else) ?(.*)");
+				
+				json branches = element["children"];
+				for (auto branch: branches) {
+					
+					string command = branch["command"].get<string>();
+					std::smatch match_command;
+					if (std::regex_match(command, match_command, regex_condition)) {
+						string condition_type = match_command[1].str();
+						string condition = match_command[2].str();
+																		
+						if (parse_condition(condition, data) || condition_type == "else") {
+							result += render_tree(branch["children"], data, path);
+							break;
+						}
+					}
+				}
+			}
+		}
+		return result;
+	} 
+	
+	string render(string input, json data) {
+		return render(input, data, "./");
+	}
+		
+	string render(string input, json data, string path) {
+		json parsed = parse(input);
+		return render_tree(parsed, data, path);
+	}
+	
 	string render_template(string filename, json data) {
 		string text = load_template(filename);
 		string path = filename.substr(0, filename.find_last_of("/\\") + 1); // Include / itself
diff --git a/src/json/LICENSE.MIT.txt b/src/json/LICENSE.MIT.txt
deleted file mode 100644
index 00599af..0000000
--- a/src/json/LICENSE.MIT.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License 
-
-Copyright (c) 2013-2017 Niels Lohmann
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/test/src/test b/test/src/test
index c29f7c4..edd1af8 100755
--- a/test/src/test
+++ b/test/src/test
Binary files differ
diff --git a/test/src/test.cpp b/test/src/test.cpp
index 6812056..ce8cd08 100644
--- a/test/src/test.cpp
+++ b/test/src/test.cpp
@@ -8,71 +8,215 @@
 using json = nlohmann::json;
 
 
-TEST_CASE("Variables") {	
+TEST_CASE("String functions") {
+	SECTION("Vector join") {
+		REQUIRE( inja::join_strings({"1", "2", "3"}, ",") == "1,2,3" );
+		REQUIRE( inja::join_strings({"1", "2", "3", "4", "5"}, " ") == "1 2 3 4 5" );
+		REQUIRE( inja::join_strings({}, " ") == "" );
+		REQUIRE( inja::join_strings({"single"}, "---") == "single" );
+	}
+	
+	SECTION("Basic search") {
+		inja::SearchMatch match = inja::search("lorem ipsum dolor it", std::regex("i(.*)m"), 0);
+		inja::SearchMatch match_position = inja::search("lorem ipsum dolor it", std::regex("i(.*)m"), 8);
+		
+		REQUIRE( match.found == true );
+		REQUIRE( match.position == 6 );
+		REQUIRE( match.length == 5 );
+		REQUIRE( match.end_position == 11 );
+		REQUIRE( match.outer == "ipsum" );
+		REQUIRE( match.inner == "psu" );
+		
+		REQUIRE( match_position.found == false );
+	}
+	
+	SECTION("Vector search") {
+		std::vector<std::string> regex_patterns = { "tras", "do(\\w*)or", "es(\\w*)as", "ip(\\w*)um" };
+		inja::SearchMatch match = inja::search("lorem ipsum dolor amit estas tronum.", regex_patterns, 0);
+		
+		std::vector<std::string> regex_patterns_rearranged = { "tras", "ip(\\w*)um", "do(\\w*)or", "es(\\w*)as" };
+		inja::SearchMatch match_rearranged = inja::search("lorem ipsum dolor amit estas tronum.", regex_patterns_rearranged, 0);
+		
+		REQUIRE( match.regex_number == 3 );
+		REQUIRE( match.outer == "ipsum" );
+		REQUIRE( match.inner == "s" );
+		
+		REQUIRE( match_rearranged.regex_number == 1 );
+		REQUIRE( match_rearranged.outer == "ipsum" );
+		REQUIRE( match_rearranged.inner == "s" );
+	}
+}
+
+
+TEST_CASE("Parser") {
 	Environment env = Environment();
+	
+	SECTION("Basic") {
+		std::string test = "asdf";
+		json result = {{{"type", "string"}, {"text", "asdf"}}};
+				
+		REQUIRE( env.parse(test) == result );
+	}
+	
+	SECTION("Variables") {
+		std::string test = "{{ name }}";
+		json result = {{{"type", "variable"}, {"command", "name"}}};
+		REQUIRE( env.parse(test) == result );
+		
+		std::string test_combined = "Hello {{ name }}!";
+		json result_combined = {
+			{{"type", "string"}, {"text", "Hello "}},
+			{{"type", "variable"}, {"command", "name"}},
+			{{"type", "string"}, {"text", "!"}}
+		};
+		REQUIRE( env.parse(test_combined) == result_combined );
+		
+		std::string test_multiple = "Hello {{ name }}! I come from {{ city }}.";
+		json result_multiple = {
+			{{"type", "string"}, {"text", "Hello "}},
+			{{"type", "variable"}, {"command", "name"}},
+			{{"type", "string"}, {"text", "! I come from "}},
+			{{"type", "variable"}, {"command", "city"}},
+			{{"type", "string"}, {"text", "."}}
+		};
+		REQUIRE( env.parse(test_multiple) == result_multiple );
+	}
+	
+	SECTION("Loops") {
+		std::string test = "open (% for e in list %)lorem(% endfor %) closing";
+		json result = {
+			{{"type", "string"}, {"text", "open "}},
+			{{"type", "loop"}, {"command", "for e in list"}, {"children", {
+				{{"type", "string"}, {"text", "lorem"}}
+			}}},
+			{{"type", "string"}, {"text", " closing"}}
+		};
+		
+		std::string test_nested = "(% for e in list %)(% for b in list2 %)lorem(% endfor %)(% endfor %)";
+		json result_nested = {
+			{{"type", "loop"}, {"command", "for e in list"}, {"children", {
+				{{"type", "loop"}, {"command", "for b in list2"}, {"children", {
+					{{"type", "string"}, {"text", "lorem"}}
+				}}}
+			}}}
+		};
+			
+		REQUIRE( env.parse(test) == result );
+		REQUIRE( env.parse(test_nested) == result_nested );
+	}
+	
+	SECTION("Conditionals") {
+		std::string test = "(% if true %)dfgh(% endif %)";
+		json result = {
+			{{"type", "condition"}, {"children", {
+				{{"type", "condition_branch"}, {"command", "if true"}, {"children", {
+					{{"type", "string"}, {"text", "dfgh"}}
+				}}}
+			}}}
+		};
+		
+		std::string test2 = "if: (% if maybe %)first if(% else if perhaps %)first else if(% else if sometimes %)second else if(% else %)test else(% endif %)";
+		json result2 = {
+			{{"type", "string"}, {"text", "if: "}},
+			{{"type", "condition"}, {"children", {
+				{{"type", "condition_branch"}, {"command", "if maybe"}, {"children", {
+					{{"type", "string"}, {"text", "first if"}}
+				}}},
+				{{"type", "condition_branch"}, {"command", "else if perhaps"}, {"children", {
+					{{"type", "string"}, {"text", "first else if"}}
+				}}},
+				{{"type", "condition_branch"}, {"command", "else if sometimes"}, {"children", {
+					{{"type", "string"}, {"text", "second else if"}}
+				}}}, 
+				{{"type", "condition_branch"}, {"command", "else"}, {"children", {
+					{{"type", "string"}, {"text", "test else"}}
+				}}}, 
+			}}}
+		};
+				
+		REQUIRE( env.parse(test) == result );
+		REQUIRE( env.parse(test2) == result2 );
+	}
+	
+	
 	json data;
 	data["name"] = "Peter";
 	data["city"] = "Washington D.C.";
+	data["age"] = 29;
 	data["names"] = {"Jeff", "Seb"};
 	data["brother"]["name"] = "Chris";
 	data["brother"]["daughters"] = {"Maria", "Helen"};
 	data["brother"]["daughter0"] = { { "name", "Maria" } };
-	
+		
 	SECTION("Variables from values") {
-		REQUIRE( env.get_variable_data("42", data) == 42 );
-		REQUIRE( env.get_variable_data("3.1415", data) == 3.1415 );
-		REQUIRE( env.get_variable_data("\"hello\"", data) == "hello" );
+		REQUIRE( env.parse_variable("42", data) == 42 );
+		REQUIRE( env.parse_variable("3.1415", data) == 3.1415 );
+		REQUIRE( env.parse_variable("\"hello\"", data) == "hello" );
 	}
-	
-	SECTION("Variables from functions") {
-		REQUIRE( env.get_variable_data("range(3)", data) == std::vector<int>({0, 1, 2}) );
-	}
-	
+		
 	SECTION("Variables from JSON data") {
-		REQUIRE( env.get_variable_data("name", data) == "Peter" );
-		REQUIRE( env.get_variable_data("names/1", data) == "Seb" );
-		REQUIRE( env.get_variable_data("brother/name", data) == "Chris" );
-		REQUIRE( env.get_variable_data("brother/daughters/0", data) == "Maria" );
-		REQUIRE_THROWS_WITH( env.get_variable_data("noelement", data), "JSON pointer found no element." );
-	}
-	
-	SECTION("Variables should be rendered") {
-		REQUIRE( env.render("My name is...", data) == "My name is..." );
-		REQUIRE( env.render("My name is {{ name }}.", data) == "My name is Peter." );
-		REQUIRE( env.render("My name is {{name}}.", data) == "My name is Peter." );
-		REQUIRE( env.render("My name is {{ name }}. I come from {{ city }}", data) == "My name is Peter. I come from Washington D.C." );
-		REQUIRE( env.render("My name is {{ names/1 }}.", data) == "My name is Seb." );
-		REQUIRE( env.render("My name is {{ brother/name }}.", data) == "My name is Chris." );
-		REQUIRE( env.render("My name is {{ brother/daughter0/name }}.", data) == "My name is Maria." );
+		REQUIRE( env.parse_variable("name", data) == "Peter" );
+		REQUIRE( env.parse_variable("age", data) == 29 );
+		REQUIRE( env.parse_variable("names/1", data) == "Seb" );
+		REQUIRE( env.parse_variable("brother/name", data) == "Chris" );
+		REQUIRE( env.parse_variable("brother/daughters/0", data) == "Maria" );
+		REQUIRE_THROWS_WITH( env.parse_variable("noelement", data), "JSON pointer found no element." );
 	}
 }
 
-TEST_CASE("Loops should be rendered") {
+TEST_CASE("Render") {
 	Environment env = Environment();
 	json data;
-	data["list"] = {"v1", "v2", "v3", "v4"};
+	data["name"] = "Peter";
+	data["city"] = "Brunswick";
+	data["age"] = 29;
+	data["names"] = {"Jeff", "Seb"};
+	data["brother"]["name"] = "Chris";
+	data["brother"]["daughters"] = {"Maria", "Helen"};
+	data["brother"]["daughter0"] = { { "name", "Maria" } };
+	data["is_happy"] = true;
+		
+	SECTION("Basic") {
+		REQUIRE( env.render("Hello World!", data) == "Hello World!" );
+		REQUIRE( env.render("", data, "../") == "" );
+	}
 	
-	REQUIRE( env.render("List: (% for entry in list %)a(% endfor %)", data) == "List: aaaa" );
-	REQUIRE( env.render("List: (% for entry in list %){{ entry }}, (% endfor %)", data) == "List: v1, v2, v3, v4, " );
-	REQUIRE( env.render("List: (% for i in range(4) %)a(% endfor %)", data) == "List: aaaa" );
+	SECTION("Variables") {
+		REQUIRE( env.render("Hello {{ name }}!", data) == "Hello Peter!" );
+		REQUIRE( env.render("{{ name }}", data) == "Peter" );
+		REQUIRE( env.render("{{name}}", data) == "Peter" );
+		REQUIRE( env.render("{{ name }} is {{ age }} years old.", data) == "Peter is 29 years old." );
+		REQUIRE( env.render("Hello {{ name }}! I come from {{ city }}.", data) == "Hello Peter! I come from Brunswick." );
+		REQUIRE( env.render("Hello {{ names/1 }}!", data) == "Hello Seb!" );
+		REQUIRE( env.render("Hello {{ brother/name }}!", data) == "Hello Chris!" );
+		REQUIRE( env.render("Hello {{ brother/daughter0/name }}!", data) == "Hello Maria!" );
+	}
+	
+	SECTION("Comments") {
+		REQUIRE( env.render("Hello{# This is a comment #}!", data) == "Hello!" );
+		REQUIRE( env.render("{# --- #Todo --- #}", data) == "" );
+	}
+	
+	SECTION("Loops") {
+		REQUIRE( env.render("Hello (% for name in names %){{ name }} (% endfor %)!", data) == "Hello Jeff Seb !" );
+		REQUIRE( env.render("Hello (% for name in names %){{ index }}: {{ name }}, (% endfor %)!", data) == "Hello 0: Jeff, 1: Seb, !" );
+	}
+	
+	SECTION("Conditionals") {
+		REQUIRE( env.render("(% if is_happy %)Yeah!(% endif %)", data) == "Yeah!" );
+		REQUIRE( env.render("(% if is_sad %)Yeah!(% endif %)", data) == "" );
+		REQUIRE( env.render("(% if is_sad %)Yeah!(% else %)Nooo...(% endif %)", data) == "Nooo..." );
+		REQUIRE( env.render("(% if age == 29 %)Right(% else %)Wrong(% endif %)", data) == "Right" );
+		REQUIRE( env.render("(% if age > 29 %)Right(% else %)Wrong(% endif %)", data) == "Wrong" );
+		REQUIRE( env.render("(% if age <= 29 %)Right(% else %)Wrong(% endif %)", data) == "Right" );
+		REQUIRE( env.render("(% if age != 28 %)Right(% else %)Wrong(% endif %)", data) == "Right" );
+		REQUIRE( env.render("(% if age >= 30 %)Right(% else %)Wrong(% endif %)", data) == "Wrong" );
+		REQUIRE( env.render("(% if age in [28, 29, 30] %)True(% endif %)", data) == "True" );
+		REQUIRE( env.render("(% if name in [\"Simon\", \"Tom\"] %)Test1(% else if name in [\"Peter\"] %)Test2(% else %)Test3(% endif %)", data) == "Test2" );
+	}
 }
 
-TEST_CASE("Conditionals should be rendered") {
-	Environment env = Environment();
-	json data;
-	data["good"] = true;
-	data["bad"] = false;
-	data["a"] = 2;
-	
-	REQUIRE( env.render("(% if good %)a(% endif %)", data) == "a" );
-	// REQUIRE( env.render("(% if good %)a(% endif %) (% if bad %)b(% endif %)", data) == "a " );
-	// REQUIRE( env.render("(% if good %)one(% else %)two(% endif %)", data) == "one" );
-	// REQUIRE( env.render("(% if bad %)one(% else %)two(% endif %)", data) == "two" );
-	// REQUIRE( env.render("(% if a == 2 %)one(% else %)two(% endif %)", data) == "one" );
-	// REQUIRE( env.render("(% if "b" in {"a", "b", "c"} %)one(% endif %)", data) == "one" );
-}
-
-TEST_CASE("Files should handled") {
+TEST_CASE("Files") {
 	Environment env = Environment();
 	json data;
 	data["name"] = "Jeff";