*/
#include "generate.h"
#include "json/json.h"
-#include "util/optional.h"
-#include "util/filesystem.h"
+#include <fstream>
+#include <cassert>
#include <limits>
-#include <algorithm>
-#include <cstdlib>
-#include <iostream>
-#include <sstream>
-#include <deque>
+#include <unordered_map>
#include <unordered_set>
+#include <set>
+#include <list>
+#include <deque>
namespace vulkan_cpu
{
{
namespace generate
{
-using namespace util::string_view_literals;
-
-struct Spirv_and_parser_generator : public Generator
-{
- struct State;
- virtual void run(Generator_args &generator_args,
- const ast::Top_level &top_level) const override;
-};
+constexpr std::size_t detail::Generated_output_stream::output_tab_width_no_tabs_allowed;
+constexpr util::string_view detail::Generated_output_stream::literal_command;
+constexpr char detail::Generated_output_stream::indent_indicator_char;
+constexpr char detail::Generated_output_stream::literal_indent_indicator_char;
+constexpr std::size_t detail::Generated_output_stream::indent_indicators_per_indent;
+constexpr char detail::Generated_output_stream::escape_char;
+constexpr bool detail::Generated_output_stream::indent_blank_lines;
-namespace
+void detail::Generated_output_stream::write_to_file(bool do_reindent) const
{
-}
-
-struct Spirv_and_parser_generator::State
-{
- class Generated_output_stream
+ std::ofstream os;
+ os.exceptions(std::ios::badbit);
+ os.open(file_path.c_str());
+ if(!os)
+ throw util::filesystem::filesystem_error(
+ "open failed", file_path, std::make_error_code(std::io_errc::stream));
+ os.exceptions(std::ios::badbit | std::ios::failbit);
+ if(do_reindent)
{
- private:
- std::deque<char> value;
- util::filesystem::path file_path;
-
- public:
- explicit Generated_output_stream(util::filesystem::path file_path) noexcept
- : value(),
- file_path(std::move(file_path))
- {
- }
- const util::filesystem::path &get_file_path() const noexcept
- {
- return file_path;
- }
- static constexpr std::size_t output_tab_width_no_tabs_allowed = 0;
- static constexpr util::string_view literal_command = "literal:"_sv;
- template <typename Fn>
- static void write_indent(Fn write_char,
- std::size_t indent_depth,
- std::size_t output_tab_width = output_tab_width_no_tabs_allowed)
- {
- if(output_tab_width != output_tab_width_no_tabs_allowed)
+ auto iter = value.begin();
+ bool is_at_start_of_line = true;
+ std::size_t start_indent_depth = 0;
+ std::size_t indent_depth = 0;
+ constexpr std::size_t output_indent_width = 4;
+ constexpr std::size_t output_tab_width = output_tab_width_no_tabs_allowed;
+ while(iter != value.end())
+ {
+ if(*iter == '\n')
{
- while(indent_depth >= output_tab_width)
- {
- indent_depth -= output_tab_width;
- write_char('\t');
- }
+ if(indent_blank_lines && is_at_start_of_line)
+ write_indent(
+ [&](char ch)
+ {
+ os << ch;
+ },
+ indent_depth,
+ output_tab_width);
+ is_at_start_of_line = true;
+ indent_depth = start_indent_depth;
+ os << *iter++;
}
- while(indent_depth--)
- write_char(' ');
- }
- static constexpr char indent_indicator_char = ' ';
- static constexpr char literal_indent_indicator_char = '`';
- static constexpr std::size_t indent_indicators_per_indent = 4;
- static constexpr char escape_char = '@';
- static constexpr bool indent_blank_lines = false;
- void write_to_file(bool do_reindent = true) const
- {
- std::ofstream os;
- os.exceptions(std::ios::badbit);
- os.open(file_path.c_str());
- if(!os)
- throw util::filesystem::filesystem_error(
- "open failed", file_path, std::make_error_code(std::io_errc::stream));
- os.exceptions(std::ios::badbit | std::ios::failbit);
- if(do_reindent)
+ else if(is_at_start_of_line)
{
- auto iter = value.begin();
- bool is_at_start_of_line = true;
- std::size_t start_indent_depth = 0;
- std::size_t indent_depth = 0;
- constexpr std::size_t output_indent_width = 4;
- constexpr std::size_t output_tab_width = output_tab_width_no_tabs_allowed;
- while(iter != value.end())
+ switch(*iter)
{
- if(*iter == '\n')
+ case '\r':
+ case '\t':
+ case '\f':
+ case '\0':
+ assert(false);
+ continue;
+ case literal_indent_indicator_char:
+ ++iter;
+ indent_depth++;
+ continue;
+ case indent_indicator_char:
+ for(std::size_t i = 0; i < indent_indicators_per_indent; i++)
{
- if(indent_blank_lines && is_at_start_of_line)
- write_indent(
- [&](char ch)
- {
- os << ch;
- },
- indent_depth,
- output_tab_width);
- is_at_start_of_line = true;
- indent_depth = start_indent_depth;
- os << *iter++;
+ assert(iter != value.end());
+ assert(*iter == indent_indicator_char);
+ ++iter;
}
- else if(is_at_start_of_line)
+ indent_depth += output_indent_width;
+ continue;
+ case escape_char:
+ {
+ ++iter;
+ assert(iter != value.end());
+ if(*iter != escape_char)
{
- switch(*iter)
+ if(*iter >= 'a' && *iter <= 'z')
{
- case '\r':
- case '\t':
- case '\f':
- case '\0':
- assert(false);
- continue;
- case literal_indent_indicator_char:
- ++iter;
- indent_depth++;
- continue;
- case indent_indicator_char:
- for(std::size_t i = 0; i < indent_indicators_per_indent; i++)
+ std::string command;
+ while(true)
{
assert(iter != value.end());
- assert(*iter == indent_indicator_char);
- ++iter;
+ if(*iter == escape_char)
+ break;
+ command += *iter++;
}
- indent_depth += output_indent_width;
- continue;
- case escape_char:
- {
- ++iter;
assert(iter != value.end());
- if(*iter != escape_char)
+ assert(*iter == escape_char);
+ ++iter;
+ auto command_sv = util::string_view(command);
+ if(command_sv.compare(0, literal_command.size(), literal_command) == 0)
{
- if(*iter >= 'a' && *iter <= 'z')
+ auto arg = command_sv.substr(literal_command.size());
+ std::size_t count = 0;
+ do
{
- std::string command;
- while(true)
- {
- assert(iter != value.end());
- if(*iter == escape_char)
- break;
- command += *iter++;
- }
- assert(iter != value.end());
- assert(*iter == escape_char);
- ++iter;
- auto command_sv = util::string_view(command);
- if(command_sv.compare(
- 0, literal_command.size(), literal_command)
- == 0)
- {
- auto arg = command_sv.substr(literal_command.size());
- std::size_t count = 0;
- do
- {
- count *= 10;
- assert(!arg.empty() && arg.front() >= '0'
- && arg.front() <= '9');
- count += arg.front() - '0';
- arg.remove_prefix(1);
- } while(!arg.empty());
- write_indent(
- [&](char ch)
- {
- os << ch;
- },
- indent_depth,
- output_tab_width);
- indent_depth = 0;
- for(std::size_t i = 0; i < count; i++)
- {
- assert(iter != value.end());
- os << *iter++;
- }
- assert(iter != value.end() && *iter == escape_char);
- ++iter;
- continue;
- }
- else
+ count *= 10;
+ assert(!arg.empty() && arg.front() >= '0'
+ && arg.front() <= '9');
+ count += arg.front() - '0';
+ arg.remove_prefix(1);
+ } while(!arg.empty());
+ write_indent(
+ [&](char ch)
{
- assert(false);
- }
- }
- switch(*iter)
+ os << ch;
+ },
+ indent_depth,
+ output_tab_width);
+ indent_depth = 0;
+ for(std::size_t i = 0; i < count; i++)
{
- case '-':
- ++iter;
- assert(start_indent_depth >= output_indent_width);
- assert(indent_depth >= output_indent_width);
- start_indent_depth -= output_indent_width;
- indent_depth -= output_indent_width;
- continue;
- case '+':
- ++iter;
- start_indent_depth += output_indent_width;
- indent_depth += output_indent_width;
- continue;
+ assert(iter != value.end());
+ os << *iter++;
}
- assert(false);
+ assert(iter != value.end() && *iter == escape_char);
+ ++iter;
continue;
}
- break;
+ else
+ {
+ assert(false);
+ }
}
+ switch(*iter)
+ {
+ case '-':
+ ++iter;
+ assert(start_indent_depth >= output_indent_width);
+ assert(indent_depth >= output_indent_width);
+ start_indent_depth -= output_indent_width;
+ indent_depth -= output_indent_width;
+ continue;
+ case '_':
+ ++iter;
+ assert(start_indent_depth >= output_indent_width);
+ start_indent_depth -= output_indent_width;
+ continue;
+ case '+':
+ ++iter;
+ start_indent_depth += output_indent_width;
+ indent_depth += output_indent_width;
+ continue;
}
- write_indent(
- [&](char ch)
- {
- os << ch;
- },
- indent_depth,
- output_tab_width);
- is_at_start_of_line = false;
- os << *iter++;
- }
- else
- {
- os << *iter++;
+ assert(false);
+ continue;
}
+ break;
}
+ }
+ write_indent(
+ [&](char ch)
+ {
+ os << ch;
+ },
+ indent_depth,
+ output_tab_width);
+ is_at_start_of_line = false;
+ os << *iter++;
}
else
{
- for(char ch : value)
- os << ch;
- }
- os.close(); // manually close to not hide error exceptions
- }
- void write_unsigned_integer(std::uint64_t value,
- unsigned base = json::ast::Number_value::default_base,
- std::size_t min_length = 1)
- {
- static_assert(std::numeric_limits<decltype(value)>::radix == 2, "");
- constexpr std::size_t buffer_size = std::numeric_limits<decltype(value)>::digits;
- char buffer[buffer_size];
- while(min_length > buffer_size)
- {
- *this << '0';
- min_length--;
+ os << *iter++;
}
- std::size_t length = json::ast::Number_value::unsigned_integer_to_buffer(
- value, buffer, buffer_size, false, base, min_length);
- *this << util::string_view(buffer, length);
}
- void write_signed_integer(std::int64_t value,
- unsigned base = json::ast::Number_value::default_base)
- {
- static_assert(std::numeric_limits<decltype(value)>::radix == 2, "");
- constexpr std::size_t buffer_size =
- std::numeric_limits<decltype(value)>::digits + 1; // one extra for sign
- char buffer[buffer_size];
- std::size_t length = json::ast::Number_value::signed_integer_to_buffer(
- value, buffer, buffer_size, false, base);
- *this << util::string_view(buffer, length);
- }
- void write_literal(util::string_view value)
- {
- *this << escape_char;
- *this << literal_command;
- write_unsigned_integer(value.size());
- *this << escape_char;
- *this << value;
- *this << escape_char;
- }
- template <typename T>
- Generated_output_stream &operator<<(T) = delete;
- Generated_output_stream &operator<<(char ch)
- {
- value.push_back(ch);
- return *this;
- }
- Generated_output_stream &operator<<(util::string_view sv)
- {
- for(char ch : sv)
- *this << ch;
- return *this;
- }
- Generated_output_stream &operator<<(const char *s)
- {
- return operator<<(util::string_view(s));
- }
- Generated_output_stream &operator<<(const std::string &s)
- {
- return operator<<(util::string_view(s));
- }
- Generated_output_stream &operator<<(std::uint64_t v)
- {
- write_unsigned_integer(v);
- return *this;
- }
- Generated_output_stream &operator<<(std::int64_t v)
- {
- write_signed_integer(v);
- return *this;
- }
- Generated_output_stream &operator<<(const ast::Copyright &v)
- {
- *this << "/*\n";
- for(auto &line : v.lines)
- {
- if(line.empty())
- {
- *this << "`*\n";
- continue;
- }
- *this << "`* ";
- bool was_last_star = false;
- for(char ch : line)
- {
- if(was_last_star && ch == '/')
- *this << ' ';
- was_last_star = (ch == '*');
- *this << ch;
- }
- *this << "\n";
- }
- *this << "`*/\n";
- return *this;
- }
- };
- struct Literal_holder
- {
- util::string_view value;
- friend Generated_output_stream &operator<<(Generated_output_stream &os,
- const Literal_holder &v)
- {
- os.write_literal(v.value);
- return os;
- }
- };
- static Literal_holder literal(util::string_view value)
- {
- return Literal_holder{value};
}
- struct Unsigned_integer_holder
- {
- std::uint64_t value;
- unsigned base;
- std::size_t min_length;
- friend Generated_output_stream &operator<<(Generated_output_stream &os,
- const Unsigned_integer_holder &v)
- {
- os.write_unsigned_integer(v.value, v.base, v.min_length);
- return os;
- }
- };
- static Unsigned_integer_holder unsigned_integer(
- std::uint64_t value,
- unsigned base = json::ast::Number_value::default_base,
- std::size_t min_length = 1)
+ else
{
- return Unsigned_integer_holder{value, base, min_length};
+ for(char ch : value)
+ os << ch;
}
- struct Signed_integer_holder
- {
- std::int64_t value;
- unsigned base;
- friend Generated_output_stream &operator<<(Generated_output_stream &os,
- const Signed_integer_holder &v)
- {
- os.write_unsigned_integer(v.value, v.base);
- return os;
- }
- };
- static Signed_integer_holder signed_integer(
- std::int64_t value, unsigned base = json::ast::Number_value::default_base)
+ os.close(); // manually close to not hide error exceptions
+}
+
+void detail::Generated_output_stream::write_unsigned_integer(std::uint64_t value,
+ unsigned base,
+ std::size_t min_length)
+{
+ static_assert(std::numeric_limits<decltype(value)>::radix == 2, "");
+ constexpr std::size_t buffer_size = std::numeric_limits<decltype(value)>::digits;
+ char buffer[buffer_size];
+ while(min_length > buffer_size)
{
- return Signed_integer_holder{value, base};
+ *this << '0';
+ min_length--;
}
- class Word_iterator
- {
- public:
- typedef std::ptrdiff_t difference_type;
- typedef util::string_view value_type;
- typedef const util::string_view &reference;
- typedef const util::string_view *pointer;
- typedef std::input_iterator_tag iterator_category;
-
- private:
- enum class Char_class
- {
- uppercase,
- other_identifier,
- word_separator
- };
- static constexpr Char_class get_char_class(char ch) noexcept
- {
- if(ch >= 'A' && ch <= 'Z')
- return Char_class::uppercase;
- if(ch >= 'a' && ch <= 'z')
- return Char_class::other_identifier;
- if(ch >= '0' && ch <= '9')
- return Char_class::other_identifier;
- return Char_class::word_separator;
- }
+ std::size_t length = json::ast::Number_value::unsigned_integer_to_buffer(
+ value, buffer, buffer_size, false, base, min_length);
+ *this << util::string_view(buffer, length);
+}
- private:
- util::string_view word;
- util::string_view words;
+void detail::Generated_output_stream::write_signed_integer(std::int64_t value, unsigned base)
+{
+ static_assert(std::numeric_limits<decltype(value)>::radix == 2, "");
+ constexpr std::size_t buffer_size =
+ std::numeric_limits<decltype(value)>::digits + 1; // one extra for sign
+ char buffer[buffer_size];
+ std::size_t length =
+ json::ast::Number_value::signed_integer_to_buffer(value, buffer, buffer_size, false, base);
+ *this << util::string_view(buffer, length);
+}
- private:
- constexpr void next() noexcept
- {
- util::optional<std::size_t> word_start;
- Char_class last_char_class = Char_class::word_separator;
- for(std::size_t i = 0; i < words.size(); i++)
- {
- auto current_char_class = get_char_class(words[i]);
- if(word_start)
- {
- switch(current_char_class)
- {
- case Char_class::word_separator:
- word = util::string_view(words.data() + *word_start, i - *word_start);
- words.remove_prefix(i);
- last_char_class = current_char_class;
- return;
- case Char_class::uppercase:
- if(last_char_class != Char_class::uppercase)
- {
- word = util::string_view(words.data() + *word_start, i - *word_start);
- words.remove_prefix(i);
- last_char_class = current_char_class;
- return;
- }
- if(i + 1 < words.size()
- && get_char_class(words[i + 1]) == Char_class::other_identifier)
- {
- word = util::string_view(words.data() + *word_start, i - *word_start);
- words.remove_prefix(i);
- last_char_class = current_char_class;
- return;
- }
- break;
- case Char_class::other_identifier:
- break;
- }
- }
- else if(current_char_class != Char_class::word_separator)
- {
- word_start = i;
- }
- last_char_class = current_char_class;
- }
- if(word_start)
- word = util::string_view(words.data() + *word_start, words.size() - *word_start);
- else
- word = {};
- words = {};
- }
- constexpr bool at_end() const noexcept
- {
- return word.empty();
- }
+detail::Generated_output_stream &detail::Generated_output_stream::operator<<(Guard_macro)
+{
+ *this << name_from_words_all_uppercase_with_trailing_underline(get_file_path().string());
+ return *this;
+}
- public:
- constexpr Word_iterator() noexcept : word(), words()
- {
- }
- constexpr explicit Word_iterator(util::string_view words) noexcept : word(), words(words)
- {
- next();
- }
- constexpr const util::string_view &operator*() const noexcept
- {
- return word;
- }
- constexpr const util::string_view *operator->() const noexcept
- {
- return &word;
- }
- constexpr Word_iterator &operator++() noexcept
- {
- next();
- return *this;
- }
- constexpr Word_iterator operator++(int) noexcept
- {
- auto retval = *this;
- next();
- return retval;
- }
- constexpr bool operator==(const Word_iterator &rt) const noexcept
- {
- return word.empty() == rt.word.empty();
- }
- constexpr bool operator!=(const Word_iterator &rt) const noexcept
- {
- return word.empty() != rt.word.empty();
- }
- constexpr Word_iterator begin() const noexcept
- {
- return *this;
- }
- constexpr Word_iterator end() const noexcept
- {
- return {};
- }
- };
- static void write_guard_macro(Generated_output_stream &os)
+std::string detail::Generated_output_stream::name_from_words_helper(Name_format name_format,
+ std::string name)
+{
+ for(char &ch : name)
+ if(ch >= 'A' && ch <= 'Z')
+ ch = ch - 'A' + 'a'; // to lowercase
+ if(name.empty() || (name[0] >= '0' && name[0] <= '9'))
+ name.insert(0, 1, '_');
+ bool has_trailing_underline = false;
+ switch(name_format)
{
- auto path_string = os.get_file_path().string();
- for(auto &word : Word_iterator(path_string))
+ case initial_capital:
+ // can't be empty because of previous insert
+ if(name[0] >= 'a' && name[0] <= 'z')
+ name[0] = name[0] - 'a' + 'A'; // to uppercase
+ break;
+ case all_uppercase_with_trailing_underline:
+ case all_uppercase:
+ if(name_format == all_uppercase_with_trailing_underline)
+ has_trailing_underline = true;
+ for(char &ch : name)
+ if(ch >= 'a' && ch <= 'z')
+ ch = ch - 'a' + 'A'; // to uppercase
+ break;
+ case all_lowercase:
+ break;
+ }
+ if(!has_trailing_underline)
+ {
+ for(auto &keyword : keywords)
{
- for(char ch : word)
+ if(name == keyword)
{
- if(ch >= 'a' && ch <= 'z')
- ch = ch - 'a' + 'A'; // to uppercase
- os << ch;
+ has_trailing_underline = true;
+ break;
}
- os << '_';
}
}
- struct Guard_macro
- {
- friend Generated_output_stream &operator<<(Generated_output_stream &os, Guard_macro)
- {
- write_guard_macro(os);
- return os;
- }
- };
- static constexpr Guard_macro guard_macro{};
+ if(has_trailing_underline)
+ name += '_';
+ return name;
+}
+
+struct Spirv_and_parser_generator : public Generator
+{
+ struct State;
+ virtual void run(Generator_args &generator_args,
+ const ast::Top_level &top_level) const override;
+};
+
+using namespace util::string_view_literals;
+
+struct Spirv_and_parser_generator::State
+{
+private:
const ast::Top_level &top_level;
- Generated_output_stream spirv_h;
- Generated_output_stream spirv_cpp;
- Generated_output_stream parser_h;
- Generated_output_stream parser_cpp;
+ detail::Generated_output_stream spirv_h;
+ detail::Generated_output_stream spirv_cpp;
+ detail::Generated_output_stream parser_h;
+ detail::Generated_output_stream parser_cpp;
+
+public:
State(const util::filesystem::path &output_directory, const ast::Top_level &top_level)
: top_level(top_level),
spirv_h(output_directory / "spirv.h"),
parser_cpp(output_directory / "parser.cpp")
{
}
- void run()
+
+private:
+ void write_file_comments()
{
constexpr auto automatically_generated_file_warning_comment =
R"(/* This file is automatically generated by generate_spirv_parser. DO NOT MODIFY. */
spirv_cpp << automatically_generated_file_warning_comment << top_level.copyright;
parser_h << automatically_generated_file_warning_comment << top_level.copyright;
parser_cpp << automatically_generated_file_warning_comment << top_level.copyright;
- spirv_h << R"(#ifndef )" << guard_macro << R"(
+ }
+ static void write_opening_inclusion_guard(detail::Generated_output_stream &os)
+ {
+ using detail::guard_macro;
+ os << R"(#ifndef )" << guard_macro << R"(
#define )" << guard_macro
- << R"(
+ << R"(
+
)";
- parser_h << R"(#ifndef )" << guard_macro << R"(
-#define )" << guard_macro
- << R"(
+ }
+ static void write_closing_inclusion_guard(detail::Generated_output_stream &os)
+ {
+ using detail::guard_macro;
+ os << R"(
+#endif /* )"
+ << guard_macro << R"( */
)";
- spirv_cpp << R"(#include ")" << spirv_h.get_file_path().filename().string() << R"("
+ }
+ void write_opening_inclusion_guards()
+ {
+ write_opening_inclusion_guard(spirv_h);
+ write_opening_inclusion_guard(parser_h);
+ }
+ void write_closing_inclusion_guards()
+ {
+ write_closing_inclusion_guard(spirv_h);
+ write_closing_inclusion_guard(parser_h);
+ }
+ static void write_local_include(detail::Generated_output_stream &os, util::string_view file)
+ {
+ os << R"(#include ")" << file << R"("
)";
- parser_h << R"(
-#include ")" << spirv_h.get_file_path().filename().string()
- << R"("
+ }
+ static void write_system_include(detail::Generated_output_stream &os, util::string_view file)
+ {
+ os << R"(#include <)" << file << R"(>
)";
- parser_cpp << R"(#include ")" << parser_h.get_file_path().filename().string() << R"("
+ }
+ void write_includes()
+ {
+ write_local_include(spirv_cpp, spirv_h.get_file_path().filename().string());
+ write_local_include(parser_h, spirv_h.get_file_path().filename().string());
+ write_local_include(parser_cpp, parser_h.get_file_path().filename().string());
+ write_system_include(spirv_h, "cstdint");
+ write_local_include(spirv_h, "util/string_view.h");
+ write_local_include(spirv_h, "util/enum.h");
+ }
+ static void write_opening_namespaces(detail::Generated_output_stream &os)
+ {
+ os << R"(
+namespace vulkan_cpu
+{
+namespace spirv
+{
)";
+ }
+ void write_opening_namespaces()
+ {
+ write_opening_namespaces(spirv_h);
+ write_opening_namespaces(spirv_cpp);
+ write_opening_namespaces(parser_h);
+ write_opening_namespaces(parser_cpp);
+ }
+ static void write_closing_namespaces(detail::Generated_output_stream &os)
+ {
+ os << R"(}
+}
+)";
+ }
+ void write_closing_namespaces()
+ {
+ write_closing_namespaces(spirv_h);
+ write_closing_namespaces(spirv_cpp);
+ write_closing_namespaces(parser_h);
+ write_closing_namespaces(parser_cpp);
+ }
+
+private:
+ static constexpr util::string_view op_enum_json_name = "Op"_sv;
+ static constexpr util::string_view extension_enum_json_name = "Extension"_sv;
+ static constexpr util::string_view capability_enum_json_name = "Capability"_sv;
+ struct Enumerant_descriptor
+ {
+ std::uint32_t value;
+ std::string cpp_name;
+ std::string json_name;
+ ast::Capabilities capabilities;
+ ast::Extensions extensions;
+ static std::string make_cpp_name(util::string_view json_enumeration_name,
+ util::string_view json_enumerant_name)
+ {
+ using detail::name_from_words_all_lowercase;
+ bool starts_with_enumeration_name = false;
+ if(json_enumerant_name.substr(0, json_enumeration_name.size()) == json_enumeration_name)
+ starts_with_enumeration_name = true;
+ bool json_name_should_have_prefix = json_enumeration_name == op_enum_json_name;
+ if(json_name_should_have_prefix)
+ {
+ if(json_enumerant_name.substr(0, json_enumeration_name.size())
+ != json_enumeration_name)
+ return name_from_words_all_lowercase(
+ json_enumeration_name, json_enumeration_name, json_enumerant_name)
+ .to_string();
+ if(json_enumerant_name.substr(json_enumeration_name.size(),
+ json_enumeration_name.size())
+ == json_enumeration_name)
+ return name_from_words_all_lowercase(json_enumeration_name, json_enumerant_name)
+ .to_string();
+ return name_from_words_all_lowercase(json_enumerant_name).to_string();
+ }
+ if(json_enumerant_name.empty())
+ throw Generate_error("json enumerant name can't be empty");
+ return name_from_words_all_lowercase(json_enumerant_name).to_string();
+ }
+ Enumerant_descriptor(std::uint32_t value,
+ util::string_view json_enumeration_name,
+ std::string json_name,
+ ast::Capabilities capabilities,
+ ast::Extensions extensions)
+ : value(value),
+ cpp_name(make_cpp_name(json_enumeration_name, json_name)),
+ json_name(std::move(json_name)),
+ capabilities(std::move(capabilities)),
+ extensions(std::move(extensions))
+ {
+ }
+ };
+ struct Enumeration_descriptor
+ {
+ bool is_bitwise;
+ std::string cpp_name;
+ std::string json_name;
+ std::list<Enumerant_descriptor> enumerants;
+ typedef std::unordered_map<std::string, std::list<Enumerant_descriptor>::const_iterator>
+ Json_name_to_enumerant_map;
+ Json_name_to_enumerant_map json_name_to_enumerant_map;
+ static Json_name_to_enumerant_map make_json_name_to_enumerant_map(
+ const std::list<Enumerant_descriptor> *enumerants)
+ {
+ Json_name_to_enumerant_map retval;
+ for(auto i = enumerants->begin(); i != enumerants->end(); ++i)
+ retval[i->json_name] = i;
+ return retval;
+ }
+ Enumeration_descriptor(bool is_bitwise,
+ std::string json_name,
+ std::list<Enumerant_descriptor> enumerants)
+ : is_bitwise(is_bitwise),
+ cpp_name(detail::name_from_words_initial_capital(json_name).to_string()),
+ json_name(std::move(json_name)),
+ enumerants(std::move(enumerants)),
+ json_name_to_enumerant_map(make_json_name_to_enumerant_map(&this->enumerants))
+ {
+ }
+ };
+
+private:
+ std::list<Enumeration_descriptor> enumerations_list;
+ std::unordered_map<std::string, std::list<Enumeration_descriptor>::const_iterator>
+ enumerations_map;
+ util::optional<std::list<Enumeration_descriptor>::const_iterator> capability_enumeration;
+ util::optional<std::list<Enumeration_descriptor>::const_iterator> extension_enumeration;
+ util::optional<std::list<Enumeration_descriptor>::const_iterator> op_enumeration;
+ std::unordered_map<std::string, std::list<Enumeration_descriptor>::const_iterator>
+ instruction_set_extension_op_enumeration_map;
+
+private:
+ std::list<Enumeration_descriptor>::const_iterator add_enumeration(
+ Enumeration_descriptor &&enumeration_descriptor)
+ {
+ auto name = enumeration_descriptor.json_name;
+ auto iter =
+ enumerations_list.insert(enumerations_list.end(), std::move(enumeration_descriptor));
+ if(!std::get<1>(enumerations_map.emplace(name, iter)))
+ throw Generate_error("duplicate enumeration: " + name);
+ return iter;
+ }
+ void fill_enumerations_helper(std::set<std::string> &extensions_set,
+ const ast::Operand_kinds::Operand_kind &ast_operand_kind)
+ {
+ auto *ast_enumerants =
+ util::get_if<ast::Operand_kinds::Operand_kind::Enumerants>(&ast_operand_kind.value);
+ if(ast_enumerants)
+ {
+ std::list<Enumerant_descriptor> enumerants;
+ for(auto &ast_enumerant : ast_enumerants->enumerants)
+ {
+ enumerants.push_back(Enumerant_descriptor(ast_enumerant.value,
+ ast_operand_kind.kind,
+ ast_enumerant.enumerant,
+ ast_enumerant.capabilities,
+ ast_enumerant.extensions));
+ for(auto &extension : ast_enumerant.extensions.extensions)
+ extensions_set.insert(extension);
+ }
+ auto iter = add_enumeration(Enumeration_descriptor(
+ ast_operand_kind.category == ast::Operand_kinds::Operand_kind::Category::bit_enum,
+ ast_operand_kind.kind,
+ std::move(enumerants)));
+ if(ast_operand_kind.kind == capability_enum_json_name)
+ {
+ if(capability_enumeration)
+ throw Generate_error("Too many " + std::string(capability_enum_json_name)
+ + " enums");
+ capability_enumeration = iter;
+ }
+ }
+ }
+ void fill_enumerations()
+ {
+ std::set<std::string> extensions_set;
+ for(auto &operand_kind : top_level.operand_kinds.operand_kinds)
+ fill_enumerations_helper(extensions_set, operand_kind);
+ std::list<Enumerant_descriptor> op_enumerants;
+ for(auto &instruction : top_level.instructions.instructions)
+ {
+ op_enumerants.push_back(Enumerant_descriptor(instruction.opcode,
+ op_enum_json_name,
+ instruction.opname,
+ instruction.capabilities,
+ instruction.extensions));
+ for(auto &extension : instruction.extensions.extensions)
+ extensions_set.insert(extension);
+ }
+ auto op_iter = add_enumeration(Enumeration_descriptor(
+ false, static_cast<std::string>(op_enum_json_name), std::move(op_enumerants)));
+ op_enumeration = op_iter;
+ for(auto &instruction_set : top_level.extension_instruction_sets)
+ {
+ std::string json_enumeration_name =
+ std::string(op_enum_json_name) + " " + instruction_set.import_name;
+ std::list<Enumerant_descriptor> enumerants;
+ for(auto &instruction : instruction_set.instructions.instructions)
+ {
+ enumerants.push_back(Enumerant_descriptor(instruction.opcode,
+ json_enumeration_name,
+ instruction.opname,
+ instruction.capabilities,
+ instruction.extensions));
+ for(auto &extension : instruction.extensions.extensions)
+ extensions_set.insert(extension);
+ }
+ auto iter = add_enumeration(
+ Enumeration_descriptor(false, json_enumeration_name, std::move(enumerants)));
+ instruction_set_extension_op_enumeration_map.emplace(instruction_set.import_name, iter);
+ }
+ std::list<Enumerant_descriptor> extension_enumerants;
+ std::uint32_t extension_index = 0;
+ for(auto &extension : extensions_set)
+ extension_enumerants.push_back(Enumerant_descriptor(
+ extension_index++, extension_enum_json_name, extension, {}, {}));
+ auto extension_iter = add_enumeration(
+ Enumeration_descriptor(false,
+ static_cast<std::string>(extension_enum_json_name),
+ std::move(extension_enumerants)));
+ extension_enumeration = extension_iter;
+ if(!capability_enumeration)
+ throw Generate_error("missing " + std::string(capability_enum_json_name) + " enum");
+ }
+ void write_basic_types()
+ {
spirv_h << R"(
-#endif /* )" << guard_macro
- << R"( */
+typedef std::uint32_t Word;
+typedef Word Id;
+)";
+ }
+ void write_enum_declarations()
+ {
+ spirv_h << "\n";
+ for(auto &enumeration : enumerations_list)
+ spirv_h << "enum class " << enumeration.cpp_name << " : Word;\n";
+ }
+ void write_enum_definitions()
+ {
+ using detail::unsigned_integer;
+ for(auto &enumeration : enumerations_list)
+ {
+ spirv_h << R"(
+enum class )" << enumeration.cpp_name
+ << R"( : Word
+{
+@+)";
+ for(auto &enumerant : enumeration.enumerants)
+ {
+ spirv_h << enumerant.cpp_name << " = ";
+ if(enumeration.is_bitwise)
+ spirv_h << "0x" << unsigned_integer(enumerant.value, 0x10);
+ else
+ spirv_h << unsigned_integer(enumerant.value, 10);
+ spirv_h << ",\n";
+ }
+ spirv_h << R"(@-};
+
+vulkan_cpu_util_generate_enum_traits()"
+ << enumeration.cpp_name;
+ for(auto &enumerant : enumeration.enumerants)
+ spirv_h << R"(,
+`````````````````````````````````````)"
+ << enumeration.cpp_name << "::" << enumerant.cpp_name;
+ spirv_h << R"();
+)";
+ }
+ }
+ const Enumerant_descriptor &get_capability(const std::string &capability)
+ {
+ auto &enumerant_map = capability_enumeration.value()->json_name_to_enumerant_map;
+ auto iter = enumerant_map.find(capability);
+ if(iter == enumerant_map.end())
+ throw Generate_error("unknown capability: " + capability);
+ return *std::get<1>(*iter);
+ }
+ const Enumerant_descriptor &get_extension(const std::string &extension)
+ {
+ auto &enumerant_map = extension_enumeration.value()->json_name_to_enumerant_map;
+ auto iter = enumerant_map.find(extension);
+ if(iter == enumerant_map.end())
+ throw Generate_error("unknown extension: " + extension);
+ return *std::get<1>(*iter);
+ }
+ void write_enum_properties_definitions()
+ {
+ for(auto &enumeration : enumerations_list)
+ {
+ spirv_h << R"(
+constexpr util::string_view get_enumerant_name()"
+ << enumeration.cpp_name << R"( v) noexcept
+{
+ using namespace util::string_view_literals;
+ switch(v)
+ {
+@+@+)";
+ std::unordered_set<std::uint32_t> values;
+ for(auto &enumerant : enumeration.enumerants)
+ {
+ if(std::get<1>(values.insert(enumerant.value)))
+ {
+ spirv_h << "case " << enumeration.cpp_name << "::" << enumerant.cpp_name << R"(:
+ return ")" << enumerant.json_name
+ << R"("_sv;
)";
- parser_h << R"(
-#endif /* )" << guard_macro
- << R"( */
+ }
+ }
+ spirv_h << R"(@-@_}
+ return ""_sv;
+}
+
+constexpr util::Enum_set<)"
+ << capability_enumeration.value()->cpp_name
+ << R"(> get_directly_required_capabilities()" << enumeration.cpp_name
+ << R"( v) noexcept
+{
+ switch(v)
+ {
+@+@+)";
+ values.clear();
+ for(auto &enumerant : enumeration.enumerants)
+ {
+ if(std::get<1>(values.insert(enumerant.value)))
+ {
+ spirv_h << "case " << enumeration.cpp_name << "::" << enumerant.cpp_name << R"(:
+ return {)";
+ auto separator = ""_sv;
+ for(auto &capability : enumerant.capabilities.capabilities)
+ {
+ spirv_h << separator;
+ separator = ", "_sv;
+ spirv_h << capability_enumeration.value()->cpp_name
+ << "::" << get_capability(capability).cpp_name;
+ }
+ spirv_h << R"(};
)";
+ }
+ }
+ spirv_h << R"(@-@_}
+ return {};
+}
+
+constexpr util::Enum_set<)"
+ << extension_enumeration.value()->cpp_name
+ << R"(> get_directly_required_extensions()" << enumeration.cpp_name
+ << R"( v) noexcept
+{
+ switch(v)
+ {
+@+@+)";
+ values.clear();
+ for(auto &enumerant : enumeration.enumerants)
+ {
+ if(std::get<1>(values.insert(enumerant.value)))
+ {
+ spirv_h << "case " << enumeration.cpp_name << "::" << enumerant.cpp_name << R"(:
+ return {)";
+ auto separator = ""_sv;
+ for(auto &extension : enumerant.extensions.extensions)
+ {
+ spirv_h << separator;
+ separator = ", "_sv;
+ spirv_h << extension_enumeration.value()->cpp_name
+ << "::" << get_extension(extension).cpp_name;
+ }
+ spirv_h << R"(};
+)";
+ }
+ }
+ spirv_h << R"(@-@_}
+ return {};
+}
+)";
+ }
+ }
+
+public:
+ void run()
+ {
+ fill_enumerations();
+ write_file_comments();
+ write_opening_inclusion_guards();
#warning finish
- spirv_h << R"(
-#error generator not finished being implemented
+ spirv_h << R"(#error generator not finished being implemented
+
)";
+ write_includes();
+ write_opening_namespaces();
+ write_basic_types();
+ write_enum_declarations();
+ write_enum_definitions();
+ write_enum_properties_definitions();
+ write_closing_namespaces();
+ write_closing_inclusion_guards();
spirv_h.write_to_file();
spirv_cpp.write_to_file();
parser_h.write_to_file();
}
};
-constexpr util::string_view
- Spirv_and_parser_generator::State::Generated_output_stream::literal_command;
+constexpr util::string_view Spirv_and_parser_generator::State::op_enum_json_name;
+constexpr util::string_view Spirv_and_parser_generator::State::extension_enum_json_name;
+constexpr util::string_view Spirv_and_parser_generator::State::capability_enum_json_name;
void Spirv_and_parser_generator::run(Generator_args &generator_args,
const ast::Top_level &top_level) const
#define GENERATE_SPIRV_PARSER_GENERATE_H_
#include "ast.h"
+#include "util/filesystem.h"
#include "util/string_view.h"
-#include <fstream>
-#include <memory>
-#include <string>
-#include <cassert>
-#include <type_traits>
-#include <cstdint>
-#include <unordered_set>
-#include <unordered_map>
-#include <vector>
+#include "word_iterator.h"
#include <stdexcept>
+#include <deque>
+#include <cstdint>
+#include <string>
+#include <utility>
namespace vulkan_cpu
{
using runtime_error::runtime_error;
};
+namespace detail
+{
+using namespace util::string_view_literals;
+
+constexpr util::string_view keywords[] = {
+ "alignas"_sv,
+ "alignof"_sv,
+ "and"_sv,
+ "and_eq"_sv,
+ "asm"_sv,
+ "atomic_cancel"_sv,
+ "atomic_commit"_sv,
+ "atomic_noexcept"_sv,
+ "auto"_sv,
+ "bitand"_sv,
+ "bitor"_sv,
+ "bool"_sv,
+ "break"_sv,
+ "case"_sv,
+ "catch"_sv,
+ "char"_sv,
+ "char16_t"_sv,
+ "char32_t"_sv,
+ "class"_sv,
+ "compl"_sv,
+ "concept"_sv,
+ "concepts"_sv,
+ "const"_sv,
+ "const_cast"_sv,
+ "constexpr"_sv,
+ "continue"_sv,
+ "decltype"_sv,
+ "default"_sv,
+ "delete"_sv,
+ "do"_sv,
+ "double"_sv,
+ "dynamic_cast"_sv,
+ "else"_sv,
+ "enum"_sv,
+ "explicit"_sv,
+ "export"_sv,
+ "extern"_sv,
+ "false"_sv,
+ "float"_sv,
+ "for"_sv,
+ "friend"_sv,
+ "goto"_sv,
+ "if"_sv,
+ "import"_sv,
+ "inline"_sv,
+ "int"_sv,
+ "long"_sv,
+ "module"_sv,
+ "modules"_sv,
+ "mutable"_sv,
+ "namespace"_sv,
+ "new"_sv,
+ "noexcept"_sv,
+ "not"_sv,
+ "not_eq"_sv,
+ "nullptr"_sv,
+ "operator"_sv,
+ "or"_sv,
+ "or_eq"_sv,
+ "private"_sv,
+ "protected"_sv,
+ "public"_sv,
+ "register"_sv,
+ "reinterpret_cast"_sv,
+ "requires"_sv,
+ "return"_sv,
+ "short"_sv,
+ "signed"_sv,
+ "sizeof"_sv,
+ "static"_sv,
+ "static_assert"_sv,
+ "static_cast"_sv,
+ "struct"_sv,
+ "switch"_sv,
+ "synchronized"_sv,
+ "template"_sv,
+ "this"_sv,
+ "thread_local"_sv,
+ "throw"_sv,
+ "true"_sv,
+ "try"_sv,
+ "typedef"_sv,
+ "typeid"_sv,
+ "typename"_sv,
+ "union"_sv,
+ "unsigned"_sv,
+ "using"_sv,
+ "virtual"_sv,
+ "void"_sv,
+ "volatile"_sv,
+ "wchar_t"_sv,
+ "while"_sv,
+ "xor"_sv,
+ "xor_eq"_sv,
+};
+
+class Generated_output_stream
+{
+private:
+ std::deque<char> value;
+ util::filesystem::path file_path;
+
+public:
+ explicit Generated_output_stream(util::filesystem::path file_path) noexcept
+ : value(),
+ file_path(std::move(file_path))
+ {
+ }
+ const util::filesystem::path &get_file_path() const noexcept
+ {
+ return file_path;
+ }
+
+private:
+ static constexpr std::size_t output_tab_width_no_tabs_allowed = 0;
+ template <typename Fn>
+ static void write_indent(Fn write_char,
+ std::size_t indent_depth,
+ std::size_t output_tab_width = output_tab_width_no_tabs_allowed)
+ {
+ if(output_tab_width != output_tab_width_no_tabs_allowed)
+ {
+ while(indent_depth >= output_tab_width)
+ {
+ indent_depth -= output_tab_width;
+ write_char('\t');
+ }
+ }
+ while(indent_depth--)
+ write_char(' ');
+ }
+ static constexpr util::string_view literal_command = "literal:"_sv;
+
+public:
+ static constexpr char indent_indicator_char = ' ';
+ static constexpr char literal_indent_indicator_char = '`';
+ static constexpr std::size_t indent_indicators_per_indent = 4;
+ static constexpr char escape_char = '@';
+ static constexpr bool indent_blank_lines = false;
+
+public:
+ void write_to_file(bool do_reindent = true) const;
+
+private:
+ void write_unsigned_integer(std::uint64_t value,
+ unsigned base = 10,
+ std::size_t min_length = 1);
+ void write_signed_integer(std::int64_t value, unsigned base = 10);
+ void write_literal(util::string_view value)
+ {
+ *this << escape_char << literal_command << value.size() << escape_char << value
+ << escape_char;
+ }
+
+public:
+ template <typename T>
+ Generated_output_stream &operator<<(T) = delete;
+ Generated_output_stream &operator<<(char ch)
+ {
+ value.push_back(ch);
+ return *this;
+ }
+ Generated_output_stream &operator<<(util::string_view sv)
+ {
+ for(char ch : sv)
+ *this << ch;
+ return *this;
+ }
+ Generated_output_stream &operator<<(const char *s)
+ {
+ return operator<<(util::string_view(s));
+ }
+ Generated_output_stream &operator<<(const std::string &s)
+ {
+ return operator<<(util::string_view(s));
+ }
+ Generated_output_stream &operator<<(std::uint64_t v)
+ {
+ write_unsigned_integer(v);
+ return *this;
+ }
+ Generated_output_stream &operator<<(std::int64_t v)
+ {
+ write_signed_integer(v);
+ return *this;
+ }
+ Generated_output_stream &operator<<(const ast::Copyright &v)
+ {
+ *this << "/*\n";
+ for(auto &line : v.lines)
+ {
+ if(line.empty())
+ {
+ *this << "`*\n";
+ continue;
+ }
+ *this << "`* ";
+ bool was_last_star = false;
+ for(char ch : line)
+ {
+ if(was_last_star && ch == '/')
+ *this << ' ';
+ was_last_star = (ch == '*');
+ *this << ch;
+ }
+ *this << "\n";
+ }
+ *this << "`*/\n";
+ return *this;
+ }
+ class Literal_holder
+ {
+ friend class Generated_output_stream;
+
+ private:
+ util::string_view value;
+ constexpr explicit Literal_holder(util::string_view value) noexcept : value(value)
+ {
+ }
+ };
+ Generated_output_stream &operator<<(const Literal_holder &v)
+ {
+ write_literal(v.value);
+ return *this;
+ }
+ static constexpr Literal_holder literal(util::string_view value) noexcept
+ {
+ return Literal_holder{value};
+ }
+ class Unsigned_integer_holder
+ {
+ friend class Generated_output_stream;
+
+ private:
+ std::uint64_t value;
+ unsigned base;
+ std::size_t min_length;
+ constexpr explicit Unsigned_integer_holder(std::uint64_t value,
+ unsigned base,
+ std::size_t min_length) noexcept
+ : value(value),
+ base(base),
+ min_length(min_length)
+ {
+ }
+ };
+ Generated_output_stream &operator<<(const Unsigned_integer_holder &v)
+ {
+ write_unsigned_integer(v.value, v.base, v.min_length);
+ return *this;
+ }
+ static constexpr Unsigned_integer_holder unsigned_integer(std::uint64_t value,
+ unsigned base = 10,
+ std::size_t min_length = 1) noexcept
+ {
+ return Unsigned_integer_holder{value, base, min_length};
+ }
+ class Signed_integer_holder
+ {
+ friend class Generated_output_stream;
+
+ private:
+ std::int64_t value;
+ unsigned base;
+ constexpr explicit Signed_integer_holder(std::int64_t value, unsigned base) noexcept
+ : value(value),
+ base(base)
+ {
+ }
+ };
+ Generated_output_stream &operator<<(const Signed_integer_holder &v)
+ {
+ write_signed_integer(v.value, v.base);
+ return *this;
+ }
+ static constexpr Signed_integer_holder signed_integer(std::int64_t value,
+ unsigned base = 10) noexcept
+ {
+ return Signed_integer_holder{value, base};
+ }
+ struct Guard_macro
+ {
+ };
+ Generated_output_stream &operator<<(Guard_macro);
+ enum Name_format
+ {
+ initial_capital,
+ all_lowercase,
+ all_uppercase,
+ all_uppercase_with_trailing_underline,
+ };
+
+private:
+ static std::string name_from_words_helper(Name_format name_format, std::string name);
+
+public:
+ template <std::size_t N>
+ class Name_from_words_holder
+ {
+ friend class Generated_output_stream;
+
+ private:
+ Name_format name_format;
+ Chained_word_iterator<N> iter;
+ template <typename... Args>
+ constexpr explicit Name_from_words_holder(
+ Name_format name_format,
+ Args &&... args) noexcept(noexcept(Chained_word_iterator<N>(std::
+ forward<Args>(
+ args)...)))
+ : name_format(name_format), iter(std::forward<Args>(args)...)
+ {
+ static_assert(sizeof...(Args) == N, "");
+ }
+
+ public:
+ std::string to_string() const
+ {
+ std::size_t name_size = 0;
+ for(const util::string_view &word : iter)
+ {
+ // don't skip first '_' to allow for trailing '_' to prevent generating keywords
+ name_size += 1 + word.size();
+ }
+ std::string name;
+ name.reserve(name_size);
+ bool first = true;
+ for(const util::string_view &word : iter)
+ {
+ if(first)
+ first = false;
+ else
+ name += '_';
+ name += word;
+ }
+ return name_from_words_helper(name_format, std::move(name));
+ }
+ };
+ template <std::size_t N>
+ Generated_output_stream &operator<<(const Name_from_words_holder<N> &v)
+ {
+ *this << v.to_string();
+ return *this;
+ }
+ template <typename... Args>
+ static constexpr Name_from_words_holder<sizeof...(Args)>
+ name_from_words(Name_format name_format, Args &&... args) noexcept(
+ noexcept(Name_from_words_holder<sizeof...(Args)>(name_format,
+ std::forward<Args>(args)...)))
+ {
+ return Name_from_words_holder<sizeof...(Args)>(name_format,
+ std::forward<Args>(args)...);
+ }
+};
+
+constexpr auto literal(util::string_view value) noexcept
+{
+ return Generated_output_stream::literal(value);
+}
+
+constexpr auto unsigned_integer(std::uint64_t value) noexcept
+{
+ return Generated_output_stream::unsigned_integer(value);
+}
+
+constexpr auto unsigned_integer(std::uint64_t value, unsigned base) noexcept
+{
+ return Generated_output_stream::unsigned_integer(value, base);
+}
+
+constexpr auto unsigned_integer(std::uint64_t value, unsigned base, std::size_t min_length) noexcept
+{
+ return Generated_output_stream::unsigned_integer(value, base, min_length);
+}
+
+constexpr auto signed_integer(std::int64_t value) noexcept
+{
+ return Generated_output_stream::signed_integer(value);
+}
+
+constexpr auto signed_integer(std::int64_t value, unsigned base) noexcept
+{
+ return Generated_output_stream::signed_integer(value, base);
+}
+
+constexpr Generated_output_stream::Guard_macro guard_macro{};
+
+template <typename... Args>
+constexpr auto name_from_words(Generated_output_stream::Name_format name_format, Args &&... args) noexcept(
+ noexcept(Generated_output_stream::name_from_words(name_format, std::forward<Args>(args)...)))
+{
+ return Generated_output_stream::name_from_words(name_format, std::forward<Args>(args)...);
+}
+
+template <typename... Args>
+constexpr auto name_from_words_all_lowercase(Args &&... args) noexcept(
+ noexcept(Generated_output_stream::name_from_words(Generated_output_stream::all_lowercase, std::forward<Args>(args)...)))
+{
+ return Generated_output_stream::name_from_words(Generated_output_stream::all_lowercase, std::forward<Args>(args)...);
+}
+
+template <typename... Args>
+constexpr auto name_from_words_all_uppercase(Args &&... args) noexcept(
+ noexcept(Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase, std::forward<Args>(args)...)))
+{
+ return Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase, std::forward<Args>(args)...);
+}
+
+template <typename... Args>
+constexpr auto name_from_words_initial_capital(Args &&... args) noexcept(
+ noexcept(Generated_output_stream::name_from_words(Generated_output_stream::initial_capital, std::forward<Args>(args)...)))
+{
+ return Generated_output_stream::name_from_words(Generated_output_stream::initial_capital, std::forward<Args>(args)...);
+}
+
+template <typename... Args>
+constexpr auto name_from_words_all_uppercase_with_trailing_underline(Args &&... args) noexcept(
+ noexcept(Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase_with_trailing_underline, std::forward<Args>(args)...)))
+{
+ return Generated_output_stream::name_from_words(Generated_output_stream::all_uppercase_with_trailing_underline, std::forward<Args>(args)...);
+}
+}
+
struct Generator
{
struct Generator_args
--- /dev/null
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * 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.
+ *
+ */
+
+#ifndef GENERATE_SPIRV_PARSER_WORD_ITERATOR_H_
+#define GENERATE_SPIRV_PARSER_WORD_ITERATOR_H_
+
+#include "util/string_view.h"
+#include "util/optional.h"
+#include <iterator>
+
+namespace vulkan_cpu
+{
+namespace generate_spirv_parser
+{
+namespace generate
+{
+class Word_iterator
+{
+public:
+ typedef std::ptrdiff_t difference_type;
+ typedef util::string_view value_type;
+ typedef const util::string_view &reference;
+ typedef const util::string_view *pointer;
+ typedef std::input_iterator_tag iterator_category;
+
+private:
+ enum class Char_class
+ {
+ uppercase,
+ number,
+ other_identifier,
+ word_separator
+ };
+ static constexpr Char_class get_char_class(char ch) noexcept
+ {
+ if(ch >= 'A' && ch <= 'Z')
+ return Char_class::uppercase;
+ if(ch >= 'a' && ch <= 'z')
+ return Char_class::other_identifier;
+ if(ch >= '0' && ch <= '9')
+ return Char_class::number;
+ return Char_class::word_separator;
+ }
+
+private:
+ util::string_view word;
+ util::string_view words;
+
+private:
+ constexpr void next() noexcept
+ {
+ util::optional<std::size_t> word_start;
+ Char_class last_char_class = Char_class::word_separator;
+ for(std::size_t i = 0; i < words.size(); i++)
+ {
+ auto current_char_class = get_char_class(words[i]);
+ if(word_start)
+ {
+ switch(current_char_class)
+ {
+ case Char_class::word_separator:
+ word = util::string_view(words.data() + *word_start, i - *word_start);
+ words.remove_prefix(i);
+ return;
+ case Char_class::uppercase:
+ if(last_char_class != Char_class::uppercase
+ && last_char_class != Char_class::number)
+ {
+ word = util::string_view(words.data() + *word_start, i - *word_start);
+ words.remove_prefix(i);
+ return;
+ }
+ if(i + 1 < words.size()
+ && get_char_class(words[i + 1]) == Char_class::other_identifier)
+ {
+ word = util::string_view(words.data() + *word_start, i - *word_start);
+ words.remove_prefix(i);
+ return;
+ }
+ break;
+ case Char_class::other_identifier:
+ case Char_class::number:
+ break;
+ }
+ }
+ else if(current_char_class != Char_class::word_separator)
+ {
+ word_start = i;
+ }
+ last_char_class = current_char_class;
+ }
+ if(word_start)
+ word = util::string_view(words.data() + *word_start, words.size() - *word_start);
+ else
+ word = {};
+ words = {};
+ }
+ constexpr bool at_end() const noexcept
+ {
+ return word.empty();
+ }
+
+public:
+ constexpr Word_iterator() noexcept : word(), words()
+ {
+ }
+ constexpr explicit Word_iterator(util::string_view words) noexcept : word(), words(words)
+ {
+ next();
+ }
+ constexpr const util::string_view &operator*() const noexcept
+ {
+ return word;
+ }
+ constexpr const util::string_view *operator->() const noexcept
+ {
+ return &word;
+ }
+ constexpr Word_iterator &operator++() noexcept
+ {
+ next();
+ return *this;
+ }
+ constexpr Word_iterator operator++(int) noexcept
+ {
+ auto retval = *this;
+ next();
+ return retval;
+ }
+ constexpr bool operator==(const Word_iterator &rt) const noexcept
+ {
+ return word.empty() == rt.word.empty();
+ }
+ constexpr bool operator!=(const Word_iterator &rt) const noexcept
+ {
+ return word.empty() != rt.word.empty();
+ }
+ constexpr Word_iterator begin() const noexcept
+ {
+ return *this;
+ }
+ constexpr Word_iterator end() const noexcept
+ {
+ return {};
+ }
+};
+
+template <std::size_t Iterator_count>
+class Chained_word_iterator
+{
+public:
+ typedef std::ptrdiff_t difference_type;
+ typedef util::string_view value_type;
+ typedef const util::string_view &reference;
+ typedef const util::string_view *pointer;
+ typedef std::input_iterator_tag iterator_category;
+
+private:
+ Word_iterator iterators[Iterator_count];
+ std::size_t current_iterator_index;
+
+private:
+ template <bool... Values>
+ static constexpr bool variadic_and() noexcept
+ {
+ for(bool v : {Values...})
+ if(!v)
+ return false;
+ return true;
+ }
+ static constexpr util::string_view to_string_view_helper(util::string_view v) noexcept
+ {
+ return v;
+ }
+ constexpr bool at_end() const noexcept
+ {
+ return current_iterator_index == Iterator_count;
+ }
+ constexpr void next() noexcept
+ {
+ assert(current_iterator_index < Iterator_count);
+ ++iterators[current_iterator_index];
+ while(iterators[current_iterator_index] == Word_iterator())
+ if(++current_iterator_index == Iterator_count)
+ return;
+ }
+
+public:
+ constexpr Chained_word_iterator() noexcept : iterators{}, current_iterator_index(Iterator_count)
+ {
+ }
+ template <typename... Args>
+ constexpr explicit Chained_word_iterator(Args &&... args) noexcept(
+ variadic_and<noexcept(to_string_view_helper(std::forward<Args>(args)))...>())
+ : iterators{Word_iterator(to_string_view_helper(std::forward<Args>(args)))...},
+ current_iterator_index(0)
+ {
+ }
+ constexpr const util::string_view &operator*() const noexcept
+ {
+ assert(current_iterator_index < Iterator_count);
+ return *iterators[current_iterator_index];
+ }
+ constexpr const util::string_view *operator->() const noexcept
+ {
+ return &operator*();
+ }
+ constexpr Chained_word_iterator &operator++() noexcept
+ {
+ next();
+ return *this;
+ }
+ constexpr Chained_word_iterator operator++(int) noexcept
+ {
+ auto retval = *this;
+ next();
+ return retval;
+ }
+ constexpr bool operator==(const Chained_word_iterator &rt) const noexcept
+ {
+ return at_end() == rt.at_end();
+ }
+ constexpr bool operator!=(const Chained_word_iterator &rt) const noexcept
+ {
+ return at_end() != rt.at_end();
+ }
+ constexpr Chained_word_iterator begin() const noexcept
+ {
+ return *this;
+ }
+ constexpr Chained_word_iterator end() const noexcept
+ {
+ return {};
+ }
+};
+
+template <typename... Args>
+constexpr Chained_word_iterator<sizeof...(Args)>
+ make_chained_word_iterator(Args &&... args) noexcept(
+ noexcept(Chained_word_iterator<sizeof...(Args)>(std::forward<Args>(args)...)))
+{
+ return Chained_word_iterator<sizeof...(Args)>(std::forward<Args>(args)...);
+}
+}
+}
+}
+
+#endif /* GENERATE_SPIRV_PARSER_WORD_ITERATOR_H_ */