| /* |
| * 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. |
| * |
| * Contains some contributions under the Thrift Software License. |
| * Please see doc/old-thrift-license.txt in the Thrift distribution for |
| * details. |
| */ |
| |
| #include <cassert> |
| |
| #include <string> |
| #include <fstream> |
| #include <iostream> |
| #include <vector> |
| #include <list> |
| |
| #include <stdlib.h> |
| #include <sys/stat.h> |
| #include <sstream> |
| #include <cctype> |
| |
| #include "thrift/platform.h" |
| #include "thrift/generate/t_oop_generator.h" |
| |
| #ifdef _WIN32 |
| #include <locale> |
| #include <codecvt> |
| #include <combaseapi.h> |
| #include <guiddef.h> |
| #endif |
| |
| using std::map; |
| using std::ofstream; |
| using std::ostream; |
| using std::ostringstream; |
| using std::string; |
| using std::stringstream; |
| using std::vector; |
| |
| static const string endl = "\n"; // avoid ostream << std::endl flushes |
| |
| class t_delphi_generator : public t_oop_generator { |
| public: |
| t_delphi_generator(t_program* program, |
| const std::map<std::string, std::string>& parsed_options, |
| const std::string& option_string) |
| : t_oop_generator(program) { |
| (void)option_string; |
| indent_impl_ = 0; |
| has_forward = false; |
| has_enum = false; |
| has_const = false; |
| std::map<std::string, std::string>::const_iterator iter; |
| |
| ansistr_binary_ = false; |
| register_types_ = false; |
| constprefix_ = false; |
| events_ = false; |
| xmldoc_ = false; |
| async_ = false; |
| for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { |
| if( iter->first.compare("ansistr_binary") == 0) { |
| ansistr_binary_ = true; |
| } else if( iter->first.compare("register_types") == 0) { |
| register_types_ = true; |
| } else if( iter->first.compare("constprefix") == 0) { |
| constprefix_ = true; |
| } else if( iter->first.compare("events") == 0) { |
| events_ = true; |
| } else if( iter->first.compare("xmldoc") == 0) { |
| xmldoc_ = true; |
| } else if( iter->first.compare("async") == 0) { |
| async_ = true; |
| } else { |
| throw "unknown option delphi:" + iter->first; |
| } |
| } |
| |
| out_dir_base_ = "gen-delphi"; |
| escape_.clear(); |
| escape_['\''] = "''"; |
| } |
| |
| void init_generator() override; |
| void close_generator() override; |
| |
| void generate_consts(std::vector<t_const*> consts) override; |
| |
| void generate_typedef(t_typedef* ttypedef) override; |
| void generate_enum(t_enum* tenum) override; |
| void generate_forward_declaration(t_struct* tstruct) override; |
| void generate_struct(t_struct* tstruct) override; |
| void generate_xception(t_struct* txception) override; |
| void generate_service(t_service* tservice) override; |
| void generate_property(ostream& out, t_field* tfield, bool isPublic, bool is_xception); |
| void generate_property_writer_(ostream& out, t_field* tfield, bool isPublic); |
| |
| void generate_delphi_property(ostream& out, |
| bool struct_is_exception, |
| t_field* tfield, |
| bool isPublic, |
| std::string fieldPrefix = ""); |
| void generate_delphi_isset_reader_writer_definition(ostream& out, t_field* tfield, bool is_xception); |
| void generate_delphi_property_reader_definition(ostream& out, |
| t_field* tfield, |
| bool is_xception_class); |
| void generate_delphi_property_writer_definition(ostream& out, |
| t_field* tfield, |
| bool is_xception_class); |
| void generate_delphi_property_reader_impl(ostream& out, |
| std::string cls_prefix, |
| std::string name, |
| t_type* type, |
| t_field* tfield, |
| std::string fieldPrefix, |
| bool is_xception_class); |
| void generate_delphi_property_writer_impl(ostream& out, |
| std::string cls_prefix, |
| std::string name, |
| t_type* type, |
| t_field* tfield, |
| std::string fieldPrefix, |
| bool is_xception_class, |
| bool is_union, |
| bool is_xception_factory, |
| std::string xception_factory_name); |
| void generate_delphi_clear_union_value(ostream& out, |
| std::string cls_prefix, |
| std::string name, |
| t_type* type, |
| t_field* tfield, |
| std::string fieldPrefix, |
| bool is_xception_class, |
| bool is_union, |
| bool is_xception_factory, |
| std::string xception_factory_name); |
| void generate_delphi_isset_reader_writer_impl(ostream& out, |
| std::string cls_prefix, |
| std::string name, |
| t_type* type, |
| t_field* tfield, |
| std::string fieldPrefix, |
| bool is_xception); |
| void generate_delphi_struct_writer_impl(ostream& out, |
| std::string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_x_factory); |
| void generate_delphi_struct_result_writer_impl(ostream& out, |
| std::string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_x_factory); |
| |
| void generate_delphi_struct_tostring_impl(ostream& out, |
| std::string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_x_factory); |
| |
| void add_delphi_uses_list(string unitname); |
| |
| void generate_delphi_struct_reader_impl(ostream& out, |
| std::string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_x_factory); |
| void generate_delphi_create_exception_impl(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception); |
| |
| bool const_needs_var(t_type* type); |
| void print_const_prop(std::ostream& out, string name, t_type* type, t_const_value* value); |
| void print_private_field(std::ostream& out, string name, t_type* type, t_const_value* value); |
| void print_const_value(std::ostream& vars, |
| std::ostream& out, |
| std::string name, |
| t_type* type, |
| t_const_value* value); |
| void initialize_field(std::ostream& vars, |
| std::ostream& out, |
| std::string name, |
| t_type* type, |
| t_const_value* value); |
| void finalize_field(std::ostream& out, |
| std::string name, |
| t_type* type, |
| t_const_value* value, |
| std::string cls_nm = ""); |
| std::string render_const_value(std::ostream& local_vars, |
| std::ostream& out, |
| std::string name, |
| t_type* type, |
| t_const_value* value); |
| void print_const_def_value(std::ostream& vars, |
| std::ostream& out, |
| std::string name, |
| t_type* type, |
| t_const_value* value, |
| std::string cls_nm = ""); |
| std::string make_constants_classname(); |
| |
| void generate_delphi_struct(t_struct* tstruct, bool is_exception); |
| void generate_delphi_struct_impl(ostream& out, |
| std::string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_result = false, |
| bool is_x_factory = false); |
| void print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct); |
| void generate_delphi_struct_type_factory(ostream& out, |
| std::string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_result = false, |
| bool is_x_factory = false); |
| void generate_delphi_struct_type_factory_registration(ostream& out, |
| std::string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_result = false, |
| bool is_x_factory = false); |
| void generate_delphi_struct_definition(std::ostream& out, |
| t_struct* tstruct, |
| bool is_xception = false, |
| bool in_class = false, |
| bool is_result = false, |
| bool is_x_factory = false); |
| void generate_delphi_struct_reader(std::ostream& out, t_struct* tstruct); |
| void generate_delphi_struct_result_writer(std::ostream& out, t_struct* tstruct); |
| void generate_delphi_struct_writer(std::ostream& out, t_struct* tstruct); |
| void generate_delphi_struct_tostring(std::ostream& out, t_struct* tstruct); |
| |
| void generate_function_helpers(t_function* tfunction); |
| void generate_service_interface(t_service* tservice); |
| void generate_service_interface(t_service* tservice, bool for_async); |
| void generate_guid(std::ostream& out); |
| void generate_service_helpers(t_service* tservice); |
| void generate_service_client(t_service* tservice); |
| void generate_service_server(t_service* tservice); |
| void generate_process_function(t_service* tservice, t_function* function); |
| |
| void generate_deserialize_field(std::ostream& out, |
| bool is_xception, |
| t_field* tfield, |
| std::string prefix, |
| std::ostream& local_vars); |
| void generate_deserialize_struct(std::ostream& out, |
| t_struct* tstruct, |
| std::string name, |
| std::string prefix); |
| void generate_deserialize_container(ostream& out, |
| bool is_xception, |
| t_type* ttype, |
| string name, |
| std::ostream& local_vars); |
| |
| void generate_deserialize_set_element(std::ostream& out, |
| bool is_xception, |
| t_set* tset, |
| std::string prefix, |
| std::ostream& local_vars); |
| void generate_deserialize_map_element(std::ostream& out, |
| bool is_xception, |
| t_map* tmap, |
| std::string prefix, |
| std::ostream& local_vars); |
| void generate_deserialize_list_element(std::ostream& out, |
| bool is_xception, |
| t_list* list, |
| std::string prefix, |
| std::ostream& local_vars); |
| |
| void generate_serialize_field(std::ostream& out, |
| bool is_xception, |
| t_field* tfield, |
| std::string prefix, |
| std::ostream& local_vars); |
| void generate_serialize_struct(std::ostream& out, |
| t_struct* tstruct, |
| std::string prefix, |
| std::ostream& local_vars); |
| void generate_serialize_container(std::ostream& out, |
| bool is_xception, |
| t_type* ttype, |
| std::string prefix, |
| std::ostream& local_vars); |
| void generate_serialize_map_element(std::ostream& out, |
| bool is_xception, |
| t_map* tmap, |
| std::string iter, |
| std::string map, |
| std::ostream& local_vars); |
| void generate_serialize_set_element(std::ostream& out, |
| bool is_xception, |
| t_set* tmap, |
| std::string iter, |
| std::ostream& local_vars); |
| void generate_serialize_list_element(std::ostream& out, |
| bool is_xception, |
| t_list* tlist, |
| std::string iter, |
| std::ostream& local_vars); |
| |
| void delphi_type_usings(std::ostream& out); |
| std::string delphi_thrift_usings(); |
| |
| std::string type_name(t_type* ttype, |
| bool b_cls = false, |
| bool b_no_postfix = false, |
| bool b_exception_factory = false, |
| bool b_full_exception_factory = false); |
| std::string normalize_clsnm(std::string name, |
| std::string prefix, |
| bool b_no_check_keyword = false); |
| std::string make_valid_delphi_identifier(std::string const& fromName); |
| std::string make_pascal_string_literal( std::string value); |
| std::string input_arg_prefix(t_type* ttype); |
| |
| std::string base_type_name(t_base_type* tbase); |
| std::string declare_field(t_field* tfield, |
| bool init = false, |
| std::string prefix = "", |
| bool is_xception_class = false); |
| std::string function_signature(t_function* tfunction, |
| bool for_async, |
| std::string full_cls = "", |
| bool is_xception = false); |
| std::string argument_list(t_struct* tstruct); |
| std::string constructor_argument_list(t_struct* tstruct, std::string current_indent); |
| std::string type_to_enum(t_type* ttype); |
| std::string prop_name(t_field* tfield, bool is_xception = false); |
| std::string prop_name(std::string name, bool is_xception = false); |
| std::string constructor_param_name(string name); |
| |
| void write_enum(std::string line); |
| void write_forward_decr(std::string line); |
| void write_const(std::string line); |
| void write_struct(std::string line); |
| void write_service(std::string line); |
| |
| std::string autogen_comment() override { |
| 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"; |
| } |
| |
| string replace_all(string contents, string search, string replace); |
| string xml_encode(string contents); |
| string xmldoc_encode(string contents); |
| string xmlattrib_encode(string contents); |
| void generate_delphi_doc(std::ostream& out, t_field* field); |
| void generate_delphi_doc(std::ostream& out, t_doc* tdoc); |
| void generate_delphi_doc(std::ostream& out, t_function* tdoc); |
| void generate_delphi_docstring_comment(std::ostream& out, string contents); |
| |
| bool type_can_be_null(t_type* ttype) { |
| while (ttype->is_typedef()) { |
| ttype = ((t_typedef*)ttype)->get_type(); |
| } |
| |
| return ttype->is_container() || ttype->is_struct() || ttype->is_xception(); |
| } |
| |
| private: |
| std::string namespace_name_; |
| std::ostringstream s_forward_decr; |
| std::ostringstream s_enum; |
| std::ostringstream s_const; |
| std::ostringstream s_struct; |
| std::ostringstream s_service; |
| std::ostringstream s_const_impl; |
| std::ostringstream s_struct_impl; |
| std::ostringstream s_service_impl; |
| std::ostringstream s_type_factory_registration; |
| std::ostringstream s_type_factory_funcs; |
| bool has_forward; |
| bool has_enum; |
| bool has_const; |
| std::string namespace_dir_; |
| std::map<std::string, int> delphi_keywords; |
| std::map<std::string, int> delphi_reserved_method; |
| std::map<std::string, int> delphi_reserved_method_exception; |
| std::map<std::string, int> types_known; |
| std::list<t_typedef*> typedefs_pending; |
| std::vector<std::string> uses_list; |
| void create_keywords(); |
| bool find_keyword(std::map<std::string, int>& keyword_map, std::string name); |
| std::string normalize_name(std::string name, |
| bool b_method = false, |
| bool b_exception_method = false); |
| std::string empty_value(t_type* type); |
| bool is_fully_defined_type(t_type* ttype); |
| void add_defined_type(t_type* ttype); |
| void init_known_types_list(); |
| bool is_void(t_type* type); |
| int indent_impl_; |
| bool ansistr_binary_; |
| bool register_types_; |
| bool constprefix_; |
| bool events_; |
| bool xmldoc_; |
| bool async_; |
| void indent_up_impl() { ++indent_impl_; }; |
| void indent_down_impl() { --indent_impl_; }; |
| std::string indent_impl() { |
| std::string ind = ""; |
| int i; |
| for (i = 0; i < indent_impl_; ++i) { |
| ind += " "; |
| } |
| return ind; |
| }; |
| std::ostream& indent_impl(std::ostream& os) { return os << indent_impl(); }; |
| }; |
| |
| string t_delphi_generator::replace_all(string contents, string search, string repl) { |
| string str(contents); |
| |
| size_t slen = search.length(); |
| size_t rlen = repl.length(); |
| size_t incr = (rlen > 0) ? rlen : 1; |
| |
| if (slen > 0) { |
| size_t found = str.find(search); |
| while ((found != string::npos) && (found < str.length())) { |
| str.replace(found, slen, repl); |
| found = str.find(search, found + incr); |
| } |
| } |
| |
| return str; |
| } |
| |
| // XML encoding |
| string t_delphi_generator::xml_encode(string contents) { |
| string str(contents); |
| |
| // escape the escape |
| str = replace_all(str, "&", "&"); |
| |
| // other standard XML entities |
| str = replace_all(str, "<", "<"); |
| str = replace_all(str, ">", ">"); |
| |
| return str; |
| } |
| |
| // XML attribute encoding |
| string t_delphi_generator::xmlattrib_encode(string contents) { |
| string str(xml_encode(contents)); |
| |
| // our attribs are enclosed in " |
| str = replace_all(str, "\"", "\\\""); |
| |
| return str; |
| } |
| |
| // XML encoding for doc comments |
| string t_delphi_generator::xmldoc_encode(string contents) { |
| string str(xml_encode(contents)); |
| |
| // XMLDoc specific: convert linebreaks into <para>graphs</para> |
| str = replace_all(str, "\r\n", "\r"); |
| str = replace_all(str, "\n", "\r"); |
| str = replace_all(str, "\r", "</para>\n<para>"); |
| |
| return str; |
| } |
| |
| void t_delphi_generator::generate_delphi_docstring_comment(ostream& out, string contents) { |
| if (xmldoc_) { |
| generate_docstring_comment(out, |
| "{$REGION 'XMLDoc'}/// <summary>\n", |
| "/// ", |
| "<para>" + contents + "</para>", |
| "/// </summary>\n{$ENDREGION}\n"); |
| } |
| } |
| |
| void t_delphi_generator::generate_delphi_doc(ostream& out, t_field* field) { |
| if (xmldoc_) { |
| if (field->get_type()->is_enum()) { |
| string combined_message = xmldoc_encode(field->get_doc()) + "\n<seealso cref=\"" |
| + xmldoc_encode(type_name(field->get_type())) + "\"/>"; |
| generate_delphi_docstring_comment(out, combined_message); |
| } else { |
| generate_delphi_doc(out, (t_doc*)field); |
| } |
| } |
| } |
| |
| void t_delphi_generator::generate_delphi_doc(ostream& out, t_doc* tdoc) { |
| if (tdoc->has_doc() && xmldoc_) { |
| generate_delphi_docstring_comment(out, xmldoc_encode(tdoc->get_doc())); |
| } |
| } |
| |
| void t_delphi_generator::generate_delphi_doc(ostream& out, t_function* tfunction) { |
| if (tfunction->has_doc() && xmldoc_) { |
| stringstream ps; |
| const vector<t_field*>& fields = tfunction->get_arglist()->get_members(); |
| vector<t_field*>::const_iterator p_iter; |
| for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { |
| t_field* p = *p_iter; |
| ps << "\n<param name=\"" << xmlattrib_encode(p->get_name()) << "\">"; |
| if (p->has_doc()) { |
| std::string str = p->get_doc(); |
| str.erase(std::remove(str.begin(), str.end(), '\n'), |
| str.end()); // remove the newlines that appear from the parser |
| ps << xmldoc_encode(str); |
| } |
| ps << "</param>"; |
| } |
| generate_docstring_comment(out, |
| "{$REGION 'XMLDoc'}", |
| "/// ", |
| "<summary><para>" + xmldoc_encode(tfunction->get_doc()) |
| + "</para></summary>" + ps.str(), |
| "{$ENDREGION}\n"); |
| } |
| } |
| |
| bool t_delphi_generator::find_keyword(std::map<std::string, int>& keyword_map, std::string name) { |
| std::string::size_type len = name.length(); |
| |
| if (len <= 0) { |
| return false; |
| } |
| |
| std::string::size_type nlast = name.find_last_of('_'); |
| |
| if (nlast >= 1) { |
| if (nlast == (len - 1)) { |
| string new_name(name, 0, nlast); |
| return find_keyword(keyword_map, new_name); |
| } |
| } |
| return (keyword_map[name] == 1); |
| } |
| |
| std::string t_delphi_generator::normalize_name(std::string name, |
| bool b_method, |
| bool b_exception_method) { |
| string tmp(name); |
| std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower)); |
| |
| bool b_found = false; |
| |
| if (find_keyword(delphi_keywords, tmp)) { |
| b_found = true; |
| } else if (b_method && find_keyword(delphi_reserved_method, tmp)) { |
| b_found = true; |
| } else if (b_exception_method && find_keyword(delphi_reserved_method_exception, tmp)) { |
| b_found = true; |
| } |
| |
| if (b_found) { |
| return name + "_"; |
| } else { |
| return name; |
| } |
| } |
| |
| void t_delphi_generator::create_keywords() { |
| delphi_keywords["and"] = 1; |
| delphi_keywords["end"] = 1; |
| delphi_keywords["interface"] = 1; |
| delphi_keywords["raise"] = 1; |
| delphi_keywords["uses"] = 1; |
| delphi_keywords["array"] = 1; |
| delphi_keywords["except"] = 1; |
| delphi_keywords["is"] = 1; |
| delphi_keywords["record"] = 1; |
| delphi_keywords["var"] = 1; |
| delphi_keywords["as"] = 1; |
| delphi_keywords["exports"] = 1; |
| delphi_keywords["label"] = 1; |
| delphi_keywords["repeat"] = 1; |
| delphi_keywords["while"] = 1; |
| delphi_keywords["asm"] = 1; |
| delphi_keywords["file"] = 1; |
| delphi_keywords["library"] = 1; |
| delphi_keywords["resourcestring"] = 1; |
| delphi_keywords["with"] = 1; |
| delphi_keywords["begin"] = 1; |
| delphi_keywords["finalization"] = 1; |
| delphi_keywords["mod"] = 1; |
| delphi_keywords["set"] = 1; |
| delphi_keywords["xor"] = 1; |
| delphi_keywords["case"] = 1; |
| delphi_keywords["finally"] = 1; |
| delphi_keywords["nil"] = 1; |
| delphi_keywords["shl"] = 1; |
| delphi_keywords["class"] = 1; |
| delphi_keywords["for"] = 1; |
| delphi_keywords["not"] = 1; |
| delphi_keywords["shr"] = 1; |
| delphi_keywords["const"] = 1; |
| delphi_keywords["function"] = 1; |
| delphi_keywords["object"] = 1; |
| delphi_keywords["string"] = 1; |
| delphi_keywords["constructor"] = 1; |
| delphi_keywords["goto"] = 1; |
| delphi_keywords["of"] = 1; |
| delphi_keywords["then"] = 1; |
| delphi_keywords["destructor"] = 1; |
| delphi_keywords["if"] = 1; |
| delphi_keywords["or"] = 1; |
| delphi_keywords["threadvar"] = 1; |
| delphi_keywords["dispinterface"] = 1; |
| delphi_keywords["implementation"] = 1; |
| delphi_keywords["out"] = 1; |
| delphi_keywords["to"] = 1; |
| delphi_keywords["div"] = 1; |
| delphi_keywords["in"] = 1; |
| delphi_keywords["packed"] = 1; |
| delphi_keywords["try"] = 1; |
| delphi_keywords["do"] = 1; |
| delphi_keywords["inherited"] = 1; |
| delphi_keywords["procedure"] = 1; |
| delphi_keywords["type"] = 1; |
| delphi_keywords["downto"] = 1; |
| delphi_keywords["initialization"] = 1; |
| delphi_keywords["program"] = 1; |
| delphi_keywords["unit"] = 1; |
| delphi_keywords["else"] = 1; |
| delphi_keywords["inline"] = 1; |
| delphi_keywords["property"] = 1; |
| delphi_keywords["until"] = 1; |
| delphi_keywords["private"] = 1; |
| delphi_keywords["protected"] = 1; |
| delphi_keywords["public"] = 1; |
| delphi_keywords["published"] = 1; |
| delphi_keywords["automated"] = 1; |
| delphi_keywords["at"] = 1; |
| delphi_keywords["on"] = 1; |
| |
| // reserved/predefined variables and types (lowercase!) |
| delphi_keywords["result"] = 1; |
| delphi_keywords["system"] = 1; |
| delphi_keywords["sysutils"] = 1; |
| delphi_keywords["thrift"] = 1; |
| delphi_keywords["tbytes"] = 1; |
| delphi_keywords["tobject"] = 1; |
| delphi_keywords["tclass"] = 1; |
| delphi_keywords["tinterfacedobject"] = 1; |
| delphi_keywords["ansistring"] = 1; |
| delphi_keywords["string"] = 1; |
| delphi_keywords["boolean"] = 1; |
| delphi_keywords["shortint"] = 1; |
| delphi_keywords["smallint"] = 1; |
| delphi_keywords["integer"] = 1; |
| delphi_keywords["int64"] = 1; |
| delphi_keywords["double"] = 1; |
| |
| delphi_reserved_method["create"] = 1; |
| delphi_reserved_method["free"] = 1; |
| delphi_reserved_method["initinstance"] = 1; |
| delphi_reserved_method["cleanupinstance"] = 1; |
| delphi_reserved_method["classtype"] = 1; |
| delphi_reserved_method["classname"] = 1; |
| delphi_reserved_method["classnameis"] = 1; |
| delphi_reserved_method["classparent"] = 1; |
| delphi_reserved_method["classinfo"] = 1; |
| delphi_reserved_method["instancesize"] = 1; |
| delphi_reserved_method["inheritsfrom"] = 1; |
| delphi_reserved_method["methodaddress"] = 1; |
| delphi_reserved_method["methodname"] = 1; |
| delphi_reserved_method["fieldaddress"] = 1; |
| delphi_reserved_method["getinterface"] = 1; |
| delphi_reserved_method["getinterfaceentry"] = 1; |
| delphi_reserved_method["getinterfacetable"] = 1; |
| delphi_reserved_method["unitname"] = 1; |
| delphi_reserved_method["equals"] = 1; |
| delphi_reserved_method["gethashcode"] = 1; |
| delphi_reserved_method["tostring"] = 1; |
| delphi_reserved_method["safecallexception"] = 1; |
| delphi_reserved_method["afterconstruction"] = 1; |
| delphi_reserved_method["beforedestruction"] = 1; |
| delphi_reserved_method["dispatch"] = 1; |
| delphi_reserved_method["defaulthandler"] = 1; |
| delphi_reserved_method["newinstance"] = 1; |
| delphi_reserved_method["freeinstance"] = 1; |
| delphi_reserved_method["destroy"] = 1; |
| delphi_reserved_method["read"] = 1; |
| delphi_reserved_method["write"] = 1; |
| |
| delphi_reserved_method_exception["setinnerexception"] = 1; |
| delphi_reserved_method_exception["setstackinfo"] = 1; |
| delphi_reserved_method_exception["getstacktrace"] = 1; |
| delphi_reserved_method_exception["raisingexception"] = 1; |
| delphi_reserved_method_exception["createfmt"] = 1; |
| delphi_reserved_method_exception["createres"] = 1; |
| delphi_reserved_method_exception["createresfmt"] = 1; |
| delphi_reserved_method_exception["createhelp"] = 1; |
| delphi_reserved_method_exception["createfmthelp"] = 1; |
| delphi_reserved_method_exception["createreshelp"] = 1; |
| delphi_reserved_method_exception["createresfmthelp"] = 1; |
| delphi_reserved_method_exception["getbaseexception"] = 1; |
| delphi_reserved_method_exception["baseexception"] = 1; |
| delphi_reserved_method_exception["helpcontext"] = 1; |
| delphi_reserved_method_exception["innerexception"] = 1; |
| delphi_reserved_method_exception["message"] = 1; |
| delphi_reserved_method_exception["stacktrace"] = 1; |
| delphi_reserved_method_exception["stackinfo"] = 1; |
| delphi_reserved_method_exception["getexceptionstackinfoproc"] = 1; |
| delphi_reserved_method_exception["getstackinfostringproc"] = 1; |
| delphi_reserved_method_exception["cleanupstackinfoproc"] = 1; |
| delphi_reserved_method_exception["raiseouterexception"] = 1; |
| delphi_reserved_method_exception["throwouterexception"] = 1; |
| } |
| |
| void t_delphi_generator::add_delphi_uses_list(string unitname) { |
| vector<std::string>::const_iterator s_iter; |
| bool found = false; |
| for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) { |
| if ((*s_iter) == unitname) { |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| uses_list.push_back(unitname); |
| } |
| } |
| |
| void t_delphi_generator::init_generator() { |
| indent_impl_ = 0; |
| namespace_name_ = program_->get_namespace("delphi"); |
| has_forward = false; |
| has_enum = false; |
| has_const = false; |
| create_keywords(); |
| |
| add_delphi_uses_list("Classes"); |
| add_delphi_uses_list("SysUtils"); |
| add_delphi_uses_list("Generics.Collections"); |
| if(async_) { |
| add_delphi_uses_list("System.Threading"); |
| } |
| |
| add_delphi_uses_list("Thrift"); |
| add_delphi_uses_list("Thrift.Utils"); |
| add_delphi_uses_list("Thrift.Collections"); |
| add_delphi_uses_list("Thrift.Protocol"); |
| add_delphi_uses_list("Thrift.Transport"); |
| if (register_types_) { |
| add_delphi_uses_list("Thrift.TypeRegistry"); |
| } |
| |
| init_known_types_list(); |
| |
| string unitname, nsname; |
| const vector<t_program*>& includes = program_->get_includes(); |
| for (auto include : includes) { |
| unitname = include->get_name(); |
| nsname = include->get_namespace("delphi"); |
| if ("" != nsname) { |
| unitname = normalize_name(nsname); |
| } |
| add_delphi_uses_list(unitname); |
| } |
| |
| MKDIR(get_out_dir().c_str()); |
| } |
| |
| void t_delphi_generator::close_generator() { |
| std::string unitname = program_name_; |
| if ("" != namespace_name_) { |
| unitname = namespace_name_; |
| } |
| |
| for (int i = 0; i < (int)unitname.size(); i++) { |
| if (unitname[i] == ' ') { |
| unitname.replace(i, 1, "_"); |
| } |
| } |
| |
| unitname = normalize_name(unitname); |
| |
| std::string f_name = get_out_dir() + "/" + unitname + ".pas"; |
| ofstream_with_content_based_conditional_update f_all; |
| |
| f_all.open(f_name); |
| |
| f_all << autogen_comment() << endl; |
| generate_delphi_doc(f_all, program_); |
| f_all << "unit " << unitname << ";" << endl << endl; |
| f_all << "{$WARN SYMBOL_DEPRECATED OFF}" << endl << endl; |
| f_all << "interface" << endl << endl; |
| f_all << "uses" << endl; |
| |
| indent_up(); |
| |
| vector<std::string>::const_iterator s_iter; |
| for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) { |
| if (s_iter != uses_list.begin()) { |
| f_all << ","; |
| f_all << endl; |
| } |
| indent(f_all) << *s_iter; |
| } |
| |
| f_all << ";" << endl << endl; |
| |
| indent_down(); |
| |
| string tmp_unit(unitname); |
| for (int i = 0; i < (int)tmp_unit.size(); i++) { |
| if (tmp_unit[i] == '.') { |
| tmp_unit.replace(i, 1, "_"); |
| } |
| } |
| |
| f_all << "const" << endl; |
| indent_up(); |
| indent(f_all) << "c" << tmp_unit |
| << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";" |
| << endl; |
| indent(f_all) << "c" << tmp_unit |
| << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";" |
| << endl; |
| indent(f_all) << "c" << tmp_unit |
| << "_Option_ConstPrefix = " << (constprefix_ ? "True" : "False") << ";" << endl; |
| indent(f_all) << "c" << tmp_unit << "_Option_Events = " << (events_ ? "True" : "False") |
| << ";" << endl; |
| indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc = " << (xmldoc_ ? "True" : "False") |
| << ";" << endl; |
| indent_down(); |
| |
| f_all << endl; |
| f_all << "type" << endl; |
| if (has_forward) { |
| f_all << s_forward_decr.str() << endl; |
| } |
| if (has_enum) { |
| indent(f_all) << endl; |
| indent(f_all) << "{$SCOPEDENUMS ON}" << endl << endl; |
| f_all << s_enum.str(); |
| indent(f_all) << "{$SCOPEDENUMS OFF}" << endl << endl; |
| } |
| f_all << s_struct.str(); |
| f_all << s_service.str(); |
| f_all << s_const.str(); |
| f_all << "implementation" << endl << endl; |
| f_all << s_struct_impl.str(); |
| f_all << s_service_impl.str(); |
| f_all << s_const_impl.str(); |
| |
| if (register_types_) { |
| f_all << endl; |
| f_all << "// Type factory methods and registration" << endl; |
| f_all << s_type_factory_funcs.str(); |
| f_all << "procedure RegisterTypeFactories;" << endl; |
| f_all << "begin" << endl; |
| f_all << s_type_factory_registration.str(); |
| f_all << "end;" << endl; |
| } |
| f_all << endl; |
| |
| string constants_class = make_constants_classname(); |
| |
| f_all << "initialization" << endl; |
| if (has_const) { |
| f_all << "{$IF CompilerVersion < 21.0} // D2010" << endl; |
| f_all << " " << constants_class.c_str() << "_Initialize;" << endl; |
| f_all << "{$IFEND}" << endl; |
| } |
| if (register_types_) { |
| f_all << " RegisterTypeFactories;" << endl; |
| } |
| f_all << endl; |
| |
| f_all << "finalization" << endl; |
| if (has_const) { |
| f_all << "{$IF CompilerVersion < 21.0} // D2010" << endl; |
| f_all << " " << constants_class.c_str() << "_Finalize;" << endl; |
| f_all << "{$IFEND}" << endl; |
| } |
| f_all << endl << endl; |
| |
| f_all << "end." << endl; |
| f_all.close(); |
| |
| if (!typedefs_pending.empty()) { |
| pwarning(0, "%d typedefs with unresolved type references left:\n", typedefs_pending.size()); |
| for (std::list<t_typedef*>::iterator iter = typedefs_pending.begin(); |
| typedefs_pending.end() != iter; |
| ++iter) { |
| pwarning(0, "- %s\n", (*iter)->get_symbolic().c_str()); |
| } |
| } |
| } |
| |
| void t_delphi_generator::delphi_type_usings(ostream& out) { |
| indent_up(); |
| indent(out) << "Classes, SysUtils, Generics.Collections, Thrift.Collections, Thrift.Protocol," |
| << endl; |
| indent(out) << "Thrift.Transport;" << endl << endl; |
| indent_down(); |
| } |
| |
| void t_delphi_generator::generate_forward_declaration(t_struct* tstruct) { |
| // Forward declare struct def |
| has_forward = true; |
| pverbose("forward declaration of %s\n", type_name(tstruct).c_str()); |
| |
| string what = tstruct->is_xception() ? "class" : "interface"; |
| |
| indent_up(); |
| indent(s_forward_decr) << type_name(tstruct, tstruct->is_xception(), true) << " = " << what << ";" |
| << endl; |
| indent_down(); |
| |
| add_defined_type(tstruct); |
| } |
| |
| void t_delphi_generator::generate_typedef(t_typedef* ttypedef) { |
| t_type* type = ttypedef->get_type(); |
| |
| // write now or save for later? |
| if (!is_fully_defined_type(type)) { |
| pverbose("typedef %s: unresolved dependencies found\n", type_name(ttypedef).c_str()); |
| typedefs_pending.push_back(ttypedef); |
| return; |
| } |
| |
| indent_up(); |
| generate_delphi_doc(s_struct, ttypedef); |
| indent(s_struct) << type_name(ttypedef) << " = "; |
| |
| // commented out: the benefit is not big enough to risk breaking existing code |
| // bool container = type->is_list() || type->is_map() || type->is_set(); |
| // if( ! container) |
| // s_struct << "type "; //the "type A = type B" syntax leads to E2574 with generics |
| |
| s_struct << type_name(ttypedef->get_type()) << ";" << endl << endl; |
| indent_down(); |
| |
| add_defined_type(ttypedef); |
| } |
| |
| bool t_delphi_generator::is_fully_defined_type(t_type* ttype) { |
| if ((nullptr != ttype->get_program()) && (ttype->get_program() != program_)) { |
| t_scope* scope = ttype->get_program()->scope(); |
| if (nullptr != scope->get_type(ttype->get_name())) { |
| // printf("type %s found in included scope %s\n", ttype->get_name().c_str(), |
| // ttype->get_program()->get_name().c_str()); |
| return true; |
| } |
| } |
| |
| if (ttype->is_typedef()) { |
| return (1 == types_known[type_name(ttype)]); |
| } |
| |
| if (ttype->is_base_type()) { |
| return (1 == types_known[base_type_name((t_base_type*)ttype)]); |
| } else if (ttype->is_enum()) { |
| return true; // enums are written first, before all other types |
| } else if (ttype->is_map()) { |
| t_map* tmap = (t_map*)ttype; |
| return is_fully_defined_type(tmap->get_key_type()) |
| && is_fully_defined_type(tmap->get_val_type()); |
| } else if (ttype->is_set()) { |
| t_set* tset = (t_set*)ttype; |
| return is_fully_defined_type(tset->get_elem_type()); |
| } else if (ttype->is_list()) { |
| t_list* tlist = (t_list*)ttype; |
| return is_fully_defined_type(tlist->get_elem_type()); |
| } |
| |
| return (1 == types_known[type_name(ttype)]); |
| } |
| |
| void t_delphi_generator::add_defined_type(t_type* ttype) { |
| // mark as known type |
| types_known[type_name(ttype)] = 1; |
| |
| // check all pending typedefs |
| std::list<t_typedef*>::iterator iter; |
| bool more = true; |
| while (more && (!typedefs_pending.empty())) { |
| more = false; |
| |
| for (iter = typedefs_pending.begin(); typedefs_pending.end() != iter; ++iter) { |
| t_typedef* ttypedef = (*iter); |
| if (is_fully_defined_type(ttypedef->get_type())) { |
| pverbose("typedef %s: all pending references are now resolved\n", |
| type_name(ttypedef).c_str()); |
| typedefs_pending.erase(iter); |
| generate_typedef(ttypedef); |
| more = true; |
| break; |
| } |
| } |
| } |
| } |
| |
| void t_delphi_generator::init_known_types_list() { |
| // known base types |
| types_known[type_name(g_type_string)] = 1; |
| types_known[type_name(g_type_binary)] = 1; |
| types_known[type_name(g_type_bool)] = 1; |
| types_known[type_name(g_type_i8)] = 1; |
| types_known[type_name(g_type_i16)] = 1; |
| types_known[type_name(g_type_i32)] = 1; |
| types_known[type_name(g_type_i64)] = 1; |
| types_known[type_name(g_type_double)] = 1; |
| } |
| |
| void t_delphi_generator::generate_enum(t_enum* tenum) { |
| has_enum = true; |
| indent_up(); |
| generate_delphi_doc(s_enum, tenum); |
| indent(s_enum) << type_name(tenum, true, true) << " = " |
| << "(" << endl; |
| indent_up(); |
| vector<t_enum_value*> constants = tenum->get_constants(); |
| if (constants.empty()) { |
| indent(s_enum) << "dummy = 0 // empty enums are not allowed"; |
| } else { |
| vector<t_enum_value*>::iterator c_iter; |
| for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { |
| int value = (*c_iter)->get_value(); |
| if (c_iter != constants.begin()) { |
| s_enum << ","; |
| s_enum << endl; |
| } |
| generate_delphi_doc(s_enum, *c_iter); |
| indent(s_enum) << normalize_name((*c_iter)->get_name()) << " = " << value; |
| } |
| } |
| s_enum << endl; |
| indent_down(); |
| indent(s_enum) << ");" << endl << endl; |
| indent_down(); |
| } |
| |
| std::string t_delphi_generator::make_pascal_string_literal(std::string value) { |
| std::stringstream result; |
| |
| if (value.length() == 0) { |
| return ""; |
| } |
| |
| result << "'"; |
| for (signed char const c: value) { |
| if( (c >= 0) && (c < 32)) { // convert ctrl chars, but leave UTF-8 alone |
| result << "#" << (int)c; |
| } else if (c == '\'') { |
| result << "''"; // duplicate any single quotes we find |
| } else { |
| result << c; // anything else "as is" |
| } |
| } |
| result << "'"; |
| |
| return result.str(); |
| } |
| |
| std::string t_delphi_generator::make_valid_delphi_identifier(std::string const& fromName) { |
| std::string str = fromName; |
| if (str.empty()) { |
| return str; |
| } |
| |
| // tests rely on this |
| assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9')); |
| |
| // if the first letter is a number, we add an additional underscore in front of it |
| char c = str.at(0); |
| if (('0' <= c) && (c <= '9')) { |
| str = "_" + str; |
| } |
| |
| // following chars: letter, number or underscore |
| for (size_t i = 0; i < str.size(); ++i) { |
| c = str.at(i); |
| if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9')) |
| && ('_' != c)) { |
| str.replace(i, 1, "_"); |
| } |
| } |
| |
| return str; |
| } |
| |
| std::string t_delphi_generator::make_constants_classname() { |
| if (constprefix_) { |
| return make_valid_delphi_identifier("T" + program_name_ + "Constants"); |
| } else { |
| return "TConstants"; // compatibility |
| } |
| } |
| |
| void t_delphi_generator::generate_consts(std::vector<t_const*> consts) { |
| if (consts.empty()) { |
| return; |
| } |
| |
| has_const = true; |
| string constants_class = make_constants_classname(); |
| |
| indent_up(); |
| indent(s_const) << constants_class.c_str() << " = class" << endl; |
| indent(s_const) << "private" << endl; |
| indent_up(); |
| vector<t_const*>::iterator c_iter; |
| for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { |
| if (const_needs_var((*c_iter)->get_type())) { |
| print_private_field(s_const, |
| normalize_name((*c_iter)->get_name()), |
| (*c_iter)->get_type(), |
| (*c_iter)->get_value()); |
| } |
| } |
| indent_down(); |
| indent(s_const) << "public" << endl; |
| indent_up(); |
| for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { |
| generate_delphi_doc(s_const, *c_iter); |
| print_const_prop(s_const, |
| normalize_name((*c_iter)->get_name()), |
| (*c_iter)->get_type(), |
| (*c_iter)->get_value()); |
| } |
| indent(s_const) << "{$IF CompilerVersion >= 21.0}" << endl; |
| indent(s_const) << "class constructor Create;" << endl; |
| indent(s_const) << "class destructor Destroy;" << endl; |
| indent(s_const) << "{$IFEND}" << endl; |
| indent_down(); |
| indent(s_const) << "end;" << endl << endl; |
| indent_down(); |
| |
| std::ostringstream vars, code; |
| |
| indent_up_impl(); |
| for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { |
| initialize_field(vars, |
| code, |
| "F" + prop_name((*c_iter)->get_name()), |
| (*c_iter)->get_type(), |
| (*c_iter)->get_value()); |
| } |
| indent_down_impl(); |
| |
| indent_impl(s_const_impl) << "{$IF CompilerVersion >= 21.0}" << endl; |
| indent_impl(s_const_impl) << "class constructor " << constants_class.c_str() << ".Create;" |
| << endl; |
| |
| if (!vars.str().empty()) { |
| indent_impl(s_const_impl) << "var" << endl; |
| s_const_impl << vars.str(); |
| } |
| indent_impl(s_const_impl) << "begin" << endl; |
| if (!code.str().empty()) { |
| s_const_impl << code.str(); |
| } |
| indent_impl(s_const_impl) << "end;" << endl << endl; |
| indent_impl(s_const_impl) << "class destructor " << constants_class.c_str() << ".Destroy;" |
| << endl; |
| indent_impl(s_const_impl) << "begin" << endl; |
| indent_up_impl(); |
| for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { |
| if (const_needs_var((*c_iter)->get_type())) { |
| finalize_field(s_const_impl, |
| normalize_name((*c_iter)->get_name()), |
| (*c_iter)->get_type(), |
| (*c_iter)->get_value()); |
| } |
| } |
| indent_impl(s_const_impl) << "inherited;" << endl; |
| indent_down_impl(); |
| indent_impl(s_const_impl) << "end;" << endl; |
| indent_impl(s_const_impl) << "{$ELSE}" << endl; |
| |
| vars.str(""); |
| code.str(""); |
| |
| indent_up_impl(); |
| for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { |
| if (const_needs_var((*c_iter)->get_type())) { |
| initialize_field(vars, |
| code, |
| constants_class + ".F" + prop_name((*c_iter)->get_name()), |
| (*c_iter)->get_type(), |
| (*c_iter)->get_value()); |
| } |
| } |
| indent_down_impl(); |
| |
| indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Initialize;" << endl; |
| if (!vars.str().empty()) { |
| indent_impl(s_const_impl) << "var" << endl; |
| s_const_impl << vars.str(); |
| } |
| indent_impl(s_const_impl) << "begin" << endl; |
| if (!code.str().empty()) { |
| s_const_impl << code.str(); |
| } |
| indent_impl(s_const_impl) << "end;" << endl << endl; |
| |
| indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Finalize;" << endl; |
| indent_impl(s_const_impl) << "begin" << endl; |
| indent_up_impl(); |
| for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { |
| finalize_field(s_const_impl, |
| normalize_name((*c_iter)->get_name()), |
| (*c_iter)->get_type(), |
| (*c_iter)->get_value(), |
| constants_class); |
| } |
| indent_down_impl(); |
| indent_impl(s_const_impl) << "end;" << endl; |
| indent_impl(s_const_impl) << "{$IFEND}" << endl << endl; |
| } |
| |
| void t_delphi_generator::print_const_def_value(std::ostream& vars, |
| std::ostream& out, |
| string name, |
| t_type* type, |
| t_const_value* value, |
| string cls_nm) { |
| |
| string cls_prefix; |
| |
| if (cls_nm == "") { |
| cls_prefix = ""; |
| } else { |
| cls_prefix = cls_nm + "."; |
| } |
| |
| if (type->is_struct() || type->is_xception()) { |
| 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*, t_const_value::value_compare>& val = value->get_map(); |
| map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter; |
| for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { |
| t_type* field_type = nullptr; |
| 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 == nullptr) { |
| throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); |
| } |
| string val = render_const_value(vars, out, name, field_type, v_iter->second); |
| indent_impl(out) << cls_prefix << normalize_name(name) << "." |
| << prop_name(v_iter->first->get_string(), type->is_xception()) |
| << " := " << val << ";" << endl; |
| } |
| } else if (type->is_map()) { |
| t_type* ktype = ((t_map*)type)->get_key_type(); |
| t_type* vtype = ((t_map*)type)->get_val_type(); |
| const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map(); |
| map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter; |
| for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { |
| string key = render_const_value(vars, out, name, ktype, v_iter->first); |
| string val = render_const_value(vars, out, name, vtype, v_iter->second); |
| indent_impl(out) << cls_prefix << normalize_name(name) << "[" << key << "]" |
| << " := " << val << ";" << endl; |
| } |
| } else if (type->is_list() || type->is_set()) { |
| t_type* etype; |
| if (type->is_list()) { |
| etype = ((t_list*)type)->get_elem_type(); |
| } else { |
| etype = ((t_set*)type)->get_elem_type(); |
| } |
| |
| 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) { |
| string val = render_const_value(vars, out, name, etype, *v_iter); |
| indent_impl(out) << cls_prefix << normalize_name(name) << ".Add(" << val << ");" << endl; |
| } |
| } |
| } |
| |
| void t_delphi_generator::print_private_field(std::ostream& out, |
| string name, |
| t_type* type, |
| t_const_value* value) { |
| (void)value; |
| indent(out) << "class var F" << name << ": " << type_name(type) << ";" << endl; |
| } |
| |
| bool t_delphi_generator::const_needs_var(t_type* type) { |
| t_type* truetype = type; |
| while (truetype->is_typedef()) { |
| truetype = ((t_typedef*)truetype)->get_type(); |
| } |
| return (!truetype->is_base_type()); |
| } |
| |
| void t_delphi_generator::print_const_prop(std::ostream& out, |
| string name, |
| t_type* type, |
| t_const_value* value) { |
| (void)value; |
| if (const_needs_var(type)) { |
| indent(out) << "class property " << name << ": " << type_name(type) << " read F" << name << ";" |
| << endl; |
| } else { |
| std::ostringstream vars; // dummy |
| string v2 = render_const_value(vars, out, name, type, value); |
| indent(out) << "const " << name << " = " << v2 << ";" << endl; |
| } |
| } |
| |
| void t_delphi_generator::print_const_value(std::ostream& vars, |
| std::ostream& out, |
| string name, |
| t_type* type, |
| t_const_value* value) { |
| t_type* truetype = type; |
| while (truetype->is_typedef()) { |
| truetype = ((t_typedef*)truetype)->get_type(); |
| } |
| |
| if (truetype->is_base_type()) { |
| // already done |
| // string v2 = render_const_value( vars, out, name, type, value); |
| // indent_impl(out) << name << " := " << v2 << ";" << endl; |
| } else if (truetype->is_enum()) { |
| indent_impl(out) << name << " := " << type_name(type) << "." << value->get_identifier_name() |
| << ";" << endl; |
| } else { |
| string typname; |
| typname = type_name(truetype, true, false, type->is_xception(), type->is_xception()); |
| indent_impl(out) << name << " := " << typname << ".Create;" << endl; |
| print_const_def_value(vars, out, name, truetype, value); |
| } |
| } |
| |
| void t_delphi_generator::initialize_field(std::ostream& vars, |
| std::ostream& out, |
| string name, |
| t_type* type, |
| t_const_value* value) { |
| print_const_value(vars, out, name, type, value); |
| } |
| |
| void t_delphi_generator::finalize_field(std::ostream& out, |
| string name, |
| t_type* type, |
| t_const_value* value, |
| string cls_nm) { |
| (void)out; |
| (void)name; |
| (void)type; |
| (void)value; |
| (void)cls_nm; |
| } |
| |
| string t_delphi_generator::render_const_value(ostream& vars, |
| ostream& out, |
| string name, |
| t_type* type, |
| t_const_value* value) { |
| (void)name; |
| |
| t_type* truetype = type; |
| while (truetype->is_typedef()) { |
| truetype = ((t_typedef*)truetype)->get_type(); |
| } |
| |
| std::ostringstream render; |
| |
| if (truetype->is_base_type()) { |
| t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base(); |
| switch (tbase) { |
| case t_base_type::TYPE_STRING: |
| render << "'" << get_escaped_string(value) << "'"; |
| break; |
| case t_base_type::TYPE_BOOL: |
| render << ((value->get_integer() > 0) ? "True" : "False"); |
| break; |
| case t_base_type::TYPE_I8: |
| render << "ShortInt( " << value->get_integer() << ")"; |
| break; |
| case t_base_type::TYPE_I16: |
| render << "SmallInt( " << value->get_integer() << ")"; |
| break; |
| case t_base_type::TYPE_I32: |
| render << "LongInt( " << value->get_integer() << ")"; |
| break; |
| case t_base_type::TYPE_I64: |
| render << "Int64( " << value->get_integer() << ")"; |
| break; |
| case t_base_type::TYPE_DOUBLE: |
| if (value->get_type() == t_const_value::CV_INTEGER) { |
| render << value->get_integer() << ".0"; // make it a double constant by adding ".0" |
| } else { |
| render << value->get_double(); |
| } |
| break; |
| default: |
| throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); |
| } |
| } else if (truetype->is_enum()) { |
| render << type_name(type, false) << "." << value->get_identifier_name(); |
| } else { |
| string t = tmp("tmp"); |
| vars << " " << t << " : " << type_name(type) << ";" << endl; |
| print_const_value(vars, out, t, type, value); |
| render << t; |
| } |
| |
| return render.str(); |
| } |
| |
| void t_delphi_generator::generate_struct(t_struct* tstruct) { |
| generate_delphi_struct(tstruct, false); |
| } |
| |
| void t_delphi_generator::generate_xception(t_struct* txception) { |
| generate_delphi_struct(txception, true); |
| } |
| |
| void t_delphi_generator::generate_delphi_struct(t_struct* tstruct, bool is_exception) { |
| indent_up(); |
| generate_delphi_struct_definition(s_struct, tstruct, is_exception); |
| indent_down(); |
| |
| add_defined_type(tstruct); |
| |
| generate_delphi_struct_impl(s_struct_impl, "", tstruct, is_exception); |
| if (register_types_) { |
| generate_delphi_struct_type_factory(s_type_factory_funcs, "", tstruct, is_exception); |
| generate_delphi_struct_type_factory_registration(s_type_factory_registration, |
| "", |
| tstruct, |
| is_exception); |
| } |
| } |
| |
| void t_delphi_generator::generate_delphi_struct_impl(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_result, |
| bool is_x_factory) { |
| |
| if (is_exception && (!is_x_factory)) { |
| generate_delphi_struct_impl(out, cls_prefix, tstruct, is_exception, is_result, true); |
| } |
| |
| string cls_nm; |
| |
| string exception_factory_name; |
| |
| if (is_exception) { |
| exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; |
| } |
| |
| if (is_exception) { |
| cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true); |
| } else { |
| cls_nm = type_name(tstruct, true, false); |
| } |
| |
| std::ostringstream vars, code; |
| |
| const vector<t_field*>& members = tstruct->get_members(); |
| vector<t_field*>::const_iterator m_iter; |
| |
| indent_up_impl(); |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| t_type* t = (*m_iter)->get_type(); |
| while (t->is_typedef()) { |
| t = ((t_typedef*)t)->get_type(); |
| } |
| if ((*m_iter)->get_value() != nullptr) { |
| initialize_field(vars, |
| code, |
| "F" + prop_name((*m_iter)->get_name(), is_exception), |
| t, |
| (*m_iter)->get_value()); |
| if ((*m_iter)->get_req() != t_field::T_REQUIRED) { |
| indent_impl(code) << "F__isset_" << prop_name((*m_iter), is_exception) << " := True;" |
| << endl; |
| } |
| } |
| } |
| indent_down_impl(); |
| |
| indent_impl(out) << "constructor " << cls_prefix << cls_nm << "." |
| << "Create;" << endl; |
| |
| if (!vars.str().empty()) { |
| out << "var" << endl; |
| out << vars.str(); |
| } |
| |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| if (is_exception && (!is_x_factory)) { |
| indent_impl(out) << "inherited Create('');" << endl; |
| } else { |
| indent_impl(out) << "inherited;" << endl; |
| } |
| |
| if (!code.str().empty()) { |
| out << code.str(); |
| } |
| |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| |
| if ((members.size() > 0) && is_exception && (!is_x_factory)) { |
| indent_impl(out) << "constructor " << cls_prefix << cls_nm << "." |
| << "Create(" << constructor_argument_list(tstruct, indent_impl()) << ");" |
| << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "Create;" << endl; |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| string propname = prop_name((*m_iter)->get_name(), is_exception); |
| string param_name = constructor_param_name((*m_iter)->get_name()); |
| indent_impl(out) << propname << " := " << param_name << ";" << endl; |
| } |
| indent_impl(out) << "UpdateMessageProperty;" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| } |
| |
| indent_impl(out) << "destructor " << cls_prefix << cls_nm << "." |
| << "Destroy;" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| t_type* t = (*m_iter)->get_type(); |
| while (t->is_typedef()) { |
| t = ((t_typedef*)t)->get_type(); |
| } |
| finalize_field(out, prop_name(*m_iter, is_exception), t, (*m_iter)->get_value()); |
| } |
| |
| indent_impl(out) << "inherited;" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| |
| if (is_exception && (!is_x_factory)) { |
| indent_impl(out) << "function " << cls_prefix << cls_nm << "." << exception_factory_name |
| << ": I" << exception_factory_name << ";" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "if F" << exception_factory_name << " = nil" << endl; |
| indent_impl(out) << "then F" << exception_factory_name << " := T" << exception_factory_name << "Impl.Create;" << endl << endl; |
| indent_impl(out) << "result := F" << exception_factory_name << ";" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| indent_impl(out) << "function " << cls_prefix << cls_nm << ".QueryInterface(const IID: TGUID; out Obj): HRESULT;" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "if GetInterface(IID, Obj)" << endl; |
| indent_impl(out) << "then result := S_OK" << endl; |
| indent_impl(out) << "else result := E_NOINTERFACE;" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| indent_impl(out) << "function " << cls_prefix << cls_nm << "._AddRef: Integer;" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "result := -1; // not refcounted" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| indent_impl(out) << "function " << cls_prefix << cls_nm << "._Release: Integer;" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "result := -1; // not refcounted" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| } |
| |
| if (tstruct->is_union()) { |
| indent_impl(out) << "procedure " << cls_prefix << cls_nm << "." |
| << "ClearUnionValues;" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| t_type* t = (*m_iter)->get_type(); |
| while (t->is_typedef()) { |
| t = ((t_typedef*)t)->get_type(); |
| } |
| |
| generate_delphi_clear_union_value(out, |
| cls_prefix, |
| cls_nm, |
| t, |
| *m_iter, |
| "F", |
| is_exception, |
| tstruct->is_union(), |
| is_x_factory, |
| exception_factory_name); |
| } |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| } |
| |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| t_type* t = (*m_iter)->get_type(); |
| while (t->is_typedef()) { |
| t = ((t_typedef*)t)->get_type(); |
| } |
| generate_delphi_property_reader_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception); |
| generate_delphi_property_writer_impl(out, |
| cls_prefix, |
| cls_nm, |
| t, |
| *m_iter, |
| "F", |
| is_exception, |
| tstruct->is_union(), |
| is_x_factory, |
| exception_factory_name); |
| if ((*m_iter)->get_req() != t_field::T_REQUIRED) { |
| generate_delphi_isset_reader_writer_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception); |
| } |
| } |
| |
| generate_delphi_struct_reader_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); |
| if (is_result) { |
| generate_delphi_struct_result_writer_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); |
| } else { |
| generate_delphi_struct_writer_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); |
| } |
| generate_delphi_struct_tostring_impl(out, cls_prefix, tstruct, is_exception, is_x_factory); |
| |
| if (is_exception && is_x_factory) { |
| generate_delphi_create_exception_impl(out, cls_prefix, tstruct, is_exception); |
| } |
| } |
| |
| void t_delphi_generator::print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct) { |
| string struct_intf_name = type_name(tstruct); |
| out << "Create_"; |
| out << struct_intf_name; |
| out << "_Impl"; |
| } |
| |
| void t_delphi_generator::generate_delphi_struct_type_factory(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_result, |
| bool is_x_factory) { |
| (void)cls_prefix; |
| if (is_exception) |
| return; |
| if (is_result) |
| return; |
| if (is_x_factory) |
| return; |
| |
| string struct_intf_name = type_name(tstruct); |
| string cls_nm = type_name(tstruct, true, false); |
| |
| out << "function "; |
| print_delphi_struct_type_factory_func(out, tstruct); |
| out << ": "; |
| out << struct_intf_name; |
| out << ";" << endl; |
| out << "begin" << endl; |
| indent_up(); |
| indent(out) << "Result := " << cls_nm << ".Create;" << endl; |
| indent_down(); |
| out << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_struct_type_factory_registration(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_result, |
| bool is_x_factory) { |
| (void)cls_prefix; |
| if (is_exception) |
| return; |
| if (is_result) |
| return; |
| if (is_x_factory) |
| return; |
| |
| string struct_intf_name = type_name(tstruct); |
| |
| indent(out) << " TypeRegistry.RegisterTypeFactory<" << struct_intf_name << ">("; |
| print_delphi_struct_type_factory_func(out, tstruct); |
| out << ");"; |
| out << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_struct_definition(ostream& out, |
| t_struct* tstruct, |
| bool is_exception, |
| bool in_class, |
| bool is_result, |
| bool is_x_factory) { |
| bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end()); |
| string struct_intf_name; |
| string struct_name; |
| string isset_name; |
| const vector<t_field*>& members = tstruct->get_members(); |
| vector<t_field*>::const_iterator m_iter; |
| |
| string exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; |
| |
| if (is_exception) { |
| struct_intf_name = type_name(tstruct, false, false, true); |
| } else { |
| struct_intf_name = type_name(tstruct); |
| } |
| |
| if (is_exception) { |
| struct_name = type_name(tstruct, true, (!is_x_factory), is_x_factory); |
| } else { |
| struct_name = type_name(tstruct, true); |
| } |
| |
| if ((!is_exception) || is_x_factory) { |
| |
| generate_delphi_doc(out, tstruct); |
| indent(out) << struct_intf_name << " = interface(IBase)" << endl; |
| indent_up(); |
| |
| generate_guid(out); |
| |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| generate_delphi_property_reader_definition(out, *m_iter, is_exception); |
| generate_delphi_property_writer_definition(out, *m_iter, is_exception); |
| } |
| |
| if (is_x_factory) { |
| out << endl; |
| indent(out) << "// Create Exception Object" << endl; |
| indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl; |
| } |
| |
| if (members.size() > 0) { |
| out << endl; |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| generate_property(out, *m_iter, true, is_exception); |
| } |
| } |
| |
| if (members.size() > 0) { |
| out << endl; |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| if ((*m_iter)->get_req() != t_field::T_REQUIRED) { |
| generate_delphi_isset_reader_writer_definition(out, *m_iter, is_exception); |
| } |
| } |
| } |
| |
| if (members.size() > 0) { |
| out << endl; |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| if ((*m_iter)->get_req() != t_field::T_REQUIRED) { |
| isset_name = "__isset_" + prop_name(*m_iter, is_exception); |
| indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";" |
| << endl; |
| } |
| } |
| } |
| |
| indent_down(); |
| indent(out) << "end;" << endl << endl; |
| } |
| |
| generate_delphi_doc(out, tstruct); |
| indent(out) << struct_name << " = "; |
| if (is_final) { |
| out << "sealed "; |
| } |
| out << "class("; |
| if (is_exception && (!is_x_factory)) { |
| out << "TException, IInterface, IBase, ISupportsToString"; |
| } else { |
| out << "TInterfacedObject, IBase, ISupportsToString, " << struct_intf_name; |
| } |
| out << ")" << endl; |
| |
| if (is_exception && (!is_x_factory)) { |
| indent(out) << "public" << endl; |
| indent_up(); |
| indent(out) << "type" << endl; |
| indent_up(); |
| generate_delphi_struct_definition(out, tstruct, is_exception, in_class, is_result, true); |
| indent_down(); |
| indent_down(); |
| } |
| |
| indent(out) << "private" << endl; |
| indent_up(); |
| |
| if (is_exception && (!is_x_factory)) { |
| indent(out) << "F" << exception_factory_name << " :" << struct_intf_name << ";" << endl << endl; |
| } |
| |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| indent(out) << declare_field(*m_iter, false, "F", is_exception) << endl; |
| } |
| |
| if (members.size() > 0) { |
| indent(out) << endl; |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| if ((*m_iter)->get_req() != t_field::T_REQUIRED) { |
| isset_name = "F__isset_" + prop_name(*m_iter, is_exception); |
| indent(out) << isset_name << ": System.Boolean;" << endl; |
| } |
| } |
| } |
| |
| indent(out) << endl; |
| |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| generate_delphi_property_reader_definition(out, *m_iter, is_exception); |
| generate_delphi_property_writer_definition(out, *m_iter, is_exception); |
| } |
| |
| if (tstruct->is_union()) { |
| out << endl; |
| indent(out) << "// Clear values(for union's property setter)" << endl; |
| indent(out) << "procedure ClearUnionValues;" << endl; |
| } |
| |
| if (members.size() > 0) { |
| out << endl; |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| if ((*m_iter)->get_req() != t_field::T_REQUIRED) { |
| isset_name = "__isset_" + prop_name(*m_iter, is_exception); |
| indent(out) << "function Get" << isset_name << ": System.Boolean;" << endl; |
| indent(out) << "procedure Set" << isset_name << "( const value : System.Boolean);" << endl; |
| } |
| } |
| } |
| |
| if (is_exception && (!is_x_factory)) { |
| out << endl; |
| indent_down(); |
| indent(out) << "strict protected" << endl; |
| indent_up(); |
| indent(out) << "function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;" << endl; |
| indent(out) << "function _AddRef: Integer; stdcall;" << endl; |
| indent(out) << "function _Release: Integer; stdcall;" << endl; |
| out << endl; |
| } |
| |
| indent_down(); |
| indent(out) << "public" << endl; |
| indent_up(); |
| |
| if ((members.size() > 0) && is_exception && (!is_x_factory)) { |
| indent(out) << "constructor Create; overload;" << endl; |
| indent(out) << "constructor Create(" << constructor_argument_list(tstruct, indent()) |
| << "); overload;" << endl; |
| } else { |
| indent(out) << "constructor Create;" << endl; |
| } |
| |
| indent(out) << "destructor Destroy; override;" << endl; |
| |
| out << endl; |
| indent(out) << "function ToString: string; override;" << endl; |
| |
| if (is_exception && (!is_x_factory)) { |
| out << endl; |
| indent(out) << "// Exception Factory" << endl; |
| indent(out) << "function " << exception_factory_name << ": " << struct_intf_name << ";" << endl; |
| } |
| |
| out << endl; |
| indent(out) << "// IBase" << endl; |
| indent(out) << "procedure Read( const iprot: IProtocol);" << endl; |
| indent(out) << "procedure Write( const oprot: IProtocol);" << endl; |
| |
| if (is_exception && is_x_factory) { |
| out << endl; |
| indent(out) << "// Create Exception Object" << endl; |
| indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl; |
| } |
| |
| if (members.size() > 0) { |
| out << endl; |
| indent(out) << "// Properties" << endl; |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| generate_property(out, *m_iter, true, is_exception); |
| } |
| } |
| |
| if (members.size() > 0) { |
| out << endl; |
| indent(out) << "// isset" << endl; |
| for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { |
| if ((*m_iter)->get_req() != t_field::T_REQUIRED) { |
| isset_name = "__isset_" + prop_name(*m_iter, is_exception); |
| indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";" |
| << endl; |
| } |
| } |
| } |
| |
| indent_down(); |
| indent(out) << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_service(t_service* tservice) { |
| indent_up(); |
| generate_delphi_doc(s_service, tservice); |
| indent(s_service) << normalize_clsnm(service_name_, "T") << " = class" << endl; |
| indent(s_service) << "public" << endl; |
| indent_up(); |
| indent(s_service) << "type" << endl; |
| generate_service_interface(tservice); |
| generate_service_client(tservice); |
| generate_service_server(tservice); |
| generate_service_helpers(tservice); |
| indent_down(); |
| indent_down(); |
| indent(s_service) << "end;" << endl; |
| indent(s_service) << endl; |
| indent_down(); |
| } |
| |
| void t_delphi_generator::generate_service_interface(t_service* tservice) { |
| generate_service_interface(tservice,false); |
| if(async_) { |
| generate_service_interface(tservice,true); |
| } |
| } |
| |
| |
| void t_delphi_generator::generate_service_interface(t_service* tservice, bool for_async) { |
| string extends = ""; |
| string extends_iface = ""; |
| string iface_name = for_async ? "IAsync" : "Iface"; |
| |
| indent_up(); |
| |
| generate_delphi_doc(s_service, tservice); |
| if (tservice->get_extends() != nullptr) { |
| extends = type_name(tservice->get_extends(), true, true); |
| extends_iface = extends + "." + iface_name; |
| generate_delphi_doc(s_service, tservice); |
| indent(s_service) << iface_name << " = interface(" << extends_iface << ")" << endl; |
| } else { |
| indent(s_service) << iface_name << " = interface" << endl; |
| } |
| |
| indent_up(); |
| generate_guid(s_service); |
| vector<t_function*> functions = tservice->get_functions(); |
| vector<t_function*>::iterator f_iter; |
| for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { |
| generate_delphi_doc(s_service, *f_iter); |
| indent(s_service) << function_signature(*f_iter, for_async) << endl; |
| } |
| indent_down(); |
| indent(s_service) << "end;" << endl << endl; |
| |
| indent_down(); |
| } |
| |
| void t_delphi_generator::generate_guid(std::ostream& out) { |
| #ifdef _WIN32 // TODO: add support for non-windows platforms if needed |
| GUID guid; |
| if (SUCCEEDED(CoCreateGuid(&guid))) { |
| OLECHAR guid_chars[40]; |
| if (StringFromGUID2(guid, &guid_chars[0], sizeof(guid_chars) / sizeof(guid_chars[0])) > 0) { |
| std::wstring guid_wstr(guid_chars); |
| std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert; |
| std::string guid_str = convert.to_bytes(guid_wstr); |
| indent(out) << "['" << guid_str << "']" << endl; |
| } |
| } |
| #else |
| (void)out; // prevent unused warning on other platforms |
| #endif |
| } |
| |
| void t_delphi_generator::generate_service_helpers(t_service* tservice) { |
| vector<t_function*> functions = tservice->get_functions(); |
| vector<t_function*>::iterator f_iter; |
| |
| for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { |
| t_struct* ts = (*f_iter)->get_arglist(); |
| generate_delphi_struct_definition(s_service, ts, false, true); |
| generate_delphi_struct_impl(s_service_impl, |
| normalize_clsnm(service_name_, "T") + ".", |
| ts, |
| false); |
| generate_function_helpers(*f_iter); |
| } |
| } |
| |
| void t_delphi_generator::generate_service_client(t_service* tservice) { |
| indent_up(); |
| string extends = ""; |
| string extends_client = "TInterfacedObject"; |
| string implements = async_ ? "Iface, IAsync" : "Iface"; |
| |
| generate_delphi_doc(s_service, tservice); |
| if (tservice->get_extends() != nullptr) { |
| extends = type_name(tservice->get_extends(), true, true); |
| extends_client = extends + ".TClient"; |
| } |
| indent(s_service) << "TClient = class( " << extends_client << ", " << implements << ")" << endl; |
| |
| indent(s_service) << "public" << endl; |
| indent_up(); |
| |
| indent(s_service) << "constructor Create( prot: IProtocol); overload;" << endl; |
| |
| indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T") |
| << ".TClient.Create( prot: IProtocol);" << endl; |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "Create( prot, prot );" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| |
| indent(s_service) |
| << "constructor Create( const iprot: IProtocol; const oprot: IProtocol); overload;" << endl; |
| |
| indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T") |
| << ".TClient.Create( const iprot: IProtocol; const oprot: IProtocol);" |
| << endl; |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "inherited Create;" << endl; |
| indent_impl(s_service_impl) << "iprot_ := iprot;" << endl; |
| indent_impl(s_service_impl) << "oprot_ := oprot;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| |
| indent_down(); |
| |
| if (extends.empty()) { |
| indent(s_service) << "protected" << endl; |
| indent_up(); |
| indent(s_service) << "iprot_: IProtocol;" << endl; |
| indent(s_service) << "oprot_: IProtocol;" << endl; |
| indent(s_service) << "seqid_: System.Integer;" << endl; |
| indent_down(); |
| |
| indent(s_service) << "public" << endl; |
| indent_up(); |
| indent(s_service) << "property InputProtocol: IProtocol read iprot_;" << endl; |
| indent(s_service) << "property OutputProtocol: IProtocol read oprot_;" << endl; |
| indent_down(); |
| } |
| |
| vector<t_function*> functions = tservice->get_functions(); |
| vector<t_function*>::const_iterator f_iter; |
| |
| indent(s_service) << "protected" << endl; |
| indent_up(); |
| |
| indent(s_service) << "// Iface" << endl; |
| for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { |
| string funname = (*f_iter)->get_name(); |
| generate_delphi_doc(s_service, *f_iter); |
| indent(s_service) << function_signature(*f_iter, false) << endl; |
| } |
| |
| if( async_) { |
| indent(s_service) << endl; |
| indent(s_service) << "// IAsync" << endl; |
| for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { |
| string funname = (*f_iter)->get_name(); |
| generate_delphi_doc(s_service, *f_iter); |
| indent(s_service) << function_signature(*f_iter, true) << endl; |
| } |
| } |
| |
| indent_down(); |
| |
| indent(s_service) << "public" << endl; |
| indent_up(); |
| |
| string full_cls = normalize_clsnm(service_name_, "T") + ".TClient"; |
| |
| for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { |
| string funname = (*f_iter)->get_name(); |
| |
| vector<t_field*>::const_iterator fld_iter; |
| t_struct* arg_struct = (*f_iter)->get_arglist(); |
| const vector<t_field*>& fields = arg_struct->get_members(); |
| |
| // one for sync only, two for async+sync |
| int mode = async_ ? 1 : 0; |
| while( mode >= 0) { |
| bool for_async = (mode != 0); |
| mode--; |
| |
| indent_impl(s_service_impl) << function_signature(*f_iter, for_async, full_cls) << endl; |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| |
| t_type* ttype = (*f_iter)->get_returntype(); |
| if( for_async) { |
| if (is_void(ttype)) { |
| // Delphi forces us to specify a type with IFuture<T>, so we use Integer=0 for void methods |
| indent_impl(s_service_impl) << "result := TTask.Future<System.Integer>(function: System.Integer" << endl; |
| } else { |
| string rettype = type_name(ttype, false, true, false, true); |
| indent_impl(s_service_impl) << "result := TTask.Future<" << rettype << ">(function: " << rettype << endl; |
| } |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| } |
| |
| indent_impl(s_service_impl) << "send_" << funname << "("; |
| |
| bool first = true; |
| for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { |
| if (first) { |
| first = false; |
| } else { |
| s_service_impl << ", "; |
| } |
| s_service_impl << normalize_name((*fld_iter)->get_name()); |
| } |
| s_service_impl << ");" << endl; |
| |
| if (!(*f_iter)->is_oneway()) { |
| s_service_impl << indent_impl(); |
| if (!(*f_iter)->get_returntype()->is_void()) { |
| s_service_impl << "Result := "; |
| } |
| s_service_impl << "recv_" << funname << "();" << endl; |
| } |
| |
| if( for_async) { |
| if (is_void(ttype)) { |
| indent_impl(s_service_impl) << "Result := 0;" << endl; // no IFuture<void> in Delphi |
| } |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end);" << endl; |
| } |
| |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| } |
| |
| t_function send_function(g_type_void, |
| string("send_") + (*f_iter)->get_name(), |
| (*f_iter)->get_arglist()); |
| |
| string argsname = (*f_iter)->get_name() + "_args"; |
| string args_clsnm = normalize_clsnm(argsname, "T"); |
| string args_intfnm = normalize_clsnm(argsname, "I"); |
| |
| string argsvar = tmp("_args"); |
| string msgvar = tmp("_msg"); |
| |
| indent(s_service) << function_signature(&send_function, false) << endl; |
| indent_impl(s_service_impl) << function_signature(&send_function, false, full_cls) << endl; |
| indent_impl(s_service_impl) << "var" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << argsvar << " : " << args_intfnm << ";" << endl; |
| indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| |
| indent_impl(s_service_impl) << "seqid_ := seqid_ + 1;" << endl; |
| indent_impl(s_service_impl) << "Thrift.Protocol.Init( " << msgvar << ", '" << funname |
| << "', " << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" |
| : "TMessageType.Call") |
| << ", seqid_);" << endl; |
| |
| indent_impl(s_service_impl) << "oprot_.WriteMessageBegin( " << msgvar << " );" << endl; |
| indent_impl(s_service_impl) << argsvar << " := " << args_clsnm << "Impl.Create();" << endl; |
| |
| for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { |
| indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter) |
| << " := " << normalize_name((*fld_iter)->get_name()) << ";" |
| << endl; |
| } |
| indent_impl(s_service_impl) << argsvar << ".Write(oprot_);" << endl; |
| for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { |
| indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter) |
| << " := " << empty_value((*fld_iter)->get_type()) << ";" << endl; |
| } |
| |
| indent_impl(s_service_impl) << "oprot_.WriteMessageEnd();" << endl; |
| indent_impl(s_service_impl) << "oprot_.Transport.Flush();" << endl; |
| |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| |
| if (!(*f_iter)->is_oneway()) { |
| string org_resultname = (*f_iter)->get_name() + "_result"; |
| string result_clsnm = normalize_clsnm(org_resultname, "T"); |
| string result_intfnm = normalize_clsnm(org_resultname, "I"); |
| |
| t_struct noargs(program_); |
| t_function recv_function((*f_iter)->get_returntype(), |
| string("recv_") + (*f_iter)->get_name(), |
| &noargs, |
| (*f_iter)->get_xceptions()); |
| |
| t_struct* xs = (*f_iter)->get_xceptions(); |
| const std::vector<t_field*>& xceptions = xs->get_members(); |
| |
| string exceptvar = tmp("_ex"); |
| string appexvar = tmp("_ax"); |
| string retvar = tmp("_ret"); |
| |
| indent(s_service) << function_signature(&recv_function, false) << endl; |
| indent_impl(s_service_impl) << function_signature(&recv_function, false, full_cls) << endl; |
| indent_impl(s_service_impl) << "var" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl; |
| if (xceptions.size() > 0) { |
| indent_impl(s_service_impl) << exceptvar << " : Exception;" << endl; |
| } |
| indent_impl(s_service_impl) << appexvar << " : TApplicationException;" << endl; |
| indent_impl(s_service_impl) << retvar << " : " << result_intfnm << ";" << endl; |
| |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << msgvar << " := iprot_.ReadMessageBegin();" << endl; |
| indent_impl(s_service_impl) << "if (" << msgvar << ".Type_ = TMessageType.Exception) then begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << appexvar << " := TApplicationException.Read(iprot_);" << endl; |
| indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl; |
| indent_impl(s_service_impl) << "raise " << appexvar << ";" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| |
| indent_impl(s_service_impl) << retvar << " := " << result_clsnm << "Impl.Create();" << endl; |
| indent_impl(s_service_impl) << retvar << ".Read(iprot_);" << endl; |
| indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl; |
| |
| if (!(*f_iter)->get_returntype()->is_void()) { |
| indent_impl(s_service_impl) << "if (" << retvar << ".__isset_success) then begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "Result := " << retvar << ".Success;" << endl; |
| t_type* type = (*f_iter)->get_returntype(); |
| if (type->is_struct() || type->is_xception() || type->is_map() || type->is_list() |
| || type->is_set()) { |
| indent_impl(s_service_impl) << retvar << ".Success := nil;" << endl; |
| } |
| indent_impl(s_service_impl) << "Exit;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| } |
| |
| vector<t_field*>::const_iterator x_iter; |
| for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { |
| indent_impl(s_service_impl) << "if (" << retvar << ".__isset_" << prop_name(*x_iter) |
| << ") then begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << exceptvar << " := " << retvar << "." << prop_name(*x_iter) |
| << ".CreateException;" << endl; |
| indent_impl(s_service_impl) << "raise " << exceptvar << ";" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| } |
| |
| if (!(*f_iter)->get_returntype()->is_void()) { |
| indent_impl(s_service_impl) |
| << "raise TApplicationExceptionMissingResult.Create('" |
| << (*f_iter)->get_name() << " failed: unknown result');" << endl; |
| } |
| |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| } |
| } |
| |
| indent_down(); |
| indent(s_service) << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_service_server(t_service* tservice) { |
| vector<t_function*> functions = tservice->get_functions(); |
| vector<t_function*>::iterator f_iter; |
| |
| string extends = ""; |
| string extends_processor = ""; |
| |
| string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl"; |
| |
| if (tservice->get_extends() != nullptr) { |
| extends = type_name(tservice->get_extends(), true, true); |
| extends_processor = extends + ".TProcessorImpl"; |
| indent(s_service) << "TProcessorImpl = class(" << extends_processor << ", IProcessor)" << endl; |
| } else { |
| indent(s_service) << "TProcessorImpl = class( TInterfacedObject, IProcessor)" << endl; |
| } |
| |
| indent(s_service) << "public" << endl; |
| indent_up(); |
| indent(s_service) << "constructor Create( iface_: Iface );" << endl; |
| indent(s_service) << "destructor Destroy; override;" << endl; |
| indent_down(); |
| |
| indent_impl(s_service_impl) << "constructor " << full_cls << ".Create( iface_: Iface );" << endl; |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| if (tservice->get_extends() != nullptr) { |
| indent_impl(s_service_impl) << "inherited Create( iface_);" << endl; |
| } else { |
| indent_impl(s_service_impl) << "inherited Create;" << endl; |
| } |
| indent_impl(s_service_impl) << "Self.iface_ := iface_;" << endl; |
| if (tservice->get_extends() != nullptr) { |
| indent_impl(s_service_impl) << "ASSERT( processMap_ <> nil); // inherited" << endl; |
| } else { |
| indent_impl(s_service_impl) |
| << "processMap_ := TThriftDictionaryImpl<string, TProcessFunction>.Create;" << endl; |
| } |
| |
| for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { |
| indent_impl(s_service_impl) << "processMap_.AddOrSetValue( '" << (*f_iter)->get_name() << "', " |
| << (*f_iter)->get_name() << "_Process);" << endl; |
| } |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| |
| indent_impl(s_service_impl) << "destructor " << full_cls << ".Destroy;" << endl; |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "inherited;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| |
| indent(s_service) << "private" << endl; |
| indent_up(); |
| indent(s_service) << "iface_: Iface;" << endl; |
| indent_down(); |
| |
| if (tservice->get_extends() == nullptr) { |
| indent(s_service) << "protected" << endl; |
| indent_up(); |
| indent(s_service) << "type" << endl; |
| indent_up(); |
| indent(s_service) << "TProcessFunction = reference to procedure( seqid: System.Integer; const iprot: " |
| "IProtocol; const oprot: IProtocol" |
| << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; |
| indent_down(); |
| indent_down(); |
| indent(s_service) << "protected" << endl; |
| indent_up(); |
| indent(s_service) << "processMap_: IThriftDictionary<string, TProcessFunction>;" << endl; |
| indent_down(); |
| } |
| |
| indent(s_service) << "public" << endl; |
| indent_up(); |
| if (extends.empty()) { |
| indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const " |
| "events : IProcessorEvents): System.Boolean;" << endl; |
| } else { |
| indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const " |
| "events : IProcessorEvents): System.Boolean; reintroduce;" << endl; |
| } |
| |
| indent_impl(s_service_impl) << "function " << full_cls << ".Process( const iprot: IProtocol; " |
| "const oprot: IProtocol; const events " |
| ": IProcessorEvents): System.Boolean;" << endl; |
| ; |
| indent_impl(s_service_impl) << "var" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "msg : Thrift.Protocol.TThriftMessage;" << endl; |
| indent_impl(s_service_impl) << "fn : TProcessFunction;" << endl; |
| indent_impl(s_service_impl) << "x : TApplicationException;" << endl; |
| if (events_) { |
| indent_impl(s_service_impl) << "context : IRequestEvents;" << endl; |
| } |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "try" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "msg := iprot.ReadMessageBegin();" << endl; |
| indent_impl(s_service_impl) << "fn := nil;" << endl; |
| indent_impl(s_service_impl) << "if not processMap_.TryGetValue(msg.Name, fn)" << endl; |
| indent_impl(s_service_impl) << "or not Assigned(fn) then begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "TProtocolUtil.Skip(iprot, TType.Struct);" << endl; |
| indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl; |
| indent_impl(s_service_impl) << "x := " |
| "TApplicationExceptionUnknownMethod.Create(" |
| "'Invalid method name: ''' + msg.Name + '''');" << endl; |
| indent_impl(s_service_impl) |
| << "Thrift.Protocol.Init( msg, msg.Name, TMessageType.Exception, msg.SeqID);" |
| << endl; |
| indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl; |
| indent_impl(s_service_impl) << "x.Write(oprot);" << endl; |
| indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; |
| indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; |
| indent_impl(s_service_impl) << "Result := True;" << endl; |
| indent_impl(s_service_impl) << "Exit;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| if (events_) { |
| indent_impl(s_service_impl) << "if events <> nil" << endl; |
| indent_impl(s_service_impl) << "then context := events.CreateRequestContext(msg.Name)" << endl; |
| indent_impl(s_service_impl) << "else context := nil;" << endl; |
| indent_impl(s_service_impl) << "try" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot, context);" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "finally" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "if context <> nil then begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "context.CleanupContext;" << endl; |
| indent_impl(s_service_impl) << "context := nil;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| } else { |
| indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot);" << endl; |
| } |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "except" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "on TTransportExceptionTimedOut do begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "Result := True;" << endl; |
| indent_impl(s_service_impl) << "Exit;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| indent_impl(s_service_impl) << "else begin" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "Result := False;" << endl; |
| indent_impl(s_service_impl) << "Exit;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| indent_impl(s_service_impl) << "Result := True;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| |
| for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { |
| generate_process_function(tservice, *f_iter); |
| } |
| |
| indent_down(); |
| indent(s_service) << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_function_helpers(t_function* tfunction) { |
| if (tfunction->is_oneway()) { |
| return; |
| } |
| |
| t_struct result(program_, tfunction->get_name() + "_result"); |
| t_field success(tfunction->get_returntype(), "Success", 0); |
| if (!tfunction->get_returntype()->is_void()) { |
| result.append(&success); |
| } |
| |
| t_struct* xs = tfunction->get_xceptions(); |
| const vector<t_field*>& fields = xs->get_members(); |
| vector<t_field*>::const_iterator f_iter; |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| result.append(*f_iter); |
| } |
| |
| generate_delphi_struct_definition(s_service, &result, false, true, true); |
| generate_delphi_struct_impl(s_service_impl, |
| normalize_clsnm(service_name_, "T") + ".", |
| &result, |
| false); |
| } |
| |
| void t_delphi_generator::generate_process_function(t_service* tservice, t_function* tfunction) { |
| (void)tservice; |
| string funcname = tfunction->get_name(); |
| string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl"; |
| |
| string org_argsname = funcname + "_args"; |
| string args_clsnm = normalize_clsnm(org_argsname, "T"); |
| string args_intfnm = normalize_clsnm(org_argsname, "I"); |
| |
| string org_resultname = funcname + "_result"; |
| string result_clsnm = normalize_clsnm(org_resultname, "T"); |
| string result_intfnm = normalize_clsnm(org_resultname, "I"); |
| |
| indent(s_service) << "procedure " << funcname |
| << "_Process( seqid: System.Integer; const iprot: IProtocol; const oprot: IProtocol" |
| << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; |
| |
| if (tfunction->is_oneway()) { |
| indent_impl(s_service_impl) << "// one way processor" << endl; |
| } else { |
| indent_impl(s_service_impl) << "// both way processor" << endl; |
| } |
| |
| indent_impl(s_service_impl) |
| << "procedure " << full_cls << "." << funcname |
| << "_Process( seqid: System.Integer; const iprot: IProtocol; const oprot: IProtocol" |
| << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl; |
| indent_impl(s_service_impl) << "var" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "args: " << args_intfnm << ";" << endl; |
| if (!tfunction->is_oneway()) { |
| indent_impl(s_service_impl) << "msg: Thrift.Protocol.TThriftMessage;" << endl; |
| indent_impl(s_service_impl) << "ret: " << result_intfnm << ";" << endl; |
| indent_impl(s_service_impl) << "appx : TApplicationException;" << endl; |
| } |
| |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "begin" << endl; |
| indent_up_impl(); |
| |
| if (events_) { |
| indent_impl(s_service_impl) << "if events <> nil then events.PreRead;" << endl; |
| } |
| indent_impl(s_service_impl) << "args := " << args_clsnm << "Impl.Create;" << endl; |
| indent_impl(s_service_impl) << "args.Read(iprot);" << endl; |
| indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl; |
| if (events_) { |
| indent_impl(s_service_impl) << "if events <> nil then events.PostRead;" << endl; |
| } |
| |
| t_struct* xs = tfunction->get_xceptions(); |
| const std::vector<t_field*>& xceptions = xs->get_members(); |
| vector<t_field*>::const_iterator x_iter; |
| |
| if (!tfunction->is_oneway()) { |
| indent_impl(s_service_impl) << "ret := " << result_clsnm << "Impl.Create;" << endl; |
| } |
| |
| indent_impl(s_service_impl) << "try" << endl; |
| indent_up_impl(); |
| |
| t_struct* arg_struct = tfunction->get_arglist(); |
| const std::vector<t_field*>& fields = arg_struct->get_members(); |
| vector<t_field*>::const_iterator f_iter; |
| |
| s_service_impl << indent_impl(); |
| if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) { |
| s_service_impl << "ret.Success := "; |
| } |
| s_service_impl << "iface_." << normalize_name(tfunction->get_name(), true) << "("; |
| bool first = true; |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| if (first) { |
| first = false; |
| } else { |
| s_service_impl << ", "; |
| } |
| s_service_impl << "args." << prop_name(*f_iter); |
| } |
| s_service_impl << ");" << endl; |
| |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| indent_impl(s_service_impl) << "args." << prop_name(*f_iter) |
| << " := " << empty_value((*f_iter)->get_type()) << ";" << endl; |
| } |
| |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "except" << endl; |
| indent_up_impl(); |
| |
| for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { |
| indent_impl(s_service_impl) << "on E: " << type_name((*x_iter)->get_type(), true, true) |
| << " do begin" << endl; |
| indent_up_impl(); |
| if (!tfunction->is_oneway()) { |
| string factory_name = normalize_clsnm((*x_iter)->get_type()->get_name(), "", true) |
| + "Factory"; |
| indent_impl(s_service_impl) << "ret." << prop_name(*x_iter) << " := E." << factory_name << ";" |
| << endl; |
| } |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| } |
| |
| indent_impl(s_service_impl) << "on E: Exception do begin" << endl; |
| indent_up_impl(); |
| if(events_) { |
| indent_impl(s_service_impl) << "if events <> nil then events.UnhandledError(E);" << endl; |
| } |
| if (!tfunction->is_oneway()) { |
| indent_impl(s_service_impl) << "appx := TApplicationExceptionInternalError.Create(E.Message);" |
| << endl; |
| indent_impl(s_service_impl) << "try" << endl; |
| indent_up_impl(); |
| if(events_) { |
| indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl; |
| } |
| indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '" |
| << tfunction->get_name() << "', TMessageType.Exception, seqid);" |
| << endl; |
| indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl; |
| indent_impl(s_service_impl) << "appx.Write(oprot);" << endl; |
| indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; |
| indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; |
| if(events_) { |
| indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl; |
| } |
| indent_impl(s_service_impl) << "Exit;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "finally" << endl; |
| indent_up_impl(); |
| indent_impl(s_service_impl) << "appx.Free;" << endl; |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| } |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl; |
| |
| if (!tfunction->is_oneway()) { |
| if (events_) { |
| indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl; |
| } |
| indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '" |
| << tfunction->get_name() << "', TMessageType.Reply, seqid); " |
| << endl; |
| indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg); " << endl; |
| indent_impl(s_service_impl) << "ret.Write(oprot);" << endl; |
| indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl; |
| indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl; |
| if (events_) { |
| indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl; |
| } |
| } else if (events_) { |
| indent_impl(s_service_impl) << "if events <> nil then events.OnewayComplete;" << endl; |
| } |
| |
| indent_down_impl(); |
| indent_impl(s_service_impl) << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_deserialize_field(ostream& out, |
| bool is_xception, |
| t_field* tfield, |
| string prefix, |
| ostream& local_vars) { |
| t_type* type = tfield->get_type(); |
| while (type->is_typedef()) { |
| type = ((t_typedef*)type)->get_type(); |
| } |
| |
| if (type->is_void()) { |
| throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); |
| } |
| |
| string name = prefix + prop_name(tfield, is_xception); |
| |
| if (type->is_struct() || type->is_xception()) { |
| generate_deserialize_struct(out, (t_struct*)type, name, ""); |
| } else if (type->is_container()) { |
| generate_deserialize_container(out, is_xception, type, name, local_vars); |
| } else if (type->is_base_type() || type->is_enum()) { |
| indent_impl(out) << name << " := "; |
| |
| if (type->is_enum()) { |
| out << type_name(type, false) << "("; |
| } |
| |
| out << "iprot."; |
| |
| 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 "compiler error: cannot serialize void field in a struct: " + name; |
| break; |
| case t_base_type::TYPE_STRING: |
| if (type->is_binary()) { |
| if (ansistr_binary_) { |
| out << "ReadAnsiString();"; |
| } else { |
| out << "ReadBinary();"; |
| } |
| } else { |
| out << "ReadString();"; |
| } |
| break; |
| case t_base_type::TYPE_BOOL: |
| out << "ReadBool();"; |
| break; |
| case t_base_type::TYPE_I8: |
| out << "ReadByte();"; |
| break; |
| case t_base_type::TYPE_I16: |
| out << "ReadI16();"; |
| break; |
| case t_base_type::TYPE_I32: |
| out << "ReadI32();"; |
| break; |
| case t_base_type::TYPE_I64: |
| out << "ReadI64();"; |
| break; |
| case t_base_type::TYPE_DOUBLE: |
| out << "ReadDouble();"; |
| break; |
| default: |
| throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase); |
| } |
| } else if (type->is_enum()) { |
| out << "ReadI32()"; |
| out << ");"; |
| } |
| out << endl; |
| } else { |
| printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", |
| tfield->get_name().c_str(), |
| type_name(type).c_str()); |
| } |
| } |
| |
| void t_delphi_generator::generate_deserialize_struct(ostream& out, |
| t_struct* tstruct, |
| string name, |
| string prefix) { |
| string typ_name; |
| |
| if (tstruct->is_xception()) { |
| typ_name = type_name(tstruct, true, false, true, true); |
| } else { |
| typ_name = type_name(tstruct, true, false); |
| } |
| |
| indent_impl(out) << prefix << name << " := " << typ_name << ".Create;" << endl; |
| indent_impl(out) << prefix << name << ".Read(iprot);" << endl; |
| } |
| |
| void t_delphi_generator::generate_deserialize_container(ostream& out, |
| bool is_xception, |
| t_type* ttype, |
| string name, |
| std::ostream& local_vars) { |
| |
| string obj; |
| string counter; |
| string local_var; |
| |
| if (ttype->is_map()) { |
| obj = tmp("_map"); |
| } else if (ttype->is_set()) { |
| obj = tmp("_set"); |
| } else if (ttype->is_list()) { |
| obj = tmp("_list"); |
| } |
| |
| if (ttype->is_map()) { |
| local_var = obj + ": TThriftMap;"; |
| } else if (ttype->is_set()) { |
| local_var = obj + ": TThriftSet;"; |
| } else if (ttype->is_list()) { |
| local_var = obj + ": TThriftList;"; |
| } |
| local_vars << " " << local_var << endl; |
| counter = tmp("_i"); |
| local_var = counter + ": System.Integer;"; |
| local_vars << " " << local_var << endl; |
| |
| indent_impl(out) << name << " := " << type_name(ttype, true) << ".Create;" << endl; |
| |
| if (ttype->is_map()) { |
| indent_impl(out) << obj << " := iprot.ReadMapBegin();" << endl; |
| } else if (ttype->is_set()) { |
| indent_impl(out) << obj << " := iprot.ReadSetBegin();" << endl; |
| } else if (ttype->is_list()) { |
| indent_impl(out) << obj << " := iprot.ReadListBegin();" << endl; |
| } |
| |
| indent_impl(out) << "for " << counter << " := 0 to " << obj << ".Count - 1 do begin" << endl; |
| indent_up_impl(); |
| if (ttype->is_map()) { |
| generate_deserialize_map_element(out, is_xception, (t_map*)ttype, name, local_vars); |
| } else if (ttype->is_set()) { |
| generate_deserialize_set_element(out, is_xception, (t_set*)ttype, name, local_vars); |
| } else if (ttype->is_list()) { |
| generate_deserialize_list_element(out, is_xception, (t_list*)ttype, name, local_vars); |
| } |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl; |
| |
| if (ttype->is_map()) { |
| indent_impl(out) << "iprot.ReadMapEnd();" << endl; |
| } else if (ttype->is_set()) { |
| indent_impl(out) << "iprot.ReadSetEnd();" << endl; |
| } else if (ttype->is_list()) { |
| indent_impl(out) << "iprot.ReadListEnd();" << endl; |
| } |
| } |
| |
| void t_delphi_generator::generate_deserialize_map_element(ostream& out, |
| bool is_xception, |
| t_map* tmap, |
| string prefix, |
| ostream& local_vars) { |
| |
| string key = tmp("_key"); |
| string val = tmp("_val"); |
| string local_var; |
| |
| t_field fkey(tmap->get_key_type(), key); |
| t_field fval(tmap->get_val_type(), val); |
| |
| local_vars << " " << declare_field(&fkey) << endl; |
| local_vars << " " << declare_field(&fval) << endl; |
| |
| generate_deserialize_field(out, is_xception, &fkey, "", local_vars); |
| generate_deserialize_field(out, is_xception, &fval, "", local_vars); |
| |
| indent_impl(out) << prefix << ".AddOrSetValue( " << key << ", " << val << ");" << endl; |
| } |
| |
| void t_delphi_generator::generate_deserialize_set_element(ostream& out, |
| bool is_xception, |
| t_set* tset, |
| string prefix, |
| ostream& local_vars) { |
| string elem = tmp("_elem"); |
| t_field felem(tset->get_elem_type(), elem); |
| local_vars << " " << declare_field(&felem) << endl; |
| generate_deserialize_field(out, is_xception, &felem, "", local_vars); |
| indent_impl(out) << prefix << ".Add(" << elem << ");" << endl; |
| } |
| |
| void t_delphi_generator::generate_deserialize_list_element(ostream& out, |
| bool is_xception, |
| t_list* tlist, |
| string prefix, |
| ostream& local_vars) { |
| string elem = tmp("_elem"); |
| t_field felem(tlist->get_elem_type(), elem); |
| local_vars << " " << declare_field(&felem) << endl; |
| generate_deserialize_field(out, is_xception, &felem, "", local_vars); |
| indent_impl(out) << prefix << ".Add(" << elem << ");" << endl; |
| } |
| |
| void t_delphi_generator::generate_serialize_field(ostream& out, |
| bool is_xception, |
| t_field* tfield, |
| string prefix, |
| ostream& local_vars) { |
| (void)local_vars; |
| |
| t_type* type = tfield->get_type(); |
| while (type->is_typedef()) { |
| type = ((t_typedef*)type)->get_type(); |
| } |
| |
| string name = prefix + prop_name(tfield, is_xception); |
| |
| if (type->is_void()) { |
| throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name; |
| } |
| |
| if (type->is_struct() || type->is_xception()) { |
| generate_serialize_struct(out, (t_struct*)type, name, local_vars); |
| } else if (type->is_container()) { |
| generate_serialize_container(out, is_xception, type, name, local_vars); |
| } else if (type->is_base_type() || type->is_enum()) { |
| |
| indent_impl(out) << "oprot."; |
| |
| 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 "compiler error: cannot serialize void field in a struct: " + name; |
| break; |
| case t_base_type::TYPE_STRING: |
| if (type->is_binary()) { |
| if (ansistr_binary_) { |
| out << "WriteAnsiString("; |
| } else { |
| out << "WriteBinary("; |
| } |
| } else { |
| out << "WriteString("; |
| } |
| out << name << ");"; |
| break; |
| case t_base_type::TYPE_BOOL: |
| out << "WriteBool(" << name << ");"; |
| break; |
| case t_base_type::TYPE_I8: |
| out << "WriteByte(" << name << ");"; |
| break; |
| case t_base_type::TYPE_I16: |
| out << "WriteI16(" << name << ");"; |
| break; |
| case t_base_type::TYPE_I32: |
| out << "WriteI32(" << name << ");"; |
| break; |
| case t_base_type::TYPE_I64: |
| out << "WriteI64(" << name << ");"; |
| break; |
| case t_base_type::TYPE_DOUBLE: |
| out << "WriteDouble(" << name << ");"; |
| break; |
| default: |
| throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase); |
| } |
| } else if (type->is_enum()) { |
| out << "WriteI32(System.Integer(" << name << "));"; |
| } |
| out << endl; |
| } else { |
| printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n", |
| prefix.c_str(), |
| tfield->get_name().c_str(), |
| type_name(type).c_str()); |
| } |
| } |
| |
| void t_delphi_generator::generate_serialize_struct(ostream& out, |
| t_struct* tstruct, |
| string prefix, |
| ostream& local_vars) { |
| (void)local_vars; |
| (void)tstruct; |
| out << indent_impl() << prefix << ".Write(oprot);" << endl; |
| } |
| |
| void t_delphi_generator::generate_serialize_container(ostream& out, |
| bool is_xception, |
| t_type* ttype, |
| string prefix, |
| ostream& local_vars) { |
| string obj; |
| if (ttype->is_map()) { |
| obj = tmp("map"); |
| local_vars << " " << obj << " : TThriftMap;" << endl; |
| indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " |
| << type_to_enum(((t_map*)ttype)->get_key_type()) << ", " |
| << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix |
| << ".Count);" << endl; |
| indent_impl(out) << "oprot.WriteMapBegin( " << obj << ");" << endl; |
| } else if (ttype->is_set()) { |
| obj = tmp("set_"); |
| local_vars << " " << obj << " : TThriftSet;" << endl; |
| indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " |
| << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix |
| << ".Count);" << endl; |
| indent_impl(out) << "oprot.WriteSetBegin( " << obj << ");" << endl; |
| } else if (ttype->is_list()) { |
| obj = tmp("list_"); |
| local_vars << " " << obj << " : TThriftList;" << endl; |
| indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", " |
| << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix |
| << ".Count);" << endl; |
| indent_impl(out) << "oprot.WriteListBegin( " << obj << ");" << endl; |
| } |
| |
| string iter = tmp("_iter"); |
| if (ttype->is_map()) { |
| local_vars << " " << iter << ": " << type_name(((t_map*)ttype)->get_key_type()) << ";" << endl; |
| indent_impl(out) << "for " << iter << " in " << prefix << ".Keys do begin" << endl; |
| indent_up_impl(); |
| } else if (ttype->is_set()) { |
| local_vars << " " << iter << ": " << type_name(((t_set*)ttype)->get_elem_type()) << ";" |
| << endl; |
| indent_impl(out) << "for " << iter << " in " << prefix << " do begin" << endl; |
| indent_up_impl(); |
| } else if (ttype->is_list()) { |
| local_vars << " " << iter << ": " << type_name(((t_list*)ttype)->get_elem_type()) << ";" |
| << endl; |
| indent_impl(out) << "for " << iter << " in " << prefix << " do begin" << endl; |
| indent_up_impl(); |
| } |
| |
| if (ttype->is_map()) { |
| generate_serialize_map_element(out, is_xception, (t_map*)ttype, iter, prefix, local_vars); |
| } else if (ttype->is_set()) { |
| generate_serialize_set_element(out, is_xception, (t_set*)ttype, iter, local_vars); |
| } else if (ttype->is_list()) { |
| generate_serialize_list_element(out, is_xception, (t_list*)ttype, iter, local_vars); |
| } |
| |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl; |
| |
| if (ttype->is_map()) { |
| indent_impl(out) << "oprot.WriteMapEnd();" << endl; |
| } else if (ttype->is_set()) { |
| indent_impl(out) << "oprot.WriteSetEnd();" << endl; |
| } else if (ttype->is_list()) { |
| indent_impl(out) << "oprot.WriteListEnd();" << endl; |
| } |
| } |
| |
| void t_delphi_generator::generate_serialize_map_element(ostream& out, |
| bool is_xception, |
| t_map* tmap, |
| string iter, |
| string map, |
| ostream& local_vars) { |
| t_field kfield(tmap->get_key_type(), iter); |
| generate_serialize_field(out, is_xception, &kfield, "", local_vars); |
| t_field vfield(tmap->get_val_type(), map + "[" + iter + "]"); |
| generate_serialize_field(out, is_xception, &vfield, "", local_vars); |
| } |
| |
| void t_delphi_generator::generate_serialize_set_element(ostream& out, |
| bool is_xception, |
| t_set* tset, |
| string iter, |
| ostream& local_vars) { |
| t_field efield(tset->get_elem_type(), iter); |
| generate_serialize_field(out, is_xception, &efield, "", local_vars); |
| } |
| |
| void t_delphi_generator::generate_serialize_list_element(ostream& out, |
| bool is_xception, |
| t_list* tlist, |
| string iter, |
| ostream& local_vars) { |
| t_field efield(tlist->get_elem_type(), iter); |
| generate_serialize_field(out, is_xception, &efield, "", local_vars); |
| } |
| |
| void t_delphi_generator::generate_property(ostream& out, |
| t_field* tfield, |
| bool isPublic, |
| bool is_xception) { |
| generate_delphi_property(out, is_xception, tfield, isPublic, "Get"); |
| } |
| |
| void t_delphi_generator::generate_delphi_property(ostream& out, |
| bool struct_is_xception, |
| t_field* tfield, |
| bool isPublic, |
| std::string fieldPrefix) { |
| (void)isPublic; |
| |
| t_type* ftype = tfield->get_type(); |
| bool is_xception = ftype->is_xception(); |
| generate_delphi_doc(out, tfield); |
| indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": " |
| << type_name(ftype, false, true, is_xception, true) << " read " |
| << fieldPrefix + prop_name(tfield, struct_is_xception) << " write Set" |
| << prop_name(tfield, struct_is_xception) << ";" << endl; |
| } |
| |
| std::string t_delphi_generator::prop_name(t_field* tfield, bool is_xception) { |
| return prop_name(tfield->get_name(), is_xception); |
| } |
| |
| std::string t_delphi_generator::prop_name(string name, bool is_xception) { |
| string ret = name; |
| ret[0] = toupper(ret[0]); |
| return normalize_name(ret, true, is_xception); |
| } |
| |
| std::string t_delphi_generator::constructor_param_name(string name) { |
| string ret = name; |
| ret[0] = toupper(ret[0]); |
| ret = "A" + ret; |
| return normalize_name(ret, false, false); |
| } |
| |
| string t_delphi_generator::normalize_clsnm(string clsnm, string prefix, bool b_no_check_keyword) { |
| if (clsnm.size() > 0) { |
| clsnm[0] = toupper(clsnm[0]); |
| } |
| if (b_no_check_keyword) { |
| return prefix + clsnm; |
| } else { |
| return normalize_name(prefix + clsnm); |
| } |
| } |
| |
| string t_delphi_generator::type_name(t_type* ttype, |
| bool b_cls, |
| bool b_no_postfix, |
| bool b_exception_factory, |
| bool b_full_exception_factory) { |
| |
| if (ttype->is_typedef()) { |
| t_typedef* tdef = (t_typedef*)ttype; |
| if (tdef->is_forward_typedef()) { // forward types according to THRIFT-2421 |
| if (tdef->get_type() != nullptr) { |
| return type_name(tdef->get_type(), |
| b_cls, |
| b_no_postfix, |
| b_exception_factory, |
| b_full_exception_factory); |
| } else { |
| throw "unresolved forward declaration: " + tdef->get_symbolic(); |
| } |
| } else { |
| return normalize_name("T" + tdef->get_symbolic()); |
| } |
| } |
| |
| string typ_nm; |
| |
| string s_factory; |
| |
| if (ttype->is_base_type()) { |
| return base_type_name((t_base_type*)ttype); |
| } else if (ttype->is_enum()) { |
| b_cls = true; |
| b_no_postfix = true; |
| } else if (ttype->is_map()) { |
| t_map* tmap = (t_map*)ttype; |
| if (b_cls) { |
| typ_nm = "TThriftDictionaryImpl"; |
| } else { |
| typ_nm = "IThriftDictionary"; |
| } |
| return typ_nm + "<" + type_name(tmap->get_key_type()) + ", " + type_name(tmap->get_val_type()) |
| + ">"; |
| } else if (ttype->is_set()) { |
| t_set* tset = (t_set*)ttype; |
| if (b_cls) { |
| typ_nm = "THashSetImpl"; |
| } else { |
| typ_nm = "IHashSet"; |
| } |
| return typ_nm + "<" + type_name(tset->get_elem_type()) + ">"; |
| } else if (ttype->is_list()) { |
| t_list* tlist = (t_list*)ttype; |
| if (b_cls) { |
| typ_nm = "TThriftListImpl"; |
| } else { |
| typ_nm = "IThriftList"; |
| } |
| return typ_nm + "<" + type_name(tlist->get_elem_type()) + ">"; |
| } |
| |
| string type_prefix; |
| |
| if (b_cls) { |
| type_prefix = "T"; |
| } else { |
| type_prefix = "I"; |
| } |
| |
| string nm = normalize_clsnm(ttype->get_name(), type_prefix); |
| |
| if (b_exception_factory) { |
| nm = nm + "Factory"; |
| } |
| |
| if (b_cls) { |
| if (!b_no_postfix) { |
| nm = nm + "Impl"; |
| } |
| } |
| |
| if (b_exception_factory && b_full_exception_factory) { |
| return type_name(ttype, true, true, false, false) + "." + nm; |
| } |
| |
| return nm; |
| } |
| |
| // returns "const " for some argument types |
| string t_delphi_generator::input_arg_prefix(t_type* ttype) { |
| |
| // base types |
| if (ttype->is_base_type()) { |
| switch (((t_base_type*)ttype)->get_base()) { |
| |
| // these should be const'ed for optimal performamce |
| case t_base_type::TYPE_STRING: // refcounted pointer |
| case t_base_type::TYPE_I64: // larger than 32 bit |
| case t_base_type::TYPE_DOUBLE: // larger than 32 bit |
| return "const "; |
| |
| // all others don't need to be |
| case t_base_type::TYPE_I8: |
| case t_base_type::TYPE_I16: |
| case t_base_type::TYPE_I32: |
| case t_base_type::TYPE_BOOL: |
| case t_base_type::TYPE_VOID: |
| return ""; |
| |
| // we better always report any unknown types |
| default: |
| throw "compiler error: no input_arg_prefix() for base type " |
| + t_base_type::t_base_name(((t_base_type*)ttype)->get_base()); |
| } |
| |
| // enums |
| } else if (ttype->is_enum()) { |
| return ""; // usually <= 32 bit |
| |
| // containers |
| } else if (ttype->is_map()) { |
| return "const "; // refcounted pointer |
| |
| } else if (ttype->is_set()) { |
| return "const "; // refcounted pointer |
| |
| } else if (ttype->is_list()) { |
| return "const "; // refcounted pointer |
| } |
| |
| // any other type, either TSomething or ISomething |
| return "const "; // possibly refcounted pointer |
| } |
| |
| string t_delphi_generator::base_type_name(t_base_type* tbase) { |
| switch (tbase->get_base()) { |
| case t_base_type::TYPE_VOID: |
| // no "void" in Delphi language |
| return ""; |
| case t_base_type::TYPE_STRING: |
| if (tbase->is_binary()) { |
| if (ansistr_binary_) { |
| return "System.AnsiString"; |
| } else { |
| return "SysUtils.TBytes"; |
| } |
| } else { |
| return "System.string"; |
| } |
| case t_base_type::TYPE_BOOL: |
| return "System.Boolean"; |
| case t_base_type::TYPE_I8: |
| return "System.ShortInt"; |
| case t_base_type::TYPE_I16: |
| return "System.SmallInt"; |
| case t_base_type::TYPE_I32: |
| return "System.Integer"; |
| case t_base_type::TYPE_I64: |
| return "System.Int64"; |
| case t_base_type::TYPE_DOUBLE: |
| return "System.Double"; |
| default: |
| throw "compiler error: no Delphi name for base type " |
| + t_base_type::t_base_name(tbase->get_base()); |
| } |
| } |
| |
| string t_delphi_generator::declare_field(t_field* tfield, |
| bool init, |
| std::string prefix, |
| bool is_xception_class) { |
| (void)init; |
| |
| t_type* ftype = tfield->get_type(); |
| bool is_xception = ftype->is_xception(); |
| |
| string result = prefix + prop_name(tfield, is_xception_class) + ": " |
| + type_name(ftype, false, true, is_xception, true) + ";"; |
| return result; |
| } |
| |
| string t_delphi_generator::function_signature(t_function* tfunction, |
| bool for_async, |
| std::string full_cls, |
| bool is_xception) { |
| t_type* ttype = tfunction->get_returntype(); |
| string prefix; |
| if (full_cls == "") { |
| prefix = ""; |
| } else { |
| prefix = full_cls + "."; |
| } |
| |
| string signature = ""; |
| |
| if( for_async) { |
| if (is_void(ttype)) { |
| signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "Async(" |
| + argument_list(tfunction->get_arglist()) + "): IFuture<Integer>;"; // no IFuture<void> in Delphi |
| } else { |
| signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "Async(" |
| + argument_list(tfunction->get_arglist()) + "): IFuture<" |
| + type_name(ttype, false, true, is_xception, true) + ">;"; |
| } |
| } else { |
| if (is_void(ttype)) { |
| signature = "procedure " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "(" |
| + argument_list(tfunction->get_arglist()) + ");"; |
| } else { |
| signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "(" |
| + argument_list(tfunction->get_arglist()) + "): " |
| + type_name(ttype, false, true, is_xception, true) + ";"; |
| } |
| } |
| |
| // deprecated method? only at intf decl! |
| if( full_cls == "") { |
| auto iter = tfunction->annotations_.find("deprecated"); |
| if( tfunction->annotations_.end() != iter) { |
| signature += " deprecated"; |
| // empty annotation values end up with "1" somewhere, ignore these as well |
| if ((iter->second.length() > 0) && (iter->second != "1")) { |
| signature += " " + make_pascal_string_literal(iter->second); |
| } |
| signature += ";"; |
| } |
| } |
| |
| return signature; |
| } |
| |
| string t_delphi_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; |
| t_type* tt; |
| |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| if (first) { |
| first = false; |
| } else { |
| result += "; "; |
| } |
| |
| tt = (*f_iter)->get_type(); |
| result += input_arg_prefix(tt); // const? |
| result += normalize_name((*f_iter)->get_name()) + ": " |
| + type_name(tt, false, true, tt->is_xception(), true); |
| } |
| return result; |
| } |
| |
| string t_delphi_generator::constructor_argument_list(t_struct* tstruct, string current_indent) { |
| ostringstream result; |
| const vector<t_field*>& fields = tstruct->get_members(); |
| vector<t_field*>::const_iterator f_iter; |
| bool first = true; |
| t_type* tt; |
| string line = ""; |
| string newline_indent = current_indent + " "; |
| |
| bool firstline = true; |
| |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| if (first) { |
| first = false; |
| } else { |
| line += ";"; |
| } |
| |
| if (line.size() > 80) { |
| if (firstline) { |
| result << endl << newline_indent; |
| firstline = false; |
| } |
| result << line << endl; |
| line = newline_indent; |
| } else if (line.size() > 0) { |
| line += " "; |
| } |
| |
| tt = (*f_iter)->get_type(); |
| line += input_arg_prefix(tt); // const? |
| line += constructor_param_name((*f_iter)->get_name()) + ": " |
| + type_name(tt, false, true, tt->is_xception(), true); |
| } |
| |
| if (line.size() > 0) { |
| result << line; |
| } |
| |
| string result_str; |
| |
| if (firstline) { |
| result_str = " " + result.str(); |
| } else { |
| result_str = result.str(); |
| } |
| |
| return result_str; |
| } |
| |
| string t_delphi_generator::type_to_enum(t_type* type) { |
| while (type->is_typedef()) { |
| type = ((t_typedef*)type)->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_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_I8: |
| 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(); |
| } |
| |
| string t_delphi_generator::empty_value(t_type* type) { |
| while (type->is_typedef()) { |
| type = ((t_typedef*)type)->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_VOID: |
| return "0"; |
| case t_base_type::TYPE_STRING: |
| if (type->is_binary()) { |
| if (ansistr_binary_) { |
| return "''"; |
| } else { |
| return "nil"; |
| } |
| } else { |
| return "''"; |
| } |
| case t_base_type::TYPE_BOOL: |
| return "False"; |
| case t_base_type::TYPE_I8: |
| case t_base_type::TYPE_I16: |
| case t_base_type::TYPE_I32: |
| case t_base_type::TYPE_I64: |
| return "0"; |
| case t_base_type::TYPE_DOUBLE: |
| return "0.0"; |
| } |
| } else if (type->is_enum()) { |
| return "T" + type->get_name() + "(0)"; |
| } else if (type->is_struct() || type->is_xception()) { |
| return "nil"; |
| } else if (type->is_map()) { |
| return "nil"; |
| } else if (type->is_set()) { |
| return "nil"; |
| } else if (type->is_list()) { |
| return "nil"; |
| } |
| |
| throw "INVALID TYPE IN type_to_enum: " + type->get_name(); |
| } |
| |
| void t_delphi_generator::generate_delphi_property_writer_definition(ostream& out, |
| t_field* tfield, |
| bool is_xception_class) { |
| t_type* ftype = tfield->get_type(); |
| bool is_xception = ftype->is_xception(); |
| |
| indent(out) << "procedure Set" << prop_name(tfield, is_xception_class) |
| << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");" |
| << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_property_reader_definition(ostream& out, |
| t_field* tfield, |
| bool is_xception_class) { |
| t_type* ftype = tfield->get_type(); |
| bool is_xception = ftype->is_xception(); |
| |
| indent(out) << "function Get" << prop_name(tfield, is_xception_class) << ": " |
| << type_name(ftype, false, true, is_xception, true) << ";" << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_isset_reader_writer_definition(ostream& out, |
| t_field* tfield, |
| bool is_xception) { |
| indent(out) << "function Get__isset_" << prop_name(tfield, is_xception) << ": System.Boolean;" << endl; |
| indent(out) << "procedure Set__isset_" << prop_name(tfield, is_xception) << "( const value : System.Boolean);" << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_clear_union_value(ostream& out, |
| std::string cls_prefix, |
| std::string name, |
| t_type* type, |
| t_field* tfield, |
| std::string fieldPrefix, |
| bool is_xception_class, |
| bool is_union, |
| bool is_xception_factory, |
| std::string xception_factory_name) { |
| (void)cls_prefix; |
| (void)name; |
| (void)type; |
| (void)is_union; |
| (void)is_xception_factory; |
| (void)xception_factory_name; |
| |
| t_type* ftype = tfield->get_type(); |
| bool is_xception = ftype->is_xception(); |
| |
| indent_impl(out) << "if F__isset_" << prop_name(tfield, is_xception_class) << " then begin" |
| << endl; |
| indent_up_impl(); |
| indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := False;" << endl; |
| indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := " |
| << "Default( " << type_name(ftype, false, true, is_xception, true) << ");" |
| << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out, |
| std::string cls_prefix, |
| std::string name, |
| t_type* type, |
| t_field* tfield, |
| std::string fieldPrefix, |
| bool is_xception_class, |
| bool is_union, |
| bool is_xception_factory, |
| std::string xception_factory_name) { |
| (void)type; |
| |
| t_type* ftype = tfield->get_type(); |
| bool is_xception = ftype->is_xception(); |
| |
| indent_impl(out) << "procedure " << cls_prefix << name << "." |
| << "Set" << prop_name(tfield, is_xception_class) |
| << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");" |
| << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| if (is_union) { |
| indent_impl(out) << "ClearUnionValues;" << endl; |
| } |
| if (tfield->get_req() != t_field::T_REQUIRED) { |
| indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := True;" << endl; |
| } |
| indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := Value;" << endl; |
| |
| if (is_xception_class && (!is_xception_factory)) { |
| indent_impl(out) << xception_factory_name << "." << prop_name(tfield, is_xception_class) |
| << " := Value;" << endl; |
| } |
| |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_property_reader_impl(ostream& out, |
| std::string cls_prefix, |
| std::string name, |
| t_type* type, |
| t_field* tfield, |
| std::string fieldPrefix, |
| bool is_xception_class) { |
| (void)type; |
| |
| t_type* ftype = tfield->get_type(); |
| bool is_xception = ftype->is_xception(); |
| |
| indent_impl(out) << "function " << cls_prefix << name << "." |
| << "Get" << prop_name(tfield, is_xception_class) << ": " |
| << type_name(ftype, false, true, is_xception, true) << ";" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "Result := " << fieldPrefix << prop_name(tfield, is_xception_class) << ";" |
| << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_isset_reader_writer_impl(ostream& out, |
| std::string cls_prefix, |
| std::string name, |
| t_type* type, |
| t_field* tfield, |
| std::string fieldPrefix, |
| bool is_xception) { |
| (void)type; |
| |
| string isset_name = "__isset_" + prop_name(tfield, is_xception); |
| |
| indent_impl(out) << "function " << cls_prefix << name << "." |
| << "Get" << isset_name << ": System.Boolean;" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "Result := " << fieldPrefix << isset_name << ";" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| |
| indent_impl(out) << "procedure " << cls_prefix << name << "." |
| << "Set" << isset_name << "( const value: System.Boolean);" << endl; |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(out) << fieldPrefix << isset_name << " := value;" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_create_exception_impl(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception) { |
| (void)cls_prefix; |
| |
| string exception_cls_nm = type_name(tstruct, true, true); |
| string cls_nm = type_name(tstruct, true, false, is_exception, is_exception); |
| |
| indent_impl(out) << "function " << cls_nm << ".CreateException: " << exception_cls_nm << ";" |
| << endl; |
| |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| |
| indent_impl(out) << "Result := " << exception_cls_nm << ".Create;" << endl; |
| string factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory"; |
| indent_impl(out) << "Result.F" << factory_name << " := Self;" << endl; |
| |
| const vector<t_field*>& fields = tstruct->get_members(); |
| vector<t_field*>::const_iterator f_iter; |
| |
| string propname; |
| |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| propname = prop_name(*f_iter, is_exception); |
| if ((*f_iter)->get_req() != t_field::T_REQUIRED) { |
| indent_impl(out) << "if __isset_" << propname << " then begin" << endl; |
| indent_up_impl(); |
| } |
| indent_impl(out) << "Result." << propname << " := " << propname << ";" << endl; |
| if ((*f_iter)->get_req() != t_field::T_REQUIRED) { |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl; |
| } |
| } |
| |
| indent_impl(out) << "Result.UpdateMessageProperty;" << endl; |
| |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| } |
| |
| void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_x_factory) { |
| |
| ostringstream local_vars; |
| ostringstream code_block; |
| |
| const vector<t_field*>& fields = tstruct->get_members(); |
| vector<t_field*>::const_iterator f_iter; |
| |
| indent_impl(code_block) << "begin" << endl; |
| indent_up_impl(); |
| |
| indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; |
| indent_impl(code_block) << "tracker := iprot.NextRecursionLevel;" << endl; |
| |
| // local bools for required fields |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| if ((*f_iter)->get_req() == t_field::T_REQUIRED) { |
| indent_impl(local_vars) << "_req_isset_" << prop_name(*f_iter, is_exception) << " : System.Boolean;" |
| << endl; |
| indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := FALSE;" |
| << endl; |
| } |
| } |
| |
| indent_impl(code_block) << "struc := iprot.ReadStructBegin;" << endl; |
| |
| indent_impl(code_block) << "try" << endl; |
| indent_up_impl(); |
| |
| indent_impl(code_block) << "while (true) do begin" << endl; |
| indent_up_impl(); |
| |
| indent_impl(code_block) << "field_ := iprot.ReadFieldBegin();" << endl; |
| |
| indent_impl(code_block) << "if (field_.Type_ = TType.Stop) then Break;" << endl; |
| |
| bool first = true; |
| |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| |
| if (first) { |
| code_block << endl; |
| indent_impl(code_block) << "case field_.ID of" << endl; |
| indent_up_impl(); |
| } |
| |
| first = false; |
| if (f_iter != fields.begin()) { |
| code_block << endl; |
| } |
| |
| indent_impl(code_block) << (*f_iter)->get_key() << ": begin" << endl; |
| indent_up_impl(); |
| indent_impl(code_block) << "if (field_.Type_ = " << type_to_enum((*f_iter)->get_type()) |
| << ") then begin" << endl; |
| indent_up_impl(); |
| |
| generate_deserialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); |
| |
| // required field? |
| if ((*f_iter)->get_req() == t_field::T_REQUIRED) { |
| indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := TRUE;" |
| << endl; |
| } |
| |
| indent_down_impl(); |
| |
| indent_impl(code_block) << "end else begin" << endl; |
| indent_up_impl(); |
| indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl; |
| indent_down_impl(); |
| indent_impl(code_block) << "end;" << endl; |
| indent_down_impl(); |
| indent_impl(code_block) << "end;"; |
| } |
| |
| if (!first) { |
| code_block << endl; |
| indent_down_impl(); |
| indent_impl(code_block) << "else" << endl; |
| indent_up_impl(); |
| } |
| |
| indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl; |
| |
| if (!first) { |
| indent_down_impl(); |
| indent_impl(code_block) << "end;" << endl; |
| } |
| |
| indent_impl(code_block) << "iprot.ReadFieldEnd;" << endl; |
| |
| indent_down_impl(); |
| |
| indent_impl(code_block) << "end;" << endl; |
| indent_down_impl(); |
| |
| indent_impl(code_block) << "finally" << endl; |
| indent_up_impl(); |
| indent_impl(code_block) << "iprot.ReadStructEnd;" << endl; |
| indent_down_impl(); |
| indent_impl(code_block) << "end;" << endl; |
| |
| // all required fields have been read? |
| first = true; |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| if ((*f_iter)->get_req() == t_field::T_REQUIRED) { |
| if(first) { |
| code_block << endl; |
| first = false; |
| } |
| indent_impl(code_block) << "if not _req_isset_" << prop_name(*f_iter, is_exception) << endl; |
| indent_impl(code_block) |
| << "then raise TProtocolExceptionInvalidData.Create(" |
| << "'required field " << prop_name(*f_iter, is_exception) << " not set');" |
| << endl; |
| } |
| } |
| |
| if( is_exception && (!is_x_factory)) { |
| code_block << endl; |
| indent_impl(code_block) << "UpdateMessageProperty;" << endl; |
| } |
| indent_down_impl(); |
| indent_impl(code_block) << "end;" << endl << endl; |
| |
| string cls_nm; |
| |
| cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory); |
| |
| indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Read( const iprot: IProtocol);" |
| << endl; |
| indent_impl(out) << "var" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "field_ : TThriftField;" << endl; |
| indent_impl(out) << "struc : TThriftStruct;" << endl; |
| indent_down_impl(); |
| out << local_vars.str() << endl; |
| out << code_block.str(); |
| } |
| |
| void t_delphi_generator::generate_delphi_struct_result_writer_impl(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_x_factory) { |
| |
| ostringstream local_vars; |
| ostringstream code_block; |
| |
| string name = tstruct->get_name(); |
| const vector<t_field*>& fields = tstruct->get_sorted_members(); |
| vector<t_field*>::const_iterator f_iter; |
| |
| indent_impl(code_block) << "begin" << endl; |
| indent_up_impl(); |
| |
| indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; |
| indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl; |
| |
| indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl; |
| indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl; |
| |
| if (fields.size() > 0) { |
| indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl; |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| indent_impl(code_block) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then" |
| << endl; |
| indent_impl(code_block) << "begin" << endl; |
| indent_up_impl(); |
| indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl; |
| indent_impl(code_block) << "field_.Type_ := " << type_to_enum((*f_iter)->get_type()) << ";" |
| << endl; |
| indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl; |
| indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl; |
| generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); |
| indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl; |
| indent_down_impl(); |
| } |
| } |
| |
| indent_impl(code_block) << "oprot.WriteFieldStop();" << endl; |
| indent_impl(code_block) << "oprot.WriteStructEnd();" << endl; |
| |
| indent_down_impl(); |
| indent_impl(code_block) << "end;" << endl << endl; |
| |
| string cls_nm; |
| |
| cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory); |
| |
| indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);" |
| << endl; |
| indent_impl(out) << "var" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "struc : TThriftStruct;" << endl; |
| |
| if (fields.size() > 0) { |
| indent_impl(out) << "field_ : TThriftField;" << endl; |
| } |
| |
| out << local_vars.str(); |
| indent_down_impl(); |
| out << code_block.str(); |
| } |
| |
| void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_x_factory) { |
| |
| ostringstream local_vars; |
| ostringstream code_block; |
| |
| string name = tstruct->get_name(); |
| const vector<t_field*>& fields = tstruct->get_sorted_members(); |
| vector<t_field*>::const_iterator f_iter; |
| |
| indent_impl(code_block) << "begin" << endl; |
| indent_up_impl(); |
| |
| indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl; |
| indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl; |
| |
| indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl; |
| indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl; |
| |
| if (fields.size() > 0) { |
| indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl; |
| } |
| |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| string fieldname = prop_name((*f_iter), is_exception); |
| bool null_allowed = type_can_be_null((*f_iter)->get_type()); |
| bool is_required = ((*f_iter)->get_req() == t_field::T_REQUIRED); |
| bool has_isset = (!is_required); |
| if (is_required && null_allowed) { |
| null_allowed = false; |
| indent_impl(code_block) << "if (Self." << fieldname << " = nil)" << endl; |
| indent_impl(code_block) << "then raise TProtocolExceptionInvalidData.Create(" |
| << "'required field " << fieldname << " not set');" |
| << endl; |
| } |
| if (null_allowed) { |
| indent_impl(code_block) << "if (Self." << fieldname << " <> nil)"; |
| if (has_isset) { |
| code_block << " and __isset_" << fieldname; |
| } |
| code_block << " then begin" << endl; |
| indent_up_impl(); |
| } else { |
| if (has_isset) { |
| indent_impl(code_block) << "if (__isset_" << fieldname << ") then begin" << endl; |
| indent_up_impl(); |
| } |
| } |
| indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl; |
| indent_impl(code_block) << "field_.Type_ := " << type_to_enum((*f_iter)->get_type()) << ";" |
| << endl; |
| indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl; |
| indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl; |
| generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars); |
| indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl; |
| if (null_allowed || has_isset) { |
| indent_down_impl(); |
| indent_impl(code_block) << "end;" << endl; |
| } |
| } |
| |
| indent_impl(code_block) << "oprot.WriteFieldStop();" << endl; |
| indent_impl(code_block) << "oprot.WriteStructEnd();" << endl; |
| |
| indent_down_impl(); |
| indent_impl(code_block) << "end;" << endl << endl; |
| |
| string cls_nm; |
| |
| cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory); |
| |
| indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);" |
| << endl; |
| indent_impl(out) << "var" << endl; |
| indent_up_impl(); |
| indent_impl(out) << "struc : TThriftStruct;" << endl; |
| if (fields.size() > 0) { |
| indent_impl(out) << "field_ : TThriftField;" << endl; |
| } |
| out << local_vars.str(); |
| indent_down_impl(); |
| out << code_block.str(); |
| } |
| |
| void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out, |
| string cls_prefix, |
| t_struct* tstruct, |
| bool is_exception, |
| bool is_x_factory) { |
| |
| const vector<t_field*>& fields = tstruct->get_members(); |
| vector<t_field*>::const_iterator f_iter; |
| |
| string cls_nm; |
| |
| if (is_exception) { |
| cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true); |
| } else { |
| cls_nm = type_name(tstruct, true, false); |
| } |
| |
| string tmp_sb = tmp("_sb"); |
| string tmp_first = tmp("_first"); |
| bool useFirstFlag = false; |
| |
| indent_impl(out) << "function " << cls_prefix << cls_nm << ".ToString: string;" << endl; |
| indent_impl(out) << "var" << endl; |
| indent_up_impl(); |
| indent_impl(out) << tmp_sb << " : TThriftStringBuilder;" << endl; |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED); |
| if (is_optional) { |
| indent_impl(out) << tmp_first << " : System.Boolean;" << endl; |
| useFirstFlag = true; |
| } |
| break; |
| } |
| indent_down_impl(); |
| indent_impl(out) << "begin" << endl; |
| indent_up_impl(); |
| |
| indent_impl(out) << tmp_sb << " := TThriftStringBuilder.Create('(');" << endl; |
| indent_impl(out) << "try" << endl; |
| indent_up_impl(); |
| |
| if (useFirstFlag) { |
| indent_impl(out) << tmp_first << " := TRUE;" << endl; |
| } |
| |
| bool had_required = false; // set to true after first required field has been processed |
| |
| for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { |
| bool null_allowed = type_can_be_null((*f_iter)->get_type()); |
| bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED); |
| if (null_allowed) { |
| indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " <> nil)"; |
| if (is_optional) { |
| out << " and __isset_" << prop_name(*f_iter, is_exception); |
| } |
| out << " then begin" << endl; |
| indent_up_impl(); |
| } else { |
| if (is_optional) { |
| indent_impl(out) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then begin" |
| << endl; |
| indent_up_impl(); |
| } |
| } |
| |
| if (useFirstFlag && (!had_required)) { |
| indent_impl(out) << "if not " << tmp_first << " then " << tmp_sb << ".Append(',');" << endl; |
| if (is_optional) { |
| indent_impl(out) << tmp_first << " := FALSE;" << endl; |
| } |
| indent_impl(out) << tmp_sb << ".Append('" << prop_name((*f_iter), is_exception) << ": ');" |
| << endl; |
| } else { |
| indent_impl(out) << tmp_sb << ".Append(', " << prop_name((*f_iter), is_exception) << ": ');" |
| << endl; |
| } |
| |
| t_type* ttype = (*f_iter)->get_type(); |
| while (ttype->is_typedef()) { |
| ttype = ((t_typedef*)ttype)->get_type(); |
| } |
| |
| if (ttype->is_xception() || ttype->is_struct()) { |
| indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " = nil) then " << tmp_sb |
| << ".Append('<null>') else " << tmp_sb << ".Append( Self." |
| << prop_name((*f_iter), is_exception) << ".ToString());" << endl; |
| } else if (ttype->is_enum()) { |
| indent_impl(out) << tmp_sb << ".Append(EnumUtils<" |
| << type_name(ttype, false, true, false, false) |
| << ">.ToString( System.Ord( Self." |
| << prop_name((*f_iter), is_exception) << ")));" << endl; |
| } else { |
| indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");" |
| << endl; |
| } |
| |
| if (null_allowed || is_optional) { |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl; |
| } |
| |
| if (!is_optional) { |
| had_required = true; // now __first must be false, so we don't need to check it anymore |
| } |
| } |
| |
| indent_impl(out) << tmp_sb << ".Append(')');" << endl; |
| indent_impl(out) << "Result := " << tmp_sb << ".ToString;" << endl; |
| if (useFirstFlag) { |
| indent_impl(out) << "if " << tmp_first << " then {prevent warning};" << endl; |
| } |
| |
| indent_down_impl(); |
| indent_impl(out) << "finally" << endl; |
| indent_up_impl(); |
| indent_impl(out) << tmp_sb << ".Free;" << endl; |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl; |
| |
| indent_down_impl(); |
| indent_impl(out) << "end;" << endl << endl; |
| } |
| |
| bool t_delphi_generator::is_void(t_type* type) { |
| while (type->is_typedef()) { |
| type = ((t_typedef*)type)->get_type(); |
| } |
| |
| if (type->is_base_type()) { |
| t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); |
| if (tbase == t_base_type::TYPE_VOID) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| THRIFT_REGISTER_GENERATOR( |
| delphi, |
| "delphi", |
| " ansistr_binary: Use AnsiString for binary datatype (default is TBytes).\n" |
| " register_types: Enable TypeRegistry, allows for creation of struct, union\n" |
| " and container instances by interface or TypeInfo()\n" |
| " constprefix: Name TConstants classes after IDL to reduce ambiguities\n" |
| " events: Enable and use processing events in the generated code.\n" |
| " xmldoc: Enable XMLDoc comments for Help Insight etc.\n" |
| " async: Generate IAsync interface to use Parallel Programming Library (XE7+ only).\n") |