diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2015-04-16 22:07:29 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2015-04-17 17:20:25 +0200 |
commit | 6c8cd11dad10587e5dde9ab7706384927b961bb6 (patch) | |
tree | 83df2371191ee2dea8ba2154ef538b91d38089ed /src/codegen.hpp | |
parent | bb018683c93673679bb54b63c8aff43f507948de (diff) | |
download | solar-6c8cd11dad10587e5dde9ab7706384927b961bb6.tar solar-6c8cd11dad10587e5dde9ab7706384927b961bb6.zip |
Completely refactor code generation
Diffstat (limited to 'src/codegen.hpp')
-rw-r--r-- | src/codegen.hpp | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/codegen.hpp b/src/codegen.hpp new file mode 100644 index 0000000..7dbfd77 --- /dev/null +++ b/src/codegen.hpp @@ -0,0 +1,219 @@ +/* + Copyright (c) 2013-2015, Matthias Schiffer <mschiffer@universe-factory.net> + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include <cstdio> +#include <memory> +#include <sstream> +#include <string> +#include <vector> + +namespace solar { + +class nocopy_t { +private: + nocopy_t(const nocopy_t &o) = delete; + nocopy_t(nocopy_t &&o) = delete; + nocopy_t & operator=(const nocopy_t &o) = delete; + nocopy_t & operator=(nocopy_t &&o) = delete; + +protected: + nocopy_t() {} +}; + +class codegen_t : private nocopy_t { +public: + struct variable_t { + std::string str; + std::string name; + + + variable_t(const std::pair<std::string, std::string> &value, bool func = false) : str(value.first), name(value.second) { + if (!func) { + char last = str[str.length()-1]; + if (last != '*' && last != '&') + str += ' '; + + str += name; + } + } + }; + + struct function_t { + variable_t type_name; + std::vector<variable_t> args; + + void add_arg(const std::pair<std::string, std::string> &value, bool func = false) { + args.emplace_back(value, func); + } + + void add_arg(const std::string &str, const std::string &name, bool func = false) { + add_arg(std::make_pair(str, name), func); + } + + function_t(const std::string &type, const std::string &name) : type_name({type + ' ' + name, name}, true) {} + }; + +private: + FILE *file; + unsigned level; + + + template<typename... Args> void open_block(Args ...args) { + write_line(args..., " {"); + level++; + } + + template<typename... Args> void close_block(Args ...args) { + level--; + write_line("}", args...); + } + + + static void handle_arg(std::ostringstream *s, bool is_call, const variable_t &var) { + if (is_call) + *s << var.name; + else + *s << var.str; + } + + static void handle_arg(std::ostringstream *s, bool is_call, const std::vector<variable_t> &vars) { + bool first = true; + for (const variable_t &var : vars) { + if (!first) + *s << ", "; + + handle_arg(s, is_call, var); + first = false; + } + } + + static void handle_arg(std::ostringstream *s, bool is_call, const function_t &f) { + handle_arg(s, is_call, f.type_name); + + *s << "("; + + if (f.args.empty() && !is_call) + *s << "void"; + else + handle_arg(s, is_call, f.args); + + *s << ")"; + } + + template<typename T> static void handle_arg(std::ostringstream *s, __attribute__((unused)) bool is_call, T arg) { + *s << arg; + } + + static void handle_args(__attribute__((unused)) std::ostringstream *s, __attribute__((unused)) bool is_call) { + } + + template<typename T, typename... Args> static void handle_args(std::ostringstream *s, bool is_call, T arg, Args ...args) { + handle_arg(s, is_call, arg); + handle_args(s, is_call, args...); + } + + template<typename... Args> void write_offset(int offset, Args ...args) { + for (int i = 0; i < int(level) + offset; i++) + std::fputc('\t', file); + + std::fputs(combine(args...).c_str(), file); + } + + void write_line_offset(__attribute__((unused)) int offset) { + std::fputs("\n", file); + } + + template<typename... Args> void write_line_offset(int offset, Args ...args) { + write_offset(offset, args..., "\n"); + } + +public: + class block_t : private nocopy_t { + private: + codegen_t *codegen; + std::string close_string; + + public: + template<typename... Args> block_t(codegen_t *codegen0, Args ...args) : codegen(codegen0) { + codegen->open_block(args...); + } + + template<typename... Args> void close(Args ...args) { + close_string = combine(args...); + } + + template<typename... Args> void close_(Args ...args) { + close(args..., ";"); + } + + ~block_t() { + codegen->close_block(close_string); + } + }; + + codegen_t(const char *filename); + ~codegen_t(); + + template<typename... Args> static std::string combine(Args ...args) { + std::ostringstream s; + handle_args(&s, false, args...); + return s.str(); + } + + template<typename... Args> static std::string call(Args ...args) { + std::ostringstream s; + handle_args(&s, true, args...); + return s.str(); + } + + template<typename... Args> void write_line(Args ...args) { + write_line_offset(0, args...); + } + + template<typename... Args> void write_line_(Args ...args) { + write_line(args..., ";"); + } + + template<typename... Args> void _write_line(Args ...args) { + write_line_offset(1, args...); + } + + template<typename... Args> void _write_line_(Args ...args) { + write_line_offset(1, args..., ";"); + } + + template<typename... Args> void write_case(Args ...args) { + write_line_offset(-1, "case ", args..., ":"); + } + + template<typename... Args> void write_default() { + write_line_offset(-1, "default:"); + } +}; + +} |