http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/d709f67d/depends/thirdparty/thrift/compiler/cpp/src/generate/t_erl_generator.cc ---------------------------------------------------------------------- diff --git a/depends/thirdparty/thrift/compiler/cpp/src/generate/t_erl_generator.cc b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_erl_generator.cc new file mode 100644 index 0000000..c066636 --- /dev/null +++ b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_erl_generator.cc @@ -0,0 +1,1044 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <string> +#include <fstream> +#include <iostream> +#include <vector> + +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sstream> +#include "t_generator.h" +#include "platform.h" +#include "version.h" + +using std::map; +using std::ofstream; +using std::ostream; +using std::ostringstream; +using std::string; +using std::stringstream; +using std::vector; + +static const std::string endl = "\n"; // avoid ostream << std::endl flushes + +/** + * Erlang code generator. + * + */ +class t_erl_generator : public t_generator { +public: + t_erl_generator(t_program* program, + const std::map<std::string, std::string>& parsed_options, + const std::string& option_string) + : t_generator(program) { + (void)parsed_options; + (void)option_string; + out_dir_base_ = "gen-erl"; + + legacy_names_ = (parsed_options.find("legacynames") != parsed_options.end()); + maps_ = (parsed_options.find("maps") != parsed_options.end()); + otp16_ = (parsed_options.find("otp16") != parsed_options.end()); + if (maps_ && otp16_) { + throw "argument error: Cannot specify both maps and otp16; maps are not available for Erlang/OTP R16 or older"; + } + } + + /** + * Init and close methods + */ + + void init_generator(); + void close_generator(); + + /** + * Program-level generation functions + */ + + void generate_typedef(t_typedef* ttypedef); + void generate_enum(t_enum* tenum); + void generate_const(t_const* tconst); + void generate_struct(t_struct* tstruct); + void generate_xception(t_struct* txception); + void generate_service(t_service* tservice); + void generate_member_type(std::ostream& out, t_type* type); + void generate_member_value(std::ostream& out, t_type* type, t_const_value* value); + + std::string render_member_type(t_field* field); + std::string render_member_value(t_field* field); + std::string render_member_requiredness(t_field* field); + + // std::string render_default_value(t_type* type); + std::string render_default_value(t_field* field); + std::string render_const_value(t_type* type, t_const_value* value); + std::string render_type_term(t_type* ttype, bool expand_structs, bool extended_info = false); + + /** + * Struct generation code + */ + + void generate_erl_struct(t_struct* tstruct, bool is_exception); + void generate_erl_struct_definition(std::ostream& out, t_struct* tstruct); + void generate_erl_struct_member(std::ostream& out, t_field* tmember); + void generate_erl_struct_info(std::ostream& out, t_struct* tstruct); + void generate_erl_extended_struct_info(std::ostream& out, t_struct* tstruct); + void generate_erl_function_helpers(t_function* tfunction); + + /** + * Service-level generation functions + */ + + void generate_service_helpers(t_service* tservice); + void generate_service_interface(t_service* tservice); + void generate_function_info(t_service* tservice, t_function* tfunction); + + /** + * Helper rendering functions + */ + + std::string erl_autogen_comment(); + std::string erl_imports(); + std::string render_includes(); + std::string type_name(t_type* ttype); + + std::string function_signature(t_function* tfunction, std::string prefix = ""); + + std::string argument_list(t_struct* tstruct); + std::string type_to_enum(t_type* ttype); + std::string type_module(t_type* ttype); + + std::string make_safe_for_module_name(std::string in) { + if (legacy_names_) { + return decapitalize(in); + } else { + return underscore(in); + } + } + + std::string atomify(std::string in) { + if (legacy_names_) { + return "'" + decapitalize(in) + "'"; + } else { + return "'" + in + "'"; + } + } + + std::string constify(std::string in) { + if (legacy_names_) { + return capitalize(in); + } else { + return uppercase(in); + } + } + + static std::string comment(string in); + +private: + bool has_default_value(t_field*); + + /* if true retain pre 0.9.2 naming scheme for functions, atoms and consts */ + bool legacy_names_; + + /* if true use maps instead of dicts in generated code */ + bool maps_; + + /* if true use non-namespaced dict and set instead of dict:dict and sets:set */ + bool otp16_; + + /** + * add function to export list + */ + + void export_function(t_function* tfunction, std::string prefix = ""); + void export_string(std::string name, int num); + + void export_types_function(t_function* tfunction, std::string prefix = ""); + void export_types_string(std::string name, int num); + + /** + * write out headers and footers for hrl files + */ + + void hrl_header(std::ostream& out, std::string name); + void hrl_footer(std::ostream& out, std::string name); + + /** + * stuff to spit out at the top of generated files + */ + + bool export_lines_first_; + std::ostringstream export_lines_; + + bool export_types_lines_first_; + std::ostringstream export_types_lines_; + + /** + * File streams + */ + + std::ostringstream f_info_; + std::ostringstream f_info_ext_; + + std::ofstream f_types_file_; + std::ofstream f_types_hrl_file_; + + std::ofstream f_consts_; + std::ostringstream f_service_; + std::ofstream f_service_file_; + std::ofstream f_service_hrl_; +}; + +/** + * UI for file generation by opening up the necessary file output + * streams. + * + * @param tprogram The program to generate + */ +void t_erl_generator::init_generator() { + // Make output directory + MKDIR(get_out_dir().c_str()); + + // setup export lines + export_lines_first_ = true; + export_types_lines_first_ = true; + + // types files + string f_types_name = get_out_dir() + make_safe_for_module_name(program_name_) + "_types.erl"; + string f_types_hrl_name = get_out_dir() + make_safe_for_module_name(program_name_) + "_types.hrl"; + + f_types_file_.open(f_types_name.c_str()); + f_types_hrl_file_.open(f_types_hrl_name.c_str()); + + hrl_header(f_types_hrl_file_, make_safe_for_module_name(program_name_) + "_types"); + + f_types_file_ << erl_autogen_comment() << endl << "-module(" + << make_safe_for_module_name(program_name_) << "_types)." << endl << erl_imports() + << endl; + + f_types_file_ << "-include(\"" << make_safe_for_module_name(program_name_) << "_types.hrl\")." + << endl << endl; + + f_types_hrl_file_ << render_includes() << endl; + + // consts file + string f_consts_name = get_out_dir() + make_safe_for_module_name(program_name_) + + "_constants.hrl"; + f_consts_.open(f_consts_name.c_str()); + + f_consts_ << erl_autogen_comment() << endl << erl_imports() << endl << "-include(\"" + << make_safe_for_module_name(program_name_) << "_types.hrl\")." << endl << endl; +} + +/** + * Boilerplate at beginning and end of header files + */ +void t_erl_generator::hrl_header(ostream& out, string name) { + out << "-ifndef(_" << name << "_included)." << endl << "-define(_" << name << "_included, yeah)." + << endl; +} + +void t_erl_generator::hrl_footer(ostream& out, string name) { + (void)name; + out << "-endif." << endl; +} + +/** + * Renders all the imports necessary for including another Thrift program + */ +string t_erl_generator::render_includes() { + const vector<t_program*>& includes = program_->get_includes(); + string result = ""; + for (size_t i = 0; i < includes.size(); ++i) { + result += "-include(\"" + make_safe_for_module_name(includes[i]->get_name()) + + "_types.hrl\").\n"; + } + if (includes.size() > 0) { + result += "\n"; + } + return result; +} + +/** + * Autogen'd comment + */ +string t_erl_generator::erl_autogen_comment() { + return std::string("%%\n") + "%% Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + + "%%\n" + "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + + "%%\n"; +} + +/** + * Comment out text + */ + +string t_erl_generator::comment(string in) { + size_t pos = 0; + in.insert(pos, "%% "); + while ((pos = in.find_first_of('\n', pos)) != string::npos) { + in.insert(++pos, "%% "); + } + return in; +} + +/** + * Prints standard thrift imports + */ +string t_erl_generator::erl_imports() { + return ""; +} + +/** + * Closes the type files + */ +void t_erl_generator::close_generator() { + + export_types_string("struct_info", 1); + export_types_string("struct_info_ext", 1); + f_types_file_ << "-export([" << export_types_lines_.str() << "])." << endl << endl; + + f_types_file_ << f_info_.str(); + f_types_file_ << "struct_info(_) -> erlang:error(function_clause)." << endl << endl; + + f_types_file_ << f_info_ext_.str(); + f_types_file_ << "struct_info_ext(_) -> erlang:error(function_clause)." << endl << endl; + + hrl_footer(f_types_hrl_file_, string("BOGUS")); + + f_types_file_.close(); + f_types_hrl_file_.close(); + f_consts_.close(); +} + +/** + * Generates a typedef. no op + * + * @param ttypedef The type definition + */ +void t_erl_generator::generate_typedef(t_typedef* ttypedef) { + (void)ttypedef; +} + +/** + * Generates code for an enumerated type. Done using a class to scope + * the values. + * + * @param tenum The enumeration + */ +void t_erl_generator::generate_enum(t_enum* tenum) { + vector<t_enum_value*> constants = tenum->get_constants(); + vector<t_enum_value*>::iterator c_iter; + + for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { + int value = (*c_iter)->get_value(); + string name = (*c_iter)->get_name(); + indent(f_types_hrl_file_) << "-define(" << constify(make_safe_for_module_name(program_name_)) + << "_" << constify(tenum->get_name()) << "_" << constify(name) << ", " + << value << ")." << endl; + } + + f_types_hrl_file_ << endl; +} + +/** + * Generate a constant value + */ +void t_erl_generator::generate_const(t_const* tconst) { + t_type* type = tconst->get_type(); + string name = tconst->get_name(); + t_const_value* value = tconst->get_value(); + + f_consts_ << "-define(" << constify(make_safe_for_module_name(program_name_)) << "_" + << constify(name) << ", " << render_const_value(type, value) << ")." << endl << endl; +} + +/** + * Prints the value of a constant with the given type. Note that type checking + * is NOT performed in this function as it is always run beforehand using the + * validate_types method in main.cc + */ +string t_erl_generator::render_const_value(t_type* type, t_const_value* value) { + type = get_true_type(type); + std::ostringstream out; + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + out << '"' << get_escaped_string(value) << '"'; + break; + case t_base_type::TYPE_BOOL: + out << (value->get_integer() > 0 ? "true" : "false"); + break; + case t_base_type::TYPE_BYTE: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + out << value->get_integer(); + break; + case t_base_type::TYPE_DOUBLE: + if (value->get_type() == t_const_value::CV_INTEGER) { + out << value->get_integer(); + } else { + out << value->get_double(); + } + break; + default: + throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + indent(out) << value->get_integer(); + + } else if (type->is_struct() || type->is_xception()) { + out << "#" << atomify(type->get_name()) << "{"; + const vector<t_field*>& fields = ((t_struct*)type)->get_members(); + vector<t_field*>::const_iterator f_iter; + const map<t_const_value*, t_const_value*>& val = value->get_map(); + map<t_const_value*, t_const_value*>::const_iterator v_iter; + + bool first = true; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + t_type* field_type = NULL; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if ((*f_iter)->get_name() == v_iter->first->get_string()) { + field_type = (*f_iter)->get_type(); + } + } + if (field_type == NULL) { + throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); + } + + if (first) { + first = false; + } else { + out << ","; + } + out << v_iter->first->get_string(); + out << " = "; + out << render_const_value(field_type, v_iter->second); + } + indent_down(); + indent(out) << "}"; + + } else if (type->is_map()) { + t_type* ktype = ((t_map*)type)->get_key_type(); + t_type* vtype = ((t_map*)type)->get_val_type(); + + if (maps_) { + out << "maps:from_list(["; + } else { + out << "dict:from_list(["; + } + map<t_const_value*, t_const_value*>::const_iterator i, end = value->get_map().end(); + for (i = value->get_map().begin(); i != end;) { + out << "{" << render_const_value(ktype, i->first) << "," + << render_const_value(vtype, i->second) << "}"; + if (++i != end) { + out << ","; + } + } + out << "])"; + } else if (type->is_set()) { + t_type* etype = ((t_set*)type)->get_elem_type(); + out << "sets:from_list(["; + vector<t_const_value*>::const_iterator i, end = value->get_list().end(); + for (i = value->get_list().begin(); i != end;) { + out << render_const_value(etype, *i); + if (++i != end) { + out << ","; + } + } + out << "])"; + } else if (type->is_list()) { + t_type* etype; + etype = ((t_list*)type)->get_elem_type(); + out << "["; + + bool first = true; + const vector<t_const_value*>& val = value->get_list(); + vector<t_const_value*>::const_iterator v_iter; + for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { + if (first) { + first = false; + } else { + out << ","; + } + out << render_const_value(etype, *v_iter); + } + out << "]"; + } else { + throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name(); + } + return out.str(); +} + +string t_erl_generator::render_default_value(t_field* field) { + t_type* type = field->get_type(); + if (type->is_struct() || type->is_xception()) { + return "#" + atomify(type->get_name()) + "{}"; + } else if (type->is_map()) { + if (maps_) { + return "#{}"; + } else { + return "dict:new()"; + } + } else if (type->is_set()) { + return "sets:new()"; + } else if (type->is_list()) { + return "[]"; + } else { + return "undefined"; + } +} + +string t_erl_generator::render_member_type(t_field* field) { + t_type* type = get_true_type(field->get_type()); + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_STRING: + return "string() | binary()"; + case t_base_type::TYPE_BOOL: + return "boolean()"; + case t_base_type::TYPE_BYTE: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + case t_base_type::TYPE_I64: + return "integer()"; + case t_base_type::TYPE_DOUBLE: + return "float()"; + default: + throw "compiler error: unsupported base type " + t_base_type::t_base_name(tbase); + } + } else if (type->is_enum()) { + return "integer()"; + } else if (type->is_struct() || type->is_xception()) { + return atomify(type->get_name()) + "()"; + } else if (type->is_map()) { + if (maps_) { + return "#{}"; + } else if (otp16_) { + return "dict()"; + } else { + return "dict:dict()"; + } + } else if (type->is_set()) { + if (otp16_) { + return "set()"; + } else { + return "sets:set()"; + } + } else if (type->is_list()) { + return "list()"; + } else { + throw "compiler error: unsupported type " + type->get_name(); + } +} + +string t_erl_generator::render_member_requiredness(t_field* field) { + switch (field->get_req()) { + case t_field::T_REQUIRED: + return "required"; + case t_field::T_OPTIONAL: + return "optional"; + default: + return "undefined"; + } +} + +/** + * Generates a struct + */ +void t_erl_generator::generate_struct(t_struct* tstruct) { + generate_erl_struct(tstruct, false); +} + +/** + * Generates a struct definition for a thrift exception. Basically the same + * as a struct but extends the Exception class. + * + * @param txception The struct definition + */ +void t_erl_generator::generate_xception(t_struct* txception) { + generate_erl_struct(txception, true); +} + +/** + * Generates a struct + */ +void t_erl_generator::generate_erl_struct(t_struct* tstruct, bool is_exception) { + (void)is_exception; + generate_erl_struct_definition(f_types_hrl_file_, tstruct); + generate_erl_struct_info(f_info_, tstruct); + generate_erl_extended_struct_info(f_info_ext_, tstruct); +} + +/** + * Generates a struct definition for a thrift data type. + * + * @param tstruct The struct definition + */ +void t_erl_generator::generate_erl_struct_definition(ostream& out, t_struct* tstruct) { + indent(out) << "%% struct " << type_name(tstruct) << endl << endl; + + std::stringstream buf; + buf << indent() << "-record(" << type_name(tstruct) << ", {"; + string field_indent(buf.str().size(), ' '); + + const vector<t_field*>& members = tstruct->get_members(); + for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();) { + generate_erl_struct_member(buf, *m_iter); + if (++m_iter != members.end()) { + buf << "," << endl << field_indent; + } + } + buf << "})."; + + out << buf.str() << endl; + out << "-type " + type_name(tstruct) << "() :: #" + type_name(tstruct) + "{}." << endl << endl; +} + +/** + * Generates the record field definition + */ + +void t_erl_generator::generate_erl_struct_member(ostream& out, t_field* tmember) { + out << atomify(tmember->get_name()); + if (has_default_value(tmember)) + out << " = " << render_member_value(tmember); + out << " :: " << render_member_type(tmember); +} + +bool t_erl_generator::has_default_value(t_field* field) { + t_type* type = field->get_type(); + if (!field->get_value()) { + if (field->get_req() == t_field::T_REQUIRED) { + if (type->is_struct() || type->is_xception() || type->is_map() || type->is_set() + || type->is_list()) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return true; + } +} + +string t_erl_generator::render_member_value(t_field* field) { + if (!field->get_value()) { + return render_default_value(field); + } else { + return render_const_value(field->get_type(), field->get_value()); + } +} + +/** + * Generates the read method for a struct + */ +void t_erl_generator::generate_erl_struct_info(ostream& out, t_struct* tstruct) { + indent(out) << "struct_info(" << type_name(tstruct) << ") ->" << endl; + indent_up(); + out << indent() << render_type_term(tstruct, true) << ";" << endl; + indent_down(); + out << endl; +} + +void t_erl_generator::generate_erl_extended_struct_info(ostream& out, t_struct* tstruct) { + indent(out) << "struct_info_ext(" << type_name(tstruct) << ") ->" << endl; + indent_up(); + out << indent() << render_type_term(tstruct, true, true) << ";" << endl; + indent_down(); + out << endl; +} + +/** + * Generates a thrift service. + * + * @param tservice The service definition + */ +void t_erl_generator::generate_service(t_service* tservice) { + service_name_ = make_safe_for_module_name(service_name_); + + string f_service_hrl_name = get_out_dir() + service_name_ + "_thrift.hrl"; + string f_service_name = get_out_dir() + service_name_ + "_thrift.erl"; + f_service_file_.open(f_service_name.c_str()); + f_service_hrl_.open(f_service_hrl_name.c_str()); + + // Reset service text aggregating stream streams + f_service_.str(""); + export_lines_.str(""); + export_lines_first_ = true; + + hrl_header(f_service_hrl_, service_name_); + + if (tservice->get_extends() != NULL) { + f_service_hrl_ << "-include(\"" + << make_safe_for_module_name(tservice->get_extends()->get_name()) + << "_thrift.hrl\"). % inherit " << endl; + } + + f_service_hrl_ << "-include(\"" << make_safe_for_module_name(program_name_) << "_types.hrl\")." + << endl << endl; + + // Generate the three main parts of the service (well, two for now in PHP) + generate_service_helpers(tservice); // cpiro: New Erlang Order + + generate_service_interface(tservice); + + // indent_down(); + + f_service_file_ << erl_autogen_comment() << endl << "-module(" << service_name_ << "_thrift)." + << endl << "-behaviour(thrift_service)." << endl << endl << erl_imports() << endl; + + f_service_file_ << "-include(\"" << make_safe_for_module_name(tservice->get_name()) + << "_thrift.hrl\")." << endl << endl; + + f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl; + + f_service_file_ << f_service_.str(); + + hrl_footer(f_service_hrl_, f_service_name); + + // Close service file + f_service_file_.close(); + f_service_hrl_.close(); +} + +/** + * Generates helper functions for a service. + * + * @param tservice The service to generate a header definition for + */ +void t_erl_generator::generate_service_helpers(t_service* tservice) { + vector<t_function*> functions = tservice->get_functions(); + vector<t_function*>::iterator f_iter; + + // indent(f_service_) << + // "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl; + + export_string("struct_info", 1); + + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_erl_function_helpers(*f_iter); + } + f_service_ << "struct_info(_) -> erlang:error(function_clause)." << endl; +} + +/** + * Generates a struct and helpers for a function. + * + * @param tfunction The function + */ +void t_erl_generator::generate_erl_function_helpers(t_function* tfunction) { + (void)tfunction; +} + +/** + * Generates a service interface definition. + * + * @param tservice The service to generate a header definition for + */ +void t_erl_generator::generate_service_interface(t_service* tservice) { + + export_string("function_info", 2); + + vector<t_function*> functions = tservice->get_functions(); + vector<t_function*>::iterator f_iter; + f_service_ << "%%% interface" << endl; + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + f_service_ << indent() << "% " << function_signature(*f_iter) << endl; + + generate_function_info(tservice, *f_iter); + } + + // Inheritance - pass unknown functions to base class + if (tservice->get_extends() != NULL) { + indent(f_service_) << "function_info(Function, InfoType) ->" << endl; + indent_up(); + indent(f_service_) << make_safe_for_module_name(tservice->get_extends()->get_name()) + << "_thrift:function_info(Function, InfoType)." << endl; + indent_down(); + } else { + // return function_clause error for non-existent functions + indent(f_service_) << "function_info(_Func, _Info) -> erlang:error(function_clause)." << endl; + } + + indent(f_service_) << endl; +} + +/** + * Generates a function_info(FunctionName, params_type) and + * function_info(FunctionName, reply_type) + */ +void t_erl_generator::generate_function_info(t_service* tservice, t_function* tfunction) { + (void)tservice; + string name_atom = atomify(tfunction->get_name()); + + t_struct* xs = tfunction->get_xceptions(); + t_struct* arg_struct = tfunction->get_arglist(); + + // function_info(Function, params_type): + indent(f_service_) << "function_info(" << name_atom << ", params_type) ->" << endl; + indent_up(); + + indent(f_service_) << render_type_term(arg_struct, true) << ";" << endl; + + indent_down(); + + // function_info(Function, reply_type): + indent(f_service_) << "function_info(" << name_atom << ", reply_type) ->" << endl; + indent_up(); + + if (!tfunction->get_returntype()->is_void()) + indent(f_service_) << render_type_term(tfunction->get_returntype(), false) << ";" << endl; + else if (tfunction->is_oneway()) + indent(f_service_) << "oneway_void;" << endl; + else + indent(f_service_) << "{struct, []}" + << ";" << endl; + indent_down(); + + // function_info(Function, exceptions): + indent(f_service_) << "function_info(" << name_atom << ", exceptions) ->" << endl; + indent_up(); + indent(f_service_) << render_type_term(xs, true) << ";" << endl; + indent_down(); +} + +/** + * Renders a function signature of the form 'type name(args)' + * + * @param tfunction Function definition + * @return String of rendered function definition + */ +string t_erl_generator::function_signature(t_function* tfunction, string prefix) { + return prefix + tfunction->get_name() + "(This" + + capitalize(argument_list(tfunction->get_arglist())) + ")"; +} + +/** + * Add a function to the exports list + */ +void t_erl_generator::export_string(string name, int num) { + if (export_lines_first_) { + export_lines_first_ = false; + } else { + export_lines_ << ", "; + } + export_lines_ << name << "/" << num; +} + +void t_erl_generator::export_types_function(t_function* tfunction, string prefix) { + + export_types_string(prefix + tfunction->get_name(), + 1 // This + + ((tfunction->get_arglist())->get_members()).size()); +} + +void t_erl_generator::export_types_string(string name, int num) { + if (export_types_lines_first_) { + export_types_lines_first_ = false; + } else { + export_types_lines_ << ", "; + } + export_types_lines_ << name << "/" << num; +} + +void t_erl_generator::export_function(t_function* tfunction, string prefix) { + + export_string(prefix + tfunction->get_name(), + 1 // This + + ((tfunction->get_arglist())->get_members()).size()); +} + +/** + * Renders a field list + */ +string t_erl_generator::argument_list(t_struct* tstruct) { + string result = ""; + + const vector<t_field*>& fields = tstruct->get_members(); + vector<t_field*>::const_iterator f_iter; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + result += ", "; // initial comma to compensate for initial This + } else { + result += ", "; + } + result += capitalize((*f_iter)->get_name()); + } + return result; +} + +string t_erl_generator::type_name(t_type* ttype) { + string prefix = ""; + string name = ttype->get_name(); + + if (ttype->is_struct() || ttype->is_xception() || ttype->is_service()) { + name = ttype->get_name(); + } + + return atomify(prefix + name); +} + +/** + * Converts the parse type to a Erlang "type" (macro for int constants) + */ +string t_erl_generator::type_to_enum(t_type* type) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "?tType_STRING"; + case t_base_type::TYPE_BOOL: + return "?tType_BOOL"; + case t_base_type::TYPE_BYTE: + return "?tType_BYTE"; + case t_base_type::TYPE_I16: + return "?tType_I16"; + case t_base_type::TYPE_I32: + return "?tType_I32"; + case t_base_type::TYPE_I64: + return "?tType_I64"; + case t_base_type::TYPE_DOUBLE: + return "?tType_DOUBLE"; + } + } else if (type->is_enum()) { + return "?tType_I32"; + } else if (type->is_struct() || type->is_xception()) { + return "?tType_STRUCT"; + } else if (type->is_map()) { + return "?tType_MAP"; + } else if (type->is_set()) { + return "?tType_SET"; + } else if (type->is_list()) { + return "?tType_LIST"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +/** + * Generate an Erlang term which represents a thrift type + */ +std::string t_erl_generator::render_type_term(t_type* type, + bool expand_structs, + bool extended_info) { + type = get_true_type(type); + + if (type->is_base_type()) { + t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); + switch (tbase) { + case t_base_type::TYPE_VOID: + throw "NO T_VOID CONSTRUCT"; + case t_base_type::TYPE_STRING: + return "string"; + case t_base_type::TYPE_BOOL: + return "bool"; + case t_base_type::TYPE_BYTE: + return "byte"; + case t_base_type::TYPE_I16: + return "i16"; + case t_base_type::TYPE_I32: + return "i32"; + case t_base_type::TYPE_I64: + return "i64"; + case t_base_type::TYPE_DOUBLE: + return "double"; + } + } else if (type->is_enum()) { + return "i32"; + } else if (type->is_struct() || type->is_xception()) { + if (expand_structs) { + + std::stringstream buf; + buf << "{struct, ["; + string field_indent(buf.str().size(), ' '); + + t_struct::members_type const& fields = static_cast<t_struct*>(type)->get_members(); + t_struct::members_type::const_iterator i, end = fields.end(); + for (i = fields.begin(); i != end;) { + t_struct::members_type::value_type member = *i; + int32_t key = member->get_key(); + string type = render_type_term(member->get_type(), false, false); // recursive call + + if (!extended_info) { + // Convert to format: {struct, [{Fid, Type}|...]} + buf << "{" << key << ", " << type << "}"; + } else { + // Convert to format: {struct, [{Fid, Req, Type, Name, Def}|...]} + string name = member->get_name(); + string value = render_member_value(member); + string requiredness = render_member_requiredness(member); + buf << "{" << key << ", " << requiredness << ", " << type << ", " << atomify(name) << ", " + << value << "}"; + } + + if (++i != end) { + buf << "," << endl << field_indent; + } + } + + buf << "]}" << endl; + return buf.str(); + } else { + return "{struct, {" + atomify(type_module(type)) + ", " + type_name(type) + "}}"; + } + } else if (type->is_map()) { + // {map, KeyType, ValType} + t_type* key_type = ((t_map*)type)->get_key_type(); + t_type* val_type = ((t_map*)type)->get_val_type(); + + return "{map, " + render_type_term(key_type, false) + ", " + render_type_term(val_type, false) + + "}"; + + } else if (type->is_set()) { + t_type* elem_type = ((t_set*)type)->get_elem_type(); + + return "{set, " + render_type_term(elem_type, false) + "}"; + + } else if (type->is_list()) { + t_type* elem_type = ((t_list*)type)->get_elem_type(); + + return "{list, " + render_type_term(elem_type, false) + "}"; + } + + throw "INVALID TYPE IN type_to_enum: " + type->get_name(); +} + +std::string t_erl_generator::type_module(t_type* ttype) { + return make_safe_for_module_name(ttype->get_program()->get_name()) + "_types"; +} + +THRIFT_REGISTER_GENERATOR( + erl, + "Erlang", + " legacynames: Output files retain naming conventions of Thrift 0.9.1 and earlier.\n" + " maps: Generate maps instead of dicts.\n" + " otp16: Generate non-namespaced dict and set instead of dict:dict and sets:set.\n")
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/d709f67d/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator.cc ---------------------------------------------------------------------- diff --git a/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator.cc b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator.cc new file mode 100644 index 0000000..e7760d7 --- /dev/null +++ b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator.cc @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "t_generator.h" +using namespace std; + +/** + * Top level program generation function. Calls the generator subclass methods + * for preparing file streams etc. then iterates over all the parts of the + * program to perform the correct actions. + * + * @param program The thrift program to compile into C++ source + */ +void t_generator::generate_program() { + // Initialize the generator + init_generator(); + + // Generate enums + vector<t_enum*> enums = program_->get_enums(); + vector<t_enum*>::iterator en_iter; + for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { + generate_enum(*en_iter); + } + + // Generate typedefs + vector<t_typedef*> typedefs = program_->get_typedefs(); + vector<t_typedef*>::iterator td_iter; + for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { + generate_typedef(*td_iter); + } + + // Generate structs, exceptions, and unions in declared order + vector<t_struct*> objects = program_->get_objects(); + + vector<t_struct*>::iterator o_iter; + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + generate_forward_declaration(*o_iter); + } + for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) { + if ((*o_iter)->is_xception()) { + generate_xception(*o_iter); + } else { + generate_struct(*o_iter); + } + } + + // Generate constants + vector<t_const*> consts = program_->get_consts(); + generate_consts(consts); + + // Generate services + vector<t_service*> services = program_->get_services(); + vector<t_service*>::iterator sv_iter; + for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { + service_name_ = get_service_name(*sv_iter); + generate_service(*sv_iter); + } + + // Close the generator + close_generator(); +} + +string t_generator::escape_string(const string& in) const { + string result = ""; + for (string::const_iterator it = in.begin(); it < in.end(); it++) { + std::map<char, std::string>::const_iterator res = escape_.find(*it); + if (res != escape_.end()) { + result.append(res->second); + } else { + result.push_back(*it); + } + } + return result; +} + +void t_generator::generate_consts(vector<t_const*> consts) { + vector<t_const*>::iterator c_iter; + for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { + generate_const(*c_iter); + } +} + +void t_generator::generate_docstring_comment(ostream& out, + const string& comment_start, + const string& line_prefix, + const string& contents, + const string& comment_end) { + if (comment_start != "") + indent(out) << comment_start; + stringstream docs(contents, ios_base::in); + while (!(docs.eof() || docs.fail())) { + char line[1024]; + docs.getline(line, 1024); + + // Just prnt a newline when the line & prefix are empty. + if (strlen(line) == 0 && line_prefix == "" && !docs.eof()) { + out << std::endl; + } else if (strlen(line) > 0 || !docs.eof()) { // skip the empty last line + indent(out) << line_prefix << line << std::endl; + } + } + if (comment_end != "") + indent(out) << comment_end; +} + +void t_generator_registry::register_generator(t_generator_factory* factory) { + gen_map_t& the_map = get_generator_map(); + if (the_map.find(factory->get_short_name()) != the_map.end()) { + failure("Duplicate generators for language \"%s\"!\n", factory->get_short_name().c_str()); + } + the_map[factory->get_short_name()] = factory; +} + +t_generator* t_generator_registry::get_generator(t_program* program, const string& options) { + string::size_type colon = options.find(':'); + string language = options.substr(0, colon); + + map<string, string> parsed_options; + if (colon != string::npos) { + string::size_type pos = colon + 1; + while (pos != string::npos && pos < options.size()) { + string::size_type next_pos = options.find(',', pos); + string option = options.substr(pos, next_pos - pos); + pos = ((next_pos == string::npos) ? next_pos : next_pos + 1); + + string::size_type separator = option.find('='); + string key, value; + if (separator == string::npos) { + key = option; + value = ""; + } else { + key = option.substr(0, separator); + value = option.substr(separator + 1); + } + + parsed_options[key] = value; + } + } + + gen_map_t& the_map = get_generator_map(); + gen_map_t::iterator iter = the_map.find(language); + + if (iter == the_map.end()) { + return NULL; + } + + return iter->second->get_generator(program, parsed_options, options); +} + +t_generator_registry::gen_map_t& t_generator_registry::get_generator_map() { + // http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 + static gen_map_t* the_map = new gen_map_t(); + return *the_map; +} + +t_generator_factory::t_generator_factory(const std::string& short_name, + const std::string& long_name, + const std::string& documentation) + : short_name_(short_name), long_name_(long_name), documentation_(documentation) { + t_generator_registry::register_generator(this); +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/d709f67d/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator.h ---------------------------------------------------------------------- diff --git a/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator.h b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator.h new file mode 100644 index 0000000..99d878a --- /dev/null +++ b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator.h @@ -0,0 +1,285 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_GENERATOR_H +#define T_GENERATOR_H + +#include <string> +#include <iostream> +#include <fstream> +#include <sstream> +#include "parse/t_program.h" +#include "globals.h" +#include "t_generator_registry.h" + +/** + * Base class for a thrift code generator. This class defines the basic + * routines for code generation and contains the top level method that + * dispatches code generation across various components. + * + */ +class t_generator { +public: + t_generator(t_program* program) { + tmp_ = 0; + indent_ = 0; + program_ = program; + program_name_ = get_program_name(program); + escape_['\n'] = "\\n"; + escape_['\r'] = "\\r"; + escape_['\t'] = "\\t"; + escape_['"'] = "\\\""; + escape_['\\'] = "\\\\"; + } + + virtual ~t_generator() {} + + /** + * Framework generator method that iterates over all the parts of a program + * and performs general actions. This is implemented by the base class and + * should not normally be overwritten in the subclasses. + */ + virtual void generate_program(); + + const t_program* get_program() const { return program_; } + + void generate_docstring_comment(std::ostream& out, + const std::string& comment_start, + const std::string& line_prefix, + const std::string& contents, + const std::string& comment_end); + + /** + * check whether sub-namespace declaraction is used by generator. + * e.g. allow + * namespace py.twisted bar + * to specify namespace to use when -gen py:twisted is specified. + * Will be called with subnamespace, i.e. is_valid_namespace("twisted") + * will be called for the above example. + */ + static bool is_valid_namespace(const std::string& sub_namespace) { + (void)sub_namespace; + return false; + } + + /** + * Escape string to use one in generated sources. + */ + virtual std::string escape_string(const std::string& in) const; + + std::string get_escaped_string(t_const_value* constval) { + return escape_string(constval->get_string()); + } + +protected: + /** + * Optional methods that may be imlemented by subclasses to take necessary + * steps at the beginning or end of code generation. + */ + + virtual void init_generator() {} + virtual void close_generator() {} + + virtual void generate_consts(std::vector<t_const*> consts); + + /** + * Pure virtual methods implemented by the generator subclasses. + */ + + virtual void generate_typedef(t_typedef* ttypedef) = 0; + virtual void generate_enum(t_enum* tenum) = 0; + virtual void generate_const(t_const* tconst) { (void)tconst; } + virtual void generate_struct(t_struct* tstruct) = 0; + virtual void generate_service(t_service* tservice) = 0; + virtual void generate_forward_declaration(t_struct*) {} + virtual void generate_xception(t_struct* txception) { + // By default exceptions are the same as structs + generate_struct(txception); + } + + /** + * Method to get the program name, may be overridden + */ + virtual std::string get_program_name(t_program* tprogram) { return tprogram->get_name(); } + + /** + * Method to get the service name, may be overridden + */ + virtual std::string get_service_name(t_service* tservice) { return tservice->get_name(); } + + /** + * Get the current output directory + */ + virtual std::string get_out_dir() const { + if (program_->is_out_path_absolute()) { + return program_->get_out_path() + "/"; + } + + return program_->get_out_path() + out_dir_base_ + "/"; + } + + /** + * Creates a unique temporary variable name, which is just "name" with a + * number appended to it (i.e. name35) + */ + std::string tmp(std::string name) { + std::ostringstream out; + out << name << tmp_++; + return out.str(); + } + + /** + * Indentation level modifiers + */ + + void indent_up() { ++indent_; } + + void indent_down() { --indent_; } + + /** + * Indentation print function + */ + std::string indent() { + std::string ind = ""; + int i; + for (i = 0; i < indent_; ++i) { + ind += " "; + } + return ind; + } + + /** + * Indentation utility wrapper + */ + std::ostream& indent(std::ostream& os) { return os << indent(); } + + /** + * Capitalization helpers + */ + std::string capitalize(std::string in) { + in[0] = toupper(in[0]); + return in; + } + std::string decapitalize(std::string in) { + in[0] = tolower(in[0]); + return in; + } + static std::string lowercase(std::string in) { + for (size_t i = 0; i < in.size(); ++i) { + in[i] = tolower(in[i]); + } + return in; + } + static std::string uppercase(std::string in) { + for (size_t i = 0; i < in.size(); ++i) { + in[i] = toupper(in[i]); + } + return in; + } + /** + * Transforms a camel case string to an equivalent one separated by underscores + * e.g. aMultiWord -> a_multi_word + * someName -> some_name + * CamelCase -> camel_case + * name -> name + * Name -> name + */ + std::string underscore(std::string in) { + in[0] = tolower(in[0]); + for (size_t i = 1; i < in.size(); ++i) { + if (isupper(in[i])) { + in[i] = tolower(in[i]); + in.insert(i, "_"); + } + } + return in; + } + /** + * Transforms a string with words separated by underscores to a camel case equivalent + * e.g. a_multi_word -> aMultiWord + * some_name -> someName + * name -> name + */ + std::string camelcase(std::string in) { + std::ostringstream out; + bool underscore = false; + + for (size_t i = 0; i < in.size(); i++) { + if (in[i] == '_') { + underscore = true; + continue; + } + if (underscore) { + out << (char)toupper(in[i]); + underscore = false; + continue; + } + out << in[i]; + } + + return out.str(); + } + +public: + /** + * Get the true type behind a series of typedefs. + */ + static t_type* get_true_type(t_type* type) { return type->get_true_type(); } + +protected: + /** + * The program being generated + */ + t_program* program_; + + /** + * Quick accessor for formatted program name that is currently being + * generated. + */ + std::string program_name_; + + /** + * Quick accessor for formatted service name that is currently being + * generated. + */ + std::string service_name_; + + /** + * Output type-specifc directory name ("gen-*") + */ + std::string out_dir_base_; + + /** + * Map of characters to escape in string literals. + */ + std::map<char, std::string> escape_; + +private: + /** + * Current code indentation level + */ + int indent_; + + /** + * Temporary variable counter, for making unique variable names + */ + int tmp_; +}; + +#endif http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/d709f67d/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator_registry.h ---------------------------------------------------------------------- diff --git a/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator_registry.h b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator_registry.h new file mode 100644 index 0000000..a852385 --- /dev/null +++ b/depends/thirdparty/thrift/compiler/cpp/src/generate/t_generator_registry.h @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef T_GENERATOR_REGISTRY_H +#define T_GENERATOR_REGISTRY_H + +class t_generator; + +/** + * A factory for producing generator classes of a particular language. + * + * This class is also responsible for: + * - Registering itself with the generator registry. + * - Providing documentation for the generators it produces. + */ +class t_generator_factory { +public: + t_generator_factory(const std::string& short_name, + const std::string& long_name, + const std::string& documentation); + + virtual ~t_generator_factory() {} + + virtual t_generator* get_generator( + // The program to generate. + t_program* program, + // Note: parsed_options will not exist beyond the call to get_generator. + const std::map<std::string, std::string>& parsed_options, + // Note: option_string might not exist beyond the call to get_generator. + const std::string& option_string) = 0; + + virtual bool is_valid_namespace(const std::string& sub_namespace) = 0; + + std::string get_short_name() { return short_name_; } + std::string get_long_name() { return long_name_; } + std::string get_documentation() { return documentation_; } + +private: + std::string short_name_; + std::string long_name_; + std::string documentation_; +}; + +template <typename generator> +class t_generator_factory_impl : public t_generator_factory { +public: + t_generator_factory_impl(const std::string& short_name, + const std::string& long_name, + const std::string& documentation) + : t_generator_factory(short_name, long_name, documentation) {} + + virtual t_generator* get_generator(t_program* program, + const std::map<std::string, std::string>& parsed_options, + const std::string& option_string) { + return new generator(program, parsed_options, option_string); + } + + virtual bool is_valid_namespace(const std::string& sub_namespace) { + return generator::is_valid_namespace(sub_namespace); + } +}; + +class t_generator_registry { +public: + static void register_generator(t_generator_factory* factory); + + static t_generator* get_generator(t_program* program, const std::string& options); + + typedef std::map<std::string, t_generator_factory*> gen_map_t; + static gen_map_t& get_generator_map(); + +private: + t_generator_registry(); + t_generator_registry(const t_generator_registry&); +}; + +#define THRIFT_REGISTER_GENERATOR(language, long_name, doc) \ + class t_##language##_generator_factory_impl \ + : public t_generator_factory_impl<t_##language##_generator> { \ + public: \ + t_##language##_generator_factory_impl() \ + : t_generator_factory_impl<t_##language##_generator>(#language, long_name, doc) {} \ + }; \ + static t_##language##_generator_factory_impl _registerer; + +#endif
