You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by dr...@apache.org on 2008/06/11 00:57:36 UTC

svn commit: r666377 - in /incubator/thrift/trunk: compiler/cpp/ compiler/cpp/src/ compiler/cpp/src/generate/ lib/alterl/src/

Author: dreiss
Date: Tue Jun 10 15:57:35 2008
New Revision: 666377

URL: http://svn.apache.org/viewvc?rev=666377&view=rev
Log:
Generator for alternative erl bindings, as well as a few more changes to lib code.

- Exceptions don't work yet, but it looks like everything else does.
- Seems to work fine on our pricing service
- Code could need some cleanup

Added:
    incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc
    incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.h
Modified:
    incubator/thrift/trunk/compiler/cpp/Makefile.am
    incubator/thrift/trunk/compiler/cpp/src/main.cc
    incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl
    incubator/thrift/trunk/lib/alterl/src/thrift_protocol.erl

Modified: incubator/thrift/trunk/compiler/cpp/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/compiler/cpp/Makefile.am?rev=666377&r1=666376&r2=666377&view=diff
==============================================================================
--- incubator/thrift/trunk/compiler/cpp/Makefile.am (original)
+++ incubator/thrift/trunk/compiler/cpp/Makefile.am Tue Jun 10 15:57:35 2008
@@ -12,6 +12,7 @@
                  src/generate/t_php_generator.cc \
                  src/generate/t_xsd_generator.cc \
                  src/generate/t_erl_generator.cc \
+                 src/generate/t_alterl_generator.cc \
                  src/globals.h \
                  src/main.h \
                  src/platform.h \
@@ -38,7 +39,8 @@
                  src/generate/t_oop_generator.h \
                  src/generate/t_php_generator.h \
                  src/generate/t_xsd_generator.h \
-                 src/generate/t_erl_generator.h
+                 src/generate/t_erl_generator.h \
+                 src/generate/t_alterl_generator.h
 
 if THRIFT_GEN_cpp
 thrift_SOURCES += src/generate/t_cpp_generator.cc

