bool MyASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) {
   add_declaration(decl->getLocStart(), decl->getNameAsString(),
         decl->isThisDeclarationADefinition(), decl);
   // Parameters will be handled automagically by VisitVarDecl
   add_type_usage(decl->getLocStart(), decl->getResultType());
   return true;
}
// Replace:
//   $(nnn)[i]
// with
//   type nnn_i = $(nnn); // to prevent 'normalize(vvv)[i]'
//   nnn_i[i]
std::string create_array_value_variables (const std::string code, std::set<std::string>& local_declarations)
{
	new_code_lines.clear();
	new_instanciations.clear();

	bool single_line_comment = false;
	bool multi_line_comment = false;
	bool preprocessor_directive = false;
	bool in_shrimp_variable = false;
	bool in_shrimp_variable_array_index = false;

	string_pos shrimp_variable_real_start;
	string_pos shrimp_variable_start;
	string_pos shrimp_variable_end;
	std::string shrimp_variable;

	unsigned int parenthesis_level = 0;

	char previous_character = ' ';

	std::string new_code;
	for (std::string::size_type n = 0; n < code.size(); ++n)
	{
		char c = code[n];
		new_code += c;
		if (c == ' '
			|| c == '\n'
			|| c == '\t'
			|| c == '\r'
			|| single_line_comment
			|| multi_line_comment
			)
		{
			if (single_line_comment)
			{
				if (c == '\n' && previous_character != '\\')
				{
					single_line_comment = false;

					// new code line
					string_pos new_code_line_start = new_code.size();

					string_pos p = n;
					char next_c = code[p];
					while ((p < code.size()) && (next_c == '\n' || next_c == '\r'))
					{
						++p;
						++new_code_line_start;

						next_c = code[p];
					}

					new_code_line (new_code_line_start, new_code);
				}
			}

			if (multi_line_comment)
			{
				if (c == '/' && previous_character == '*')
					multi_line_comment = false;
			}

			if (preprocessor_directive)
			{
				if (c == '\n' && previous_character != '\\')
				{
					preprocessor_directive = false;

					// new code line
					string_pos new_code_line_start = new_code.size();

					string_pos p = n;
					char next_c = code[p];
					while ((p < code.size()) && (next_c == '\n' || next_c == '\r'))
					{
						++p;
						++new_code_line_start;

						next_c = code[p];
					}

					new_code_line (new_code_line_start, new_code);
				}
			}

			continue;
		}

		if (c == '/' && previous_character == '/')
		{
			single_line_comment = true;
		}
		else if (c == '*' && previous_character == '/')
		{
			multi_line_comment = true;
		}
		else if (c == '#')
		{
			preprocessor_directive = true;
		}
		else if (c == ';')
		{
			if (parenthesis_level == 0)
			{
				string_pos new_code_line_start = new_code.size();

				string_pos p = n;
				char next_c = code[p];
				while (next_c == '\n' || next_c == '\r')
				{
					++p;
					++new_code_line_start;

					next_c = code[p];
				}

				new_code_line (new_code_line_start, new_code);
			}
		}
		else if (c == '(')
		{
			parenthesis_level++;

			if (previous_character == '$' && !in_shrimp_variable_array_index)
			{
				in_shrimp_variable = true;
				shrimp_variable_real_start = n - 1;
				shrimp_variable_start = n + 1;
			}
		}
		else if (c == ')')
		{
			parenthesis_level--;

			if (in_shrimp_variable)
			{
				in_shrimp_variable = false;
				shrimp_variable_end = n - 1;
				shrimp_variable = trim (std::string (code, shrimp_variable_start, shrimp_variable_end - shrimp_variable_start + 1));
			}
		}
		else if (c == '[' && previous_character == ')' && !in_shrimp_variable_array_index)
		{
			in_shrimp_variable_array_index = true;
		}
		else if (c == ']')
		{
			if (in_shrimp_variable_array_index)
			{
				in_shrimp_variable_array_index = false;

				// replace variable in new code
				add_declaration (shrimp_variable, local_declarations);

				string_pos replacement_start = new_code.size() - (n - shrimp_variable_real_start + 1);
				string_pos replacement_size = shrimp_variable_end - shrimp_variable_real_start + 2;

				new_code.replace (replacement_start, replacement_size, get_valued_variable_name (shrimp_variable));
			}
		}

		previous_character = c;
	}

	// build shader block
	std::string shader_block = "";
	for (std::vector<std::string>::iterator i = new_code_lines.begin(); i != new_code_lines.end(); ++i)
	{
		shader_block += "\t" + *i;
	}

	return shader_block;
}
bool MyASTVisitor::VisitTagDecl(clang::TagDecl* decl) {
   add_declaration(decl->getLocStart(), decl->getNameAsString(),
         decl->isThisDeclarationADefinition(), decl);
   return true;
}
bool MyASTVisitor::VisitLabelStmt(clang::LabelStmt* stmt) {
   add_declaration(stmt->getIdentLoc(), stmt->getName(), true, stmt->getDecl());
   return true;
}
bool MyASTVisitor::VisitEnumConstantDecl(clang::EnumConstantDecl* decl) {
   add_declaration(decl->getLocStart(), decl->getNameAsString(), true, decl);
   return true;
}
bool MyASTVisitor::VisitVarDecl(clang::VarDecl* decl) {
   add_declaration(decl->getLocStart(), decl->getNameAsString(), true, decl);
   add_type_usage(decl->getLocStart(), decl->getType());
   return true;
}
bool MyASTVisitor::VisitTypedefNameDecl(clang::TypedefNameDecl* decl) {
   add_type_usage(decl->getTypeSourceInfo()->getTypeLoc().getLocStart(),
         decl->getUnderlyingType());
   add_declaration(decl->getLocStart(), decl->getNameAsString(), true, decl);
   return true;
}