working on refactoring generate_spirv_parser
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 30 Jun 2017 12:29:40 +0000 (05:29 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 30 Jun 2017 12:29:40 +0000 (05:29 -0700)
src/generate_spirv_parser/generate.cpp
src/generate_spirv_parser/generate.h
src/generate_spirv_parser/parser.cpp
src/generate_spirv_parser/word_iterator.h [new file with mode: 0644]

index 5ca92b397ab6106b4c93c032cf67c66552c7eb85..c1a05c606833cc8b1ecf5e78ce49b25934f9f15e 100644 (file)
  */
 #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
 {
@@ -38,515 +37,270 @@ namespace generate_spirv_parser
 {
 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"),
@@ -555,7 +309,9 @@ struct Spirv_and_parser_generator::State
           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. */
@@ -564,34 +320,435 @@ struct Spirv_and_parser_generator::State
         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();
@@ -599,8 +756,9 @@ struct Spirv_and_parser_generator::State
     }
 };
 
-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
index 7e9ffddeaa6c4a4a103e4f6cfef7cc71fe74eac6..34aa3dcbfdde13be4c19a355ebabe27a221ed569 100644 (file)
 #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
 {
@@ -48,6 +45,434 @@ struct Generate_error : public std::runtime_error
     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
index f48eb1eccad53a1c9571d673262dee6fb1c7c267..3a928b4bfdfd55d1a0919b28bbf88ab70754a84c 100644 (file)
@@ -750,7 +750,7 @@ ast::Extension_instruction_set parse_extension_instruction_set(json::ast::Value
               file_name.size() - file_name_suffix.size(), file_name_suffix.size(), file_name_suffix)
               != 0)
         throw Parse_error(top_level_value.location, {}, "file name is unrecognizable");
-    auto instruction_set_name = std::move(file_name);
+    auto instruction_set_name = file_name;
     instruction_set_name.erase(instruction_set_name.size() - file_name_suffix.size(), file_name_suffix.size());
     instruction_set_name.erase(0, file_name_prefix.size());
     if(top_level_value.get_value_kind() != json::ast::Value_kind::object)
@@ -786,9 +786,9 @@ ast::Extension_instruction_set parse_extension_instruction_set(json::ast::Value
             throw Parse_error(entry_value.location, path_builder.path(), "unknown key");
         }
     }
-    return ast::Extension_instruction_set(
+    auto retval = ast::Extension_instruction_set(
         std::move(instruction_set_name),
-        std::move(import_name),
+        import_name,
         get_value_or_throw_parse_error(
             std::move(copyright), top_level_value.location, nullptr, "missing copyright"),
         get_value_or_throw_parse_error(
@@ -797,6 +797,8 @@ ast::Extension_instruction_set parse_extension_instruction_set(json::ast::Value
             revision, top_level_value.location, nullptr, "missing revision"),
         get_value_or_throw_parse_error(
             std::move(instructions), top_level_value.location, nullptr, "missing instructions"));
+    std::cerr << "Parsed extension instruction set: " << import_name << " from " << file_name << std::endl;
+    return retval;
 }
 }
 
diff --git a/src/generate_spirv_parser/word_iterator.h b/src/generate_spirv_parser/word_iterator.h
new file mode 100644 (file)
index 0000000..0e98c0d
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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_ */