Added: incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc?rev=666377&view=auto
==============================================================================
--- incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc (added)
+++ incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc Tue Jun 10 15:57:35 2008
@@ -0,0 +1,772 @@
+// Copyright (c) 2006- Facebook
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include "t_alterl_generator.h"
+
+using namespace std;
+
+/**
+ * UI for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_alterl_generator::init_generator() {
+  // Make output directory
+  mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+
+  // setup export lines
+  export_lines_first_ = true;
+  export_types_lines_first_ = true;
+
+  // types files
+  string f_types_name = get_out_dir()+program_name_+"_types.erl";
+  string f_types_hrl_name = get_out_dir()+program_name_+"_types.hrl";
+
+  f_types_file_.open(f_types_name.c_str());
+  f_types_hrl_file_.open(f_types_hrl_name.c_str());
+
+  hrl_header(f_types_hrl_file_, program_name_ + "_types");
+
+  f_types_file_ <<
+    erl_autogen_comment() << endl <<
+    "-module(" << program_name_ << "_types)." << endl <<
+    erl_imports() << endl;
+
+  f_types_file_ <<
+    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
+    endl;
+
+  f_types_hrl_file_ << render_includes() << endl;
+
+  // consts file
+  string f_consts_name = get_out_dir()+program_name_+"_constants.hrl";
+  f_consts_.open(f_consts_name.c_str());
+
+  f_consts_ <<
+    erl_autogen_comment() << endl <<
+    erl_imports() << endl <<
+    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
+    endl;
+}
+
+/**
+ * Boilerplate at beginning and end of header files
+ */
+void t_alterl_generator::hrl_header(ostream& out, string name) {
+  out << "-ifndef(_" << name << "_included)." << endl <<
+    "-define(_" << name << "_included, yeah)." << endl;
+}
+
+void t_alterl_generator::hrl_footer(ostream& out, string name) {
+  out << "-endif." << endl;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_alterl_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += "-include(\"" + includes[i]->get_name() + "_types.hrl\").\n";
+  }
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+  return result;
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_alterl_generator::erl_autogen_comment() {
+  return
+    std::string("%%\n") +
+    "%% Autogenerated by Thrift\n" +
+    "%%\n" +
+    "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
+    "%%\n";
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_alterl_generator::erl_imports() {
+  return "";
+}
+
+/**
+ * Closes the type files
+ */
+void t_alterl_generator::close_generator() {
+  // Close types file
+  export_types_string("struct_info", 1);
+
+  f_types_file_ << "-export([" << export_types_lines_.str() << "])." << endl;
+  f_types_file_ << f_types_.str();
+  f_types_file_ << "struct_info('i am a dummy struct') -> undefined." << endl;
+
+  hrl_footer(f_types_hrl_file_, string("BOGUS"));
+
+  f_types_file_.close();
+  f_types_hrl_file_.close();
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. no op
+ *
+ * @param ttypedef The type definition
+ */
+void t_alterl_generator::generate_typedef(t_typedef* ttypedef) {
+}
+
+/**
+ * Generates code for an enumerated type. Done using a class to scope
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_alterl_generator::generate_enum(t_enum* tenum) {
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+
+  int value = -1;
+
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if ((*c_iter)->has_value()) {
+      value = (*c_iter)->get_value();
+    } else {
+      ++value;
+    }
+
+    string name = capitalize((*c_iter)->get_name());
+
+    f_types_hrl_file_ <<
+      indent() << "-define(" << program_name_ << "_" << name << ", " << value << ")."<< endl;
+  }
+
+  f_types_hrl_file_ << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_alterl_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = capitalize(tconst->get_name());
+  t_const_value* value = tconst->get_value();
+
+  f_consts_ << "-define(" << program_name_ << "_" << name << ", " << render_const_value(type, value) << ")." << endl << endl;
+}
+
+/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+string t_alterl_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << "\"" << value->get_string() << "\"";
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+
+  } else if (type->is_struct() || type->is_xception()) {
+    out << "#" << type->get_name() << "{";
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+
+    bool first = true;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+
+      if (first) {
+        first = false;
+      } else {
+        out << ",";
+      }
+      out << v_iter->first->get_string();
+      out << " = ";
+      out << render_const_value(field_type, v_iter->second);
+    }
+    indent_down();
+    indent(out) << "}";
+
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+
+    bool first = true;
+    out << "dict:from_list([";
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (first) {
+        first=false;
+      } else {
+        out << ",";
+      }
+      out << "("
+          << render_const_value(ktype, v_iter->first)  << ","
+          << render_const_value(vtype, v_iter->second) << ")";
+    }
+    out << "])";
+
+  } else if (type->is_set()) {
+    t_type* etype;
+    etype = ((t_set*)type)->get_elem_type();
+
+    bool first = true;
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    out << "sets:from_list([";
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (first) {
+        first=false;
+      } else {
+        out << ",";
+      }
+      out << "(" << render_const_value(etype, *v_iter) << ",true)";
+    }
+    out << "])";
+
+  } else if (type->is_list()) {
+    t_type* etype;
+    etype = ((t_list*)type)->get_elem_type();
+    out << "[";
+
+    bool first = true;
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (first) {
+        first=false;
+      } else {
+        out << ",";
+      }
+      out << render_const_value(etype, *v_iter);
+    }
+    out << "]";
+  }
+  return out.str();
+}
+
+/**
+ * Generates a struct
+ */
+void t_alterl_generator::generate_struct(t_struct* tstruct) {
+  generate_erl_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct but extends the Exception class.
+ *
+ * @param txception The struct definition
+ */
+void t_alterl_generator::generate_xception(t_struct* txception) {
+  generate_erl_struct(txception, true);
+}
+
+/**
+ * Generates a struct
+ */
+void t_alterl_generator::generate_erl_struct(t_struct* tstruct,
+                                          bool is_exception) {
+  generate_erl_struct_definition(f_types_, f_types_hrl_file_, tstruct, is_exception);
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_alterl_generator::generate_erl_struct_definition(ostream& out,
+                                                     ostream& hrl_out,
+                                                     t_struct* tstruct,
+                                                     bool is_exception,
+                                                     bool is_result)
+{
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent(out) << "%% struct " << type_name(tstruct) << endl;
+
+  if (is_exception) {
+  }
+
+  out << endl;
+
+  if (members.size() > 0) {
+    indent(out)     << "% -record(" << type_name(tstruct) << ", {";
+    indent(hrl_out) <<   "-record(" << type_name(tstruct) << ", {";
+
+    bool first = true;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (first) {
+        first = false;
+      } else {
+        out     << ", ";
+        hrl_out << ", ";
+      }
+      out     << (*m_iter)->get_name();
+      hrl_out << (*m_iter)->get_name();
+    }
+    out     << "})." << endl;
+    hrl_out << "})." << endl;
+  } else { // no members; explicit comment
+    indent(out)     << "% -record(" << type_name(tstruct) << ", {})." << endl;
+    indent(hrl_out) <<   "-record(" << type_name(tstruct) << ", {})." << endl;
+  }
+
+  out << endl;
+  hrl_out << endl;
+
+
+  generate_erl_struct_info(out, tstruct);
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_alterl_generator::generate_erl_struct_info(ostream& out,
+                                                  t_struct* tstruct) {
+  string name = type_name(tstruct);
+
+  indent(out) << "struct_info('" << name << "') ->" << endl;
+  indent_up();
+
+  out << indent() << generate_type_term(tstruct, true) << ";" << endl;
+
+  indent_down();
+  out << endl;
+}
+
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_alterl_generator::generate_service(t_service* tservice) {
+  // somehow this point is reached before the constructor and it's not downcased yet
+  // ...awesome
+  service_name_[0] = tolower(service_name_[0]);
+
+  string f_service_hrl_name = get_out_dir()+service_name_+"_thrift.hrl";
+  string f_service_name = get_out_dir()+service_name_+"_thrift.erl";
+  f_service_file_.open(f_service_name.c_str());
+  f_service_hrl_.open(f_service_hrl_name.c_str());
+
+  hrl_header(f_service_hrl_, service_name_);
+
+  if (tservice->get_extends() != NULL) {
+    f_service_hrl_ << "-include(\"" <<
+      uncapitalize(tservice->get_extends()->get_name()) << "_thrift.hrl\"). % inherit " << endl;
+  }
+
+  f_service_hrl_ <<
+    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
+    endl;
+
+  // Generate the three main parts of the service (well, two for now in PHP)
+  generate_service_helpers(tservice); // cpiro: New Erlang Order
+
+  generate_service_interface(tservice);
+
+  // indent_down();
+
+  f_service_file_ <<
+    erl_autogen_comment() << endl <<
+    "-module(" << service_name_ << "_thrift)." << endl <<
+    "-behaviour(thrift_service)." << endl << endl <<
+    erl_imports() << endl;
+
+  f_service_file_ << "-include(\"" << uncapitalize(tservice->get_name()) << "_thrift.hrl\")." << endl << endl;
+
+  f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl;
+
+  f_service_file_ << f_service_.str();
+
+  hrl_footer(f_service_hrl_, f_service_name);
+
+  // Close service file
+  f_service_file_.close();
+  f_service_hrl_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_alterl_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  //  indent(f_service_) <<
+  //  "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+  export_string("struct_info", 1);
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_erl_function_helpers(*f_iter);
+  }
+  f_service_    << "struct_info('i am a dummy struct') -> undefined." << endl; 
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_alterl_generator::generate_erl_function_helpers(t_function* tfunction) {
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_alterl_generator::generate_service_interface(t_service* tservice) {
+
+  export_string("function_info", 2);
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  f_service_ << "%%% interface" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      indent() << "% " << function_signature(*f_iter) << endl;
+
+    generate_function_info(tservice, *f_iter);
+  }
+
+  // Dummy function_info so we don't worry about the ;s
+  indent(f_service_) << "function_info(xxx, dummy) -> dummy." << endl;
+
+  indent(f_service_) << endl;
+}
+
+
+/**
+ * Generates a function_info(FunctionName, params_type) and
+ * function_info(FunctionName, reply_type)
+ */
+void t_alterl_generator::generate_function_info(t_service* tservice,
+                                                t_function* tfunction) {
+
+  string name_atom = "'" + tfunction->get_name() + "'";
+
+
+
+  t_struct* xs = tfunction->get_xceptions();
+  t_struct* arg_struct = tfunction->get_arglist();
+
+  // function_info(Function, params_type):
+  indent(f_service_) <<
+    "function_info(" << name_atom << ", params_type) ->" << endl;
+  indent_up();
+
+  indent(f_service_) << generate_type_term(arg_struct, true) << ";" << endl;
+
+  indent_down();
+
+  // function_info(Function, reply_type):
+  indent(f_service_) <<
+    "function_info(" << name_atom << ", reply_type) ->" << endl;
+  indent_up();
+
+  if (!tfunction->get_returntype()->is_void())
+    indent(f_service_) << generate_type_term(tfunction->get_returntype(), true) << ";" << endl;
+  else
+    indent(f_service_) << "{struct, []}" << ";" << endl;
+  indent_down();
+
+  // function_info(Function, exceptions):
+  indent(f_service_) <<
+    "function_info(" << name_atom << ", exceptions) ->" << endl;
+  indent_up();
+
+  // TODO(todd) exceptions here are probably broken
+  indent(f_service_) << generate_type_term(xs, false) << ";" << endl;
+
+  indent_down();
+
+  // function_info(Function, is_async):
+  indent(f_service_) <<
+    "function_info(" << name_atom << ", is_async) -> ";
+
+  f_service_ << ((tfunction->is_async()) ? "true" : "false");
+  f_service_ << ";" << endl;
+}
+
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_alterl_generator::declare_field(t_field* tfield) {  // TODO
+  string result = "@" + tfield->get_name();
+  t_type* type = get_true_type(tfield->get_type());
+  if (tfield->get_value() != NULL) {
+    result += " = " + render_const_value(type, tfield->get_value());
+  } else {
+    result += " = nil";
+  }
+  return result;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_alterl_generator::function_signature(t_function* tfunction,
+                                           string prefix) {
+  return
+    prefix + tfunction->get_name() +
+    "(This" +  capitalize(argument_list(tfunction->get_arglist())) + ")";
+}
+
+/**
+ * Add a function to the exports list
+ */
+void t_alterl_generator::export_string(string name, int num) {
+  if (export_lines_first_) {
+    export_lines_first_ = false;
+  } else {
+    export_lines_ << ", ";
+  }
+  export_lines_ << name << "/" << num;
+}
+
+void t_alterl_generator::export_types_function(t_function* tfunction,
+                                               string prefix) {
+
+  export_types_string(prefix + tfunction->get_name(),
+                      1 // This
+                      + ((tfunction->get_arglist())->get_members()).size()
+                      );
+}
+
+void t_alterl_generator::export_types_string(string name, int num) {
+  if (export_types_lines_first_) {
+    export_types_lines_first_ = false;
+  } else {
+    export_types_lines_ << ", ";
+  }
+  export_types_lines_ << name << "/" << num;
+}
+
+void t_alterl_generator::export_function(t_function* tfunction,
+                                      string prefix) {
+
+  export_string(prefix + tfunction->get_name(),
+                1 // This
+                + ((tfunction->get_arglist())->get_members()).size()
+                );
+}
+
+
+/**
+ * Renders a field list
+ */
+string t_alterl_generator::argument_list(t_struct* tstruct) {
+  string result = "";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      result += ", "; // initial comma to compensate for initial This
+    } else {
+      result += ", ";
+    }
+    result += capitalize((*f_iter)->get_name());
+  }
+  return result;
+}
+
+string t_alterl_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  string name = ttype->get_name();
+
+  if (ttype->is_struct() || ttype->is_xception() || ttype->is_service()) {
+    name = uncapitalize(ttype->get_name());
+  }
+
+  return prefix + name;
+}
+
+/**
+ * Converts the parse type to a Erlang "type" (macro for int constants)
+ */
+string t_alterl_generator::type_to_enum(t_type* type) {
+  type = get_true_type(type);
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "?tType_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "?tType_BOOL";
+    case t_base_type::TYPE_BYTE:
+      return "?tType_BYTE";
+    case t_base_type::TYPE_I16:
+      return "?tType_I16";
+    case t_base_type::TYPE_I32:
+      return "?tType_I32";
+    case t_base_type::TYPE_I64:
+      return "?tType_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "?tType_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "?tType_I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "?tType_STRUCT";
+  } else if (type->is_map()) {
+    return "?tType_MAP";
+  } else if (type->is_set()) {
+    return "?tType_SET";
+  } else if (type->is_list()) {
+    return "?tType_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+
+/**
+ * Generate an Erlang term which represents a thrift type
+ */
+std::string t_alterl_generator::generate_type_term(t_type* type,
+                                                   bool expand_structs) {
+    type = get_true_type(type);
+
+    
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "string";
+    case t_base_type::TYPE_BOOL:
+      return "bool";
+    case t_base_type::TYPE_BYTE:
+      return "byte";
+    case t_base_type::TYPE_I16:
+      return "i16";
+    case t_base_type::TYPE_I32:
+      return "i32";
+    case t_base_type::TYPE_I64:
+      return "i64";
+    case t_base_type::TYPE_DOUBLE:
+      return "double";
+    }
+  } else if (type->is_enum()) {
+    return "i32";
+  } else if (type->is_struct() || type->is_xception()) {
+    if (expand_structs) {
+      // Convert to format: {struct, [{Fid, TypeTerm}, {Fid, TypeTerm}...]}
+      std::stringstream ret;
+
+
+      ret << "{struct, [";
+
+      int first = true;
+      const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+      vector<t_field*>::const_iterator f_iter;
+
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        // Comma separate the tuples
+        if (!first) ret << "," << endl << indent();
+        first = false;
+
+        ret << "{" << (*f_iter)->get_key() << ", " <<
+          generate_type_term((*f_iter)->get_type(), false) << "}";
+      }
+
+      ret << "]}" << endl;
+
+      return ret.str();
+    } else {
+      return "{struct, {'" + type_module(type) + "', '" + type_name(type) + "'}}";
+    }
+  } else if (type->is_map()) {
+    // {map, KeyType, ValType}
+    t_type *key_type = ((t_map*)type)->get_key_type();
+    t_type *val_type = ((t_map*)type)->get_val_type();
+
+    return "{map, " + generate_type_term(key_type, false) + ", " +
+      generate_type_term(val_type, false) + "}";
+
+  } else if (type->is_set()) {
+    t_type *elem_type = ((t_set*)type)->get_elem_type();
+    
+    return "{set, " + generate_type_term(elem_type, false) + "}";
+
+  } else if (type->is_list()) {
+    t_type *elem_type = ((t_list*)type)->get_elem_type();
+    
+    return "{list, " + generate_type_term(elem_type, false) + "}";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+std::string t_alterl_generator::type_module(t_type* ttype) {
+  return ttype->get_program()->get_name() + "_types";
+}

Added: incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.h
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.h?rev=666377&view=auto
==============================================================================
--- incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.h (added)
+++ incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.h Tue Jun 10 15:57:35 2008
@@ -0,0 +1,135 @@
+#ifndef T_ALTERL_GENERATOR_H
+#define T_ALTERL_GENERATOR_H
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include "t_oop_generator.h"
+
+/**
+ * Erlang code generator.
+ *
+ * @author
+ */
+class t_alterl_generator : public t_generator {
+ public:
+  t_alterl_generator(t_program* program) :
+    t_generator(program) 
+  {
+    program_name_[0] = tolower(program_name_[0]);
+    service_name_[0] = tolower(service_name_[0]);
+    out_dir_base_ = "gen-erl";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef  (t_typedef*  ttypedef);
+  void generate_enum     (t_enum*     tenum);
+  void generate_const    (t_const*    tconst);
+  void generate_struct   (t_struct*   tstruct);
+  void generate_xception (t_struct*   txception);
+  void generate_service  (t_service*  tservice);
+
+  std::string render_const_value(t_type* type, t_const_value* value);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_erl_struct(t_struct* tstruct, bool is_exception);
+  void generate_erl_struct_definition(std::ostream& out, std::ostream& hrl_out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
+  void generate_erl_struct_info(std::ostream& out, t_struct* tstruct);
+  void generate_erl_function_helpers(t_function* tfunction);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_helpers   (t_service*  tservice);
+  void generate_service_interface (t_service* tservice);
+  void generate_function_info     (t_service* tservice, t_function* tfunction);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string erl_autogen_comment();
+  std::string erl_imports();
+  std::string render_includes();
+  std::string declare_field(t_field* tfield);
+  std::string type_name(t_type* ttype);
+
+  std::string function_signature(t_function* tfunction, std::string prefix="");
+
+
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string generate_type_term(t_type* ttype, bool expand_structs);
+  std::string type_module(t_type* ttype);
+
+  std::string capitalize(std::string in) {
+    in[0] = toupper(in[0]);
+    return in;
+  }
+
+  std::string uncapitalize(std::string in) {
+    in[0] = tolower(in[0]);
+    return in;
+  }
+
+ private:
+
+  /**
+   * add function to export list
+   */
+
+  void export_function(t_function* tfunction, std::string prefix="");
+  void export_string(std::string name, int num);
+
+  void export_types_function(t_function* tfunction, std::string prefix="");
+  void export_types_string(std::string name, int num);
+
+  /**
+   * write out headers and footers for hrl files
+   */
+  
+  void hrl_header(std::ostream& out, std::string name);
+  void hrl_footer(std::ostream& out, std::string name); 
+
+  /**
+   * stuff to spit out at the top of generated files
+   */
+
+  bool export_lines_first_;
+  std::ostringstream export_lines_;
+
+  bool export_types_lines_first_;
+  std::ostringstream export_types_lines_;
+
+  /**
+   * File streams
+   */
+
+  std::ostringstream f_types_;
+  std::ofstream f_types_file_;
+  std::ofstream f_types_hrl_file_;
+
+  std::ofstream f_consts_; 
+  std::ostringstream f_service_;
+  std::ofstream f_service_file_;
+  std::ofstream f_service_hrl_;
+
+};
+
+#endif

Modified: incubator/thrift/trunk/compiler/cpp/src/main.cc
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/compiler/cpp/src/main.cc?rev=666377&r1=666376&r2=666377&view=diff
==============================================================================
--- incubator/thrift/trunk/compiler/cpp/src/main.cc (original)
+++ incubator/thrift/trunk/compiler/cpp/src/main.cc Tue Jun 10 15:57:35 2008
@@ -39,6 +39,7 @@
 #include "generate/t_php_generator.h"
 #include "generate/t_xsd_generator.h"
 #include "generate/t_erl_generator.h"
+#include "generate/t_alterl_generator.h"
 
 using namespace std;
 
@@ -152,6 +153,7 @@
 bool gen_rest = false;
 bool gen_perl = false;
 bool gen_erl = false;
+bool gen_alterl = false;
 bool gen_ocaml = false;
 bool gen_hs = false;
 bool gen_cocoa = false;
@@ -602,6 +604,7 @@
   fprintf(stderr, "  -phpo       Generate PHP with object oriented subclasses (with -php)\n");
   fprintf(stderr, "  -xsd        Generate XSD output files\n");
   fprintf(stderr, "  -erl        Generate Erlang output files\n");
+  fprintf(stderr, "  -alterl     Generate Alternative Erlang output files\n");
   fprintf(stderr, "  -o dir      Set the output directory for gen-* packages\n");
   fprintf(stderr, "               (default: current directory)\n");
   fprintf(stderr, "  -I dir      Add a directory to the list of directories\n");
@@ -878,6 +881,13 @@
       delete erl;
     }
 
+    if (gen_alterl) {
+      pverbose("Generating Alternative Erlang\n");
+      t_alterl_generator* alterl = new t_alterl_generator(program);
+      alterl->generate_program();
+      delete alterl;
+    }
+
     if (dump_docs) {
       dump_docstrings(program);
     }
@@ -994,6 +1004,8 @@
         gen_perl = true;
       } else if (strcmp(arg, "-erl") == 0) {
         gen_erl = true;
+      } else if (strcmp(arg, "-alterl") == 0) {
+        gen_alterl = true;
       } else if (strcmp(arg, "-ocaml") == 0) {
         gen_ocaml = true;
       } else if (strcmp(arg, "-hs") == 0) {
@@ -1105,7 +1117,7 @@
   }
 
   // You gotta generate something!
-  if (!gen_php && !gen_phpi && !gen_xsd && !gen_erl && generator_strings.empty()) {
+  if (!gen_php && !gen_phpi && !gen_xsd && !gen_erl && !gen_alterl && generator_strings.empty()) {
     fprintf(stderr, "!!! No output language(s) specified\n\n");
     usage();
   }

Modified: incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl?rev=666377&r1=666376&r2=666377&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl (original)
+++ incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl Tue Jun 10 15:57:35 2008
@@ -29,44 +29,13 @@
     case thrift_protocol:read(IProto, message_begin) of
         #protocol_message_begin{name = Function,
                                 type = ?tMessageType_CALL} ->
-            ok = handle_function(State, list_to_atom(binary_to_list(Function))),
+            ok= handle_function(State, list_to_atom(binary_to_list(Function))),
             loop(State);
         {error, closed} ->
-            error_logger:info_msg("Processor finished~n"),
+            error_logger:info_msg("Client disconnected~n"),
             ok
     end.
 
-%handle_function(State = #state{in_protocol = IProto,
-%                               out_protocol = OProto},
-%                add) ->
-%    io:format("Reading struct~n"),
-%    {ok, Struct} = thrift_protocol:read(IProto,
-%                  {struct, [{1, i32},
-%                            {2, i32}]}),
-%    io:format("Struct: ~p~n", [Struct]),
-    
-%    {A, B} = Struct,
-
-%    thrift_protocol:write(OProto, #protocol_message_begin{
-%                            name = "addResult",
-%                            type = ?tMessageType_REPLY,
-%                            seqid = 0}),
-%    thrift_protocol:write(OProto, {{struct, [{0, i32}]},
-%                                   {A + B}}),
-%    thrift_protocol:write(OProto, message_end);
-
-%handle_function(State = #state{in_protocol = IProto,
-%                               out_protocol = OProto},
-%                complexTest) ->
-%    io:format("Reading struct~n"),
-%    Struct = thrift_protocol:read(
-%               IProto,
-%               {struct, [{1, {struct,
-%                              [{1, {list, i32}},
-%                               {2, {map, string, {struct, [{1, i16}]}}}]}}]}),
-    
-%    io:format("Struct: ~p~n", [Struct]);
-
 
 handle_function(State = #state{in_protocol = IProto,
                                out_protocol = OProto,
@@ -76,17 +45,21 @@
     InParams = Service:function_info(Function, params_type),
 
     {ok, Params} = thrift_protocol:read(IProto, InParams),
-    Result = Handler:handle_function(Function, Params),
+
+    {Micro, Result} = timer:tc(Handler, handle_function, [Function, Params]),
+    error_logger:info_msg("Processed ~p(~p) in ~.4fms~n",
+                          [Function, Params, Micro/1000.0]),
     
     ReplyType = Service:function_info(Function, reply_type),
     
     case Result of
         {reply, Reply} -> 
+            StructName = atom_to_list(Function) ++ "_result",
             thrift_protocol:write(OProto, #protocol_message_begin{
-                            name = atom_to_list(Function) ++ "_result",
+                            name = StructName,
                             type = ?tMessageType_REPLY,
                             seqid = 0}),
-            thrift_protocol:write(OProto, {{struct, [{0, ReplyType}]}, {Reply}}),
+            thrift_protocol:write(OProto, {{struct, [{0, ReplyType}]}, {StructName, Reply}}),
             thrift_protocol:write(OProto, message_end)
     end,
     ok.

Modified: incubator/thrift/trunk/lib/alterl/src/thrift_protocol.erl
URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/alterl/src/thrift_protocol.erl?rev=666377&r1=666376&r2=666377&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/alterl/src/thrift_protocol.erl (original)
+++ incubator/thrift/trunk/lib/alterl/src/thrift_protocol.erl Tue Jun 10 15:57:35 2008
@@ -75,6 +75,14 @@
             end || Index <- lists:seq(1, length(Structure))],
     {ok, list_to_tuple(List)};
 
+read(IProto, {struct, {Module, StructureName}}) when is_atom(Module),
+                                                     is_atom(StructureName) ->
+    case read(IProto, Module:struct_info(StructureName)) of
+        {ok, StructureElems} ->
+            {ok, list_to_tuple([StructureName | tuple_to_list(StructureElems)])};
+        Else -> Else
+    end;
+
 read(IProto, {list, Type}) ->
     #protocol_list_begin{etype = EType, size = Size} =
         read(IProto, list_begin),
@@ -217,12 +225,21 @@
 %% Description: 
 %%--------------------------------------------------------------------
 write(Proto, {{struct, StructDef}, Data})
-  when is_list(StructDef), is_tuple(Data), length(StructDef) == size(Data) ->
-    ok = write(Proto, #protocol_struct_begin{}),
-    ok = struct_write_loop(Proto, StructDef, tuple_to_list(Data)),
+  when is_list(StructDef), is_tuple(Data), length(StructDef) == size(Data) - 1 ->
+
+    [StructName | Elems] = tuple_to_list(Data),
+    ok = write(Proto, #protocol_struct_begin{name = StructName}),
+    ok = struct_write_loop(Proto, StructDef, Elems),
     ok = write(Proto, struct_end),
     ok;
 
+write(Proto, {{struct, {Module, StructureName}}, Data})
+  when is_atom(Module),
+       is_atom(StructureName),
+       element(1, Data) =:= StructureName ->
+    StructType = Module:struct_info(StructureName),
+    write(Proto, {Module:struct_info(StructureName), Data});
+
 write(Proto, {{list, Type}, Data})
   when is_list(Data) ->
     ok = write(Proto,