Thrift now a TLP - INFRA-3116

git-svn-id: https://svn.apache.org/repos/asf/thrift/branches/0.1.x@1028168 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
new file mode 100644
index 0000000..3838fac
--- /dev/null
+++ b/compiler/cpp/Makefile.am
@@ -0,0 +1,136 @@
+#
+# 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.
+#
+
+AM_YFLAGS = -d
+BUILT_SOURCES =
+
+bin_PROGRAMS = thrift
+
+thrift_OBJDIR = obj
+
+thrift_SOURCES = src/thrifty.yy \
+                 src/thriftl.ll \
+                 src/main.cc \
+                 src/md5.c \
+                 src/generate/t_generator.cc \
+                 src/globals.h \
+                 src/main.h \
+                 src/platform.h \
+                 src/md5.h \
+                 src/parse/t_doc.h \
+                 src/parse/t_type.h \
+                 src/parse/t_base_type.h \
+                 src/parse/t_enum.h \
+                 src/parse/t_enum_value.h \
+                 src/parse/t_typedef.h \
+                 src/parse/t_container.h \
+                 src/parse/t_list.h \
+                 src/parse/t_set.h \
+                 src/parse/t_map.h \
+                 src/parse/t_struct.h \
+                 src/parse/t_field.h \
+                 src/parse/t_service.h \
+                 src/parse/t_function.h \
+                 src/parse/t_program.h \
+                 src/parse/t_scope.h \
+                 src/parse/t_const.h \
+                 src/parse/t_const_value.h \
+                 src/generate/t_generator.h \
+                 src/generate/t_oop_generator.h
+
+if THRIFT_GEN_cpp
+thrift_SOURCES += src/generate/t_cpp_generator.cc
+endif
+if THRIFT_GEN_java
+thrift_SOURCES += src/generate/t_java_generator.cc
+endif
+if THRIFT_GEN_csharp
+thrift_SOURCES += src/generate/t_csharp_generator.cc
+endif
+if THRIFT_GEN_py
+thrift_SOURCES += src/generate/t_py_generator.cc
+endif
+if THRIFT_GEN_rb
+thrift_SOURCES += src/generate/t_rb_generator.cc
+endif
+if THRIFT_GEN_perl
+thrift_SOURCES += src/generate/t_perl_generator.cc
+endif
+if THRIFT_GEN_php
+thrift_SOURCES += src/generate/t_php_generator.cc
+endif
+if THRIFT_GEN_erl
+thrift_SOURCES += src/generate/t_erl_generator.cc
+endif
+if THRIFT_GEN_cocoa
+thrift_SOURCES += src/generate/t_cocoa_generator.cc
+endif
+if THRIFT_GEN_st
+thrift_SOURCES += src/generate/t_st_generator.cc
+endif
+if THRIFT_GEN_ocaml
+thrift_SOURCES += src/generate/t_ocaml_generator.cc
+endif
+if THRIFT_GEN_hs
+thrift_SOURCES += src/generate/t_hs_generator.cc
+endif
+if THRIFT_GEN_xsd
+thrift_SOURCES += src/generate/t_xsd_generator.cc
+endif
+if THRIFT_GEN_html
+thrift_SOURCES += src/generate/t_html_generator.cc
+endif
+
+thrift_CXXFLAGS = -Wall -I$(srcdir)/src $(BOOST_CPPFLAGS)
+thrift_LDFLAGS = -Wall $(BOOST_LDFLAGS)
+
+thrift_LDADD = @LEXLIB@
+
+EXTRA_DIST = README
+
+clean-local:
+	$(RM) thriftl.cc thrifty.cc thrifty.h version.h
+
+src/main.cc: version.h
+
+# Adding this to BUILT_SOURCES will cause version.h to be
+# regenerated on every "make all" or "make check", which is
+# necessary because it changes whenever we "svn up" or similar.
+# Ideally, we would like this to be regenerated whenever the
+# compiler is rebuilt, but every way we could think of to do
+# that caused unnecessary rebuilds of the compiler.
+BUILT_SOURCES += regen_version_h
+
+THRIFT_VERSION=$(shell /bin/sh $(top_srcdir)/print_version.sh -v)
+THRIFT_REVISION=$(shell /bin/sh $(top_srcdir)/print_version.sh -r)
+
+regen_version_h:
+	@printf "Regenerating version.h... "
+	@TMPFILE=`mktemp ./version_h.tmp_XXXXXX` ; \
+		echo "// AUTOGENERATED, DO NOT EDIT" > $$TMPFILE ; \
+		echo '#define THRIFT_VERSION "$(THRIFT_VERSION)"' >> $$TMPFILE ; \
+		echo '#define THRIFT_REVISION "$(THRIFT_REVISION)"' >> $$TMPFILE ; \
+		if cmp $$TMPFILE version.h >/dev/null ; \
+		then \
+			rm -f $$TMPFILE ; \
+			echo "No changes." ; \
+		else \
+			mv $$TMPFILE version.h ; \
+			echo "Updated." ; \
+		fi
diff --git a/compiler/cpp/README b/compiler/cpp/README
new file mode 100644
index 0000000..fb100a8
--- /dev/null
+++ b/compiler/cpp/README
@@ -0,0 +1,39 @@
+Thrift Code Compiler
+
+License
+=======
+
+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.
+
+Thrift Code Compiler
+====================
+
+This compiler takes thrift files as input and generates output code across
+various programming languages. To build and install it, do this:
+
+  ./bootstrap.sh
+  ./configure
+  make
+  sudo make install
+
+It requires some form of LEX and YACC to be installed, which should be
+picked up by autoconf.
+
+Not much else to report here. You'll have to look at the code to get your
+questions answered. Or just run the executable after you build and take
+a look at the usage message.
diff --git a/compiler/cpp/src/generate/t_cocoa_generator.cc b/compiler/cpp/src/generate/t_cocoa_generator.cc
new file mode 100644
index 0000000..48c853c
--- /dev/null
+++ b/compiler/cpp/src/generate/t_cocoa_generator.cc
@@ -0,0 +1,2059 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "t_oop_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * Objective-C code generator.
+ *
+ * mostly copy/pasting/tweaking from mcslee's work.
+ */
+class t_cocoa_generator : public t_oop_generator {
+ public:
+  t_cocoa_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    out_dir_base_ = "gen-cocoa";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef (t_typedef*  ttypedef);
+  void generate_enum    (t_enum*     tenum);
+  void generate_struct  (t_struct*   tstruct);
+  void generate_xception(t_struct*   txception);
+  void generate_service (t_service*  tservice);
+
+  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+  std::string render_const_value(std::string name, t_type* type, t_const_value* value,
+                                 bool containerize_it=false);
+
+  void generate_cocoa_struct(t_struct* tstruct, bool is_exception);
+  void generate_cocoa_struct_interface(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
+  void generate_cocoa_struct_implementation(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
+  void generate_cocoa_struct_initializer_signature(std::ofstream& out,
+                                                   t_struct* tstruct);
+  void generate_cocoa_struct_field_accessor_declarations(std::ofstream& out,
+                                                         t_struct* tstruct,
+                                                         bool is_exception);
+  void generate_cocoa_struct_field_accessor_implementations(std::ofstream& out,
+                                                            t_struct* tstruct,
+                                                            bool is_exception);
+  void generate_cocoa_struct_reader(std::ofstream& out, t_struct* tstruct);
+  void generate_cocoa_struct_result_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_cocoa_struct_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_cocoa_struct_description(std::ofstream& out, t_struct* tstruct);
+
+  std::string function_result_helper_struct_type(t_function* tfunction);
+  void generate_function_helpers(t_function* tfunction);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_cocoa_service_protocol (std::ofstream& out, t_service* tservice);
+  void generate_cocoa_service_client_interface (std::ofstream& out, t_service* tservice);
+  void generate_cocoa_service_client_implementation (std::ofstream& out, t_service* tservice);
+  void generate_cocoa_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* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream& out,
+                                          t_field*    tfield,
+                                          std::string fieldName);
+
+  void generate_deserialize_struct       (std::ofstream& out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_deserialize_container    (std::ofstream& out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_deserialize_set_element  (std::ofstream& out,
+                                          t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (std::ofstream& out,
+                                          t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (std::ofstream& out,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+
+  void generate_serialize_field          (std::ofstream& out,
+                                          t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_serialize_struct         (std::ofstream& out,
+                                          t_struct*   tstruct,
+                                          std::string fieldName="");
+
+  void generate_serialize_container      (std::ofstream& out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream& out,
+                                          t_map*      tmap,
+                                          std::string iter,
+                                          std::string map);
+
+  void generate_serialize_set_element    (std::ofstream& out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream& out,
+                                          t_list*     tlist,
+                                          std::string index,
+                                          std::string listName);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string cocoa_prefix();
+  std::string cocoa_imports();
+  std::string cocoa_thrift_imports();
+  std::string type_name(t_type* ttype, bool class_ref=false);
+  std::string base_type_name(t_base_type* tbase);
+  std::string declare_field(t_field* tfield);
+  std::string function_signature(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string format_string_for_type(t_type* type);
+  std::string call_field_setter(t_field* tfield, std::string fieldName);
+  std::string containerize(t_type * ttype, std::string fieldName);
+  std::string decontainerize(t_field * tfield, std::string fieldName);
+
+  bool type_can_be_null(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return
+      ttype->is_container() ||
+      ttype->is_struct() ||
+      ttype->is_xception() ||
+      ttype->is_string();
+  }
+
+ private:
+
+  std::string cocoa_prefix_;
+  std::string constants_declarations_;
+
+  /**
+   * File streams
+   */
+
+  std::ofstream f_header_;
+  std::ofstream f_impl_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ */
+void t_cocoa_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  cocoa_prefix_ = program_->get_namespace("cocoa");
+
+  // we have a .h header file...
+  string f_header_name = program_name_+".h";
+  string f_header_fullname = get_out_dir()+f_header_name;
+  f_header_.open(f_header_fullname.c_str());
+
+  f_header_ <<
+    autogen_comment() <<
+    endl;
+
+  f_header_ <<
+    cocoa_imports() <<
+    cocoa_thrift_imports();
+
+  // ...and a .m implementation file
+  string f_impl_name = get_out_dir()+program_name_+".m";
+  f_impl_.open(f_impl_name.c_str());
+
+  f_impl_ <<
+    autogen_comment() <<
+    endl;
+
+  f_impl_ <<
+    cocoa_imports() <<
+    cocoa_thrift_imports() <<
+    "#import \"" << f_header_name << "\"" << endl <<
+    endl;
+
+}
+
+/**
+ * Prints standard Cocoa imports
+ *
+ * @return List of imports for Cocoa libraries
+ */
+string t_cocoa_generator::cocoa_imports() {
+  return
+    string() +
+    "#import <Cocoa/Cocoa.h>\n" +
+    "\n";
+}
+
+/**
+ * Prints thrift runtime imports
+ *
+ * @return List of imports necessary for thrift runtime
+ */
+string t_cocoa_generator::cocoa_thrift_imports() {
+  string result = string() +
+    "#import <TProtocol.h>\n" +
+    "#import <TApplicationException.h>\n" +
+    "#import <TProtocolUtil.h>\n" +
+    "\n";
+
+  // Include other Thrift includes
+  const vector<t_program*>& includes = program_->get_includes();
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += "#import \"" + includes[i]->get_name() + ".h\"" + "\n";
+  }
+  result += "\n";
+
+  return result;
+}
+
+
+/**
+ * Finish up generation.
+ */
+void t_cocoa_generator::close_generator()
+{
+  // stick our constants declarations at the end of the header file
+  // since they refer to things we are defining.
+  f_header_ << constants_declarations_ << endl;
+}
+
+/**
+ * Generates a typedef. This is just a simple 1-liner in objective-c
+ *
+ * @param ttypedef The type definition
+ */
+void t_cocoa_generator::generate_typedef(t_typedef* ttypedef) {
+  f_header_ <<
+    indent() << "typedef " << type_name(ttypedef->get_type()) << " " << cocoa_prefix_ << ttypedef->get_symbolic() << ";" << endl <<
+    endl;
+}
+
+/**
+ * Generates code for an enumerated type. In Objective-C, this is
+ * essentially the same as the thrift definition itself, using the
+ * enum keyword in Objective-C.  For namespace purposes, the name of
+ * the enum plus an underscore is prefixed onto each element.
+ *
+ * @param tenum The enumeration
+ */
+void t_cocoa_generator::generate_enum(t_enum* tenum) {
+  f_header_ <<
+    indent() << "enum " << cocoa_prefix_ << tenum->get_name() << " {" << endl;
+  indent_up();
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_header_ <<
+        "," << endl;
+    }
+    f_header_ <<
+      indent() << tenum->get_name() << "_" << (*c_iter)->get_name();
+    if ((*c_iter)->has_value()) {
+      f_header_ <<
+        " = " << (*c_iter)->get_value();
+    }
+  }
+
+  indent_down();
+  f_header_ <<
+    endl <<
+    "};" << endl <<
+    endl;
+}
+
+/**
+ * Generates a class that holds all the constants.  Primitive values
+ * could have been placed outside this class, but I just put
+ * everything in for consistency.
+ */
+void t_cocoa_generator::generate_consts(std::vector<t_const*> consts) {
+  std::ostringstream const_interface;
+  string constants_class_name = cocoa_prefix_ + program_name_ + "Constants";
+
+  const_interface << "@interface " << constants_class_name << " ";
+  scope_up(const_interface);
+  scope_down(const_interface);
+
+  // getter method for each constant defined.
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    const_interface <<
+      "+ (" << type_name(type) << ") " << name << ";" << endl;
+  }
+
+  const_interface << "@end";
+
+  // this gets spit into the header file in ::close_generator
+  constants_declarations_ = const_interface.str();
+
+  // static variables in the .m hold all constant values
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    f_impl_ <<
+      "static " << type_name(type) << " " << cocoa_prefix_ << name;
+    if (!type->is_container() && !type->is_struct()) {
+      f_impl_ << " = " << render_const_value(name, type, (*c_iter)->get_value());
+    }
+    f_impl_ << ";" << endl;
+  }
+  f_impl_ << endl;
+
+  f_impl_ << "@implementation " << constants_class_name << endl;
+
+  // initialize complex constants when the class is loaded
+  f_impl_ << "+ (void) initialize ";
+  scope_up(f_impl_);
+
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    if ((*c_iter)->get_type()->is_container() ||
+        (*c_iter)->get_type()->is_struct()) {
+      string name = (*c_iter)->get_name();
+      f_impl_ << indent() << name << " = " << render_const_value(name,
+                                                                 (*c_iter)->get_type(),
+                                                                 (*c_iter)->get_value());
+      f_impl_ << ";" << endl;
+    }
+  }
+  scope_down(f_impl_);
+
+  // getter method for each constant
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    f_impl_ <<
+      "+ (" << type_name(type) << ") " << name;
+    scope_up(f_impl_);
+    indent(f_impl_) << "return " << name << ";" << endl;
+    scope_down(f_impl_);
+  }
+
+  f_impl_ << "@end" << endl << endl;
+}
+
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with protected data members, read(), write(), and getters and setters.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_struct(t_struct* tstruct) {
+  generate_cocoa_struct_interface(f_header_, tstruct, false);
+  generate_cocoa_struct_implementation(f_impl_, tstruct, false);
+}
+
+/**
+ * Exceptions are structs, but they inherit from NSException
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_xception(t_struct* txception) {
+  generate_cocoa_struct_interface(f_header_, txception, true);
+  generate_cocoa_struct_implementation(f_impl_, txception, true);
+}
+
+
+/**
+ * Generate the interface for a struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_interface(ofstream &out,
+                                                      t_struct* tstruct,
+                                                      bool is_exception) {
+  out << "@interface " << cocoa_prefix_ << tstruct->get_name() << " : ";
+
+  if (is_exception) {
+    out << "NSException ";
+  } else {
+    out << "NSObject ";
+  }
+
+  scope_up(out);
+
+  // members are protected.  this is redundant, but explicit.
+  //  f_header_ << endl << "@protected:" << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+
+  // member varialbes
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    out << indent() << declare_field(*m_iter) << endl;
+  }
+
+  if (members.size() > 0) {
+    out << endl;
+    // isset fields
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      indent(out) <<
+        "BOOL __" << (*m_iter)->get_name() << "_isset;" <<  endl;
+    }
+  }
+
+  scope_down(out);
+  out << endl;
+
+  // initializer for all fields
+  if (!members.empty()) {
+    generate_cocoa_struct_initializer_signature(out, tstruct);
+    out << ";" << endl;
+  }
+  out << endl;
+
+  // read and write
+  out << "- (void) read: (id <TProtocol>) inProtocol;" << endl;
+  out << "- (void) write: (id <TProtocol>) outProtocol;" << endl;
+  out << endl;
+
+  // getters and setters
+  generate_cocoa_struct_field_accessor_declarations(out, tstruct, is_exception);
+
+  out << "@end" << endl << endl;
+}
+
+
+/**
+ * Generate signature for initializer of struct with a parameter for
+ * each field.
+ */
+void t_cocoa_generator::generate_cocoa_struct_initializer_signature(ofstream &out,
+                                                                  t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  indent(out) << "- (id) initWith";
+  for (m_iter = members.begin(); m_iter != members.end(); ) {
+    if (m_iter == members.begin()) {
+      out << capitalize((*m_iter)->get_name());
+    } else {
+      out << (*m_iter)->get_name();
+    }
+    out << ": (" << type_name((*m_iter)->get_type()) << ") " <<
+      (*m_iter)->get_name();
+    ++m_iter;
+    if (m_iter != members.end()) {
+      out << " ";
+    }
+  }
+}
+
+
+/**
+ * Generate getter and setter declarations for all fields, plus an
+ * IsSet getter.
+ */
+void t_cocoa_generator::generate_cocoa_struct_field_accessor_declarations(ofstream &out,
+                                                                          t_struct* tstruct,
+                                                                          bool is_exception) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    out << indent() << "- (" << type_name((*m_iter)->get_type()) << ") " << decapitalize((*m_iter)->get_name()) << ";" << endl;
+    out << indent() << "- (void) set" << capitalize((*m_iter)->get_name()) <<
+      ": (" << type_name((*m_iter)->get_type()) << ") " << (*m_iter)->get_name() << ";" << endl;
+    out << indent() << "- (BOOL) " << (*m_iter)->get_name() << "IsSet;" << endl << endl;
+  }
+}
+
+
+/**
+ * Generate struct implementation.
+ *
+ * @param tstruct      The struct definition
+ * @param is_exception Is this an exception?
+ * @param is_result    If this is a result it needs a different writer
+ */
+void t_cocoa_generator::generate_cocoa_struct_implementation(ofstream &out,
+                                                             t_struct* tstruct,
+                                                             bool is_exception,
+                                                             bool is_result) {
+  indent(out) <<
+    "@implementation " << cocoa_prefix_ << tstruct->get_name() << endl;
+
+  // exceptions need to call the designated initializer on NSException
+  if (is_exception) {
+    out << indent() << "- (id) init" << endl;
+    scope_up(out);
+    out << indent() << "return [super initWithName: @\"" << tstruct->get_name() <<
+        "\" reason: @\"unknown\" userInfo: nil];" << endl;
+    scope_down(out);
+  }
+
+  // initializer with all fields as params
+  const vector<t_field*>& members = tstruct->get_members();
+  if (!members.empty()) {
+    generate_cocoa_struct_initializer_signature(out, tstruct);
+    out << endl;
+    scope_up(out);
+    if (is_exception) {
+      out << indent() << "self = [self init];" << endl;
+    } else {
+      out << indent() << "self = [super init];" << endl;
+    }
+
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      out << indent() << "__" << (*m_iter)->get_name() << " = ";
+      if (type_can_be_null(t)) {
+        out << "[" << (*m_iter)->get_name() << " retain];" << endl;
+      } else {
+        out << (*m_iter)->get_name() << ";" << endl;
+      }
+      out << indent() << "__" << (*m_iter)->get_name() << "_isset = YES;" << endl;
+    }
+
+    out << indent() << "return self;" << endl;
+    scope_down(out);
+    out << endl;
+  }
+
+  // dealloc
+  if (!members.empty()) {
+    out << "- (void) dealloc" << endl;
+    scope_up(out);
+
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if (type_can_be_null(t)) {
+        indent(out) << "[__" << (*m_iter)->get_name() << " release];" << endl;
+      }
+    }
+
+    out << indent() << "[super dealloc];" << endl;
+    scope_down(out);
+    out << endl;
+  }
+
+  // the rest of the methods
+  generate_cocoa_struct_field_accessor_implementations(out, tstruct, is_exception);
+  generate_cocoa_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_cocoa_struct_result_writer(out, tstruct);
+  } else {
+    generate_cocoa_struct_writer(out, tstruct);
+  }
+  generate_cocoa_struct_description(out, tstruct);
+
+  out << "@end" << endl << endl;
+}
+
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_reader(ofstream& out,
+                                                     t_struct* tstruct) {
+  out <<
+    "- (void) read: (id <TProtocol>) inProtocol" << endl;
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables
+  indent(out) << "NSString * fieldName;" << endl;
+  indent(out) << "int fieldType;" << endl;
+  indent(out) << "int fieldID;" << endl;
+  out << endl;
+
+  indent(out) << "[inProtocol readStructBeginReturningName: NULL];" << endl;
+
+  // Loop over reading in fields
+  indent(out) <<
+    "while (true)" << endl;
+    scope_up(out);
+
+    // Read beginning field marker
+    indent(out) <<
+      "[inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];" << endl;
+
+    // Check for field STOP marker and break
+    indent(out) <<
+      "if (fieldType == TType_STOP) { " << endl;
+    indent_up();
+    indent(out) <<
+      "break;" << endl;
+    indent_down();
+    indent(out) <<
+      "}" << endl;
+
+    // Switch statement on the field we are reading
+    indent(out) <<
+      "switch (fieldID)" << endl;
+
+      scope_up(out);
+
+      // Generate deserialization code for known cases
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        indent(out) <<
+          "case " << (*f_iter)->get_key() << ":" << endl;
+        indent_up();
+        indent(out) <<
+          "if (fieldType == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+        indent_up();
+
+        generate_deserialize_field(out, *f_iter, "fieldValue");
+        indent(out) << call_field_setter(*f_iter, "fieldValue") << endl;
+        // if this is an allocated field, release it since the struct
+        // is now retaining it
+        if (type_can_be_null((*f_iter)->get_type())) {
+          // deserialized strings are autorelease, so don't release them
+          if (!(get_true_type((*f_iter)->get_type())->is_string())) {
+            indent(out) << "[fieldValue release];" << endl;
+          }
+        }
+
+        indent_down();
+        out <<
+          indent() << "} else { " << endl <<
+          indent() << "  [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
+          indent() << "}" << endl <<
+          indent() << "break;" << endl;
+        indent_down();
+      }
+
+      // In the default case we skip the field
+      out <<
+        indent() << "default:" << endl <<
+        indent() << "  [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
+        indent() << "  break;" << endl;
+
+      scope_down(out);
+
+    // Read field end marker
+    indent(out) <<
+      "[inProtocol readFieldEnd];" << endl;
+
+    scope_down(out);
+
+    out <<
+      indent() << "[inProtocol readStructEnd];" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_writer(ofstream& out,
+                                                     t_struct* tstruct) {
+  out <<
+    indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out <<
+    indent() << "[outProtocol writeStructBeginWithName: @\"" << name << "\"];" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out <<
+      indent() << "if (__" << (*f_iter)->get_name() << "_isset) {" << endl;
+    indent_up();
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out <<
+        indent() << "if (__" << (*f_iter)->get_name() << " != nil) {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
+      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
+      " fieldID: " << (*f_iter)->get_key() << "];" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "__"+(*f_iter)->get_name());
+
+    // Write field closer
+    indent(out) <<
+      "[outProtocol writeFieldEnd];" << endl;
+
+    if (null_allowed) {
+      scope_down(out);
+    }
+    scope_down(out);
+  }
+  // Write the struct map
+  out <<
+    indent() << "[outProtocol writeFieldStop];" << endl <<
+    indent() << "[outProtocol writeStructEnd];" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct, which
+ * is a function result. These fields are only written if they are
+ * set, and only one of them can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_result_writer(ofstream& out,
+                                                            t_struct* tstruct) {
+  out <<
+    indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out <<
+    indent() << "[outProtocol writeStructBeginWithName: @\"" << name << "\"];" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out <<
+        endl <<
+        indent() << "if ";
+    } else {
+      out <<
+        " else if ";
+    }
+
+    out <<
+      "(__" << (*f_iter)->get_name() << "_isset) {" << endl;
+    indent_up();
+
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out <<
+        indent() << "if (__" << (*f_iter)->get_name() << " != nil) {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
+      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
+      " fieldID: " << (*f_iter)->get_key() << "];" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "__"+(*f_iter)->get_name());
+
+    // Write field closer
+    indent(out) <<
+      "[outProtocol writeFieldEnd];" << endl;
+
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+
+    indent_down();
+    indent(out) << "}";
+  }
+  // Write the struct map
+  out <<
+    endl <<
+    indent() << "[outProtocol writeFieldStop];" << endl <<
+    indent() << "[outProtocol writeStructEnd];" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generate property accessor methods for all fields in the struct.
+ * getter, setter, isset getter.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_field_accessor_implementations(ofstream& out,
+                                                                             t_struct* tstruct,
+                                                                             bool is_exception) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = field_name;
+    cap_name[0] = toupper(cap_name[0]);
+
+    // Simple getter
+    indent(out) << "- (" << type_name(type) << ") ";
+    out << field_name << " {" << endl;
+    indent_up();
+    if (!type_can_be_null(type)) {
+      indent(out) << "return __" << field_name << ";" << endl;
+    } else {
+      indent(out) << "return [[__" << field_name << " retain] autorelease];" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Simple setter
+    indent(out) << "- (void) set" << cap_name << ": (" << type_name(type) <<
+      ") " << field_name << " {" << endl;
+    indent_up();
+    if (!type_can_be_null(type)) {
+      indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
+    } else {
+      indent(out) << "[" << field_name << " retain];" << endl;
+      indent(out) << "[__" << field_name << " release];" << endl;
+      indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
+    }
+    indent(out) << "__" << field_name << "_isset = YES;" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // IsSet
+    indent(out) << "- (BOOL) " << field_name << "IsSet {" << endl;
+    indent_up();
+    indent(out) << "return __" << field_name << "_isset;" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Unsetter - do we need this?
+    indent(out) << "- (void) unset" << cap_name << " {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "[__" << field_name << " release];" << endl;
+      indent(out) << "__" << field_name << " = nil;" << endl;
+    }
+    indent(out) << "__" << field_name << "_isset = NO;" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a description method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_description(ofstream& out,
+                                                          t_struct* tstruct) {
+  out <<
+    indent() << "- (NSString *) description {" << endl;
+  indent_up();
+
+  out <<
+    indent() << "NSMutableString * ms = [NSMutableString stringWithString: @\"" <<
+    tstruct->get_name() << "(\"];" << endl;
+
+  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;
+      indent(out) << "[ms appendString: @\"" << (*f_iter)->get_name() << ":\"];" << endl;
+    } else {
+      indent(out) << "[ms appendString: @\"," << (*f_iter)->get_name() << ":\"];" << endl;
+    }
+    t_type* ttype = (*f_iter)->get_type();
+    indent(out) << "[ms appendFormat: @\"" << format_string_for_type(ttype) << "\", __" <<
+      (*f_iter)->get_name() << "];" << endl;
+  }
+  out <<
+    indent() << "[ms appendString: @\")\"];" << endl <<
+    indent() << "return [ms copy];" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl <<
+    endl;
+}
+
+
+/**
+ * Generates a thrift service.  In Objective-C this consists of a
+ * protocol definition, a client interface and a client implementation.
+ *
+ * @param tservice The service definition
+ */
+void t_cocoa_generator::generate_service(t_service* tservice) {
+  generate_cocoa_service_protocol(f_header_, tservice);
+  generate_cocoa_service_client_interface(f_header_, tservice);
+  generate_cocoa_service_helpers(tservice);
+  generate_cocoa_service_client_implementation(f_impl_, tservice);
+}
+
+
+/**
+ * Generates structs for all the service return types
+ *
+ * @param tservice The service
+ */
+void t_cocoa_generator::generate_cocoa_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) {
+    generate_function_helpers(*f_iter);
+  }
+}
+
+string t_cocoa_generator::function_result_helper_struct_type(t_function* tfunction) {
+  return capitalize(tfunction->get_name()) + "Result_";
+}
+
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_cocoa_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  // create a result struct with a success field of the return type,
+  // and a field for each type of exception thrown
+  t_struct result(program_, function_result_helper_struct_type(tfunction));
+  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 the result struct
+  generate_cocoa_struct_interface(f_impl_, &result, false);
+  generate_cocoa_struct_implementation(f_impl_, &result, false, true);
+}
+
+/**
+ * Generates a service protocol definition.
+ *
+ * @param tservice The service to generate a protocol definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_protocol(ofstream& out,
+                                                        t_service* tservice) {
+  out << "@protocol " << cocoa_prefix_ << tservice->get_name() << " <NSObject>" << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    out << "- " << function_signature(*f_iter) << ";" <<
+      "  // throws ";
+    t_struct* xs = (*f_iter)->get_xceptions();
+    const std::vector<t_field*>& xceptions = xs->get_members();
+    vector<t_field*>::const_iterator x_iter;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      out << type_name((*x_iter)->get_type()) + ", ";
+    }
+    out << "TException" << endl;
+  }
+  out << "@end" << endl << endl;
+}
+
+
+/**
+ * Generates a service client interface definition.
+ *
+ * @param tservice The service to generate a client interface definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_interface(ofstream& out,
+                                                                t_service* tservice) {
+  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : NSObject <" <<
+    cocoa_prefix_ << tservice->get_name() << "> ";
+
+  scope_up(out);
+  out << indent() << "id <TProtocol> inProtocol;" << endl;
+  out << indent() << "id <TProtocol> outProtocol;" << endl;
+  scope_down(out);
+
+  out << "- (id) initWithProtocol: (id <TProtocol>) protocol;" << endl;
+  out << "- (id) initWithInProtocol: (id <TProtocol>) inProtocol outProtocol: (id <TProtocol>) outProtocol;" << endl;
+  out << "@end" << endl << endl;
+}
+
+
+/**
+ * Generates a service client implementation.
+ *
+ * @param tservice The service to generate an implementation for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_implementation(ofstream& out,
+                                                                     t_service* tservice) {
+  out << "@implementation " << cocoa_prefix_ << tservice->get_name() << "Client" << endl;
+
+  // initializers
+  out << "- (id) initWithProtocol: (id <TProtocol>) protocol" << endl;
+  scope_up(out);
+  out << indent() << "return [self initWithInProtocol: protocol outProtocol: protocol];" << endl;
+  scope_down(out);
+  out << endl;
+
+  out << "- (id) initWithInProtocol: (id <TProtocol>) anInProtocol outProtocol: (id <TProtocol>) anOutProtocol" << endl;
+  scope_up(out);
+  out << indent() << "[super init];" << endl;
+  out << indent() << "inProtocol = [anInProtocol retain];" << endl;
+  out << indent() << "outProtocol = [anOutProtocol retain];" << endl;
+  out << indent() << "return self;" << endl;
+  scope_down(out);
+  out << endl;
+
+  // dealloc
+  out << "- (void) dealloc" << endl;
+  scope_up(out);
+  out << indent() << "[inProtocol release];" << endl;
+  out << indent() << "[outProtocol release];" << endl;
+  out << indent() << "[super dealloc];" << endl;
+  scope_down(out);
+  out << endl;
+
+  // generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+
+    t_function send_function(g_type_void,
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
+
+    string argsname = (*f_iter)->get_name() + "_args";
+
+    // Open function
+    indent(out) <<
+      "- " << function_signature(&send_function) << endl;
+    scope_up(out);
+
+    // Serialize the request
+    out <<
+      indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\"" <<
+      " type: TMessageType_CALL" <<
+      " sequenceID: 0];" << endl;
+
+    out <<
+      indent() << "[outProtocol writeStructBeginWithName: @\"" << argsname << "\"];" << endl;
+
+    // write out function parameters
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      string fieldName = (*fld_iter)->get_name();
+      if (type_can_be_null((*fld_iter)->get_type())) {
+        out << indent() << "if (" << fieldName << " != nil)";
+        scope_up(out);
+      }
+      out <<
+        indent() << "[outProtocol writeFieldBeginWithName: @\"" << fieldName << "\""
+        " type: " << type_to_enum((*fld_iter)->get_type()) <<
+        " fieldID: " << (*fld_iter)->get_key() << "];" << endl;
+
+      generate_serialize_field(out, *fld_iter, fieldName);
+
+      out <<
+        indent() << "[outProtocol writeFieldEnd];" << endl;
+
+      if (type_can_be_null((*fld_iter)->get_type())) {
+        scope_down(out);
+      }
+    }
+
+    out <<
+      indent() << "[outProtocol writeFieldStop];" << endl;
+    out <<
+      indent() << "[outProtocol writeStructEnd];" << endl;
+
+    out <<
+      indent() << "[outProtocol writeMessageEnd];" << endl <<
+      indent() << "[[outProtocol transport] flush];" << endl;
+
+    scope_down(out);
+    out << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+      // Open function
+      indent(out) <<
+        "- " << function_signature(&recv_function) << endl;
+      scope_up(out);
+
+      // TODO(mcslee): Message validation here, was the seqid etc ok?
+
+      // check for an exception
+      out <<
+        indent() << "int msgType = 0;" << endl <<
+        indent() << "[inProtocol readMessageBeginReturningName: nil type: &msgType sequenceID: NULL];" << endl <<
+        indent() << "if (msgType == TMessageType_EXCEPTION) {" << endl <<
+        indent() << "  TApplicationException * x = [TApplicationException read: inProtocol];" << endl <<
+        indent() << "  [inProtocol readMessageEnd];" << endl <<
+        indent() << "  @throw x;" << endl <<
+        indent() << "}" << endl;
+
+      // FIXME - could optimize here to reduce creation of temporary objects.
+      string resultname = function_result_helper_struct_type(*f_iter);
+      out <<
+        indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_ <<
+        resultname << " alloc] init] autorelease];" << endl;
+      indent(out) << "[result read: inProtocol];" << endl;
+      indent(out) << "[inProtocol readMessageEnd];" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out <<
+          indent() << "if ([result successIsSet]) {" << endl <<
+          indent() << "  return [result success];" << endl <<
+          indent() << "}" << endl;
+      }
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        out <<
+          indent() << "if ([result " << (*x_iter)->get_name() << "IsSet]) {" << endl <<
+          indent() << "  @throw [result " << (*x_iter)->get_name() << "];" << endl <<
+          indent() << "}" << endl;
+      }
+
+      // If you get here it's an exception, unless a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(out) <<
+          "return;" << endl;
+      } else {
+        out <<
+          indent() << "@throw [TApplicationException exceptionWithType: TApplicationException_MISSING_RESULT" << endl <<
+          indent() << "                                         reason: @\"" << (*f_iter)->get_name() << " failed: unknown result\"];" << endl;
+      }
+
+      // Close function
+      scope_down(out);
+      out << endl;
+    }
+
+    // Open function
+    indent(out) <<
+      "- " << function_signature(*f_iter) << endl;
+    scope_up(out);
+    indent(out) <<
+      "[self send_" << funname;
+
+    // Declare the function arguments
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        out << " ";
+      }
+      out << ": " << (*fld_iter)->get_name();
+    }
+    out << "];" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      out << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out << "return ";
+      }
+      out <<
+        "[self recv_" << funname << "];" << endl;
+    }
+    scope_down(out);
+    out << endl;
+  }
+
+  indent_down();
+
+  out << "@end" << endl << endl;
+}
+
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param fieldName The variable name for this field
+ */
+void t_cocoa_generator::generate_deserialize_field(ofstream& out,
+                                                   t_field* tfield,
+                                                   string fieldName) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type,
+                                fieldName);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, fieldName);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) <<
+      type_name(type) << " " << fieldName << " = [inProtocol ";
+
+    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: " +
+          tfield->get_name();
+        break;
+      case t_base_type::TYPE_STRING:
+        if (((t_base_type*)type)->is_binary()) {
+          out << "readBinary];";
+        } else {
+          out << "readString];";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool];";
+        break;
+      case t_base_type::TYPE_BYTE:
+        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 Objective-C name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32];";
+    }
+    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());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, allocates the struct and invokes read:
+ */
+void t_cocoa_generator::generate_deserialize_struct(ofstream& out,
+                                                    t_struct* tstruct,
+                                                    string fieldName) {
+  indent(out) << type_name(tstruct) << fieldName << " = [[" <<
+    type_name(tstruct, true) << " alloc] init];" << endl;
+  indent(out) << "[" << fieldName << " read: inProtocol];" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_cocoa_generator::generate_deserialize_container(ofstream& out,
+                                                       t_type* ttype,
+                                                       string fieldName) {
+  string size = tmp("_size");
+  indent(out) << "int " << size << ";" << endl;
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out)
+      << "[inProtocol readMapBeginReturningKeyType: NULL valueType: NULL size: &" <<
+      size << "];" << endl;
+    indent(out) << "NSMutableDictionary * " << fieldName <<
+      " = [[NSMutableDictionary alloc] initWithCapacity: " << size << "];" << endl;
+  } else if (ttype->is_set()) {
+    indent(out)
+      << "[inProtocol readSetBeginReturningElementType: NULL size: &" << size << "];" << endl;
+    indent(out) << "NSMutableSet * " << fieldName <<
+      " = [[NSMutableSet alloc] initWithCapacity: " << size << "];" << endl;
+  } else if (ttype->is_list()) {
+    indent(out)
+      << "[inProtocol readListBeginReturningElementType: NULL size: &" << size << "];" << endl;
+    indent(out) << "NSMutableArray * " << fieldName <<
+      " = [[NSMutableArray alloc] initWithCapacity: " << size << "];" << endl;
+  }
+  // FIXME - the code above does not verify that the element types of
+  // the containers being read match the element types of the
+  // containers we are reading into.  Does that matter?
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "int " << i << ";" << endl <<
+    indent() << "for (" << i << " = 0; " <<
+    i << " < " << size << "; " <<
+    "++" << i << ")" << endl;
+
+    scope_up(out);
+
+    if (ttype->is_map()) {
+      generate_deserialize_map_element(out, (t_map*)ttype, fieldName);
+    } else if (ttype->is_set()) {
+      generate_deserialize_set_element(out, (t_set*)ttype, fieldName);
+    } else if (ttype->is_list()) {
+      generate_deserialize_list_element(out, (t_list*)ttype, fieldName);
+    }
+
+    scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "[inProtocol readMapEnd];" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "[inProtocol readSetEnd];" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "[inProtocol readListEnd];" << endl;
+  }
+
+}
+
+
+/**
+ * Take a variable of a given type and wrap it in code to make it
+ * suitable for putting into a container, if necessary.  Basically,
+ * wrap scaler primitives in NSNumber objects.
+ */
+string t_cocoa_generator::containerize(t_type * ttype,
+                                       string fieldName)
+{
+  // FIXME - optimize here to avoid autorelease pool?
+  ttype = get_true_type(ttype);
+  if (ttype->is_enum()) {
+    return "[NSNumber numberWithInt: " + fieldName + "]";
+  } else if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "can't containerize void";
+    case t_base_type::TYPE_BOOL:
+      return "[NSNumber numberWithBool: " + fieldName + "]";
+    case t_base_type::TYPE_BYTE:
+      return "[NSNumber numberWithUnsignedChar: " + fieldName + "]";
+    case t_base_type::TYPE_I16:
+      return "[NSNumber numberWithShort: " + fieldName + "]";
+    case t_base_type::TYPE_I32:
+      return "[NSNumber numberWithLong: " + fieldName + "]";
+    case t_base_type::TYPE_I64:
+      return "[NSNumber numberWithLongLong: " + fieldName + "]";
+    case t_base_type::TYPE_DOUBLE:
+      return "[NSNumber numberWithDouble: " + fieldName + "]";
+    default:
+      break;
+    }
+  }
+
+  // do nothing
+  return fieldName;
+}
+
+
+/**
+ * Generates code to deserialize a map element
+ */
+void t_cocoa_generator::generate_deserialize_map_element(ofstream& out,
+                                                         t_map* tmap,
+                                                         string fieldName) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  generate_deserialize_field(out, &fkey, key);
+  generate_deserialize_field(out, &fval, val);
+
+  indent(out) <<
+    "[" << fieldName << " setObject: " << containerize(fval.get_type(), val) <<
+    " forKey: " << containerize(fkey.get_type(), key) << "];" << endl;
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_cocoa_generator::generate_deserialize_set_element(ofstream& out,
+                                                         t_set* tset,
+                                                         string fieldName) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem, elem);
+
+  indent(out) <<
+    "[" << fieldName << " addObject: " << containerize(felem.get_type(), elem) << "];" << endl;
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_cocoa_generator::generate_deserialize_list_element(ofstream& out,
+                                                          t_list* tlist,
+                                                          string fieldName) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem, elem);
+
+  indent(out) <<
+    "[" << fieldName << " addObject: " << containerize(felem.get_type(), elem) << "];" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param fieldName Name to of the variable holding the field
+ */
+void t_cocoa_generator::generate_serialize_field(ofstream& out,
+                                                 t_field* tfield,
+                                                 string fieldName) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out,
+                              (t_struct*)type,
+                              fieldName);
+  } else if (type->is_container()) {
+    generate_serialize_container(out,
+                                 type,
+                                 fieldName);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) <<
+      "[outProtocol ";
+
+    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: " + fieldName;
+        break;
+      case t_base_type::TYPE_STRING:
+        if (((t_base_type*)type)->is_binary()) {
+          out << "writeBinary: " << fieldName << "];";
+        } else {
+          out << "writeString: " << fieldName << "];";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool: " << fieldName << "];";
+        break;
+      case t_base_type::TYPE_BYTE:
+        out << "writeByte: " << fieldName << "];";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16: " << fieldName << "];";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32: " << fieldName << "];";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64: " << fieldName << "];";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble: " << fieldName << "];";
+        break;
+      default:
+        throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32: " << fieldName << "];";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serialize a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param fieldName Name of variable holding struct
+ */
+void t_cocoa_generator::generate_serialize_struct(ofstream& out,
+                                                  t_struct* tstruct,
+                                                  string fieldName) {
+  out <<
+    indent() << "[" << fieldName << " write: outProtocol];" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype  The type of container
+ * @param fieldName Name of variable holding container
+ */
+void t_cocoa_generator::generate_serialize_container(ofstream& out,
+                                                     t_type* ttype,
+                                                     string fieldName) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "[outProtocol writeMapBeginWithKeyType: " <<
+      type_to_enum(((t_map*)ttype)->get_key_type()) << " valueType: " <<
+      type_to_enum(((t_map*)ttype)->get_val_type()) << " size: [" <<
+      fieldName << " count]];" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "[outProtocol writeSetBeginWithElementType: " <<
+      type_to_enum(((t_set*)ttype)->get_elem_type()) << " size: [" <<
+      fieldName << " count]];" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "[outProtocol writeListBeginWithElementType: " <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << " size: [" <<
+      fieldName << " count]];" << endl;
+  }
+
+  string iter = tmp("_iter");
+  string key;
+  if (ttype->is_map()) {
+    key = tmp("key");
+    indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " keyEnumerator];" << endl;
+    indent(out) << "id " << key << ";" << endl;
+    indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
+  } else if (ttype->is_set()) {
+    key = tmp("obj");
+    indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " objectEnumerator];" << endl;
+    indent(out) << "id " << key << ";" << endl;
+    indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
+  } else if (ttype->is_list()) {
+    key = tmp("i");
+    indent(out) << "int " << key << ";" << endl;
+    indent(out) <<
+      "for (" << key << " = 0; " << key << " < [" << fieldName << " count]; " << key << "++)" << endl;
+  }
+
+    scope_up(out);
+
+    if (ttype->is_map()) {
+      generate_serialize_map_element(out, (t_map*)ttype, key, fieldName);
+    } else if (ttype->is_set()) {
+      generate_serialize_set_element(out, (t_set*)ttype, key);
+    } else if (ttype->is_list()) {
+      generate_serialize_list_element(out, (t_list*)ttype, key, fieldName);
+    }
+
+    scope_down(out);
+
+    if (ttype->is_map()) {
+      indent(out) <<
+        "[outProtocol writeMapEnd];" << endl;
+    } else if (ttype->is_set()) {
+      indent(out) <<
+        "[outProtocol writeSetEnd];" << endl;
+    } else if (ttype->is_list()) {
+      indent(out) <<
+        "[outProtocol writeListEnd];" << endl;
+    }
+
+  scope_down(out);
+}
+
+/**
+ * Given a field variable name, wrap it in code that converts it to a
+ * primitive type, if necessary.
+ */
+string t_cocoa_generator::decontainerize(t_field * tfield,
+                                         string fieldName)
+{
+  t_type * ttype = get_true_type(tfield->get_type());
+  if (ttype->is_enum()) {
+    return "[" + fieldName + " intValue]";
+  } else if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "can't decontainerize void";
+    case t_base_type::TYPE_BOOL:
+      return "[" + fieldName + " boolValue]";
+    case t_base_type::TYPE_BYTE:
+      return "[" + fieldName + " unsignedCharValue]";
+    case t_base_type::TYPE_I16:
+      return "[" + fieldName + " shortValue]";
+    case t_base_type::TYPE_I32:
+      return "[" + fieldName + " longValue]";
+    case t_base_type::TYPE_I64:
+      return "[" + fieldName + " longLongValue]";
+    case t_base_type::TYPE_DOUBLE:
+      return "[" + fieldName + " doubleValue]";
+    default:
+      break;
+    }
+  }
+
+  // do nothing
+  return fieldName;
+}
+
+
+/**
+ * Serializes the members of a map.
+ */
+void t_cocoa_generator::generate_serialize_map_element(ofstream& out,
+                                                       t_map* tmap,
+                                                       string key,
+                                                       string mapName) {
+  t_field kfield(tmap->get_key_type(), key);
+  generate_serialize_field(out, &kfield, decontainerize(&kfield, key));
+  t_field vfield(tmap->get_val_type(), "[" + mapName + " objectForKey: " + key + "]");
+  generate_serialize_field(out, &vfield, decontainerize(&vfield, vfield.get_name()));
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_cocoa_generator::generate_serialize_set_element(ofstream& out,
+                                                       t_set* tset,
+                                                       string elementName) {
+  t_field efield(tset->get_elem_type(), elementName);
+  generate_serialize_field(out, &efield, decontainerize(&efield, elementName));
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_cocoa_generator::generate_serialize_list_element(ofstream& out,
+                                                        t_list* tlist,
+                                                        string index,
+                                                        string listName) {
+  t_field efield(tlist->get_elem_type(), "[" + listName + " objectAtIndex: " + index + "]");
+  generate_serialize_field(out, &efield, decontainerize(&efield, efield.get_name()));
+}
+
+
+/**
+ * Returns an Objective-C name
+ *
+ * @param ttype The type
+ * @param class_ref Do we want a Class reference istead of a type reference?
+ * @return Java type name, i.e. HashMap<Key,Value>
+ */
+string t_cocoa_generator::type_name(t_type* ttype, bool class_ref) {
+  if (ttype->is_typedef()) {
+    return cocoa_prefix_ + ttype->get_name();
+  }
+
+  string result;
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype);
+  } else if (ttype->is_enum()) {
+    return "int";
+  } else if (ttype->is_map()) {
+    result = "NSDictionary";
+  } else if (ttype->is_set()) {
+    result = "NSSet";
+  } else if (ttype->is_list()) {
+    result = "NSArray";
+  } else {
+    // Check for prefix
+    t_program* program = ttype->get_program();
+    if (program != NULL) {
+      result = program->get_namespace("cocoa") + ttype->get_name();
+    } else {
+      result = ttype->get_name();
+    }
+  }
+
+  if (!class_ref) {
+    result += " *";
+  }
+  return result;
+}
+
+/**
+ * Returns the Objective-C type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ */
+string t_cocoa_generator::base_type_name(t_base_type* type) {
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (type->is_binary()) {
+      return "NSData *";
+    } else {
+      return "NSString *";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "BOOL";
+  case t_base_type::TYPE_BYTE:
+    return "uint8_t";
+  case t_base_type::TYPE_I16:
+    return"int16_t";
+  case t_base_type::TYPE_I32:
+    return "int32_t";
+  case t_base_type::TYPE_I64:
+    return"int64_t";
+  case t_base_type::TYPE_DOUBLE:
+    return "double";
+  default:
+    throw "compiler error: no objective-c name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+
+/**
+ * Spit out code that evaluates to the specified constant value.
+ */
+string t_cocoa_generator::render_const_value(string name,
+                                             t_type* type,
+                                             t_const_value* value,
+                                             bool containerize_it) {
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      render << "@\"" << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "YES" : "NO");
+      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:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << 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()) {
+    render << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    render << "[[" << type_name(type, true) << " alloc] initWith";
+    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) {
+        render << capitalize(v_iter->first->get_string());
+        first = false;
+      } else {
+        render << " " << v_iter->first->get_string();
+      }
+      render << ": " << render_const_value(name, field_type, v_iter->second);
+    }
+    render << "]";
+  } else if (type->is_map()) {
+    render << "[[NSDictionary alloc] initWithObjectsAndKeys: ";
+    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;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(name, ktype, v_iter->first, true);
+      string val = render_const_value(name, vtype, v_iter->second, true);
+      if (first) {
+        first = false;
+      } else {
+        render << ", ";
+      }
+      render << val << ", " << key;
+    }
+    render << ", nil]";
+  } else if (type->is_list()) {
+    render << "[[NSArray alloc] initWithObjects: ";
+    t_type * etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    bool first = true;
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (first) {
+        first = false;
+      } else {
+        render << ", ";
+      }
+      render << render_const_value(name, etype, *v_iter, true);
+    }
+    render << ", nil]";
+  } else if (type->is_set()) {
+    render << "[[NSSet alloc] initWithObjects: ";
+    t_type * etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    bool first = true;
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (first) {
+        first = false;
+      } else {
+        render << ", ";
+      }
+      render << render_const_value(name, etype, *v_iter, true);
+    }
+    render << ", nil]";
+  } else {
+    throw "don't know how to render constant for type: " + type->get_name();
+  }
+
+  if (containerize_it) {
+    return containerize(type, render.str());
+  }
+
+  return render.str();
+}
+
+
+/**
+ * Declares a field.
+ *
+ * @param ttype The type
+ */
+string t_cocoa_generator::declare_field(t_field* tfield) {
+  return type_name(tfield->get_type()) + " __" + tfield->get_name() + ";";
+}
+
+/**
+ * Renders a function signature
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cocoa_generator::function_signature(t_function* tfunction) {
+  t_type* ttype = tfunction->get_returntype();
+  std::string result =
+    "(" + type_name(ttype) + ") " + tfunction->get_name() + argument_list(tfunction->get_arglist());
+  return result;
+}
+
+
+/**
+ * Renders a colon separated list of types and names, suitable for an
+ * objective-c parameter list
+ */
+string t_cocoa_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;
+    } else {
+      result += " ";
+    }
+    result += ": (" + type_name((*f_iter)->get_type()) + ") " + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+
+/**
+ * Converts the parse type to an Objective-C enum string for the given type.
+ */
+string t_cocoa_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();
+}
+
+
+/**
+ * Returns a format string specifier for the supplied parse type.
+ */
+string t_cocoa_generator::format_string_for_type(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 "\\\"%@\\\"";
+    case t_base_type::TYPE_BOOL:
+      return "%i";
+    case t_base_type::TYPE_BYTE:
+      return "%i";
+    case t_base_type::TYPE_I16:
+      return "%hi";
+    case t_base_type::TYPE_I32:
+      return "%i";
+    case t_base_type::TYPE_I64:
+      return "%qi";
+    case t_base_type::TYPE_DOUBLE:
+      return "%f";
+    }
+  } else if (type->is_enum()) {
+    return "%i";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "%@";
+  } else if (type->is_map()) {
+    return "%@";
+  } else if (type->is_set()) {
+    return "%@";
+  } else if (type->is_list()) {
+    return "%@";
+  }
+
+  throw "INVALID TYPE IN format_string_for_type: " + type->get_name();
+}
+
+/**
+ * Generate a call to a field's setter.
+ *
+ * @param tfield Field the setter is being called on
+ * @param fieldName Name of variable to pass to setter
+ */
+
+string t_cocoa_generator::call_field_setter(t_field* tfield, string fieldName) {
+  return "[self set" + capitalize(tfield->get_name()) + ": " + fieldName + "];";
+}
+
+
+THRIFT_REGISTER_GENERATOR(cocoa, "Cocoa", "");
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
new file mode 100644
index 0000000..67a4bd4
--- /dev/null
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -0,0 +1,3003 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <cassert>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <sys/stat.h>
+
+#include "platform.h"
+#include "t_oop_generator.h"
+using namespace std;
+
+
+/**
+ * C++ code generator. This is legitimacy incarnate.
+ *
+ */
+class t_cpp_generator : public t_oop_generator {
+ public:
+  t_cpp_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    std::map<std::string, std::string>::const_iterator iter;
+
+    iter = parsed_options.find("dense");
+    gen_dense_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("include_prefix");
+    use_include_prefix_ = (iter != parsed_options.end());
+
+    out_dir_base_ = "gen-cpp";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct) {
+    generate_cpp_struct(tstruct, false);
+  }
+  void generate_xception(t_struct* txception) {
+    generate_cpp_struct(txception, true);
+  }
+  void generate_cpp_struct(t_struct* tstruct, bool is_exception);
+
+  void generate_service(t_service* tservice);
+
+  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+  std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+
+  void generate_struct_definition    (std::ofstream& out, t_struct* tstruct, bool is_exception=false, bool pointers=false, bool read=true, bool write=true);
+  void generate_struct_fingerprint   (std::ofstream& out, t_struct* tstruct, bool is_definition);
+  void generate_struct_reader        (std::ofstream& out, t_struct* tstruct, bool pointers=false);
+  void generate_struct_writer        (std::ofstream& out, t_struct* tstruct, bool pointers=false);
+  void generate_struct_result_writer (std::ofstream& out, t_struct* tstruct, bool pointers=false);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_interface (t_service* tservice);
+  void generate_service_null      (t_service* tservice);
+  void generate_service_multiface (t_service* tservice);
+  void generate_service_helpers   (t_service* tservice);
+  void generate_service_client    (t_service* tservice);
+  void generate_service_processor (t_service* tservice);
+  void generate_service_skeleton  (t_service* tservice);
+  void generate_process_function  (t_service* tservice, t_function* tfunction);
+  void generate_function_helpers  (t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream& out,
+                                          t_field*    tfield,
+                                          std::string prefix="",
+                                          std::string suffix="");
+
+  void generate_deserialize_struct       (std::ofstream& out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_deserialize_container    (std::ofstream& out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_deserialize_set_element  (std::ofstream& out,
+                                          t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (std::ofstream& out,
+                                          t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (std::ofstream& out,
+                                          t_list*     tlist,
+                                          std::string prefix,
+                                          bool push_back,
+                                          std::string index);
+
+  void generate_serialize_field          (std::ofstream& out,
+                                          t_field*    tfield,
+                                          std::string prefix="",
+                                          std::string suffix="");
+
+  void generate_serialize_struct         (std::ofstream& out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::ofstream& out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream& out,
+                                          t_map*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_set_element    (std::ofstream& out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream& out,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string namespace_prefix(std::string ns);
+  std::string namespace_open(std::string ns);
+  std::string namespace_close(std::string ns);
+  std::string type_name(t_type* ttype, bool in_typedef=false, bool arg=false);
+  std::string base_type_name(t_base_type::t_base tbase);
+  std::string declare_field(t_field* tfield, bool init=false, bool pointer=false, bool constant=false, bool reference=false);
+  std::string function_signature(t_function* tfunction, std::string prefix="", bool name_params=true);
+  std::string argument_list(t_struct* tstruct, bool name_params=true);
+  std::string type_to_enum(t_type* ttype);
+  std::string local_reflection_name(const char*, t_type* ttype, bool external=false);
+
+  // These handles checking gen_dense_ and checking for duplicates.
+  void generate_local_reflection(std::ofstream& out, t_type* ttype, bool is_definition);
+  void generate_local_reflection_pointer(std::ofstream& out, t_type* ttype);
+
+  bool is_complex_type(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return
+      ttype->is_container() ||
+      ttype->is_struct() ||
+      ttype->is_xception() ||
+      (ttype->is_base_type() && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING));
+  }
+
+  void set_use_include_prefix(bool use_include_prefix) {
+    use_include_prefix_ = use_include_prefix;
+  }
+
+ private:
+  /**
+   * Returns the include prefix to use for a file generated by program, or the
+   * empty string if no include prefix should be used.
+   */
+  std::string get_include_prefix(const t_program& program) const;
+
+  /**
+   * True iff we should generate local reflection metadata for TDenseProtocol.
+   */
+  bool gen_dense_;
+
+  /**
+   * True iff we should use a path prefix in our #include statements for other
+   * thrift-generated header files.
+   */
+  bool use_include_prefix_;
+
+  /**
+   * Strings for namespace, computed once up front then used directly
+   */
+
+  std::string ns_open_;
+  std::string ns_close_;
+
+  /**
+   * File streams, stored here to avoid passing them as parameters to every
+   * function.
+   */
+
+  std::ofstream f_types_;
+  std::ofstream f_types_impl_;
+  std::ofstream f_header_;
+  std::ofstream f_service_;
+
+  /**
+   * When generating local reflections, make sure we don't generate duplicates.
+   */
+  std::set<std::string> reflected_fingerprints_;
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_cpp_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string f_types_name = get_out_dir()+program_name_+"_types.h";
+  f_types_.open(f_types_name.c_str());
+
+  string f_types_impl_name = get_out_dir()+program_name_+"_types.cpp";
+  f_types_impl_.open(f_types_impl_name.c_str());
+
+  // Print header
+  f_types_ <<
+    autogen_comment();
+  f_types_impl_ <<
+    autogen_comment();
+
+  // Start ifndef
+  f_types_ <<
+    "#ifndef " << program_name_ << "_TYPES_H" << endl <<
+    "#define " << program_name_ << "_TYPES_H" << endl <<
+    endl;
+
+  // Include base types
+  f_types_ <<
+    "#include <Thrift.h>" << endl <<
+    "#include <protocol/TProtocol.h>" << endl <<
+    "#include <transport/TTransport.h>" << endl <<
+    endl;
+
+  // Include other Thrift includes
+  const vector<t_program*>& includes = program_->get_includes();
+  for (size_t i = 0; i < includes.size(); ++i) {
+    f_types_ <<
+      "#include \"" << get_include_prefix(*(includes[i])) <<
+      includes[i]->get_name() << "_types.h\"" << endl;
+  }
+  f_types_ << endl;
+
+  // Include custom headers
+  const vector<string>& cpp_includes = program_->get_cpp_includes();
+  for (size_t i = 0; i < cpp_includes.size(); ++i) {
+    if (cpp_includes[i][0] == '<') {
+      f_types_ <<
+        "#include " << cpp_includes[i] << endl;
+    } else {
+      f_types_ <<
+        "#include \"" << cpp_includes[i] << "\"" << endl;
+    }
+  }
+  f_types_ <<
+    endl;
+
+  // Include the types file
+  f_types_impl_ <<
+    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
+    "_types.h\"" << endl <<
+    endl;
+
+  // If we are generating local reflection metadata, we need to include
+  // the definition of TypeSpec.
+  if (gen_dense_) {
+    f_types_impl_ <<
+      "#include <TReflectionLocal.h>" << endl <<
+      endl;
+  }
+
+  // Open namespace
+  ns_open_ = namespace_open(program_->get_namespace("cpp"));
+  ns_close_ = namespace_close(program_->get_namespace("cpp"));
+
+  f_types_ <<
+    ns_open_ << endl <<
+    endl;
+
+  f_types_impl_ <<
+    ns_open_ << endl <<
+    endl;
+}
+
+/**
+ * Closes the output files.
+ */
+void t_cpp_generator::close_generator() {
+  // Close namespace
+  f_types_ <<
+    ns_close_ << endl <<
+    endl;
+  f_types_impl_ <<
+    ns_close_ << endl;
+
+  // Close ifndef
+  f_types_ <<
+    "#endif" << endl;
+
+  // Close output file
+  f_types_.close();
+  f_types_impl_.close();
+}
+
+/**
+ * Generates a typedef. This is just a simple 1-liner in C++
+ *
+ * @param ttypedef The type definition
+ */
+void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ <<
+    indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << ttypedef->get_symbolic() << ";" << endl <<
+    endl;
+}
+
+/**
+ * Generates code for an enumerated type. In C++, this is essentially the same
+ * as the thrift definition itself, using the enum keyword in C++.
+ *
+ * @param tenum The enumeration
+ */
+void t_cpp_generator::generate_enum(t_enum* tenum) {
+  f_types_ <<
+    indent() << "enum " << tenum->get_name() << " {" << endl;
+  indent_up();
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_types_ <<
+        "," << endl;
+    }
+    f_types_ <<
+      indent() << (*c_iter)->get_name();
+    if ((*c_iter)->has_value()) {
+      f_types_ <<
+        " = " << (*c_iter)->get_value();
+    }
+  }
+
+  indent_down();
+  f_types_ <<
+    endl <<
+    "};" << endl <<
+    endl;
+
+  generate_local_reflection(f_types_, tenum, false);
+  generate_local_reflection(f_types_impl_, tenum, true);
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
+  string f_consts_name = get_out_dir()+program_name_+"_constants.h";
+  ofstream f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  string f_consts_impl_name = get_out_dir()+program_name_+"_constants.cpp";
+  ofstream f_consts_impl;
+  f_consts_impl.open(f_consts_impl_name.c_str());
+
+  // Print header
+  f_consts <<
+    autogen_comment();
+  f_consts_impl <<
+    autogen_comment();
+
+  // Start ifndef
+  f_consts <<
+    "#ifndef " << program_name_ << "_CONSTANTS_H" << endl <<
+    "#define " << program_name_ << "_CONSTANTS_H" << endl <<
+    endl <<
+    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
+    "_types.h\"" << endl <<
+    endl <<
+    ns_open_ << endl <<
+    endl;
+
+  f_consts_impl <<
+    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
+    "_constants.h\"" << endl <<
+    endl <<
+    ns_open_ << endl <<
+    endl;
+
+  f_consts <<
+    "class " << program_name_ << "Constants {" << endl <<
+    " public:" << endl <<
+    "  " << program_name_ << "Constants();" << endl <<
+    endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    f_consts <<
+      indent() << type_name(type) << " " << name << ";" << endl;
+  }
+  indent_down();
+  f_consts <<
+    "};" << endl;
+
+  f_consts_impl <<
+    "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
+    endl <<
+    program_name_ << "Constants::" << program_name_ << "Constants() {" << endl;
+  indent_up();
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts_impl,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value());
+  }
+  indent_down();
+  indent(f_consts_impl) <<
+    "}" << endl;
+
+  f_consts <<
+    endl <<
+    "extern const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
+    endl <<
+    ns_close_ << endl <<
+    endl <<
+    "#endif" << endl;
+  f_consts.close();
+
+  f_consts_impl <<
+    endl <<
+    ns_close_ << 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
+ */
+void t_cpp_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    indent(out) << name << " = " << v2 << ";" << endl <<
+      endl;
+  } else if (type->is_enum()) {
+    indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl <<
+      endl;
+  } else 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*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    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();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
+      indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
+    }
+    out << 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*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
+    }
+    out << endl;
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)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(out, name, etype, *v_iter);
+      indent(out) << name << ".push_back(" << val << ");" << endl;
+    }
+    out << endl;
+  } else if (type->is_set()) {
+    t_type* 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(out, name, etype, *v_iter);
+      indent(out) << name << ".insert(" << val << ");" << endl;
+    }
+    out << endl;
+  } else {
+    throw "INVALID TYPE IN print_const_value: " + type->get_name();
+  }
+}
+
+/**
+ *
+ */
+string t_cpp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+  std::ostringstream render;
+
+  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:
+      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_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      render << value->get_integer() << "LL";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << 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()) {
+    render << "(" << type_name(type) << ")" << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    indent(out) << type_name(type) << " " << t << ";" << endl;
+    print_const_value(out, t, type, value);
+    render << t;
+  }
+
+  return render.str();
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with data members and a read/write() function, plus a mirroring isset
+ * inner class.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) {
+  generate_struct_definition(f_types_, tstruct, is_exception);
+  generate_struct_fingerprint(f_types_impl_, tstruct, true);
+  generate_local_reflection(f_types_, tstruct, false);
+  generate_local_reflection(f_types_impl_, tstruct, true);
+  generate_local_reflection_pointer(f_types_impl_, tstruct);
+  generate_struct_reader(f_types_impl_, tstruct);
+  generate_struct_writer(f_types_impl_, tstruct);
+}
+
+/**
+ * Writes the struct definition into the header file
+ *
+ * @param out Output stream
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_definition(ofstream& out,
+                                                 t_struct* tstruct,
+                                                 bool is_exception,
+                                                 bool pointers,
+                                                 bool read,
+                                                 bool write) {
+  string extends = "";
+  if (is_exception) {
+    extends = " : public apache::thrift::TException";
+  }
+
+  // Open struct def
+  out <<
+    indent() << "class " << tstruct->get_name() << extends << " {" << endl <<
+    indent() << " public:" << endl <<
+    endl;
+  indent_up();
+
+  // Put the fingerprint up top for all to see.
+  generate_struct_fingerprint(out, tstruct, false);
+
+  // Get members
+  vector<t_field*>::const_iterator m_iter;
+  const vector<t_field*>& members = tstruct->get_members();
+
+  if (!pointers) {
+    // Default constructor
+    indent(out) <<
+      tstruct->get_name() << "()";
+
+    bool init_ctor = false;
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if (t->is_base_type()) {
+        string dval;
+        if (t->is_enum()) {
+          dval += "(" + type_name(t) + ")";
+        }
+        dval += t->is_string() ? "\"\"" : "0";
+        t_const_value* cv = (*m_iter)->get_value();
+        if (cv != NULL) {
+          dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
+        }
+        if (!init_ctor) {
+          init_ctor = true;
+          out << " : ";
+          out << (*m_iter)->get_name() << "(" << dval << ")";
+        } else {
+          out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
+        }
+      }
+    }
+    out << " {" << endl;
+    indent_up();
+    // TODO(dreiss): When everything else in Thrift is perfect,
+    // do more of these in the initializer list.
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+
+      if (!t->is_base_type()) {
+        t_const_value* cv = (*m_iter)->get_value();
+        if (cv != NULL) {
+          print_const_value(out, (*m_iter)->get_name(), t, cv);
+        }
+      }
+    }
+    scope_down(out);
+  }
+
+  if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) {
+    out <<
+      endl <<
+      indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
+  }
+
+  // Pointer to this structure's reflection local typespec.
+  if (gen_dense_) {
+    indent(out) <<
+      "static apache::thrift::reflection::local::TypeSpec* local_reflection;" <<
+      endl << endl;
+  }
+
+  // Declare all fields
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) <<
+      declare_field(*m_iter, false, pointers && !(*m_iter)->get_type()->is_xception(), !read) << endl;
+  }
+
+  // Isset struct has boolean fields, but only for non-required fields.
+  bool has_nonrequired_fields = false;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if ((*m_iter)->get_req() != t_field::T_REQUIRED)
+      has_nonrequired_fields = true;
+  }
+
+  if (has_nonrequired_fields && (!pointers || read)) {
+    out <<
+      endl <<
+      indent() << "struct __isset {" << endl;
+    indent_up();
+
+      indent(out) <<
+        "__isset() : ";
+      bool first = true;
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
+          continue;
+        }
+        if (first) {
+          first = false;
+          out <<
+            (*m_iter)->get_name() << "(false)";
+        } else {
+          out <<
+            ", " << (*m_iter)->get_name() << "(false)";
+        }
+      }
+      out << " {}" << endl;
+
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+          indent(out) <<
+            "bool " << (*m_iter)->get_name() << ";" << endl;
+        }
+      }
+
+    indent_down();
+    indent(out) <<
+      "} __isset;" << endl;
+  }
+
+  out << endl;
+
+  if (!pointers) {
+    // Generate an equality testing operator.  Make it inline since the compiler
+    // will do a better job than we would when deciding whether to inline it.
+    out <<
+      indent() << "bool operator == (const " << tstruct->get_name() << " & " <<
+      (members.size() > 0 ? "rhs" : "/* rhs */") << ") const" << endl;
+    scope_up(out);
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      // Most existing Thrift code does not use isset or optional/required,
+      // so we treat "default" fields as required.
+      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
+        out <<
+          indent() << "if (!(" << (*m_iter)->get_name()
+                   << " == rhs." << (*m_iter)->get_name() << "))" << endl <<
+          indent() << "  return false;" << endl;
+      } else {
+        out <<
+          indent() << "if (__isset." << (*m_iter)->get_name()
+                   << " != rhs.__isset." << (*m_iter)->get_name() << ")" << endl <<
+          indent() << "  return false;" << endl <<
+          indent() << "else if (__isset." << (*m_iter)->get_name() << " && !("
+                   << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name()
+                   << "))" << endl <<
+          indent() << "  return false;" << endl;
+      }
+    }
+    indent(out) << "return true;" << endl;
+    scope_down(out);
+    out <<
+      indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" << endl <<
+      indent() << "  return !(*this == rhs);" << endl <<
+      indent() << "}" << endl << endl;
+
+    // Generate the declaration of a less-than operator.  This must be
+    // implemented by the application developer if they wish to use it.  (They
+    // will get a link error if they try to use it without an implementation.)
+    out <<
+      indent() << "bool operator < (const "
+               << tstruct->get_name() << " & ) const;" << endl << endl;
+  }
+  if (read) {
+    out <<
+      indent() << "uint32_t read(apache::thrift::protocol::TProtocol* iprot);" << endl;
+  }
+  if (write) {
+    out <<
+      indent() << "uint32_t write(apache::thrift::protocol::TProtocol* oprot) const;" << endl;
+  }
+  out << endl;
+
+  indent_down();
+  indent(out) <<
+    "};" << endl <<
+    endl;
+}
+
+/**
+ * Writes the fingerprint of a struct to either the header or implementation.
+ *
+ * @param out Output stream
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_fingerprint(ofstream& out,
+                                                  t_struct* tstruct,
+                                                  bool is_definition) {
+  string stat, nspace, comment;
+  if (is_definition) {
+    stat = "";
+    nspace = tstruct->get_name() + "::";
+    comment = " ";
+  } else {
+    stat = "static ";
+    nspace = "";
+    comment = "; // ";
+  }
+
+  if (tstruct->has_fingerprint()) {
+    out <<
+      indent() << stat << "const char* " << nspace
+        << "ascii_fingerprint" << comment << "= \"" <<
+        tstruct->get_ascii_fingerprint() << "\";" << endl <<
+      indent() << stat << "const uint8_t " << nspace <<
+        "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {";
+    const char* comma = "";
+    for (int i = 0; i < t_type::fingerprint_len; i++) {
+      out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]);
+      comma = ",";
+    }
+    out << "};" << endl << endl;
+  }
+}
+
+/**
+ * Writes the local reflection of a type (either declaration or definition).
+ */
+void t_cpp_generator::generate_local_reflection(std::ofstream& out,
+                                                t_type* ttype,
+                                                bool is_definition) {
+  if (!gen_dense_) {
+    return;
+  }
+  ttype = get_true_type(ttype);
+  assert(ttype->has_fingerprint());
+  string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl");
+  // Note that we have generated this fingerprint.  If we already did, bail out.
+  if (!reflected_fingerprints_.insert(key).second) {
+    return;
+  }
+  // Let each program handle its own structures.
+  if (ttype->get_program() != NULL && ttype->get_program() != program_) {
+    return;
+  }
+
+  // Do dependencies.
+  if (ttype->is_list()) {
+    generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition);
+  } else if (ttype->is_set()) {
+    generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition);
+  } else if (ttype->is_map()) {
+    generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition);
+    generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition);
+  } else if (ttype->is_struct() || ttype->is_xception()) {
+    // Hacky hacky.  For efficiency and convenience, we need a dummy "T_STOP"
+    // type at the end of our typespec array.  Unfortunately, there is no
+    // T_STOP type, so we use the global void type, and special case it when
+    // generating its typespec.
+
+    const vector<t_field*>& members = ((t_struct*)ttype)->get_sorted_members();
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      generate_local_reflection(out, (**m_iter).get_type(), is_definition);
+    }
+    generate_local_reflection(out, g_type_void, is_definition);
+
+    // For definitions of structures, do the arrays of metas and field specs also.
+    if (is_definition) {
+      out <<
+        indent() << "apache::thrift::reflection::local::FieldMeta" << endl <<
+        indent() << local_reflection_name("metas", ttype) <<"[] = {" << endl;
+      indent_up();
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        indent(out) << "{ " << (*m_iter)->get_key() << ", " <<
+          (((*m_iter)->get_req() == t_field::T_OPTIONAL) ? "true" : "false") <<
+          " }," << endl;
+      }
+      // Zero for the T_STOP marker.
+      indent(out) << "{ 0, false }" << endl << "};" << endl;
+      indent_down();
+
+      out <<
+        indent() << "apache::thrift::reflection::local::TypeSpec*" << endl <<
+        indent() << local_reflection_name("specs", ttype) <<"[] = {" << endl;
+      indent_up();
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        indent(out) << "&" <<
+          local_reflection_name("typespec", (*m_iter)->get_type(), true) << "," << endl;
+      }
+      indent(out) << "&" <<
+        local_reflection_name("typespec", g_type_void) << "," << endl;
+      indent_down();
+      indent(out) << "};" << endl;
+    }
+  }
+
+  out <<
+    indent() << "// " << ttype->get_fingerprint_material() << endl <<
+    indent() << (is_definition ? "" : "extern ") <<
+      "apache::thrift::reflection::local::TypeSpec" << endl <<
+      local_reflection_name("typespec", ttype) <<
+      (is_definition ? "(" : ";") << endl;
+
+  if (!is_definition) {
+    out << endl;
+    return;
+  }
+
+  indent_up();
+
+  if (ttype->is_void()) {
+    indent(out) << "apache::thrift::protocol::T_STOP";
+  } else {
+    indent(out) << type_to_enum(ttype);
+  }
+
+  if (ttype->is_struct()) {
+    out << "," << endl <<
+      indent() << type_name(ttype) << "::binary_fingerprint," << endl <<
+      indent() << local_reflection_name("metas", ttype) << "," << endl <<
+      indent() << local_reflection_name("specs", ttype);
+  } else if (ttype->is_list()) {
+    out << "," << endl <<
+      indent() << "&" << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type()) << "," << endl <<
+      indent() << "NULL";
+  } else if (ttype->is_set()) {
+    out << "," << endl <<
+      indent() << "&" << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type()) << "," << endl <<
+      indent() << "NULL";
+  } else if (ttype->is_map()) {
+    out << "," << endl <<
+      indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type()) << "," << endl <<
+      indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type());
+  }
+
+  out << ");" << endl << endl;
+
+  indent_down();
+}
+
+/**
+ * Writes the structure's static pointer to its local reflection typespec
+ * into the implementation file.
+ */
+void t_cpp_generator::generate_local_reflection_pointer(std::ofstream& out,
+                                                        t_type* ttype) {
+  if (!gen_dense_) {
+    return;
+  }
+  indent(out) <<
+    "apache::thrift::reflection::local::TypeSpec* " <<
+      ttype->get_name() << "::local_reflection = " << endl <<
+    indent() << "  &" << local_reflection_name("typespec", ttype) << ";" <<
+    endl << endl;
+}
+
+/**
+ * Makes a helper function to gen a struct reader.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_reader(ofstream& out,
+                                             t_struct* tstruct,
+                                             bool pointers) {
+  indent(out) <<
+    "uint32_t " << tstruct->get_name() << "::read(apache::thrift::protocol::TProtocol* iprot) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables
+  out <<
+    endl <<
+    indent() << "uint32_t xfer = 0;" << endl <<
+    indent() << "std::string fname;" << endl <<
+    indent() << "apache::thrift::protocol::TType ftype;" << endl <<
+    indent() << "int16_t fid;" << endl <<
+    endl <<
+    indent() << "xfer += iprot->readStructBegin(fname);" << endl <<
+    endl <<
+    indent() << "using apache::thrift::protocol::TProtocolException;" << endl <<
+    endl;
+
+  // Required variables aren't in __isset, so we need tmp vars to check them.
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
+      indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
+  }
+  out << endl;
+
+
+  // Loop over reading in fields
+  indent(out) <<
+    "while (true)" << endl;
+    scope_up(out);
+
+    // Read beginning field marker
+    indent(out) <<
+      "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
+
+    // Check for field STOP marker
+    out <<
+      indent() << "if (ftype == apache::thrift::protocol::T_STOP) {" << endl <<
+      indent() << "  break;" << endl <<
+      indent() << "}" << endl;
+
+    // Switch statement on the field we are reading
+    indent(out) <<
+      "switch (fid)" << endl;
+
+      scope_up(out);
+
+      // Generate deserialization code for known cases
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        indent(out) <<
+          "case " << (*f_iter)->get_key() << ":" << endl;
+        indent_up();
+        indent(out) <<
+          "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+        indent_up();
+
+        const char *isset_prefix =
+          ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." : "isset_";
+
+#if 0
+        // This code throws an exception if the same field is encountered twice.
+        // We've decided to leave it out for performance reasons.
+        // TODO(dreiss): Generate this code and "if" it out to make it easier
+        // for people recompiling thrift to include it.
+        out <<
+          indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl <<
+          indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
+#endif
+
+        if (pointers && !(*f_iter)->get_type()->is_xception()) {
+          generate_deserialize_field(out, *f_iter, "(*(this->", "))");
+        } else {
+          generate_deserialize_field(out, *f_iter, "this->");
+        }
+        out <<
+          indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl;
+        indent_down();
+        out <<
+          indent() << "} else {" << endl <<
+          indent() << "  xfer += iprot->skip(ftype);" << endl <<
+          // TODO(dreiss): Make this an option when thrift structs
+          // have a common base class.
+          // indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl <<
+          indent() << "}" << endl <<
+          indent() << "break;" << endl;
+        indent_down();
+      }
+
+      // In the default case we skip the field
+      out <<
+        indent() << "default:" << endl <<
+        indent() << "  xfer += iprot->skip(ftype);" << endl <<
+        indent() << "  break;" << endl;
+
+      scope_down(out);
+
+    // Read field end marker
+    indent(out) <<
+      "xfer += iprot->readFieldEnd();" << endl;
+
+    scope_down(out);
+
+  out <<
+    endl <<
+    indent() << "xfer += iprot->readStructEnd();" << endl;
+
+  // Throw if any required fields are missing.
+  // We do this after reading the struct end so that
+  // there might possibly be a chance of continuing.
+  out << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
+      out <<
+        indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
+        indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
+  }
+
+  indent(out) << "return xfer;" << endl;
+
+  indent_down();
+  indent(out) <<
+    "}" << endl << endl;
+}
+
+/**
+ * Generates the write function.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_writer(ofstream& out,
+                                             t_struct* tstruct,
+                                             bool pointers) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "uint32_t " << tstruct->get_name() << "::write(apache::thrift::protocol::TProtocol* oprot) const {" << endl;
+  indent_up();
+
+  out <<
+    indent() << "uint32_t xfer = 0;" << endl;
+
+  indent(out) <<
+    "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
+      indent(out) << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
+      indent_up();
+    }
+    // Write field header
+    out <<
+      indent() << "xfer += oprot->writeFieldBegin(" <<
+      "\"" << (*f_iter)->get_name() << "\", " <<
+      type_to_enum((*f_iter)->get_type()) << ", " <<
+      (*f_iter)->get_key() << ");" << endl;
+    // Write field contents
+    if (pointers) {
+      generate_serialize_field(out, *f_iter, "(*(this->", "))");
+    } else {
+      generate_serialize_field(out, *f_iter, "this->");
+    }
+    // Write field closer
+    indent(out) <<
+      "xfer += oprot->writeFieldEnd();" << endl;
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
+      indent_down();
+      indent(out) << '}' << endl;
+    }
+  }
+
+  // Write the struct map
+  out <<
+    indent() << "xfer += oprot->writeFieldStop();" << endl <<
+    indent() << "xfer += oprot->writeStructEnd();" << endl <<
+    indent() << "return xfer;" << endl;
+
+  indent_down();
+  indent(out) <<
+    "}" << endl <<
+    endl;
+}
+
+/**
+ * Struct writer for result of a function, which can have only one of its
+ * fields set and does a conditional if else look up into the __isset field
+ * of the struct.
+ *
+ * @param out Output stream
+ * @param tstruct The result struct
+ */
+void t_cpp_generator::generate_struct_result_writer(ofstream& out,
+                                                    t_struct* tstruct,
+                                                    bool pointers) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "uint32_t " << tstruct->get_name() << "::write(apache::thrift::protocol::TProtocol* oprot) const {" << endl;
+  indent_up();
+
+  out <<
+    endl <<
+    indent() << "uint32_t xfer = 0;" << endl <<
+    endl;
+
+  indent(out) <<
+    "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out <<
+        endl <<
+        indent() << "if ";
+    } else {
+      out <<
+        " else if ";
+    }
+
+    out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
+
+    indent_up();
+
+    // Write field header
+    out <<
+      indent() << "xfer += oprot->writeFieldBegin(" <<
+      "\"" << (*f_iter)->get_name() << "\", " <<
+      type_to_enum((*f_iter)->get_type()) << ", " <<
+      (*f_iter)->get_key() << ");" << endl;
+    // Write field contents
+    if (pointers) {
+      generate_serialize_field(out, *f_iter, "(*(this->", "))");
+    } else {
+      generate_serialize_field(out, *f_iter, "this->");
+    }
+    // Write field closer
+    indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}";
+  }
+
+  // Write the struct map
+  out <<
+    endl <<
+    indent() << "xfer += oprot->writeFieldStop();" << endl <<
+    indent() << "xfer += oprot->writeStructEnd();" << endl <<
+    indent() << "return xfer;" << endl;
+
+  indent_down();
+  indent(out) <<
+    "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_cpp_generator::generate_service(t_service* tservice) {
+  string svcname = tservice->get_name();
+
+  // Make output files
+  string f_header_name = get_out_dir()+svcname+".h";
+  f_header_.open(f_header_name.c_str());
+
+  // Print header file includes
+  f_header_ <<
+    autogen_comment();
+  f_header_ <<
+    "#ifndef " << svcname << "_H" << endl <<
+    "#define " << svcname << "_H" << endl <<
+    endl <<
+    "#include <TProcessor.h>" << endl <<
+    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
+    "_types.h\"" << endl;
+
+  t_service* extends_service = tservice->get_extends();
+  if (extends_service != NULL) {
+    f_header_ <<
+      "#include \"" << get_include_prefix(*(extends_service->get_program())) <<
+      extends_service->get_name() << ".h\"" << endl;
+  }
+
+  f_header_ <<
+    endl <<
+    ns_open_ << endl <<
+    endl;
+
+  // Service implementation file includes
+  string f_service_name = get_out_dir()+svcname+".cpp";
+  f_service_.open(f_service_name.c_str());
+  f_service_ <<
+    autogen_comment();
+  f_service_ <<
+    "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" <<
+    endl <<
+    endl <<
+    ns_open_ << endl <<
+    endl;
+
+  // Generate all the components
+  generate_service_interface(tservice);
+  generate_service_null(tservice);
+  generate_service_helpers(tservice);
+  generate_service_client(tservice);
+  generate_service_processor(tservice);
+  generate_service_multiface(tservice);
+  generate_service_skeleton(tservice);
+
+  // Close the namespace
+  f_service_ <<
+    ns_close_ << endl <<
+    endl;
+  f_header_ <<
+    ns_close_ << endl <<
+    endl;
+  f_header_ <<
+    "#endif" << endl;
+
+  // Close the files
+  f_service_.close();
+  f_header_.close();
+}
+
+/**
+ * Generates helper functions for a service. Basically, this generates types
+ * for all the arguments and results to functions.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_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();
+    string name_orig = ts->get_name();
+
+    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
+    generate_struct_definition(f_header_, ts, false);
+    generate_struct_reader(f_service_, ts);
+    generate_struct_writer(f_service_, ts);
+    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
+    generate_struct_definition(f_header_, ts, false, true, false, true);
+    generate_struct_writer(f_service_, ts, true);
+    ts->set_name(name_orig);
+
+    generate_function_helpers(tservice, *f_iter);
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  if (tservice->get_extends() != NULL) {
+    extends = " : virtual public " + type_name(tservice->get_extends()) + "If";
+  }
+  f_header_ <<
+    "class " << service_name_ << "If" << extends << " {" << endl <<
+    " public:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << "virtual ~" << service_name_ << "If() {}" << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_header_ <<
+      indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
+  }
+  indent_down();
+  f_header_ <<
+    "};" << endl << endl;
+}
+
+/**
+ * Generates a null implementation of the service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_generator::generate_service_null(t_service* tservice) {
+  string extends = "";
+  if (tservice->get_extends() != NULL) {
+    extends = " , virtual public " + type_name(tservice->get_extends()) + "Null";
+  }
+  f_header_ <<
+    "class " << service_name_ << "Null : virtual public " << service_name_ << "If" << extends << " {" << endl <<
+    " public:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << "virtual ~" << service_name_ << "Null() {}" << endl;
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_header_ <<
+      indent() << function_signature(*f_iter, "", false) << " {" << endl;
+    indent_up();
+    t_type* returntype = (*f_iter)->get_returntype();
+    if (returntype->is_void()) {
+      f_header_ <<
+        indent() << "return;" << endl;
+    } else if (is_complex_type(returntype)) {
+      f_header_ <<
+        indent() << "return;" << endl;
+    } else {
+      t_field returnfield(returntype, "_return");
+      f_header_ <<
+        indent() << declare_field(&returnfield, true) << endl <<
+        indent() << "return _return;" << endl;
+    }
+    indent_down();
+    f_header_ <<
+      indent() << "}" << endl;
+  }
+  indent_down();
+  f_header_ <<
+    "};" << endl << endl;
+}
+
+
+/**
+ * Generates a multiface, which is a single server that just takes a set
+ * of objects implementing the interface and calls them all, returning the
+ * value of the last one to be called.
+ *
+ * @param tservice The service to generate a multiserver for.
+ */
+void t_cpp_generator::generate_service_multiface(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_multiface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_multiface = ", public " + extends + "Multiface";
+  }
+
+  string list_type = string("std::vector<boost::shared_ptr<") + service_name_ + "If> >";
+
+  // Generate the header portion
+  f_header_ <<
+    "class " << service_name_ << "Multiface : " <<
+    "virtual public " << service_name_ << "If" <<
+    extends_multiface << " {" << endl <<
+    " public:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
+  if (!extends.empty()) {
+    f_header_ <<
+      indent() << "  std::vector<boost::shared_ptr<" + service_name_ + "If> >::iterator iter;" << endl <<
+      indent() << "  for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl <<
+      indent() << "    " << extends << "Multiface::add(*iter);" << endl <<
+      indent() << "  }" << endl;
+  }
+  f_header_ <<
+    indent() << "}" << endl <<
+    indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl;
+  indent_down();
+
+  // Protected data members
+  f_header_ <<
+    " protected:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << list_type << " ifaces_;" << endl <<
+    indent() << service_name_ << "Multiface() {}" << endl <<
+    indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) {" << endl;
+  if (!extends.empty()) {
+    f_header_ <<
+      indent() << "  " << extends << "Multiface::add(iface);" << endl;
+  }
+  f_header_ <<
+    indent() << "  ifaces_.push_back(iface);" << endl <<
+    indent() << "}" << endl;
+  indent_down();
+
+  f_header_ <<
+    indent() << " public:" << endl;
+  indent_up();
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arglist = (*f_iter)->get_arglist();
+    const vector<t_field*>& args = arglist->get_members();
+    vector<t_field*>::const_iterator a_iter;
+
+    string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
+    bool first = true;
+    if (is_complex_type((*f_iter)->get_returntype())) {
+      call += "_return";
+      first = false;
+    }
+    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
+      if (first) {
+        first = false;
+      } else {
+        call += ", ";
+      }
+      call += (*a_iter)->get_name();
+    }
+    call += ")";
+
+    f_header_ <<
+      indent() << function_signature(*f_iter) << " {" << endl;
+    indent_up();
+    f_header_ <<
+      indent() << "uint32_t sz = ifaces_.size();" << endl <<
+      indent() << "for (uint32_t i = 0; i < sz; ++i) {" << endl;
+    if (!(*f_iter)->get_returntype()->is_void()) {
+      f_header_ <<
+        indent() << "  if (i == sz - 1) {" << endl;
+      if (is_complex_type((*f_iter)->get_returntype())) {
+        f_header_ <<
+          indent() << "    " << call << ";" << endl <<
+          indent() << "    return;" << endl;
+      } else {
+        f_header_ <<
+          indent() << "    return " << call << ";" << endl;
+      }
+      f_header_ <<
+        indent() << "  } else {" << endl <<
+        indent() << "    " << call << ";" << endl <<
+        indent() << "  }" << endl;
+    } else {
+      f_header_ <<
+        indent() << "  " << call << ";" << endl;
+    }
+
+    f_header_ <<
+      indent() << "}" << endl;
+
+    indent_down();
+    f_header_ <<
+      indent() << "}" << endl <<
+      endl;
+  }
+
+  indent_down();
+  f_header_ <<
+    indent() << "};" << endl <<
+    endl;
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = ", public " + extends + "Client";
+  }
+
+  // Generate the header portion
+  f_header_ <<
+    "class " << service_name_ << "Client : " <<
+    "virtual public " << service_name_ << "If" <<
+    extends_client << " {" << endl <<
+    " public:" << endl;
+
+  indent_up();
+  f_header_ <<
+    indent() << service_name_ << "Client(boost::shared_ptr<apache::thrift::protocol::TProtocol> prot) :" << endl;
+  if (extends.empty()) {
+    f_header_ <<
+      indent() << "  piprot_(prot)," << endl <<
+      indent() << "  poprot_(prot) {" << endl <<
+      indent() << "  iprot_ = prot.get();" << endl <<
+      indent() << "  oprot_ = prot.get();" << endl <<
+      indent() << "}" << endl;
+  } else {
+    f_header_ <<
+      indent() << "  " << extends << "Client(prot, prot) {}" << endl;
+  }
+
+  f_header_ <<
+    indent() << service_name_ << "Client(boost::shared_ptr<apache::thrift::protocol::TProtocol> iprot, boost::shared_ptr<apache::thrift::protocol::TProtocol> oprot) :" << endl;
+  if (extends.empty()) {
+    f_header_ <<
+      indent() << "  piprot_(iprot)," << endl <<
+      indent() << "  poprot_(oprot) {" << endl <<
+      indent() << "  iprot_ = iprot.get();" << endl <<
+      indent() << "  oprot_ = oprot.get();" << endl <<
+      indent() << "}" << endl;
+  } else {
+    f_header_ <<
+      indent() << "  " << extends << "Client(iprot, oprot) {}" << endl;
+  }
+
+  // Generate getters for the protocols.
+  f_header_ <<
+    indent() << "boost::shared_ptr<apache::thrift::protocol::TProtocol> getInputProtocol() {" << endl <<
+    indent() << "  return piprot_;" << endl <<
+    indent() << "}" << endl;
+
+  f_header_ <<
+    indent() << "boost::shared_ptr<apache::thrift::protocol::TProtocol> getOutputProtocol() {" << endl <<
+    indent() << "  return poprot_;" << endl <<
+    indent() << "}" << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_function send_function(g_type_void,
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
+    indent(f_header_) << function_signature(*f_iter) << ";" << endl;
+    indent(f_header_) << function_signature(&send_function) << ";" << endl;
+    if (!(*f_iter)->is_oneway()) {
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      indent(f_header_) << function_signature(&recv_function) << ";" << endl;
+    }
+  }
+  indent_down();
+
+  if (extends.empty()) {
+    f_header_ <<
+      " protected:" << endl;
+    indent_up();
+    f_header_ <<
+      indent() << "boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot_;"  << endl <<
+      indent() << "boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot_;"  << endl <<
+      indent() << "apache::thrift::protocol::TProtocol* iprot_;"  << endl <<
+      indent() << "apache::thrift::protocol::TProtocol* oprot_;"  << endl;
+    indent_down();
+  }
+
+  f_header_ <<
+    "};" << endl <<
+    endl;
+
+  string scope = service_name_ + "Client::";
+
+  // Generate client method implementations
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    indent(f_service_) <<
+      function_signature(*f_iter, scope) << endl;
+    scope_up(f_service_);
+    indent(f_service_) <<
+      "send_" << funname << "(";
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << (*fld_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        if (is_complex_type((*f_iter)->get_returntype())) {
+          f_service_ << "recv_" << funname << "(_return);" << endl;
+        } else {
+          f_service_ << "return recv_" << funname << "();" << endl;
+        }
+      } else {
+        f_service_ <<
+          "recv_" << funname << "();" << endl;
+      }
+    }
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    // Function for sending
+    t_function send_function(g_type_void,
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
+
+    // Open the send function
+    indent(f_service_) <<
+      function_signature(&send_function, scope) << endl;
+    scope_up(f_service_);
+
+    // Function arguments and results
+    string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs";
+    string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult";
+
+    // Serialize the request
+    f_service_ <<
+      indent() << "int32_t cseqid = 0;" << endl <<
+      indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", apache::thrift::protocol::T_CALL, cseqid);" << endl <<
+      endl <<
+      indent() << argsname << " args;" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ <<
+        indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    f_service_ <<
+      indent() << "args.write(oprot_);" << endl <<
+      endl <<
+      indent() << "oprot_->writeMessageEnd();" << endl <<
+      indent() << "oprot_->getTransport()->flush();" << endl <<
+      indent() << "oprot_->getTransport()->writeEnd();" << endl;
+
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    // Generate recv function only if not an oneway function
+    if (!(*f_iter)->is_oneway()) {
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      indent(f_service_) <<
+        function_signature(&recv_function, scope) << endl;
+      scope_up(f_service_);
+
+      f_service_ <<
+        endl <<
+        indent() << "int32_t rseqid = 0;" << endl <<
+        indent() << "std::string fname;" << endl <<
+        indent() << "apache::thrift::protocol::TMessageType mtype;" << endl <<
+        endl <<
+        indent() << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl <<
+        indent() << "if (mtype == apache::thrift::protocol::T_EXCEPTION) {" << endl <<
+        indent() << "  apache::thrift::TApplicationException x;" << endl <<
+        indent() << "  x.read(iprot_);" << endl <<
+        indent() << "  iprot_->readMessageEnd();" << endl <<
+        indent() << "  iprot_->getTransport()->readEnd();" << endl <<
+        indent() << "  throw x;" << endl <<
+        indent() << "}" << endl <<
+        indent() << "if (mtype != apache::thrift::protocol::T_REPLY) {" << endl <<
+        indent() << "  iprot_->skip(apache::thrift::protocol::T_STRUCT);" << endl <<
+        indent() << "  iprot_->readMessageEnd();" << endl <<
+        indent() << "  iprot_->getTransport()->readEnd();" << endl <<
+        indent() << "  throw apache::thrift::TApplicationException(apache::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
+        indent() << "}" << endl <<
+        indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl <<
+        indent() << "  iprot_->skip(apache::thrift::protocol::T_STRUCT);" << endl <<
+        indent() << "  iprot_->readMessageEnd();" << endl <<
+        indent() << "  iprot_->getTransport()->readEnd();" << endl <<
+        indent() << "  throw apache::thrift::TApplicationException(apache::thrift::TApplicationException::WRONG_METHOD_NAME);" << endl <<
+        indent() << "}" << endl;
+
+      if (!(*f_iter)->get_returntype()->is_void() &&
+          !is_complex_type((*f_iter)->get_returntype())) {
+        t_field returnfield((*f_iter)->get_returntype(), "_return");
+        f_service_ <<
+          indent() << declare_field(&returnfield) << endl;
+      }
+
+      f_service_ <<
+        indent() << resultname << " result;" << endl;
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "result.success = &_return;" << endl;
+      }
+
+      f_service_ <<
+        indent() << "result.read(iprot_);" << endl <<
+        indent() << "iprot_->readMessageEnd();" << endl <<
+        indent() << "iprot_->getTransport()->readEnd();" << endl <<
+        endl;
+
+      // Careful, only look for _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        if (is_complex_type((*f_iter)->get_returntype())) {
+          f_service_ <<
+            indent() << "if (result.__isset.success) {" << endl <<
+            indent() << "  // _return pointer has now been filled" << endl <<
+            indent() << "  return;" << endl <<
+            indent() << "}" << endl;
+        } else {
+          f_service_ <<
+            indent() << "if (result.__isset.success) {" << endl <<
+            indent() << "  return _return;" << endl <<
+            indent() << "}" << endl;
+        }
+      }
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
+          indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl <<
+          indent() << "}" << endl;
+      }
+
+      // We only get here if we are a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "return;" << endl;
+      } else {
+        f_service_ <<
+          indent() << "throw apache::thrift::TApplicationException(apache::thrift::TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+      // Close function
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_processor(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = ", public " + extends + "Processor";
+  }
+
+  // Generate the header portion
+  f_header_ <<
+    "class " << service_name_ << "Processor : " <<
+    "virtual public apache::thrift::TProcessor" <<
+    extends_processor << " {" << endl;
+
+  // Protected data members
+  f_header_ <<
+    " protected:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << "boost::shared_ptr<" << service_name_ << "If> iface_;" << endl;
+  f_header_ <<
+    indent() << "virtual bool process_fn(apache::thrift::protocol::TProtocol* iprot, apache::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid);" << endl;
+  indent_down();
+
+  // Process function declarations
+  f_header_ <<
+    " private:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, apache::thrift::protocol::TProtocol*, apache::thrift::protocol::TProtocol*)> processMap_;" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_header_) <<
+      "void process_" << (*f_iter)->get_name() << "(int32_t seqid, apache::thrift::protocol::TProtocol* iprot, apache::thrift::protocol::TProtocol* oprot);" << endl;
+  }
+  indent_down();
+
+  indent_up();
+  string declare_map = "";
+  indent_up();
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    declare_map += indent();
+    declare_map += "processMap_[\"";
+    declare_map += (*f_iter)->get_name();
+    declare_map += "\"] = &";
+    declare_map += service_name_;
+    declare_map += "Processor::process_";
+    declare_map += (*f_iter)->get_name();
+    declare_map += ";\n";
+  }
+  indent_down();
+
+  f_header_ <<
+    " public:" << endl <<
+    indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface) :" << endl;
+  if (extends.empty()) {
+    f_header_ <<
+      indent() << "  iface_(iface) {" << endl;
+  } else {
+    f_header_ <<
+      indent() << "  " << extends << "Processor(iface)," << endl <<
+      indent() << "  iface_(iface) {" << endl;
+  }
+  f_header_ <<
+    declare_map <<
+    indent() << "}" << endl <<
+    endl <<
+    indent() << "virtual bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot, boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot);" << endl <<
+    indent() << "virtual ~" << service_name_ << "Processor() {}" << endl;
+  indent_down();
+  f_header_ <<
+    "};" << endl << endl;
+
+  // Generate the server implementation
+  f_service_ <<
+    "bool " << service_name_ << "Processor::process(boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot, boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot) {" << endl;
+  indent_up();
+
+  f_service_ <<
+    endl <<
+    indent() << "apache::thrift::protocol::TProtocol* iprot = piprot.get();" << endl <<
+    indent() << "apache::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
+    indent() << "std::string fname;" << endl <<
+    indent() << "apache::thrift::protocol::TMessageType mtype;" << endl <<
+    indent() << "int32_t seqid;" << endl <<
+    endl <<
+    indent() << "iprot->readMessageBegin(fname, mtype, seqid);" << endl <<
+    endl <<
+    indent() << "if (mtype != apache::thrift::protocol::T_CALL && mtype != apache::thrift::protocol::T_ONEWAY) {" << endl <<
+    indent() << "  iprot->skip(apache::thrift::protocol::T_STRUCT);" << endl <<
+    indent() << "  iprot->readMessageEnd();" << endl <<
+    indent() << "  iprot->getTransport()->readEnd();" << endl <<
+    indent() << "  apache::thrift::TApplicationException x(apache::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
+    indent() << "  oprot->writeMessageBegin(fname, apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
+    indent() << "  x.write(oprot);" << endl <<
+    indent() << "  oprot->writeMessageEnd();" << endl <<
+    indent() << "  oprot->getTransport()->flush();" << endl <<
+    indent() << "  oprot->getTransport()->writeEnd();" << endl <<
+    indent() << "  return true;" << endl <<
+    indent() << "}" << endl <<
+    endl <<
+    indent() << "return process_fn(iprot, oprot, fname, seqid);" <<
+    endl;
+
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl <<
+    endl;
+
+  f_service_ <<
+    "bool " << service_name_ << "Processor::process_fn(apache::thrift::protocol::TProtocol* iprot, apache::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid) {" << endl;
+  indent_up();
+
+  // HOT: member function pointer map
+  f_service_ <<
+    indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, apache::thrift::protocol::TProtocol*, apache::thrift::protocol::TProtocol*)>::iterator pfn;" << endl <<
+    indent() << "pfn = processMap_.find(fname);" << endl <<
+    indent() << "if (pfn == processMap_.end()) {" << endl;
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "  iprot->skip(apache::thrift::protocol::T_STRUCT);" << endl <<
+      indent() << "  iprot->readMessageEnd();" << endl <<
+      indent() << "  iprot->getTransport()->readEnd();" << endl <<
+      indent() << "  apache::thrift::TApplicationException x(apache::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: '\"+fname+\"'\");" << endl <<
+      indent() << "  oprot->writeMessageBegin(fname, apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
+      indent() << "  x.write(oprot);" << endl <<
+      indent() << "  oprot->writeMessageEnd();" << endl <<
+      indent() << "  oprot->getTransport()->flush();" << endl <<
+      indent() << "  oprot->getTransport()->writeEnd();" << endl <<
+      indent() << "  return true;" << endl;
+  } else {
+    f_service_ <<
+      indent() << "  return " << extends << "Processor::process_fn(iprot, oprot, fname, seqid);" << endl;
+  }
+  f_service_ <<
+    indent() << "}" << endl <<
+    indent() << "(this->*(pfn->second))(seqid, iprot, oprot);" << endl <<
+    indent() << "return true;" << endl;
+
+  indent_down();
+  f_service_ <<
+    "}" << endl <<
+    endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_cpp_generator::generate_function_helpers(t_service* tservice,
+                                                t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  t_struct result(program_, tservice->get_name() + "_" + 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_struct_definition(f_header_, &result, false);
+  generate_struct_reader(f_service_, &result);
+  generate_struct_result_writer(f_service_, &result);
+
+  result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
+  generate_struct_definition(f_header_, &result, false, true, true, false);
+  generate_struct_reader(f_service_, &result, true);
+
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_cpp_generator::generate_process_function(t_service* tservice,
+                                                t_function* tfunction) {
+  // Open function
+  f_service_ <<
+    "void " << tservice->get_name() << "Processor::" <<
+    "process_" << tfunction->get_name() <<
+    "(int32_t seqid, apache::thrift::protocol::TProtocol* iprot, apache::thrift::protocol::TProtocol* oprot)" << endl;
+  scope_up(f_service_);
+
+  string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
+  string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
+
+  f_service_ <<
+    indent() << argsname << " args;" << endl <<
+    indent() << "args.read(iprot);" << endl <<
+    indent() << "iprot->readMessageEnd();" << endl <<
+    indent() << "iprot->getTransport()->readEnd();" << endl <<
+    endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result
+  if (!tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << resultname << " result;" << endl;
+  }
+
+  // Try block for functions with exceptions
+  f_service_ <<
+    indent() << "try {" << endl;
+  indent_up();
+
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  bool first = true;
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    if (is_complex_type(tfunction->get_returntype())) {
+      first = false;
+      f_service_ << "iface_->" << tfunction->get_name() << "(result.success";
+    } else {
+      f_service_ << "result.success = iface_->" << tfunction->get_name() << "(";
+    }
+  } else {
+    f_service_ <<
+      "iface_->" << tfunction->get_name() << "(";
+  }
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  // Set isset on success field
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ <<
+      indent() << "result.__isset.success = true;" << endl;
+  }
+
+  indent_down();
+  f_service_ << indent() << "}";
+
+  if (!tfunction->is_oneway()) {
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name() << ") {" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ <<
+          indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
+          indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
+        indent_down();
+        f_service_ << indent() << "}";
+      } else {
+        f_service_ << "}";
+      }
+    }
+  }
+
+  f_service_ << " catch (const std::exception& e) {" << endl;
+
+  if (!tfunction->is_oneway()) {
+    indent_up();
+    f_service_ <<
+      indent() << "apache::thrift::TApplicationException x(e.what());" << endl <<
+      indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
+      indent() << "x.write(oprot);" << endl <<
+      indent() << "oprot->writeMessageEnd();" << endl <<
+      indent() << "oprot->getTransport()->flush();" << endl <<
+      indent() << "oprot->getTransport()->writeEnd();" << endl <<
+      indent() << "return;" << endl;
+    indent_down();
+  }
+  f_service_ << indent() << "}" << endl;
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "return;" << endl;
+    indent_down();
+    f_service_ << "}" << endl <<
+      endl;
+    return;
+  }
+
+  // Serialize the result into a struct
+  f_service_ <<
+    endl <<
+    indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", apache::thrift::protocol::T_REPLY, seqid);" << endl <<
+    indent() << "result.write(oprot);" << endl <<
+    indent() << "oprot->writeMessageEnd();" << endl <<
+    indent() << "oprot->getTransport()->flush();" << endl <<
+    indent() << "oprot->getTransport()->writeEnd();" << endl;
+
+  // Close function
+  scope_down(f_service_);
+  f_service_ << endl;
+}
+
+/**
+ * Generates a skeleton file of a server
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
+  string svcname = tservice->get_name();
+
+  // Service implementation file includes
+  string f_skeleton_name = get_out_dir()+svcname+"_server.skeleton.cpp";
+
+  string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp"));
+
+  ofstream f_skeleton;
+  f_skeleton.open(f_skeleton_name.c_str());
+  f_skeleton <<
+    "// This autogenerated skeleton file illustrates how to build a server." << endl <<
+    "// You should copy it to another filename to avoid overwriting it." << endl <<
+    endl <<
+    "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl <<
+    "#include <protocol/TBinaryProtocol.h>" << endl <<
+    "#include <server/TSimpleServer.h>" << endl <<
+    "#include <transport/TServerSocket.h>" << endl <<
+    "#include <transport/TBufferTransports.h>" << endl <<
+    endl <<
+    "using namespace apache::thrift;" << endl <<
+    "using namespace apache::thrift::protocol;" << endl <<
+    "using namespace apache::thrift::transport;" << endl <<
+    "using namespace apache::thrift::server;" << endl <<
+    endl <<
+    "using boost::shared_ptr;" << endl <<
+    endl;
+
+  if (!ns.empty()) {
+    f_skeleton <<
+      "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
+      endl;
+  }
+
+  f_skeleton <<
+    "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl <<
+    " public:" << endl;
+  indent_up();
+  f_skeleton <<
+    indent() << svcname << "Handler() {" << endl <<
+    indent() << "  // Your initialization goes here" << endl <<
+    indent() << "}" << endl <<
+    endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_skeleton <<
+      indent() << function_signature(*f_iter) << " {" << endl <<
+      indent() << "  // Your implementation goes here" << endl <<
+      indent() << "  printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl <<
+      indent() << "}" << endl <<
+      endl;
+  }
+
+  indent_down();
+  f_skeleton <<
+    "};" << endl <<
+    endl;
+
+  f_skeleton <<
+    indent() << "int main(int argc, char **argv) {" << endl;
+  indent_up();
+  f_skeleton <<
+    indent() << "int port = 9090;" << endl <<
+    indent() << "shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl <<
+    indent() << "shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl <<
+    indent() << "shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));" << endl <<
+    indent() << "shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl <<
+    indent() << "shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());" << endl <<
+    endl <<
+    indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl <<
+    indent() << "server.serve();" << endl <<
+    indent() << "return 0;" << endl;
+  indent_down();
+  f_skeleton <<
+    "}" << endl <<
+    endl;
+
+  // Close the files
+  f_skeleton.close();
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_cpp_generator::generate_deserialize_field(ofstream& out,
+                                                 t_field* tfield,
+                                                 string prefix,
+                                                 string suffix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name() + suffix;
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type()) {
+    indent(out) <<
+      "xfer += iprot->";
+    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 (((t_base_type*)type)->is_binary()) {
+        out << "readBinary(" << name << ");";
+      }
+      else {
+        out << "readString(" << name << ");";
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "readBool(" << name << ");";
+      break;
+    case t_base_type::TYPE_BYTE:
+      out << "readByte(" << name << ");";
+      break;
+    case t_base_type::TYPE_I16:
+      out << "readI16(" << name << ");";
+      break;
+    case t_base_type::TYPE_I32:
+      out << "readI32(" << name << ");";
+      break;
+    case t_base_type::TYPE_I64:
+      out << "readI64(" << name << ");";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      out << "readDouble(" << name << ");";
+      break;
+    default:
+      throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
+    }
+    out <<
+      endl;
+  } else if (type->is_enum()) {
+    string t = tmp("ecast");
+    out <<
+      indent() << "int32_t " << t << ";" << endl <<
+      indent() << "xfer += iprot->readI32(" << t << ");" << endl <<
+      indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(), type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_cpp_generator::generate_deserialize_struct(ofstream& out,
+                                                  t_struct* tstruct,
+                                                  string prefix) {
+  indent(out) <<
+    "xfer += " << prefix << ".read(iprot);" << endl;
+}
+
+void t_cpp_generator::generate_deserialize_container(ofstream& out,
+                                                     t_type* ttype,
+                                                     string prefix) {
+  scope_up(out);
+
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+
+  t_container* tcontainer = (t_container*)ttype;
+  bool use_push = tcontainer->has_cpp_name();
+
+  indent(out) <<
+    prefix << ".clear();" << endl <<
+    indent() << "uint32_t " << size << ";" << endl;
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out <<
+      indent() << "apache::thrift::protocol::TType " << ktype << ";" << endl <<
+      indent() << "apache::thrift::protocol::TType " << vtype << ";" << endl <<
+      indent() << "iprot->readMapBegin(" <<
+                   ktype << ", " << vtype << ", " << size << ");" << endl;
+  } else if (ttype->is_set()) {
+    out <<
+      indent() << "apache::thrift::protocol::TType " << etype << ";" << endl <<
+      indent() << "iprot->readSetBegin(" <<
+                   etype << ", " << size << ");" << endl;
+  } else if (ttype->is_list()) {
+    out <<
+      indent() << "apache::thrift::protocol::TType " << etype << ";" << endl <<
+      indent() << "iprot->readListBegin(" <<
+      etype << ", " << size << ");" << endl;
+    if (!use_push) {
+      indent(out) << prefix << ".resize(" << size << ");" << endl;
+    }
+  }
+
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  out <<
+    indent() << "uint32_t " << i << ";" << endl <<
+    indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
+
+    scope_up(out);
+
+    if (ttype->is_map()) {
+      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+    } else if (ttype->is_set()) {
+      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+    } else if (ttype->is_list()) {
+      generate_deserialize_list_element(out, (t_list*)ttype, prefix, use_push, i);
+    }
+
+    scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot->readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot->readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot->readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_cpp_generator::generate_deserialize_map_element(ofstream& out,
+                                                       t_map* tmap,
+                                                       string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  out <<
+    indent() << declare_field(&fkey) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  indent(out) <<
+    declare_field(&fval, false, false, false, true) << " = " <<
+    prefix << "[" << key << "];" << endl;
+
+  generate_deserialize_field(out, &fval);
+}
+
+void t_cpp_generator::generate_deserialize_set_element(ofstream& out,
+                                                       t_set* tset,
+                                                       string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) <<
+    declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".insert(" << elem << ");" << endl;
+}
+
+void t_cpp_generator::generate_deserialize_list_element(ofstream& out,
+                                                        t_list* tlist,
+                                                        string prefix,
+                                                        bool use_push,
+                                                        string index) {
+  if (use_push) {
+    string elem = tmp("_elem");
+    t_field felem(tlist->get_elem_type(), elem);
+    indent(out) << declare_field(&felem) << endl;
+    generate_deserialize_field(out, &felem);
+    indent(out) << prefix << ".push_back(" << elem << ");" << endl;
+  } else {
+    t_field felem(tlist->get_elem_type(), prefix + "[" + index + "]");
+    generate_deserialize_field(out, &felem);
+  }
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_cpp_generator::generate_serialize_field(ofstream& out,
+                                               t_field* tfield,
+                                               string prefix,
+                                               string suffix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  string name = prefix + tfield->get_name() + suffix;
+
+  // Do nothing for void types
+  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);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) <<
+      "xfer += 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 (((t_base_type*)type)->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        }
+        else {
+          out << "writeString(" << name << ");";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_BYTE:
+        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 C++ writer for base type " + t_base_type::t_base_name(tbase) + name;
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32((int32_t)" << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           name.c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_cpp_generator::generate_serialize_struct(ofstream& out,
+                                                t_struct* tstruct,
+                                                string prefix) {
+  indent(out) <<
+    "xfer += " << prefix << ".write(oprot);" << endl;
+}
+
+void t_cpp_generator::generate_serialize_container(ofstream& out,
+                                                   t_type* ttype,
+                                                   string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "xfer += oprot->writeMapBegin(" <<
+      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+      prefix << ".size());" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "xfer += oprot->writeSetBegin(" <<
+      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".size());" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "xfer += oprot->writeListBegin(" <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".size());" << endl;
+  }
+
+  string iter = tmp("_iter");
+  out <<
+    indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl <<
+    indent() << "for (" << iter << " = " << prefix  << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl;
+  scope_up(out);
+    if (ttype->is_map()) {
+      generate_serialize_map_element(out, (t_map*)ttype, iter);
+    } else if (ttype->is_set()) {
+      generate_serialize_set_element(out, (t_set*)ttype, iter);
+    } else if (ttype->is_list()) {
+      generate_serialize_list_element(out, (t_list*)ttype, iter);
+    }
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "xfer += oprot->writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "xfer += oprot->writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "xfer += oprot->writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_cpp_generator::generate_serialize_map_element(ofstream& out,
+                                                     t_map* tmap,
+                                                     string iter) {
+  t_field kfield(tmap->get_key_type(), iter + "->first");
+  generate_serialize_field(out, &kfield, "");
+
+  t_field vfield(tmap->get_val_type(), iter + "->second");
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_cpp_generator::generate_serialize_set_element(ofstream& out,
+                                                     t_set* tset,
+                                                     string iter) {
+  t_field efield(tset->get_elem_type(), "(*" + iter + ")");
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_cpp_generator::generate_serialize_list_element(ofstream& out,
+                                                      t_list* tlist,
+                                                      string iter) {
+  t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Makes a :: prefix for a namespace
+ *
+ * @param ns The namepsace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_prefix(string ns) {
+  if (ns.size() == 0) {
+    return "";
+  }
+  string result = "";
+  string::size_type loc;
+  while ((loc = ns.find(".")) != string::npos) {
+    result += ns.substr(0, loc);
+    result += "::";
+    ns = ns.substr(loc+1);
+  }
+  if (ns.size() > 0) {
+    result += ns + "::";
+  }
+  return result;
+}
+
+/**
+ * Opens namespace.
+ *
+ * @param ns The namepsace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_open(string ns) {
+  if (ns.size() == 0) {
+    return "";
+  }
+  string result = "";
+  string separator = "";
+  string::size_type loc;
+  while ((loc = ns.find(".")) != string::npos) {
+    result += separator;
+    result += "namespace ";
+    result += ns.substr(0, loc);
+    result += " {";
+    separator = " ";
+    ns = ns.substr(loc+1);
+  }
+  if (ns.size() > 0) {
+    result += separator + "namespace " + ns + " {";
+  }
+  return result;
+}
+
+/**
+ * Closes namespace.
+ *
+ * @param ns The namepsace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_close(string ns) {
+  if (ns.size() == 0) {
+    return "";
+  }
+  string result = "}";
+  string::size_type loc;
+  while ((loc = ns.find(".")) != string::npos) {
+    result += "}";
+    ns = ns.substr(loc+1);
+  }
+  result += " // namespace";
+  return result;
+}
+
+/**
+ * Returns a C++ type name
+ *
+ * @param ttype The type
+ * @return String of the type name, i.e. std::set<type>
+ */
+string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
+  if (ttype->is_base_type()) {
+    string bname = base_type_name(((t_base_type*)ttype)->get_base());
+    if (!arg) {
+      return bname;
+    }
+
+    if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) {
+      return "const " + bname + "&";
+    } else {
+      return "const " + bname;
+    }
+  }
+
+  // Check for a custom overloaded C++ name
+  if (ttype->is_container()) {
+    string cname;
+
+    t_container* tcontainer = (t_container*) ttype;
+    if (tcontainer->has_cpp_name()) {
+      cname = tcontainer->get_cpp_name();
+    } else if (ttype->is_map()) {
+      t_map* tmap = (t_map*) ttype;
+      cname = "std::map<" +
+        type_name(tmap->get_key_type(), in_typedef) + ", " +
+        type_name(tmap->get_val_type(), in_typedef) + "> ";
+    } else if (ttype->is_set()) {
+      t_set* tset = (t_set*) ttype;
+      cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> ";
+    } else if (ttype->is_list()) {
+      t_list* tlist = (t_list*) ttype;
+      cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
+    }
+
+    if (arg) {
+      return "const " + cname + "&";
+    } else {
+      return cname;
+    }
+  }
+
+  string class_prefix;
+  if (in_typedef && (ttype->is_struct() || ttype->is_xception())) {
+    class_prefix = "class ";
+  }
+
+  // Check if it needs to be namespaced
+  string pname;
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    pname =
+      class_prefix +
+      namespace_prefix(program->get_namespace("cpp")) +
+      ttype->get_name();
+  } else {
+    pname = class_prefix + ttype->get_name();
+  }
+
+  if (arg) {
+    if (is_complex_type(ttype)) {
+      return "const " + pname + "&";
+    } else {
+      return "const " + pname;
+    }
+  } else {
+    return pname;
+  }
+}
+
+/**
+ * Returns the C++ type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @return Explicit C++ type, i.e. "int32_t"
+ */
+string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    return "std::string";
+  case t_base_type::TYPE_BOOL:
+    return "bool";
+  case t_base_type::TYPE_BYTE:
+    return "int8_t";
+  case t_base_type::TYPE_I16:
+    return "int16_t";
+  case t_base_type::TYPE_I32:
+    return "int32_t";
+  case t_base_type::TYPE_I64:
+    return "int64_t";
+  case t_base_type::TYPE_DOUBLE:
+    return "double";
+  default:
+    throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ * @return Field declaration, i.e. int x = 0;
+ */
+string t_cpp_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant, bool reference) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = "";
+  if (constant) {
+    result += "const ";
+  }
+  result += type_name(tfield->get_type());
+  if (pointer) {
+    result += "*";
+  }
+  if (reference) {
+    result += "&";
+  }
+  result += " " + tfield->get_name();
+  if (init) {
+    t_type* type = get_true_type(tfield->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:
+        break;
+      case t_base_type::TYPE_STRING:
+        result += " = \"\"";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = 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:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+      default:
+        throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = (" + type_name(type) + ")0";
+    }
+  }
+  if (!reference) {
+    result += ";";
+  }
+  return result;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cpp_generator::function_signature(t_function* tfunction,
+                                           string prefix,
+                                           bool name_params) {
+  t_type* ttype = tfunction->get_returntype();
+  t_struct* arglist = tfunction->get_arglist();
+
+  if (is_complex_type(ttype)) {
+    bool empty = arglist->get_members().size() == 0;
+    return
+      "void " + prefix + tfunction->get_name() +
+      "(" + type_name(ttype) + (name_params ? "& _return" : "& /* _return */") +
+      (empty ? "" : (", " + argument_list(arglist, name_params))) + ")";
+  } else {
+    return
+      type_name(ttype) + " " + prefix + tfunction->get_name() +
+      "(" + argument_list(arglist, name_params) + ")";
+  }
+}
+
+/**
+ * Renders a field list
+ *
+ * @param tstruct The struct definition
+ * @return Comma sepearated list of all field names in that struct
+ */
+string t_cpp_generator::argument_list(t_struct* tstruct, bool name_params) {
+  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;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type(), false, true) + " " +
+      (name_params ? (*f_iter)->get_name() : "/* " + (*f_iter)->get_name() + " */");
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ *
+ * @param type Thrift Type
+ * @return String of C++ code to definition of that type constant
+ */
+string t_cpp_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 "apache::thrift::protocol::T_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "apache::thrift::protocol::T_BOOL";
+    case t_base_type::TYPE_BYTE:
+      return "apache::thrift::protocol::T_BYTE";
+    case t_base_type::TYPE_I16:
+      return "apache::thrift::protocol::T_I16";
+    case t_base_type::TYPE_I32:
+      return "apache::thrift::protocol::T_I32";
+    case t_base_type::TYPE_I64:
+      return "apache::thrift::protocol::T_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "apache::thrift::protocol::T_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "apache::thrift::protocol::T_I32";
+  } else if (type->is_struct()) {
+    return "apache::thrift::protocol::T_STRUCT";
+  } else if (type->is_xception()) {
+    return "apache::thrift::protocol::T_STRUCT";
+  } else if (type->is_map()) {
+    return "apache::thrift::protocol::T_MAP";
+  } else if (type->is_set()) {
+    return "apache::thrift::protocol::T_SET";
+  } else if (type->is_list()) {
+    return "apache::thrift::protocol::T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Returns the symbol name of the local reflection of a type.
+ */
+string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype, bool external) {
+  ttype = get_true_type(ttype);
+
+  // We have to use the program name as part of the identifier because
+  // if two thrift "programs" are compiled into one actual program
+  // you would get a symbol collison if they both defined list<i32>.
+  // trlo = Thrift Reflection LOcal.
+  string prog;
+  string name;
+  string nspace;
+
+  // TODO(dreiss): Would it be better to pregenerate the base types
+  //               and put them in Thrift.{h,cpp} ?
+
+  if (ttype->is_base_type()) {
+    prog = program_->get_name();
+    name = ttype->get_ascii_fingerprint();
+  } else if (ttype->is_enum()) {
+    assert(ttype->get_program() != NULL);
+    prog = ttype->get_program()->get_name();
+    name = ttype->get_ascii_fingerprint();
+  } else if (ttype->is_container()) {
+    prog = program_->get_name();
+    name = ttype->get_ascii_fingerprint();
+  } else {
+    assert(ttype->is_struct() || ttype->is_xception());
+    assert(ttype->get_program() != NULL);
+    prog = ttype->get_program()->get_name();
+    name = ttype->get_ascii_fingerprint();
+  }
+
+  if (external &&
+      ttype->get_program() != NULL &&
+      ttype->get_program() != program_) {
+    nspace = namespace_prefix(ttype->get_program()->get_namespace("cpp"));
+  }
+
+  return nspace + "trlo_" + prefix + "_" + prog + "_" + name;
+}
+
+string t_cpp_generator::get_include_prefix(const t_program& program) const {
+  string include_prefix = program.get_include_prefix();
+  if (!use_include_prefix_ ||
+      (include_prefix.size() > 0 && include_prefix[0] == '/')) {
+    // if flag is turned off or this is absolute path, return empty prefix
+    return "";
+  }
+
+  string::size_type last_slash = string::npos;
+  if ((last_slash = include_prefix.rfind("/")) != string::npos) {
+    return include_prefix.substr(0, last_slash) + "/" + out_dir_base_ + "/";
+  }
+
+  return "";
+}
+
+
+THRIFT_REGISTER_GENERATOR(cpp, "C++",
+"    dense:           Generate type specifications for the dense protocol.\n"
+"    include_prefix:  Use full include paths in generated files.\n"
+);
diff --git a/compiler/cpp/src/generate/t_csharp_generator.cc b/compiler/cpp/src/generate/t_csharp_generator.cc
new file mode 100644
index 0000000..5a910ea
--- /dev/null
+++ b/compiler/cpp/src/generate/t_csharp_generator.cc
@@ -0,0 +1,1700 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+
+#include "platform.h"
+#include "t_oop_generator.h"
+using namespace std;
+
+
+class t_csharp_generator : public t_oop_generator
+{
+  public:
+    t_csharp_generator(
+        t_program* program,
+        const std::map<std::string, std::string>& parsed_options,
+        const std::string& option_string)
+      : t_oop_generator(program)
+    {
+      out_dir_base_ = "gen-csharp";
+    }
+    void init_generator();
+    void close_generator();
+
+    void generate_consts(std::vector<t_const*> consts);
+
+    void generate_typedef (t_typedef* ttypedef);
+    void generate_enum (t_enum* tenum);
+    void generate_struct (t_struct* tstruct);
+    void generate_xception (t_struct* txception);
+    void generate_service (t_service* tservice);
+    void generate_property(ofstream& out, t_field* tfield, bool isPublic);
+    bool print_const_value (std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false, bool needtype=false);
+    std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+    void print_const_constructor(std::ofstream& out, std::vector<t_const*> consts);
+    void print_const_def_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+
+    void generate_csharp_struct(t_struct* tstruct, bool is_exception);
+    void generate_csharp_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false);
+    void generate_csharp_struct_reader(std::ofstream& out, t_struct* tstruct);
+    void generate_csharp_struct_result_writer(std::ofstream& out, t_struct* tstruct);
+    void generate_csharp_struct_writer(std::ofstream& out, t_struct* tstruct);
+    void generate_csharp_struct_tostring(std::ofstream& out, t_struct* tstruct);
+
+    void generate_function_helpers(t_function* tfunction);
+    void generate_service_interface (t_service* tservice);
+    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::ofstream& out, t_field* tfield, std::string prefix="");
+    void generate_deserialize_struct (std::ofstream& out, t_struct* tstruct, std::string prefix="");
+    void generate_deserialize_container (std::ofstream& out, t_type* ttype, std::string prefix="");
+    void generate_deserialize_set_element (std::ofstream& out, t_set* tset, std::string prefix="");
+    void generate_deserialize_map_element (std::ofstream& out, t_map* tmap, std::string prefix="");
+    void generate_deserialize_list_element (std::ofstream& out, t_list* list, std::string prefix="");
+    void generate_serialize_field (std::ofstream& out, t_field* tfield, std::string prefix="");
+    void generate_serialize_struct (std::ofstream& out, t_struct* tstruct, std::string prefix="");
+    void generate_serialize_container (std::ofstream& out, t_type* ttype, std::string prefix="");
+    void generate_serialize_map_element (std::ofstream& out, t_map* tmap, std::string iter, std::string map);
+    void generate_serialize_set_element (std::ofstream& out, t_set* tmap, std::string iter);
+    void generate_serialize_list_element (std::ofstream& out, t_list* tlist, std::string iter);
+
+    void start_csharp_namespace (std::ofstream& out);
+    void end_csharp_namespace (std::ofstream& out);
+
+    std::string csharp_type_usings();
+    std::string csharp_thrift_usings();
+
+    std::string type_name(t_type* ttype, bool in_countainer=false, bool in_init=false);
+    std::string base_type_name(t_base_type* tbase, bool in_container=false);
+    std::string declare_field(t_field* tfield, bool init=false);
+    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 prop_name(t_field* tfield);
+
+    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() ||
+        ttype->is_string();
+    }
+
+  private:
+    std::string namespace_name_;
+    std::ofstream f_service_;
+    std::string namespace_dir_;
+};
+
+
+void t_csharp_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+  namespace_name_ = program_->get_namespace("csharp");
+
+  string dir = namespace_name_;
+  string subdir = get_out_dir().c_str();
+  string::size_type loc;
+
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc + 1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  namespace_dir_ = subdir;
+}
+
+void t_csharp_generator::start_csharp_namespace(ofstream& out) {
+  if (!namespace_name_.empty()) {
+    out <<
+      "namespace " << namespace_name_ << "\n";
+    scope_up(out);
+  }
+}
+
+void t_csharp_generator::end_csharp_namespace(ofstream& out) {
+  if (!namespace_name_.empty()) {
+    scope_down(out);
+  }
+}
+
+string t_csharp_generator::csharp_type_usings() {
+  return string() +
+    "using System;\n" +
+    "using System.Collections;\n" +
+    "using System.Collections.Generic;\n" +
+    "using System.Text;\n" +
+    "using System.IO;\n" +
+    "using Thrift;\n" +
+    "using Thrift.Collections;\n";
+}
+
+string t_csharp_generator::csharp_thrift_usings() {
+  return string() +
+    "using Thrift.Protocol;\n" +
+    "using Thrift.Transport;\n";
+}
+
+void t_csharp_generator::close_generator() { }
+void t_csharp_generator::generate_typedef(t_typedef* ttypedef) {}
+
+void t_csharp_generator::generate_enum(t_enum* tenum) {
+  string f_enum_name = namespace_dir_+"/" + (tenum->get_name())+".cs";
+  ofstream f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  f_enum <<
+    autogen_comment() << endl;
+
+  start_csharp_namespace(f_enum);
+
+  indent(f_enum) <<
+    "public enum " << tenum->get_name() << "\n";
+  scope_up(f_enum);
+
+  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;
+    }
+
+    indent(f_enum) <<
+      (*c_iter)->get_name() <<
+      " = " << value << "," << endl;
+  }
+
+  scope_down(f_enum);
+
+  end_csharp_namespace(f_enum);
+
+  f_enum.close();
+}
+
+void t_csharp_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()){
+    return;
+  }
+  string f_consts_name = namespace_dir_ + "/Constants.cs";
+  ofstream f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  f_consts <<
+    autogen_comment() <<
+    csharp_type_usings() << endl;
+
+  start_csharp_namespace(f_consts);
+
+  indent(f_consts) <<
+    "public class Constants" << endl;
+  scope_up(f_consts);
+
+  vector<t_const*>::iterator c_iter;
+  bool need_static_constructor = false;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    if (print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false)) {
+      need_static_constructor = true;
+    }
+  }
+
+  if (need_static_constructor) {
+    print_const_constructor(f_consts, consts);
+  }
+
+  scope_down(f_consts);
+  end_csharp_namespace(f_consts);
+  f_consts.close();
+}
+
+void t_csharp_generator::print_const_def_value(std::ofstream& out, string name, t_type* type, t_const_value* value)
+{
+  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*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    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();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << "." << v_iter->first->get_string() << " = " << 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*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << 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(out, name, etype, *v_iter);
+      indent(out) << name << ".Add(" << val << ");" << endl;
+    }
+  }
+}
+
+void t_csharp_generator::print_const_constructor(std::ofstream& out, std::vector<t_const*> consts) {
+  indent(out) << "static Constants()" << endl;
+  scope_up(out);
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    t_const_value* value = (*c_iter)->get_value();
+
+    print_const_def_value(out, name, type, value);
+  }
+  scope_down(out);
+}
+
+
+//it seems like all that methods that call this are using in_static to be the opposite of what it would imply
+bool t_csharp_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval, bool needtype) {
+  indent(out);
+  bool need_static_construction = !in_static;
+  if (!defval || needtype) {
+    out <<
+      (in_static ? "" : "public static ") <<
+      type_name(type) << " ";
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    out << name << " = " << v2 << ";" << endl;
+    need_static_construction = false;
+  } else if (type->is_enum()) {
+    out << name << " = (" << type_name(type, false, true) << ")" << value->get_integer() << ";" << endl;
+    need_static_construction = false;
+  } else if (type->is_struct() || type->is_xception()) {
+    out << name << " = new " << type_name(type) << "();" << endl;
+  } else if (type->is_map()) {
+    out << name << " = new " << type_name(type, true, true) << "();" << endl;
+  } else if (type->is_list() || type->is_set()) {
+    out << name << " = new " << type_name(type) << "();" << endl;
+  }
+
+  if (defval && !type->is_base_type() && !type->is_enum()) {
+    print_const_def_value(out, name, type, value);
+  }
+
+  return need_static_construction;
+}
+
+std::string t_csharp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+  std::ostringstream render;
+
+  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:
+        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_BYTE:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        render << value->get_integer();
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        if (value->get_type() == t_const_value::CV_INTEGER) {
+          render << value->get_integer();
+        } else {
+          render << value->get_double();
+        }
+        break;
+      default:
+        throw "compiler error: no const of base type " + tbase;
+    }
+  } else if (type->is_enum()) {
+    render << "(" << type->get_name() << ")" << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true, true, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+void t_csharp_generator::generate_struct(t_struct* tstruct) {
+  generate_csharp_struct(tstruct, false);
+}
+
+void t_csharp_generator::generate_xception(t_struct* txception) {
+  generate_csharp_struct(txception, true);
+}
+
+void t_csharp_generator::generate_csharp_struct(t_struct* tstruct, bool is_exception) {
+  string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs";
+  ofstream f_struct;
+
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct <<
+    autogen_comment() <<
+    csharp_type_usings() <<
+    csharp_thrift_usings();
+
+  generate_csharp_struct_definition(f_struct, tstruct, is_exception);
+
+  f_struct.close();
+}
+
+void t_csharp_generator::generate_csharp_struct_definition(ofstream &out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result) {
+
+  if (!in_class) {
+    start_csharp_namespace(out);
+  }
+
+  out << endl;
+  indent(out) << "[Serializable]" << endl;
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+ 
+  indent(out) << "public " << (is_final ? "sealed " : "") << "class " << tstruct->get_name() << " : ";
+
+  if (is_exception) {
+    out << "Exception, ";
+  }
+  out << "TBase";
+
+  out << endl;
+
+  scope_up(out);
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  //make private members with public Properties
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) <<
+      "private " << declare_field(*m_iter, false) << endl;
+  }
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_property(out, *m_iter, true);
+  }
+
+  if (members.size() > 0) {
+    out <<
+      endl <<
+      indent() << "public Isset __isset;" << endl <<
+      indent() << "[Serializable]" << endl <<
+      indent() << "public struct Isset {" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      indent(out) <<
+        "public bool " << (*m_iter)->get_name() << ";" << endl;
+    }
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+
+  indent(out) <<
+    "public " << tstruct->get_name() << "() {" << endl;
+  indent_up();
+  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() != NULL) {
+      print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  generate_csharp_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_csharp_struct_result_writer(out, tstruct);
+  } else {
+    generate_csharp_struct_writer(out, tstruct);
+  }
+  generate_csharp_struct_tostring(out, tstruct);
+  scope_down(out);
+  out << endl;
+
+  if (!in_class)
+  {
+    end_csharp_namespace(out);
+  }
+}
+
+void t_csharp_generator::generate_csharp_struct_reader(ofstream& out, t_struct* tstruct) {
+  indent(out) <<
+    "public void Read (TProtocol iprot)" << endl;
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "TField field;" << endl <<
+    indent() << "iprot.ReadStructBegin();" << endl;
+
+  indent(out) <<
+    "while (true)" << endl;
+  scope_up(out);
+
+  indent(out) <<
+    "field = iprot.ReadFieldBegin();" << endl;
+
+  indent(out) <<
+    "if (field.Type == TType.Stop) { " << endl;
+  indent_up();
+  indent(out) <<
+    "break;" << endl;
+  indent_down();
+  indent(out) <<
+    "}" << endl;
+
+  indent(out) <<
+    "switch (field.ID)" << endl;
+
+  scope_up(out);
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) <<
+      "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) <<
+      "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter, "this.");
+    indent(out) <<
+      "this.__isset." << (*f_iter)->get_name() << " = true;" << endl;
+    indent_down();
+    out <<
+      indent() << "} else { " << endl <<
+      indent() << "  TProtocolUtil.Skip(iprot, field.Type);" << endl <<
+      indent() << "}" << endl <<
+      indent() << "break;" << endl;
+    indent_down();
+  }
+
+  indent(out) <<
+    "default: " << endl;
+  indent_up();
+  indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl;
+  indent(out) << "break;" << endl;
+  indent_down();
+
+  scope_down(out);
+
+  indent(out) <<
+    "iprot.ReadFieldEnd();" << endl;
+
+  scope_down(out);
+
+  indent(out) <<
+    "iprot.ReadStructEnd();" << endl;
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+
+}
+
+void t_csharp_generator::generate_csharp_struct_writer(ofstream& out, t_struct* tstruct) {
+  out <<
+    indent() << "public void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+  indent(out) <<
+    "oprot.WriteStructBegin(struc);" << endl;
+
+  if (fields.size() > 0) {
+    indent(out) << "TField field = new TField();" << endl;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      bool null_allowed = type_can_be_null((*f_iter)->get_type());
+      if (null_allowed) {
+        indent(out) <<
+          "if (this." << (*f_iter)->get_name() << " != null && __isset." << (*f_iter)->get_name() << ") {" << endl;
+        indent_up();
+      }
+      else
+      {
+        indent(out) <<
+          "if (__isset." << (*f_iter)->get_name() << ") {" << endl;
+        indent_up();
+      }
+
+      indent(out) <<
+        "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl;
+      indent(out) <<
+        "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
+      indent(out) <<
+        "field.ID = " << (*f_iter)->get_key() << ";" << endl;
+      indent(out) <<
+        "oprot.WriteFieldBegin(field);" << endl;
+
+      generate_serialize_field(out, *f_iter, "this.");
+
+      indent(out) <<
+        "oprot.WriteFieldEnd();" << endl;
+
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent(out) <<
+    "oprot.WriteFieldStop();" << endl;
+  indent(out) <<
+    "oprot.WriteStructEnd();" << endl;
+
+  indent_down();
+
+  indent(out) <<
+    "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_result_writer(ofstream& out, t_struct* tstruct) {
+  indent(out) <<
+    "public void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+  indent(out) <<
+    "oprot.WriteStructBegin(struc);" << endl;
+
+  if (fields.size() > 0) {
+    indent(out) << "TField field = new TField();" << endl;
+    bool first = true;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if (first) {
+        first = false;
+        out <<
+          endl << indent() << "if ";
+      } else {
+        out <<
+          " else if ";
+      }
+
+      out <<
+        "(this.__isset." << (*f_iter)->get_name() << ") {" << endl;
+      indent_up();
+
+      bool null_allowed = type_can_be_null((*f_iter)->get_type());
+      if (null_allowed) {
+        indent(out) <<
+          "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
+        indent_up();
+      }
+
+      indent(out) <<
+        "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl;
+      indent(out) <<
+        "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
+      indent(out) <<
+        "field.ID = " << (*f_iter)->get_key() << ";" << endl;
+      indent(out) <<
+        "oprot.WriteFieldBegin(field);" << endl;
+
+      generate_serialize_field(out, *f_iter, "this.");
+
+      indent(out) <<
+        "oprot.WriteFieldEnd();" << endl;
+
+      if (null_allowed) {
+        indent_down();
+        indent(out) << "}" << endl;
+      }
+
+      indent_down();
+      indent(out) << "}";
+    }
+  }
+
+  out <<
+    endl <<
+    indent() << "oprot.WriteFieldStop();" << endl <<
+    indent() << "oprot.WriteStructEnd();" << endl;
+
+  indent_down();
+
+  indent(out) <<
+    "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_tostring(ofstream& out, t_struct* tstruct) {
+  indent(out) <<
+    "public override string ToString() {" << endl;
+  indent_up();
+
+  indent(out) <<
+    "StringBuilder sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
+
+  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;
+      indent(out) <<
+        "sb.Append(\"" << (*f_iter)->get_name() << ": \");" << endl;
+    } else {
+      indent(out) <<
+        "sb.Append(\"," << (*f_iter)->get_name() << ": \");" << endl;
+    }
+    t_type* ttype = (*f_iter)->get_type();
+    if (ttype->is_xception() || ttype->is_struct()) {
+      indent(out) <<
+        "sb.Append(this." << (*f_iter)->get_name() << "== null ? \"<null>\" : "<< "this." << (*f_iter)->get_name() << ".ToString());" << endl;
+    } else {
+      indent(out) <<
+        "sb.Append(this." << (*f_iter)->get_name() << ");" << endl;
+    }
+  }
+
+  indent(out) <<
+    "sb.Append(\")\");" << endl;
+  indent(out) <<
+    "return sb.ToString();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_service(t_service* tservice) {
+  string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    autogen_comment() <<
+    csharp_type_usings() <<
+    csharp_thrift_usings();
+
+  start_csharp_namespace(f_service_);
+
+  indent(f_service_) <<
+    "public class " << service_name_ << " {" << endl;
+  indent_up();
+
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  indent_down();
+
+  indent(f_service_) <<
+    "}" << endl;
+  end_csharp_namespace(f_service_);
+  f_service_.close();
+}
+
+void t_csharp_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " : " + extends + ".Iface";
+  }
+
+  indent(f_service_) <<
+    "public interface Iface" << extends_iface << " {" << endl;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+  {
+    indent(f_service_) <<
+      function_signature(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl << endl;
+}
+
+void t_csharp_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_csharp_struct_definition(f_service_, ts, false, true);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+void t_csharp_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = extends + ".Client, ";
+  }
+
+  indent(f_service_) <<
+    "public class Client : " << extends_client << "Iface {" << endl;
+  indent_up();
+  indent(f_service_) <<
+    "public Client(TProtocol prot) : this(prot, prot)" << endl;
+  scope_up(f_service_);
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) <<
+    "public Client(TProtocol iprot, TProtocol oprot)";
+  if (!extends.empty()) {
+    f_service_ << " : base(iprot, oprot)";
+  }
+  f_service_ << endl;
+
+  scope_up(f_service_);
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "iprot_ = iprot;" << endl <<
+      indent() << "oprot_ = oprot;" << endl;
+  }
+  scope_down(f_service_);
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected TProtocol iprot_;" << endl <<
+      indent() << "protected TProtocol oprot_;" << endl <<
+      indent() << "protected int seqid_;" << endl << endl;
+
+    f_service_ << indent() << "public TProtocol InputProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "get { return iprot_; }" << endl;
+    scope_down(f_service_);
+
+    f_service_ << indent() << "public TProtocol OutputProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "get { return oprot_; }" << endl;
+    scope_down(f_service_);
+    f_service_ << endl << endl;
+  }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+
+    indent(f_service_) <<
+      "public " << function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+    indent(f_service_) <<
+      "send_" << funname << "(";
+
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << (*fld_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ <<
+        "recv_" << funname << "();" << endl;
+    }
+    scope_down(f_service_);
+    f_service_ << 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";
+
+    indent(f_service_) <<
+      "public " << function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    f_service_ <<
+      indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", TMessageType.Call, seqid_));" << endl <<
+      indent() << argsname << " args = new " << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ <<
+        indent() << "args." << prop_name(*fld_iter) << " = " << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    f_service_ <<
+      indent() << "args.Write(oprot_);" << endl <<
+      indent() << "oprot_.WriteMessageEnd();" << endl <<
+      indent() << "oprot_.Transport.Flush();" << endl;
+
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      string resultname = (*f_iter)->get_name() + "_result";
+
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+          string("recv_") + (*f_iter)->get_name(),
+          &noargs,
+          (*f_iter)->get_xceptions());
+      indent(f_service_) <<
+        "public " << function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      f_service_ <<
+        indent() << "TMessage msg = iprot_.ReadMessageBegin();" << endl <<
+        indent() << "if (msg.Type == TMessageType.Exception) {" << endl;
+      indent_up();
+      f_service_ <<
+        indent() << "TApplicationException x = TApplicationException.Read(iprot_);" << endl <<
+        indent() << "iprot_.ReadMessageEnd();" << endl <<
+        indent() << "throw x;" << endl;
+      indent_down();
+      f_service_ <<
+        indent() << "}" << endl <<
+        indent() << resultname << " result = new " << resultname << "();" << endl <<
+        indent() << "result.Read(iprot_);" << endl <<
+        indent() << "iprot_.ReadMessageEnd();" << endl;
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "if (result.__isset.success) {" << endl <<
+          indent() << "  return result.Success;" << endl <<
+          indent() << "}" << endl;
+      }
+
+      t_struct *xs = (*f_iter)->get_xceptions();
+
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
+          indent() << "  throw result." << prop_name(*x_iter) << ";" << endl <<
+          indent() << "}" << endl;
+      }
+
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "return;" << endl;
+      } else {
+        f_service_ <<
+          indent() << "throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+
+  indent_down();
+  indent(f_service_) <<
+    "}" << endl;
+}
+
+void t_csharp_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 = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".Processor, ";
+  }
+
+  indent(f_service_) <<
+    "public class Processor : " << extends_processor << "TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) <<
+    "public Processor(Iface iface)" ;
+  if (!extends.empty()) {
+    f_service_ << " : base(iface)";
+  }
+  f_service_ << endl;
+  scope_up(f_service_);
+  f_service_ <<
+    indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = " << (*f_iter)->get_name() << "_Process;" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);" << endl;
+  }
+
+  f_service_ <<
+    indent() << "private Iface iface_;" << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>();" << endl;
+  }
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    indent(f_service_) <<
+      "public bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  else
+  {
+    indent(f_service_) <<
+      "public new bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  scope_up(f_service_);
+
+  f_service_ <<  indent() << "try" << endl;
+  scope_up(f_service_);
+
+  f_service_ <<
+    indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
+
+  f_service_ <<
+    indent() << "ProcessFunction fn;" << endl <<
+    indent() << "processMap_.TryGetValue(msg.Name, out fn);" << endl <<
+    indent() << "if (fn == null) {" << endl <<
+    indent() << "  TProtocolUtil.Skip(iprot, TType.Struct);" << endl <<
+    indent() << "  iprot.ReadMessageEnd();" << endl <<
+    indent() << "  TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + msg.Name + \"'\");" << endl <<
+    indent() << "  oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));" << endl <<
+    indent() << "  x.Write(oprot);" << endl <<
+    indent() << "  oprot.WriteMessageEnd();" << endl <<
+    indent() << "  oprot.Transport.Flush();" << endl <<
+    indent() << "  return true;" << endl <<
+    indent() << "}" << endl <<
+    indent() << "fn(msg.SeqID, iprot, oprot);" << endl;
+
+  scope_down(f_service_);
+
+  f_service_ <<
+    indent() << "catch (IOException)" << endl;
+  scope_up(f_service_);
+  f_service_ <<
+    indent() << "return false;" << endl;
+  scope_down(f_service_);
+
+  f_service_ <<
+    indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+  {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) <<
+    "}" << endl << endl;
+}
+
+void t_csharp_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_csharp_struct_definition(f_service_, &result, false, true, true);
+}
+
+void t_csharp_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  indent(f_service_) <<
+    "public void " << tfunction->get_name() << "_Process(int seqid, TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ <<
+    indent() << argsname << " args = new " << argsname << "();" << endl <<
+    indent() << "args.Read(iprot);" << endl <<
+    indent() << "iprot.ReadMessageEnd();" << 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()) {
+    f_service_ <<
+      indent() << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  if (xceptions.size() > 0) {
+    f_service_ <<
+      indent() << "try {" << endl;
+    indent_up();
+  }
+
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.Success = ";
+  }
+  f_service_ <<
+    "iface_." << tfunction->get_name() << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << prop_name(*f_iter);
+  }
+  f_service_ << ");" << endl;
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}";
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*x_iter)->get_name() << ") {" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ <<
+          indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name() << ";" << endl;
+        indent_down();
+        f_service_ << indent() << "}";
+      } else {
+        f_service_ << "}";
+      }
+    }
+    f_service_ << endl;
+  }
+
+  if (tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "return;" << endl;
+    scope_down(f_service_);
+
+    return;
+  }
+
+  f_service_ <<
+    indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.Reply, seqid)); " << endl <<
+    indent() << "result.Write(oprot);" << endl <<
+    indent() << "oprot.WriteMessageEnd();" << endl <<
+    indent() << "oprot.Transport.Flush();" << endl;
+
+  scope_down(f_service_);
+
+  f_service_ << endl;
+}
+
+void t_csharp_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix) {
+  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 + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) <<
+      name << " = ";
+
+    if (type->is_enum())
+    {
+      out << "(" << type_name(type, false, true) << ")";
+    }
+
+    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 (((t_base_type*)type)->is_binary()) {
+             out << "ReadBinary();";
+          } else {
+            out << "ReadString();";
+          }
+          break;
+        case t_base_type::TYPE_BOOL:
+          out << "ReadBool();";
+          break;
+        case t_base_type::TYPE_BYTE:
+          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 C# name for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      out << "ReadI32();";
+    }
+    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_csharp_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) {
+  out <<
+    indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
+    indent() << prefix << ".Read(iprot);" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  indent(out) <<
+    prefix << " = new " << type_name(ttype, false, true) << "();" <<endl;
+  if (ttype->is_map()) {
+    out <<
+      indent() << "TMap " << obj << " = iprot.ReadMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    out <<
+      indent() << "TSet " << obj << " = iprot.ReadSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    out <<
+      indent() << "TList " << obj << " = iprot.ReadListBegin();" << endl;
+  }
+
+  string i = tmp("_i");
+  indent(out) <<
+    "for( int " << i << " = 0; " << i << " < " << obj << ".Count" << "; " << "++" << i << ")" << endl;
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "iprot.ReadMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.ReadSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.ReadListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+void t_csharp_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) <<
+    declare_field(&fkey) << endl;
+  indent(out) <<
+    declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) <<
+    prefix << "[" << key << "] = " << val << ";" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) <<
+    declare_field(&felem, true) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_list_element(ofstream& out, t_list* tlist, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) <<
+    declare_field(&felem, true) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+    string name = prefix + tfield->get_name();
+    indent(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 (((t_base_type*)type)->is_binary()) {
+            out << "WriteBinary(";
+          } else {
+            out << "WriteString(";
+          }
+          out << name << ");";
+          break;
+        case t_base_type::TYPE_BOOL:
+          out << "WriteBool(" << name << ");";
+          break;
+        case t_base_type::TYPE_BYTE:
+          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 C# name for base type " + tbase;
+      }
+    } else if (type->is_enum()) {
+      out << "WriteI32((int)" << 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_csharp_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) {
+  out <<
+    indent() << prefix << ".Write(oprot);" << endl;
+}
+
+void t_csharp_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "oprot.WriteMapBegin(new TMap(" <<
+      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+      prefix << ".Count));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "oprot.WriteSetBegin(new TSet(" <<
+      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".Count));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "oprot.WriteListBegin(new TList(" <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".Count));" << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    indent(out) <<
+      "foreach (" <<
+      type_name(((t_map*)ttype)->get_key_type()) << " " << iter <<
+      " in " <<
+      prefix << ".Keys)";
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "foreach (" <<
+      type_name(((t_set*)ttype)->get_elem_type()) << " " << iter <<
+      " in " <<
+      prefix << ")";
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "foreach (" <<
+      type_name(((t_list*)ttype)->get_elem_type()) << " " << iter <<
+      " in " <<
+      prefix << ")";
+  }
+
+  out << endl;
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.WriteMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.WriteSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.WriteListEnd();" << endl;
+  }
+
+  scope_down(out);
+  scope_down(out);
+}
+
+void t_csharp_generator::generate_serialize_map_element(ofstream& out, t_map* tmap, string iter, string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, &kfield, "");
+  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+  generate_serialize_field(out, &vfield, "");
+}
+
+void t_csharp_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+void t_csharp_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+void t_csharp_generator::generate_property(ofstream& out, t_field* tfield, bool isPublic) {
+    indent(out) << (isPublic ? "public " : "private ") << type_name(tfield->get_type())
+                << " " << prop_name(tfield) << endl;
+    scope_up(out);
+    indent(out) << "get" << endl;
+    scope_up(out);
+    indent(out) << "return " << tfield->get_name() << ";" << endl;
+    scope_down(out);
+    indent(out) << "set" << endl;
+    scope_up(out);
+    indent(out) << "__isset." << tfield->get_name() << " = true;" << endl;
+    indent(out) << "this." << tfield->get_name() << " = value;" << endl;
+    scope_down(out);
+    scope_down(out);
+    out << endl;
+}
+
+std::string t_csharp_generator::prop_name(t_field* tfield) {
+    string name (tfield->get_name());
+    name[0] = toupper(name[0]);
+    return name;
+}
+
+string t_csharp_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype, in_container);
+  } else if (ttype->is_map()) {
+    t_map *tmap = (t_map*) ttype;
+    return "Dictionary<" + type_name(tmap->get_key_type(), true) +
+      ", " + type_name(tmap->get_val_type(), true) + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*) ttype;
+    return "THashSet<" + type_name(tset->get_elem_type(), true) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*) ttype;
+    return "List<" + type_name(tlist->get_elem_type(), true) + ">";
+  }
+
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    string ns = program->get_namespace("csharp");
+    if (!ns.empty()) {
+      return ns + "." + ttype->get_name();
+    }
+  }
+
+  return ttype->get_name();
+}
+
+string t_csharp_generator::base_type_name(t_base_type* tbase, bool in_container) {
+  switch (tbase->get_base()) {
+    case t_base_type::TYPE_VOID:
+      return "void";
+    case t_base_type::TYPE_STRING:
+      if (tbase->is_binary()) {
+        return "byte[]";
+      } else {
+        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 "short";
+    case t_base_type::TYPE_I32:
+      return "int";
+    case t_base_type::TYPE_I64:
+      return "long";
+    case t_base_type::TYPE_DOUBLE:
+      return "double";
+    default:
+      throw "compiler error: no C# name for base type " + tbase->get_base();
+  }
+}
+
+string t_csharp_generator::declare_field(t_field* tfield, bool init) {
+  string result = type_name(tfield->get_type()) + " " + tfield->get_name();
+  if (init) {
+    t_type* ttype = tfield->get_type();
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw "NO T_VOID CONSTRUCT";
+        case t_base_type::TYPE_STRING:
+          result += " = null";
+          break;
+        case t_base_type::TYPE_BOOL:
+          result += " = 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:
+          result += " = 0";
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          result += " = (double)0";
+          break;
+      }
+    } else if (ttype->is_enum()) {
+      result += " = (" + type_name(ttype, false, true) + ")0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    }
+  }
+  return result + ";";
+}
+
+string t_csharp_generator::function_signature(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  return type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")";
+}
+
+string t_csharp_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;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+string t_csharp_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_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();
+}
+
+
+THRIFT_REGISTER_GENERATOR(csharp, "C#", "");
diff --git a/compiler/cpp/src/generate/t_erl_generator.cc b/compiler/cpp/src/generate/t_erl_generator.cc
new file mode 100644
index 0000000..0aff4f3
--- /dev/null
+++ b/compiler/cpp/src/generate/t_erl_generator.cc
@@ -0,0 +1,932 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include "t_generator.h"
+#include "platform.h"
+
+using namespace std;
+
+
+/**
+ * Erlang code generator.
+ *
+ */
+class t_erl_generator : public t_generator {
+ public:
+  t_erl_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_generator(program)
+  {
+    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_;
+
+};
+
+
+/**
+ * UI for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_erl_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // setup export lines
+  export_lines_first_ = true;
+  export_types_lines_first_ = true;
+
+  // types files
+  string f_types_name = get_out_dir()+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_erl_generator::hrl_header(ostream& out, string name) {
+  out << "-ifndef(_" << name << "_included)." << endl <<
+    "-define(_" << name << "_included, yeah)." << endl;
+}
+
+void t_erl_generator::hrl_footer(ostream& out, string name) {
+  out << "-endif." << endl;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_erl_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += "-include(\"" + includes[i]->get_name() + "_types.hrl\").\n";
+  }
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+  return result;
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_erl_generator::erl_autogen_comment() {
+  return
+    std::string("%%\n") +
+    "%% Autogenerated by Thrift\n" +
+    "%%\n" +
+    "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
+    "%%\n";
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_erl_generator::erl_imports() {
+  return "";
+}
+
+/**
+ * Closes the type files
+ */
+void t_erl_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_erl_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_erl_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_erl_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_erl_generator::render_const_value(t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream out;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+
+  } else if (type->is_struct() || type->is_xception()) {
+    out << "#" << 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 << "]";
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+/**
+ * Generates a struct
+ */
+void t_erl_generator::generate_struct(t_struct* tstruct) {
+  generate_erl_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct but extends the Exception class.
+ *
+ * @param txception The struct definition
+ */
+void t_erl_generator::generate_xception(t_struct* txception) {
+  generate_erl_struct(txception, true);
+}
+
+/**
+ * Generates a struct
+ */
+void t_erl_generator::generate_erl_struct(t_struct* tstruct,
+                                          bool is_exception) {
+  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_erl_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 << ", ";
+      }
+      std::string name = uncapitalize((*m_iter)->get_name());
+      out     << name;
+      hrl_out << 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_erl_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_erl_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());
+
+  // Reset service text aggregating stream streams
+  f_service_.str("");
+  export_lines_.str("");
+  export_lines_first_ = true;
+
+  hrl_header(f_service_hrl_, service_name_);
+
+  if (tservice->get_extends() != NULL) {
+    f_service_hrl_ << "-include(\"" <<
+      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_erl_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  //  indent(f_service_) <<
+  //  "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+  export_string("struct_info", 1);
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_erl_function_helpers(*f_iter);
+  }
+  f_service_    << "struct_info('i am a dummy struct') -> undefined." << endl;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_erl_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_erl_generator::generate_service_interface(t_service* tservice) {
+
+  export_string("function_info", 2);
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  f_service_ << "%%% interface" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      indent() << "% " << function_signature(*f_iter) << endl;
+
+    generate_function_info(tservice, *f_iter);
+  }
+
+  // Inheritance - pass unknown functions to base class
+  if (tservice->get_extends() != NULL) {
+      indent(f_service_) << "function_info(Function, InfoType) ->" << endl;
+      indent_up();
+      indent(f_service_) << uncapitalize(tservice->get_extends()->get_name())
+                         << "_thrift:function_info(Function, InfoType)." << endl;
+      indent_down();
+  } else {
+      // 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_erl_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(), false) << ";" << endl;
+  else if (tfunction->is_oneway())
+    indent(f_service_) << "oneway_void;" << endl;
+  else
+    indent(f_service_) << "{struct, []}" << ";" << endl;
+  indent_down();
+
+  // function_info(Function, exceptions):
+  indent(f_service_) <<
+    "function_info(" << name_atom << ", exceptions) ->" << endl;
+  indent_up();
+  indent(f_service_) << generate_type_term(xs, true) << ";" << endl;
+  indent_down();
+}
+
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_erl_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_erl_generator::function_signature(t_function* tfunction,
+                                           string prefix) {
+  return
+    prefix + tfunction->get_name() +
+    "(This" +  capitalize(argument_list(tfunction->get_arglist())) + ")";
+}
+
+/**
+ * Add a function to the exports list
+ */
+void t_erl_generator::export_string(string name, int num) {
+  if (export_lines_first_) {
+    export_lines_first_ = false;
+  } else {
+    export_lines_ << ", ";
+  }
+  export_lines_ << name << "/" << num;
+}
+
+void t_erl_generator::export_types_function(t_function* tfunction,
+                                               string prefix) {
+
+  export_types_string(prefix + tfunction->get_name(),
+                      1 // This
+                      + ((tfunction->get_arglist())->get_members()).size()
+                      );
+}
+
+void t_erl_generator::export_types_string(string name, int num) {
+  if (export_types_lines_first_) {
+    export_types_lines_first_ = false;
+  } else {
+    export_types_lines_ << ", ";
+  }
+  export_types_lines_ << name << "/" << num;
+}
+
+void t_erl_generator::export_function(t_function* tfunction,
+                                      string prefix) {
+
+  export_string(prefix + tfunction->get_name(),
+                1 // This
+                + ((tfunction->get_arglist())->get_members()).size()
+                );
+}
+
+
+/**
+ * Renders a field list
+ */
+string t_erl_generator::argument_list(t_struct* tstruct) {
+  string result = "";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      result += ", "; // initial comma to compensate for initial This
+    } else {
+      result += ", ";
+    }
+    result += capitalize((*f_iter)->get_name());
+  }
+  return result;
+}
+
+string t_erl_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  string name = ttype->get_name();
+
+  if (ttype->is_struct() || ttype->is_xception() || ttype->is_service()) {
+    name = uncapitalize(ttype->get_name());
+  }
+
+  return prefix + name;
+}
+
+/**
+ * Converts the parse type to a Erlang "type" (macro for int constants)
+ */
+string t_erl_generator::type_to_enum(t_type* type) {
+  type = get_true_type(type);
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "?tType_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "?tType_BOOL";
+    case t_base_type::TYPE_BYTE:
+      return "?tType_BYTE";
+    case t_base_type::TYPE_I16:
+      return "?tType_I16";
+    case t_base_type::TYPE_I32:
+      return "?tType_I32";
+    case t_base_type::TYPE_I64:
+      return "?tType_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "?tType_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "?tType_I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "?tType_STRUCT";
+  } else if (type->is_map()) {
+    return "?tType_MAP";
+  } else if (type->is_set()) {
+    return "?tType_SET";
+  } else if (type->is_list()) {
+    return "?tType_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+
+/**
+ * Generate an Erlang term which represents a thrift type
+ */
+std::string t_erl_generator::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_erl_generator::type_module(t_type* ttype) {
+  return uncapitalize(ttype->get_program()->get_name()) + "_types";
+}
+
+THRIFT_REGISTER_GENERATOR(erl, "Erlang", "");
diff --git a/compiler/cpp/src/generate/t_generator.cc b/compiler/cpp/src/generate/t_generator.cc
new file mode 100644
index 0000000..38c053c
--- /dev/null
+++ b/compiler/cpp/src/generate/t_generator.cc
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "t_generator.h"
+using namespace std;
+
+/**
+ * Top level program generation function. Calls the generator subclass methods
+ * for preparing file streams etc. then iterates over all the parts of the
+ * program to perform the correct actions.
+ *
+ * @param program The thrift program to compile into C++ source
+ */
+void t_generator::generate_program() {
+  // Initialize the generator
+  init_generator();
+
+  // Generate enums
+  vector<t_enum*> enums = program_->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    generate_enum(*en_iter);
+  }
+
+  // Generate typedefs
+  vector<t_typedef*> typedefs = program_->get_typedefs();
+  vector<t_typedef*>::iterator td_iter;
+  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+    generate_typedef(*td_iter);
+  }
+
+  // Generate constants
+  vector<t_const*> consts = program_->get_consts();
+  generate_consts(consts);
+
+  // Generate structs and exceptions in declared order
+  vector<t_struct*> objects = program_->get_objects();
+  vector<t_struct*>::iterator o_iter;
+  for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+    if ((*o_iter)->is_xception()) {
+      generate_xception(*o_iter);
+    } else {
+      generate_struct(*o_iter);
+    }
+  }
+
+  // Generate services
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    service_name_ = get_service_name(*sv_iter);
+    generate_service(*sv_iter);
+  }
+
+  // Close the generator
+  close_generator();
+}
+
+string t_generator::escape_string(const string &in) const {
+  string result = "";
+  for (string::const_iterator it = in.begin(); it < in.end(); it++) {
+    std::map<char, std::string>::const_iterator res = escape_.find(*it);
+    if (res != escape_.end()) {
+      result.append(res->second);
+    } else {
+      result.push_back(*it);
+    }
+  }
+  return result;
+}
+
+void t_generator::generate_consts(vector<t_const*> consts) {
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    generate_const(*c_iter);
+  }
+}
+
+void t_generator::generate_docstring_comment(ofstream& out,
+                                             const string& comment_start,
+                                             const string& line_prefix,
+                                             const string& contents,
+                                             const string& comment_end) {
+  if (comment_start != "") indent(out) << comment_start;
+  stringstream docs(contents, ios_base::in);
+  while (!docs.eof()) {
+    char line[1024];
+    docs.getline(line, 1024);
+    if (strlen(line) > 0 || !docs.eof()) {  // skip the empty last line
+      indent(out) << line_prefix << line << std::endl;
+    }
+  }
+  if (comment_end != "") indent(out) << comment_end;
+}
+
+
+void t_generator_registry::register_generator(t_generator_factory* factory) {
+  gen_map_t& the_map = get_generator_map();
+  if (the_map.find(factory->get_short_name()) != the_map.end()) {
+    failure("Duplicate generators for language \"%s\"!\n", factory->get_short_name().c_str());
+  }
+  the_map[factory->get_short_name()] = factory;
+}
+
+t_generator* t_generator_registry::get_generator(t_program* program,
+                                                 const string& options) {
+  string::size_type colon = options.find(':');
+  string language = options.substr(0, colon);
+
+  map<string, string> parsed_options;
+  if (colon != string::npos) {
+    string::size_type pos = colon+1;
+    while (pos != string::npos && pos < options.size()) {
+      string::size_type next_pos = options.find(',', pos);
+      string option = options.substr(pos, next_pos-pos);
+      pos = ((next_pos == string::npos) ? next_pos : next_pos+1);
+
+      string::size_type separator = option.find('=');
+      string key, value;
+      if (separator == string::npos) {
+        key = option;
+        value = "";
+      } else {
+        key = option.substr(0, separator);
+        value = option.substr(separator+1);
+      }
+
+      parsed_options[key] = value;
+    }
+  }
+
+  gen_map_t& the_map = get_generator_map();
+  gen_map_t::iterator iter = the_map.find(language);
+
+  if (iter == the_map.end()) {
+    return NULL;
+  }
+
+  return iter->second->get_generator(program, parsed_options, options);
+}
+
+t_generator_registry::gen_map_t& t_generator_registry::get_generator_map() {
+  // http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
+  static gen_map_t* the_map = new gen_map_t();
+  return *the_map;
+}
+
+t_generator_factory::t_generator_factory(
+    const std::string& short_name,
+    const std::string& long_name,
+    const std::string& documentation)
+  : short_name_(short_name)
+  , long_name_(long_name)
+  , documentation_(documentation)
+{
+  t_generator_registry::register_generator(this);
+}
diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h
new file mode 100644
index 0000000..7514fb1
--- /dev/null
+++ b/compiler/cpp/src/generate/t_generator.h
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_GENERATOR_H
+#define T_GENERATOR_H
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include "parse/t_program.h"
+#include "globals.h"
+
+/**
+ * Base class for a thrift code generator. This class defines the basic
+ * routines for code generation and contains the top level method that
+ * dispatches code generation across various components.
+ *
+ */
+class t_generator {
+ public:
+  t_generator(t_program* program) {
+    tmp_ = 0;
+    indent_ = 0;
+    program_ = program;
+    program_name_ = get_program_name(program);
+    escape_['\n'] = "\\n";
+    escape_['\r'] = "\\r";
+    escape_['\t'] = "\\t";
+    escape_['"']  = "\\\"";
+    escape_['\\'] = "\\\\";
+  }
+
+  virtual ~t_generator() {}
+
+  /**
+   * Framework generator method that iterates over all the parts of a program
+   * and performs general actions. This is implemented by the base class and
+   * should not normally be overwritten in the subclasses.
+   */
+  virtual void generate_program();
+
+  const t_program* get_program() const { return program_; }
+
+  void generate_docstring_comment(std::ofstream& out,
+                                  const std::string& comment_start,
+                                  const std::string& line_prefix,
+                                  const std::string& contents,
+                                  const std::string& comment_end);
+
+  /**
+   * Escape string to use one in generated sources.
+   */
+  virtual std::string escape_string(const std::string &in) const;
+
+  std::string get_escaped_string(t_const_value* constval) {
+    return escape_string(constval->get_string());
+  }
+
+ protected:
+
+  /**
+   * Optional methods that may be imlemented by subclasses to take necessary
+   * steps at the beginning or end of code generation.
+   */
+
+  virtual void init_generator() {}
+  virtual void close_generator() {}
+
+  virtual void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Pure virtual methods implemented by the generator subclasses.
+   */
+
+  virtual void generate_typedef  (t_typedef*  ttypedef)  = 0;
+  virtual void generate_enum     (t_enum*     tenum)     = 0;
+  virtual void generate_const    (t_const*    tconst) {}
+  virtual void generate_struct   (t_struct*   tstruct)   = 0;
+  virtual void generate_service  (t_service*  tservice)  = 0;
+  virtual void generate_xception (t_struct*   txception) {
+    // By default exceptions are the same as structs
+    generate_struct(txception);
+  }
+
+  /**
+   * Method to get the program name, may be overridden
+   */
+  virtual std::string get_program_name(t_program* tprogram) {
+    return tprogram->get_name();
+  }
+
+  /**
+   * Method to get the service name, may be overridden
+   */
+  virtual std::string get_service_name(t_service* tservice) {
+    return tservice->get_name();
+  }
+
+  /**
+   * Get the current output directory
+   */
+  virtual std::string get_out_dir() const {
+    return program_->get_out_path() + out_dir_base_ + "/";
+  }
+
+  /**
+   * Creates a unique temporary variable name, which is just "name" with a
+   * number appended to it (i.e. name35)
+   */
+  std::string tmp(std::string name) {
+    std::ostringstream out;
+    out << name << tmp_++;
+    return out.str();
+  }
+
+  /**
+   * Indentation level modifiers
+   */
+
+  void indent_up(){
+    ++indent_;
+  }
+
+  void indent_down() {
+    --indent_;
+  }
+
+  /**
+   * Indentation print function
+   */
+  std::string indent() {
+    std::string ind = "";
+    int i;
+    for (i = 0; i < indent_; ++i) {
+      ind += "  ";
+    }
+    return ind;
+  }
+
+  /**
+   * Indentation utility wrapper
+   */
+  std::ostream& indent(std::ostream &os) {
+    return os << indent();
+  }
+
+  /**
+   * Capitalization helpers
+   */
+  std::string capitalize(std::string in) {
+    in[0] = toupper(in[0]);
+    return in;
+  }
+  std::string decapitalize(std::string in) {
+    in[0] = tolower(in[0]);
+    return in;
+  }
+  std::string lowercase(std::string in) {
+    for (size_t i = 0; i < in.size(); ++i) {
+      in[i] = tolower(in[i]);
+    }
+    return in;
+  }
+  std::string underscore(std::string in) {
+    in[0] = tolower(in[0]);
+    for (size_t i = 1; i < in.size(); ++i) {
+      if (isupper(in[i])) {
+        in[i] = tolower(in[i]);
+        in.insert(i, "_");
+      }
+    }
+    return in;
+  }
+
+  /**
+   * Get the true type behind a series of typedefs.
+   */
+  static t_type* get_true_type(t_type* type) {
+    while (type->is_typedef()) {
+      type = ((t_typedef*)type)->get_type();
+    }
+    return type;
+  }
+
+ protected:
+  /**
+   * The program being generated
+   */
+  t_program* program_;
+
+  /**
+   * Quick accessor for formatted program name that is currently being
+   * generated.
+   */
+  std::string program_name_;
+
+  /**
+   * Quick accessor for formatted service name that is currently being
+   * generated.
+   */
+  std::string service_name_;
+
+  /**
+   * Output type-specifc directory name ("gen-*")
+   */
+  std::string out_dir_base_;
+
+  /**
+   * Map of characters to escape in string literals.
+   */
+  std::map<char, std::string> escape_;
+
+ private:
+  /**
+   * Current code indentation level
+   */
+  int indent_;
+
+  /**
+   * Temporary variable counter, for making unique variable names
+   */
+  int tmp_;
+};
+
+
+/**
+ * A factory for producing generator classes of a particular language.
+ *
+ * This class is also responsible for:
+ *  - Registering itself with the generator registry.
+ *  - Providing documentation for the generators it produces.
+ */
+class t_generator_factory {
+ public:
+  t_generator_factory(const std::string& short_name,
+                      const std::string& long_name,
+                      const std::string& documentation);
+
+  virtual ~t_generator_factory() {}
+
+  virtual t_generator* get_generator(
+      // The program to generate.
+      t_program* program,
+      // Note: parsed_options will not exist beyond the call to get_generator.
+      const std::map<std::string, std::string>& parsed_options,
+      // Note: option_string might not exist beyond the call to get_generator.
+      const std::string& option_string)
+    = 0;
+
+  std::string get_short_name() { return short_name_; }
+  std::string get_long_name() { return long_name_; }
+  std::string get_documentation() { return documentation_; }
+
+ private:
+  std::string short_name_;
+  std::string long_name_;
+  std::string documentation_;
+};
+
+template <typename generator>
+class t_generator_factory_impl : public t_generator_factory {
+ public:
+  t_generator_factory_impl(const std::string& short_name,
+                           const std::string& long_name,
+                           const std::string& documentation)
+    : t_generator_factory(short_name, long_name, documentation)
+  {}
+
+  virtual t_generator* get_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string) {
+    return new generator(program, parsed_options, option_string);
+  }
+};
+
+class t_generator_registry {
+ public:
+  static void register_generator(t_generator_factory* factory);
+
+  static t_generator* get_generator(t_program* program,
+                                    const std::string& options);
+
+  typedef std::map<std::string, t_generator_factory*> gen_map_t;
+  static gen_map_t& get_generator_map();
+
+ private:
+  t_generator_registry();
+  t_generator_registry(const t_generator_registry&);
+};
+
+#define THRIFT_REGISTER_GENERATOR(language, long_name, doc)        \
+  class t_##language##_generator_factory_impl                      \
+    : public t_generator_factory_impl<t_##language##_generator>    \
+  {                                                                \
+   public:                                                         \
+    t_##language##_generator_factory_impl()                        \
+      : t_generator_factory_impl<t_##language##_generator>(        \
+          #language, long_name, doc)                               \
+    {}                                                             \
+  };                                                               \
+  static t_##language##_generator_factory_impl _registerer;
+
+#endif
diff --git a/compiler/cpp/src/generate/t_hs_generator.cc b/compiler/cpp/src/generate/t_hs_generator.cc
new file mode 100644
index 0000000..c8fda77
--- /dev/null
+++ b/compiler/cpp/src/generate/t_hs_generator.cc
@@ -0,0 +1,1445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include "t_oop_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * Haskell code generator.
+ *
+ */
+class t_hs_generator : public t_oop_generator {
+ public:
+  t_hs_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    out_dir_base_ = "gen-hs";
+  }
+
+  /**
+   * 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_hs_struct(t_struct* tstruct, bool is_exception);
+  void generate_hs_struct_definition(std::ofstream &out,t_struct* tstruct, bool is_xception=false,bool helper=false);
+  void generate_hs_struct_reader(std::ofstream& out, t_struct* tstruct);
+  void generate_hs_struct_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_hs_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_service_client    (t_service* tservice);
+  void generate_service_server    (t_service* tservice);
+  void generate_process_function  (t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix);
+
+  void generate_deserialize_struct       (std::ofstream &out,
+                                          t_struct*   tstruct);
+
+  void generate_deserialize_container    (std::ofstream &out,
+                                          t_type*     ttype);
+
+  void generate_deserialize_set_element  (std::ofstream &out,
+                                          t_set*      tset);
+
+
+  void generate_deserialize_list_element (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+  void generate_deserialize_type          (std::ofstream &out,
+                                           t_type* type);
+
+  void generate_serialize_field          (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string name= "");
+
+  void generate_serialize_struct         (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string kiter,
+                                          std::string viter);
+
+  void generate_serialize_set_element    (std::ofstream &out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string hs_autogen_comment();
+  std::string hs_imports();
+  std::string type_name(t_type* ttype);
+  std::string function_type(t_function* tfunc, bool options = false, bool io = false, bool method = false);
+  std::string type_to_enum(t_type* ttype);
+  std::string render_hs_type(t_type* type, bool needs_parens = true);
+
+
+ private:
+
+  /**
+   * File streams
+   */
+
+  std::ofstream f_types_;
+  std::ofstream f_consts_;
+  std::ofstream f_service_;
+  std::ofstream f_iface_;
+  std::ofstream f_client_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_hs_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+
+  string pname = capitalize(program_name_);
+  string f_types_name = get_out_dir()+pname+"_Types.hs";
+  f_types_.open(f_types_name.c_str());
+
+  string f_consts_name = get_out_dir()+pname+"_Consts.hs";
+  f_consts_.open(f_consts_name.c_str());
+
+  // Print header
+  f_types_ <<
+    hs_autogen_comment() << endl <<
+    "module " << pname <<"_Types where" << endl <<
+    hs_imports() << endl;
+
+  f_consts_ <<
+    hs_autogen_comment() << endl <<
+    "module " << pname <<"_Consts where" << endl <<
+    hs_imports() << endl <<
+    "import " << pname<<"_Types"<< endl;
+
+}
+
+
+/**
+ * Autogen'd comment
+ */
+string t_hs_generator::hs_autogen_comment() {
+  return
+    std::string("-----------------------------------------------------------------\n") +
+    "-- Autogenerated by Thrift                                     --\n" +
+    "--                                                             --\n" +
+    "-- DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING --\n" +
+    "-----------------------------------------------------------------\n";
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_hs_generator::hs_imports() {
+  return "import Thrift\nimport Data.Typeable ( Typeable )\nimport Control.Exception\nimport qualified Data.Map as Map\nimport qualified Data.Set as Set\nimport Data.Int";
+}
+
+/**
+ * Closes the type files
+ */
+void t_hs_generator::close_generator() {
+  // Close types file
+  f_types_.close();
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. Ez.
+ *
+ * @param ttypedef The type definition
+ */
+void t_hs_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ <<
+    indent() << "type "<< capitalize(ttypedef->get_symbolic()) << " = " << render_hs_type(ttypedef->get_type(), false) << endl << endl;
+}
+
+/**
+ * Generates code for an enumerated type.
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_hs_generator::generate_enum(t_enum* tenum) {
+  indent(f_types_) << "data "<<capitalize(tenum->get_name())<<" = ";
+  indent_up();
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    string name = capitalize((*c_iter)->get_name());
+    if(first)
+      first=false;
+    else
+      f_types_ << "|";
+    f_types_ << name;
+  }
+  indent(f_types_) << "deriving (Show,Eq, Typeable, Ord)" << endl;
+  indent_down();
+
+  int value = -1;
+  indent(f_types_) << "instance Enum " << capitalize(tenum->get_name()) << " where" << endl;
+  indent_up();
+  indent(f_types_) << "fromEnum t = case t of" << endl;
+  indent_up();
+  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_ <<
+      indent() << name << " -> " << value << endl;
+  }
+  indent_down();
+
+  indent(f_types_) << "toEnum t = case t of" << endl;
+  indent_up();
+  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_ <<
+      indent() << value << " -> " << name << endl;
+  }
+  indent(f_types_) << "_ -> throw ThriftException" << endl;
+  indent_down();
+  indent_down();
+}
+
+/**
+ * Generate a constant value
+ */
+void t_hs_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = decapitalize(tconst->get_name());
+  t_const_value* value = tconst->get_value();
+
+  indent(f_consts_) << name << " :: " << render_hs_type(type, false) << endl;
+  indent(f_consts_) << 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_hs_generator::render_const_value(t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream out;
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "True" : "False");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    t_enum* tenum = (t_enum*)type;
+    vector<t_enum_value*> constants = tenum->get_constants();
+    vector<t_enum_value*>::iterator c_iter;
+    int val = -1;
+    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+      if ((*c_iter)->has_value()) {
+        val = (*c_iter)->get_value();
+      } else {
+        ++val;
+      }
+      if(val == value->get_integer()){
+        indent(out) << capitalize((*c_iter)->get_name());
+        break;
+      }
+    }
+  } else if (type->is_struct() || type->is_xception()) {
+    string cname = type_name(type);
+    indent(out) << cname << "{";
+    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();
+      }
+      string fname = v_iter->first->get_string();
+      if(first)
+        first=false;
+      else
+        out << ",";
+      out << "f_" << cname << "_" << fname << " = Just (" << render_const_value(field_type, v_iter->second) << ")";
+
+    }
+    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;
+    out << "(Map.fromList [";
+    bool first=true;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(ktype, v_iter->first);
+      string val = render_const_value(vtype, v_iter->second);
+      if(first)
+        first=false;
+      else
+        out << ",";
+      out << "(" << key << ","<< val << ")";
+    }
+    out << "])";
+  } 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;
+    bool first = true;
+
+    if (type->is_set())
+        out << "(Set.fromList ";
+
+    out << "[";
+
+    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 << "]";
+    if (type->is_set())
+        out << ")";
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+/**
+ * Generates a "struct"
+ */
+void t_hs_generator::generate_struct(t_struct* tstruct) {
+  generate_hs_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct, but also has an exception declaration.
+ *
+ * @param txception The struct definition
+ */
+void t_hs_generator::generate_xception(t_struct* txception) {
+  generate_hs_struct(txception, true);
+}
+
+/**
+ * Generates a Haskell struct
+ */
+void t_hs_generator::generate_hs_struct(t_struct* tstruct,
+                                              bool is_exception) {
+  generate_hs_struct_definition(f_types_,tstruct, is_exception,false);
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_hs_generator::generate_hs_struct_definition(ofstream& out,
+                                                   t_struct* tstruct,
+                                                   bool is_exception,
+                                                   bool helper) {
+  string tname = type_name(tstruct);
+  string name = tstruct->get_name();
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent(out) << "data "<<tname<<" = "<<tname;
+  if (members.size() > 0) {
+    out << "{";
+    bool first=true;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if(first)
+        first=false;
+      else
+        out << ",";
+      string mname = (*m_iter)->get_name();
+      out << "f_" << tname << "_" << mname << " :: Maybe " << render_hs_type((*m_iter)->get_type());
+    }
+    out << "}";
+  }
+
+  out << " deriving (Show,Eq,Ord,Typeable)" << endl;
+  if (is_exception) out << "instance Exception " << tname << endl;
+  generate_hs_struct_writer(out, tstruct);
+
+  generate_hs_struct_reader(out, tstruct);
+  //f_struct_.close();
+}
+
+
+
+/**
+ * Generates the read method for a struct
+ */
+void t_hs_generator::generate_hs_struct_reader(ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  string sname = type_name(tstruct);
+  string str = tmp("_str");
+  string t = tmp("_t");
+  string id = tmp("_id");
+
+  indent(out) << "read_" << sname << "_fields iprot rec = do" << endl;
+  indent_up(); // do
+
+  // Read beginning field marker
+  indent(out) << "(_," << t <<","<<id<<") <- readFieldBegin iprot" << endl;
+  // Check for field STOP marker and break
+  indent(out) <<
+    "if " << t <<" == T_STOP then return rec else" << endl;
+  indent_up(); // if
+  indent(out) << "case " << id<<" of " << endl;
+  indent_up(); // case
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << (*f_iter)->get_key() << " -> ";
+    out << "if " << t <<" == " << type_to_enum((*f_iter)->get_type()) << " then do" << endl;
+    indent_up(); // if
+    indent(out) << "s <- ";
+    generate_deserialize_field(out, *f_iter,str);
+    out << endl;
+    indent(out) << "read_"<<sname<<"_fields iprot rec{f_"<<sname<<"_"<< decapitalize((*f_iter)->get_name()) <<"=Just s}" << endl;
+    out <<
+      indent() << "else do" << endl;
+    indent_up();
+    indent(out) << "skip iprot "<< t << endl;
+    indent(out) << "read_"<<sname<<"_fields iprot rec" << endl;
+    indent_down(); // -do
+    indent_down(); // -if
+  }
+
+
+  // In the default case we skip the field
+  out <<
+    indent() << "_ -> do" << endl;
+  indent_up();
+  indent(out) << "skip iprot "<<t<< endl;
+  indent(out) << "readFieldEnd iprot" << endl;
+  indent(out) << "read_"<<sname<<"_fields iprot rec" << endl;
+  indent_down(); // -case
+  indent_down(); // -if
+  indent_down(); // -do
+  indent_down();
+
+  // read
+  indent(out) << "read_"<<sname<<" iprot = do" << endl;
+  indent_up();
+  indent(out) << "readStructBegin iprot" << endl;
+  indent(out) << "rec <- read_"<<sname<<"_fields iprot ("<<sname<<"{";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if(first)
+      first=false;
+    else
+      out << ",";
+    out << "f_" << sname << "_" << decapitalize((*f_iter)->get_name()) << "=Nothing";
+  }
+  out << "})" << endl;
+  indent(out) << "readStructEnd iprot" << endl;
+  indent(out) << "return rec" << endl;
+  indent_down();
+}
+
+void t_hs_generator::generate_hs_struct_writer(ofstream& out,
+                                               t_struct* tstruct) {
+  string name = type_name(tstruct);
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+  string str = tmp("_str");
+  string f = tmp("_f");
+
+  indent(out) <<
+    "write_"<<name<<" oprot rec = do" << endl;
+  indent_up();
+  indent(out) <<
+    "writeStructBegin oprot \""<<name<<"\"" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    // Write field header
+    string mname = (*f_iter)->get_name();
+    indent(out) <<
+      "case f_" << name << "_" << mname << " rec of {Nothing -> return (); Just _v -> do" << endl;
+    indent_up();
+    indent(out) << "writeFieldBegin oprot (\""<< (*f_iter)->get_name()<<"\","
+                <<type_to_enum((*f_iter)->get_type())<<","
+                <<(*f_iter)->get_key()<<")" << endl;
+
+    // Write field contents
+    out << indent();
+    generate_serialize_field(out, *f_iter, "_v");
+    out << endl;
+    // Write field closer
+    indent(out) << "writeFieldEnd oprot}" << endl;
+    indent_down();
+  }
+
+  // Write the struct map
+  out <<
+    indent() << "writeFieldStop oprot" << endl <<
+    indent() << "writeStructEnd oprot" << endl;
+
+  indent_down();
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_hs_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_out_dir()+capitalize(service_name_)+".hs";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    hs_autogen_comment() << endl <<
+    "module " << capitalize(service_name_) << " where" << endl <<
+    hs_imports() << endl;
+
+
+  if(tservice->get_extends()){
+    f_service_ <<
+      "import qualified " << capitalize(tservice->get_extends()->get_name()) << endl;
+  }
+
+
+  f_service_ <<
+     "import " << capitalize(program_name_) << "_Types" << endl <<
+    "import qualified " << capitalize(service_name_) << "_Iface as Iface" << endl;
+
+
+  // Generate the three main parts of the service
+  generate_service_helpers(tservice);
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+
+
+  // Close service file
+  f_service_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_hs_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;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_hs_struct_definition(f_service_,ts, false);
+    generate_hs_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_hs_generator::generate_hs_function_helpers(t_function* tfunction) {
+  t_struct result(program_, decapitalize(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_hs_struct_definition(f_service_,&result, false);
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_hs_generator::generate_service_interface(t_service* tservice) {
+  string f_iface_name = get_out_dir()+capitalize(service_name_)+"_Iface.hs";
+  f_iface_.open(f_iface_name.c_str());
+  indent(f_iface_) << "module " << capitalize(service_name_) << "_Iface where" << endl;
+
+  indent(f_iface_) <<
+    hs_imports() << endl <<
+    "import " << capitalize(program_name_) << "_Types" << endl <<
+    endl;
+
+  if (tservice->get_extends() != NULL) {
+    string extends = type_name(tservice->get_extends());
+    indent(f_iface_) << "import " << extends <<"_Iface" << endl;
+    indent(f_iface_) << "class "<< extends << "_Iface a => " << capitalize(service_name_) << "_Iface a where" << endl;
+  } else {
+    f_iface_ << indent() << "class " << capitalize(service_name_) << "_Iface a where" << endl;
+  }
+  indent_up();
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string ft = function_type(*f_iter,true,true,true);
+    f_iface_ <<
+      indent() << decapitalize((*f_iter)->get_name()) << " :: a -> " << ft  << endl;
+  }
+  indent_down();
+  f_iface_.close();
+
+}
+
+/**
+ * Generates a service client definition. Note that in Haskell, the client doesn't implement iface. This is because
+ * The client does not (and should not have to) deal with arguments being Nothing.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_hs_generator::generate_service_client(t_service* tservice) {
+  string f_client_name = get_out_dir()+capitalize(service_name_)+"_Client.hs";
+  f_client_.open(f_client_name.c_str());
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+
+  string extends = "";
+  string exports="";
+  bool first = true;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    if(first)
+      first=false;
+    else
+      exports+=",";
+    string funname = (*f_iter)->get_name();
+    exports+=funname;
+  }
+  indent(f_client_) << "module " << capitalize(service_name_) << "_Client("<<exports<<") where" << endl;
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    indent(f_client_) << "import " << extends << "_Client" << endl;
+  }
+  indent(f_client_) << "import Data.IORef" << endl;
+  indent(f_client_) << hs_imports() << endl;
+  indent(f_client_) << "import " << capitalize(program_name_) << "_Types" << endl;
+  indent(f_client_) << "import " << capitalize(service_name_) << endl;
+  // DATS RITE A GLOBAL VAR
+  indent(f_client_) << "seqid = newIORef 0" << endl;
+
+
+  // Generate client method implementations
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string funname = (*f_iter)->get_name();
+
+    string fargs = "";
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      fargs+= " arg_" + decapitalize((*fld_iter)->get_name());
+    }
+
+    // Open function
+    indent(f_client_) << funname << " (ip,op)" <<  fargs << " = do" << endl;
+    indent_up();
+    indent(f_client_) <<  "send_" << funname << " op" << fargs;
+
+    f_client_ << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_client_ << indent();
+      f_client_ <<
+        "recv_" << funname << " ip" << endl;
+    }
+    indent_down();
+
+    indent(f_client_) <<
+      "send_" << funname << " op" << fargs << " = do" << endl;
+    indent_up();
+    indent(f_client_) << "seq <- seqid" << endl;
+    indent(f_client_) << "seqn <- readIORef seq" << endl;
+    std::string argsname = capitalize((*f_iter)->get_name() + "_args");
+
+    // Serialize the request header
+    f_client_ <<
+      indent() << "writeMessageBegin op (\"" << (*f_iter)->get_name() << "\", M_CALL, seqn)" << endl;
+    f_client_ << indent() << "write_" << argsname << " op ("<<argsname<<"{";
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if(first)
+        first=false;
+      else
+        f_client_ << ",";
+      f_client_ << "f_" << argsname <<"_" << (*fld_iter)->get_name() << "=Just arg_" << (*fld_iter)->get_name();
+    }
+    f_client_ << "})" << endl;
+
+    // Write to the stream
+    f_client_ <<
+      indent() << "writeMessageEnd op" << endl <<
+      indent() << "tFlush (getTransport op)" << endl;
+
+    indent_down();
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = capitalize((*f_iter)->get_name() + "_result");
+      t_struct noargs(program_);
+
+      std::string funname = string("recv_") + (*f_iter)->get_name();
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               funname,
+                               &noargs);
+      // Open function
+      f_client_ <<
+        indent() << funname << " ip = do" << endl;
+      indent_up(); // fun
+
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+
+      f_client_ <<
+        indent() << "(fname, mtype, rseqid) <- readMessageBegin ip" << endl;
+      f_client_ <<
+        indent() << "if mtype == M_EXCEPTION then do" << endl <<
+        indent() << "  x <- readAppExn ip" << endl <<
+        indent() << "  readMessageEnd ip" << endl;
+      f_client_ <<
+        indent() << "  throw x" << endl;
+      f_client_ <<
+        indent() << "  else return ()" << endl;
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+
+      f_client_ <<
+        indent() << "res <- read_" << resultname << " ip" << endl;
+      f_client_ <<
+        indent() << "readMessageEnd ip" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_client_ <<
+          indent() << "case f_" << resultname << "_success res of" << endl;
+        indent_up(); // case
+        indent(f_client_) << "Just v -> return v" << endl;
+        indent(f_client_) << "Nothing -> do" << endl;
+        indent_up(); // none
+      }
+
+
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_client_ <<
+          indent() << "case f_"<< resultname << "_" << (*x_iter)->get_name() << " res of" << endl;
+        indent_up(); //case
+        indent(f_client_) << "Nothing -> return ()" << endl;
+        indent(f_client_) << "Just _v -> throw _v" << endl;
+        indent_down(); //-case
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_client_) <<
+          "return ()" << endl;
+      } else {
+        f_client_ <<
+          indent() << "throw (AppExn AE_MISSING_RESULT \"" << (*f_iter)->get_name() << " failed: unknown result\")" << endl;
+        indent_down(); //-none
+        indent_down(); //-case
+      }
+
+      // Close function
+      indent_down(); //-fun
+    }
+  }
+  f_client_.close();
+
+
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_hs_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+
+  indent(f_service_) << "proc handler (iprot,oprot) (name,typ,seqid) = case name of" << endl;
+  indent_up();
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string fname = (*f_iter)->get_name();
+    indent(f_service_) << "\""<<fname<<"\" -> process_" << decapitalize(fname) << " (seqid,iprot,oprot,handler)" << endl;
+  }
+  indent(f_service_) << "_ -> ";
+  if(tservice->get_extends() != NULL){
+    f_service_ << type_name(tservice->get_extends()) << ".proc handler (iprot,oprot) (name,typ,seqid)" << endl;
+  } else {
+    f_service_ << "do" << endl;
+    indent_up();
+    indent(f_service_) << "skip iprot T_STRUCT" << endl;
+    indent(f_service_) << "readMessageEnd iprot" << endl;
+    indent(f_service_) << "writeMessageBegin oprot (name,M_EXCEPTION,seqid)" << endl;
+    indent(f_service_) << "writeAppExn oprot (AppExn AE_UNKNOWN_METHOD (\"Unknown function \" ++ name))" << endl;
+    indent(f_service_) << "writeMessageEnd oprot" << endl;
+    indent(f_service_) << "tFlush (getTransport oprot)" << endl;
+    indent_down();
+  }
+  indent_down();
+
+  // Generate the server implementation
+  indent(f_service_) <<
+    "process handler (iprot, oprot) = do" << endl;
+  indent_up();
+
+  f_service_ <<
+    indent() << "(name, typ, seqid) <- readMessageBegin iprot" << endl;
+  f_service_ << indent() << "proc handler (iprot,oprot) (name,typ,seqid)" << endl;
+  indent(f_service_) << "return True" << endl;
+  indent_down();
+
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_hs_generator::generate_process_function(t_service* tservice,
+                                               t_function* tfunction) {
+  // Open function
+  indent(f_service_) <<
+    "process_" << tfunction->get_name() << " (seqid, iprot, oprot, handler) = do" << endl;
+  indent_up();
+
+  string argsname = capitalize(tfunction->get_name()) + "_args";
+  string resultname = capitalize(tfunction->get_name()) + "_result";
+
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+
+  f_service_ <<
+    indent() << "args <- read_" << argsname << " iprot" << endl;
+  f_service_ <<
+    indent() << "readMessageEnd iprot" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+  int n = xceptions.size();
+  if (!tfunction->is_oneway()){
+    if(!tfunction->get_returntype()->is_void()){
+      n++;
+    }
+    indent(f_service_) << "rs <- return (" << resultname;
+
+    for(int i=0; i<n;i++){
+      f_service_ << " Nothing";
+    }
+    f_service_ << ")" << endl;
+  }
+
+  indent(f_service_) << "res <- ";
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    for(unsigned int i=0;i<xceptions.size();i++){
+      f_service_ << "(Control.Exception.catch" << endl;
+      indent_up();
+      f_service_ << indent();
+    }
+  }
+
+  f_service_ << "(do" << endl;
+  indent_up();
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()){
+    f_service_ << "res <- ";
+  }
+  f_service_ << "Iface." << tfunction->get_name() << " handler";
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    f_service_ <<  " (f_" << argsname <<  "_" << (*f_iter)->get_name() << " args)";
+  }
+
+
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()){
+    f_service_ << endl;
+    indent(f_service_) << "return rs{f_"<<resultname<<"_success= Just res}";
+  } else if (!tfunction->is_oneway()){
+    f_service_ << endl;
+    indent(f_service_) << "return rs";
+  }
+  f_service_ << ")" << endl;
+  indent_down();
+
+  if (xceptions.size() > 0 && !tfunction->is_oneway()) {
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      indent(f_service_) << "(\\e  -> " <<endl;
+      indent_up();
+      if(!tfunction->is_oneway()){
+        f_service_ <<
+          indent() << "return rs{f_"<<resultname<<"_" << (*x_iter)->get_name() << " =Just e}";
+      } else {
+        indent(f_service_) << "return ()";
+      }
+      f_service_ << "))" << endl;
+      indent_down();
+      indent_down();
+    }
+  }
+
+
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "return ()" << endl;
+    indent_down();
+    return;
+  }
+
+  f_service_ <<
+    indent() << "writeMessageBegin oprot (\"" << tfunction->get_name() << "\", M_REPLY, seqid);" << endl <<
+    indent() << "write_"<<resultname<<" oprot res" << endl <<
+    indent() << "writeMessageEnd oprot" << endl <<
+    indent() << "tFlush (getTransport oprot)" << endl;
+
+  // Close function
+  indent_down();
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_hs_generator::generate_deserialize_field(ofstream &out,
+                                                   t_field* tfield,
+                                                   string prefix){
+  t_type* type = tfield->get_type();
+  generate_deserialize_type(out,type);
+}
+
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_hs_generator::generate_deserialize_type(ofstream &out,
+                                                   t_type* type){
+  type = get_true_type(type);
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE";
+  }
+
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type);
+  } else 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";
+      break;
+    case t_base_type::TYPE_STRING:
+      out << "readString";
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "readBool";
+      break;
+    case t_base_type::TYPE_BYTE:
+      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 PHP name for base type " + t_base_type::t_base_name(tbase);
+    }
+    out << " iprot";
+  } else if (type->is_enum()) {
+    string ename = capitalize(type->get_name());
+    out << "(do {i <- readI32 iprot; return (toEnum i :: " << ename << ")})";
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n",
+           type->get_name().c_str());
+  }
+}
+
+
+/**
+ * Generates an unserializer for a struct, calling read()
+ */
+void t_hs_generator::generate_deserialize_struct(ofstream &out,
+                                                  t_struct* tstruct) {
+  string name = capitalize(tstruct->get_name());
+  out << "(read_" << name << " iprot)";
+
+}
+
+/**
+ * Serialize a container by writing out the header followed by
+ * data and then a footer.
+ */
+void t_hs_generator::generate_deserialize_container(ofstream &out,
+                                                    t_type* ttype) {
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+  string con = tmp("_con");
+
+  t_field fsize(g_type_i32, size);
+  t_field fktype(g_type_byte, ktype);
+  t_field fvtype(g_type_byte, vtype);
+  t_field fetype(g_type_byte, etype);
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out << "(let {f 0 = return []; f n = do {k <- ";
+    generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
+    out << "; v <- ";
+    generate_deserialize_type(out,((t_map*)ttype)->get_val_type());
+    out << ";r <- f (n-1); return $ (k,v):r}} in do {("<<ktype<<","<<vtype<<","<<size<<") <- readMapBegin iprot; l <- f " << size << "; return $ Map.fromList l})";
+  } else if (ttype->is_set()) {
+    out << "(let {f 0 = return []; f n = do {v <- ";
+    generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
+    out << ";r <- f (n-1); return $ v:r}} in do {("<<etype<<","<<size<<") <- readSetBegin iprot; l <- f " << size << "; return $ Set.fromList l})";
+  } else if (ttype->is_list()) {
+    out << "(let {f 0 = return []; f n = do {v <- ";
+    generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
+    out << ";r <- f (n-1); return $ v:r}} in do {("<<etype<<","<<size<<") <- readListBegin iprot; f " << size << "})";
+  }
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_hs_generator::generate_serialize_field(ofstream &out,
+                                                 t_field* tfield,
+                                                 string name) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      tfield->get_name();
+  }
+
+  if(name.length() == 0){
+    name = decapitalize(tfield->get_name());
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out,
+                              (t_struct*)type,
+                              name);
+  } else if (type->is_container()) {
+    generate_serialize_container(out,
+                                 type,
+                                 name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    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:
+        out << "writeString oprot " << name;
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool oprot " << name;
+       break;
+      case t_base_type::TYPE_BYTE:
+        out << "writeByte oprot " << name;
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16 oprot " << name;
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32 oprot " << name;
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64 oprot " << name;
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble oprot " << name;
+        break;
+      default:
+        throw "compiler error: no hs name for base type " + t_base_type::t_base_name(tbase);
+      }
+
+    } else if (type->is_enum()) {
+      string ename = capitalize(type->get_name());
+      out << "writeI32 oprot (fromEnum "<< name << ")";
+    }
+
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_hs_generator::generate_serialize_struct(ofstream &out,
+                                               t_struct* tstruct,
+                                               string prefix) {
+  out << "write_" << type_name(tstruct) << " oprot " << prefix;
+}
+
+void t_hs_generator::generate_serialize_container(ofstream &out,
+                                                  t_type* ttype,
+                                                  string prefix) {
+  if (ttype->is_map()) {
+    string k = tmp("_kiter");
+    string v = tmp("_viter");
+    out << "(let {f [] = return (); f (("<<k<<","<<v<<"):t) = do {";
+    generate_serialize_map_element(out, (t_map*)ttype, k, v);
+    out << ";f t}} in do {writeMapBegin oprot ("<< type_to_enum(((t_map*)ttype)->get_key_type())<<","<< type_to_enum(((t_map*)ttype)->get_val_type())<<",Map.size " << prefix << "); f (Map.toList " << prefix << ");writeMapEnd oprot})";
+  } else if (ttype->is_set()) {
+    string v = tmp("_viter");
+    out << "(let {f [] = return (); f ("<<v<<":t) = do {";
+    generate_serialize_set_element(out, (t_set*)ttype, v);
+    out << ";f t}} in do {writeSetBegin oprot ("<< type_to_enum(((t_set*)ttype)->get_elem_type())<<",Set.size " << prefix << "); f (Set.toList " << prefix << ");writeSetEnd oprot})";
+  } else if (ttype->is_list()) {
+    string v = tmp("_viter");
+    out << "(let {f [] = return (); f ("<<v<<":t) = do {";
+    generate_serialize_list_element(out, (t_list*)ttype, v);
+    out << ";f t}} in do {writeListBegin oprot ("<< type_to_enum(((t_list*)ttype)->get_elem_type())<<",length " << prefix << "); f " << prefix << ";writeListEnd oprot})";
+  }
+
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_hs_generator::generate_serialize_map_element(ofstream &out,
+                                                     t_map* tmap,
+                                                     string kiter,
+                                                     string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  out << "do {";
+  generate_serialize_field(out, &kfield);
+  out << ";";
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield);
+  out << "}";
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_hs_generator::generate_serialize_set_element(ofstream &out,
+                                                     t_set* tset,
+                                                     string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_hs_generator::generate_serialize_list_element(ofstream &out,
+                                                      t_list* tlist,
+                                                      string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+
+string t_hs_generator::function_type(t_function* tfunc, bool options, bool io, bool method){
+  string result="";
+
+  const vector<t_field*>& fields = tfunc->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if(options) result += "Maybe ";
+    result += render_hs_type((*f_iter)->get_type(), options);
+    result += " -> ";
+  }
+  if(fields.empty() && !method){
+    result += "() -> ";
+  }
+  if(io) result += "IO ";
+  result += render_hs_type(tfunc->get_returntype(), io);
+  return result;
+}
+
+
+string t_hs_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    if (!ttype->is_service()) {
+      prefix = capitalize(program->get_name()) + "_Types.";
+    }
+  }
+
+  string name = ttype->get_name();
+  if(ttype->is_service()){
+    name = capitalize(name);
+  } else {
+    name = capitalize(name);
+  }
+  return prefix + name;
+}
+
+/**
+ * Converts the parse type to a Protocol.t_type enum
+ */
+string t_hs_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:
+      return "T_VOID";
+    case t_base_type::TYPE_STRING:
+      return "T_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "T_BOOL";
+    case t_base_type::TYPE_BYTE:
+      return "T_BYTE";
+    case t_base_type::TYPE_I16:
+      return "T_I16";
+    case t_base_type::TYPE_I32:
+      return "T_I32";
+    case t_base_type::TYPE_I64:
+      return "T_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "T_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "T_I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "T_STRUCT";
+  } else if (type->is_map()) {
+    return "T_MAP";
+  } else if (type->is_set()) {
+    return "T_SET";
+  } else if (type->is_list()) {
+    return "T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Converts the parse type to an haskell type
+ */
+string t_hs_generator::render_hs_type(t_type* type, bool needs_parens) {
+  type = get_true_type(type);
+  string type_repr;
+
+  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 "()";
+    case t_base_type::TYPE_STRING:
+      return "String";
+    case t_base_type::TYPE_BOOL:
+      return "Bool";
+    case t_base_type::TYPE_BYTE:
+      return "Int";
+    case t_base_type::TYPE_I16:
+      return "Int";
+    case t_base_type::TYPE_I32:
+      return "Int";
+    case t_base_type::TYPE_I64:
+      return "Int64";
+    case t_base_type::TYPE_DOUBLE:
+      return "Double";
+    }
+  } else if (type->is_enum()) {
+    return capitalize(((t_enum*)type)->get_name());
+  } else if (type->is_struct() || type->is_xception()) {
+    return type_name((t_struct*)type);
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+
+    type_repr = "Map.Map " + render_hs_type(ktype, true) + " " + render_hs_type(vtype, true);
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+
+    type_repr = "Set.Set " + render_hs_type(etype, true) ;
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    return "[" + render_hs_type(etype, false) + "]";
+  } else {
+    throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+  }
+
+  return needs_parens ? "(" + type_repr + ")" : type_repr;
+}
+
+
+THRIFT_REGISTER_GENERATOR(hs, "Haskell", "");
diff --git a/compiler/cpp/src/generate/t_html_generator.cc b/compiler/cpp/src/generate/t_html_generator.cc
new file mode 100644
index 0000000..ad1c4cb
--- /dev/null
+++ b/compiler/cpp/src/generate/t_html_generator.cc
@@ -0,0 +1,637 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <map>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "t_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * HTML code generator
+ *
+ * mostly copy/pasting/tweaking from mcslee's work.
+ */
+class t_html_generator : public t_generator {
+ public:
+  t_html_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_generator(program)
+  {
+    out_dir_base_ = "gen-html";
+    escape_.clear();
+    escape_['&']  = "&amp;";
+    escape_['<']  = "&lt;";
+    escape_['>']  = "&gt;";
+    escape_['"']  = "&quot;";
+    escape_['\''] = "&apos;";
+  }
+
+  void generate_program();
+  void generate_program_toc();
+  void generate_program_toc_row(t_program* tprog);
+  void generate_program_toc_rows(t_program* tprog,
+				 std::vector<t_program*>& finished);
+  void generate_index();
+  void generate_css();
+
+  /**
+   * 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_service (t_service*  tservice);
+  void generate_xception(t_struct*   txception);
+
+  void print_doc        (t_doc* tdoc);
+  int  print_type       (t_type* ttype);
+  void print_const_value(t_const_value* tvalue);
+
+  std::ofstream f_out_;
+};
+
+/**
+ * Emits the Table of Contents links at the top of the module's page
+ */
+void t_html_generator::generate_program_toc() {
+  f_out_ << "<table><tr><th>Module</th><th>Services</th>"
+	 << "<th>Data types</th><th>Constants</th></tr>" << endl;
+  generate_program_toc_row(program_);
+  f_out_ << "</table>" << endl;
+}
+
+
+/**
+ * Recurses through from the provided program and generates a ToC row
+ * for each discovered program exactly once by maintaining the list of
+ * completed rows in 'finished'
+ */
+void t_html_generator::generate_program_toc_rows(t_program* tprog,
+				 std::vector<t_program*>& finished) {
+  for (vector<t_program*>::iterator iter = finished.begin();
+       iter != finished.end(); iter++) {
+    if (tprog->get_path() == (*iter)->get_path()) {
+      return;
+    }
+  }
+  finished.push_back(tprog);
+  generate_program_toc_row(tprog);
+  vector<t_program*> includes = tprog->get_includes();
+  for (vector<t_program*>::iterator iter = includes.begin();
+       iter != includes.end(); iter++) {
+    generate_program_toc_rows(*iter, finished);
+  }
+}
+
+/**
+ * Emits the Table of Contents links at the top of the module's page
+ */
+void t_html_generator::generate_program_toc_row(t_program* tprog) {
+  string fname = tprog->get_name() + ".html";
+  f_out_ << "<tr>" << endl << "<td>" << tprog->get_name() << "</td><td>";
+  if (!tprog->get_services().empty()) {
+    vector<t_service*> services = tprog->get_services();
+    vector<t_service*>::iterator sv_iter;
+    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+      string name = get_service_name(*sv_iter);
+      f_out_ << "<a href=\"" << fname << "#Svc_" << name << "\">" << name
+	     << "</a><br/>" << endl;
+      f_out_ << "<ul>" << endl;
+      map<string,string> fn_html;
+      vector<t_function*> functions = (*sv_iter)->get_functions();
+      vector<t_function*>::iterator fn_iter;
+      for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) {
+	string fn_name = (*fn_iter)->get_name();
+	string html = "<li><a href=\"" + fname + "#Fn_" + name + "_" +
+	  fn_name + "\">" + fn_name + "</a></li>";
+	fn_html.insert(pair<string,string>(fn_name, html));
+      }
+      for (map<string,string>::iterator html_iter = fn_html.begin();
+	   html_iter != fn_html.end(); html_iter++) {
+	f_out_ << html_iter->second << endl;
+      }
+      f_out_ << "</ul>" << endl;
+    }
+  }
+  f_out_ << "</td>" << endl << "<td>";
+  map<string,string> data_types;
+  if (!tprog->get_enums().empty()) {
+    vector<t_enum*> enums = tprog->get_enums();
+    vector<t_enum*>::iterator en_iter;
+    for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+      string name = (*en_iter)->get_name();
+      // f_out_ << "<a href=\"" << fname << "#Enum_" << name << "\">" << name
+      // <<  "</a><br/>" << endl;
+      string html = "<a href=\"" + fname + "#Enum_" + name + "\">" + name +
+	"</a>";
+      data_types.insert(pair<string,string>(name, html));
+    }
+  }
+  if (!tprog->get_typedefs().empty()) {
+    vector<t_typedef*> typedefs = tprog->get_typedefs();
+    vector<t_typedef*>::iterator td_iter;
+    for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+      string name = (*td_iter)->get_symbolic();
+      // f_out_ << "<a href=\"" << fname << "#Typedef_" << name << "\">" << name
+      // << "</a><br/>" << endl;
+      string html = "<a href=\"" + fname + "#Typedef_" + name + "\">" + name +
+	"</a>";
+      data_types.insert(pair<string,string>(name, html));
+    }
+  }
+  if (!tprog->get_objects().empty()) {
+    vector<t_struct*> objects = tprog->get_objects();
+    vector<t_struct*>::iterator o_iter;
+    for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+      string name = (*o_iter)->get_name();
+      //f_out_ << "<a href=\"" << fname << "#Struct_" << name << "\">" << name
+      //<< "</a><br/>" << endl;
+      string html = "<a href=\"" + fname + "#Struct_" + name + "\">" + name +
+	"</a>";
+      data_types.insert(pair<string,string>(name, html));
+    }
+  }
+  for (map<string,string>::iterator dt_iter = data_types.begin();
+       dt_iter != data_types.end(); dt_iter++) {
+    f_out_ << dt_iter->second << "<br/>" << endl;
+  }
+  f_out_ << "</td>" << endl << "<td><code>";
+  if (!tprog->get_consts().empty()) {
+    map<string,string> const_html;
+    vector<t_const*> consts = tprog->get_consts();
+    vector<t_const*>::iterator con_iter;
+    for (con_iter = consts.begin(); con_iter != consts.end(); ++con_iter) {
+      string name = (*con_iter)->get_name();
+      string html ="<a href=\"" + fname + "#Const_" + name +
+	"\">" + name + "</a>";
+      const_html.insert(pair<string,string>(name, html));
+    }
+    for (map<string,string>::iterator con_iter = const_html.begin();
+	 con_iter != const_html.end(); con_iter++) {
+      f_out_ << con_iter->second << "<br/>" << endl;
+    }
+  }
+  f_out_ << "</code></td>" << endl << "</tr>";
+}
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * stream.
+ */
+void t_html_generator::generate_program() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  string fname = get_out_dir() + program_->get_name() + ".html";
+  f_out_.open(fname.c_str());
+  f_out_ << "<html><head>" << endl;
+  f_out_ << "<link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\"/>"
+	 << endl;
+  f_out_ << "<title>Thrift module: " << program_->get_name()
+	 << "</title></head><body>" << endl << "<h1>Thrift module: "
+	 << program_->get_name() << "</h1>" << endl;
+
+  print_doc(program_);
+
+  generate_program_toc();
+
+  if (!program_->get_consts().empty()) {
+    f_out_ << "<hr/><h2 id=\"Constants\">Constants</h2>" << endl;
+    vector<t_const*> consts = program_->get_consts();
+    f_out_ << "<table>";
+    f_out_ << "<tr><th>Constant</th><th>Type</th><th>Value</th></tr>" << endl;
+    generate_consts(consts);
+    f_out_ << "</table>";
+  }
+
+  if (!program_->get_enums().empty()) {
+    f_out_ << "<hr/><h2 id=\"Enumerations\">Enumerations</h2>" << endl;
+    // Generate enums
+    vector<t_enum*> enums = program_->get_enums();
+    vector<t_enum*>::iterator en_iter;
+    for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+      generate_enum(*en_iter);
+    }
+  }
+
+  if (!program_->get_typedefs().empty()) {
+    f_out_ << "<hr/><h2 id=\"Typedefs\">Type declarations</h2>" << endl;
+    // Generate typedefs
+    vector<t_typedef*> typedefs = program_->get_typedefs();
+    vector<t_typedef*>::iterator td_iter;
+    for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+      generate_typedef(*td_iter);
+    }
+  }
+
+  if (!program_->get_objects().empty()) {
+    f_out_ << "<hr/><h2 id=\"Structs\">Data structures</h2>" << endl;
+    // Generate structs and exceptions in declared order
+    vector<t_struct*> objects = program_->get_objects();
+    vector<t_struct*>::iterator o_iter;
+    for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+      if ((*o_iter)->is_xception()) {
+	generate_xception(*o_iter);
+      } else {
+	generate_struct(*o_iter);
+      }
+    }
+  }
+
+  if (!program_->get_services().empty()) {
+    f_out_ << "<hr/><h2 id=\"Services\">Services</h2>" << endl;
+    // Generate services
+    vector<t_service*> services = program_->get_services();
+    vector<t_service*>::iterator sv_iter;
+    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+      service_name_ = get_service_name(*sv_iter);
+      generate_service(*sv_iter);
+    }
+  }
+
+  f_out_ << "</body></html>" << endl;
+  f_out_.close();
+
+  generate_index();
+  generate_css();
+}
+
+/**
+ * Emits the index.html file for the recursive set of Thrift programs
+ */
+void t_html_generator::generate_index() {
+  string index_fname = get_out_dir() + "index.html";
+  f_out_.open(index_fname.c_str());
+  f_out_ << "<html><head>" << endl;
+  f_out_ << "<link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\"/>"
+	 << endl;
+  f_out_ << "<title>All Thrift declarations</title></head><body>"
+	 << endl << "<h1>All Thrift declarations</h1>" << endl;
+  f_out_ << "<table><tr><th>Module</th><th>Services</th><th>Data types</th>"
+	 << "<th>Constants</th></tr>" << endl;
+  vector<t_program*> programs;
+  generate_program_toc_rows(program_, programs);
+  f_out_ << "</table>" << endl;
+  f_out_ << "</body></html>" << endl;
+  f_out_.close();
+}
+
+void t_html_generator::generate_css() {
+  string css_fname = get_out_dir() + "style.css";
+  f_out_.open(css_fname.c_str());
+  f_out_ << "/* Auto-generated CSS for generated Thrift docs */" << endl;
+  f_out_ <<
+    "body { font-family: Tahoma, sans-serif; }" << endl;
+  f_out_ <<
+    "pre { background-color: #dddddd; padding: 6px; }" << endl;
+  f_out_ <<
+    "h3,h4 { padding-top: 0px; margin-top: 0px; }" << endl;
+  f_out_ <<
+    "div.definition { border: 1px solid gray; margin: 10px; padding: 10px; }" << endl;
+  f_out_ <<
+    "div.extends { margin: -0.5em 0 1em 5em }" << endl;
+  f_out_ <<
+    "table { border: 1px solid grey; border-collapse: collapse; }" << endl;
+  f_out_ <<
+    "td { border: 1px solid grey; padding: 1px 6px; vertical-align: top; }" << endl;
+  f_out_ <<
+    "th { border: 1px solid black; background-color: #bbbbbb;" << endl <<
+    "     text-align: left; padding: 1px 6px; }" << endl;
+  f_out_.close();
+}
+
+/**
+ * If the provided documentable object has documentation attached, this
+ * will emit it to the output stream in HTML format.
+ */
+void t_html_generator::print_doc(t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    string doc = tdoc->get_doc();
+    size_t index;
+    while ((index = doc.find_first_of("\r\n")) != string::npos) {
+      if (index == 0) {
+	f_out_ << "<p/>" << endl;
+      } else {
+	f_out_ << doc.substr(0, index) << endl;
+      }
+      if (index + 1 < doc.size() && doc.at(index) != doc.at(index + 1) &&
+	  (doc.at(index + 1) == '\r' || doc.at(index + 1) == '\n')) {
+	index++;
+      }
+      doc = doc.substr(index + 1);
+    }
+    f_out_ << doc << "<br/>";
+  }
+}
+
+/**
+ * Prints out the provided type in HTML
+ */
+int t_html_generator::print_type(t_type* ttype) {
+  int len = 0;
+  f_out_ << "<code>";
+  if (ttype->is_container()) {
+    if (ttype->is_list()) {
+      f_out_ << "list&lt;";
+      len = 6 + print_type(((t_list*)ttype)->get_elem_type());
+      f_out_ << "&gt;";
+    } else if (ttype->is_set()) {
+      f_out_ << "set&lt;";
+      len = 5 + print_type(((t_set*)ttype)->get_elem_type());
+      f_out_ << "&gt;";
+    } else if (ttype->is_map()) {
+      f_out_ << "map&lt;";
+      len = 5 + print_type(((t_map*)ttype)->get_key_type());
+      f_out_ << ", ";
+      len += print_type(((t_map*)ttype)->get_val_type());
+      f_out_ << "&gt;";
+    }
+  } else if (ttype->is_base_type()) {
+    f_out_ << ttype->get_name();
+    len = ttype->get_name().size();
+  } else {
+    string prog_name = ttype->get_program()->get_name();
+    string type_name = ttype->get_name();
+    f_out_ << "<a href=\"" << prog_name << ".html#";
+    if (ttype->is_typedef()) {
+      f_out_ << "Typedef_";
+    } else if (ttype->is_struct() || ttype->is_xception()) {
+      f_out_ << "Struct_";
+    } else if (ttype->is_enum()) {
+      f_out_ << "Enum_";
+    } else if (ttype->is_service()) {
+      f_out_ << "Svc_";
+    }
+    f_out_ << type_name << "\">";
+    len = type_name.size();
+    if (ttype->get_program() != program_) {
+      f_out_ << prog_name << ".";
+      len += prog_name.size() + 1;
+    }
+    f_out_ << type_name << "</a>";
+  }
+  f_out_ << "</code>";
+  return len;
+}
+
+/**
+ * Prints out an HTML representation of the provided constant value
+ */
+void t_html_generator::print_const_value(t_const_value* tvalue) {
+  bool first = true;
+  switch (tvalue->get_type()) {
+  case t_const_value::CV_INTEGER:
+    f_out_ << tvalue->get_integer();
+    break;
+  case t_const_value::CV_DOUBLE:
+    f_out_ << tvalue->get_double();
+    break;
+  case t_const_value::CV_STRING:
+    f_out_ << '"' << get_escaped_string(tvalue) << '"';
+    break;
+  case t_const_value::CV_MAP:
+    {
+      f_out_ << "{ ";
+      map<t_const_value*, t_const_value*> map_elems = tvalue->get_map();
+      map<t_const_value*, t_const_value*>::iterator map_iter;
+      for (map_iter = map_elems.begin(); map_iter != map_elems.end();
+	   map_iter++) {
+	if (!first) {
+	  f_out_ << ", ";
+	}
+	first = false;
+	print_const_value(map_iter->first);
+	f_out_ << " = ";
+	print_const_value(map_iter->second);
+      }
+      f_out_ << " }";
+    }
+    break;
+  case t_const_value::CV_LIST:
+    {
+      f_out_ << "{ ";
+      vector<t_const_value*> list_elems = tvalue->get_list();;
+      vector<t_const_value*>::iterator list_iter;
+      for (list_iter = list_elems.begin(); list_iter != list_elems.end();
+	   list_iter++) {
+	if (!first) {
+	  f_out_ << ", ";
+	}
+	first = false;
+	print_const_value(*list_iter);
+      }
+      f_out_ << " }";
+    }
+    break;
+  default:
+    f_out_ << "UNKNOWN";
+    break;
+  }
+}
+
+/**
+ * Generates a typedef.
+ *
+ * @param ttypedef The type definition
+ */
+void t_html_generator::generate_typedef(t_typedef* ttypedef) {
+  string name = ttypedef->get_name();
+  f_out_ << "<div class=\"definition\">";
+  f_out_ << "<h3 id=\"Typedef_" << name << "\">Typedef: " << name
+	 << "</h3>" << endl;
+  f_out_ << "<p><strong>Base type:</strong>&nbsp;";
+  print_type(ttypedef->get_type());
+  f_out_ << "</p>" << endl;
+  print_doc(ttypedef);
+  f_out_ << "</div>" << endl;
+}
+
+/**
+ * Generates code for an enumerated type.
+ *
+ * @param tenum The enumeration
+ */
+void t_html_generator::generate_enum(t_enum* tenum) {
+  string name = tenum->get_name();
+  f_out_ << "<div class=\"definition\">";
+  f_out_ << "<h3 id=\"Enum_" << name << "\">Enumeration: " << name
+	 << "</h3>" << endl;
+  print_doc(tenum);
+  vector<t_enum_value*> values = tenum->get_constants();
+  vector<t_enum_value*>::iterator val_iter;
+  f_out_ << "<br/><table>" << endl;
+  for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
+    f_out_ << "<tr><td><code>";
+    f_out_ << (*val_iter)->get_name();
+    f_out_ << "</code></td><td><code>";
+    f_out_ << (*val_iter)->get_value();
+    f_out_ << "</code></td></tr>" << endl;
+  }
+  f_out_ << "</table></div>" << endl;
+}
+
+/**
+ * Generates a constant value
+ */
+void t_html_generator::generate_const(t_const* tconst) {
+  string name = tconst->get_name();
+  f_out_ << "<tr id=\"Const_" << name << "\"><td><code>" << name
+	 << "</code></td><td><code>";
+  print_type(tconst->get_type());
+  f_out_ << "</code></td><td><code>";
+  print_const_value(tconst->get_value());
+  f_out_ << "</code></td></tr>";
+  if (tconst->has_doc()) {
+    f_out_ << "<tr><td colspan=\"3\"><blockquote>";
+    print_doc(tconst);
+    f_out_ << "</blockquote></td></tr>";
+  }
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_html_generator::generate_struct(t_struct* tstruct) {
+  string name = tstruct->get_name();
+  f_out_ << "<div class=\"definition\">";
+  f_out_ << "<h3 id=\"Struct_" << name << "\">";
+  if (tstruct->is_xception()) {
+    f_out_ << "Exception: ";
+  } else {
+    f_out_ << "Struct: ";
+  }
+  f_out_ << name << "</h3>" << endl;
+  vector<t_field*> members = tstruct->get_members();
+  vector<t_field*>::iterator mem_iter = members.begin();
+  f_out_ << "<table>";
+  f_out_ << "<tr><th>Field</th><th>Type</th><th>Required</th><th>Default value</th></tr>"
+	 << endl;
+  for ( ; mem_iter != members.end(); mem_iter++) {
+    f_out_ << "<tr><td>" << (*mem_iter)->get_name() << "</td><td>";
+    print_type((*mem_iter)->get_type());
+    f_out_ << "</td><td>";
+    if ((*mem_iter)->get_req() != t_field::T_OPTIONAL) {
+      f_out_ << "yes";
+    } else {
+      f_out_ << "no";
+    }
+    f_out_ << "</td><td>";
+    t_const_value* default_val = (*mem_iter)->get_value();
+    if (default_val != NULL) {
+      print_const_value(default_val);
+    }
+    f_out_ << "</td></tr>" << endl;
+  }
+  f_out_ << "</table><br/>";
+  print_doc(tstruct);
+  f_out_ << "</div>";
+}
+
+/**
+ * Exceptions are special structs
+ *
+ * @param tstruct The struct definition
+ */
+void t_html_generator::generate_xception(t_struct* txception) {
+  generate_struct(txception);
+}
+
+/**
+ * Generates the HTML block for a Thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_html_generator::generate_service(t_service* tservice) {
+  f_out_ << "<h3 id=\"Svc_" << service_name_ << "\">Service: "
+	 << service_name_ << "</h3>" << endl;
+
+  if (tservice->get_extends()) {
+    f_out_ << "<div class=\"extends\"><em>extends</em> ";
+    print_type(tservice->get_extends());
+    f_out_ << "</div>\n";
+  }
+  print_doc(tservice);
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator fn_iter = functions.begin();
+  for ( ; fn_iter != functions.end(); fn_iter++) {
+    string fn_name = (*fn_iter)->get_name();
+    f_out_ << "<div class=\"definition\">";
+    f_out_ << "<h4 id=\"Fn_" << service_name_ << "_" << fn_name
+	   << "\">Function: " << service_name_ << "." << fn_name
+	   << "</h4>" << endl;
+    f_out_ << "<pre>";
+    int offset = print_type((*fn_iter)->get_returntype());
+    bool first = true;
+    f_out_ << " " << fn_name << "(";
+    offset += fn_name.size() + 2;
+    vector<t_field*> args = (*fn_iter)->get_arglist()->get_members();
+    vector<t_field*>::iterator arg_iter = args.begin();
+    if (arg_iter != args.end()) {
+      for ( ; arg_iter != args.end(); arg_iter++) {
+	if (!first) {
+	  f_out_ << "," << endl;
+	  for (int i = 0; i < offset; ++i) {
+	    f_out_ << " ";
+	  }
+	}
+	first = false;
+	print_type((*arg_iter)->get_type());
+	f_out_ << " " << (*arg_iter)->get_name();
+	if ((*arg_iter)->get_value() != NULL) {
+	  f_out_ << " = ";
+	  print_const_value((*arg_iter)->get_value());
+	}
+      }
+    }
+    f_out_ << ")" << endl;
+    first = true;
+    vector<t_field*> excepts = (*fn_iter)->get_xceptions()->get_members();
+    vector<t_field*>::iterator ex_iter = excepts.begin();
+    if (ex_iter != excepts.end()) {
+      f_out_ << "    throws ";
+      for ( ; ex_iter != excepts.end(); ex_iter++) {
+	if (!first) {
+	  f_out_ << ", ";
+	}
+	first = false;
+	print_type((*ex_iter)->get_type());
+      }
+      f_out_ << endl;
+    }
+    f_out_ << "</pre>";
+    print_doc(*fn_iter);
+    f_out_ << "</div>";
+  }
+}
+
+THRIFT_REGISTER_GENERATOR(html, "HTML", "");
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
new file mode 100644
index 0000000..3ec816f
--- /dev/null
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -0,0 +1,3008 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <sys/stat.h>
+#include <stdexcept>
+
+#include "platform.h"
+#include "t_oop_generator.h"
+using namespace std;
+
+
+/**
+ * Java code generator.
+ *
+ */
+class t_java_generator : public t_oop_generator {
+ public:
+  t_java_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    std::map<std::string, std::string>::const_iterator iter;
+
+    iter = parsed_options.find("beans");
+    bean_style_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("nocamel");
+    nocamel_style_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("hashcode");
+    gen_hash_code_ = (iter != parsed_options.end());
+
+    out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java");
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef (t_typedef*  ttypedef);
+  void generate_enum    (t_enum*     tenum);
+  void generate_struct  (t_struct*   tstruct);
+  void generate_xception(t_struct*   txception);
+  void generate_service (t_service*  tservice);
+
+  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false);
+  std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_java_struct(t_struct* tstruct, bool is_exception);
+
+  void generate_java_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false);
+  void generate_java_struct_equality(std::ofstream& out, t_struct* tstruct);
+  void generate_java_struct_reader(std::ofstream& out, t_struct* tstruct);
+  void generate_java_validator(std::ofstream& out, t_struct* tstruct);
+  void generate_java_struct_result_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_java_struct_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_java_struct_tostring(std::ofstream& out, t_struct* tstruct);
+  void generate_java_meta_data_map(std::ofstream& out, t_struct* tstruct);
+  void generate_field_value_meta_data(std::ofstream& out, t_type* type);
+  std::string get_java_type_string(t_type* type);
+  void generate_reflection_setters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
+  void generate_reflection_getters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
+  void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct);
+  void generate_generic_isset_method(std::ofstream& out, t_struct* tstruct);
+  void generate_java_bean_boilerplate(std::ofstream& out, t_struct* tstruct);
+
+  void generate_function_helpers(t_function* tfunction);
+  std::string get_cap_name(std::string name);
+  std::string generate_isset_check(t_field* field);
+  std::string generate_isset_check(std::string field);
+  void generate_isset_set(ofstream& out, t_field* field);
+  
+  void generate_service_interface (t_service* tservice);
+  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* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream& out,
+                                          t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_deserialize_struct       (std::ofstream& out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_deserialize_container    (std::ofstream& out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_deserialize_set_element  (std::ofstream& out,
+                                          t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (std::ofstream& out,
+                                          t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (std::ofstream& out,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+
+  void generate_serialize_field          (std::ofstream& out,
+                                          t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_serialize_struct         (std::ofstream& out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::ofstream& out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream& out,
+                                          t_map*      tmap,
+                                          std::string iter,
+                                          std::string map);
+
+  void generate_serialize_set_element    (std::ofstream& out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream& out,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  void generate_java_doc                 (std::ofstream& out,
+                                          t_doc*     tdoc);
+
+  void generate_java_doc                 (std::ofstream& out,
+                                          t_function* tdoc);
+
+  void generate_deep_copy_container(std::ofstream& out, std::string source_name_p1, std::string source_name_p2, std::string result_name, t_type* type);
+  void generate_deep_copy_non_container(std::ofstream& out, std::string source_name, std::string dest_name, t_type* type);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string java_package();
+  std::string java_type_imports();
+  std::string java_thrift_imports();
+  std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false);
+  std::string base_type_name(t_base_type* tbase, bool in_container=false);
+  std::string declare_field(t_field* tfield, bool init=false);
+  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 get_enum_class_name(t_type* type);
+
+  bool type_can_be_null(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return
+      ttype->is_container() ||
+      ttype->is_struct() ||
+      ttype->is_xception() ||
+      ttype->is_string();
+  }
+
+  std::string constant_name(std::string name);
+
+ private:
+
+  /**
+   * File streams
+   */
+
+  std::string package_name_;
+  std::ofstream f_service_;
+  std::string package_dir_;
+
+  bool bean_style_;
+  bool nocamel_style_;
+  bool gen_hash_code_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_java_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  package_name_ = program_->get_namespace("java");
+
+  string dir = package_name_;
+  string subdir = get_out_dir();
+  string::size_type loc;
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc+1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  package_dir_ = subdir;
+}
+
+/**
+ * Packages the generated file
+ *
+ * @return String of the package, i.e. "package org.apache.thriftdemo;"
+ */
+string t_java_generator::java_package() {
+  if (!package_name_.empty()) {
+    return string("package ") + package_name_ + ";\n\n";
+  }
+  return "";
+}
+
+/**
+ * Prints standard java imports
+ *
+ * @return List of imports for Java types that are used in here
+ */
+string t_java_generator::java_type_imports() {
+  string hash_builder;
+  if (gen_hash_code_) {
+    hash_builder = "import org.apache.commons.lang.builder.HashCodeBuilder;\n";
+  }
+
+  return
+    string() +
+    hash_builder +
+    "import java.util.List;\n" +
+    "import java.util.ArrayList;\n" +
+    "import java.util.Map;\n" +
+    "import java.util.HashMap;\n" +
+    "import java.util.Set;\n" +
+    "import java.util.HashSet;\n" +
+    "import java.util.Collections;\n\n";
+}
+
+/**
+ * Prints standard java imports
+ *
+ * @return List of imports necessary for thrift
+ */
+string t_java_generator::java_thrift_imports() {
+  return
+    string() +
+    "import org.apache.thrift.*;\n" +
+    "import org.apache.thrift.meta_data.*;\n" +
+    "import org.apache.thrift.protocol.*;\n\n";
+}
+
+/**
+ * Nothing in Java
+ */
+void t_java_generator::close_generator() {}
+
+/**
+ * Generates a typedef. This is not done in Java, since it does
+ * not support arbitrary name replacements, and it'd be a wacky waste
+ * of overhead to make wrapper classes.
+ *
+ * @param ttypedef The type definition
+ */
+void t_java_generator::generate_typedef(t_typedef* ttypedef) {}
+
+/**
+ * Enums are a class with a set of static constants.
+ *
+ * @param tenum The enumeration
+ */
+void t_java_generator::generate_enum(t_enum* tenum) {
+  // Make output file
+  string f_enum_name = package_dir_+"/"+(tenum->get_name())+".java";
+  ofstream f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  // Comment and package it
+  f_enum <<
+    autogen_comment() <<
+    java_package() << endl;
+  
+  // Add java imports
+  f_enum << string() +
+    "import java.util.Set;\n" +
+    "import java.util.HashSet;\n" +
+    "import java.util.Collections;\n" +
+    "import org.apache.thrift.IntRangeSet;\n" +
+    "import java.util.Map;\n" + 
+    "import java.util.HashMap;\n" << endl;
+
+  f_enum <<
+    "public class " << tenum->get_name() << " ";
+  scope_up(f_enum);
+
+  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;
+    }
+
+    indent(f_enum) <<
+      "public static final int " << (*c_iter)->get_name() <<
+      " = " << value << ";" << endl;
+  }
+  
+  // Create a static Set with all valid values for this enum
+  f_enum << endl;
+  indent(f_enum) << "public static final IntRangeSet VALID_VALUES = new IntRangeSet(";
+  indent_up();
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    // populate set
+    if ((*c_iter)->has_value()) {
+      f_enum << (first ? "" : ", ") << (*c_iter)->get_name();
+      first = false;
+    }
+  }
+  indent_down();
+  f_enum << ");" << endl;
+
+  indent(f_enum) << "public static final Map<Integer, String> VALUES_TO_NAMES = new HashMap<Integer, String>() {{" << endl;
+
+  indent_up();
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {    
+    indent(f_enum) << "put(" << (*c_iter)->get_name() << ", \"" << (*c_iter)->get_name() <<"\");" << endl;
+  }
+  indent_down();
+
+  
+  indent(f_enum) << "}};" << endl;
+
+  scope_down(f_enum);
+  
+  f_enum.close();
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_java_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+
+  string f_consts_name = package_dir_+"/Constants.java";
+  ofstream f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  // Print header
+  f_consts <<
+    autogen_comment() <<
+    java_package() <<
+    java_type_imports();
+
+  f_consts <<
+    "public class Constants {" << endl <<
+    endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value(),
+                      false);
+  }
+  indent_down();
+  indent(f_consts) <<
+    "}" << endl;
+  f_consts.close();
+}
+
+
+/**
+ * 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
+ */
+void t_java_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) {
+  type = get_true_type(type);
+
+  indent(out);
+  if (!defval) {
+    out <<
+      (in_static ? "" : "public static final ") <<
+      type_name(type) << " ";
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    out << name << " = " << v2 << ";" << endl << endl;
+  } else if (type->is_enum()) {
+    out << name << " = " << value->get_integer() << ";" << endl << endl;
+  } else 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*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    out << name << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    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();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << ".";
+      std::string cap_name = get_cap_name(v_iter->first->get_string());
+      out << "set" << cap_name << "(" << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_map()) {
+    out << name << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    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;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << ".put(" << key << ", " << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_list() || type->is_set()) {
+    out << name << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    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(out, name, etype, *v_iter);
+      indent(out) << name << ".add(" << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else {
+    throw "compiler error: no const of type " + type->get_name();
+  }
+}
+
+string t_java_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      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_BYTE:
+      render << "(byte)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I16:
+      render << "(short)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I32:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      render << value->get_integer() << "L";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << "(double)" << value->get_integer();
+      } else {
+        render << 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()) {
+    render << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with data members, read(), write(), and an inner Isset class.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_struct(t_struct* tstruct) {
+  generate_java_struct(tstruct, false);
+}
+
+/**
+ * Exceptions are structs, but they inherit from Exception
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_xception(t_struct* txception) {
+  generate_java_struct(txception, true);
+}
+
+
+/**
+ * Java struct definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct(t_struct* tstruct,
+                                            bool is_exception) {
+  // Make output file
+  string f_struct_name = package_dir_+"/"+(tstruct->get_name())+".java";
+  ofstream f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct <<
+    autogen_comment() <<
+    java_package() <<
+    java_type_imports() <<
+    java_thrift_imports();
+
+  generate_java_struct_definition(f_struct,
+                                  tstruct,
+                                  is_exception);
+  f_struct.close();
+}
+
+/**
+ * Java struct definition. This has various parameters, as it could be
+ * generated standalone or inside another class as a helper. If it
+ * is a helper than it is a static class.
+ *
+ * @param tstruct      The struct definition
+ * @param is_exception Is this an exception?
+ * @param in_class     If inside a class, needs to be static class
+ * @param is_result    If this is a result it needs a different writer
+ */
+void t_java_generator::generate_java_struct_definition(ofstream &out,
+                                                       t_struct* tstruct,
+                                                       bool is_exception,
+                                                       bool in_class,
+                                                       bool is_result) {
+  generate_java_doc(out, tstruct);
+
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+  indent(out) <<
+    "public " << (is_final ? "final " : "") <<
+     (in_class ? "static " : "") << "class " << tstruct->get_name() << " ";
+
+  if (is_exception) {
+    out << "extends Exception ";
+  }
+  out << "implements TBase, java.io.Serializable, Cloneable ";
+
+  scope_up(out);
+
+  indent(out) <<
+    "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name() << "\");" << endl;
+
+  // Members are public for -java, private for -javabean
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) <<
+      "private static final TField " << constant_name((*m_iter)->get_name()) <<
+      "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " <<
+      type_to_enum((*m_iter)->get_type()) << ", " <<
+      "(short)" << (*m_iter)->get_key() << ");" << endl;
+  }
+
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (bean_style_) {
+      indent(out) << "private ";
+    } else {
+      generate_java_doc(out, *m_iter);
+      indent(out) << "public ";
+    }
+    out << declare_field(*m_iter, false) << endl;
+
+    indent(out) << "public static final int " << upcase_string((*m_iter)->get_name()) << " = " << (*m_iter)->get_key() << ";" << endl;
+  }
+  
+  // Inner Isset class
+  if (members.size() > 0) {
+    out <<
+      endl <<
+      indent() << "private final Isset __isset = new Isset();" << endl <<
+      indent() << "private static final class Isset implements java.io.Serializable {" << endl;
+    indent_up();
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        if (!type_can_be_null((*m_iter)->get_type())){
+          indent(out) <<
+            "public boolean " << (*m_iter)->get_name() << " = false;" <<  endl;
+        }
+      }
+    indent_down();
+    out <<
+      indent() << "}" << endl <<
+      endl;
+  }
+
+  generate_java_meta_data_map(out, tstruct);
+  
+  // Static initializer to populate global class to struct metadata map
+  indent(out) << "static {" << endl;
+  indent_up();
+  indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ".class, metaDataMap);" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  // Default constructor
+  indent(out) <<
+    "public " << tstruct->get_name() << "() {" << endl;
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL) {
+      print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+
+  if (!members.empty()) {
+    // Full constructor for all fields
+    indent(out) <<
+      "public " << tstruct->get_name() << "(" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ) {
+      indent(out) << type_name((*m_iter)->get_type()) << " " <<
+        (*m_iter)->get_name();
+      ++m_iter;
+      if (m_iter != members.end()) {
+        out << "," << endl;
+      }
+    }
+    out << ")" << endl;
+    indent_down();
+    indent(out) << "{" << endl;
+    indent_up();
+    indent(out) << "this();" << endl;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      indent(out) << "this." << (*m_iter)->get_name() << " = " <<
+        (*m_iter)->get_name() << ";" << endl;
+      generate_isset_set(out, (*m_iter));
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+
+  // copy constructor
+  indent(out) << "/**" << endl;
+  indent(out) << " * Performs a deep copy on <i>other</i>." << endl;
+  indent(out) << " */" << endl;
+  indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {" << endl;
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+    std::string field_name = field->get_name();
+    t_type* type = field->get_type();
+    bool can_be_null = type_can_be_null(type);
+
+    if (!can_be_null) {
+      indent(out) << "__isset." << field_name << " = other.__isset." << field_name << ";" << endl;
+    }
+
+    if (can_be_null) {
+      indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl;
+      indent_up();
+    }
+
+    if (type->is_container()) {
+      generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type);
+      indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl;
+    } else {
+      indent(out) << "this." << field_name << " = ";
+      generate_deep_copy_non_container(out, "other." + field_name, field_name, type);
+      out << ";" << endl;
+    }
+
+    if (can_be_null) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  // clone method, so that you can deep copy an object when you don't know its class.
+  indent(out) << "@Override" << endl;
+  indent(out) << "public " << tstruct->get_name() << " clone() {" << endl;
+  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
+  indent(out) << "}" << endl << endl;
+
+  generate_java_bean_boilerplate(out, tstruct);
+  generate_generic_field_getters_setters(out, tstruct);
+  generate_generic_isset_method(out, tstruct);
+
+  generate_java_struct_equality(out, tstruct);
+
+  generate_java_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_java_struct_result_writer(out, tstruct);
+  } else {
+    generate_java_struct_writer(out, tstruct);
+  }
+  generate_java_struct_tostring(out, tstruct);
+  generate_java_validator(out, tstruct);
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generates equals methods and a hashCode method for a structure.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_equality(ofstream& out,
+                                                     t_struct* tstruct) {
+  out << indent() << "@Override" << endl <<
+    indent() << "public boolean equals(Object that) {" << endl;
+  indent_up();
+  out <<
+    indent() << "if (that == null)" << endl <<
+    indent() << "  return false;" << endl <<
+    indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl <<
+    indent() << "  return this.equals((" << tstruct->get_name() << ")that);" << endl <<
+    indent() << "return false;" << endl;
+  scope_down(out);
+  out << endl;
+
+  out <<
+    indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl;
+  indent_up();
+  out <<
+    indent() << "if (that == null)" << endl <<
+    indent() << "  return false;" << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    out << endl;
+
+    t_type* t = get_true_type((*m_iter)->get_type());
+    // Most existing Thrift code does not use isset or optional/required,
+    // so we treat "default" fields as required.
+    bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
+    bool can_be_null = type_can_be_null(t);
+    string name = (*m_iter)->get_name();
+
+    string this_present = "true";
+    string that_present = "true";
+    string unequal;
+
+    if (is_optional || can_be_null) {
+      this_present += " && this." + generate_isset_check(*m_iter);
+      that_present += " && that." + generate_isset_check(*m_iter);
+    }
+
+    out <<
+      indent() << "boolean this_present_" << name << " = "
+               << this_present << ";" << endl <<
+      indent() << "boolean that_present_" << name << " = "
+               << that_present << ";" << endl <<
+      indent() << "if (" << "this_present_" << name
+               << " || that_present_" << name << ") {" << endl;
+    indent_up();
+    out <<
+      indent() << "if (!(" << "this_present_" << name
+               << " && that_present_" << name << "))" << endl <<
+      indent() << "  return false;" << endl;
+
+    if (t->is_base_type() && ((t_base_type*)t)->is_binary()) {
+      unequal = "!java.util.Arrays.equals(this." + name + ", that." + name + ")";
+    } else if (can_be_null) {
+      unequal = "!this." + name + ".equals(that." + name + ")";
+    } else {
+      unequal = "this." + name + " != that." + name;
+    }
+
+    out <<
+      indent() << "if (" << unequal << ")" << endl <<
+      indent() << "  return false;" << endl;
+
+    scope_down(out);
+  }
+  out << endl;
+  indent(out) << "return true;" << endl;
+  scope_down(out);
+  out << endl;
+
+  out << indent() << "@Override" << endl <<
+    indent() << "public int hashCode() {" << endl;
+  indent_up();
+  if (gen_hash_code_) {
+    indent(out) << "HashCodeBuilder builder = new HashCodeBuilder();" << endl;
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << endl;
+
+      t_type* t = get_true_type((*m_iter)->get_type());
+      bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
+      bool can_be_null = type_can_be_null(t);
+      string name = (*m_iter)->get_name();
+
+      string present = "true";
+
+      if (is_optional || can_be_null) {
+        present += " && (" + generate_isset_check(*m_iter) + ")";
+      }
+
+      out <<
+        indent() << "boolean present_" << name << " = "
+                 << present << ";" << endl <<
+        indent() << "builder.append(present_" << name << ");" << endl <<
+        indent() << "if (present_" << name << ")" << endl <<
+        indent() << "  builder.append(" << name << ");" << endl;
+    }
+
+    out << endl;
+    indent(out) << "return builder.toHashCode();" << endl;
+  } else {
+    indent(out) << "return 0;" << endl;
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_reader(ofstream& out,
+                                                   t_struct* tstruct) {
+  out <<
+    indent() << "public void read(TProtocol iprot) throws TException {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables and read struct header
+  out <<
+    indent() << "TField field;" << endl <<
+    indent() << "iprot.readStructBegin();" << endl;
+
+  // Loop over reading in fields
+  indent(out) <<
+    "while (true)" << endl;
+    scope_up(out);
+
+    // Read beginning field marker
+    indent(out) <<
+      "field = iprot.readFieldBegin();" << endl;
+
+    // Check for field STOP marker and break
+    indent(out) <<
+      "if (field.type == TType.STOP) { " << endl;
+    indent_up();
+    indent(out) <<
+      "break;" << endl;
+    indent_down();
+    indent(out) <<
+      "}" << endl;
+
+    // Switch statement on the field we are reading
+    indent(out) <<
+      "switch (field.id)" << endl;
+
+      scope_up(out);
+
+      // Generate deserialization code for known cases
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        indent(out) <<
+          "case " << upcase_string((*f_iter)->get_name()) << ":" << endl;
+        indent_up();
+        indent(out) <<
+          "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+        indent_up();
+
+        generate_deserialize_field(out, *f_iter, "this.");
+        generate_isset_set(out, *f_iter);
+        indent_down();
+        out <<
+          indent() << "} else { " << endl <<
+          indent() << "  TProtocolUtil.skip(iprot, field.type);" << endl <<
+          indent() << "}" << endl <<
+          indent() << "break;" << endl;
+        indent_down();
+      }
+
+      // In the default case we skip the field
+      out <<
+        indent() << "default:" << endl <<
+        indent() << "  TProtocolUtil.skip(iprot, field.type);" << endl <<
+        indent() << "  break;" << endl;
+
+      scope_down(out);
+
+    // Read field end marker
+    indent(out) <<
+      "iprot.readFieldEnd();" << endl;
+
+    scope_down(out);
+
+    out <<
+      indent() << "iprot.readStructEnd();" << endl << endl;
+    
+    // in non-beans style, check for required fields of primitive type
+    // (which can be checked here but not in the general validate method)
+    if (!bean_style_){
+      out << endl << indent() << "// check for required fields of primitive type, which can't be checked in the validate method" << endl;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
+          out <<
+            indent() << "if (!__isset." << (*f_iter)->get_name() << ") {" << endl <<
+            indent() << "  throw new TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' was not found in serialized data! Struct: \" + toString());" << endl <<
+            indent() << "}" << endl;
+        }
+      }
+    }
+
+    // performs various checks (e.g. check that all required fields are set)
+    indent(out) << "validate();" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+// generates java method to perform various checks
+// (e.g. check that all required fields are set)
+void t_java_generator::generate_java_validator(ofstream& out,
+                                                   t_struct* tstruct){
+  indent(out) << "public void validate() throws TException {" << endl;
+  indent_up();  
+  
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  
+  out << indent() << "// check for required fields" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      if (bean_style_) {
+        out <<
+          indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl <<
+          indent() << "  throw new TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' is unset! Struct:\" + toString());" << endl <<
+          indent() << "}" << endl << endl;
+      } else{
+        if (type_can_be_null((*f_iter)->get_type())) {
+          indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl;
+          indent(out) << "  throw new TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl;
+          indent(out) << "}" << endl;
+        } else {
+          indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() << "' because it's a primitive and you chose the non-beans generator." << endl;
+        }
+      }      
+    }
+  }
+  
+  // check that fields of type enum have valid values
+  out << indent() << "// check that fields of type enum have valid values" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+    t_type* type = field->get_type();
+    // if field is an enum, check that its value is valid
+    if (type->is_enum()){
+      indent(out) << "if (" << generate_isset_check(field) << " && !" << get_enum_class_name(type) << ".VALID_VALUES.contains(" << field->get_name() << ")){" << endl;
+      indent_up();
+      indent(out) << "throw new TProtocolException(\"The field '" << field->get_name() << "' has been assigned the invalid value \" + " << field->get_name() << ");" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    } 
+  }  
+  
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_writer(ofstream& out,
+                                                   t_struct* tstruct) {
+  out <<
+    indent() << "public void write(TProtocol oprot) throws TException {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl << endl;
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out <<
+        indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
+      indent_up();
+    }
+    bool optional = bean_style_ && (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (optional) {
+      indent(out) << "if (" << generate_isset_check((*f_iter)) << ") {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) <<
+      "oprot.writeFieldEnd();" << endl;
+
+    if (optional) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+  // Write the struct map
+  out <<
+    indent() << "oprot.writeFieldStop();" << endl <<
+    indent() << "oprot.writeStructEnd();" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct,
+ * which is a function result. These fields are only written
+ * if they are set in the Isset array, and only one of them
+ * can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_result_writer(ofstream& out,
+                                                          t_struct* tstruct) {
+  out <<
+    indent() << "public void write(TProtocol oprot) throws TException {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out <<
+        endl <<
+        indent() << "if ";
+    } else {
+      out << " else if ";
+    }
+
+    out << "(this." << generate_isset_check(*f_iter) << ") {" << endl;
+
+    indent_up();
+    
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) <<
+      "oprot.writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}";
+  }
+  // Write the struct map
+  out <<
+    endl <<
+    indent() << "oprot.writeFieldStop();" << endl <<
+    indent() << "oprot.writeStructEnd();" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+void t_java_generator::generate_reflection_getters(ostringstream& out, t_type* type, string field_name, string cap_name) {
+  indent(out) << "case " << upcase_string(field_name) << ":" << endl;
+  indent_up();
+
+  if (type->is_base_type() && !type->is_string()) {
+    t_base_type* base_type = (t_base_type*)type;
+
+    indent(out) << "return new " << type_name(type, true, false) << "(" << (base_type->is_bool() ? "is" : "get") << cap_name << "());" << endl << endl;
+  } else {
+    indent(out) << "return get" << cap_name << "();" << endl << endl;
+  }
+
+  indent_down();
+}
+
+void t_java_generator::generate_reflection_setters(ostringstream& out, t_type* type, string field_name, string cap_name) {
+  indent(out) << "case " << upcase_string(field_name) << ":" << endl;
+  indent_up();
+  indent(out) << "if (value == null) {" << endl;
+  indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
+  indent(out) << "} else {" << endl;
+  indent(out) << "  set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl;
+  indent(out) << "}" << endl;
+  indent(out) << "break;" << endl << endl;
+
+  indent_down();
+}
+
+void t_java_generator::generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct) {
+
+  std::ostringstream getter_stream;
+  std::ostringstream setter_stream;
+
+  // build up the bodies of both the getter and setter at once
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    indent_up();
+    generate_reflection_setters(setter_stream, type, field_name, cap_name);
+    generate_reflection_getters(getter_stream, type, field_name, cap_name);
+    indent_down();
+  }
+
+
+  // create the setter
+  indent(out) << "public void setFieldValue(int fieldID, Object value) {" << endl;
+  indent_up();
+
+  indent(out) << "switch (fieldID) {" << endl;
+
+  out << setter_stream.str();
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalArgumentException(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  // create the getter
+  indent(out) << "public Object getFieldValue(int fieldID) {" << endl;
+  indent_up();
+
+  indent(out) << "switch (fieldID) {" << endl;
+
+  out << getter_stream.str();
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalArgumentException(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+
+  indent(out) << "}" << endl;
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+// Creates a generic isSet method that takes the field number as argument
+void t_java_generator::generate_generic_isset_method(std::ofstream& out, t_struct* tstruct){
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // create the isSet method
+  indent(out) << "// Returns true if field corresponding to fieldID is set (has been asigned a value) and false otherwise" << endl;
+  indent(out) << "public boolean isSet(int fieldID) {" << endl;
+  indent_up();
+  indent(out) << "switch (fieldID) {" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << "return " << generate_isset_check(field) << ";" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalArgumentException(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a set of Java Bean boilerplate functions (setters, getters, etc.)
+ * for the given struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_bean_boilerplate(ofstream& out,
+                                                      t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    if (type->is_container()) {
+      // Method to return the size of the collection
+      indent(out) << "public int get" << cap_name;
+      out << get_cap_name("size() {") << endl;
+
+      indent_up();
+      indent(out) << "return (this." << field_name << " == null) ? 0 : " <<
+        "this." << field_name << ".size();" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+    }
+
+    if (type->is_set() || type->is_list()) {
+
+      t_type* element_type;
+      if (type->is_set()) {
+        element_type = ((t_set*)type)->get_elem_type();
+      } else {
+        element_type = ((t_list*)type)->get_elem_type();
+      }
+
+      // Iterator getter for sets and lists
+      indent(out) << "public java.util.Iterator<" <<
+        type_name(element_type, true, false) <<  "> get" << cap_name;
+      out << get_cap_name("iterator() {") << endl;
+
+      indent_up();
+      indent(out) << "return (this." << field_name << " == null) ? null : " <<
+        "this." << field_name << ".iterator();" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+
+      // Add to set or list, create if the set/list is null
+      indent(out);
+      out << "public void add" << get_cap_name("to");
+      out << cap_name << "(" << type_name(element_type) << " elem) {" << endl;
+
+      indent_up();
+      indent(out) << "if (this." << field_name << " == null) {" << endl;
+      indent_up();
+      indent(out) << "this." << field_name << " = new " << type_name(type, false, true) <<
+        "();" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+      indent(out) << "this." << field_name << ".add(elem);" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+
+    } else if (type->is_map()) {
+      // Put to map
+      t_type* key_type = ((t_map*)type)->get_key_type();
+      t_type* val_type = ((t_map*)type)->get_val_type();
+
+      indent(out);
+      out << "public void put" << get_cap_name("to");
+      out << cap_name << "(" << type_name(key_type) << " key, "
+        << type_name(val_type) << " val) {" << endl;
+
+      indent_up();
+      indent(out) << "if (this." << field_name << " == null) {" << endl;
+      indent_up();
+      indent(out) << "this." << field_name << " = new " <<
+        type_name(type, false, true) << "();" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+      indent(out) << "this." << field_name << ".put(key, val);" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+    }
+
+    // Simple getter
+    generate_java_doc(out, field);
+    indent(out) << "public " << type_name(type);
+    if (type->is_base_type() &&
+        ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
+      out << " is";
+    } else {
+      out << " get";
+    }
+    out << cap_name << "() {" << endl;
+    indent_up();
+    indent(out) << "return this." << field_name << ";" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Simple setter
+    generate_java_doc(out, field);
+    indent(out) << "public void set" << cap_name << "(" << type_name(type) <<
+      " " << field_name << ") {" << endl;
+    indent_up();
+    indent(out) << "this." << field_name << " = " << field_name << ";" <<
+      endl;
+    generate_isset_set(out, field);
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Unsetter
+    indent(out) << "public void unset" << cap_name << "() {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "this." << field_name << " = null;" << endl;
+    } else {
+      indent(out) << "this.__isset." << field_name << " = false;" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // isSet method
+    indent(out) << "// Returns true if field " << field_name << " is set (has been asigned a value) and false otherwise" << endl;
+    indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "return this." << field_name << " != null;" << endl;
+    } else {
+      indent(out) << "return this.__isset." << field_name << ";" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+    
+    if(!bean_style_) {
+      indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {" << endl;
+      indent_up();
+      if (type_can_be_null(type)) {
+        indent(out) << "if (!value) {" << endl;
+        indent(out) << "  this." << field_name << " = null;" << endl;
+        indent(out) << "}" << endl;
+      } else {
+        indent(out) << "this.__isset." << field_name << " = value;" << endl;
+      }
+      indent_down();
+      indent(out) << "}" << endl << endl; 
+    }
+  }
+}
+
+/**
+ * Generates a toString() method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_tostring(ofstream& out,
+                                                     t_struct* tstruct) {
+  out << indent() << "@Override" << endl <<
+    indent() << "public String toString() {" << endl;
+  indent_up();
+
+  out <<
+    indent() << "StringBuilder sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
+  out << indent() << "boolean first = true;" << endl << endl;
+
+  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) {
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if(could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
+      indent_up();
+    }
+
+    t_field* field = (*f_iter);
+
+    if (!first) {
+      indent(out) << "if (!first) sb.append(\", \");" << endl;
+    }
+    indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
+    bool can_be_null = type_can_be_null(field->get_type());
+    if (can_be_null) {
+      indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
+      indent(out) << "  sb.append(\"null\");" << endl;
+      indent(out) << "} else {" << endl;
+      indent_up();
+    }
+    
+    if (field->get_type()->is_base_type() && ((t_base_type*)(field->get_type()))->is_binary()) {
+      indent(out) << "  int __" << field->get_name() << "_size = Math.min(this." << field->get_name() << ".length, 128);" << endl;
+      indent(out) << "  for (int i = 0; i < __" << field->get_name() << "_size; i++) {" << endl;
+      indent(out) << "    if (i != 0) sb.append(\" \");" << endl;
+      indent(out) << "    sb.append(Integer.toHexString(this." << field->get_name() << "[i]).length() > 1 ? Integer.toHexString(this." << field->get_name() << "[i]).substring(Integer.toHexString(this." << field->get_name() << "[i]).length() - 2).toUpperCase() : \"0\" + Integer.toHexString(this." << field->get_name() << "[i]).toUpperCase());" <<endl;
+      indent(out) << "  }" << endl;
+      indent(out) << "  if (this." << field->get_name() << ".length > 128) sb.append(\" ...\");" << endl;
+    } else if(field->get_type()->is_enum()) {
+      indent(out) << "String " << field->get_name() << "_name = " << get_enum_class_name(field->get_type()) << ".VALUES_TO_NAMES.get(this." << (*f_iter)->get_name() << ");"<< endl;
+      indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
+      indent(out) << "  sb.append(" << field->get_name() << "_name);" << endl;
+      indent(out) << "  sb.append(\" (\");" << endl;
+      indent(out) << "}" << endl;
+      indent(out) << "sb.append(this." << field->get_name() << ");" << endl;
+      indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
+      indent(out) << "  sb.append(\")\");" << endl;
+      indent(out) << "}" << endl;
+    } else {
+      indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl;
+    }
+    
+    if (can_be_null) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    indent(out) << "first = false;" << endl;
+
+    if(could_be_unset) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    first = false;
+  }
+  out <<
+    indent() << "sb.append(\")\");" << endl <<
+    indent() << "return sb.toString();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates a static map with meta data to store information such as fieldID to
+ * fieldName mapping
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_meta_data_map(ofstream& out,
+                                                   t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Static Map with fieldID -> FieldMetaData mappings
+  indent(out) << "public static final Map<Integer, FieldMetaData> metaDataMap = Collections.unmodifiableMap(new HashMap<Integer, FieldMetaData>() {{" << endl;
+
+  // Populate map
+  indent_up();
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    std::string field_name = field->get_name();
+    indent(out) << "put(" << upcase_string(field_name) << ", new FieldMetaData(\"" << field_name << "\", ";
+
+    // Set field requirement type (required, optional, etc.)
+    if (field->get_req() == t_field::T_REQUIRED) {
+      out << "TFieldRequirementType.REQUIRED, ";
+    } else if (field->get_req() == t_field::T_OPTIONAL) {
+      out << "TFieldRequirementType.OPTIONAL, ";
+    } else {
+      out << "TFieldRequirementType.DEFAULT, ";
+    }
+
+    // Create value meta data    
+    generate_field_value_meta_data(out, field->get_type());
+    out  << "));" << endl;
+  }
+  indent_down();
+  indent(out) << "}});" << endl << endl;
+}
+
+/** 
+ * Returns a string with the java representation of the given thrift type
+ * (e.g. for the type struct it returns "TType.STRUCT")
+ */
+std::string t_java_generator::get_java_type_string(t_type* type) {
+  if (type->is_list()){
+    return "TType.LIST";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_typedef()) {
+    return get_java_type_string(((t_typedef*)type)->get_type());
+  } else if (type->is_base_type()) {
+    switch (((t_base_type*)type)->get_base()) {
+      case t_base_type::TYPE_VOID   : return      "TType.VOID"; break;
+      case t_base_type::TYPE_STRING : return    "TType.STRING"; break;
+      case t_base_type::TYPE_BOOL   : return      "TType.BOOL"; break;
+      case t_base_type::TYPE_BYTE   : return      "TType.BYTE"; break;
+      case t_base_type::TYPE_I16    : return       "TType.I16"; break;
+      case t_base_type::TYPE_I32    : return       "TType.I32"; break;
+      case t_base_type::TYPE_I64    : return       "TType.I64"; break;
+      case t_base_type::TYPE_DOUBLE : return    "TType.DOUBLE"; break;
+      default : throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_java_generator::get_java_type_string!"); break; // This should never happen!
+    }
+  } else {
+    throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_java_generator::get_java_type_string!"); // This should never happen!
+  }
+}
+
+void t_java_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type){
+  out << endl;
+  indent_up();
+  indent_up();
+  if (type->is_struct()){
+    indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type) << ".class";
+  } else if (type->is_container()){
+    if (type->is_list()){
+      indent(out) << "new ListMetaData(TType.LIST, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();    
+      generate_field_value_meta_data(out, elem_type);   
+    } else if (type->is_set()){
+      indent(out) << "new SetMetaData(TType.SET, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();    
+      generate_field_value_meta_data(out, elem_type); 
+    } else{ // map
+      indent(out) << "new MapMetaData(TType.MAP, ";
+      t_type* key_type = ((t_map*)type)->get_key_type();
+      t_type* val_type = ((t_map*)type)->get_val_type();
+      generate_field_value_meta_data(out, key_type);
+      out << ", ";
+      generate_field_value_meta_data(out, val_type);
+    }
+  } else {
+    indent(out) << "new FieldValueMetaData(" << get_java_type_string(type);
+  }
+  out << ")";
+  indent_down();
+  indent_down();
+}
+
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_java_generator::generate_service(t_service* tservice) {
+  // Make output file
+  string f_service_name = package_dir_+"/"+service_name_+".java";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    autogen_comment() <<
+    java_package() <<
+    java_type_imports() <<
+    java_thrift_imports();
+
+  f_service_ <<
+    "public class " << service_name_ << " {" << endl <<
+    endl;
+  indent_up();
+
+  // Generate the three main parts of the service
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  indent_down();
+  f_service_ <<
+    "}" << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_java_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " extends " + extends + ".Iface";
+  }
+
+  generate_java_doc(f_service_, tservice);
+  f_service_ << indent() << "public interface Iface" << extends_iface <<
+    " {" << endl << endl;
+  indent_up();
+  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_java_doc(f_service_, *f_iter);
+    indent(f_service_) << "public " << function_signature(*f_iter) << ";" <<
+      endl << endl;
+  }
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates structs for all the service args and return types
+ *
+ * @param tservice The service
+ */
+void t_java_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_java_struct_definition(f_service_, ts, false, true);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_java_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = " extends " + extends + ".Client";
+  }
+
+  indent(f_service_) <<
+    "public static class Client" << extends_client << " implements Iface {" << endl;
+  indent_up();
+
+  indent(f_service_) <<
+    "public Client(TProtocol prot)" << endl;
+  scope_up(f_service_);
+  indent(f_service_) <<
+    "this(prot, prot);" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) <<
+    "public Client(TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "iprot_ = iprot;" << endl <<
+      indent() << "oprot_ = oprot;" << endl;
+  } else {
+    f_service_ <<
+      indent() << "super(iprot, oprot);" << endl;
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected TProtocol iprot_;"  << endl <<
+      indent() << "protected TProtocol oprot_;"  << endl <<
+      endl <<
+      indent() << "protected int seqid_;" << endl <<
+      endl;
+
+    indent(f_service_) <<
+      "public TProtocol getInputProtocol()" << endl;
+    scope_up(f_service_);
+    indent(f_service_) <<
+      "return this.iprot_;" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    indent(f_service_) <<
+      "public TProtocol getOutputProtocol()" << endl;
+    scope_up(f_service_);
+    indent(f_service_) <<
+      "return this.oprot_;" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+
+  }
+
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    indent(f_service_) <<
+      "public " << function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+    indent(f_service_) <<
+      "send_" << funname << "(";
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << (*fld_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ <<
+        "recv_" << funname << "();" << endl;
+    }
+    scope_down(f_service_);
+    f_service_ << 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";
+
+    // Open function
+    indent(f_service_) <<
+      "public " << function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    // Serialize the request
+    f_service_ <<
+      indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType.CALL, seqid_));" << endl <<
+      indent() << argsname << " args = new " << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ <<
+        indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    f_service_ <<
+      indent() << "args.write(oprot_);" << endl <<
+      indent() << "oprot_.writeMessageEnd();" << endl <<
+      indent() << "oprot_.getTransport().flush();" << endl;
+
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      string resultname = (*f_iter)->get_name() + "_result";
+
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+      // Open function
+      indent(f_service_) <<
+        "public " << function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      // TODO(mcslee): Message validation here, was the seqid etc ok?
+
+      f_service_ <<
+        indent() << "TMessage msg = iprot_.readMessageBegin();" << endl <<
+        indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl <<
+        indent() << "  TApplicationException x = TApplicationException.read(iprot_);" << endl <<
+        indent() << "  iprot_.readMessageEnd();" << endl <<
+        indent() << "  throw x;" << endl <<
+        indent() << "}" << endl <<
+        indent() << resultname << " result = new " << resultname << "();" << endl <<
+        indent() << "result.read(iprot_);" << endl <<
+        indent() << "iprot_.readMessageEnd();" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "if (result." << generate_isset_check("success") << ") {" << endl <<
+          indent() << "  return result.success;" << endl <<
+          indent() << "}" << endl;
+      }
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "if (result." << (*x_iter)->get_name() << " != null) {" << endl <<
+          indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl <<
+          indent() << "}" << endl;
+      }
+
+      // If you get here it's an exception, unless a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "return;" << endl;
+      } else {
+        f_service_ <<
+          indent() << "throw new TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+      // Close function
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+
+  indent_down();
+  indent(f_service_) <<
+    "}" << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_java_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Extends stuff
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = " extends " + extends + ".Processor";
+  }
+
+  // Generate the header portion
+  indent(f_service_) <<
+    "public static class Processor" << extends_processor << " implements TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) <<
+    "public Processor(Iface iface)" << endl;
+  scope_up(f_service_);
+  if (!extends.empty()) {
+    f_service_ <<
+      indent() << "super(iface);" << endl;
+  }
+  f_service_ <<
+    indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      indent() << "processMap_.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected static interface ProcessFunction {" << endl <<
+      indent() << "  public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException;" << endl <<
+      indent() << "}" << endl <<
+      endl;
+  }
+
+  f_service_ <<
+    indent() << "private Iface iface_;" << endl;
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected final HashMap<String,ProcessFunction> processMap_ = new HashMap<String,ProcessFunction>();" << endl;
+  }
+
+  f_service_ << endl;
+
+  // Generate the server implementation
+  indent(f_service_) <<
+    "public boolean process(TProtocol iprot, TProtocol oprot) throws TException" << endl;
+  scope_up(f_service_);
+
+  f_service_ <<
+    indent() << "TMessage msg = iprot.readMessageBegin();" << endl;
+
+  // TODO(mcslee): validate message, was the seqid etc. legit?
+
+  f_service_ <<
+    indent() << "ProcessFunction fn = processMap_.get(msg.name);" << endl <<
+    indent() << "if (fn == null) {" << endl <<
+    indent() << "  TProtocolUtil.skip(iprot, TType.STRUCT);" << endl <<
+    indent() << "  iprot.readMessageEnd();" << endl <<
+    indent() << "  TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: '\"+msg.name+\"'\");" << endl <<
+    indent() << "  oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl <<
+    indent() << "  x.write(oprot);" << endl <<
+    indent() << "  oprot.writeMessageEnd();" << endl <<
+    indent() << "  oprot.getTransport().flush();" << endl <<
+    indent() << "  return true;" << endl <<
+    indent() << "}" << endl <<
+    indent() << "fn.process(msg.seqid, iprot, oprot);" << endl;
+
+  f_service_ <<
+    indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) <<
+    "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_java_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_java_struct_definition(f_service_, &result, false, true, true);
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_java_generator::generate_process_function(t_service* tservice,
+                                                 t_function* tfunction) {
+  // Open class
+  indent(f_service_) <<
+    "private class " << tfunction->get_name() << " implements ProcessFunction {" << endl;
+  indent_up();
+
+  // Open function
+  indent(f_service_) <<
+    "public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException" << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ <<
+    indent() << argsname << " args = new " << argsname << "();" << endl <<
+    indent() << "args.read(iprot);" << endl <<
+    indent() << "iprot.readMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ <<
+      indent() << "try {" << endl;
+    indent_up();
+  }
+
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.success = ";
+  }
+  f_service_ <<
+    "iface_." << tfunction->get_name() << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  // Set isset on success field
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() && !type_can_be_null(tfunction->get_returntype())) {
+    f_service_ <<
+      indent() << "result.__isset.success = true;" << endl;
+  }
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}";
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*x_iter)->get_name() << ") {" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ <<
+          indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl;
+        indent_down();
+        f_service_ << indent() << "}";
+      } else {
+        f_service_ << "}";
+      }
+    }
+    f_service_ << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "return;" << endl;
+    scope_down(f_service_);
+
+    // Close class
+    indent_down();
+    f_service_ <<
+      indent() << "}" << endl <<
+      endl;
+    return;
+  }
+
+  f_service_ <<
+    indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl <<
+    indent() << "result.write(oprot);" << endl <<
+    indent() << "oprot.writeMessageEnd();" << endl <<
+    indent() << "oprot.getTransport().flush();" << endl;
+
+  // Close function
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Close class
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param prefix The variable name or container for this field
+ */
+void t_java_generator::generate_deserialize_field(ofstream& out,
+                                                  t_field* tfield,
+                                                  string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type,
+                                name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) <<
+      name << " = 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 (((t_base_type*)type)->is_binary()) {
+          out << "readBinary();";
+        } else {
+          out << "readString();";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool();";
+        break;
+      case t_base_type::TYPE_BYTE:
+        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 Java name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32();";
+    }
+    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());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, invokes read()
+ */
+void t_java_generator::generate_deserialize_struct(ofstream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix) {
+  out <<
+    indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
+    indent() << prefix << ".read(iprot);" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_java_generator::generate_deserialize_container(ofstream& out,
+                                                      t_type* ttype,
+                                                      string prefix) {
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl;
+  }
+
+  indent(out)
+    << prefix << " = new " << type_name(ttype, false, true)
+    // size the collection correctly
+    << "("
+    << (ttype->is_list() ? "" : "2*" )
+    << obj << ".size"
+    << ");" << endl;
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) <<
+    "for (int " << i << " = 0; " <<
+    i << " < " << obj << ".size" << "; " <<
+    "++" << i << ")" << endl;
+
+    scope_up(out);
+
+    if (ttype->is_map()) {
+      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+    } else if (ttype->is_set()) {
+      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+    } else if (ttype->is_list()) {
+      generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+    }
+
+    scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot.readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_java_generator::generate_deserialize_map_element(ofstream& out,
+                                                        t_map* tmap,
+                                                        string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) <<
+    declare_field(&fkey) << endl;
+  indent(out) <<
+    declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) <<
+    prefix << ".put(" << key << ", " << val << ");" << endl;
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_java_generator::generate_deserialize_set_element(ofstream& out,
+                                                        t_set* tset,
+                                                        string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) <<
+    declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".add(" << elem << ");" << endl;
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_java_generator::generate_deserialize_list_element(ofstream& out,
+                                                         t_list* tlist,
+                                                         string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) <<
+    declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".add(" << elem << ");" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_java_generator::generate_serialize_field(ofstream& out,
+                                                t_field* tfield,
+                                                string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out,
+                              (t_struct*)type,
+                              prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out,
+                                 type,
+                                 prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = prefix + tfield->get_name();
+    indent(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 (((t_base_type*)type)->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        } else {
+          out << "writeString(" << name << ");";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_BYTE:
+        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 Java name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(" << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_java_generator::generate_serialize_struct(ofstream& out,
+                                                 t_struct* tstruct,
+                                                 string prefix) {
+  out <<
+    indent() << prefix << ".write(oprot);" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype  The type of container
+ * @param prefix String prefix for fields
+ */
+void t_java_generator::generate_serialize_container(ofstream& out,
+                                                    t_type* ttype,
+                                                    string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "oprot.writeMapBegin(new TMap(" <<
+      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+      prefix << ".size()));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "oprot.writeSetBegin(new TSet(" <<
+      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".size()));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "oprot.writeListBegin(new TList(" <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+      prefix << ".size()));" << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    indent(out) <<
+      "for (Map.Entry<" <<
+      type_name(((t_map*)ttype)->get_key_type(), true, false) << ", " <<
+      type_name(((t_map*)ttype)->get_val_type(), true, false) << "> " << iter <<
+      " : " <<
+      prefix << ".entrySet())";
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "for (" <<
+      type_name(((t_set*)ttype)->get_elem_type()) << " " << iter <<
+      " : " <<
+      prefix << ")";
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "for (" <<
+      type_name(((t_list*)ttype)->get_elem_type()) << " " << iter <<
+      " : " <<
+      prefix << ")";
+  }
+
+    scope_up(out);
+
+    if (ttype->is_map()) {
+      generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+    } else if (ttype->is_set()) {
+      generate_serialize_set_element(out, (t_set*)ttype, iter);
+    } else if (ttype->is_list()) {
+      generate_serialize_list_element(out, (t_list*)ttype, iter);
+    }
+
+    scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "oprot.writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "oprot.writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "oprot.writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ */
+void t_java_generator::generate_serialize_map_element(ofstream& out,
+                                                      t_map* tmap,
+                                                      string iter,
+                                                      string map) {
+  t_field kfield(tmap->get_key_type(), iter + ".getKey()");
+  generate_serialize_field(out, &kfield, "");
+  t_field vfield(tmap->get_val_type(), iter + ".getValue()");
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_java_generator::generate_serialize_set_element(ofstream& out,
+                                                      t_set* tset,
+                                                      string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_java_generator::generate_serialize_list_element(ofstream& out,
+                                                       t_list* tlist,
+                                                       string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Returns a Java type name
+ *
+ * @param ttype The type
+ * @param container Is the type going inside a container?
+ * @return Java type name, i.e. HashMap<Key,Value>
+ */
+string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
+  // In Java typedefs are just resolved to their real type
+  ttype = get_true_type(ttype);
+  string prefix;
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype, in_container);
+  } else if (ttype->is_enum()) {
+    return (in_container ? "Integer" : "int");
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*) ttype;
+    if (in_init) {
+      prefix = "HashMap";
+    } else {
+      prefix = "Map";
+    }
+    return prefix + "<" +
+      type_name(tmap->get_key_type(), true) + "," +
+      type_name(tmap->get_val_type(), true) + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*) ttype;
+    if (in_init) {
+      prefix = "HashSet<";
+    } else {
+      prefix = "Set<";
+    }
+    return prefix + type_name(tset->get_elem_type(), true) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*) ttype;
+    if (in_init) {
+      prefix = "ArrayList<";
+    } else {
+      prefix = "List<";
+    }
+    return prefix + type_name(tlist->get_elem_type(), true) + ">";
+  }
+
+  // Check for namespacing
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    string package = program->get_namespace("java");
+    if (!package.empty()) {
+      return package + "." + ttype->get_name();
+    }
+  }
+
+  return ttype->get_name();
+}
+
+/**
+ * Returns the C++ type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @param container Is it going in a Java container?
+ */
+string t_java_generator::base_type_name(t_base_type* type,
+                                        bool in_container) {
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (type->is_binary()) {
+      return "byte[]";
+    } else {
+      return "String";
+    }
+  case t_base_type::TYPE_BOOL:
+    return (in_container ? "Boolean" : "boolean");
+  case t_base_type::TYPE_BYTE:
+    return (in_container ? "Byte" : "byte");
+  case t_base_type::TYPE_I16:
+    return (in_container ? "Short" : "short");
+  case t_base_type::TYPE_I32:
+    return (in_container ? "Integer" : "int");
+  case t_base_type::TYPE_I64:
+    return (in_container ? "Long" : "long");
+  case t_base_type::TYPE_DOUBLE:
+    return (in_container ? "Double" : "double");
+  default:
+    throw "compiler error: no C++ name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_java_generator::declare_field(t_field* tfield, bool init) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = type_name(tfield->get_type()) + " " + tfield->get_name();
+  if (init) {
+    t_type* ttype = get_true_type(tfield->get_type());
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = null";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = 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:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+    }
+
+    } else if (ttype->is_enum()) {
+      result += " = 0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";;
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_java_generator::function_signature(t_function* tfunction,
+                                            string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  std::string result =
+    type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ") throws ";
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+    result += type_name((*x_iter)->get_type(), false, false) + ", ";
+  }
+  result += "TException";
+  return result;
+}
+
+/**
+ * Renders a comma separated field list, with type names
+ */
+string t_java_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;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_java_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();
+}
+
+/**
+ * Applies the correct style to a string based on the value of nocamel_style_
+ */
+std::string t_java_generator::get_cap_name(std::string name){
+  if (nocamel_style_) {
+    return "_" + name;
+  } else {
+    name[0] = toupper(name[0]);
+    return name;
+  }
+}
+
+string t_java_generator::constant_name(string name) {
+  string constant_name;
+
+  bool is_first = true;
+  bool was_previous_char_upper = false;
+  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
+    string::value_type character = (*iter);
+
+    bool is_upper = isupper(character);
+
+    if (is_upper && !is_first && !was_previous_char_upper) {
+      constant_name += '_';
+    }
+    constant_name += toupper(character);
+
+    is_first = false;
+    was_previous_char_upper = is_upper;
+  }
+
+  return constant_name;
+}
+
+/**
+ * Emits a JavaDoc comment if the provided object has a doc in Thrift
+ */
+void t_java_generator::generate_java_doc(ofstream &out,
+                                         t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out,
+      "/**\n",
+      " * ", tdoc->get_doc(),
+      " */\n");
+  }
+}
+
+/**
+ * Emits a JavaDoc comment if the provided function object has a doc in Thrift
+ */
+void t_java_generator::generate_java_doc(ofstream &out,
+                                         t_function* tfunction) {
+  if (tfunction->has_doc()) {
+    stringstream ss;
+    ss << tfunction->get_doc();
+    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;
+      ss << "\n@param " << p->get_name();
+      if (p->has_doc()) {
+        ss << " " << p->get_doc();
+      }
+    }
+    generate_docstring_comment(out,
+      "/**\n",
+      " * ", ss.str(),
+      " */\n");
+  }
+}
+
+void t_java_generator::generate_deep_copy_container(ofstream &out, std::string source_name_p1, std::string source_name_p2,
+                                                    std::string result_name, t_type* type) {
+
+  t_container* container = (t_container*)type;
+  std::string source_name;
+  if (source_name_p2 == "")
+      source_name = source_name_p1;
+  else
+      source_name = source_name_p1 + "." + source_name_p2;
+
+  indent(out) << type_name(type, true, false) << " " << result_name << " = new " << type_name(container, false, true) << "();" << endl;
+
+  std::string iterator_element_name = source_name_p1 + "_element";
+  std::string result_element_name = result_name + "_copy";
+
+  if(container->is_map()) {
+    t_type* key_type = ((t_map*)container)->get_key_type();
+    t_type* val_type = ((t_map*)container)->get_val_type();
+
+    indent(out) <<
+      "for (Map.Entry<" << type_name(key_type, true, false) << ", " << type_name(val_type, true, false) << "> " << iterator_element_name << " : " << source_name << ".entrySet()) {" << endl;
+    indent_up();
+
+    out << endl;
+
+    indent(out) << type_name(key_type, true, false) << " " << iterator_element_name << "_key = " << iterator_element_name << ".getKey();" << endl;
+    indent(out) << type_name(val_type, true, false) << " " << iterator_element_name << "_value = " << iterator_element_name << ".getValue();" << endl;
+
+    out << endl;
+
+    if (key_type->is_container()) {
+      generate_deep_copy_container(out, iterator_element_name + "_key", "", result_element_name + "_key", key_type);
+    } else {
+      indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = ";
+      generate_deep_copy_non_container(out, iterator_element_name + "_key", result_element_name + "_key", key_type);
+      out << ";" << endl;
+    }
+
+    out << endl;
+
+    if (val_type->is_container()) {
+      generate_deep_copy_container(out, iterator_element_name + "_value", "", result_element_name + "_value", val_type);
+    } else {
+      indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = ";
+      generate_deep_copy_non_container(out, iterator_element_name + "_value", result_element_name + "_value", val_type);
+      out << ";" << endl;
+    }
+
+    out << endl;
+
+    indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name << "_value);" << endl;
+
+    indent_down();
+    indent(out) << "}" << endl;
+
+  } else {
+    t_type* elem_type;
+
+    if (container->is_set()) {
+      elem_type = ((t_set*)container)->get_elem_type();
+    } else {
+      elem_type = ((t_list*)container)->get_elem_type();
+    }
+
+    indent(out)
+      << "for (" << type_name(elem_type, true, false) << " " << iterator_element_name << " : " << source_name << ") {" << endl;
+
+    indent_up();
+
+    if (elem_type->is_container()) {
+      // recursive deep copy
+      generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type);
+      indent(out) << result_name << ".add(" << result_element_name << ");" << endl;
+    } else {
+      // iterative copy
+      if(((t_base_type*)elem_type)->is_binary()){
+        indent(out) << "byte[] temp_binary_element = ";
+        generate_deep_copy_non_container(out, iterator_element_name, "temp_binary_element", elem_type);
+        out << ";" << endl;
+        indent(out) << result_name << ".add(temp_binary_element);" << endl;
+      }
+      else{
+        indent(out) << result_name << ".add(";
+        generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type);
+        out << ");" << endl;
+      }
+    }
+
+    indent_down();
+
+    indent(out) << "}" << endl;
+
+  }
+}
+
+void t_java_generator::generate_deep_copy_non_container(ofstream& out, std::string source_name, std::string dest_name, t_type* type) {
+  if (type->is_base_type() || type->is_enum() || type->is_typedef()) {
+    // binary fields need to be copied with System.arraycopy
+    if (((t_base_type*)type)->is_binary()){
+      out << "new byte[" << source_name << ".length];" << endl;
+      indent(out) << "System.arraycopy(" << source_name << ", 0, " << dest_name << ", 0, " << source_name << ".length)";
+    }
+    // everything else can be copied directly
+    else
+      out << source_name;
+  } else {
+    out << "new " << type_name(type, true, true) << "(" << source_name << ")";
+  }
+}
+
+std::string t_java_generator::generate_isset_check(t_field* field) {
+  return generate_isset_check(field->get_name());
+}
+
+std::string t_java_generator::generate_isset_check(std::string field_name) {
+  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
+}
+
+void t_java_generator::generate_isset_set(ofstream& out, t_field* field) {
+  if (!type_can_be_null(field->get_type())) {
+    indent(out) << "this.__isset." << field->get_name() << " = true;" << endl;
+  }
+}
+
+std::string t_java_generator::get_enum_class_name(t_type* type) {
+  string package = "";
+  t_program* program = type->get_program();
+  if (program != NULL && program != program_) {
+    package = program->get_namespace("java") + ".";
+  }
+  return package + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(java, "Java",
+"    beans:           Generate bean-style output files.\n"
+"    nocamel:         Do not use CamelCase field accessors with beans.\n"
+"    hashcode:        Generate quality hashCode methods.\n"
+);
diff --git a/compiler/cpp/src/generate/t_ocaml_generator.cc b/compiler/cpp/src/generate/t_ocaml_generator.cc
new file mode 100644
index 0000000..0405a04
--- /dev/null
+++ b/compiler/cpp/src/generate/t_ocaml_generator.cc
@@ -0,0 +1,1673 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include "t_oop_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * OCaml code generator.
+ *
+ */
+class t_ocaml_generator : public t_oop_generator {
+ public:
+  t_ocaml_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    out_dir_base_ = "gen-ocaml";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  /**
+   * Program-level generation functions
+   */
+  void generate_program  ();
+  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_ocaml_struct(t_struct* tstruct, bool is_exception);
+  void generate_ocaml_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
+  void generate_ocaml_struct_sig(std::ofstream& out, t_struct* tstruct, bool is_exception);
+  void generate_ocaml_struct_reader(std::ofstream& out, t_struct* tstruct);
+  void generate_ocaml_struct_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_ocaml_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_service_client    (t_service* tservice);
+  void generate_service_server    (t_service* tservice);
+  void generate_process_function  (t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix);
+
+  void generate_deserialize_struct       (std::ofstream &out,
+                                          t_struct*   tstruct);
+
+  void generate_deserialize_container    (std::ofstream &out,
+                                          t_type*     ttype);
+
+  void generate_deserialize_set_element  (std::ofstream &out,
+                                          t_set*      tset);
+
+
+  void generate_deserialize_list_element (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+  void generate_deserialize_type          (std::ofstream &out,
+                                           t_type* type);
+
+  void generate_serialize_field          (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string name= "");
+
+  void generate_serialize_struct         (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string kiter,
+                                          std::string viter);
+
+  void generate_serialize_set_element    (std::ofstream &out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string ocaml_autogen_comment();
+  std::string ocaml_imports();
+  std::string type_name(t_type* ttype);
+  std::string function_signature(t_function* tfunction, std::string prefix="");
+  std::string function_type(t_function* tfunc, bool method=false, bool options = false);
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string render_ocaml_type(t_type* type);
+
+
+ private:
+
+  /**
+   * File streams
+   */
+
+  std::ofstream f_types_;
+  std::ofstream f_consts_;
+  std::ofstream f_service_;
+
+  std::ofstream f_types_i_;
+  std::ofstream f_service_i_;
+
+};
+
+
+/*
+ * This is necessary because we want typedefs to appear later,
+ * after all the types have been declared.
+ */
+void t_ocaml_generator::generate_program() {
+  // Initialize the generator
+  init_generator();
+
+  // Generate enums
+  vector<t_enum*> enums = program_->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    generate_enum(*en_iter);
+  }
+
+  // Generate structs
+  vector<t_struct*> structs = program_->get_structs();
+  vector<t_struct*>::iterator st_iter;
+  for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) {
+    generate_struct(*st_iter);
+  }
+
+  // Generate xceptions
+  vector<t_struct*> xceptions = program_->get_xceptions();
+  vector<t_struct*>::iterator x_iter;
+  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+    generate_xception(*x_iter);
+  }
+
+  // Generate typedefs
+  vector<t_typedef*> typedefs = program_->get_typedefs();
+  vector<t_typedef*>::iterator td_iter;
+  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+    generate_typedef(*td_iter);
+  }
+
+  // Generate services
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    service_name_ = get_service_name(*sv_iter);
+    generate_service(*sv_iter);
+  }
+
+  // Generate constants
+  vector<t_const*> consts = program_->get_consts();
+  generate_consts(consts);
+
+  // Close the generator
+  close_generator();
+}
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_ocaml_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string f_types_name = get_out_dir()+program_name_+"_types.ml";
+  f_types_.open(f_types_name.c_str());
+  string f_types_i_name = get_out_dir()+program_name_+"_types.mli";
+  f_types_i_.open(f_types_i_name.c_str());
+
+  string f_consts_name = get_out_dir()+program_name_+"_consts.ml";
+  f_consts_.open(f_consts_name.c_str());
+
+  // Print header
+  f_types_ <<
+    ocaml_autogen_comment() << endl <<
+    ocaml_imports() << endl;
+  f_types_i_ <<
+    ocaml_autogen_comment() << endl <<
+    ocaml_imports() << endl;
+  f_consts_ <<
+    ocaml_autogen_comment() << endl <<
+    ocaml_imports() << endl <<
+    "open " << capitalize(program_name_)<<"_types"<< endl;
+}
+
+
+/**
+ * Autogen'd comment
+ */
+string t_ocaml_generator::ocaml_autogen_comment() {
+  return
+    std::string("(*\n") +
+    " Autogenerated by Thrift\n" +
+    "\n" +
+    " DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING\n" +
+    "*)\n";
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_ocaml_generator::ocaml_imports() {
+  return "open Thrift";
+}
+
+/**
+ * Closes the type files
+ */
+void t_ocaml_generator::close_generator() {
+  // Close types file
+  f_types_.close();
+}
+
+/**
+ * Generates a typedef. Ez.
+ *
+ * @param ttypedef The type definition
+ */
+void t_ocaml_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ <<
+    indent() << "type "<< decapitalize(ttypedef->get_symbolic()) << " = " << render_ocaml_type(ttypedef->get_type()) << endl << endl;
+  f_types_i_ <<
+    indent() << "type "<< decapitalize(ttypedef->get_symbolic()) << " = " << render_ocaml_type(ttypedef->get_type()) << endl << endl;
+}
+
+/**
+ * Generates code for an enumerated type.
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_ocaml_generator::generate_enum(t_enum* tenum) {
+  indent(f_types_) << "module " << capitalize(tenum->get_name()) << " = " << endl << "struct" << endl;
+  indent(f_types_i_) << "module " << capitalize(tenum->get_name()) << " : " << endl << "sig" << endl;
+  indent_up();
+  indent(f_types_) << "type t = " << endl;
+  indent(f_types_i_) << "type t = " << endl;
+  indent_up();
+  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) {
+    string name = capitalize((*c_iter)->get_name());
+    indent(f_types_) << "| " << name << endl;
+    indent(f_types_i_) << "| " << name << endl;
+  }
+  indent_down();
+
+  indent(f_types_) << "let to_i = function" << endl;
+  indent(f_types_i_) << "val to_i : t -> int" << endl;
+  indent_up();
+  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_ <<
+      indent() << "| " << name << " -> " << value << endl;
+  }
+  indent_down();
+
+  indent(f_types_) << "let of_i = function" << endl;
+  indent(f_types_i_) << "val of_i : int -> t" << endl;
+  indent_up();
+  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_ <<
+      indent() << "| " << value << " -> " << name << endl;
+  }
+  indent(f_types_) << "| _ -> raise Thrift_error" << endl;
+  indent_down();
+  indent_down();
+  indent(f_types_) << "end" << endl;
+  indent(f_types_i_) << "end" << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_ocaml_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = decapitalize(tconst->get_name());
+  t_const_value* value = tconst->get_value();
+
+  indent(f_consts_) << "let " << 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_ocaml_generator::render_const_value(t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream out;
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      out << value->get_integer() << "L";
+      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()) {
+    t_enum* tenum = (t_enum*)type;
+    vector<t_enum_value*> constants = tenum->get_constants();
+    vector<t_enum_value*>::iterator c_iter;
+    int val = -1;
+    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+      if ((*c_iter)->has_value()) {
+        val = (*c_iter)->get_value();
+      } else {
+        ++val;
+      }
+      if(val == value->get_integer()){
+        indent(out) << capitalize(tenum->get_name()) << "." << capitalize((*c_iter)->get_name());
+        break;
+      }
+    }
+  } else if (type->is_struct() || type->is_xception()) {
+    string cname = type_name(type);
+    string ct = tmp("_c");
+    out << endl;
+    indent_up();
+    indent(out) << "(let " << ct << " = new " << cname << " in" << endl;
+    indent_up();
+    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;
+    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();
+      }
+      string fname = v_iter->first->get_string();
+      out << indent();
+      out << ct <<"#set_" << fname << " ";
+      out << render_const_value(field_type, v_iter->second);
+      out << ";" << endl;
+    }
+    indent(out) << ct << ")";
+    indent_down();
+    indent_down();
+  } 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;
+    string hm = tmp("_hm");
+    out << endl;
+    indent_up();
+    indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl;
+    indent_up();
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(ktype, v_iter->first);
+      string val = render_const_value(vtype, v_iter->second);
+      indent(out) << "Hashtbl.add " << hm << " " << key << " " << val << ";" << endl;
+    }
+    indent(out) << hm << ")";
+    indent_down();
+    indent_down();
+  } else if (type->is_list()) {
+    t_type* etype;
+    etype = ((t_list*)type)->get_elem_type();
+    out << "[" << endl;
+    indent_up();
+    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) {
+      out << indent();
+      out << render_const_value(etype, *v_iter);
+      out << ";" << endl;
+    }
+    indent_down();
+    indent(out) << "]";
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    string hm = tmp("_hm");
+    indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl;
+    indent_up();
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(etype, *v_iter);
+      indent(out) << "Hashtbl.add " << hm << " " << val << " true;" << endl;
+    }
+    indent(out) << hm << ")" << endl;
+    indent_down();
+    out << endl;
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+/**
+ * Generates a "struct"
+ */
+void t_ocaml_generator::generate_struct(t_struct* tstruct) {
+  generate_ocaml_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct, but also has an exception declaration.
+ *
+ * @param txception The struct definition
+ */
+void t_ocaml_generator::generate_xception(t_struct* txception) {
+  generate_ocaml_struct(txception, true);
+}
+
+/**
+ * Generates an OCaml struct
+ */
+void t_ocaml_generator::generate_ocaml_struct(t_struct* tstruct,
+                                              bool is_exception) {
+  generate_ocaml_struct_definition(f_types_, tstruct, is_exception);
+  generate_ocaml_struct_sig(f_types_i_,tstruct,is_exception);
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_ocaml_generator::generate_ocaml_struct_definition(ofstream& out,
+                                                         t_struct* tstruct,
+                                                         bool is_exception) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  string tname = type_name(tstruct);
+  indent(out) << "class " << tname << " =" << endl;
+  indent(out) << "object (self)" << endl;
+
+  indent_up();
+
+  string x = tmp("_x");
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      string mname = decapitalize((*m_iter)->get_name());
+      indent(out) << "val mutable _" << mname << " : " << render_ocaml_type((*m_iter)->get_type()) << " option = None" << endl;
+      indent(out) << "method get_" << mname << " = _" << mname << endl;
+      indent(out) << "method grab_" << mname << " = match _"<<mname<<" with None->raise (Field_empty \""<<tname<<"."<<mname<<"\") | Some " << x <<" -> " << x << endl;
+      indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- Some " << x << endl;
+    }
+  }
+  generate_ocaml_struct_writer(out, tstruct);
+  indent_down();
+  indent(out) << "end" << endl;
+
+  if(is_exception){
+    indent(out) << "exception " << capitalize(tname) <<" of " << tname << endl;
+  }
+
+  generate_ocaml_struct_reader(out, tstruct);
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_ocaml_generator::generate_ocaml_struct_sig(ofstream& out,
+                                                  t_struct* tstruct,
+                                                  bool is_exception) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  string tname = type_name(tstruct);
+  indent(out) << "class " << tname << " :" << endl;
+  indent(out) << "object" << endl;
+
+  indent_up();
+
+  string x = tmp("_x");
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      string mname = decapitalize((*m_iter)->get_name());
+      string type = render_ocaml_type((*m_iter)->get_type());
+      indent(out) << "method get_" << mname << " : " << type << " option" << endl;
+      indent(out) << "method grab_" << mname << " : " << type << endl;
+      indent(out) << "method set_" << mname << " : " << type << " -> unit" << endl;
+    }
+  }
+  indent(out) << "method write : Protocol.t -> unit" << endl;
+  indent_down();
+  indent(out) << "end" << endl;
+
+  if(is_exception){
+    indent(out) << "exception " << capitalize(tname) <<" of " << tname << endl;
+  }
+
+  indent(out) << "val read_" << tname << " : Protocol.t -> " << tname << endl;
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_ocaml_generator::generate_ocaml_struct_reader(ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  string sname = type_name(tstruct);
+  string str = tmp("_str");
+  string t = tmp("_t");
+  string id = tmp("_id");
+  indent(out) <<
+    "let rec read_" << sname << " (iprot : Protocol.t) =" << endl;
+  indent_up();
+  indent(out) << "let " << str << " = new " << sname << " in" << endl;
+  indent_up();
+  indent(out) <<
+    "ignore(iprot#readStructBegin);" << endl;
+
+  // Loop over reading in fields
+  indent(out) <<
+    "(try while true do" << endl;
+  indent_up();
+  indent_up();
+
+  // Read beginning field marker
+  indent(out) <<
+    "let (_," << t <<","<<id<<") = iprot#readFieldBegin in" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) <<
+    "if " << t <<" = Protocol.T_STOP then" << endl;
+  indent_up();
+  indent(out) <<
+      "raise Break" << endl;
+    indent_down();
+    indent(out) << "else ();" << endl;
+
+    indent(out) << "(match " << id<<" with " << endl;
+    indent_up();
+    // Generate deserialization code for known cases
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      indent(out) << "| " << (*f_iter)->get_key() << " -> (";
+      out << "if " << t <<" = " << type_to_enum((*f_iter)->get_type()) << " then" << endl;
+      indent_up();
+      indent_up();
+      generate_deserialize_field(out, *f_iter,str);
+      indent_down();
+      out <<
+        indent() << "else" << endl <<
+        indent() << "  iprot#skip "<< t << ")" << endl;
+      indent_down();
+    }
+
+    // In the default case we skip the field
+    out <<
+      indent() << "| _ -> " << "iprot#skip "<<t<<");" << endl;
+    indent_down();
+    // Read field end marker
+    indent(out) << "iprot#readFieldEnd;" << endl;
+    indent_down();
+    indent(out) << "done; ()" << endl;
+    indent_down();
+    indent(out) << "with Break -> ());" << endl;
+
+    indent(out) <<
+      "iprot#readStructEnd;" << endl;
+
+    indent(out) << str << endl << endl;
+    indent_down();
+    indent_down();
+}
+
+void t_ocaml_generator::generate_ocaml_struct_writer(ofstream& out,
+                                               t_struct* tstruct) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+  string str = tmp("_str");
+  string f = tmp("_f");
+
+  indent(out) <<
+    "method write (oprot : Protocol.t) =" << endl;
+  indent_up();
+  indent(out) <<
+    "oprot#writeStructBegin \""<<name<<"\";" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    // Write field header
+    string mname = "_"+decapitalize((*f_iter)->get_name());
+    indent(out) <<
+      "(match " << mname << " with None -> () | Some _v -> " << endl;
+    indent_up();
+    indent(out) << "oprot#writeFieldBegin(\""<< (*f_iter)->get_name()<<"\","
+                <<type_to_enum((*f_iter)->get_type())<<","
+                <<(*f_iter)->get_key()<<");" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "_v");
+
+    // Write field closer
+    indent(out) << "oprot#writeFieldEnd" << endl;
+
+    indent_down();
+    indent(out) << ");" << endl;
+  }
+
+  // Write the struct map
+  out <<
+    indent() << "oprot#writeFieldStop;" << endl <<
+    indent() << "oprot#writeStructEnd" << endl;
+
+  indent_down();
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_ocaml_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_out_dir()+capitalize(service_name_)+".ml";
+  f_service_.open(f_service_name.c_str());
+  string f_service_i_name = get_out_dir()+capitalize(service_name_)+".mli";
+  f_service_i_.open(f_service_i_name.c_str());
+
+  f_service_ <<
+    ocaml_autogen_comment() << endl <<
+    ocaml_imports() << endl;
+  f_service_i_ <<
+    ocaml_autogen_comment() << endl <<
+    ocaml_imports() << endl;
+
+  /* if (tservice->get_extends() != NULL) {
+    f_service_ <<
+      "open " << capitalize(tservice->get_extends()->get_name()) << endl;
+    f_service_i_ <<
+      "open " << capitalize(tservice->get_extends()->get_name()) << endl;
+  }
+  */
+  f_service_ <<
+     "open " << capitalize(program_name_) << "_types" << endl <<
+    endl;
+
+  f_service_i_ <<
+     "open " << capitalize(program_name_) << "_types" << endl <<
+    endl;
+
+  // Generate the three main parts of the service
+  generate_service_helpers(tservice);
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+
+
+  // Close service file
+  f_service_.close();
+  f_service_i_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_ocaml_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;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_ocaml_struct_definition(f_service_, ts, false);
+    generate_ocaml_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_ocaml_generator::generate_ocaml_function_helpers(t_function* tfunction) {
+  t_struct result(program_, decapitalize(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_ocaml_struct_definition(f_service_, &result, false);
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_ocaml_generator::generate_service_interface(t_service* tservice) {
+  f_service_ <<
+    indent() << "class virtual iface =" << endl << "object (self)" << endl;
+  f_service_i_ <<
+    indent() << "class virtual iface :" << endl << "object" << endl;
+
+  indent_up();
+
+  if (tservice->get_extends() != NULL) {
+    string extends = type_name(tservice->get_extends());
+    indent(f_service_) << "inherit " << extends << ".iface" << endl;
+    indent(f_service_i_) << "inherit " << extends << ".iface" << endl;
+  }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string ft = function_type(*f_iter,true,true);
+    f_service_ <<
+      indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : " << ft  << endl;
+    f_service_i_ <<
+      indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : " << ft << endl;
+  }
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+  indent(f_service_i_) << "end" << endl << endl;
+}
+
+/**
+ * Generates a service client definition. Note that in OCaml, the client doesn't implement iface. This is because
+ * The client does not (and should not have to) deal with arguments being None.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_ocaml_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  indent(f_service_) <<
+    "class client (iprot : Protocol.t) (oprot : Protocol.t) =" << endl << "object (self)" << endl;
+  indent(f_service_i_) <<
+    "class client : Protocol.t -> Protocol.t -> " << endl << "object" << endl;
+  indent_up();
+
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    indent(f_service_) << "inherit " << extends << ".client iprot oprot as super" << endl;
+    indent(f_service_i_) << "inherit " << extends << ".client" << endl;
+  }
+  indent(f_service_) << "val mutable seqid = 0" << endl;
+
+
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    indent(f_service_) <<
+      "method " << function_signature(*f_iter) << " = " << endl;
+    indent(f_service_i_) <<
+      "method " << decapitalize((*f_iter)->get_name()) << " : " << function_type(*f_iter,true,false) << endl;
+    indent_up();
+    indent(f_service_) <<
+      "self#send_" << funname;
+
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << " " << decapitalize((*fld_iter)->get_name());
+    }
+    f_service_ << ";" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      f_service_ <<
+        "self#recv_" << funname << endl;
+    }
+    indent_down();
+
+    indent(f_service_) <<
+      "method private send_" << function_signature(*f_iter) << " = " << endl;
+    indent_up();
+
+    std::string argsname = decapitalize((*f_iter)->get_name() + "_args");
+
+    // Serialize the request header
+    f_service_ <<
+      indent() << "oprot#writeMessageBegin (\"" << (*f_iter)->get_name() << "\", Protocol.CALL, seqid);" << endl;
+
+    f_service_ <<
+      indent() << "let args = new " << argsname << " in" << endl;
+    indent_up();
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ <<
+        indent() << "args#set_" << (*fld_iter)->get_name() << " " << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    // Write to the stream
+    f_service_ <<
+      indent() << "args#write oprot;" << endl <<
+      indent() << "oprot#writeMessageEnd;" << endl <<
+      indent() << "oprot#getTransport#flush" << endl;
+
+    indent_down();
+    indent_down();
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = decapitalize((*f_iter)->get_name() + "_result");
+      t_struct noargs(program_);
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      f_service_ <<
+        indent() << "method private " << function_signature(&recv_function) << " =" << endl;
+      indent_up();
+
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+
+      f_service_ <<
+        indent() << "let (fname, mtype, rseqid) = iprot#readMessageBegin in" << endl;
+      indent_up();
+      f_service_ <<
+        indent() << "(if mtype = Protocol.EXCEPTION then" << endl <<
+        indent() << "  let x = Application_Exn.read iprot in" << endl;
+      indent_up();
+      f_service_ <<
+        indent() << "  (iprot#readMessageEnd;" <<
+        indent() << "   raise (Application_Exn.E x))" << endl;
+      indent_down();
+      f_service_ <<
+        indent() << "else ());" << endl;
+      string res = "_";
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+
+      if (!(*f_iter)->get_returntype()->is_void() || xceptions.size() > 0) {
+        res = "result";
+      }
+      f_service_ <<
+        indent() << "let "<<res<<" = read_" << resultname << " iprot in" << endl;
+      indent_up();
+      f_service_ <<
+        indent() << "iprot#readMessageEnd;" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "match result#get_success with Some v -> v | None -> (" << endl;
+        indent_up();
+      }
+
+
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "(match result#get_" << (*x_iter)->get_name() << " with None -> () | Some _v ->" << endl;
+        indent(f_service_) << "  raise (" << capitalize(type_name((*x_iter)->get_type())) << " _v));" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "()" << endl;
+      } else {
+        f_service_ <<
+          indent() << "raise (Application_Exn.E (Application_Exn.create Application_Exn.MISSING_RESULT \"" << (*f_iter)->get_name() << " failed: unknown result\")))" << endl;
+        indent_down();
+      }
+
+      // Close function
+      indent_down();
+      indent_down();
+      indent_down();
+    }
+  }
+
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+  indent(f_service_i_) << "end" << endl << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_ocaml_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+
+  // Generate the header portion
+  indent(f_service_) <<
+    "class processor (handler : iface) =" << endl << indent() << "object (self)" << endl;
+  indent(f_service_i_) <<
+    "class processor : iface ->" << endl << indent() << "object" << endl;
+  indent_up();
+
+  f_service_ <<
+     indent() << "inherit Processor.t" << endl <<
+    endl;
+  f_service_i_ <<
+     indent() << "inherit Processor.t" << endl <<
+    endl;
+  string extends = "";
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    indent(f_service_) << "inherit " + extends + ".processor (handler :> " + extends + ".iface)" << endl;
+    indent(f_service_i_) << "inherit " + extends + ".processor" << endl;
+  }
+
+  if (extends.empty()) {
+    indent(f_service_) << "val processMap = Hashtbl.create " << functions.size() << endl;
+  }
+  indent(f_service_i_) << "val processMap : (string, int * Protocol.t * Protocol.t -> unit) Hashtbl.t" << endl;
+
+  // Generate the server implementation
+  indent(f_service_) <<
+    "method process iprot oprot =" << endl;
+  indent(f_service_i_) <<
+    "method process : Protocol.t -> Protocol.t -> bool" << endl;
+  indent_up();
+
+  f_service_ <<
+    indent() << "let (name, typ, seqid)  = iprot#readMessageBegin in" << endl;
+  indent_up();
+  // TODO(mcslee): validate message
+
+  // HOT: dictionary function lookup
+  f_service_ <<
+    indent() << "if Hashtbl.mem processMap name then" << endl <<
+    indent() << "  (Hashtbl.find processMap name) (seqid, iprot, oprot)" << endl <<
+    indent() << "else (" << endl <<
+    indent() << "  iprot#skip(Protocol.T_STRUCT);" << endl <<
+    indent() << "  iprot#readMessageEnd;" << endl <<
+    indent() << "  let x = Application_Exn.create Application_Exn.UNKNOWN_METHOD (\"Unknown function \"^name) in" << endl <<
+    indent() << "    oprot#writeMessageBegin(name, Protocol.EXCEPTION, seqid);" << endl <<
+    indent() << "    x#write oprot;" << endl <<
+    indent() << "    oprot#writeMessageEnd;" << endl <<
+    indent() << "    oprot#getTransport#flush" << endl <<
+    indent() << ");" << endl;
+
+  // Read end of args field, the T_STOP, and the struct close
+  f_service_ <<
+    indent() << "true" << endl;
+  indent_down();
+  indent_down();
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent(f_service_) << "initializer" << endl;
+  indent_up();
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      indent() << "Hashtbl.add processMap \"" << (*f_iter)->get_name() << "\" self#process_" << (*f_iter)->get_name() << ";" << endl;
+  }
+  indent_down();
+
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+  indent(f_service_i_) << "end" << endl << endl;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_ocaml_generator::generate_process_function(t_service* tservice,
+                                               t_function* tfunction) {
+  // Open function
+  indent(f_service_) <<
+    "method private process_" << tfunction->get_name() <<
+    " (seqid, iprot, oprot) =" << endl;
+  indent_up();
+
+  string argsname = decapitalize(tfunction->get_name()) + "_args";
+  string resultname = decapitalize(tfunction->get_name()) + "_result";
+
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  string args = "args";
+  if(fields.size() == 0){
+    args="_";
+  }
+
+  f_service_ <<
+    indent() << "let "<<args<<" = read_" << argsname << " iprot in" << endl;
+  indent_up();
+  f_service_ <<
+    indent() << "iprot#readMessageEnd;" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "let result = new " << resultname << " in" << endl;
+    indent_up();
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ <<
+      indent() << "(try" << endl;
+    indent_up();
+  }
+
+
+
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result#set_success ";
+  }
+  f_service_ <<
+    "(handler#" << tfunction->get_name();
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    f_service_ <<  " args#get_" << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+
+  if (xceptions.size() > 0) {
+    indent_down();
+    indent(f_service_) << "with" <<endl;
+    indent_up();
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ <<
+        indent() << "| " << capitalize(type_name((*x_iter)->get_type())) << " " << (*x_iter)->get_name() << " -> " << endl;
+      indent_up();
+      indent_up();
+      if(!tfunction->is_oneway()){
+           f_service_ <<
+             indent() << "result#set_" << (*x_iter)->get_name() << " " << (*x_iter)->get_name() << endl;
+      } else {
+        indent(f_service_) << "()";
+      }
+      indent_down();
+      indent_down();
+    }
+    indent_down();
+    f_service_ << indent() << ");" << endl;
+  }
+
+
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "()" << endl;
+    indent_down();
+    indent_down();
+    return;
+  }
+
+  f_service_ <<
+    indent() << "oprot#writeMessageBegin (\"" << tfunction->get_name() << "\", Protocol.REPLY, seqid);" << endl <<
+    indent() << "result#write oprot;" << endl <<
+    indent() << "oprot#writeMessageEnd;" << endl <<
+    indent() << "oprot#getTransport#flush" << endl;
+
+  // Close function
+  indent_down();
+  indent_down();
+  indent_down();
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_ocaml_generator::generate_deserialize_field(ofstream &out,
+                                                   t_field* tfield,
+                                                   string prefix){
+  t_type* type = tfield->get_type();
+
+
+  string name = decapitalize(tfield->get_name());
+  indent(out) << prefix << "#set_"<<name << " ";
+  generate_deserialize_type(out,type);
+  out << endl;
+}
+
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_ocaml_generator::generate_deserialize_type(ofstream &out,
+                                                   t_type* type){
+  type = get_true_type(type);
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE";
+  }
+
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type);
+  } else if (type->is_base_type()) {
+    out << "iprot#";
+    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";
+      break;
+    case t_base_type::TYPE_STRING:
+      out << "readString";
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "readBool";
+      break;
+    case t_base_type::TYPE_BYTE:
+      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 PHP name for base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    string ename = capitalize(type->get_name());
+    out << "(" <<ename << ".of_i iprot#readI32)";
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n",
+           type->get_name().c_str());
+  }
+}
+
+
+/**
+ * Generates an unserializer for a struct, calling read()
+ */
+void t_ocaml_generator::generate_deserialize_struct(ofstream &out,
+                                                  t_struct* tstruct) {
+  string name = decapitalize(tstruct->get_name());
+  out << "(read_" << name << " iprot)";
+
+}
+
+/**
+ * Serialize a container by writing out the header followed by
+ * data and then a footer.
+ */
+void t_ocaml_generator::generate_deserialize_container(ofstream &out,
+                                                    t_type* ttype) {
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+  string con = tmp("_con");
+
+  t_field fsize(g_type_i32, size);
+  t_field fktype(g_type_byte, ktype);
+  t_field fvtype(g_type_byte, vtype);
+  t_field fetype(g_type_byte, etype);
+
+  out << endl;
+  indent_up();
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out) << "(let ("<<ktype<<","<<vtype<<","<<size<<") = iprot#readMapBegin in" << endl;
+    indent(out) << "let "<<con<<" = Hashtbl.create "<<size<<" in" << endl;
+    indent_up();
+    indent(out) << "for i = 1 to "<<size<<" do" <<endl;
+    indent_up();
+    indent(out) << "let _k = ";
+    generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
+    out << " in" << endl;
+    indent(out) << "let _v = ";
+    generate_deserialize_type(out,((t_map*)ttype)->get_val_type());
+    out << " in" << endl;
+    indent_up();
+    indent(out) << "Hashtbl.add "<<con<< " _k _v" << endl;
+    indent_down();
+    indent_down();
+    indent(out) << "done; iprot#readMapEnd; "<<con<<")";
+    indent_down();
+  } else if (ttype->is_set()) {
+    indent(out) << "(let ("<<etype<<","<<size<<") = iprot#readSetBegin in" << endl;
+    indent(out) << "let "<<con<<" = Hashtbl.create "<<size<<" in" << endl;
+    indent_up();
+    indent(out) << "for i = 1 to "<<size<<" do" <<endl;
+    indent_up();
+    indent(out) << "Hashtbl.add "<<con<<" ";
+    generate_deserialize_type(out,((t_set*)ttype)->get_elem_type());
+    out << " true" << endl;
+    indent_down();
+    indent(out) << "done; iprot#readSetEnd; "<<con<<")";
+    indent_down();
+  } else if (ttype->is_list()) {
+    indent(out) << "(let ("<<etype<<","<<size<<") = iprot#readListBegin in" << endl;
+    indent_up();
+    indent(out) << "let "<<con<<" = (Array.to_list (Array.init "<<size<<" (fun _ -> ";
+    generate_deserialize_type(out,((t_list*)ttype)->get_elem_type());
+    out << "))) in" << endl;
+    indent_up();
+    indent(out) << "iprot#readListEnd; "<<con<<")";
+    indent_down();
+    indent_down();
+  }
+  indent_down();
+}
+
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_ocaml_generator::generate_serialize_field(ofstream &out,
+                                                 t_field* tfield,
+                                                 string name) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      tfield->get_name();
+  }
+
+  if(name.length() == 0){
+    name = decapitalize(tfield->get_name());
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out,
+                              (t_struct*)type,
+                              name);
+  } else if (type->is_container()) {
+    generate_serialize_container(out,
+                                 type,
+                                 name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+
+    indent(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:
+        out << "writeString(" << name << ")";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ")";
+       break;
+      case t_base_type::TYPE_BYTE:
+        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 ocaml name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      string ename = capitalize(type->get_name());
+      out << "writeI32("<<ename<<".to_i " << name << ")";
+    }
+
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+  out << ";" << endl;
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_ocaml_generator::generate_serialize_struct(ofstream &out,
+                                               t_struct* tstruct,
+                                               string prefix) {
+  indent(out) << prefix << "#write(oprot)";
+}
+
+void t_ocaml_generator::generate_serialize_container(ofstream &out,
+                                                  t_type* ttype,
+                                                  string prefix) {
+  if (ttype->is_map()) {
+    indent(out) << "oprot#writeMapBegin("<< type_to_enum(((t_map*)ttype)->get_key_type()) << ",";
+    out << type_to_enum(((t_map*)ttype)->get_val_type()) << ",";
+    out << "Hashtbl.length " << prefix << ");" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "oprot#writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ",";
+    out << "Hashtbl.length " << prefix << ");" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "oprot#writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ",";
+    out << "List.length " << prefix << ");" << endl;
+  }
+
+  if (ttype->is_map()) {
+    string kiter = tmp("_kiter");
+    string viter = tmp("_viter");
+    indent(out) << "Hashtbl.iter (fun "<<kiter<<" -> fun " << viter << " -> " << endl;
+    indent_up();
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    indent_down();
+    indent(out) << ") " << prefix << ";" << endl;
+  } else if (ttype->is_set()) {
+    string iter = tmp("_iter");
+    indent(out) << "Hashtbl.iter (fun "<<iter<<" -> fun _ -> ";
+    indent_up();
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    indent_down();
+    indent(out) << ") " << prefix << ";" << endl;
+  } else if (ttype->is_list()) {
+    string iter = tmp("_iter");
+    indent(out) << "List.iter (fun "<<iter<<" -> ";
+    indent_up();
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    indent_down();
+    indent(out) << ") " << prefix << ";" <<  endl;
+  }
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "oprot#writeMapEnd";
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "oprot#writeSetEnd";
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "oprot#writeListEnd";
+  }
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_ocaml_generator::generate_serialize_map_element(ofstream &out,
+                                                     t_map* tmap,
+                                                     string kiter,
+                                                     string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield);
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_ocaml_generator::generate_serialize_set_element(ofstream &out,
+                                                     t_set* tset,
+                                                     string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_ocaml_generator::generate_serialize_list_element(ofstream &out,
+                                                      t_list* tlist,
+                                                      string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+
+
+/**
+ * Renders a function signature of the form 'name args'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_ocaml_generator::function_signature(t_function* tfunction,
+                                           string prefix) {
+  return
+    prefix + decapitalize(tfunction->get_name()) +
+    " " +  argument_list(tfunction->get_arglist());
+}
+
+string t_ocaml_generator::function_type(t_function* tfunc, bool method, bool options){
+  string result="";
+
+  const vector<t_field*>& fields = tfunc->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    result += render_ocaml_type((*f_iter)->get_type());
+    if(options)
+      result += " option";
+    result += " -> ";
+  }
+  if(fields.empty() && !method){
+    result += "unit -> ";
+  }
+  result += render_ocaml_type(tfunc->get_returntype());
+  return result;
+}
+
+/**
+ * Renders a field list
+ */
+string t_ocaml_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;
+    } else {
+      result += " ";
+    }
+    result += (*f_iter)->get_name();
+  }
+  return result;
+}
+
+string t_ocaml_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    if (!ttype->is_service()) {
+      prefix = capitalize(program->get_name()) + "_types.";
+    }
+  }
+
+  string name = ttype->get_name();
+  if(ttype->is_service()){
+    name = capitalize(name);
+  } else {
+    name = decapitalize(name);
+  }
+  return prefix + name;
+}
+
+/**
+ * Converts the parse type to a Protocol.t_type enum
+ */
+string t_ocaml_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:
+      return "Protocol.T_VOID";
+    case t_base_type::TYPE_STRING:
+      return "Protocol.T_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "Protocol.T_BOOL";
+    case t_base_type::TYPE_BYTE:
+      return "Protocol.T_BYTE";
+    case t_base_type::TYPE_I16:
+      return "Protocol.T_I16";
+    case t_base_type::TYPE_I32:
+      return "Protocol.T_I32";
+    case t_base_type::TYPE_I64:
+      return "Protocol.T_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "Protocol.T_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "Protocol.T_I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "Protocol.T_STRUCT";
+  } else if (type->is_map()) {
+    return "Protocol.T_MAP";
+  } else if (type->is_set()) {
+    return "Protocol.T_SET";
+  } else if (type->is_list()) {
+    return "Protocol.T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Converts the parse type to an ocaml type
+ */
+string t_ocaml_generator::render_ocaml_type(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:
+      return "unit";
+    case t_base_type::TYPE_STRING:
+      return "string";
+    case t_base_type::TYPE_BOOL:
+      return "bool";
+    case t_base_type::TYPE_BYTE:
+      return "int";
+    case t_base_type::TYPE_I16:
+      return "int";
+    case t_base_type::TYPE_I32:
+      return "int";
+    case t_base_type::TYPE_I64:
+      return "Int64.t";
+    case t_base_type::TYPE_DOUBLE:
+      return "float";
+    }
+  } else if (type->is_enum()) {
+    return capitalize(((t_enum*)type)->get_name())+".t";
+  } else if (type->is_struct() || type->is_xception()) {
+    return type_name((t_struct*)type);
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    return "("+render_ocaml_type(ktype)+","+render_ocaml_type(vtype)+") Hashtbl.t";
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    return "("+render_ocaml_type(etype)+",bool) Hashtbl.t";
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    return render_ocaml_type(etype)+" list";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+
+THRIFT_REGISTER_GENERATOR(ocaml, "OCaml", "");
diff --git a/compiler/cpp/src/generate/t_oop_generator.h b/compiler/cpp/src/generate/t_oop_generator.h
new file mode 100644
index 0000000..bf75786
--- /dev/null
+++ b/compiler/cpp/src/generate/t_oop_generator.h
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_OOP_GENERATOR_H
+#define T_OOP_GENERATOR_H
+
+#include <string>
+#include <iostream>
+
+#include "globals.h"
+#include "t_generator.h"
+
+#include <algorithm>
+
+/**
+ * Class with utility methods shared across common object oriented languages.
+ * Specifically, most of this stuff is for C++/Java.
+ *
+ */
+class t_oop_generator : public t_generator {
+ public:
+  t_oop_generator(t_program* program) :
+    t_generator(program) {}
+
+  /**
+   * Scoping, using curly braces!
+   */
+
+  void scope_up(std::ostream& out) {
+    indent(out) << "{" << std::endl;
+    indent_up();
+  }
+
+  void scope_down(std::ostream& out) {
+    indent_down();
+    indent(out) << "}" << std::endl;
+  }
+
+  std::string upcase_string(std::string original) {
+    std::transform(original.begin(), original.end(), original.begin(), (int(*)(int)) toupper);
+    return original;
+  }
+
+  /**
+   * Generates a comment about this code being autogenerated, using C++ style
+   * comments, which are also fair game in Java / PHP, yay!
+   *
+   * @return C-style comment mentioning that this file is autogenerated.
+   */
+  virtual std::string 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";
+  }
+};
+
+#endif
+
diff --git a/compiler/cpp/src/generate/t_perl_generator.cc b/compiler/cpp/src/generate/t_perl_generator.cc
new file mode 100644
index 0000000..ae204fd
--- /dev/null
+++ b/compiler/cpp/src/generate/t_perl_generator.cc
@@ -0,0 +1,1815 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <list>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "t_oop_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * PERL code generator.
+ *
+ */
+class t_perl_generator : public t_oop_generator {
+ public:
+  t_perl_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    out_dir_base_ = "gen-perl";
+    escape_['$'] = "\\$";
+    escape_['@'] = "\\@";
+  }
+
+  /**
+   * 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);
+
+  /**
+   * Structs!
+   */
+
+  void generate_perl_struct(t_struct* tstruct, bool is_exception);
+  void generate_perl_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
+  void generate_perl_struct_reader(std::ofstream& out, t_struct* tstruct);
+  void generate_perl_struct_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_perl_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_service_rest      (t_service* tservice);
+  void generate_service_client    (t_service* tservice);
+  void generate_service_processor (t_service* tservice);
+  void generate_process_function  (t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="",
+                                          bool inclass=false);
+
+  void generate_deserialize_struct       (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_deserialize_container    (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_deserialize_set_element  (std::ofstream &out,
+                                          t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+
+  void generate_serialize_field          (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_serialize_struct         (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string kiter,
+                                          std::string viter);
+
+  void generate_serialize_set_element    (std::ofstream &out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string perl_includes();
+  std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
+  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 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";
+  }
+
+  void perl_namespace_dirs(t_program* p, std::list<std::string>& dirs) {
+    std::string ns = p->get_namespace("perl");
+    std::string::size_type loc;
+
+    if (ns.size() > 0) {
+      while ((loc = ns.find(".")) != std::string::npos) {
+        dirs.push_back(ns.substr(0, loc));
+        ns = ns.substr(loc+1);
+      }
+    }
+
+    if (ns.size() > 0) {
+      dirs.push_back(ns);
+    }
+  }
+
+  std::string perl_namespace(t_program* p) {
+    std::string ns = p->get_namespace("perl");
+    std::string result = "";
+    std::string::size_type loc;
+
+    if (ns.size() > 0) {
+      while ((loc = ns.find(".")) != std::string::npos) {
+        result += ns.substr(0, loc);
+        result += "::";
+        ns = ns.substr(loc+1);
+      }
+
+      if (ns.size() > 0) {
+        result += ns + "::";
+      }
+    }
+
+    return result;
+  }
+
+  std::string get_namespace_out_dir() {
+    std::string outdir = get_out_dir();
+    std::list<std::string> dirs;
+    perl_namespace_dirs(program_, dirs);
+    std::list<std::string>::iterator it;
+    for (it = dirs.begin(); it != dirs.end(); it++) {
+      outdir += *it + "/";
+    }
+    return outdir;
+  }
+
+ private:
+
+  /**
+   * File streams
+   */
+  std::ofstream f_types_;
+  std::ofstream f_consts_;
+  std::ofstream f_helpers_;
+  std::ofstream f_service_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_perl_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  string outdir = get_out_dir();
+  std::list<std::string> dirs;
+  perl_namespace_dirs(program_, dirs);
+  std::list<std::string>::iterator it;
+  for (it = dirs.begin(); it != dirs.end(); it++) {
+      outdir += *it + "/";
+      MKDIR(outdir.c_str());
+  }
+
+  // Make output file
+  string f_types_name = outdir+"Types.pm";
+  f_types_.open(f_types_name.c_str());
+  string f_consts_name = outdir+"Constants.pm";
+  f_consts_.open(f_consts_name.c_str());
+
+  // Print header
+  f_types_ <<
+    autogen_comment() <<
+    perl_includes();
+
+  // Print header
+  f_consts_ <<
+    autogen_comment() <<
+    "package "<< perl_namespace(program_) <<"Constants;"<<endl<<
+    perl_includes() <<
+    endl;
+}
+
+/**
+ * Prints standard java imports
+ */
+string t_perl_generator::perl_includes() {
+  string inc;
+
+  inc  = "require 5.6.0;\n";
+  inc += "use strict;\n";
+  inc += "use warnings;\n";
+  inc += "use Thrift;\n\n";
+
+  return inc;
+}
+
+/**
+ * Close up (or down) some filez.
+ */
+void t_perl_generator::close_generator() {
+  // Close types file
+  f_types_ << "1;" << endl;
+  f_types_.close();
+
+  f_consts_ << "1;" << endl;
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. This is not done in PERL, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_perl_generator::generate_typedef(t_typedef* ttypedef) {}
+
+/**
+ * Generates code for an enumerated type. Since define is expensive to lookup
+ * in PERL, we use a global array for this.
+ *
+ * @param tenum The enumeration
+ */
+void t_perl_generator::generate_enum(t_enum* tenum) {
+  f_types_ << "package " << perl_namespace(program_) <<tenum->get_name()<<";"<<endl;
+
+  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;
+    }
+
+    f_types_ << "use constant "<<(*c_iter)->get_name() << " => " << value << ";" << endl;
+  }
+}
+
+/**
+ * Generate a constant value
+ */
+void t_perl_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_consts_ << "use constant " << name << " => ";
+  f_consts_ << render_const_value(type, value);
+  f_consts_ << ";" << 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_perl_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+
+  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_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "1" : "0");
+      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()) {
+    out << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << "new " << perl_namespace(type->get_program()) << type->get_name() << "({" << endl;
+    indent_up();
+    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;
+    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();
+      }
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " => ";
+      out << render_const_value(field_type, v_iter->second);
+      out << ",";
+      out << endl;
+    }
+
+    out << "})";
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    out << "{" << endl;
+
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << render_const_value(ktype, v_iter->first);
+      out << " => ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
+    }
+
+    out << "}";
+  } 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();
+    }
+    out << "[" << endl;
+    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) {
+
+      out << render_const_value(etype, *v_iter);
+      if (type->is_set()) {
+        out << " => 1";
+      }
+      out << "," << endl;
+    }
+    out << "]";
+  }
+  return out.str();
+}
+
+/**
+ * Make a struct
+ */
+void t_perl_generator::generate_struct(t_struct* tstruct) {
+  generate_perl_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_perl_generator::generate_xception(t_struct* txception) {
+  generate_perl_struct(txception, true);
+}
+
+/**
+ * Structs can be normal or exceptions.
+ */
+void t_perl_generator::generate_perl_struct(t_struct* tstruct,
+                                            bool is_exception) {
+  generate_perl_struct_definition(f_types_, tstruct, is_exception);
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is nothing in PERL
+ * where the objects are all just associative arrays (unless of course we
+ * decide to start using objects for them...)
+ *
+ * @param tstruct The struct definition
+ */
+void t_perl_generator::generate_perl_struct_definition(ofstream& out,
+                                                       t_struct* tstruct,
+                                                       bool is_exception) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out <<
+      "package " << perl_namespace(tstruct->get_program()) << tstruct->get_name() <<";\n";
+  if (is_exception) {
+    out << "use base('Thrift::TException');\n";
+  }
+
+  //Create simple acessor methods
+  out << "use Class::Accessor;\n";
+  out << "use base('Class::Accessor');\n";
+
+  if (members.size() > 0) {
+      out << perl_namespace(tstruct->get_program()) << tstruct->get_name() <<"->mk_accessors( qw( ";
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+          t_type* t = get_true_type((*m_iter)->get_type());
+          if (!t->is_xception()) {
+              out << (*m_iter)->get_name() << " ";
+          }
+      }
+
+      out << ") );\n";
+  }
+
+
+  // new()
+  out << "sub new {\n";
+  indent_up();
+  out << "my $classname = shift;\n";
+  out << "my $self      = {};\n";
+  out << "my $vals      = shift || {};\n";
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string dval = "undef";
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
+      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
+    }
+    out <<
+      "$self->{" << (*m_iter)->get_name() << "} = " << dval << ";" << endl;
+  }
+
+  // Generate constructor from array
+  if (members.size() > 0) {
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
+        indent(out) << "$self->{" << (*m_iter)->get_name() << "} = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
+      }
+    }
+
+    out << indent() << "if (UNIVERSAL::isa($vals,'HASH')) {" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out <<
+        indent() << "if (defined $vals->{" << (*m_iter)->get_name() << "}) {" << endl <<
+        indent() << "  $self->{" << (*m_iter)->get_name() << "} = $vals->{" << (*m_iter)->get_name() << "};" << endl <<
+        indent() << "}" << endl;
+    }
+    indent_down();
+    out <<
+      indent() << "}" << endl;
+
+  }
+
+  out << "return bless($self,$classname);\n";
+  indent_down();
+  out << "}\n\n";
+
+  out <<
+    "sub getName {" << endl <<
+    indent() << "  return '" << tstruct->get_name() << "';" << endl <<
+    indent() << "}" << endl <<
+    endl;
+
+  generate_perl_struct_reader(out, tstruct);
+  generate_perl_struct_writer(out, tstruct);
+
+}
+
+/**
+ * Generates the read() method for a struct
+ */
+void t_perl_generator::generate_perl_struct_reader(ofstream& out,
+                                                   t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << "sub read {" <<endl;
+
+  indent_up();
+
+  out <<
+    indent() << "my $self  = shift;" <<endl <<
+    indent() << "my $input = shift;" <<endl <<
+    indent() << "my $xfer  = 0;" << endl <<
+    indent() << "my $fname;"     << endl <<
+    indent() << "my $ftype = 0;" << endl <<
+    indent() << "my $fid   = 0;" << endl;
+
+  indent(out) << "$xfer += $input->readStructBegin(\\$fname);" << endl;
+
+
+  // Loop over reading in fields
+  indent(out) << "while (1) " << endl;
+
+  scope_up(out);
+
+  indent(out) << "$xfer += $input->readFieldBegin(\\$fname, \\$ftype, \\$fid);" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if ($ftype == TType::STOP) {" << endl;
+  indent_up();
+  indent(out) << "last;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Switch statement on the field we are reading
+  indent(out) << "SWITCH: for($fid)" << endl;
+
+  scope_up(out);
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+
+    indent(out) << "/^" << (*f_iter)->get_key() << "$/ && do{";
+    indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+
+    indent_up();
+    generate_deserialize_field(out, *f_iter, "self->");
+    indent_down();
+
+    indent(out) << "} else {" << endl;
+
+    indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
+
+    out <<
+      indent() << "}" << endl <<
+      indent() << "last; };" << endl;
+
+  }
+  // In the default case we skip the field
+
+  indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
+
+  scope_down(out);
+
+  indent(out) << "$xfer += $input->readFieldEnd();" << endl;
+
+  scope_down(out);
+
+  indent(out) << "$xfer += $input->readStructEnd();" << endl;
+
+  indent(out) << "return $xfer;" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates the write() method for a struct
+ */
+void t_perl_generator::generate_perl_struct_writer(ofstream& out,
+                                                   t_struct* tstruct) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << "sub write {" << endl;
+
+  indent_up();
+  indent(out) << "my $self   = shift;"<<endl;
+  indent(out) << "my $output = shift;"<<endl;
+  indent(out) << "my $xfer   = 0;" << endl;
+
+  indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out << indent() << "if (defined $self->{" << (*f_iter)->get_name() << "}) {" << endl;
+    indent_up();
+
+    indent(out) <<
+      "$xfer += $output->writeFieldBegin(" <<
+      "'" << (*f_iter)->get_name() << "', " <<
+      type_to_enum((*f_iter)->get_type()) << ", " <<
+      (*f_iter)->get_key() << ");" << endl;
+
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "self->");
+
+    indent(out) <<
+        "$xfer += $output->writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+
+  out <<
+    indent() << "$xfer += $output->writeFieldStop();" << endl <<
+    indent() << "$xfer += $output->writeStructEnd();" << endl;
+
+  out <<indent() << "return $xfer;" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_perl_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_namespace_out_dir()+service_name_+".pm";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    ///      "package "<<service_name_<<";"<<endl<<
+    autogen_comment() <<
+    perl_includes();
+
+  f_service_ <<
+    "use " << perl_namespace(tservice->get_program()) << "Types;" << endl;
+
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    f_service_ <<
+      "use " << perl_namespace(extends_s->get_program()) << extends_s->get_name() << ";" << endl;
+  }
+
+  f_service_ <<
+    endl;
+
+  // Generate the three main parts of the service (well, two for now in PERL)
+  generate_service_helpers(tservice);
+  generate_service_interface(tservice);
+  generate_service_rest(tservice);
+  generate_service_client(tservice);
+  generate_service_processor(tservice);
+
+  // Close service file
+  f_service_ << "1;" << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_perl_generator::generate_service_processor(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    extends = perl_namespace(extends_s->get_program()) + extends_s->get_name();
+    extends_processor = "use base('" + extends + "Processor');";
+  }
+
+  indent_up();
+
+  // Generate the header portion
+  f_service_ <<
+      "package " << perl_namespace(program_) << service_name_ << "Processor;" << endl << extends_processor << endl;
+
+
+  if (extends.empty()) {
+    f_service_ << "sub new {" << endl;
+
+    indent_up();
+
+    f_service_ <<
+      indent() <<  "my $classname = shift;"<< endl <<
+      indent() <<  "my $handler   = shift;"<< endl <<
+      indent() <<  "my $self      = {};"   << endl;
+
+    f_service_ <<
+      indent() << "$self->{handler} = $handler;" << endl;
+
+    f_service_ <<
+      indent() << "return bless($self,$classname);"<<endl;
+
+    indent_down();
+
+    f_service_ <<"}" << endl << endl;
+  }
+
+  // Generate the server implementation
+  f_service_ << "sub process {" << endl;
+  indent_up();
+
+  f_service_ <<
+    indent() << "my $self   = shift;"<<endl <<
+    indent() << "my $input  = shift;"<<endl <<
+    indent() << "my $output = shift;"<<endl;
+
+  f_service_ <<
+    indent() << "my $rseqid = 0;" << endl <<
+    indent() << "my $fname  = undef;" << endl <<
+    indent() << "my $mtype  = 0;" << endl << endl;
+
+  f_service_ <<
+    indent() << "$input->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl;
+
+  // HOT: check for method implementation
+  f_service_ <<
+    indent() << "my $methodname = 'process_'.$fname;" << endl <<
+    indent() << "if (!method_exists($self, $methodname)) {" << endl;
+
+  f_service_ <<
+    indent() << "  $input->skip(TType::STRUCT);" << endl <<
+    indent() << "  $input->readMessageEnd();" << endl <<
+    indent() << "  my $x = new TApplicationException('Function '.$fname.' not implemented.', TApplicationException::UNKNOWN_METHOD);" << endl <<
+    indent() << "  $output->writeMessageBegin($fname, TMessageType::EXCEPTION, $rseqid);" << endl <<
+    indent() << "  $x->write($output);" << endl <<
+    indent() << "  $output->writeMessageEnd();" << endl <<
+    indent() << "  $output->getTransport()->flush();" << endl <<
+    indent() << "  return;" << endl;
+
+  f_service_ <<
+    indent() <<  "}" << endl <<
+    indent() <<  "$self->$methodname($rseqid, $input, $output);" << endl <<
+    indent() <<  "return 1;" << endl;
+
+  indent_down();
+
+  f_service_ <<
+    indent() << "}" << endl <<endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_perl_generator::generate_process_function(t_service* tservice,
+                                                 t_function* tfunction) {
+  // Open function
+  f_service_ <<
+    "sub process_" << tfunction->get_name() << "{"<<endl;
+
+  indent_up();
+
+  f_service_ <<
+    indent() << "my $self = shift;"<<endl<<
+    indent() << "my ($seqid, $input, $output); " << endl;
+
+  string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args";
+  string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result";
+
+  f_service_ <<
+    indent() << "my $args = new " << argsname << "();" << endl <<
+    indent() << "$args->read($input);" << endl;
+
+  f_service_ <<
+    indent() << "$input->readMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "my $result = new " << resultname << "();" << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ <<
+      indent() << "eval {" << endl;
+    indent_up();
+  }
+
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "$result->{success} = ";
+  }
+  f_service_ <<
+    "$self->{handler}->" << tfunction->get_name() << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "$args->" << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ <<
+        indent() << "}; if( UNIVERSAL::isa($@,'"<<(*x_iter)->get_type()->get_name()<<"') ){ "<<endl;
+
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ <<
+          indent() << "$result->{" << (*x_iter)->get_name() << "} = $@;" << endl;
+        indent_down();
+        f_service_ << indent();
+      }
+    }
+    indent_down();
+    f_service_ << "}" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "return;" << endl;
+    indent_down();
+    f_service_ <<
+      indent() << "}" << endl;
+    return;
+  }
+  indent_up();
+  // Serialize the request header
+  f_service_ <<
+    indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', TMessageType::REPLY, $seqid);" << endl <<
+    indent() << "$result->write($output);" << endl <<
+    indent() << "$output->getTransport()->flush();" << endl;
+  indent_down();
+
+  // Close function
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl;
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_perl_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  f_service_ <<
+    "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    string name = ts->get_name();
+    ts->set_name(service_name_ + "_" + name);
+    generate_perl_struct_definition(f_service_, ts, false);
+    generate_perl_function_helpers(*f_iter);
+    ts->set_name(name);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_perl_generator::generate_perl_function_helpers(t_function* tfunction) {
+  t_struct result(program_, service_name_ + "_" + 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_perl_struct_definition(f_service_, &result, false);
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_perl_generator::generate_service_interface(t_service* tservice) {
+  string extends_if = "";
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    extends_if = "use base('" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + "If');";
+  }
+
+  f_service_ <<
+    "package " << perl_namespace(program_) << service_name_ << "If;"<<endl<<
+    extends_if<<endl;
+
+
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      "sub " << function_signature(*f_iter) <<endl<< "  die 'implement interface';\n}" << endl;
+  }
+  indent_down();
+
+}
+
+/**
+ * Generates a REST interface
+ */
+void t_perl_generator::generate_service_rest(t_service* tservice) {
+  string extends = "";
+  string extends_if = "";
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    extends    =  extends_s->get_name();
+    extends_if = "use base('" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + "Rest');";
+  }
+  f_service_ <<
+    "package " << perl_namespace(program_) << service_name_ << "Rest;"<<endl<<
+    extends_if << endl;
+
+
+  if (extends.empty()) {
+    f_service_ << "sub new {" << endl;
+
+    indent_up();
+
+    f_service_ <<
+      indent() << "my $classname=shift;"<<endl <<
+      indent() << "my $impl     =shift;"<<endl <<
+      indent() << "my $self     ={ impl => $impl };"<<endl << endl<<
+      indent() << "return bless($self,$classname);" << endl;
+
+
+    indent_down();
+
+    f_service_  <<
+      indent() << "}" << endl << endl;
+  }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      "sub " << (*f_iter)->get_name() <<
+      "{"    <<endl;
+
+    indent_up();
+
+    f_service_ <<
+      indent() << "my $self = shift;"<< endl <<
+      indent() << "my $request = shift;" << endl << endl;
+
+
+    const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
+      t_type* atype = get_true_type((*a_iter)->get_type());
+      string req = "$request->{'" + (*a_iter)->get_name() + "'}";
+      f_service_ <<
+        indent() << "my $" << (*a_iter)->get_name() << " = (" << req << ") ? " << req << " : undef;" << endl;
+      if (atype->is_string() &&
+          ((t_base_type*)atype)->is_string_list()) {
+        f_service_ <<
+          indent() << "my @" << (*a_iter)->get_name() << " = split(/,/, $" << (*a_iter)->get_name() << ");" << endl <<
+          indent()     << "$"<<(*a_iter)->get_name() <<" = \\@"<<(*a_iter)->get_name()<<endl;
+      }
+    }
+    f_service_ <<
+      indent() << "return $self->{impl}->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl;
+    indent_down();
+    indent(f_service_) << "}" << endl <<endl;
+  }
+
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_perl_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    extends = perl_namespace(extends_s->get_program()) + extends_s->get_name();
+    extends_client = "use base('" + extends + "Client');";
+  }
+
+  f_service_ <<
+      "package " << perl_namespace(program_) << service_name_ << "Client;"<<endl;
+
+  f_service_ <<
+      extends_client << endl <<
+      "use base('" << perl_namespace(program_) << service_name_ << "If');" << endl;
+
+  // Constructor function
+  f_service_ << "sub new {"<<endl;
+
+  indent_up();
+
+  f_service_ <<
+    indent() << "my $classname = shift;"<<endl<<
+    indent() << "my $input     = shift;"<<endl<<
+    indent() << "my $output    = shift;"<<endl<<
+    indent() << "my $self      = {};"   <<endl;
+
+  if (!extends.empty()) {
+    f_service_ <<
+      indent() << "  $self = $classname->SUPER::new($input, $output);" << endl;
+  } else {
+    f_service_ <<
+      indent() << "  $self->{input}  = $input;" << endl <<
+      indent() << "  $self->{output} = defined $output ? $output : $input;" << endl <<
+      indent() << "  $self->{seqid}  = 0;" << endl;
+  }
+
+  f_service_ <<
+    indent() << "return bless($self,$classname);"<<endl;
+
+  indent_down();
+
+  f_service_ <<
+    indent() << "}" << endl << endl;
+
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    f_service_ << "sub " << function_signature(*f_iter) << endl;
+
+    indent_up();
+
+    indent(f_service_) << indent() <<
+      "$self->send_" << funname << "(";
+
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << "$" << (*fld_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ <<
+        "$self->recv_" << funname << "();" << endl;
+    }
+
+    indent_down();
+
+    f_service_ << "}" << endl << endl;
+
+    f_service_ <<
+      "sub send_" << function_signature(*f_iter) << endl;
+
+    indent_up();
+
+    std::string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args";
+
+    // Serialize the request header
+    f_service_ <<
+      indent() << "$self->{output}->writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, $self->{seqid});" << endl;
+
+    f_service_ <<
+      indent() << "my $args = new " << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ <<
+        indent() << "$args->{" << (*fld_iter)->get_name() << "} = $" << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    // Write to the stream
+    f_service_ <<
+      indent() << "$args->write($self->{output});" << endl <<
+      indent() << "$self->{output}->writeMessageEnd();" << endl <<
+      indent() << "$self->{output}->getTransport()->flush();" << endl;
+
+
+    indent_down();
+
+    f_service_ << "}" << endl;
+
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
+      t_struct noargs(program_);
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      f_service_ <<
+        endl <<
+        "sub " << function_signature(&recv_function) << endl;
+
+      indent_up();
+
+      f_service_ <<
+        indent() << "my $rseqid = 0;" << endl <<
+        indent() << "my $fname;" << endl <<
+        indent() << "my $mtype = 0;" << endl <<
+        endl;
+
+      f_service_ <<
+        indent() << "$self->{input}->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl <<
+        indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl <<
+        indent() << "  my $x = new TApplicationException();" << endl <<
+        indent() << "  $x->read($self->{input});" << endl <<
+        indent() << "  $self->{input}->readMessageEnd();" << endl <<
+        indent() << "  die $x;" << endl <<
+        indent() << "}" << endl;
+
+
+      f_service_ <<
+        indent() << "my $result = new " << resultname << "();" << endl <<
+        indent() << "$result->read($self->{input});" << endl;
+
+
+      f_service_ <<
+        indent() << "$self->{input}->readMessageEnd();" << endl <<
+        endl;
+
+
+      // Careful, only return result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "if (defined $result->{success} ) {" << endl <<
+          indent() << "  return $result->{success};" << endl <<
+          indent() << "}" << endl;
+      }
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "if (defined $result->{" << (*x_iter)->get_name() << "}) {" << endl <<
+          indent() << "  die $result->{" << (*x_iter)->get_name() << "};" << endl <<
+          indent() << "}" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "return;" << endl;
+      } else {
+        f_service_ <<
+          indent() << "die \"" << (*f_iter)->get_name() << " failed: unknown result\";" << endl;
+      }
+
+      // Close function
+      indent_down();
+      f_service_ << "}"<<endl;
+
+    }
+  }
+
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_perl_generator::generate_deserialize_field(ofstream &out,
+                                                  t_field* tfield,
+                                                  string prefix,
+                                                  bool inclass) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  string name = tfield->get_name();
+
+  //Hack for when prefix is defined (always a hash ref)
+  if (!prefix.empty()) {
+    name = prefix + "{" + tfield->get_name() + "}";
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type,
+                                 name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) <<
+      "$xfer += $input->";
+
+    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:
+        out << "readString(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_BYTE:
+        out << "readByte(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "readI16(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "readI32(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "readI64(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "readDouble(\\$" << name << ");";
+        break;
+      default:
+        throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32(\\$" << name << ");";
+    }
+    out << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(), type->get_name().c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_perl_generator::generate_deserialize_struct(ofstream &out,
+                                                   t_struct* tstruct,
+                                                   string prefix) {
+  out <<
+    indent() << "$" << prefix << " = new " << perl_namespace(tstruct->get_program()) << tstruct->get_name() << "();" << endl <<
+    indent() << "$xfer += $" << prefix << "->read($input);" << endl;
+}
+
+void t_perl_generator::generate_deserialize_container(ofstream &out,
+                                                      t_type* ttype,
+                                                      string prefix) {
+  scope_up(out);
+
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+
+  t_field fsize(g_type_i32, size);
+  t_field fktype(g_type_byte, ktype);
+  t_field fvtype(g_type_byte, vtype);
+  t_field fetype(g_type_byte, etype);
+
+  out <<
+    indent() << "my $" << size << " = 0;" << endl;
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out <<
+      indent() << "$" << prefix << " = {};" << endl <<
+      indent() << "my $" << ktype << " = 0;" << endl <<
+      indent() << "my $" << vtype << " = 0;" << endl;
+
+    out <<
+      indent() << "$xfer += $input->readMapBegin(" <<
+      "\\$" << ktype << ", \\$" << vtype << ", \\$" << size << ");" << endl;
+
+  } else if (ttype->is_set()) {
+
+    out <<
+      indent() << "$" << prefix << " = {};" << endl <<
+      indent() << "my $" << etype << " = 0;" << endl <<
+      indent() << "$xfer += $input->readSetBegin(" <<
+      "\\$" << etype << ", \\$" << size << ");" << endl;
+
+  } else if (ttype->is_list()) {
+
+    out <<
+      indent() << "$" << prefix << " = [];" << endl <<
+      indent() << "my $" << etype << " = 0;" << endl <<
+      indent() << "$xfer += $input->readListBegin(" <<
+      "\\$" << etype << ", \\$" << size << ");" << endl;
+
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) <<
+    "for (my $" <<
+    i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "$xfer += $input->readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "$xfer += $input->readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "$xfer += $input->readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_perl_generator::generate_deserialize_map_element(ofstream &out,
+                                                        t_map* tmap,
+                                                        string prefix) {
+  string key = tmp("key");
+  string val = tmp("val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) <<
+    declare_field(&fkey, true, true) << endl;
+  indent(out) <<
+    declare_field(&fval, true, true) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) <<
+    "$" << prefix << "->{$" << key << "} = $" << val << ";" << endl;
+}
+
+void t_perl_generator::generate_deserialize_set_element(ofstream &out,
+                                                        t_set* tset,
+                                                        string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) <<
+    "my $" << elem << " = undef;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    "$" << prefix << "->{$" << elem << "} = 1;" << endl;
+}
+
+void t_perl_generator::generate_deserialize_list_element(ofstream &out,
+                                                         t_list* tlist,
+                                                         string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) <<
+    "my $" << elem << " = undef;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    "push(@{$" << prefix << "},$" << elem << ");" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_perl_generator::generate_serialize_field(ofstream &out,
+                                                t_field* tfield,
+                                                string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out,
+                              (t_struct*)type,
+                               prefix + "{"+tfield->get_name()+"}" );
+  } else if (type->is_container()) {
+    generate_serialize_container(out,
+                                 type,
+                                 prefix + "{" + tfield->get_name()+"}");
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = tfield->get_name();
+
+    //Hack for when prefix is defined (always a hash ref)
+    if(!prefix.empty())
+      name = prefix + "{" + tfield->get_name() + "}";
+
+    indent(out) <<
+      "$xfer += $output->";
+
+    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:
+        out << "writeString($" << name << ");";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool($" << name << ");";
+        break;
+      case t_base_type::TYPE_BYTE:
+        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 PERL name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32($" << name << ");";
+    }
+    out << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_perl_generator::generate_serialize_struct(ofstream &out,
+                                                 t_struct* tstruct,
+                                                 string prefix) {
+    indent(out) <<
+      "$xfer += $" << prefix << "->write($output);" << endl;
+}
+
+/**
+ * Writes out a container
+ */
+void t_perl_generator::generate_serialize_container(ofstream &out,
+                                                    t_type* ttype,
+                                                    string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "$output->writeMapBegin(" <<
+      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+      "scalar(keys %{$" << prefix << "}));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "$output->writeSetBegin(" <<
+      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+      "scalar(@{$" << prefix << "}));" << endl;
+
+  } else if (ttype->is_list()) {
+
+    indent(out) <<
+      "$output->writeListBegin(" <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+      "scalar(@{$" << prefix << "}));" << endl;
+
+  }
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    string kiter = tmp("kiter");
+    string viter = tmp("viter");
+    indent(out) <<
+      "while( my ($"<<kiter<<",$"<<viter<<") = each %{$" << prefix << "}) " << endl;
+
+    scope_up(out);
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    scope_down(out);
+
+  } else if (ttype->is_set()) {
+    string iter = tmp("iter");
+    indent(out) <<
+      "foreach my $"<<iter<<" (@{$" << prefix << "})" << endl;
+    scope_up(out);
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    scope_down(out);
+
+
+  } else if (ttype->is_list()) {
+    string iter = tmp("iter");
+    indent(out) <<
+      "foreach my $"<<iter<<" (@{$" << prefix << "}) " << endl;
+    scope_up(out);
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    scope_down(out);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "$output->writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "$output->writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "$output->writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_perl_generator::generate_serialize_map_element(ofstream &out,
+                                                      t_map* tmap,
+                                                      string kiter,
+                                                      string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield);
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_perl_generator::generate_serialize_set_element(ofstream &out,
+                                                      t_set* tset,
+                                                      string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_perl_generator::generate_serialize_list_element(ofstream &out,
+                                                       t_list* tlist,
+                                                       string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_perl_generator::declare_field(t_field* tfield, bool init, bool obj) {
+  string result = "my $" + tfield->get_name();
+  if (init) {
+    t_type* type = get_true_type(tfield->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:
+        break;
+      case t_base_type::TYPE_STRING:
+        result += " = ''";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = 0";
+        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:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = 0.0";
+        break;
+      default:
+        throw "compiler error: no PERL initializer for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = 0";
+    } else if (type->is_container()) {
+      result += " = []";
+    } else if (type->is_struct() || type->is_xception()) {
+      if (obj) {
+        result += " = new " + perl_namespace(type->get_program()) + type->get_name() + "()";
+      } else {
+        result += " = undef";
+      }
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_perl_generator::function_signature(t_function* tfunction,
+                                            string prefix) {
+
+  string str;
+
+  str  = prefix + tfunction->get_name() + "{\n";
+  str += "  my $self = shift;\n";
+
+  //Need to create perl function arg inputs
+  const vector<t_field*> &fields = tfunction->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    str += "  my $" + (*f_iter)->get_name() + " = shift;\n";
+  }
+
+  return str;
+}
+
+/**
+ * Renders a field list
+ */
+string t_perl_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;
+    } else {
+      result += ", ";
+    }
+    result += "$" + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_perl_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();
+}
+
+THRIFT_REGISTER_GENERATOR(perl, "Perl", "");
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
new file mode 100644
index 0000000..436a632
--- /dev/null
+++ b/compiler/cpp/src/generate/t_php_generator.cc
@@ -0,0 +1,2281 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "t_oop_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * PHP code generator.
+ *
+ */
+class t_php_generator : public t_oop_generator {
+ public:
+  t_php_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    std::map<std::string, std::string>::const_iterator iter;
+
+    iter = parsed_options.find("inlined");
+    binary_inline_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("rest");
+    rest_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("server");
+    phps_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("autoload");
+    autoload_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("oop");
+    oop_ = (iter != parsed_options.end());
+
+    if (oop_ && binary_inline_) {
+      throw "oop and inlined are mutually exclusive.";
+    }
+
+    out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
+    escape_['$'] = "\\$";
+  }
+
+  /**
+   * 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);
+
+  /**
+   * Structs!
+   */
+
+  void generate_php_struct(t_struct* tstruct, bool is_exception);
+  void generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
+  void _generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
+  void generate_php_struct_reader(std::ofstream& out, t_struct* tstruct);
+  void generate_php_struct_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_php_function_helpers(t_function* tfunction);
+
+  void generate_php_type_spec(std::ofstream &out, t_type* t);
+  void generate_php_struct_spec(std::ofstream &out, t_struct* tstruct);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_helpers   (t_service* tservice);
+  void generate_service_interface (t_service* tservice);
+  void generate_service_rest      (t_service* tservice);
+  void generate_service_client    (t_service* tservice);
+  void _generate_service_client   (std::ofstream &out, t_service* tservice);
+  void generate_service_processor (t_service* tservice);
+  void generate_process_function  (t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="",
+                                          bool inclass=false);
+
+  void generate_deserialize_struct       (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_deserialize_container    (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_deserialize_set_element  (std::ofstream &out,
+                                          t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+
+  void generate_serialize_field          (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_serialize_struct         (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string kiter,
+                                          std::string viter);
+
+  void generate_serialize_set_element    (std::ofstream &out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string php_includes();
+  std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
+  std::string function_signature(t_function* tfunction, std::string prefix="");
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_cast(t_type* ttype);
+  std::string type_to_enum(t_type* ttype);
+
+  std::string php_namespace(t_program* p) {
+    std::string ns = p->get_namespace("php");
+    return ns.size() ? (ns + "_") : "";
+  }
+
+ private:
+
+  /**
+   * File streams
+   */
+  std::ofstream f_types_;
+  std::ofstream f_consts_;
+  std::ofstream f_helpers_;
+  std::ofstream f_service_;
+
+  /**
+   * Generate protocol-independent template? Or Binary inline code?
+   */
+  bool binary_inline_;
+
+  /**
+   * Generate a REST handler class
+   */
+  bool rest_;
+
+  /**
+   * Generate stubs for a PHP server
+   */
+  bool phps_;
+
+  /**
+   * Generate PHP code that uses autoload
+   */
+  bool autoload_;
+
+  /**
+   * Whether to use OOP base class TBase
+   */
+  bool oop_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_php_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string f_types_name = get_out_dir()+program_name_+"_types.php";
+  f_types_.open(f_types_name.c_str());
+
+  // Print header
+  f_types_ <<
+    "<?php" << endl <<
+    autogen_comment() <<
+    php_includes();
+
+  // Include other Thrift includes
+  const vector<t_program*>& includes = program_->get_includes();
+  for (size_t i = 0; i < includes.size(); ++i) {
+    string package = includes[i]->get_name();
+    f_types_ <<
+      "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << package << "/" << package << "_types.php';" << endl;
+  }
+  f_types_ << endl;
+
+  // Print header
+  if (!program_->get_consts().empty()) {
+    string f_consts_name = get_out_dir()+program_name_+"_constants.php";
+    f_consts_.open(f_consts_name.c_str());
+    f_consts_ <<
+      "<?php" << endl <<
+      autogen_comment() <<
+      "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" + program_name_ + "/" + program_name_ + "_types.php';" << endl <<
+      endl <<
+      "$GLOBALS['" << program_name_ << "_CONSTANTS'] = array();" << endl <<
+      endl;
+  }
+}
+
+/**
+ * Prints standard php includes
+ */
+string t_php_generator::php_includes() {
+  return
+    string("include_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';\n\n");
+}
+
+/**
+ * Close up (or down) some filez.
+ */
+void t_php_generator::close_generator() {
+  // Close types file
+  f_types_ << "?>" << endl;
+  f_types_.close();
+
+  if (!program_->get_consts().empty()) {
+    f_consts_ << "?>" << endl;
+    f_consts_.close();
+  }
+}
+
+/**
+ * Generates a typedef. This is not done in PHP, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_php_generator::generate_typedef(t_typedef* ttypedef) {}
+
+/**
+ * Generates code for an enumerated type. Since define is expensive to lookup
+ * in PHP, we use a global array for this.
+ *
+ * @param tenum The enumeration
+ */
+void t_php_generator::generate_enum(t_enum* tenum) {
+  f_types_ <<
+    "$GLOBALS['" << php_namespace(tenum->get_program()) << "E_" << tenum->get_name() << "'] = array(" << endl;
+
+  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;
+    }
+
+    f_types_ <<
+      "  '" << (*c_iter)->get_name() << "' => " << value << "," << endl;
+  }
+
+  f_types_ <<
+    ");" << endl << endl;
+
+
+  // We're also doing it this way to see how it performs. It's more legible
+  // code but you can't do things like an 'extract' on it, which is a bit of
+  // a downer.
+  f_types_ <<
+    "final class " << php_namespace(tenum->get_program()) << tenum->get_name() << " {" << endl;
+  indent_up();
+
+  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;
+    }
+
+    indent(f_types_) <<
+      "const " << (*c_iter)->get_name() << " = " << value << ";" << endl;
+  }
+
+  indent(f_types_) <<
+    "static public $__names = array(" << endl;
+  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;
+    }
+
+    indent(f_types_) <<
+      "  " << value << " => '" << (*c_iter)->get_name() << "'," << endl;
+  }
+  indent(f_types_) <<
+    ");" << endl;
+
+  indent_down();
+  f_types_ << "}" << endl << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_php_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_consts_ << "$GLOBALS['" << program_name_ << "_CONSTANTS']['" << name << "'] = ";
+  f_consts_ << render_const_value(type, value);
+  f_consts_ << ";" << 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_php_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+  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_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << "new " << php_namespace(type->get_program()) << type->get_name() << "(array(" << endl;
+    indent_up();
+    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;
+    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();
+      }
+      out << indent();
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " => ";
+      out << render_const_value(field_type, v_iter->second);
+      out << endl;
+    }
+    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();
+    out << "array(" << endl;
+    indent_up();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent();
+      out << render_const_value(ktype, v_iter->first);
+      out << " => ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << ")";
+  } 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();
+    }
+    out << "array(" << endl;
+    indent_up();
+    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) {
+      out << indent();
+      out << render_const_value(etype, *v_iter);
+      if (type->is_set()) {
+        out << " => true";
+      }
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << ")";
+  }
+  return out.str();
+}
+
+/**
+ * Make a struct
+ */
+void t_php_generator::generate_struct(t_struct* tstruct) {
+  generate_php_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_php_generator::generate_xception(t_struct* txception) {
+  generate_php_struct(txception, true);
+}
+
+/**
+ * Structs can be normal or exceptions.
+ */
+void t_php_generator::generate_php_struct(t_struct* tstruct,
+                                          bool is_exception) {
+  generate_php_struct_definition(f_types_, tstruct, is_exception);
+}
+
+void t_php_generator::generate_php_type_spec(ofstream& out,
+                                             t_type* t) {
+  t = get_true_type(t);
+  indent(out) << "'type' => " << type_to_enum(t) << "," << endl;
+
+  if (t->is_base_type() || t->is_enum()) {
+    // Noop, type is all we need
+  } else if (t->is_struct() || t->is_xception()) {
+    indent(out) << "'class' => '" << php_namespace(t->get_program()) << t->get_name() <<"'," << endl;
+  } else if (t->is_map()) {
+    t_type* ktype = get_true_type(((t_map*)t)->get_key_type());
+    t_type* vtype = get_true_type(((t_map*)t)->get_val_type());
+    indent(out) << "'ktype' => " << type_to_enum(ktype) << "," << endl;
+    indent(out) << "'vtype' => " << type_to_enum(vtype) << "," << endl;
+    indent(out) << "'key' => array(" << endl;
+    indent_up();
+    generate_php_type_spec(out, ktype);
+    indent_down();
+    indent(out) << ")," << endl;
+    indent(out) << "'val' => array(" << endl;
+    indent_up();
+    generate_php_type_spec(out, vtype);
+    indent(out) << ")," << endl;
+    indent_down();
+  } else if (t->is_list() || t->is_set()) {
+    t_type* etype;
+    if (t->is_list()) {
+      etype = get_true_type(((t_list*)t)->get_elem_type());
+    } else {
+      etype = get_true_type(((t_set*)t)->get_elem_type());
+    }
+    indent(out) << "'etype' => " << type_to_enum(etype) <<"," << endl;
+    indent(out) << "'elem' => array(" << endl;
+    indent_up();
+    generate_php_type_spec(out, etype);
+    indent(out) << ")," << endl;
+    indent_down();
+  } else {
+    throw "compiler error: no type for php struct spec field";
+  }
+
+}
+
+/**
+ * Generates the struct specification structure, which fully qualifies enough
+ * type information to generalize serialization routines.
+ */
+void t_php_generator::generate_php_struct_spec(ofstream& out,
+                                               t_struct* tstruct) {
+  indent(out) << "if (!isset(self::$_TSPEC)) {" << endl;
+  indent_up();
+
+  indent(out) << "self::$_TSPEC = array(" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    indent(out) << (*m_iter)->get_key() << " => array(" << endl;
+    indent_up();
+    out <<
+      indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
+    generate_php_type_spec(out, t);
+    indent(out) << ")," << endl;
+    indent_down();
+  }
+
+  indent_down();
+  indent(out) << "  );" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+
+void t_php_generator::generate_php_struct_definition(ofstream& out,
+                                                     t_struct* tstruct,
+                                                     bool is_exception) {
+  if (autoload_) {
+    // Make output file
+    ofstream autoload_out;
+    string f_struct = program_name_+"."+(tstruct->get_name())+".php";
+    string f_struct_name = get_out_dir()+f_struct;
+    autoload_out.open(f_struct_name.c_str());
+    autoload_out << "<?php" << endl;
+    _generate_php_struct_definition(autoload_out, tstruct, is_exception);
+    autoload_out << endl << "?>" << endl;
+    autoload_out.close();
+
+    f_types_ <<
+      "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(php_namespace(tstruct->get_program()) + tstruct->get_name()) << "'] = '" << program_name_ << "/" << f_struct << "';" << endl;
+
+  } else {
+    _generate_php_struct_definition(out, tstruct, is_exception);
+  }
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is nothing in PHP
+ * where the objects are all just associative arrays (unless of course we
+ * decide to start using objects for them...)
+ *
+ * @param tstruct The struct definition
+ */
+void t_php_generator::_generate_php_struct_definition(ofstream& out,
+                                                     t_struct* tstruct,
+                                                     bool is_exception) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out <<
+    "class " << php_namespace(tstruct->get_program()) << tstruct->get_name();
+  if (is_exception) {
+    out << " extends TException";
+  } else if (oop_) {
+    out << " extends TBase";
+  }
+  out <<
+    " {" << endl;
+  indent_up();
+
+  indent(out) << "static $_TSPEC;" << endl << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string dval = "null";
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
+      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
+    }
+    indent(out) <<
+      "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl;
+  }
+
+  out << endl;
+
+  // Generate constructor from array
+  string param = (members.size() > 0) ? "$vals=null" : "";
+  out <<
+    indent() << "public function __construct(" << param << ") {" << endl;
+  indent_up();
+
+  generate_php_struct_spec(out, tstruct);
+
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
+        indent(out) << "$this->" << (*m_iter)->get_name() << " = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
+      }
+    }
+    out <<
+      indent() << "if (is_array($vals)) {" << endl;
+    indent_up();
+    if (oop_) {
+      out << indent() << "parent::__construct(self::$_TSPEC, $vals);" << endl;
+    } else {
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        out <<
+          indent() << "if (isset($vals['" << (*m_iter)->get_name() << "'])) {" << endl <<
+          indent() << "  $this->" << (*m_iter)->get_name() << " = $vals['" << (*m_iter)->get_name() << "'];" << endl <<
+          indent() << "}" << endl;
+      }
+    }
+    indent_down();
+    out <<
+      indent() << "}" << endl;
+  }
+  scope_down(out);
+  out << endl;
+
+  out <<
+    indent() << "public function getName() {" << endl <<
+    indent() << "  return '" << tstruct->get_name() << "';" << endl <<
+    indent() << "}" << endl <<
+    endl;
+
+  generate_php_struct_reader(out, tstruct);
+  generate_php_struct_writer(out, tstruct);
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates the read() method for a struct
+ */
+void t_php_generator::generate_php_struct_reader(ofstream& out,
+                                                 t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "public function read($input)" << endl;
+  scope_up(out);
+
+  if (oop_) {
+    indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" << endl;
+    scope_down(out);
+    return;
+  }
+
+  out <<
+    indent() << "$xfer = 0;" << endl <<
+    indent() << "$fname = null;" << endl <<
+    indent() << "$ftype = 0;" << endl <<
+    indent() << "$fid = 0;" << endl;
+
+  // Declare stack tmp variables
+  if (!binary_inline_) {
+    indent(out) <<
+      "$xfer += $input->readStructBegin($fname);" << endl;
+  }
+
+  // Loop over reading in fields
+  indent(out) <<
+    "while (true)" << endl;
+
+    scope_up(out);
+
+    // Read beginning field marker
+    if (binary_inline_) {
+      t_field fftype(g_type_byte, "ftype");
+      t_field ffid(g_type_i16, "fid");
+      generate_deserialize_field(out, &fftype);
+      out <<
+        indent() << "if ($ftype == TType::STOP) {" << endl <<
+        indent() << "  break;" << endl <<
+        indent() << "}" << endl;
+      generate_deserialize_field(out, &ffid);
+    } else {
+      indent(out) <<
+        "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl;
+      // Check for field STOP marker and break
+      indent(out) <<
+        "if ($ftype == TType::STOP) {" << endl;
+      indent_up();
+      indent(out) <<
+        "break;" << endl;
+      indent_down();
+      indent(out) <<
+        "}" << endl;
+    }
+
+    // Switch statement on the field we are reading
+    indent(out) <<
+      "switch ($fid)" << endl;
+
+      scope_up(out);
+
+      // Generate deserialization code for known cases
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        indent(out) <<
+          "case " << (*f_iter)->get_key() << ":" << endl;
+        indent_up();
+        indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+        indent_up();
+        generate_deserialize_field(out, *f_iter, "this->");
+        indent_down();
+        out <<
+          indent() << "} else {" << endl;
+        if (binary_inline_) {
+          indent(out) <<  "  $xfer += TProtocol::skipBinary($input, $ftype);" << endl;
+        } else {
+          indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
+        }
+        out <<
+          indent() << "}" << endl <<
+          indent() << "break;" << endl;
+        indent_down();
+      }
+
+      // In the default case we skip the field
+      indent(out) <<  "default:" << endl;
+      if (binary_inline_) {
+        indent(out) <<  "  $xfer += TProtocol::skipBinary($input, $ftype);" << endl;
+      } else {
+        indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
+      }
+      indent(out) <<  "  break;" << endl;
+
+      scope_down(out);
+
+    if (!binary_inline_) {
+      // Read field end marker
+      indent(out) <<
+        "$xfer += $input->readFieldEnd();" << endl;
+    }
+
+    scope_down(out);
+
+  if (!binary_inline_) {
+    indent(out) <<
+      "$xfer += $input->readStructEnd();" << endl;
+  }
+
+  indent(out) <<
+    "return $xfer;" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates the write() method for a struct
+ */
+void t_php_generator::generate_php_struct_writer(ofstream& out,
+                                                 t_struct* tstruct) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (binary_inline_) {
+    indent(out) <<
+      "public function write(&$output) {" << endl;
+  } else {
+    indent(out) <<
+      "public function write($output) {" << endl;
+  }
+  indent_up();
+
+  if (oop_) {
+    indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);" << endl;
+    scope_down(out);
+    return;
+  }
+
+  indent(out) <<
+    "$xfer = 0;" << endl;
+
+  if (!binary_inline_) {
+    indent(out) <<
+      "$xfer += $output->writeStructBegin('" << name << "');" << endl;
+  }
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out <<
+      indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl;
+    indent_up();
+
+    t_type* type = get_true_type((*f_iter)->get_type());
+    string expect;
+    if (type->is_container()) {
+      expect = "array";
+    } else if (type->is_struct()) {
+      expect = "object";
+    }
+    if (!expect.empty()) {
+      out <<
+        indent() << "if (!is_" << expect << "($this->" << (*f_iter)->get_name() << ")) {" << endl;
+      indent_up();
+      out <<
+        indent() << "throw new TProtocolException('Bad type in structure.', TProtocolException::INVALID_DATA);" << endl;
+      scope_down(out);
+    }
+
+    // Write field header
+    if (binary_inline_) {
+      out <<
+        indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl <<
+        indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl;
+    } else {
+      indent(out) <<
+        "$xfer += $output->writeFieldBegin(" <<
+        "'" << (*f_iter)->get_name() << "', " <<
+        type_to_enum((*f_iter)->get_type()) << ", " <<
+        (*f_iter)->get_key() << ");" << endl;
+    }
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this->");
+
+    // Write field closer
+    if (!binary_inline_) {
+      indent(out) <<
+        "$xfer += $output->writeFieldEnd();" << endl;
+    }
+
+    indent_down();
+    indent(out) <<
+      "}" << endl;
+  }
+
+  if (binary_inline_) {
+    out <<
+      indent() << "$output .= pack('c', TType::STOP);" << endl;
+  } else {
+    out <<
+      indent() << "$xfer += $output->writeFieldStop();" << endl <<
+      indent() << "$xfer += $output->writeStructEnd();" << endl;
+  }
+
+  out <<
+    indent() << "return $xfer;" << endl;
+
+  indent_down();
+  out <<
+    indent() << "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_php_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_out_dir()+service_name_+".php";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    "<?php" << endl <<
+    autogen_comment() <<
+    php_includes();
+
+  f_service_ <<
+    "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_ << "/" << program_name_ << "_types.php';" << endl;
+
+  if (tservice->get_extends() != NULL) {
+    f_service_ <<
+      "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << tservice->get_extends()->get_program()->get_name() << "/" << tservice->get_extends()->get_name() << ".php';" << endl;
+  }
+
+  f_service_ <<
+    endl;
+
+  // Generate the three main parts of the service (well, two for now in PHP)
+  generate_service_interface(tservice);
+  if (rest_) {
+    generate_service_rest(tservice);
+  }
+  generate_service_client(tservice);
+  generate_service_helpers(tservice);
+  if (phps_) {
+    generate_service_processor(tservice);
+  }
+
+  // Close service file
+  f_service_ << "?>" << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_php_generator::generate_service_processor(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = tservice->get_extends()->get_name();
+    extends_processor = " extends " + extends + "Processor";
+  }
+
+  // Generate the header portion
+  f_service_ <<
+    "class " << service_name_ << "Processor" << extends_processor << " {" << endl;
+  indent_up();
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected $handler_ = null;" << endl;
+  }
+
+  f_service_ <<
+    indent() << "public function __construct($handler) {" << endl;
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "  $this->handler_ = $handler;" << endl;
+  } else {
+    f_service_ <<
+      indent() << "  parent::__construct($handler);" << endl;
+  }
+  f_service_ <<
+    indent() << "}" << endl <<
+    endl;
+
+  // Generate the server implementation
+  indent(f_service_) <<
+    "public function process($input, $output) {" << endl;
+  indent_up();
+
+  f_service_ <<
+    indent() << "$rseqid = 0;" << endl <<
+    indent() << "$fname = null;" << endl <<
+    indent() << "$mtype = 0;" << endl <<
+    endl;
+
+  if (binary_inline_) {
+    t_field ffname(g_type_string, "fname");
+    t_field fmtype(g_type_byte, "mtype");
+    t_field fseqid(g_type_i32, "rseqid");
+    generate_deserialize_field(f_service_, &ffname, "", true);
+    generate_deserialize_field(f_service_, &fmtype, "", true);
+    generate_deserialize_field(f_service_, &fseqid, "", true);
+  } else {
+    f_service_ <<
+      indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl;
+  }
+
+  // HOT: check for method implementation
+  f_service_ <<
+    indent() << "$methodname = 'process_'.$fname;" << endl <<
+    indent() << "if (!method_exists($this, $methodname)) {" << endl;
+  if (binary_inline_) {
+    f_service_ <<
+      indent() << "  throw new Exception('Function '.$fname.' not implemented.');" << endl;
+  } else {
+    f_service_ <<
+      indent() << "  $input->skip(TType::STRUCT);" << endl <<
+      indent() << "  $input->readMessageEnd();" << endl <<
+      indent() << "  $x = new TApplicationException('Function '.$fname.' not implemented.', TApplicationException::UNKNOWN_METHOD);" << endl <<
+      indent() << "  $output->writeMessageBegin($fname, TMessageType::EXCEPTION, $rseqid);" << endl <<
+      indent() << "  $x->write($output);" << endl <<
+      indent() << "  $output->writeMessageEnd();" << endl <<
+      indent() << "  $output->getTransport()->flush();" << endl <<
+      indent() << "  return;" << endl;
+  }
+  f_service_ <<
+    indent() << "}" << endl <<
+    indent() << "$this->$methodname($rseqid, $input, $output);" << endl <<
+    indent() << "return true;" << endl;
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl <<
+    endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  f_service_ << "}" << endl;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_php_generator::generate_process_function(t_service* tservice,
+                                                t_function* tfunction) {
+  // Open function
+  indent(f_service_) <<
+    "protected function process_" << tfunction->get_name() <<
+    "($seqid, $input, $output) {" << endl;
+  indent_up();
+
+  string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args";
+  string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result";
+
+  f_service_ <<
+    indent() << "$args = new " << argsname << "();" << endl <<
+    indent() << "$args->read($input);" << endl;
+  if (!binary_inline_) {
+    f_service_ <<
+      indent() << "$input->readMessageEnd();" << endl;
+  }
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "$result = new " << resultname << "();" << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ <<
+      indent() << "try {" << endl;
+    indent_up();
+  }
+
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "$result->success = ";
+  }
+  f_service_ <<
+    "$this->handler_->" << tfunction->get_name() << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "$args->" << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ <<
+        indent() << "} catch (" << php_namespace((*x_iter)->get_type()->get_program()) << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ <<
+          indent() << "$result->" << (*x_iter)->get_name() << " = $" << (*x_iter)->get_name() << ";" << endl;
+        indent_down();
+        f_service_ << indent();
+      }
+    }
+    f_service_ << "}" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "return;" << endl;
+    indent_down();
+    f_service_ <<
+      indent() << "}" << endl;
+    return;
+  }
+
+  // Serialize the request header
+  if (binary_inline_) {
+    f_service_ <<
+      indent() << "$buff = pack('N', (0x80010000 | TMessageType::REPLY)); " << endl <<
+      indent() << "$buff .= pack('N', strlen('" << tfunction->get_name() << "'));" << endl <<
+      indent() << "$buff .= '" << tfunction->get_name() << "';" << endl <<
+      indent() << "$buff .= pack('N', $seqid);" << endl <<
+      indent() << "$result->write($buff);" << endl <<
+      indent() << "$output->write($buff);" << endl <<
+      indent() << "$output->flush();" << endl;
+  } else {
+    f_service_ <<
+      indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', TMessageType::REPLY, $seqid);" << endl <<
+      indent() << "$result->write($output);" << endl <<
+      indent() << "$output->getTransport()->flush();" << endl;
+  }
+
+  // Close function
+  indent_down();
+  f_service_ <<
+    indent() << "}" << endl;
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_php_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  f_service_ <<
+    "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    string name = ts->get_name();
+    ts->set_name(service_name_ + "_" + name);
+    generate_php_struct_definition(f_service_, ts, false);
+    generate_php_function_helpers(*f_iter);
+    ts->set_name(name);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_php_generator::generate_php_function_helpers(t_function* tfunction) {
+  if (!tfunction->is_oneway()) {
+    t_struct result(program_, service_name_ + "_" + 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_php_struct_definition(f_service_, &result, false);
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_php_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_if = "";
+  if (tservice->get_extends() != NULL) {
+    extends = " extends " + tservice->get_extends()->get_name();
+    extends_if = " extends " + tservice->get_extends()->get_name() + "If";
+  }
+  f_service_ <<
+    "interface " << service_name_ << "If" << extends_if << " {" << endl;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_service_) <<
+      "public function " << function_signature(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  f_service_ <<
+    "}" << endl << endl;
+}
+
+/**
+ * Generates a REST interface
+ */
+void t_php_generator::generate_service_rest(t_service* tservice) {
+  string extends = "";
+  string extends_if = "";
+  if (tservice->get_extends() != NULL) {
+    extends = " extends " + tservice->get_extends()->get_name();
+    extends_if = " extends " + tservice->get_extends()->get_name() + "Rest";
+  }
+  f_service_ <<
+    "class " << service_name_ << "Rest" << extends_if << " {" << endl;
+  indent_up();
+
+  if (extends.empty()) {
+    f_service_ <<
+      indent() << "protected $impl_;" << endl <<
+      endl;
+  }
+
+  f_service_ <<
+    indent() << "public function __construct($impl) {" << endl <<
+    indent() << "  $this->impl_ = $impl;" << endl <<
+    indent() << "}" << endl <<
+    endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_service_) <<
+      "public function " << (*f_iter)->get_name() << "($request) {" << endl;
+    indent_up();
+    const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
+      t_type* atype = get_true_type((*a_iter)->get_type());
+      string cast = type_to_cast(atype);
+      string req = "$request['" + (*a_iter)->get_name() + "']";
+      if (atype->is_bool()) {
+        f_service_ <<
+          indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req << ") && (" << req << " !== 'false'));" << endl;
+      } else {
+        f_service_ <<
+          indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? " << cast << req << " : null;" << endl;
+      }
+      if (atype->is_string() &&
+          ((t_base_type*)atype)->is_string_list()) {
+        f_service_ <<
+          indent() << "$" << (*a_iter)->get_name() << " = explode(',', $" << (*a_iter)->get_name() << ");" << endl;
+      } else if (atype->is_map() || atype->is_list()) {
+        f_service_ <<
+          indent() << "$" << (*a_iter)->get_name() << " = json_decode($" << (*a_iter)->get_name() << ", true);" << endl;
+      } else if (atype->is_set()) {
+        f_service_ <<
+          indent() << "$" << (*a_iter)->get_name() << " = array_fill_keys(json_decode($" << (*a_iter)->get_name() << ", true), 1);" << endl;
+      } else if (atype->is_struct() || atype->is_xception()) {
+        f_service_ <<
+          indent() << "if ($" << (*a_iter)->get_name() << " !== null) {" << endl <<
+          indent() << "  $" << (*a_iter)->get_name() << " = new " << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($" << (*a_iter)->get_name() << ", true));" << endl <<
+          indent() << "}" << endl;
+      }
+    }
+    f_service_ <<
+      indent() << "return $this->impl_->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl;
+    indent_down();
+    indent(f_service_) <<
+      "}" << endl <<
+      endl;
+  }
+  indent_down();
+  f_service_ <<
+    "}" << endl << endl;
+}
+
+void t_php_generator::generate_service_client(t_service* tservice) {
+  if (autoload_) {
+    // Make output file
+    ofstream autoload_out;
+    string f_struct = program_name_+"."+(tservice->get_name())+".client.php";
+    string f_struct_name = get_out_dir()+f_struct;
+    autoload_out.open(f_struct_name.c_str());
+    autoload_out << "<?php" << endl;
+    _generate_service_client(autoload_out, tservice);
+    autoload_out << endl << "?>" << endl;
+    autoload_out.close();
+
+    f_service_ <<
+      "$GLOBALS['THRIFT_AUTOLOAD']['" << lowercase(service_name_ + "Client") << "'] = '" << program_name_ << "/" << f_struct << "';" << endl;
+
+  } else {
+    _generate_service_client(f_service_, tservice);
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_php_generator::_generate_service_client(ofstream& out, t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = tservice->get_extends()->get_name();
+    extends_client = " extends " + extends + "Client";
+  }
+
+  out <<
+    "class " << service_name_ << "Client" << extends_client << " implements " << service_name_ << "If {" << endl;
+  indent_up();
+
+  // Private members
+  if (extends.empty()) {
+    out <<
+      indent() << "protected $input_ = null;" << endl <<
+      indent() << "protected $output_ = null;" << endl <<
+      endl;
+    out <<
+      indent() << "protected $seqid_ = 0;" << endl <<
+      endl;
+  }
+
+  // Constructor function
+  out <<
+    indent() << "public function __construct($input, $output=null) {" << endl;
+  if (!extends.empty()) {
+    out <<
+      indent() << "  parent::__construct($input, $output);" << endl;
+  } else {
+    out <<
+      indent() << "  $this->input_ = $input;" << endl <<
+      indent() << "  $this->output_ = $output ? $output : $input;" << endl;
+  }
+  out <<
+    indent() << "}" << endl << endl;
+
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    indent(out) <<
+      "public function " << function_signature(*f_iter) << endl;
+    scope_up(out);
+      indent(out) <<
+        "$this->send_" << funname << "(";
+
+      bool first = true;
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        if (first) {
+          first = false;
+        } else {
+          out << ", ";
+        }
+        out << "$" << (*fld_iter)->get_name();
+      }
+      out << ");" << endl;
+
+      if (!(*f_iter)->is_oneway()) {
+        out << indent();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          out << "return ";
+        }
+        out <<
+          "$this->recv_" << funname << "();" << endl;
+      }
+    scope_down(out);
+    out << endl;
+
+    indent(out) <<
+      "public function send_" << function_signature(*f_iter) << endl;
+    scope_up(out);
+
+      std::string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args";
+
+      out <<
+        indent() << "$args = new " << argsname << "();" << endl;
+
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        out <<
+          indent() << "$args->" << (*fld_iter)->get_name() << " = $" << (*fld_iter)->get_name() << ";" << endl;
+      }
+
+      out <<
+        indent() << "$bin_accel = ($this->output_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_write_binary');" << endl;
+
+      out <<
+        indent() << "if ($bin_accel)" << endl;
+      scope_up(out);
+
+      out <<
+        indent() << "thrift_protocol_write_binary($this->output_, '" << (*f_iter)->get_name() << "', TMessageType::CALL, $args, $this->seqid_, $this->output_->isStrictWrite());" << endl;
+
+      scope_down(out);
+      out <<
+        indent() << "else" << endl;
+      scope_up(out);
+
+      // Serialize the request header
+      if (binary_inline_) {
+        out <<
+          indent() << "$buff = pack('N', (0x80010000 | TMessageType::CALL));" << endl <<
+          indent() << "$buff .= pack('N', strlen('" << funname << "'));" << endl <<
+          indent() << "$buff .= '" << funname << "';" << endl <<
+          indent() << "$buff .= pack('N', $this->seqid_);" << endl;
+      } else {
+        out <<
+          indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, $this->seqid_);" << endl;
+      }
+
+      // Write to the stream
+      if (binary_inline_) {
+        out <<
+          indent() << "$args->write($buff);" << endl <<
+          indent() << "$this->output_->write($buff);" << endl <<
+          indent() << "$this->output_->flush();" << endl;
+      } else {
+        out <<
+          indent() << "$args->write($this->output_);" << endl <<
+          indent() << "$this->output_->writeMessageEnd();" << endl <<
+          indent() << "$this->output_->getTransport()->flush();" << endl;
+      }
+
+    scope_down(out);
+
+    scope_down(out);
+
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
+      t_struct noargs(program_);
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      out <<
+        endl <<
+        indent() << "public function " << function_signature(&recv_function) << endl;
+      scope_up(out);
+
+      out <<
+        indent() << "$bin_accel = ($this->input_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED)"
+                 << " && function_exists('thrift_protocol_read_binary');" << endl;
+
+      out <<
+        indent() << "if ($bin_accel) $result = thrift_protocol_read_binary($this->input_, '" << resultname << "', $this->input_->isStrictRead());" << endl;
+      out <<
+        indent() << "else" << endl;
+      scope_up(out);
+
+      out <<
+        indent() << "$rseqid = 0;" << endl <<
+        indent() << "$fname = null;" << endl <<
+        indent() << "$mtype = 0;" << endl <<
+        endl;
+
+      if (binary_inline_) {
+        t_field ffname(g_type_string, "fname");
+        t_field fseqid(g_type_i32, "rseqid");
+        out <<
+          indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl <<
+          indent() << "$ver = $ver[1];" << endl <<
+          indent() << "$mtype = $ver & 0xff;" << endl <<
+          indent() << "$ver = $ver & 0xffff0000;" << endl <<
+          indent() << "if ($ver != 0x80010000) throw new TProtocolException('Bad version identifier: '.$ver, TProtocolException::BAD_VERSION);" << endl;
+        generate_deserialize_field(out, &ffname, "", true);
+        generate_deserialize_field(out, &fseqid, "", true);
+      } else {
+        out <<
+          indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl <<
+          indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl <<
+          indent() << "  $x = new TApplicationException();" << endl <<
+          indent() << "  $x->read($this->input_);" << endl <<
+          indent() << "  $this->input_->readMessageEnd();" << endl <<
+          indent() << "  throw $x;" << endl <<
+          indent() << "}" << endl;
+      }
+
+      out <<
+        indent() << "$result = new " << resultname << "();" << endl <<
+        indent() << "$result->read($this->input_);" << endl;
+
+      if (!binary_inline_) {
+        out <<
+          indent() << "$this->input_->readMessageEnd();" << endl;
+      }
+
+      scope_down(out);
+
+      // Careful, only return result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out <<
+          indent() << "if ($result->success !== null) {" << endl <<
+          indent() << "  return $result->success;" << endl <<
+          indent() << "}" << endl;
+      }
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        out <<
+          indent() << "if ($result->" << (*x_iter)->get_name() << " !== null) {" << endl <<
+          indent() << "  throw $result->" << (*x_iter)->get_name() << ";" << endl <<
+          indent() << "}" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(out) <<
+          "return;" << endl;
+      } else {
+        out <<
+          indent() << "throw new Exception(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+    // Close function
+    scope_down(out);
+    out << endl;
+
+    }
+  }
+
+  indent_down();
+  out <<
+    "}" << endl << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_php_generator::generate_deserialize_field(ofstream &out,
+                                                 t_field* tfield,
+                                                 string prefix,
+                                                 bool inclass) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type,
+                                 name);
+  } else {
+
+    if (type->is_container()) {
+      generate_deserialize_container(out, type, name);
+    } else if (type->is_base_type() || type->is_enum()) {
+
+      if (binary_inline_) {
+        std::string itrans = (inclass ? "$this->input_" : "$input");
+
+        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:
+            out <<
+              indent() << "$len = unpack('N', " << itrans << "->readAll(4));" << endl <<
+              indent() << "$len = $len[1];" << endl <<
+              indent() << "if ($len > 0x7fffffff) {" << endl <<
+              indent() << "  $len = 0 - (($len - 1) ^ 0xffffffff);" << endl <<
+              indent() << "}" << endl <<
+              indent() << "$" << name << " = " << itrans << "->readAll($len);" << endl;
+            break;
+          case t_base_type::TYPE_BOOL:
+            out <<
+              indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
+              indent() << "$" << name << " = (bool)$" << name << "[1];" << endl;
+            break;
+          case t_base_type::TYPE_BYTE:
+            out <<
+              indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
+              indent() << "$" << name << " = $" << name << "[1];" << endl;
+            break;
+          case t_base_type::TYPE_I16:
+            out <<
+              indent() << "$val = unpack('n', " << itrans << "->readAll(2));" << endl <<
+              indent() << "$val = $val[1];" << endl <<
+              indent() << "if ($val > 0x7fff) {" << endl <<
+              indent() << "  $val = 0 - (($val - 1) ^ 0xffff);" << endl <<
+              indent() << "}" << endl <<
+              indent() << "$" << name << " = $val;" << endl;
+            break;
+          case t_base_type::TYPE_I32:
+            out <<
+              indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl <<
+              indent() << "$val = $val[1];" << endl <<
+              indent() << "if ($val > 0x7fffffff) {" << endl <<
+              indent() << "  $val = 0 - (($val - 1) ^ 0xffffffff);" << endl <<
+              indent() << "}" << endl <<
+              indent() << "$" << name << " = $val;" << endl;
+            break;
+          case t_base_type::TYPE_I64:
+            out <<
+              indent() << "$arr = unpack('N2', " << itrans << "->readAll(8));" << endl <<
+              indent() << "if ($arr[1] & 0x80000000) {" << endl <<
+              indent() << "  $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl <<
+              indent() << "  $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl <<
+              indent() << "  $" << name << " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl <<
+              indent() << "} else {" << endl <<
+              indent() << "  $" << name << " = $arr[1]*4294967296 + $arr[2];" << endl <<
+              indent() << "}" << endl;
+            break;
+          case t_base_type::TYPE_DOUBLE:
+            out <<
+              indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl <<
+              indent() << "$" << name << " = $arr[1];" << endl;
+            break;
+          default:
+            throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase) + tfield->get_name();
+          }
+        } else if (type->is_enum()) {
+            out <<
+              indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl <<
+              indent() << "$val = $val[1];" << endl <<
+              indent() << "if ($val > 0x7fffffff) {" << endl <<
+              indent() << "  $val = 0 - (($val - 1) ^ 0xffffffff);" << endl <<
+              indent() << "}" << endl <<
+              indent() << "$" << name << " = $val;" << endl;
+        }
+      } else {
+
+        indent(out) <<
+          "$xfer += $input->";
+
+        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:
+            out << "readString($" << name << ");";
+            break;
+          case t_base_type::TYPE_BOOL:
+            out << "readBool($" << name << ");";
+            break;
+          case t_base_type::TYPE_BYTE:
+            out << "readByte($" << name << ");";
+            break;
+          case t_base_type::TYPE_I16:
+            out << "readI16($" << name << ");";
+            break;
+          case t_base_type::TYPE_I32:
+            out << "readI32($" << name << ");";
+            break;
+          case t_base_type::TYPE_I64:
+            out << "readI64($" << name << ");";
+            break;
+          case t_base_type::TYPE_DOUBLE:
+            out << "readDouble($" << name << ");";
+            break;
+          default:
+            throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
+          }
+        } else if (type->is_enum()) {
+          out << "readI32($" << name << ");";
+        }
+        out << endl;
+      }
+    } else {
+      printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+             tfield->get_name().c_str(), type->get_name().c_str());
+    }
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_php_generator::generate_deserialize_struct(ofstream &out,
+                                                  t_struct* tstruct,
+                                                  string prefix) {
+  out <<
+    indent() << "$" << prefix << " = new " << php_namespace(tstruct->get_program()) << tstruct->get_name() << "();" << endl <<
+    indent() << "$xfer += $" << prefix << "->read($input);" << endl;
+}
+
+void t_php_generator::generate_deserialize_container(ofstream &out,
+                                                     t_type* ttype,
+                                                     string prefix) {
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+
+  t_field fsize(g_type_i32, size);
+  t_field fktype(g_type_byte, ktype);
+  t_field fvtype(g_type_byte, vtype);
+  t_field fetype(g_type_byte, etype);
+
+  out <<
+    indent() << "$" << prefix << " = array();" << endl <<
+    indent() << "$" << size << " = 0;" << endl;
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out <<
+      indent() << "$" << ktype << " = 0;" << endl <<
+      indent() << "$" << vtype << " = 0;" << endl;
+    if (binary_inline_) {
+      generate_deserialize_field(out, &fktype);
+      generate_deserialize_field(out, &fvtype);
+      generate_deserialize_field(out, &fsize);
+    } else {
+      out <<
+        indent() << "$xfer += $input->readMapBegin(" <<
+        "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl;
+    }
+  } else if (ttype->is_set()) {
+    if (binary_inline_) {
+      generate_deserialize_field(out, &fetype);
+      generate_deserialize_field(out, &fsize);
+    } else {
+      out <<
+        indent() << "$" << etype << " = 0;" << endl <<
+        indent() << "$xfer += $input->readSetBegin(" <<
+        "$" << etype << ", $" << size << ");" << endl;
+    }
+  } else if (ttype->is_list()) {
+    if (binary_inline_) {
+      generate_deserialize_field(out, &fetype);
+      generate_deserialize_field(out, &fsize);
+    } else {
+      out <<
+        indent() << "$" << etype << " = 0;" << endl <<
+        indent() << "$xfer += $input->readListBegin(" <<
+        "$" << etype << ", $" << size << ");" << endl;
+    }
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) <<
+    "for ($" <<
+    i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
+
+    scope_up(out);
+
+    if (ttype->is_map()) {
+      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+    } else if (ttype->is_set()) {
+      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+    } else if (ttype->is_list()) {
+      generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+    }
+
+    scope_down(out);
+
+  if (!binary_inline_) {
+    // Read container end
+    if (ttype->is_map()) {
+      indent(out) << "$xfer += $input->readMapEnd();" << endl;
+    } else if (ttype->is_set()) {
+      indent(out) << "$xfer += $input->readSetEnd();" << endl;
+    } else if (ttype->is_list()) {
+      indent(out) << "$xfer += $input->readListEnd();" << endl;
+    }
+  }
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_php_generator::generate_deserialize_map_element(ofstream &out,
+                                                       t_map* tmap,
+                                                       string prefix) {
+  string key = tmp("key");
+  string val = tmp("val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) <<
+    declare_field(&fkey, true, true) << endl;
+  indent(out) <<
+    declare_field(&fval, true, true) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) <<
+    "$" << prefix << "[$" << key << "] = $" << val << ";" << endl;
+}
+
+void t_php_generator::generate_deserialize_set_element(ofstream &out,
+                                                       t_set* tset,
+                                                       string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) <<
+    "$" << elem << " = null;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    "$" << prefix << "[$" << elem << "] = true;" << endl;
+}
+
+void t_php_generator::generate_deserialize_list_element(ofstream &out,
+                                                        t_list* tlist,
+                                                        string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) <<
+    "$" << elem << " = null;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    "$" << prefix << " []= $" << elem << ";" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_php_generator::generate_serialize_field(ofstream &out,
+                                               t_field* tfield,
+                                               string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out,
+                              (t_struct*)type,
+                              prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out,
+                                 type,
+                                 prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = prefix + tfield->get_name();
+
+    if (binary_inline_) {
+      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:
+          out <<
+            indent() << "$output .= pack('N', strlen($" << name << "));" << endl <<
+            indent() << "$output .= $" << name << ";" << endl;
+          break;
+        case t_base_type::TYPE_BOOL:
+          out <<
+            indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl;
+          break;
+        case t_base_type::TYPE_BYTE:
+          out <<
+            indent() << "$output .= pack('c', $" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I16:
+          out <<
+            indent() << "$output .= pack('n', $" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I32:
+          out <<
+            indent() << "$output .= pack('N', $" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I64:
+          out <<
+            indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name << " & 0xFFFFFFFF);" << endl;
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          out <<
+            indent() << "$output .= strrev(pack('d', $" << name << "));" << endl;
+          break;
+        default:
+          throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
+        }
+      } else if (type->is_enum()) {
+        out <<
+          indent() << "$output .= pack('N', $" << name << ");" << endl;
+      }
+    } else {
+
+      indent(out) <<
+        "$xfer += $output->";
+
+      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:
+          out << "writeString($" << name << ");";
+          break;
+        case t_base_type::TYPE_BOOL:
+          out << "writeBool($" << name << ");";
+          break;
+        case t_base_type::TYPE_BYTE:
+          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 PHP name for base type " + t_base_type::t_base_name(tbase);
+        }
+      } else if (type->is_enum()) {
+        out << "writeI32($" << name << ");";
+      }
+      out << endl;
+    }
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_php_generator::generate_serialize_struct(ofstream &out,
+                                                t_struct* tstruct,
+                                                string prefix) {
+  indent(out) <<
+    "$xfer += $" << prefix << "->write($output);" << endl;
+}
+
+/**
+ * Writes out a container
+ */
+void t_php_generator::generate_serialize_container(ofstream &out,
+                                                   t_type* ttype,
+                                                   string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    if (binary_inline_) {
+      out <<
+        indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type()) << ");" << endl <<
+        indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl <<
+        indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
+    } else {
+      indent(out) <<
+        "$output->writeMapBegin(" <<
+        type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+        type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+        "count($" << prefix << "));" << endl;
+    }
+  } else if (ttype->is_set()) {
+    if (binary_inline_) {
+      out <<
+        indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl <<
+        indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
+
+    } else {
+      indent(out) <<
+        "$output->writeSetBegin(" <<
+        type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+        "count($" << prefix << "));" << endl;
+    }
+  } else if (ttype->is_list()) {
+    if (binary_inline_) {
+      out <<
+        indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl <<
+        indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
+
+    } else {
+      indent(out) <<
+        "$output->writeListBegin(" <<
+        type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+        "count($" << prefix << "));" << endl;
+    }
+  }
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    string kiter = tmp("kiter");
+    string viter = tmp("viter");
+    indent(out) <<
+      "foreach ($" << prefix << " as " <<
+      "$" << kiter << " => $" << viter << ")" << endl;
+    scope_up(out);
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    scope_down(out);
+  } else if (ttype->is_set()) {
+    string iter = tmp("iter");
+    indent(out) <<
+      "foreach ($" << prefix << " as $" << iter << " => $true)" << endl;
+    scope_up(out);
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    scope_down(out);
+  } else if (ttype->is_list()) {
+    string iter = tmp("iter");
+    indent(out) <<
+      "foreach ($" << prefix << " as $" << iter << ")" << endl;
+    scope_up(out);
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    scope_down(out);
+  }
+
+  scope_down(out);
+
+  if (!binary_inline_) {
+    if (ttype->is_map()) {
+      indent(out) <<
+        "$output->writeMapEnd();" << endl;
+    } else if (ttype->is_set()) {
+      indent(out) <<
+        "$output->writeSetEnd();" << endl;
+    } else if (ttype->is_list()) {
+      indent(out) <<
+        "$output->writeListEnd();" << endl;
+    }
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_php_generator::generate_serialize_map_element(ofstream &out,
+                                                     t_map* tmap,
+                                                     string kiter,
+                                                     string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield, "");
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_php_generator::generate_serialize_set_element(ofstream &out,
+                                                     t_set* tset,
+                                                     string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_php_generator::generate_serialize_list_element(ofstream &out,
+                                                      t_list* tlist,
+                                                      string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) {
+  string result = "$" + tfield->get_name();
+  if (init) {
+    t_type* type = get_true_type(tfield->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:
+        break;
+      case t_base_type::TYPE_STRING:
+        result += " = ''";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = 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:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = 0.0";
+        break;
+      default:
+        throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = 0";
+    } else if (type->is_container()) {
+      result += " = array()";
+    } else if (type->is_struct() || type->is_xception()) {
+      if (obj) {
+        result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()";
+      } else {
+        result += " = null";
+      }
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_php_generator::function_signature(t_function* tfunction,
+                                           string prefix) {
+  return
+    prefix + tfunction->get_name() +
+    "(" + argument_list(tfunction->get_arglist()) + ")";
+}
+
+/**
+ * Renders a field list
+ */
+string t_php_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;
+    } else {
+      result += ", ";
+    }
+    result += "$" + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+/**
+ * Gets a typecast string for a particular type.
+ */
+string t_php_generator::type_to_cast(t_type* type) {
+  if (type->is_base_type()) {
+    t_base_type* btype = (t_base_type*)type;
+    switch (btype->get_base()) {
+    case t_base_type::TYPE_BOOL:
+      return "(bool)";
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return "(int)";
+    case t_base_type::TYPE_DOUBLE:
+      return "(double)";
+    case t_base_type::TYPE_STRING:
+      return "(string)";
+    default:
+      return "";
+    }
+  } else if (type->is_enum()) {
+    return "(int)";
+  }
+  return "";
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_php_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::LST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(php, "PHP",
+"    inlined:         Generate PHP inlined files\n"
+"    server:          Generate PHP server stubs\n"
+"    autoload:        Generate PHP with autoload\n"
+"    oop:             Generate PHP with object oriented subclasses\n"
+"    rest:            Generate PHP REST processors\n"
+);
diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc
new file mode 100644
index 0000000..343c982
--- /dev/null
+++ b/compiler/cpp/src/generate/t_py_generator.cc
@@ -0,0 +1,2310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include <algorithm>
+#include "t_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * Python code generator.
+ *
+ */
+class t_py_generator : public t_generator {
+ public:
+  t_py_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_generator(program)
+  {
+    std::map<std::string, std::string>::const_iterator iter;
+
+    iter = parsed_options.find("new_style");
+    gen_newstyle_ = (iter != parsed_options.end());
+
+    iter = parsed_options.find("twisted");
+    gen_twisted_ = (iter != parsed_options.end());
+
+    out_dir_base_ = "gen-py";
+  }
+
+  /**
+   * 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_py_struct(t_struct* tstruct, bool is_exception);
+  void generate_py_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
+  void generate_py_struct_reader(std::ofstream& out, t_struct* tstruct);
+  void generate_py_struct_writer(std::ofstream& out, t_struct* tstruct);
+  void generate_py_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_service_client    (t_service* tservice);
+  void generate_service_remote    (t_service* tservice);
+  void generate_service_server    (t_service* tservice);
+  void generate_process_function  (t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="",
+                                          bool inclass=false);
+
+  void generate_deserialize_struct       (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_deserialize_container    (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_deserialize_set_element  (std::ofstream &out,
+                                          t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+
+  void generate_serialize_field          (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_serialize_struct         (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string kiter,
+                                          std::string viter);
+
+  void generate_serialize_set_element    (std::ofstream &out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  void generate_python_docstring         (std::ofstream& out,
+                                          t_struct* tstruct);
+
+  void generate_python_docstring         (std::ofstream& out,
+                                          t_function* tfunction);
+
+  void generate_python_docstring         (std::ofstream& out,
+                                          t_doc*    tdoc,
+                                          t_struct* tstruct,
+                                          const char* subheader);
+
+  void generate_python_docstring         (std::ofstream& out,
+                                          t_doc* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string py_autogen_comment();
+  std::string py_imports();
+  std::string render_includes();
+  std::string render_fastbinary_includes();
+  std::string declare_argument(t_field* tfield);
+  std::string render_field_default_value(t_field* tfield);
+  std::string type_name(t_type* ttype);
+  std::string function_signature(t_function* tfunction, std::string prefix="");
+  std::string function_signature_if(t_function* tfunction, std::string prefix="");
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string type_to_spec_args(t_type* ttype);
+
+  static std::string get_real_py_module(const t_program* program) {
+    std::string real_module = program->get_namespace("py");
+    if (real_module.empty()) {
+      return program->get_name();
+    }
+    return real_module;
+  }
+
+ private:
+
+  /**
+   * True iff we should generate new-style classes.
+   */
+  bool gen_newstyle_;
+
+  /**
+   * True iff we should generate Twisted-friendly RPC services.
+   */
+  bool gen_twisted_;
+
+  /**
+   * File streams
+   */
+
+  std::ofstream f_types_;
+  std::ofstream f_consts_;
+  std::ofstream f_service_;
+
+  std::string package_dir_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_py_generator::init_generator() {
+  // Make output directory
+  string module = get_real_py_module(program_);
+  package_dir_ = get_out_dir();
+  while (true) {
+    // TODO: Do better error checking here.
+    MKDIR(package_dir_.c_str());
+    std::ofstream init_py((package_dir_+"/__init__.py").c_str());
+    init_py.close();
+    if (module.empty()) {
+      break;
+    }
+    string::size_type pos = module.find('.');
+    if (pos == string::npos) {
+      package_dir_ += "/";
+      package_dir_ += module;
+      module.clear();
+    } else {
+      package_dir_ += "/";
+      package_dir_ += module.substr(0, pos);
+      module.erase(0, pos+1);
+    }
+  }
+
+  // Make output file
+  string f_types_name = package_dir_+"/"+"ttypes.py";
+  f_types_.open(f_types_name.c_str());
+
+  string f_consts_name = package_dir_+"/"+"constants.py";
+  f_consts_.open(f_consts_name.c_str());
+
+  string f_init_name = package_dir_+"/__init__.py";
+  ofstream f_init;
+  f_init.open(f_init_name.c_str());
+  f_init  <<
+    "__all__ = ['ttypes', 'constants'";
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    f_init << ", '" << (*sv_iter)->get_name() << "'";
+  }
+  f_init << "]" << endl;
+  f_init.close();
+
+  // Print header
+  f_types_ <<
+    py_autogen_comment() << endl <<
+    py_imports() << endl <<
+    render_includes() << endl <<
+    render_fastbinary_includes() <<
+    endl << endl;
+
+  f_consts_ <<
+    py_autogen_comment() << endl <<
+    py_imports() << endl <<
+    "from ttypes import *" << endl <<
+    endl;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_py_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += "import " + get_real_py_module(includes[i]) + ".ttypes\n";
+  }
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+  return result;
+}
+
+/**
+ * Renders all the imports necessary to use the accelerated TBinaryProtocol
+ */
+string t_py_generator::render_fastbinary_includes() {
+  return
+    "from thrift.transport import TTransport\n"
+    "from thrift.protocol import TBinaryProtocol\n"
+    "try:\n"
+    "  from thrift.protocol import fastbinary\n"
+    "except:\n"
+    "  fastbinary = None\n";
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_py_generator::py_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_py_generator::py_imports() {
+  return
+    string("from thrift.Thrift import *");
+}
+
+/**
+ * Closes the type files
+ */
+void t_py_generator::close_generator() {
+  // Close types file
+  f_types_.close();
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. This is not done in Python, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_py_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_py_generator::generate_enum(t_enum* tenum) {
+  f_types_ <<
+    "class " << tenum->get_name() <<
+    (gen_newstyle_ ? "(object)" : "") <<
+    ":" << endl;
+  indent_up();
+  generate_python_docstring(f_types_, 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;
+    }
+
+    f_types_ <<
+      indent() << (*c_iter)->get_name() << " = " << value << endl;
+  }
+
+  indent_down();
+  f_types_ << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_py_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  indent(f_consts_) << name << " = " << render_const_value(type, value);
+  f_consts_ << 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_py_generator::render_const_value(t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream out;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "True" : "False");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << type->get_name() << "(**{" << endl;
+    indent_up();
+    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;
+    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();
+      }
+      out << indent();
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " : ";
+      out << render_const_value(field_type, v_iter->second);
+      out << "," << endl;
+    }
+    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();
+    out << "{" << endl;
+    indent_up();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent();
+      out << render_const_value(ktype, v_iter->first);
+      out << " : ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << "}";
+  } 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();
+    }
+    if (type->is_set()) {
+      out << "set(";
+    }
+    out << "[" << endl;
+    indent_up();
+    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) {
+      out << indent();
+      out << render_const_value(etype, *v_iter);
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << "]";
+    if (type->is_set()) {
+      out << ")";
+    }
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+
+  return out.str();
+}
+
+/**
+ * Generates a python struct
+ */
+void t_py_generator::generate_struct(t_struct* tstruct) {
+  generate_py_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_py_generator::generate_xception(t_struct* txception) {
+  generate_py_struct(txception, true);
+}
+
+/**
+ * Generates a python struct
+ */
+void t_py_generator::generate_py_struct(t_struct* tstruct,
+                                        bool is_exception) {
+  generate_py_struct_definition(f_types_, tstruct, is_exception);
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_py_generator::generate_py_struct_definition(ofstream& out,
+                                                   t_struct* tstruct,
+                                                   bool is_exception,
+                                                   bool is_result) {
+
+  const vector<t_field*>& members = tstruct->get_members();
+  const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out <<
+    "class " << tstruct->get_name();
+  if (is_exception) {
+    out << "(Exception)";
+  } else if (gen_newstyle_) {
+    out << "(object)";
+  }
+  out <<
+    ":" << endl;
+  indent_up();
+  generate_python_docstring(out, tstruct);
+
+  out << endl;
+
+  /*
+     Here we generate the structure specification for the fastbinary codec.
+     These specifications have the following structure:
+     thrift_spec -> tuple of item_spec
+     item_spec -> None | (tag, type_enum, name, spec_args, default)
+     tag -> integer
+     type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
+     name -> string_literal
+     default -> None  # Handled by __init__
+     spec_args -> None  # For simple types
+                | (type_enum, spec_args)  # Value type for list/set
+                | (type_enum, spec_args, type_enum, spec_args)
+                  # Key and value for map
+                | (class_name, spec_args_ptr) # For struct/exception
+     class_name -> identifier  # Basically a pointer to the class
+     spec_args_ptr -> expression  # just class_name.spec_args
+
+     TODO(dreiss): Consider making this work for structs with negative tags.
+  */
+
+  // TODO(dreiss): Look into generating an empty tuple instead of None
+  // for structures with no members.
+  // TODO(dreiss): Test encoding of structs where some inner structs
+  // don't have thrift_spec.
+  if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
+    indent(out) << "thrift_spec = (" << endl;
+    indent_up();
+
+    int sorted_keys_pos = 0;
+    for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
+
+      for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) {
+        indent(out) << "None, # " << sorted_keys_pos << endl;
+      }
+
+      indent(out) << "(" << (*m_iter)->get_key() << ", "
+            << type_to_enum((*m_iter)->get_type()) << ", "
+            << "'" << (*m_iter)->get_name() << "'" << ", "
+            << type_to_spec_args((*m_iter)->get_type()) << ", "
+            << render_field_default_value(*m_iter) << ", "
+            << "),"
+            << " # " << sorted_keys_pos
+            << endl;
+
+      sorted_keys_pos ++;
+    }
+
+    indent_down();
+    indent(out) << ")" << endl << endl;
+  } else {
+    indent(out) << "thrift_spec = None" << endl;
+  }
+
+
+  if (members.size() > 0) {
+    out <<
+      indent() << "def __init__(self,";
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      // This fills in default values, as opposed to nulls
+      out << " " << declare_argument(*m_iter) << ",";
+    }
+
+    out << "):" << endl;
+
+    indent_up();
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      // Initialize fields
+      t_type* type = (*m_iter)->get_type();
+      if (!type->is_base_type() && !type->is_enum() && (*m_iter)->get_value() != NULL) {
+        indent(out) <<
+          "if " << (*m_iter)->get_name() << " is " << "self.thrift_spec[" <<
+            (*m_iter)->get_key() << "][4]:" << endl;
+        indent(out) << "  " << (*m_iter)->get_name() << " = " <<
+          render_field_default_value(*m_iter) << endl;
+      }
+      indent(out) <<
+        "self." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << endl;
+    }
+
+    indent_down();
+
+    out << endl;
+  }
+
+  generate_py_struct_reader(out, tstruct);
+  generate_py_struct_writer(out, tstruct);
+
+  // For exceptions only, generate a __str__ method. This is
+  // because when raised exceptions are printed to the console, __repr__
+  // isn't used. See python bug #5882
+  if (is_exception) {
+    out <<
+      indent() << "def __str__(self):" << endl <<
+      indent() << "  return repr(self)" << endl <<
+      endl;
+  }
+
+  // Printing utilities so that on the command line thrift
+  // structs look pretty like dictionaries
+  out <<
+    indent() << "def __repr__(self):" << endl <<
+    indent() << "  L = ['%s=%r' % (key, value)" << endl <<
+    indent() << "    for key, value in self.__dict__.iteritems()]" << endl <<
+    indent() << "  return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl <<
+    endl;
+
+  // Equality and inequality methods that compare by value
+  out <<
+    indent() << "def __eq__(self, other):" << endl;
+  indent_up();
+  out <<
+    indent() << "return isinstance(other, self.__class__) and "
+                "self.__dict__ == other.__dict__" << endl;
+  indent_down();
+  out << endl;
+
+  out <<
+    indent() << "def __ne__(self, other):" << endl;
+  indent_up();
+  out <<
+    indent() << "return not (self == other)" << endl;
+  indent_down();
+  out << endl;
+
+  indent_down();
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_py_generator::generate_py_struct_reader(ofstream& out,
+                                                t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "def read(self, iprot):" << endl;
+  indent_up();
+
+  indent(out) <<
+    "if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated "
+    "and isinstance(iprot.trans, TTransport.CReadableTransport) "
+    "and self.thrift_spec is not None "
+    "and fastbinary is not None:" << endl;
+  indent_up();
+
+  indent(out) <<
+    "fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))" << endl;
+  indent(out) <<
+    "return" << endl;
+  indent_down();
+
+  indent(out) <<
+    "iprot.readStructBegin()" << endl;
+
+  // Loop over reading in fields
+  indent(out) <<
+    "while True:" << endl;
+    indent_up();
+
+    // Read beginning field marker
+    indent(out) <<
+      "(fname, ftype, fid) = iprot.readFieldBegin()" << endl;
+
+    // Check for field STOP marker and break
+    indent(out) <<
+      "if ftype == TType.STOP:" << endl;
+    indent_up();
+    indent(out) <<
+      "break" << endl;
+    indent_down();
+
+    // Switch statement on the field we are reading
+    bool first = true;
+
+    // Generate deserialization code for known cases
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if (first) {
+        first = false;
+        out <<
+          indent() << "if ";
+      } else {
+        out <<
+          indent() << "elif ";
+      }
+      out << "fid == " << (*f_iter)->get_key() << ":" << endl;
+      indent_up();
+      indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << ":" << endl;
+      indent_up();
+      generate_deserialize_field(out, *f_iter, "self.");
+      indent_down();
+      out <<
+        indent() << "else:" << endl <<
+        indent() << "  iprot.skip(ftype)" << endl;
+      indent_down();
+    }
+
+    // In the default case we skip the field
+    out <<
+      indent() <<  "else:" << endl <<
+      indent() <<  "  iprot.skip(ftype)" << endl;
+
+    // Read field end marker
+    indent(out) <<
+      "iprot.readFieldEnd()" << endl;
+
+    indent_down();
+
+    indent(out) <<
+      "iprot.readStructEnd()" << endl;
+
+    indent_down();
+  out << endl;
+}
+
+void t_py_generator::generate_py_struct_writer(ofstream& out,
+                                               t_struct* tstruct) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) <<
+    "def write(self, oprot):" << endl;
+  indent_up();
+
+  indent(out) <<
+    "if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated "
+    "and self.thrift_spec is not None "
+    "and fastbinary is not None:" << endl;
+  indent_up();
+
+  indent(out) <<
+    "oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))" << endl;
+  indent(out) <<
+    "return" << endl;
+  indent_down();
+
+  indent(out) <<
+    "oprot.writeStructBegin('" << name << "')" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    // Write field header
+    indent(out) <<
+      "if self." << (*f_iter)->get_name() << " != None:" << endl;
+    indent_up();
+    indent(out) <<
+      "oprot.writeFieldBegin(" <<
+      "'" << (*f_iter)->get_name() << "', " <<
+      type_to_enum((*f_iter)->get_type()) << ", " <<
+      (*f_iter)->get_key() << ")" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "self.");
+
+    // Write field closer
+    indent(out) <<
+      "oprot.writeFieldEnd()" << endl;
+
+    indent_down();
+  }
+
+  // Write the struct map
+  out <<
+    indent() << "oprot.writeFieldStop()" << endl <<
+    indent() << "oprot.writeStructEnd()" << endl;
+
+  indent_down();
+  out <<
+    endl;
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_py_generator::generate_service(t_service* tservice) {
+  string f_service_name = package_dir_+"/"+service_name_+".py";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    py_autogen_comment() << endl <<
+    py_imports() << endl;
+
+  if (tservice->get_extends() != NULL) {
+    f_service_ <<
+      "import " << get_real_py_module(tservice->get_extends()->get_program()) <<
+      "." << tservice->get_extends()->get_name() << endl;
+  }
+
+  f_service_ <<
+    "from ttypes import *" << endl <<
+    "from thrift.Thrift import TProcessor" << endl <<
+    render_fastbinary_includes() << endl;
+
+  if (gen_twisted_) {
+    f_service_ <<
+      "from zope.interface import Interface, implements" << endl <<
+      "from twisted.internet import defer" << endl <<
+      "from thrift.transport import TTwisted" << endl;
+  }
+
+  f_service_ << endl;
+
+  // Generate the three main parts of the service (well, two for now in PHP)
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+  generate_service_remote(tservice);
+
+  // Close service file
+  f_service_ << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_py_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  f_service_ <<
+    "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_py_struct_definition(f_service_, ts, false);
+    generate_py_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_py_generator::generate_py_function_helpers(t_function* tfunction) {
+  if (!tfunction->is_oneway()) {
+    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_py_struct_definition(f_service_, &result, false, true);
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_py_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_if = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_if = "(" + extends + ".Iface)";
+  } else {
+    if (gen_twisted_) {
+      extends_if = "(Interface)";
+    }
+  }
+
+  f_service_ <<
+    "class Iface" << extends_if << ":" << endl;
+  indent_up();
+  generate_python_docstring(f_service_, tservice);
+  vector<t_function*> functions = tservice->get_functions();
+  if (functions.empty()) {
+    f_service_ <<
+      indent() << "pass" << endl;
+  } else {
+    vector<t_function*>::iterator f_iter;
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      f_service_ <<
+        indent() << "def " << function_signature_if(*f_iter) << ":" << endl;
+      indent_up();
+      generate_python_docstring(f_service_, (*f_iter));
+      f_service_ <<
+        indent() << "pass" << endl << endl;
+      indent_down();
+    }
+  }
+
+  indent_down();
+  f_service_ <<
+    endl;
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_py_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    if (gen_twisted_) {
+      extends_client = "(" + extends + ".Client)";
+    } else {
+      extends_client = extends + ".Client, ";
+    }
+  } else {
+    if (gen_twisted_ && gen_newstyle_) {
+        extends_client = "(object)";
+    }
+  }
+
+  if (gen_twisted_) {
+    f_service_ <<
+      "class Client" << extends_client << ":" << endl <<
+      "  implements(Iface)" << endl << endl;
+  } else {
+    f_service_ <<
+      "class Client(" << extends_client << "Iface):" << endl;
+  }
+  indent_up();
+  generate_python_docstring(f_service_, tservice);
+
+  // Constructor function
+  if (gen_twisted_) {
+    f_service_ <<
+      indent() << "def __init__(self, transport, oprot_factory):" << endl;
+  } else {
+    f_service_ <<
+      indent() << "def __init__(self, iprot, oprot=None):" << endl;
+  }
+  if (extends.empty()) {
+    if (gen_twisted_) {
+      f_service_ <<
+        indent() << "  self._transport = transport" << endl <<
+        indent() << "  self._oprot_factory = oprot_factory" << endl <<
+        indent() << "  self._seqid = 0" << endl <<
+        indent() << "  self._reqs = {}" << endl <<
+        endl;
+    } else {
+      f_service_ <<
+        indent() << "  self._iprot = self._oprot = iprot" << endl <<
+        indent() << "  if oprot != None:" << endl <<
+        indent() << "    self._oprot = oprot" << endl <<
+        indent() << "  self._seqid = 0" << endl <<
+        endl;
+    }
+  } else {
+    if (gen_twisted_) {
+      f_service_ <<
+        indent() << "  " << extends << ".Client.__init__(self, transport, oprot_factory)" << endl <<
+        endl;
+    } else {
+      f_service_ <<
+        indent() << "  " << extends << ".Client.__init__(self, iprot, oprot)" << endl <<
+        endl;
+    }
+  }
+
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    indent(f_service_) <<
+      "def " << function_signature(*f_iter) << ":" << endl;
+    indent_up();
+    generate_python_docstring(f_service_, (*f_iter));
+    if (gen_twisted_) {
+      indent(f_service_) << "self._seqid += 1" << endl;
+      if (!(*f_iter)->is_oneway()) {
+        indent(f_service_) <<
+          "d = self._reqs[self._seqid] = defer.Deferred()" << endl;
+      }
+    }
+
+    indent(f_service_) <<
+      "self.send_" << funname << "(";
+
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << (*fld_iter)->get_name();
+    }
+    f_service_ << ")" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (gen_twisted_) {
+        f_service_ << "return d" << endl;
+      } else {
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          f_service_ << "return ";
+        }
+        f_service_ <<
+          "self.recv_" << funname << "()" << endl;
+      }
+    } else {
+      if (gen_twisted_) {
+        f_service_ <<
+          indent() << "return defer.succeed(None)" << endl;
+      }
+    }
+    indent_down();
+    f_service_ << endl;
+
+    indent(f_service_) <<
+      "def send_" << function_signature(*f_iter) << ":" << endl;
+
+    indent_up();
+
+    std::string argsname = (*f_iter)->get_name() + "_args";
+
+    // Serialize the request header
+    if (gen_twisted_) {
+      f_service_ <<
+        indent() << "oprot = self._oprot_factory.getProtocol(self._transport)" << endl <<
+        indent() <<
+          "oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)"
+        << endl;
+    } else {
+      f_service_ <<
+        indent() << "self._oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)" << endl;
+    }
+
+    f_service_ <<
+      indent() << "args = " << argsname << "()" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ <<
+        indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << endl;
+    }
+
+    // Write to the stream
+    if (gen_twisted_) {
+      f_service_ <<
+        indent() << "args.write(oprot)" << endl <<
+        indent() << "oprot.writeMessageEnd()" << endl <<
+        indent() << "oprot.trans.flush()" << endl;
+    } else {
+      f_service_ <<
+        indent() << "args.write(self._oprot)" << endl <<
+        indent() << "self._oprot.writeMessageEnd()" << endl <<
+        indent() << "self._oprot.trans.flush()" << endl;
+    }
+
+    indent_down();
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = (*f_iter)->get_name() + "_result";
+      // Open function
+      f_service_ <<
+        endl;
+      if (gen_twisted_) {
+        f_service_ <<
+          indent() << "def recv_" << (*f_iter)->get_name() <<
+              "(self, iprot, mtype, rseqid):" << endl;
+      } else {
+        t_struct noargs(program_);
+        t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+        f_service_ <<
+          indent() << "def " << function_signature(&recv_function) << ":" << endl;
+      }
+      indent_up();
+
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+
+      if (gen_twisted_) {
+        f_service_ <<
+          indent() << "d = self._reqs.pop(rseqid)" << endl;
+      } else {
+        f_service_ <<
+          indent() << "(fname, mtype, rseqid) = self._iprot.readMessageBegin()" << endl;
+      }
+
+      f_service_ <<
+        indent() << "if mtype == TMessageType.EXCEPTION:" << endl <<
+        indent() << "  x = TApplicationException()" << endl;
+
+      if (gen_twisted_) {
+        f_service_ <<
+          indent() << "  x.read(iprot)" << endl <<
+          indent() << "  iprot.readMessageEnd()" << endl <<
+          indent() << "  return d.errback(x)" << endl <<
+          indent() << "result = " << resultname << "()" << endl <<
+          indent() << "result.read(iprot)" << endl <<
+          indent() << "iprot.readMessageEnd()" << endl;
+      } else {
+        f_service_ <<
+          indent() << "  x.read(self._iprot)" << endl <<
+          indent() << "  self._iprot.readMessageEnd()" << endl <<
+          indent() << "  raise x" << endl <<
+          indent() << "result = " << resultname << "()" << endl <<
+          indent() << "result.read(self._iprot)" << endl <<
+          indent() << "self._iprot.readMessageEnd()" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "if result.success != None:" << endl;
+          if (gen_twisted_) {
+            f_service_ <<
+              indent() << "  return d.callback(result.success)" << endl;
+          } else {
+            f_service_ <<
+              indent() << "  return result.success" << endl;
+          }
+      }
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "if result." << (*x_iter)->get_name() << " != None:" << endl;
+          if (gen_twisted_) {
+            f_service_ <<
+              indent() << "  return d.errback(result." << (*x_iter)->get_name() << ")" << endl;
+
+          } else {
+            f_service_ <<
+              indent() << "  raise result." << (*x_iter)->get_name() << "" << endl;
+          }
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        if (gen_twisted_) {
+          indent(f_service_) <<
+            "return d.callback(None)" << endl;
+        } else {
+          indent(f_service_) <<
+            "return" << endl;
+        }
+      } else {
+        if (gen_twisted_) {
+          f_service_ <<
+            indent() << "return d.errback(TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"))" << endl;
+        } else {
+          f_service_ <<
+            indent() << "raise TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+        }
+      }
+
+      // Close function
+      indent_down();
+      f_service_ << endl;
+    }
+  }
+
+  indent_down();
+  f_service_ <<
+    endl;
+}
+
+/**
+ * Generates a command line tool for making remote requests
+ *
+ * @param tservice The service to generate a remote for.
+ */
+void t_py_generator::generate_service_remote(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string f_remote_name = package_dir_+"/"+service_name_+"-remote";
+  ofstream f_remote;
+  f_remote.open(f_remote_name.c_str());
+
+  f_remote <<
+    "#!/usr/bin/env python" << endl <<
+    py_autogen_comment() << endl <<
+    "import sys" << endl <<
+    "import pprint" << endl <<
+    "from urlparse import urlparse" << endl <<
+    "from thrift.transport import TTransport" << endl <<
+    "from thrift.transport import TSocket" << endl <<
+    "from thrift.transport import THttpClient" << endl <<
+    "from thrift.protocol import TBinaryProtocol" << endl <<
+    endl;
+
+  f_remote <<
+    "import " << service_name_ << endl <<
+    "from ttypes import *" << endl <<
+    endl;
+
+  f_remote <<
+    "if len(sys.argv) <= 1 or sys.argv[1] == '--help':" << endl <<
+    "  print ''" << endl <<
+    "  print 'Usage: ' + sys.argv[0] + ' [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]'" << endl <<
+    "  print ''" << endl <<
+    "  print 'Functions:'" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_remote <<
+      "  print '  " << (*f_iter)->get_returntype()->get_name() << " " << (*f_iter)->get_name() << "(";
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const std::vector<t_field*>& args = arg_struct->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    int num_args = args.size();
+    bool first = true;
+    for (int i = 0; i < num_args; ++i) {
+      if (first) {
+        first = false;
+      } else {
+        f_remote << ", ";
+      }
+      f_remote <<
+        args[i]->get_type()->get_name() << " " << args[i]->get_name();
+    }
+    f_remote << ")'" << endl;
+  }
+  f_remote <<
+    "  print ''" << endl <<
+    "  sys.exit(0)" << endl <<
+    endl;
+
+  f_remote <<
+    "pp = pprint.PrettyPrinter(indent = 2)" << endl <<
+    "host = 'localhost'" << endl <<
+    "port = 9090" << endl <<
+    "uri = ''" << endl <<
+    "framed = False" << endl <<
+    "http = False" << endl <<
+    "argi = 1" << endl <<
+    endl <<
+    "if sys.argv[argi] == '-h':" << endl <<
+    "  parts = sys.argv[argi+1].split(':') " << endl <<
+    "  host = parts[0]" << endl <<
+    "  port = int(parts[1])" << endl <<
+    "  argi += 2" << endl <<
+    endl <<
+    "if sys.argv[argi] == '-u':" << endl <<
+    "  url = urlparse(sys.argv[argi+1])" << endl <<
+    "  parts = url[1].split(':') " << endl <<
+    "  host = parts[0]" << endl <<
+    "  if len(parts) > 1:" << endl <<
+    "    port = int(parts[1])" << endl <<
+    "  else:" << endl <<
+    "    port = 80" << endl <<
+    "  uri = url[2]" << endl <<
+    "  http = True" << endl <<
+    "  argi += 2" << endl <<
+    endl <<
+    "if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':" << endl <<
+    "  framed = True" << endl <<
+    "  argi += 1" << endl <<
+    endl <<
+    "cmd = sys.argv[argi]" << endl <<
+    "args = sys.argv[argi+1:]" << endl <<
+    endl <<
+    "if http:" << endl <<
+    "  transport = THttpClient.THttpClient(host, port, uri)" << endl <<
+    "else:" << endl <<
+    "  socket = TSocket.TSocket(host, port)" << endl <<
+    "  if framed:" << endl <<
+    "    transport = TTransport.TFramedTransport(socket)" << endl <<
+    "  else:" << endl <<
+    "    transport = TTransport.TBufferedTransport(socket)" << endl <<
+    "protocol = TBinaryProtocol.TBinaryProtocol(transport)" << endl <<
+    "client = " << service_name_ << ".Client(protocol)" << endl <<
+    "transport.open()" << endl <<
+    endl;
+
+  // Generate the dispatch methods
+  bool first = true;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_remote << "el";
+    }
+
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const std::vector<t_field*>& args = arg_struct->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    int num_args = args.size();
+
+    f_remote <<
+      "if cmd == '" << (*f_iter)->get_name() << "':" << endl <<
+      "  if len(args) != " << num_args << ":" << endl <<
+      "    print '" << (*f_iter)->get_name() << " requires " << num_args << " args'" << endl <<
+      "    sys.exit(1)" << endl <<
+      "  pp.pprint(client." << (*f_iter)->get_name() << "(";
+    for (int i = 0; i < num_args; ++i) {
+      if (args[i]->get_type()->is_string()) {
+        f_remote << "args[" << i << "],";
+      } else {
+        f_remote << "eval(args[" << i << "]),";
+      }
+    }
+    f_remote << "))" << endl;
+
+    f_remote << endl;
+  }
+
+  f_remote << "transport.close()" << endl;
+
+  // Close service file
+  f_remote.close();
+
+  // Make file executable, love that bitwise OR action
+  chmod(f_remote_name.c_str(),
+          S_IRUSR
+        | S_IWUSR
+        | S_IXUSR
+#ifndef MINGW
+        | S_IRGRP
+        | S_IXGRP
+        | S_IROTH
+        | S_IXOTH
+#endif
+  );
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_py_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".Processor, ";
+  }
+
+  // Generate the header portion
+  if (gen_twisted_) {
+    f_service_ <<
+      "class Processor(" << extends_processor << "TProcessor):" << endl <<
+      "  implements(Iface)" << endl << endl;
+  } else {
+    f_service_ <<
+      "class Processor(" << extends_processor << "Iface, TProcessor):" << endl;
+  }
+
+  indent_up();
+
+  indent(f_service_) <<
+    "def __init__(self, handler):" << endl;
+  indent_up();
+  if (extends.empty()) {
+    if (gen_twisted_) {
+      f_service_ <<
+        indent() << "self._handler = Iface(handler)" << endl;
+    } else {
+      f_service_ <<
+        indent() << "self._handler = handler" << endl;
+    }
+
+    f_service_ <<
+      indent() << "self._processMap = {}" << endl;
+  } else {
+    if (gen_twisted_) {
+      f_service_ <<
+        indent() << extends << ".Processor.__init__(self, Iface(handler))" << endl;
+    } else {
+      f_service_ <<
+        indent() << extends << ".Processor.__init__(self, handler)" << endl;
+    }
+  }
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ <<
+      indent() << "self._processMap[\"" << (*f_iter)->get_name() << "\"] = Processor.process_" << (*f_iter)->get_name() << endl;
+  }
+  indent_down();
+  f_service_ << endl;
+
+  // Generate the server implementation
+  indent(f_service_) <<
+    "def process(self, iprot, oprot):" << endl;
+  indent_up();
+
+  f_service_ <<
+    indent() << "(name, type, seqid) = iprot.readMessageBegin()" << endl;
+
+  // TODO(mcslee): validate message
+
+  // HOT: dictionary function lookup
+  f_service_ <<
+    indent() << "if name not in self._processMap:" << endl <<
+    indent() << "  iprot.skip(TType.STRUCT)" << endl <<
+    indent() << "  iprot.readMessageEnd()" << endl <<
+    indent() << "  x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown function %s' % (name))" << endl <<
+    indent() << "  oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)" << endl <<
+    indent() << "  x.write(oprot)" << endl <<
+    indent() << "  oprot.writeMessageEnd()" << endl <<
+    indent() << "  oprot.trans.flush()" << endl;
+
+  if (gen_twisted_) {
+    f_service_ <<
+      indent() << "  return defer.succeed(None)" << endl;
+  } else {
+    f_service_ <<
+      indent() << "  return" << endl;
+  }
+
+  f_service_ <<
+    indent() << "else:" << endl;
+
+  if (gen_twisted_) {
+    f_service_ <<
+      indent() << "  return self._processMap[name](self, seqid, iprot, oprot)" << endl;
+  } else {
+    f_service_ <<
+      indent() << "  self._processMap[name](self, seqid, iprot, oprot)" << endl;
+
+    // Read end of args field, the T_STOP, and the struct close
+    f_service_ <<
+      indent() << "return True" << endl;
+  }
+
+  indent_down();
+  f_service_ << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  f_service_ << endl;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_py_generator::generate_process_function(t_service* tservice,
+                                               t_function* tfunction) {
+  // Open function
+  indent(f_service_) <<
+    "def process_" << tfunction->get_name() <<
+    "(self, seqid, iprot, oprot):" << endl;
+  indent_up();
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ <<
+    indent() << "args = " << argsname << "()" << endl <<
+    indent() << "args.read(iprot)" << endl <<
+    indent() << "iprot.readMessageEnd()" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "result = " << resultname << "()" << endl;
+  }
+
+  if (gen_twisted_) {
+    // Generate the function call
+    t_struct* arg_struct = tfunction->get_arglist();
+    const std::vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    f_service_ <<
+      indent() << "d = defer.maybeDeferred(self._handler." <<
+        tfunction->get_name() << ", ";
+    bool first = true;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << "args." << (*f_iter)->get_name();
+    }
+    f_service_ << ")" << endl;
+
+    // Shortcut out here for oneway functions
+    if (tfunction->is_oneway()) {
+      f_service_ <<
+        indent() << "return d" << endl;
+      indent_down();
+      f_service_ << endl;
+      return;
+    }
+
+    f_service_ <<
+      indent() <<
+        "d.addCallback(self.write_results_success_" <<
+          tfunction->get_name() << ", result, seqid, oprot)" << endl;
+
+    if (xceptions.size() > 0) {
+      f_service_ <<
+        indent() <<
+          "d.addErrback(self.write_results_exception_" <<
+            tfunction->get_name() << ", result, seqid, oprot)" << endl;
+    }
+
+    f_service_ <<
+      indent() << "return d" << endl;
+
+    indent_down();
+    f_service_ << endl;
+
+    indent(f_service_) <<
+        "def write_results_success_" << tfunction->get_name() <<
+        "(self, success, result, seqid, oprot):" << endl;
+    indent_up();
+    f_service_ <<
+      indent() << "result.success = success" << endl <<
+      indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() <<
+        "\", TMessageType.REPLY, seqid)" << endl <<
+      indent() << "result.write(oprot)" << endl <<
+      indent() << "oprot.writeMessageEnd()" << endl <<
+      indent() << "oprot.trans.flush()" << endl;
+    indent_down();
+    f_service_ << endl;
+
+    // Try block for a function with exceptions
+    if (!tfunction->is_oneway() && xceptions.size() > 0) {
+      indent(f_service_) <<
+        "def write_results_exception_" << tfunction->get_name() <<
+        "(self, error, result, seqid, oprot):" << endl;
+      indent_up();
+      f_service_ <<
+        indent() << "try:" << endl;
+
+      // Kinda absurd
+      f_service_ <<
+        indent() << "  error.raiseException()" << endl;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "except " << type_name((*x_iter)->get_type()) << ", " << (*x_iter)->get_name() << ":" << endl;
+        if (!tfunction->is_oneway()) {
+          indent_up();
+          f_service_ <<
+            indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
+          indent_down();
+        } else {
+          f_service_ <<
+            indent() << "pass" << endl;
+        }
+      }
+      f_service_ <<
+        indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() <<
+          "\", TMessageType.REPLY, seqid)" << endl <<
+        indent() << "result.write(oprot)" << endl <<
+        indent() << "oprot.writeMessageEnd()" << endl <<
+        indent() << "oprot.trans.flush()" << endl;
+      indent_down();
+      f_service_ << endl;
+    }
+  } else {
+
+    // Try block for a function with exceptions
+    if (xceptions.size() > 0) {
+      f_service_ <<
+        indent() << "try:" << endl;
+      indent_up();
+    }
+
+    // Generate the function call
+    t_struct* arg_struct = tfunction->get_arglist();
+    const std::vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    f_service_ << indent();
+    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+      f_service_ << "result.success = ";
+    }
+    f_service_ <<
+      "self._handler." << tfunction->get_name() << "(";
+    bool first = true;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << "args." << (*f_iter)->get_name();
+    }
+    f_service_ << ")" << endl;
+
+    if (!tfunction->is_oneway() && xceptions.size() > 0) {
+      indent_down();
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ <<
+          indent() << "except " << type_name((*x_iter)->get_type()) << ", " << (*x_iter)->get_name() << ":" << endl;
+        if (!tfunction->is_oneway()) {
+          indent_up();
+          f_service_ <<
+            indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
+          indent_down();
+        } else {
+          f_service_ <<
+            indent() << "pass" << endl;
+        }
+      }
+    }
+
+    // Shortcut out here for oneway functions
+    if (tfunction->is_oneway()) {
+      f_service_ <<
+        indent() << "return" << endl;
+      indent_down();
+      f_service_ << endl;
+      return;
+    }
+
+    f_service_ <<
+      indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl <<
+      indent() << "result.write(oprot)" << endl <<
+      indent() << "oprot.writeMessageEnd()" << endl <<
+      indent() << "oprot.trans.flush()" << endl;
+
+    // Close function
+    indent_down();
+    f_service_ << endl;
+  }
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_py_generator::generate_deserialize_field(ofstream &out,
+                                                t_field* tfield,
+                                                string prefix,
+                                                bool inclass) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type,
+                                 name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) <<
+      name << " = 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:
+        out << "readString();";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool();";
+        break;
+      case t_base_type::TYPE_BYTE:
+        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 PHP name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32();";
+    }
+    out << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(), type->get_name().c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, calling read()
+ */
+void t_py_generator::generate_deserialize_struct(ofstream &out,
+                                                  t_struct* tstruct,
+                                                  string prefix) {
+  out <<
+    indent() << prefix << " = " << type_name(tstruct) << "()" << endl <<
+    indent() << prefix << ".read(iprot)" << endl;
+}
+
+/**
+ * Serialize a container by writing out the header followed by
+ * data and then a footer.
+ */
+void t_py_generator::generate_deserialize_container(ofstream &out,
+                                                    t_type* ttype,
+                                                    string prefix) {
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+
+  t_field fsize(g_type_i32, size);
+  t_field fktype(g_type_byte, ktype);
+  t_field fvtype(g_type_byte, vtype);
+  t_field fetype(g_type_byte, etype);
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out <<
+      indent() << prefix << " = {}" << endl <<
+      indent() << "(" << ktype << ", " << vtype << ", " << size << " ) = iprot.readMapBegin() " << endl;
+  } else if (ttype->is_set()) {
+    out <<
+      indent() << prefix << " = set()" << endl <<
+      indent() << "(" << etype << ", " << size << ") = iprot.readSetBegin()" << endl;
+  } else if (ttype->is_list()) {
+    out <<
+      indent() << prefix << " = []" << endl <<
+      indent() << "(" << etype << ", " << size << ") = iprot.readListBegin()" << endl;
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) <<
+    "for " << i << " in xrange(" << size << "):" << endl;
+
+    indent_up();
+
+    if (ttype->is_map()) {
+      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+    } else if (ttype->is_set()) {
+      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+    } else if (ttype->is_list()) {
+      generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+    }
+
+    indent_down();
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot.readMapEnd()" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.readSetEnd()" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.readListEnd()" << endl;
+  }
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_py_generator::generate_deserialize_map_element(ofstream &out,
+                                                       t_map* tmap,
+                                                       string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) <<
+    prefix << "[" << key << "] = " << val << endl;
+}
+
+/**
+ * Write a set element
+ */
+void t_py_generator::generate_deserialize_set_element(ofstream &out,
+                                                       t_set* tset,
+                                                       string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".add(" << elem << ")" << endl;
+}
+
+/**
+ * Write a list element
+ */
+void t_py_generator::generate_deserialize_list_element(ofstream &out,
+                                                        t_list* tlist,
+                                                        string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) <<
+    prefix << ".append(" << elem << ")" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_py_generator::generate_serialize_field(ofstream &out,
+                                               t_field* tfield,
+                                               string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out,
+                              (t_struct*)type,
+                              prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out,
+                                 type,
+                                 prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = prefix + tfield->get_name();
+
+    indent(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:
+        out << "writeString(" << name << ")";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ")";
+        break;
+      case t_base_type::TYPE_BYTE:
+        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 PHP name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(" << name << ")";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_py_generator::generate_serialize_struct(ofstream &out,
+                                               t_struct* tstruct,
+                                               string prefix) {
+  indent(out) <<
+    prefix << ".write(oprot)" << endl;
+}
+
+void t_py_generator::generate_serialize_container(ofstream &out,
+                                                  t_type* ttype,
+                                                  string prefix) {
+  if (ttype->is_map()) {
+    indent(out) <<
+      "oprot.writeMapBegin(" <<
+      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+      "len(" << prefix << "))" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "oprot.writeSetBegin(" <<
+      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+      "len(" << prefix << "))" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "oprot.writeListBegin(" <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+      "len(" << prefix << "))" << endl;
+  }
+
+  if (ttype->is_map()) {
+    string kiter = tmp("kiter");
+    string viter = tmp("viter");
+    indent(out) <<
+      "for " << kiter << "," << viter << " in " << prefix << ".items():" << endl;
+    indent_up();
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    indent_down();
+  } else if (ttype->is_set()) {
+    string iter = tmp("iter");
+    indent(out) <<
+      "for " << iter << " in " << prefix << ":" << endl;
+    indent_up();
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    indent_down();
+  } else if (ttype->is_list()) {
+    string iter = tmp("iter");
+    indent(out) <<
+      "for " << iter << " in " << prefix << ":" << endl;
+    indent_up();
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    indent_down();
+  }
+
+  if (ttype->is_map()) {
+    indent(out) <<
+      "oprot.writeMapEnd()" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) <<
+      "oprot.writeSetEnd()" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) <<
+      "oprot.writeListEnd()" << endl;
+  }
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_py_generator::generate_serialize_map_element(ofstream &out,
+                                                     t_map* tmap,
+                                                     string kiter,
+                                                     string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield, "");
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_py_generator::generate_serialize_set_element(ofstream &out,
+                                                     t_set* tset,
+                                                     string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_py_generator::generate_serialize_list_element(ofstream &out,
+                                                      t_list* tlist,
+                                                      string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Generates the docstring for a given struct.
+ */
+void t_py_generator::generate_python_docstring(ofstream& out,
+                                               t_struct* tstruct) {
+  generate_python_docstring(out, tstruct, tstruct, "Attributes");
+}
+
+/**
+ * Generates the docstring for a given function.
+ */
+void t_py_generator::generate_python_docstring(ofstream& out,
+                                               t_function* tfunction) {
+  generate_python_docstring(out, tfunction, tfunction->get_arglist(), "Parameters");
+}
+
+/**
+ * Generates the docstring for a struct or function.
+ */
+void t_py_generator::generate_python_docstring(ofstream& out,
+                                               t_doc*    tdoc,
+                                               t_struct* tstruct,
+                                               const char* subheader) {
+  bool has_doc = false;
+  stringstream ss;
+  if (tdoc->has_doc()) {
+    has_doc = true;
+    ss << tdoc->get_doc();
+  }
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  if (fields.size() > 0) {
+    if (has_doc) {
+      ss << endl;
+    }
+    has_doc = true;
+    ss << subheader << ":\n";
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ss << " - " << p->get_name();
+      if (p->has_doc()) {
+        ss << ": " << p->get_doc();
+      } else {
+        ss << endl;
+      }
+    }
+  }
+
+  if (has_doc) {
+    generate_docstring_comment(out,
+      "\"\"\"\n",
+      "", ss.str(),
+      "\"\"\"\n");
+  }
+}
+
+/**
+ * Generates the docstring for a generic object.
+ */
+void t_py_generator::generate_python_docstring(ofstream& out,
+                                               t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out,
+      "\"\"\"\n",
+      "", tdoc->get_doc(),
+      "\"\"\"\n");
+  }
+}
+
+/**
+ * Declares an argument, which may include initialization as necessary.
+ *
+ * @param tfield The field
+ */
+string t_py_generator::declare_argument(t_field* tfield) {
+  std::ostringstream result;
+  result << tfield->get_name() << "=";
+  if (tfield->get_value() != NULL) {
+    result << "thrift_spec[" <<
+      tfield->get_key() << "][4]";
+  } else {
+    result << "None";
+  }
+  return result.str();
+}
+
+/**
+ * Renders a field default value, returns None otherwise.
+ *
+ * @param tfield The field
+ */
+string t_py_generator::render_field_default_value(t_field* tfield) {
+  t_type* type = get_true_type(tfield->get_type());
+  if (tfield->get_value() != NULL) {
+    return render_const_value(type, tfield->get_value());
+  } else {
+    return "None";
+  }
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_py_generator::function_signature(t_function* tfunction,
+                                           string prefix) {
+  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
+  return
+    prefix + tfunction->get_name() +
+    "(self, " + argument_list(tfunction->get_arglist()) + ")";
+}
+
+/**
+ * Renders an interface function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_py_generator::function_signature_if(t_function* tfunction,
+                                           string prefix) {
+  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
+  string signature = prefix + tfunction->get_name() + "(";
+  if (!gen_twisted_) {
+    signature += "self, ";
+  }
+  signature += argument_list(tfunction->get_arglist()) + ")";
+  return signature;
+}
+
+
+/**
+ * Renders a field list
+ */
+string t_py_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;
+    } else {
+      result += ", ";
+    }
+    result += (*f_iter)->get_name();
+  }
+  return result;
+}
+
+string t_py_generator::type_name(t_type* ttype) {
+  t_program* program = ttype->get_program();
+  if (ttype->is_service()) {
+    return get_real_py_module(program) + "." + ttype->get_name();
+  }
+  if (program != NULL && program != program_) {
+    return get_real_py_module(program) + ".ttypes." + ttype->get_name();
+  }
+  return ttype->get_name();
+}
+
+/**
+ * Converts the parse type to a Python tyoe
+ */
+string t_py_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();
+}
+
+/** See the comment inside generate_py_struct_definition for what this is. */
+string t_py_generator::type_to_spec_args(t_type* ttype) {
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  if (ttype->is_base_type() || ttype->is_enum()) {
+    return "None";
+  } else if (ttype->is_struct() || ttype->is_xception()) {
+    return "(" + type_name(ttype) + ", " + type_name(ttype) + ".thrift_spec)";
+  } else if (ttype->is_map()) {
+    return "(" +
+      type_to_enum(((t_map*)ttype)->get_key_type()) + "," +
+      type_to_spec_args(((t_map*)ttype)->get_key_type()) + "," +
+      type_to_enum(((t_map*)ttype)->get_val_type()) + "," +
+      type_to_spec_args(((t_map*)ttype)->get_val_type()) +
+      ")";
+
+  } else if (ttype->is_set()) {
+    return "(" +
+      type_to_enum(((t_set*)ttype)->get_elem_type()) + "," +
+      type_to_spec_args(((t_set*)ttype)->get_elem_type()) +
+      ")";
+
+  } else if (ttype->is_list()) {
+    return "(" +
+      type_to_enum(((t_list*)ttype)->get_elem_type()) + "," +
+      type_to_spec_args(((t_list*)ttype)->get_elem_type()) +
+      ")";
+  }
+
+  throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
+}
+
+
+THRIFT_REGISTER_GENERATOR(py, "Python",
+"    new_style:       Generate new-style classes.\n" \
+"    twisted:         Generate Twisted-friendly RPC services.\n"
+);
diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc
new file mode 100644
index 0000000..708cd42
--- /dev/null
+++ b/compiler/cpp/src/generate/t_rb_generator.cc
@@ -0,0 +1,1097 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+
+#include <boost/tokenizer.hpp>
+
+#include "t_oop_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * Ruby code generator.
+ *
+ */
+class t_rb_generator : public t_oop_generator {
+ public:
+  t_rb_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    out_dir_base_ = "gen-rb";
+  }
+
+  /**
+   * 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_rb_struct(std::ofstream& out, t_struct* tstruct, bool is_exception);
+  void generate_rb_struct_required_validator(std::ofstream& out, t_struct* tstruct);
+  void generate_rb_function_helpers(t_function* tfunction);
+  void generate_rb_simple_constructor(std::ofstream& out, t_struct* tstruct);
+  void generate_rb_simple_exception_constructor(std::ofstream& out, t_struct* tstruct);
+  void generate_field_constants (std::ofstream& out, t_struct* tstruct);
+  void generate_accessors   (std::ofstream& out, t_struct* tstruct);
+  void generate_field_defns (std::ofstream& out, t_struct* tstruct);
+  void generate_field_data  (std::ofstream& out, t_type* field_type, const std::string& field_name, t_const_value* field_value, bool optional);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_helpers   (t_service*  tservice);
+  void generate_service_interface (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* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field        (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="",
+                                          bool inclass=false);
+
+  void generate_deserialize_struct       (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_deserialize_container    (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_deserialize_set_element  (std::ofstream &out,
+                                          t_set*      tset,
+                                          std::string prefix="");
+
+  void generate_deserialize_map_element  (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string prefix="");
+
+  void generate_deserialize_list_element (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string prefix="");
+
+  void generate_serialize_field          (std::ofstream &out,
+                                          t_field*    tfield,
+                                          std::string prefix="");
+
+  void generate_serialize_struct         (std::ofstream &out,
+                                          t_struct*   tstruct,
+                                          std::string prefix="");
+
+  void generate_serialize_container      (std::ofstream &out,
+                                          t_type*     ttype,
+                                          std::string prefix="");
+
+  void generate_serialize_map_element    (std::ofstream &out,
+                                          t_map*      tmap,
+                                          std::string kiter,
+                                          std::string viter);
+
+  void generate_serialize_set_element    (std::ofstream &out,
+                                          t_set*      tmap,
+                                          std::string iter);
+
+  void generate_serialize_list_element   (std::ofstream &out,
+                                          t_list*     tlist,
+                                          std::string iter);
+
+  void generate_rdoc                     (std::ofstream& out, 
+                                          t_doc* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string rb_autogen_comment();
+  std::string render_includes();
+  std::string declare_field(t_field* tfield);
+  std::string type_name(t_type* ttype);
+  std::string full_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::vector<std::string> ruby_modules(t_program* p) {
+    std::string ns = p->get_namespace("rb");
+    boost::tokenizer<> tok(ns);
+    std::vector<std::string> modules;
+
+    for(boost::tokenizer<>::iterator beg=tok.begin(); beg != tok.end(); ++beg) {
+      modules.push_back(capitalize(*beg));
+    }
+
+    return modules;
+  }
+
+  void begin_namespace(std::ofstream&, std::vector<std::string>);
+  void end_namespace(std::ofstream&, std::vector<std::string>);
+
+ private:
+
+  /**
+   * File streams
+   */
+
+  std::ofstream f_types_;
+  std::ofstream f_consts_;
+  std::ofstream f_service_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_rb_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string f_types_name = get_out_dir()+underscore(program_name_)+"_types.rb";
+  f_types_.open(f_types_name.c_str());
+
+  string f_consts_name = get_out_dir()+underscore(program_name_)+"_constants.rb";
+  f_consts_.open(f_consts_name.c_str());
+
+  // Print header
+  f_types_ <<
+    rb_autogen_comment() << endl <<
+    render_includes() << endl;
+    begin_namespace(f_types_, ruby_modules(program_));
+
+  f_consts_ <<
+    rb_autogen_comment() << endl <<
+    "require File.dirname(__FILE__) + '/" << underscore(program_name_) << "_types'" << endl <<
+    endl;
+    begin_namespace(f_consts_, ruby_modules(program_));
+
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_rb_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += "require '" + underscore(includes[i]->get_name()) + "_types'\n";
+  }
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+  return result;
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_rb_generator::rb_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";
+}
+
+/**
+ * Closes the type files
+ */
+void t_rb_generator::close_generator() {
+  // Close types file
+  end_namespace(f_types_, ruby_modules(program_));
+  end_namespace(f_consts_, ruby_modules(program_));
+  f_types_.close();
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. This is not done in Ruby, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_rb_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_rb_generator::generate_enum(t_enum* tenum) {
+  indent(f_types_) <<
+    "module " << capitalize(tenum->get_name()) << endl;
+  indent_up();
+
+  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;
+    }
+
+    // Ruby class constants have to be capitalized... omg i am so on the fence
+    // about languages strictly enforcing capitalization why can't we just all
+    // agree and play nice.
+    string name = capitalize((*c_iter)->get_name());
+
+    f_types_ <<
+      indent() << name << " = " << value << endl;
+  }
+  
+  // Create a set with valid values for this enum
+  indent(f_types_) << "VALID_VALUES = Set.new([";
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    // Populate the set
+    first ? first = false: f_types_ << ", ";
+    f_types_ << capitalize((*c_iter)->get_name());
+  }
+  f_types_ << "]).freeze" << endl;
+
+  indent_down();
+  indent(f_types_) <<
+    "end" << endl << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_rb_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  name[0] = toupper(name[0]);
+
+  indent(f_consts_) << name << " = " << render_const_value(type, value);
+  f_consts_ << 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_rb_generator::render_const_value(t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream out;
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << "%q\"" << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << type->get_name() << ".new({" << endl;
+    indent_up();
+    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;
+    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();
+      }
+      out << indent();
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " => ";
+      out << render_const_value(field_type, v_iter->second);
+      out << "," << endl;
+    }
+    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();
+    out << "{" << endl;
+    indent_up();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent();
+      out << render_const_value(ktype, v_iter->first);
+      out << " => ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << "}";
+  } 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();
+    }
+    if (type->is_set()) {
+      out << "Set.new([";
+    } else {
+      out << "[" << endl;
+    }
+    indent_up();
+    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) {
+      out << indent();
+      out << render_const_value(etype, *v_iter);
+      out << "," << endl;
+    }
+    indent_down();
+    if (type->is_set()) {
+      indent(out) << "])";
+    } else {
+      indent(out) << "]";
+    }
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+/**
+ * Generates a ruby struct
+ */
+void t_rb_generator::generate_struct(t_struct* tstruct) {
+  generate_rb_struct(f_types_, 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_rb_generator::generate_xception(t_struct* txception) {
+  generate_rb_struct(f_types_, txception, true);
+}
+
+/**
+ * Generates a ruby struct
+ */
+void t_rb_generator::generate_rb_struct(std::ofstream& out, t_struct* tstruct, bool is_exception = false) {
+  generate_rdoc(out, tstruct);
+  indent(out) << "class " << type_name(tstruct);
+  if (is_exception) {
+    out << " < ::Thrift::Exception";
+  }
+  out << endl;
+
+  indent_up();
+  indent(out) << "include ::Thrift::Struct" << endl;
+
+  if (is_exception) {
+    generate_rb_simple_exception_constructor(out, tstruct);
+  }
+
+  generate_field_constants(out, tstruct);
+  generate_accessors(out, tstruct);
+  generate_field_defns(out, tstruct);
+  generate_rb_struct_required_validator(out, tstruct);
+  
+  indent_down();
+  indent(out) << "end" << endl << endl;
+}
+
+void t_rb_generator::generate_rb_simple_exception_constructor(std::ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+
+  if (members.size() == 1) {
+    vector<t_field*>::const_iterator m_iter = members.begin();
+
+    if ((*m_iter)->get_type()->is_string()) {
+      string name = (*m_iter)->get_name();
+
+      indent(out) << "def initialize(message=nil)" << endl;
+      indent_up();
+      indent(out) << "super()" << endl;
+      indent(out) << "self." << name << " = message" << endl;
+      indent_down();
+      indent(out) << "end" << endl << endl;
+
+      if (name != "message") {
+        indent(out) << "def message; " << name << " end" << endl << endl;
+      }
+    }
+  }
+}
+
+void t_rb_generator::generate_field_constants(std::ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    std::string field_name = (*f_iter)->get_name();
+    std::string cap_field_name = upcase_string(field_name);
+    
+    indent(out) << cap_field_name << " = " << (*f_iter)->get_key() << endl;
+  }
+  out << endl;
+}
+
+void t_rb_generator::generate_accessors(std::ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  if (members.size() > 0) {
+    indent(out) << "::Thrift::Struct.field_accessor self";
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << ", :" << (*m_iter)->get_name();
+    }
+    out << endl;
+  }
+}
+
+void t_rb_generator::generate_field_defns(std::ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "FIELDS = {" << endl;
+  indent_up();
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (f_iter != fields.begin()) {
+      out << "," << endl;
+    }
+
+    // generate the field docstrings within the FIELDS constant. no real better place...
+    generate_rdoc(out, *f_iter);
+
+    indent(out) <<
+      upcase_string((*f_iter)->get_name()) << " => ";
+
+    generate_field_data(out, (*f_iter)->get_type(), (*f_iter)->get_name(), (*f_iter)->get_value(), 
+      (*f_iter)->get_req() == t_field::T_OPTIONAL);
+  }
+  indent_down();
+  out << endl;
+  indent(out) << "}" << endl << endl;
+  
+  indent(out) << "def struct_fields; FIELDS; end" << endl << endl;
+  
+}
+
+void t_rb_generator::generate_field_data(std::ofstream& out, t_type* field_type,
+    const std::string& field_name = "", t_const_value* field_value = NULL, bool optional = false) {
+  field_type = get_true_type(field_type);
+
+  // Begin this field's defn
+  out << "{:type => " << type_to_enum(field_type);
+
+  if (!field_name.empty()) {
+    out << ", :name => '" << field_name << "'";
+  }
+
+  if (field_value != NULL) {
+    out << ", :default => " << render_const_value(field_type, field_value);
+  }
+
+  if (!field_type->is_base_type()) {
+    if (field_type->is_struct() || field_type->is_xception()) {
+      out << ", :class => " << full_type_name((t_struct*)field_type);
+    } else if (field_type->is_list()) {
+      out << ", :element => ";
+      generate_field_data(out, ((t_list*)field_type)->get_elem_type());
+    } else if (field_type->is_map()) {
+      out << ", :key => ";
+      generate_field_data(out, ((t_map*)field_type)->get_key_type());
+      out << ", :value => ";
+      generate_field_data(out, ((t_map*)field_type)->get_val_type());
+    } else if (field_type->is_set()) {
+      out << ", :element => ";
+      generate_field_data(out, ((t_set*)field_type)->get_elem_type());
+    }
+  }
+  
+  if(optional) {
+    out << ", :optional => true";
+  }
+
+  if (field_type->is_enum()) {
+    out << ", :enum_class => " << full_type_name(field_type);
+  }
+
+  // End of this field's defn
+  out << "}";
+}
+
+void t_rb_generator::begin_namespace(std::ofstream& out, vector<std::string> modules) {
+  for (vector<std::string>::iterator m_iter = modules.begin(); m_iter != modules.end(); ++m_iter) {
+    indent(out) << "module " << *m_iter << endl;
+    indent_up();
+  }
+}
+
+void t_rb_generator::end_namespace(std::ofstream& out, vector<std::string> modules) {
+  for (vector<std::string>::reverse_iterator m_iter = modules.rbegin(); m_iter != modules.rend(); ++m_iter) {
+    indent_down();
+    indent(out) << "end" << endl;
+  }
+}
+
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_rb_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_out_dir()+underscore(service_name_)+".rb";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ <<
+    rb_autogen_comment() << endl <<
+    "require 'thrift'" << endl;
+
+  if (tservice->get_extends() != NULL) {
+    f_service_ <<
+      "require '" << underscore(tservice->get_extends()->get_name()) << "'" << endl;
+  }
+
+  f_service_ <<
+    "require File.dirname(__FILE__) + '/" << underscore(program_name_) << "_types'" << endl <<
+    endl;
+
+  begin_namespace(f_service_, ruby_modules(tservice->get_program()));
+
+  indent(f_service_) << "module " << capitalize(tservice->get_name()) << endl;
+  indent_up();
+
+  // Generate the three main parts of the service (well, two for now in PHP)
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  indent_down();
+  indent(f_service_) << "end" << endl <<
+    endl;
+
+  end_namespace(f_service_, ruby_modules(tservice->get_program()));
+
+  // Close service file
+  f_service_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_rb_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;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_rb_struct(f_service_, ts);
+    generate_rb_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_rb_generator::generate_rb_function_helpers(t_function* tfunction) {
+  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_rb_struct(f_service_, &result);
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_rb_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = full_type_name(tservice->get_extends());
+    extends_client = " < " + extends + "::Client ";
+  }
+
+  indent(f_service_) <<
+    "class Client" << extends_client << endl;
+  indent_up();
+
+  indent(f_service_) <<
+    "include ::Thrift::Client" << endl << endl;
+
+  // Generate client method implementations
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    indent(f_service_) <<
+      "def " << function_signature(*f_iter) << endl;
+    indent_up();
+      indent(f_service_) <<
+        "send_" << funname << "(";
+
+      bool first = true;
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        if (first) {
+          first = false;
+        } else {
+          f_service_ << ", ";
+        }
+        f_service_ << (*fld_iter)->get_name();
+      }
+      f_service_ << ")" << endl;
+
+      if (!(*f_iter)->is_oneway()) {
+        f_service_ << indent();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          f_service_ << "return ";
+        }
+        f_service_ <<
+          "recv_" << funname << "()" << endl;
+      }
+    indent_down();
+    indent(f_service_) << "end" << endl;
+    f_service_ << endl;
+
+    indent(f_service_) <<
+      "def send_" << function_signature(*f_iter) << endl;
+    indent_up();
+
+      std::string argsname = capitalize((*f_iter)->get_name() + "_args");
+
+      indent(f_service_) << "send_message('" << funname << "', " << argsname;
+
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        f_service_ << ", :" << (*fld_iter)->get_name() << " => " << (*fld_iter)->get_name();
+      }
+
+      f_service_ << ")" << endl;
+
+    indent_down();
+    indent(f_service_) << "end" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = capitalize((*f_iter)->get_name() + "_result");
+      t_struct noargs(program_);
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      f_service_ <<
+        endl <<
+        indent() << "def " << function_signature(&recv_function) << endl;
+      indent_up();
+
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+
+      f_service_ <<
+        indent() << "result = receive_message(" << resultname << ")" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ <<
+          indent() << "return result.success unless result.success.nil?" << endl;
+      }
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        indent(f_service_) <<
+          "raise result." << (*x_iter)->get_name() <<
+            " unless result." << (*x_iter)->get_name() << ".nil?" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "return" << endl;
+      } else {
+        f_service_ <<
+          indent() << "raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, '" << (*f_iter)->get_name() << " failed: unknown result')" << endl;
+      }
+
+      // Close function
+      indent_down();
+      indent(f_service_) << "end" << endl << endl;
+    }
+  }
+
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_rb_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = full_type_name(tservice->get_extends());
+    extends_processor = " < " + extends + "::Processor ";
+  }
+
+  // Generate the header portion
+  indent(f_service_) <<
+    "class Processor" << extends_processor << endl;
+  indent_up();
+
+  f_service_ <<
+    indent() << "include ::Thrift::Processor" << endl <<
+    endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_rb_generator::generate_process_function(t_service* tservice,
+                                               t_function* tfunction) {
+  // Open function
+  indent(f_service_) <<
+    "def process_" << tfunction->get_name() <<
+    "(seqid, iprot, oprot)" << endl;
+  indent_up();
+
+  string argsname = capitalize(tfunction->get_name()) + "_args";
+  string resultname = capitalize(tfunction->get_name()) + "_result";
+
+  f_service_ <<
+    indent() << "args = read_args(iprot, " << argsname << ")" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "result = " << resultname << ".new()" << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ <<
+      indent() << "begin" << endl;
+    indent_up();
+  }
+
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.success = ";
+  }
+  f_service_ <<
+    "@handler." << tfunction->get_name() << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << (*f_iter)->get_name();
+  }
+  f_service_ << ")" << endl;
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ <<
+        indent() << "rescue " << full_type_name((*x_iter)->get_type()) << " => " << (*x_iter)->get_name() << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ <<
+          indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
+        indent_down();
+      }
+    }
+    indent(f_service_) << "end" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ <<
+      indent() << "return" << endl;
+    indent_down();
+    indent(f_service_) << "end" << endl << endl;
+    return;
+  }
+
+  f_service_ <<
+    indent() << "write_result(result, oprot, '" << tfunction->get_name() << "', seqid)" << endl;
+
+  // Close function
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_rb_generator::function_signature(t_function* tfunction,
+                                           string prefix) {
+  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
+  return
+    prefix + tfunction->get_name() +
+    "(" +  argument_list(tfunction->get_arglist()) + ")";
+}
+
+/**
+ * Renders a field list
+ */
+string t_rb_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;
+    } else {
+      result += ", ";
+    }
+    result += (*f_iter)->get_name();
+  }
+  return result;
+}
+
+string t_rb_generator::type_name(t_type* ttype) {
+  string prefix = "";
+
+  string name = ttype->get_name();
+  if (ttype->is_struct() || ttype->is_xception() || ttype->is_enum()) {
+    name = capitalize(ttype->get_name());
+  }
+
+  return prefix + name;
+}
+
+string t_rb_generator::full_type_name(t_type* ttype) {
+  string prefix = "";
+  vector<std::string> modules = ruby_modules(ttype->get_program());
+  for (vector<std::string>::iterator m_iter = modules.begin();
+       m_iter != modules.end(); ++m_iter) {
+    prefix += *m_iter + "::";
+  }
+  return prefix + type_name(ttype);
+}
+
+/**
+ * Converts the parse type to a Ruby tyoe
+ */
+string t_rb_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 "::Thrift::Types::STRING";
+    case t_base_type::TYPE_BOOL:
+      return "::Thrift::Types::BOOL";
+    case t_base_type::TYPE_BYTE:
+      return "::Thrift::Types::BYTE";
+    case t_base_type::TYPE_I16:
+      return "::Thrift::Types::I16";
+    case t_base_type::TYPE_I32:
+      return "::Thrift::Types::I32";
+    case t_base_type::TYPE_I64:
+      return "::Thrift::Types::I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "::Thrift::Types::DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "::Thrift::Types::I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "::Thrift::Types::STRUCT";
+  } else if (type->is_map()) {
+    return "::Thrift::Types::MAP";
+  } else if (type->is_set()) {
+    return "::Thrift::Types::SET";
+  } else if (type->is_list()) {
+    return "::Thrift::Types::LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+
+void t_rb_generator::generate_rdoc(std::ofstream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out,
+      "", "# ", tdoc->get_doc(), "");
+  }
+}
+
+void t_rb_generator::generate_rb_struct_required_validator(std::ofstream& out, 
+                                                           t_struct* tstruct) {
+  indent(out) << "def validate" << endl;
+  indent_up();
+  
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+    if (field->get_req() == t_field::T_REQUIRED) {
+      indent(out) << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field " << field->get_name() << " is unset!')";
+      if (field->get_type()->is_bool()) {
+        out << " if @" << field->get_name() << ".nil?";
+      } else {
+        out << " unless @" << field->get_name();
+      }
+      out << endl;
+    }
+  }
+  
+  // if field is an enum, check that its value is valid
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+        
+    if (field->get_type()->is_enum()){      
+      indent(out) << "unless @" << field->get_name() << ".nil? || " << field->get_type()->get_name() << "::VALID_VALUES.include?(@" << field->get_name() << ")" << endl;      
+      indent_up();
+      indent(out) << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field " << field->get_name() << "!')" << endl;  
+      indent_down();
+      indent(out) << "end" << endl;
+    }
+  }  
+  
+  indent_down();
+  indent(out) << "end" << endl << endl;
+  
+}
+
+THRIFT_REGISTER_GENERATOR(rb, "Ruby", "");
diff --git a/compiler/cpp/src/generate/t_st_generator.cc b/compiler/cpp/src/generate/t_st_generator.cc
new file mode 100644
index 0000000..3600a3b
--- /dev/null
+++ b/compiler/cpp/src/generate/t_st_generator.cc
@@ -0,0 +1,1071 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <boost/tokenizer.hpp>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+
+#include "platform.h"
+#include "t_oop_generator.h"
+using namespace std;
+
+
+/**
+ * Smalltalk code generator.
+ *
+ */
+class t_st_generator : public t_oop_generator {
+ public:
+  t_st_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    out_dir_base_ = "gen-st";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef     (t_typedef*  ttypedef);
+  void generate_enum        (t_enum*     tenum);
+  void generate_const       (t_const*    tconst);
+  void generate_struct      (t_struct*   tstruct);
+  void generate_xception    (t_struct*   txception);
+  void generate_service     (t_service*  tservice);
+  void generate_class_side_definition ();
+  void generate_force_consts ();
+
+
+  std::string render_const_value(t_type* type, t_const_value* value);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_st_struct (std::ofstream& out, t_struct* tstruct, bool is_exception);
+  void generate_accessors   (std::ofstream& out, t_struct* tstruct);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_client    (t_service* tservice);
+
+  void generate_send_method (t_function* tfunction);
+  void generate_recv_method (t_function* tfunction);
+
+  std::string map_reader (t_map *tmap);
+  std::string list_reader (t_list *tlist);
+  std::string set_reader (t_set *tset);
+  std::string struct_reader (t_struct *tstruct, std::string clsName);
+
+  std::string map_writer (t_map *tmap, std::string name);
+  std::string list_writer (t_list *tlist, std::string name);
+  std::string set_writer (t_set *tset, std::string name);
+  std::string struct_writer (t_struct *tstruct, std::string fname);
+
+  std::string write_val (t_type *t, std::string fname);
+  std::string read_val (t_type *t);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string st_autogen_comment();
+
+  void st_class_def(std::ofstream &out, std::string name);
+  void st_method(std::ofstream &out, std::string cls, std::string name);
+  void st_method(std::ofstream &out, std::string cls, std::string name, std::string category);
+  void st_close_method(std::ofstream &out);
+  void st_class_method(std::ofstream &out, std::string cls, std::string name);
+  void st_class_method(std::ofstream &out, std::string cls, std::string name, std::string category);
+  void st_setter(std::ofstream &out, std::string cls, std::string name, std::string type);
+  void st_getter(std::ofstream &out, std::string cls, std::string name);
+  void st_accessors(std::ofstream &out, std::string cls, std::string name, std::string type);
+
+  std::string class_name();
+  std::string client_class_name();
+  std::string prefix(std::string name);
+  std::string declare_field(t_field* tfield);
+  std::string sanitize(std::string s);
+  std::string type_name(t_type* ttype);
+
+  std::string function_signature(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct);
+  std::string function_types_comment(t_function* fn);
+
+  std::string type_to_enum(t_type* ttype);
+  std::string a_type(t_type* type);
+  bool is_vowel(char c);
+  std::string temp_name();
+  std::string generated_category();
+
+ private:
+
+  /**
+   * File streams
+   */
+  int temporary_var;
+  std::ofstream f_;
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_st_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  temporary_var = 0;
+
+  // Make output file
+  string f_name = get_out_dir()+"/"+program_name_+".st";
+  f_.open(f_name.c_str());
+
+  // Print header
+  f_ << st_autogen_comment() << endl;
+
+  st_class_def(f_, program_name_);
+  generate_class_side_definition();
+
+  //Generate enums
+  vector<t_enum*> enums = program_->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    generate_enum(*en_iter);
+  }
+}
+
+string t_st_generator::class_name() {
+  return capitalize(program_name_);
+}
+
+string t_st_generator::prefix(string class_name) {
+  string prefix = program_->get_namespace("smalltalk.prefix");
+  string name = capitalize(class_name);
+  name = prefix.empty() ? name : (prefix + name);
+  return name;
+}
+
+string t_st_generator::client_class_name() {
+  return capitalize(service_name_) + "Client";
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_st_generator::st_autogen_comment() {
+  return
+    std::string("'") +
+    "Autogenerated by Thrift\n" +
+    "\n" +
+    "DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
+    "'!\n";
+}
+
+void t_st_generator::generate_force_consts() {
+  f_ << prefix(class_name()) << " enums keysAndValuesDo: [:k :v | " <<
+    prefix(class_name()) << " enums at: k put: v value].!" << endl;
+
+  f_ << prefix(class_name()) << " constants keysAndValuesDo: [:k :v | " <<
+    prefix(class_name()) << " constants at: k put: v value].!" << endl;
+
+}
+
+void t_st_generator::close_generator() {
+  generate_force_consts();
+  f_.close();
+}
+
+string t_st_generator::generated_category() {
+  string cat = program_->get_namespace("smalltalk.category");
+  // For compatibility with the Thrift grammar, the category must
+  // be punctuated by dots.  Replaces them with dashes here.
+  for (string::iterator iter = cat.begin(); iter != cat.end(); ++iter) {
+    if (*iter == '.') {
+      *iter = '-';
+    }
+  }
+  return cat.size() ? cat : "Generated-" + class_name();
+}
+
+/**
+ * Generates a typedef. This is not done in Smalltalk, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_st_generator::generate_typedef(t_typedef* ttypedef) {}
+
+void t_st_generator::st_class_def(std::ofstream &out, string name) {
+  out << "Object subclass: #" << prefix(name) << endl;
+  indent_up();
+  out << indent() << "instanceVariableNames: ''" << endl <<
+    indent() << "classVariableNames: ''" << endl <<
+    indent() << "poolDictionaries: ''" << endl <<
+    indent() << "category: '" << generated_category() << "'!" << endl << endl;
+}
+
+void t_st_generator::st_method(std::ofstream &out, string cls, string name) {
+  st_method(out, cls, name, "as yet uncategorized");
+}
+
+void t_st_generator::st_class_method(std::ofstream &out, string cls, string name) {
+  st_method(out, cls + " class", name);
+}
+
+void t_st_generator::st_class_method(std::ofstream &out, string cls, string name, string category) {
+  st_method(out, cls, name, category);
+}
+
+void t_st_generator::st_method(std::ofstream &out, string cls, string name, string category) {
+  char timestr[50];
+  time_t rawtime;
+  struct tm *tinfo;
+
+  time(&rawtime);
+  tinfo = localtime(&rawtime);
+  strftime(timestr, 50, "%m/%d/%Y %H:%M", tinfo);
+
+  out << "!" << prefix(cls) <<
+    " methodsFor: '"+category+"' stamp: 'thrift " << timestr << "'!\n" <<
+    name << endl;
+
+  indent_up();
+  out << indent();
+}
+
+void t_st_generator::st_close_method(std::ofstream &out) {
+  out << "! !" << endl << endl;
+  indent_down();
+}
+
+void t_st_generator::st_setter(std::ofstream &out, string cls, string name, string type = "anObject") {
+  st_method(out, cls, name + ": " + type);
+  out << name << " := " + type;
+  st_close_method(out);
+}
+
+void t_st_generator::st_getter(std::ofstream &out, string cls, string name) {
+  st_method(out, cls, name + "");
+  out << "^ " << name;
+  st_close_method(out);
+}
+
+void t_st_generator::st_accessors(std::ofstream &out, string cls, string name, string type = "anObject") {
+  st_setter(out, cls, name, type);
+  st_getter(out, cls, name);
+}
+
+void t_st_generator::generate_class_side_definition() {
+  f_ << prefix(class_name()) << " class" << endl <<
+    "\tinstanceVariableNames: 'constants enums'!" << endl << endl;
+
+  st_accessors(f_, class_name() + " class", "enums");
+  st_accessors(f_, class_name() + " class", "constants");
+
+  f_ << prefix(class_name()) << " enums: Dictionary new!" << endl;
+  f_ << prefix(class_name()) << " constants: Dictionary new!" << endl;
+
+  f_ << endl;
+}
+
+/**
+ * Generates code for an enumerated type. Done using a class to scope
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_st_generator::generate_enum(t_enum* tenum) {
+  string cls_name = program_name_ + capitalize(tenum->get_name());
+
+  f_ << prefix(class_name()) << " enums at: '" << tenum->get_name() << "' put: [" <<
+    "(Dictionary new " << endl;
+
+  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;
+    }
+
+    f_ << "\tat: '" << (*c_iter)->get_name() << "' put: " << value << ";" << endl;
+  }
+
+  f_ << "\tyourself)]!" << endl << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_st_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_ << prefix(class_name()) << " constants at: '" << name << "' put: [" <<
+    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_st_generator::render_const_value(t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream out;
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << "(" << capitalize(type->get_name()) << " new " << endl;
+    indent_up();
+
+    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;
+
+    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();
+      }
+
+      out << indent() << v_iter->first->get_string() << ": " <<
+        render_const_value(field_type, v_iter->second) << ";" << endl;
+    }
+    out << indent() << "yourself)";
+
+    indent_down();
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    out << "(Dictionary new" << endl;
+    indent_up();
+    indent_up();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << indent();
+      out << "at: " << render_const_value(ktype, v_iter->first);
+      out << " put: ";
+      out << render_const_value(vtype, v_iter->second);
+      out << ";" << endl;
+    }
+    out << indent() << indent() << "yourself)";
+    indent_down();
+    indent_down();
+  } 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();
+    }
+    if (type->is_set()) {
+      out << "(Set new" << endl;
+    } else {
+      out << "(OrderedCollection new" << endl;
+    }
+    indent_up();
+    indent_up();
+    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) {
+      out << indent() << indent();
+      out << "add: " << render_const_value(etype, *v_iter);
+      out << ";" << endl;
+    }
+    out << indent() << indent() << "yourself)";
+    indent_down();
+    indent_down();
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+/**
+ * Generates a Smalltalk struct
+ */
+void t_st_generator::generate_struct(t_struct* tstruct) {
+  generate_st_struct(f_, 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_st_generator::generate_xception(t_struct* txception) {
+  generate_st_struct(f_, txception, true);
+}
+
+/**
+ * Generates a smalltalk class to represent a struct
+ */
+void t_st_generator::generate_st_struct(std::ofstream& out, t_struct* tstruct, bool is_exception = false) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  if (is_exception)
+    out << "Error";
+  else
+    out << "Object";
+
+  out << " subclass: #" << prefix(type_name(tstruct)) << endl <<
+    "\tinstanceVariableNames: '";
+
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (m_iter != members.begin()) out << " ";
+      out << sanitize((*m_iter)->get_name());
+    }
+  }
+
+  out << "'\n" <<
+    "\tclassVariableNames: ''\n" <<
+    "\tpoolDictionaries: ''\n" <<
+    "\tcategory: '" << generated_category() << "'!\n\n";
+
+  generate_accessors(out, tstruct);
+}
+
+bool t_st_generator::is_vowel(char c) {
+  switch(tolower(c)) {
+    case 'a': case 'e': case 'i': case 'o': case 'u':
+    return true;
+  }
+  return false;
+}
+
+string t_st_generator::a_type(t_type* type) {
+  string prefix;
+
+  if (is_vowel(type_name(type)[0]))
+    prefix = "an";
+  else
+    prefix = "a";
+
+  return prefix + capitalize(type_name(type));
+}
+
+void t_st_generator::generate_accessors(std::ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  string type;
+  string prefix;
+
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      st_accessors(out,
+                   capitalize(type_name(tstruct)),
+                   sanitize((*m_iter)->get_name()),
+                   a_type((*m_iter)->get_type()));
+    }
+    out << endl;
+  }
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_st_generator::generate_service(t_service* tservice) {
+  generate_service_client(tservice);
+  // generate_service_server(tservice);
+}
+
+string t_st_generator::temp_name() {
+  std::ostringstream out;
+  out << "temp" << temporary_var++;
+  return out.str();
+}
+
+string t_st_generator::map_writer(t_map *tmap, string fname) {
+  std::ostringstream out;
+  string key = temp_name();
+  string val = temp_name();
+
+  out << "[oprot writeMapBegin: (TMap new keyType: " << type_to_enum(tmap->get_key_type()) <<
+    "; valueType: " << type_to_enum(tmap->get_val_type()) << "; size: " << fname << " size)." << endl;
+  indent_up();
+
+  out << indent() << fname << " keysAndValuesDo: [:" << key << " :" << val << " |" << endl;
+  indent_up();
+
+  out << indent() << write_val(tmap->get_key_type(), key) << "." << endl <<
+    indent() << write_val(tmap->get_val_type(), val);
+  indent_down();
+
+  out << "]." << endl <<
+    indent() << "oprot writeMapEnd] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::map_reader(t_map *tmap) {
+  std::ostringstream out;
+  string desc = temp_name();
+  string val = temp_name();
+
+  out << "[|" << desc << " " << val << "| " << endl;
+  indent_up();
+
+  out << indent() << desc << " := iprot readMapBegin." << endl <<
+    indent() << val << " := Dictionary new." << endl <<
+    indent() << desc << " size timesRepeat: [" << endl;
+
+  indent_up();
+  out << indent() << val << " at: " << read_val(tmap->get_key_type()) <<
+    " put: " << read_val(tmap->get_val_type());
+  indent_down();
+
+  out << "]." << endl <<
+    indent() << "iprot readMapEnd." << endl <<
+  indent() << val << "] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::list_writer(t_list *tlist, string fname) {
+  std::ostringstream out;
+  string val = temp_name();
+
+  out << "[oprot writeListBegin: (TList new elemType: " <<
+    type_to_enum(tlist->get_elem_type()) << "; size: " << fname << " size)." << endl;
+  indent_up();
+
+  out << indent() << fname << " do: [:" << val << "|" << endl;
+  indent_up();
+
+  out << indent() << write_val(tlist->get_elem_type(), val) << endl;
+  indent_down();
+
+  out << "]." << endl <<
+    indent() << "oprot writeListEnd] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::list_reader(t_list *tlist) {
+  std::ostringstream out;
+  string desc = temp_name();
+  string val = temp_name();
+
+  out << "[|" << desc << " " << val << "| " << desc << " := iprot readListBegin." << endl;
+  indent_up();
+
+  out << indent() << val << " := OrderedCollection new." << endl <<
+    indent() << desc << " size timesRepeat: [" << endl;
+
+  indent_up();
+  out << indent() << val << " add: " << read_val(tlist->get_elem_type());
+  indent_down();
+
+  out << "]." << endl <<
+    indent() << "iprot readListEnd." << endl <<
+  indent() << val << "] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::set_writer(t_set *tset, string fname) {
+  std::ostringstream out;
+  string val = temp_name();
+
+  out << "[oprot writeSetBegin: (TSet new elemType: " << type_to_enum(tset->get_elem_type()) <<
+    "; size: " << fname << " size)." << endl;
+  indent_up();
+
+  out << indent() << fname << " do: [:" << val << "|" << endl;
+  indent_up();
+
+  out << indent() << write_val(tset->get_elem_type(), val) << endl;
+  indent_down();
+
+  out << "]." << endl <<
+    indent() << "oprot writeSetEnd] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::set_reader(t_set *tset) {
+  std::ostringstream out;
+  string desc = temp_name();
+  string val = temp_name();
+
+  out << "[|" << desc << " " << val << "| " << desc << " := iprot readSetBegin." << endl;
+  indent_up();
+
+  out << indent() << val << " := Set new." << endl <<
+    indent() << desc << " size timesRepeat: [" << endl;
+
+  indent_up();
+  out << indent() << val << " add: " << read_val(tset->get_elem_type());
+  indent_down();
+
+  out << "]." << endl <<
+    indent() << "iprot readSetEnd." << endl <<
+  indent() << val << "] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::struct_writer(t_struct *tstruct, string sname) {
+  std::ostringstream out;
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator fld_iter;
+
+  out << "[oprot writeStructBegin: " <<
+    "(TStruct new name: '" + tstruct->get_name() +"')." << endl;
+  indent_up();
+
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    bool optional = (*fld_iter)->get_req() == t_field::T_OPTIONAL;
+    string fname = (*fld_iter)->get_name();
+    string accessor = sname + " " + sanitize(fname);
+
+    if (optional) {
+      out << indent() << accessor << " ifNotNil: [" << endl;
+      indent_up();
+    }
+
+    out << indent() << "oprot writeFieldBegin: (TField new name: '" << fname <<
+      "'; type: " << type_to_enum((*fld_iter)->get_type()) <<
+      "; id: " << (*fld_iter)->get_key() << ")." << endl;
+
+    out << indent() << write_val((*fld_iter)->get_type(), accessor) << "." << endl <<
+      indent() << "oprot writeFieldEnd";
+
+    if (optional) {
+      out << "]";
+      indent_down();
+    }
+
+    out << "." << endl;
+  }
+
+  out << indent() << "oprot writeFieldStop; writeStructEnd] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::struct_reader(t_struct *tstruct, string clsName = "") {
+  std::ostringstream out;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator fld_iter;
+  string val = temp_name();
+  string desc = temp_name();
+  string found = temp_name();
+
+  if (clsName.size() == 0) {
+    clsName = tstruct->get_name();
+  }
+
+  out << "[|" << desc << " " << val << "|" << endl;
+  indent_up();
+
+  //This is nasty, but without it we'll break things by prefixing TResult.
+  string name = ((capitalize(clsName) == "TResult") ? capitalize(clsName) : prefix(clsName));
+  out << indent() << val << " := " << name << " new." << endl;
+
+  out << indent() << "iprot readStructBegin." << endl <<
+    indent() << "[" << desc << " := iprot readFieldBegin." << endl <<
+    indent() << desc << " type = TType stop] whileFalse: [|" << found << "|" << endl;
+  indent_up();
+
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    out << indent() << desc << " id = " << (*fld_iter)->get_key() <<
+      " ifTrue: [" << endl;
+    indent_up();
+
+    out << indent() << found << " := true." << endl <<
+      indent() << val << " " << sanitize((*fld_iter)->get_name()) << ": " <<
+      read_val((*fld_iter)->get_type());
+    indent_down();
+
+    out << "]." << endl;
+  }
+
+  out << indent() << found << " ifNil: [iprot skip: " << desc << " type]]." << endl;
+  indent_down();
+
+  out << indent() << "oprot readStructEnd." << endl <<
+    indent() << val << "] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::write_val(t_type *t, string fname) {
+  t = get_true_type(t);
+
+  if (t->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*) t)->get_base();
+    switch(tbase) {
+    case t_base_type::TYPE_DOUBLE:
+      return "iprot writeDouble: " + fname + " asFloat";
+      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:
+      return "iprot write" + capitalize(type_name(t)) + ": " + fname + " asInteger";
+    default:
+      return "iprot write" + capitalize(type_name(t)) + ": " + fname;
+    }
+  } else if (t->is_map()) {
+    return map_writer((t_map*) t, fname);
+  } else if (t->is_struct() || t->is_xception()) {
+    return struct_writer((t_struct*) t, fname);
+  } else if (t->is_list()) {
+    return list_writer((t_list*) t, fname);
+  } else if (t->is_set()) {
+    return set_writer((t_set*) t, fname);
+  } else if (t->is_enum()) {
+    return "iprot writeI32: " + fname;
+  } else {
+    throw "Sorry, I don't know how to write this: " + type_name(t);
+  }
+}
+
+string t_st_generator::read_val(t_type *t) {
+  t = get_true_type(t);
+
+  if (t->is_base_type()) {
+    return "iprot read" + capitalize(type_name(t));
+  } else if (t->is_map()) {
+    return map_reader((t_map*) t);
+  } else if (t->is_struct() || t->is_xception()) {
+    return struct_reader((t_struct*) t);
+  } else if (t->is_list()) {
+    return list_reader((t_list*) t);
+  } else if (t->is_set()) {
+    return set_reader((t_set*) t);
+  } else if (t->is_enum()) {
+    return "iprot readI32";
+  } else {
+    throw "Sorry, I don't know how to read this: " + type_name(t);
+  }
+}
+
+void t_st_generator::generate_send_method(t_function* function) {
+  string funname = function->get_name();
+  string signature = function_signature(function);
+  t_struct* arg_struct = function->get_arglist();
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator fld_iter;
+
+  st_method(f_, client_class_name(), "send" + capitalize(signature));
+  f_ << "oprot writeMessageBegin:" << endl;
+  indent_up();
+
+  f_ << indent() << "(TCallMessage new" << endl;
+  indent_up();
+
+  f_ << indent() << "name: '" << funname << "'; " << endl <<
+    indent() << "seqid: self nextSeqid)." << endl;
+  indent_down();
+  indent_down();
+
+  f_ << indent() << "oprot writeStructBegin: " <<
+    "(TStruct new name: '" + capitalize(function->get_name()) + "_args')." << endl;
+
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    string fname = (*fld_iter)->get_name();
+
+    f_ << indent() << "oprot writeFieldBegin: (TField new name: '" << fname <<
+      "'; type: " << type_to_enum((*fld_iter)->get_type()) <<
+      "; id: " << (*fld_iter)->get_key() << ")." << endl;
+
+    f_ << indent() << write_val((*fld_iter)->get_type(), fname) << "." << endl <<
+      indent() << "oprot writeFieldEnd." << endl;
+  }
+
+  f_ << indent() << "oprot writeFieldStop; writeStructEnd; writeMessageEnd." << endl;
+  f_ << indent() << "oprot transport flush";
+
+  st_close_method(f_);
+}
+
+// We only support receiving TResult structures (so this won't work on the server side)
+void t_st_generator::generate_recv_method(t_function* function) {
+  string funname = function->get_name();
+  string signature = function_signature(function);
+
+  t_struct result(program_, "TResult");
+  t_field success(function->get_returntype(), "success", 0);
+  result.append(&success);
+
+  t_struct* xs = function->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) {
+    // duplicate the field, but call it "exception"... we don't need a dynamic name
+    t_field *exception = new t_field((*f_iter)->get_type(), "exception", (*f_iter)->get_key());
+    result.append(exception);
+  }
+
+  st_method(f_, client_class_name(), "recv" + capitalize(funname));
+  f_ << "| f msg res | " << endl <<
+    indent() << "msg := oprot readMessageBegin." << endl <<
+    indent() << "self validateRemoteMessage: msg." << endl <<
+    indent() << "res := " << struct_reader(&result) << "." << endl <<
+    indent() << "oprot readMessageEnd." << endl <<
+    indent() << "oprot transport flush." << endl <<
+    indent() << "res exception ifNotNil: [res exception signal]." << endl <<
+    indent() << "^ res";
+  st_close_method(f_);
+}
+
+string t_st_generator::function_types_comment(t_function* fn) {
+  std::ostringstream out;
+  const vector<t_field*>& fields = fn->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << "\"";
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out << (*f_iter)->get_name() << ": " << type_name((*f_iter)->get_type());
+    if ((f_iter + 1) != fields.end()) {
+      out << ", ";
+    }
+  }
+
+  out << "\"";
+
+  return out.str();
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_st_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "TClient";
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = extends + "Client";
+  }
+
+  f_ << extends_client << " subclass: #" << prefix(client_class_name()) << endl <<
+    "\tinstanceVariableNames: ''\n" <<
+    "\tclassVariableNames: ''\n" <<
+    "\tpoolDictionaries: ''\n" <<
+    "\tcategory: '" << generated_category() << "'!\n\n";
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+    string signature = function_signature(*f_iter);
+
+    st_method(f_, client_class_name(), signature);
+    f_ << function_types_comment(*f_iter) << endl <<
+      indent() << "self send" << capitalize(signature) << "." << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_ << indent() << "^ self recv" << capitalize(funname) << " success " << endl;
+    }
+
+    st_close_method(f_);
+
+    generate_send_method(*f_iter);
+    if (!(*f_iter)->is_oneway()) {
+      generate_recv_method(*f_iter);
+    }
+  }
+}
+
+string t_st_generator::sanitize(string s) {
+  std::ostringstream out;
+  bool underscore = false;
+
+  for (unsigned int i = 0; i < s.size(); i++) {
+    if (s[i] == '_') {
+      underscore = true;
+      continue;
+    }
+    if (underscore) {
+      out << (char) toupper(s[i]);
+      underscore = false;
+      continue;
+    }
+    out << s[i];
+  }
+
+  return out.str();
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_st_generator::function_signature(t_function* tfunction) {
+  return tfunction->get_name() + capitalize(argument_list(tfunction->get_arglist()));
+}
+
+/**
+ * Renders a field list
+ */
+string t_st_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;
+    } else {
+      result += " ";
+    }
+    result += (*f_iter)->get_name() + ": " + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+string t_st_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    if (!ttype->is_service()) {
+      prefix = program->get_name() + "_types.";
+    }
+  }
+
+  string name = ttype->get_name();
+  if (ttype->is_struct() || ttype->is_xception()) {
+    name = capitalize(ttype->get_name());
+  }
+
+  return prefix + name;
+}
+
+/* Convert t_type to Smalltalk type code */
+string t_st_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();
+}
+
+
+THRIFT_REGISTER_GENERATOR(st, "Smalltalk", "");
diff --git a/compiler/cpp/src/generate/t_xsd_generator.cc b/compiler/cpp/src/generate/t_xsd_generator.cc
new file mode 100644
index 0000000..729a91a
--- /dev/null
+++ b/compiler/cpp/src/generate/t_xsd_generator.cc
@@ -0,0 +1,354 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "t_generator.h"
+#include "platform.h"
+using namespace std;
+
+
+/**
+ * XSD generator, creates an XSD for the base types etc.
+ *
+ */
+class t_xsd_generator : public t_generator {
+ public:
+  t_xsd_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_generator(program)
+  {
+    out_dir_base_ = "gen-xsd";
+  }
+
+  virtual ~t_xsd_generator() {}
+
+  /**
+   * 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_service(t_service* tservice);
+  void generate_struct(t_struct* tstruct);
+
+ private:
+
+  void generate_element(std::ostream& out, std::string name, t_type* ttype, t_struct* attrs=NULL, bool optional=false, bool nillable=false, bool list_element=false);
+
+  std::string ns(std::string in, std::string ns) {
+    return ns + ":" + in;
+  }
+
+  std::string xsd(std::string in) {
+    return ns(in, "xsd");
+  }
+
+  std::string type_name(t_type* ttype);
+  std::string base_type_name(t_base_type::t_base tbase);
+
+  /**
+   * Output xsd/php file
+   */
+  std::ofstream f_xsd_;
+  std::ofstream f_php_;
+
+  /**
+   * Output string stream
+   */
+  std::ostringstream s_xsd_types_;
+
+};
+
+
+void t_xsd_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string f_php_name = get_out_dir()+program_->get_name()+"_xsd.php";
+  f_php_.open(f_php_name.c_str());
+
+  f_php_ <<
+    "<?php" << endl;
+
+}
+
+void t_xsd_generator::close_generator() {
+  f_php_ << "?>" << endl;
+  f_php_.close();
+}
+
+void t_xsd_generator::generate_typedef(t_typedef* ttypedef) {
+  indent(s_xsd_types_) <<
+    "<xsd:simpleType name=\"" << ttypedef->get_name() << "\">" << endl;
+  indent_up();
+  if (ttypedef->get_type()->is_string() && ((t_base_type*)ttypedef->get_type())->is_string_enum()) {
+    indent(s_xsd_types_) <<
+      "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\">" << endl;
+    indent_up();
+    const vector<string>& values = ((t_base_type*)ttypedef->get_type())->get_string_enum_vals();
+    vector<string>::const_iterator v_iter;
+    for (v_iter = values.begin(); v_iter != values.end(); ++v_iter) {
+      indent(s_xsd_types_) <<
+        "<xsd:enumeration value=\"" << (*v_iter) << "\" />" << endl;
+    }
+    indent_down();
+    indent(s_xsd_types_) <<
+      "</xsd:restriction>" << endl;
+  } else {
+    indent(s_xsd_types_) <<
+      "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\" />" << endl;
+  }
+  indent_down();
+  indent(s_xsd_types_) <<
+    "</xsd:simpleType>" << endl << endl;
+}
+
+void t_xsd_generator::generate_struct(t_struct* tstruct) {
+  vector<t_field*>::const_iterator m_iter;
+  const vector<t_field*>& members = tstruct->get_members();
+  bool xsd_all = tstruct->get_xsd_all();
+
+  indent(s_xsd_types_) << "<xsd:complexType name=\"" << tstruct->get_name() << "\">" << endl;
+  indent_up();
+  if (xsd_all) {
+    indent(s_xsd_types_) << "<xsd:all>" << endl;
+  } else {
+    indent(s_xsd_types_) << "<xsd:sequence>" << endl;
+  }
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_element(s_xsd_types_, (*m_iter)->get_name(), (*m_iter)->get_type(), (*m_iter)->get_xsd_attrs(), (*m_iter)->get_xsd_optional() || xsd_all, (*m_iter)->get_xsd_nillable());
+  }
+
+  indent_down();
+  if (xsd_all) {
+    indent(s_xsd_types_) << "</xsd:all>" << endl;
+  } else {
+    indent(s_xsd_types_) << "</xsd:sequence>" << endl;
+  }
+  indent_down();
+  indent(s_xsd_types_) <<
+    "</xsd:complexType>" << endl <<
+    endl;
+}
+
+void t_xsd_generator::generate_element(ostream& out,
+                                       string name,
+                                       t_type* ttype,
+                                       t_struct* attrs,
+                                       bool optional,
+                                       bool nillable,
+                                       bool list_element) {
+  string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : "";
+  string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : "";
+  string soptional = sminOccurs + smaxOccurs;
+  string snillable = nillable ? " nillable=\"true\"" : "";
+
+  if (ttype->is_void() || ttype->is_list()) {
+    indent(out) <<
+      "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
+    indent_up();
+    if (attrs == NULL && ttype->is_void()) {
+      indent(out) <<
+        "<xsd:complexType />" << endl;
+    } else {
+      indent(out) <<
+        "<xsd:complexType>" << endl;
+      indent_up();
+      if (ttype->is_list()) {
+        indent(out) << "<xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" << endl;
+        indent_up();
+        string subname;
+        t_type* subtype = ((t_list*)ttype)->get_elem_type();
+        if (subtype->is_base_type() || subtype->is_container()) {
+          subname = name + "_elt";
+        } else {
+          subname = type_name(subtype);
+        }
+        f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname << "';" << endl;
+        generate_element(out, subname, subtype, NULL, false, false, true);
+        indent_down();
+        indent(out) << "</xsd:sequence>" << endl;
+        indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
+      }
+      if (attrs != NULL) {
+        const vector<t_field*>& members = attrs->get_members();
+        vector<t_field*>::const_iterator a_iter;
+        for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
+          indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
+        }
+      }
+      indent_down();
+      indent(out) <<
+        "</xsd:complexType>" << endl;
+    }
+    indent_down();
+    indent(out) <<
+      "</xsd:element>" << endl;
+  } else {
+    if (attrs == NULL) {
+      indent(out) <<
+        "<xsd:element name=\"" << name << "\"" << " type=\"" << type_name(ttype) << "\"" << soptional << snillable << " />" << endl;
+    } else {
+      // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
+      indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
+      indent_up();
+      indent(out) << "<xsd:complexType>" << endl;
+      indent_up();
+      indent(out) << "<xsd:complexContent>" << endl;
+      indent_up();
+      indent(out) << "<xsd:extension base=\"" << type_name(ttype) << "\">" << endl;
+      indent_up();
+      const vector<t_field*>& members = attrs->get_members();
+      vector<t_field*>::const_iterator a_iter;
+      for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
+        indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
+      }
+      indent_down();
+      indent(out) << "</xsd:extension>" << endl;
+      indent_down();
+      indent(out) << "</xsd:complexContent>" << endl;
+      indent_down();
+      indent(out) << "</xsd:complexType>" << endl;
+      indent_down();
+      indent(out) << "</xsd:element>" << endl;
+    }
+  }
+}
+
+void t_xsd_generator::generate_service(t_service* tservice) {
+  // Make output file
+  string f_xsd_name = get_out_dir()+tservice->get_name()+".xsd";
+  f_xsd_.open(f_xsd_name.c_str());
+
+  string ns = program_->get_namespace("xsd");
+  if (ns.size() > 0) {
+    ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " +
+      "elementFormDefault=\"qualified\"";
+  }
+
+  // Print the XSD header
+  f_xsd_ <<
+    "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl <<
+    "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" << ns << ">" << endl <<
+    endl <<
+    "<!-- Yo yo yo, this XSD woz be generated by Thrift. -->" << endl <<
+    endl;
+
+  // Print out the type definitions
+  indent(f_xsd_) << s_xsd_types_.str();
+
+  // Keep a list of all the possible exceptions that might get thrown
+  map<string, t_struct*> all_xceptions;
+
+  // List the elements that you might actually get
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string elemname = (*f_iter)->get_name() + "_response";
+    t_type* returntype = (*f_iter)->get_returntype();
+    generate_element(f_xsd_, elemname, returntype);
+    f_xsd_ << endl;
+
+    t_struct* xs = (*f_iter)->get_xceptions();
+    const std::vector<t_field*>& xceptions = xs->get_members();
+    vector<t_field*>::const_iterator x_iter;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type());
+    }
+  }
+
+  map<string, t_struct*>::iterator ax_iter;
+  for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) {
+    generate_element(f_xsd_, ax_iter->first, ax_iter->second);
+  }
+
+  // Close the XSD document
+  f_xsd_ << endl << "</xsd:schema>" << endl;
+  f_xsd_.close();
+}
+
+string t_xsd_generator::type_name(t_type* ttype) {
+  if (ttype->is_typedef()) {
+    return ttype->get_name();
+  }
+
+  if (ttype->is_base_type()) {
+    return xsd(base_type_name(((t_base_type*)ttype)->get_base()));
+  }
+
+  if (ttype->is_enum()) {
+    return xsd("int");
+  }
+
+  if (ttype->is_struct() || ttype->is_xception()) {
+    return ttype->get_name();
+  }
+
+  return "container";
+}
+
+/**
+ * Returns the XSD type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @return Explicit XSD type, i.e. xsd:string
+ */
+string t_xsd_generator::base_type_name(t_base_type::t_base tbase) {
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    return "string";
+  case t_base_type::TYPE_BOOL:
+    return "boolean";
+  case t_base_type::TYPE_BYTE:
+    return "byte";
+  case t_base_type::TYPE_I16:
+    return "short";
+  case t_base_type::TYPE_I32:
+    return "int";
+  case t_base_type::TYPE_I64:
+    return "long";
+  case t_base_type::TYPE_DOUBLE:
+    return "decimal";
+  default:
+    throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+THRIFT_REGISTER_GENERATOR(xsd, "XSD", "");
diff --git a/compiler/cpp/src/globals.h b/compiler/cpp/src/globals.h
new file mode 100644
index 0000000..b204143
--- /dev/null
+++ b/compiler/cpp/src/globals.h
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_GLOBALS_H
+#define T_GLOBALS_H
+
+#include <set>
+#include <queue>
+#include <stack>
+#include <vector>
+#include <string>
+
+/**
+ * This module contains all the global variables (slap on the wrist) that are
+ * shared throughout the program. The reason for this is to facilitate simple
+ * interaction between the parser and the rest of the program. Before calling
+ * yyparse(), the main.cc program will make necessary adjustments to these
+ * global variables such that the parser does the right thing and puts entries
+ * into the right containers, etc.
+ *
+ */
+
+/**
+ * Hooray for forward declaration of types!
+ */
+
+class t_program;
+class t_scope;
+class t_type;
+
+/**
+ * Parsing mode, two passes up in this gin rummy!
+ */
+
+enum PARSE_MODE {
+  INCLUDES = 1,
+  PROGRAM = 2
+};
+
+/**
+ * Strictness level
+ */
+extern int g_strict;
+
+/**
+ * The master program parse tree. This is accessed from within the parser code
+ * to build up the program elements.
+ */
+extern t_program* g_program;
+
+/**
+ * Global types for the parser to be able to reference
+ */
+
+extern t_type* g_type_void;
+extern t_type* g_type_string;
+extern t_type* g_type_binary;
+extern t_type* g_type_slist;
+extern t_type* g_type_bool;
+extern t_type* g_type_byte;
+extern t_type* g_type_i16;
+extern t_type* g_type_i32;
+extern t_type* g_type_i64;
+extern t_type* g_type_double;
+
+/**
+ * The scope that we are currently parsing into
+ */
+extern t_scope* g_scope;
+
+/**
+ * The parent scope to also load symbols into
+ */
+extern t_scope* g_parent_scope;
+
+/**
+ * The prefix for the parent scope entries
+ */
+extern std::string g_parent_prefix;
+
+/**
+ * The parsing pass that we are on. We do different things on each pass.
+ */
+extern PARSE_MODE g_parse_mode;
+
+/**
+ * Global time string, used in formatting error messages etc.
+ */
+extern char* g_time_str;
+
+/**
+ * The last parsed doctext comment.
+ */
+extern char* g_doctext;
+
+/**
+ * The location of the last parsed doctext comment.
+ */
+extern int g_doctext_lineno;
+
+#endif
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
new file mode 100644
index 0000000..7a5d2d4
--- /dev/null
+++ b/compiler/cpp/src/main.cc
@@ -0,0 +1,1207 @@
+/*
+ * 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.
+ */
+
+/**
+ * thrift - a lightweight cross-language rpc/serialization tool
+ *
+ * This file contains the main compiler engine for Thrift, which invokes the
+ * scanner/parser to build the thrift object tree. The interface generation
+ * code for each language lives in a file by the language name under the
+ * generate/ folder, and all parse structures live in parse/
+ *
+ */
+
+#include <cassert>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string>
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifdef MINGW
+# include <windows.h> /* for GetFullPathName */
+#endif
+
+// Careful: must include globals first for extern definitions
+#include "globals.h"
+
+#include "main.h"
+#include "parse/t_program.h"
+#include "parse/t_scope.h"
+#include "generate/t_generator.h"
+
+#include "version.h"
+
+using namespace std;
+
+/**
+ * Global program tree
+ */
+t_program* g_program;
+
+/**
+ * Global types
+ */
+
+t_type* g_type_void;
+t_type* g_type_string;
+t_type* g_type_binary;
+t_type* g_type_slist;
+t_type* g_type_bool;
+t_type* g_type_byte;
+t_type* g_type_i16;
+t_type* g_type_i32;
+t_type* g_type_i64;
+t_type* g_type_double;
+
+/**
+ * Global scope
+ */
+t_scope* g_scope;
+
+/**
+ * Parent scope to also parse types
+ */
+t_scope* g_parent_scope;
+
+/**
+ * Prefix for putting types in parent scope
+ */
+string g_parent_prefix;
+
+/**
+ * Parsing pass
+ */
+PARSE_MODE g_parse_mode;
+
+/**
+ * Current directory of file being parsed
+ */
+string g_curdir;
+
+/**
+ * Current file being parsed
+ */
+string g_curpath;
+
+/**
+ * Search path for inclusions
+ */
+vector<string> g_incl_searchpath;
+
+/**
+ * Should C++ include statements use path prefixes for other thrift-generated
+ * header files
+ */
+bool g_cpp_use_include_prefix = false;
+
+/**
+ * Global debug state
+ */
+int g_debug = 0;
+
+/**
+ * Strictness level
+ */
+int g_strict = 127;
+
+/**
+ * Warning level
+ */
+int g_warn = 1;
+
+/**
+ * Verbose output
+ */
+int g_verbose = 0;
+
+/**
+ * Global time string
+ */
+char* g_time_str;
+
+/**
+ * The last parsed doctext comment.
+ */
+char* g_doctext;
+
+/**
+ * The location of the last parsed doctext comment.
+ */
+int g_doctext_lineno;
+
+/**
+ * Flags to control code generation
+ */
+bool gen_cpp = false;
+bool gen_dense = false;
+bool gen_java = false;
+bool gen_javabean = false;
+bool gen_rb = false;
+bool gen_py = false;
+bool gen_py_newstyle = false;
+bool gen_xsd = false;
+bool gen_php = false;
+bool gen_phpi = false;
+bool gen_phps = true;
+bool gen_phpa = false;
+bool gen_phpo = false;
+bool gen_rest = false;
+bool gen_perl = false;
+bool gen_erl = false;
+bool gen_ocaml = false;
+bool gen_hs = false;
+bool gen_cocoa = false;
+bool gen_csharp = false;
+bool gen_st = false;
+bool gen_recurse = false;
+
+/**
+ * MinGW doesn't have realpath, so use fallback implementation in that case,
+ * otherwise this just calls through to realpath
+ */
+char *saferealpath(const char *path, char *resolved_path) {
+#ifdef MINGW
+  char buf[MAX_PATH];
+  char* basename;
+  DWORD len = GetFullPathName(path, MAX_PATH, buf, &basename);
+  if (len == 0 || len > MAX_PATH - 1){
+    strcpy(resolved_path, path);
+  } else {
+    CharLowerBuff(buf, len);
+    strcpy(resolved_path, buf);
+  }
+  return resolved_path;
+#else
+  return realpath(path, resolved_path);
+#endif
+}
+
+
+/**
+ * Report an error to the user. This is called yyerror for historical
+ * reasons (lex and yacc expect the error reporting routine to be called
+ * this). Call this function to report any errors to the user.
+ * yyerror takes printf style arguments.
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void yyerror(const char* fmt, ...) {
+  va_list args;
+  fprintf(stderr,
+          "[ERROR:%s:%d] (last token was '%s')\n",
+          g_curpath.c_str(),
+          yylineno,
+          yytext);
+
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+
+  fprintf(stderr, "\n");
+}
+
+/**
+ * Prints a debug message from the parser.
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pdebug(const char* fmt, ...) {
+  if (g_debug == 0) {
+    return;
+  }
+  va_list args;
+  printf("[PARSE:%d] ", yylineno);
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+  printf("\n");
+}
+
+/**
+ * Prints a verbose output mode message
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pverbose(const char* fmt, ...) {
+  if (g_verbose == 0) {
+    return;
+  }
+  va_list args;
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+}
+
+/**
+ * Prints a warning message
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pwarning(int level, const char* fmt, ...) {
+  if (g_warn < level) {
+    return;
+  }
+  va_list args;
+  printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno);
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+  printf("\n");
+}
+
+/**
+ * Prints a failure message and exits
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void failure(const char* fmt, ...) {
+  va_list args;
+  fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno);
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+  printf("\n");
+  exit(1);
+}
+
+/**
+ * Converts a string filename into a thrift program name
+ */
+string program_name(string filename) {
+  string::size_type slash = filename.rfind("/");
+  if (slash != string::npos) {
+    filename = filename.substr(slash+1);
+  }
+  string::size_type dot = filename.rfind(".");
+  if (dot != string::npos) {
+    filename = filename.substr(0, dot);
+  }
+  return filename;
+}
+
+/**
+ * Gets the directory path of a filename
+ */
+string directory_name(string filename) {
+  string::size_type slash = filename.rfind("/");
+  // No slash, just use the current directory
+  if (slash == string::npos) {
+    return ".";
+  }
+  return filename.substr(0, slash);
+}
+
+/**
+ * Finds the appropriate file path for the given filename
+ */
+string include_file(string filename) {
+  // Absolute path? Just try that
+  if (filename[0] == '/') {
+    // Realpath!
+    char rp[PATH_MAX];
+    if (saferealpath(filename.c_str(), rp) == NULL) {
+      pwarning(0, "Cannot open include file %s\n", filename.c_str());
+      return std::string();
+    }
+
+    // Stat this file
+    struct stat finfo;
+    if (stat(rp, &finfo) == 0) {
+      return rp;
+    }
+  } else { // relative path, start searching
+    // new search path with current dir global
+    vector<string> sp = g_incl_searchpath;
+    sp.insert(sp.begin(), g_curdir);
+
+    // iterate through paths
+    vector<string>::iterator it;
+    for (it = sp.begin(); it != sp.end(); it++) {
+      string sfilename = *(it) + "/" + filename;
+
+      // Realpath!
+      char rp[PATH_MAX];
+      if (saferealpath(sfilename.c_str(), rp) == NULL) {
+        continue;
+      }
+
+      // Stat this files
+      struct stat finfo;
+      if (stat(rp, &finfo) == 0) {
+        return rp;
+      }
+    }
+  }
+
+  // Uh oh
+  pwarning(0, "Could not find include file %s\n", filename.c_str());
+  return std::string();
+}
+
+/**
+ * Clears any previously stored doctext string.
+ * Also prints a warning if we are discarding information.
+ */
+void clear_doctext() {
+  if (g_doctext != NULL) {
+    pwarning(2, "Uncaptured doctext at on line %d.", g_doctext_lineno);
+  }
+  free(g_doctext);
+  g_doctext = NULL;
+}
+
+/**
+ * Cleans up text commonly found in doxygen-like comments
+ *
+ * Warning: if you mix tabs and spaces in a non-uniform way,
+ * you will get what you deserve.
+ */
+char* clean_up_doctext(char* doctext) {
+  // Convert to C++ string, and remove Windows's carriage returns.
+  string docstring = doctext;
+  docstring.erase(
+      remove(docstring.begin(), docstring.end(), '\r'),
+      docstring.end());
+
+  // Separate into lines.
+  vector<string> lines;
+  string::size_type pos = string::npos;
+  string::size_type last;
+  while (true) {
+    last = (pos == string::npos) ? 0 : pos+1;
+    pos = docstring.find('\n', last);
+    if (pos == string::npos) {
+      // First bit of cleaning.  If the last line is only whitespace, drop it.
+      string::size_type nonwhite = docstring.find_first_not_of(" \t", last);
+      if (nonwhite != string::npos) {
+        lines.push_back(docstring.substr(last));
+      }
+      break;
+    }
+    lines.push_back(docstring.substr(last, pos-last));
+  }
+
+  // A very profound docstring.
+  if (lines.empty()) {
+    return NULL;
+  }
+
+  // Clear leading whitespace from the first line.
+  pos = lines.front().find_first_not_of(" \t");
+  lines.front().erase(0, pos);
+
+  // If every nonblank line after the first has the same number of spaces/tabs,
+  // then a star, remove them.
+  bool have_prefix = true;
+  bool found_prefix = false;
+  string::size_type prefix_len = 0;
+  vector<string>::iterator l_iter;
+  for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
+    if (l_iter->empty()) {
+      continue;
+    }
+
+    pos = l_iter->find_first_not_of(" \t");
+    if (!found_prefix) {
+      if (pos != string::npos) {
+        if (l_iter->at(pos) == '*') {
+          found_prefix = true;
+          prefix_len = pos;
+        } else {
+          have_prefix = false;
+          break;
+        }
+      } else {
+        // Whitespace-only line.  Truncate it.
+        l_iter->clear();
+      }
+    } else if (l_iter->size() > pos
+        && l_iter->at(pos) == '*'
+        && pos == prefix_len) {
+      // Business as usual.
+    } else if (pos == string::npos) {
+      // Whitespace-only line.  Let's truncate it for them.
+      l_iter->clear();
+    } else {
+      // The pattern has been broken.
+      have_prefix = false;
+      break;
+    }
+  }
+
+  // If our prefix survived, delete it from every line.
+  if (have_prefix) {
+    // Get the star too.
+    prefix_len++;
+    for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
+      l_iter->erase(0, prefix_len);
+    }
+  }
+
+  // Now delete the minimum amount of leading whitespace from each line.
+  prefix_len = string::npos;
+  for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
+    if (l_iter->empty()) {
+      continue;
+    }
+    pos = l_iter->find_first_not_of(" \t");
+    if (pos != string::npos
+        && (prefix_len == string::npos || pos < prefix_len)) {
+      prefix_len = pos;
+    }
+  }
+
+  // If our prefix survived, delete it from every line.
+  if (prefix_len != string::npos) {
+    for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
+      l_iter->erase(0, prefix_len);
+    }
+  }
+
+  // Remove trailing whitespace from every line.
+  for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
+    pos = l_iter->find_last_not_of(" \t");
+    if (pos != string::npos && pos != l_iter->length()-1) {
+      l_iter->erase(pos+1);
+    }
+  }
+
+  // If the first line is empty, remove it.
+  // Don't do this earlier because a lot of steps skip the first line.
+  if (lines.front().empty()) {
+    lines.erase(lines.begin());
+  }
+
+  // Now rejoin the lines and copy them back into doctext.
+  docstring.clear();
+  for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
+    docstring += *l_iter;
+    docstring += '\n';
+  }
+
+  assert(docstring.length() <= strlen(doctext));
+  strcpy(doctext, docstring.c_str());
+  return doctext;
+}
+
+/** Set to true to debug docstring parsing */
+static bool dump_docs = false;
+
+/**
+ * Dumps docstrings to stdout
+ * Only works for top-level definitions and the whole program doc
+ * (i.e., not enum constants, struct fields, or functions.
+ */
+void dump_docstrings(t_program* program) {
+  string progdoc = program->get_doc();
+  if (!progdoc.empty()) {
+    printf("Whole program doc:\n%s\n", progdoc.c_str());
+  }
+  const vector<t_typedef*>& typedefs = program->get_typedefs();
+  vector<t_typedef*>::const_iterator t_iter;
+  for (t_iter = typedefs.begin(); t_iter != typedefs.end(); ++t_iter) {
+    t_typedef* td = *t_iter;
+    if (td->has_doc()) {
+      printf("typedef %s:\n%s\n", td->get_name().c_str(), td->get_doc().c_str());
+    }
+  }
+  const vector<t_enum*>& enums = program->get_enums();
+  vector<t_enum*>::const_iterator e_iter;
+  for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) {
+    t_enum* en = *e_iter;
+    if (en->has_doc()) {
+      printf("enum %s:\n%s\n", en->get_name().c_str(), en->get_doc().c_str());
+    }
+  }
+  const vector<t_const*>& consts = program->get_consts();
+  vector<t_const*>::const_iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    t_const* co = *c_iter;
+    if (co->has_doc()) {
+      printf("const %s:\n%s\n", co->get_name().c_str(), co->get_doc().c_str());
+    }
+  }
+  const vector<t_struct*>& structs = program->get_structs();
+  vector<t_struct*>::const_iterator s_iter;
+  for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) {
+    t_struct* st = *s_iter;
+    if (st->has_doc()) {
+      printf("struct %s:\n%s\n", st->get_name().c_str(), st->get_doc().c_str());
+    }
+  }
+  const vector<t_struct*>& xceptions = program->get_xceptions();
+  vector<t_struct*>::const_iterator x_iter;
+  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+    t_struct* xn = *x_iter;
+    if (xn->has_doc()) {
+      printf("xception %s:\n%s\n", xn->get_name().c_str(), xn->get_doc().c_str());
+    }
+  }
+  const vector<t_service*>& services = program->get_services();
+  vector<t_service*>::const_iterator v_iter;
+  for (v_iter = services.begin(); v_iter != services.end(); ++v_iter) {
+    t_service* sv = *v_iter;
+    if (sv->has_doc()) {
+      printf("service %s:\n%s\n", sv->get_name().c_str(), sv->get_doc().c_str());
+    }
+  }
+}
+
+/**
+ * Call generate_fingerprint for every structure and enum.
+ */
+void generate_all_fingerprints(t_program* program) {
+  const vector<t_struct*>& structs = program->get_structs();
+  vector<t_struct*>::const_iterator s_iter;
+  for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) {
+    t_struct* st = *s_iter;
+    st->generate_fingerprint();
+  }
+
+  const vector<t_struct*>& xceptions = program->get_xceptions();
+  vector<t_struct*>::const_iterator x_iter;
+  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+    t_struct* st = *x_iter;
+    st->generate_fingerprint();
+  }
+
+  const vector<t_enum*>& enums = program->get_enums();
+  vector<t_enum*>::const_iterator e_iter;
+  for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) {
+    t_enum* e = *e_iter;
+    e->generate_fingerprint();
+  }
+
+  g_type_void->generate_fingerprint();
+
+  // If you want to generate fingerprints for implicit structures, start here.
+  /*
+  const vector<t_service*>& services = program->get_services();
+  vector<t_service*>::const_iterator v_iter;
+  for (v_iter = services.begin(); v_iter != services.end(); ++v_iter) {
+    t_service* sv = *v_iter;
+  }
+  */
+}
+
+/**
+ * Prints the version number
+ */
+void version() {
+  printf("Thrift version %s-%s\n", THRIFT_VERSION, THRIFT_REVISION);
+}
+
+/**
+ * Diplays the usage message and then exits with an error code.
+ */
+void usage() {
+  fprintf(stderr, "Usage: thrift [options] file\n");
+  fprintf(stderr, "Options:\n");
+  fprintf(stderr, "  -version    Print the compiler version\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");
+  fprintf(stderr, "                searched for include directives\n");
+  fprintf(stderr, "  -nowarn     Suppress all compiler warnings (BAD!)\n");
+  fprintf(stderr, "  -strict     Strict compiler warnings on\n");
+  fprintf(stderr, "  -v[erbose]  Verbose mode\n");
+  fprintf(stderr, "  -r[ecurse]  Also generate included files\n");
+  fprintf(stderr, "  -debug      Parse debug trace to stdout\n");
+  fprintf(stderr, "  --gen STR   Generate code with a dynamically-registered generator.\n");
+  fprintf(stderr, "                STR has the form language[:key1=val1[,key2,[key3=val3]]].\n");
+  fprintf(stderr, "                Keys and values are options passed to the generator.\n");
+  fprintf(stderr, "                Many options will not require values.\n");
+  fprintf(stderr, "\n");
+  fprintf(stderr, "Available generators (and options):\n");
+
+  t_generator_registry::gen_map_t gen_map = t_generator_registry::get_generator_map();
+  t_generator_registry::gen_map_t::iterator iter;
+  for (iter = gen_map.begin(); iter != gen_map.end(); ++iter) {
+    fprintf(stderr, "  %s (%s):\n",
+        iter->second->get_short_name().c_str(),
+        iter->second->get_long_name().c_str());
+    fprintf(stderr, "%s", iter->second->get_documentation().c_str());
+  }
+  exit(1);
+}
+
+/**
+ * You know, when I started working on Thrift I really thought it wasn't going
+ * to become a programming language because it was just a generator and it
+ * wouldn't need runtime type information and all that jazz. But then we
+ * decided to add constants, and all of a sudden that means runtime type
+ * validation and inference, except the "runtime" is the code generator
+ * runtime. Shit. I've been had.
+ */
+void validate_const_rec(std::string name, t_type* type, t_const_value* value) {
+  if (type->is_void()) {
+    throw "type error: cannot declare a void const: " + name;
+  }
+
+  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:
+      if (value->get_type() != t_const_value::CV_STRING) {
+        throw "type error: const \"" + name + "\" was declared as string";
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as bool";
+      }
+      break;
+    case t_base_type::TYPE_BYTE:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as byte";
+      }
+      break;
+    case t_base_type::TYPE_I16:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as i16";
+      }
+      break;
+    case t_base_type::TYPE_I32:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as i32";
+      }
+      break;
+    case t_base_type::TYPE_I64:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as i64";
+      }
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() != t_const_value::CV_INTEGER &&
+          value->get_type() != t_const_value::CV_DOUBLE) {
+        throw "type error: const \"" + name + "\" was declared as double";
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase) + name;
+    }
+  } else if (type->is_enum()) {
+    if (value->get_type() != t_const_value::CV_INTEGER) {
+      throw "type error: const \"" + name + "\" was declared as enum";
+    }
+  } else if (type->is_struct() || type->is_xception()) {
+    if (value->get_type() != t_const_value::CV_MAP) {
+      throw "type error: const \"" + name + "\" was declared as struct/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*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (v_iter->first->get_type() != t_const_value::CV_STRING) {
+        throw "type error: " + name + " struct key must be string";
+      }
+      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();
+      }
+
+      validate_const_rec(name + "." + v_iter->first->get_string(), field_type, v_iter->second);
+    }
+  } else if (type->is_map()) {
+    t_type* k_type = ((t_map*)type)->get_key_type();
+    t_type* v_type = ((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;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      validate_const_rec(name + "<key>", k_type, v_iter->first);
+      validate_const_rec(name + "<val>", v_type, v_iter->second);
+    }
+  } else if (type->is_list() || type->is_set()) {
+    t_type* e_type;
+    if (type->is_list()) {
+      e_type = ((t_list*)type)->get_elem_type();
+    } else {
+      e_type = ((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) {
+      validate_const_rec(name + "<elem>", e_type, *v_iter);
+    }
+  }
+}
+
+/**
+ * Check the type of the parsed const information against its declared type
+ */
+void validate_const_type(t_const* c) {
+  validate_const_rec(c->get_name(), c->get_type(), c->get_value());
+}
+
+/**
+ * Check the type of a default value assigned to a field.
+ */
+void validate_field_value(t_field* field, t_const_value* cv) {
+  validate_const_rec(field->get_name(), field->get_type(), cv);
+}
+
+/**
+ * Check that all the elements of a throws block are actually exceptions.
+ */
+bool validate_throws(t_struct* throws) {
+  const vector<t_field*>& members = throws->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (!(*m_iter)->get_type()->is_xception()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
+ * Parses a program
+ */
+void parse(t_program* program, t_program* parent_program) {
+  // Get scope file path
+  string path = program->get_path();
+
+  // Set current dir global, which is used in the include_file function
+  g_curdir = directory_name(path);
+  g_curpath = path;
+
+  // Open the file
+  yyin = fopen(path.c_str(), "r");
+  if (yyin == 0) {
+    failure("Could not open input file: \"%s\"", path.c_str());
+  }
+
+  // Create new scope and scan for includes
+  pverbose("Scanning %s for includes\n", path.c_str());
+  g_parse_mode = INCLUDES;
+  g_program = program;
+  g_scope = program->scope();
+  try {
+    yylineno = 1;
+    if (yyparse() != 0) {
+      failure("Parser error during include pass.");
+    }
+  } catch (string x) {
+    failure(x.c_str());
+  }
+  fclose(yyin);
+
+  // Recursively parse all the include programs
+  vector<t_program*>& includes = program->get_includes();
+  vector<t_program*>::iterator iter;
+  for (iter = includes.begin(); iter != includes.end(); ++iter) {
+    parse(*iter, program);
+  }
+
+  // Parse the program file
+  g_parse_mode = PROGRAM;
+  g_program = program;
+  g_scope = program->scope();
+  g_parent_scope = (parent_program != NULL) ? parent_program->scope() : NULL;
+  g_parent_prefix = program->get_name() + ".";
+  g_curpath = path;
+  yyin = fopen(path.c_str(), "r");
+  if (yyin == 0) {
+    failure("Could not open input file: \"%s\"", path.c_str());
+  }
+  pverbose("Parsing %s for types\n", path.c_str());
+  yylineno = 1;
+  try {
+    if (yyparse() != 0) {
+      failure("Parser error during types pass.");
+    }
+  } catch (string x) {
+    failure(x.c_str());
+  }
+  fclose(yyin);
+}
+
+/**
+ * Generate code
+ */
+void generate(t_program* program, const vector<string>& generator_strings) {
+  // Oooohh, recursive code generation, hot!!
+  if (gen_recurse) {
+    const vector<t_program*>& includes = program->get_includes();
+    for (size_t i = 0; i < includes.size(); ++i) {
+      // Propogate output path from parent to child programs
+      includes[i]->set_out_path(program->get_out_path());
+
+      generate(includes[i], generator_strings);
+    }
+  }
+
+  // Generate code!
+  try {
+    pverbose("Program: %s\n", program->get_path().c_str());
+
+    // Compute fingerprints.
+    generate_all_fingerprints(program);
+
+    if (dump_docs) {
+      dump_docstrings(program);
+    }
+
+    vector<string>::const_iterator iter;
+    for (iter = generator_strings.begin(); iter != generator_strings.end(); ++iter) {
+      t_generator* generator = t_generator_registry::get_generator(program, *iter);
+
+      if (generator == NULL) {
+        pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str());
+      } else {
+        pverbose("Generating \"%s\"\n", iter->c_str());
+        generator->generate_program();
+        delete generator;
+      }
+    }
+
+  } catch (string s) {
+    printf("Error: %s\n", s.c_str());
+  } catch (const char* exc) {
+    printf("Error: %s\n", exc);
+  }
+
+}
+
+/**
+ * Parse it up.. then spit it back out, in pretty much every language. Alright
+ * not that many languages, but the cool ones that we care about.
+ */
+int main(int argc, char** argv) {
+  int i;
+  std::string out_path;
+
+  // Setup time string
+  time_t now = time(NULL);
+  g_time_str = ctime(&now);
+
+  // Check for necessary arguments, you gotta have at least a filename and
+  // an output language flag
+  if (argc < 2) {
+    usage();
+  }
+
+  vector<string> generator_strings;
+
+  // Set the current path to a dummy value to make warning messages clearer.
+  g_curpath = "arguments";
+
+  // Hacky parameter handling... I didn't feel like using a library sorry!
+  for (i = 1; i < argc-1; i++) {
+    char* arg;
+
+    arg = strtok(argv[i], " ");
+    while (arg != NULL) {
+      // Treat double dashes as single dashes
+      if (arg[0] == '-' && arg[1] == '-') {
+        ++arg;
+      }
+
+      if (strcmp(arg, "-version") == 0) {
+        version();
+        exit(1);
+      } else if (strcmp(arg, "-debug") == 0) {
+        g_debug = 1;
+      } else if (strcmp(arg, "-nowarn") == 0) {
+        g_warn = 0;
+      } else if (strcmp(arg, "-strict") == 0) {
+        g_strict = 255;
+        g_warn = 2;
+      } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "-verbose") == 0 ) {
+        g_verbose = 1;
+      } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-recurse") == 0 ) {
+        gen_recurse = true;
+      } else if (strcmp(arg, "-gen") == 0) {
+        arg = argv[++i];
+        if (arg == NULL) {
+          fprintf(stderr, "!!! Missing generator specification\n");
+          usage();
+        }
+        generator_strings.push_back(arg);
+      } else if (strcmp(arg, "-dense") == 0) {
+        gen_dense = true;
+      } else if (strcmp(arg, "-cpp") == 0) {
+        gen_cpp = true;
+      } else if (strcmp(arg, "-javabean") == 0) {
+        gen_javabean = true;
+      } else if (strcmp(arg, "-java") == 0) {
+        gen_java = true;
+      } else if (strcmp(arg, "-php") == 0) {
+        gen_php = true;
+      } else if (strcmp(arg, "-phpi") == 0) {
+        gen_phpi = true;
+      } else if (strcmp(arg, "-phps") == 0) {
+        gen_php = true;
+        gen_phps = true;
+      } else if (strcmp(arg, "-phpl") == 0) {
+        gen_php = true;
+        gen_phps = false;
+      } else if (strcmp(arg, "-phpa") == 0) {
+        gen_php = true;
+        gen_phps = false;
+        gen_phpa = true;
+      } else if (strcmp(arg, "-phpo") == 0) {
+        gen_php = true;
+        gen_phpo = true;
+      } else if (strcmp(arg, "-rest") == 0) {
+        gen_rest = true;
+      } else if (strcmp(arg, "-py") == 0) {
+        gen_py = true;
+      } else if (strcmp(arg, "-pyns") == 0) {
+        gen_py = true;
+        gen_py_newstyle = true;
+      } else if (strcmp(arg, "-rb") == 0) {
+        gen_rb = true;
+      } else if (strcmp(arg, "-xsd") == 0) {
+        gen_xsd = true;
+      } else if (strcmp(arg, "-perl") == 0) {
+        gen_perl = true;
+      } else if (strcmp(arg, "-erl") == 0) {
+        gen_erl = true;
+      } else if (strcmp(arg, "-ocaml") == 0) {
+        gen_ocaml = true;
+      } else if (strcmp(arg, "-hs") == 0) {
+        gen_hs = true;
+      } else if (strcmp(arg, "-cocoa") == 0) {
+        gen_cocoa = true;
+      } else if (strcmp(arg, "-st") == 0) {
+        gen_st = true;
+      } else if (strcmp(arg, "-csharp") == 0) {
+        gen_csharp = true;
+      } else if (strcmp(arg, "-cpp_use_include_prefix") == 0) {
+        g_cpp_use_include_prefix = true;
+      } else if (strcmp(arg, "-I") == 0) {
+        // An argument of "-I\ asdf" is invalid and has unknown results
+        arg = argv[++i];
+
+        if (arg == NULL) {
+          fprintf(stderr, "!!! Missing Include directory\n");
+          usage();
+        }
+        g_incl_searchpath.push_back(arg);
+      } else if (strcmp(arg, "-o") == 0) {
+        arg = argv[++i];
+        if (arg == NULL) {
+          fprintf(stderr, "-o: missing output directory\n");
+          usage();
+        }
+        out_path = arg;
+
+#ifdef MINGW
+        //strip out trailing \ on Windows
+        int last = out_path.length()-1;
+        if (out_path[last] == '\\')
+        {
+          out_path.erase(last);
+        }
+#endif
+
+        struct stat sb;
+        if (stat(out_path.c_str(), &sb) < 0) {
+          fprintf(stderr, "Output directory %s is unusable: %s\n", out_path.c_str(), strerror(errno));
+          return -1;
+        }
+        if (! S_ISDIR(sb.st_mode)) {
+          fprintf(stderr, "Output directory %s exists but is not a directory\n", out_path.c_str());
+          return -1;
+        }
+      } else {
+        fprintf(stderr, "!!! Unrecognized option: %s\n", arg);
+        usage();
+      }
+
+      // Tokenize more
+      arg = strtok(NULL, " ");
+    }
+  }
+
+  // if you're asking for version, you have a right not to pass a file
+  if (strcmp(argv[argc-1], "-version") == 0) {
+    version();
+    exit(1);
+  }
+
+  // TODO(dreiss): Delete these when everyone is using the new hotness.
+  if (gen_cpp) {
+    pwarning(1, "-cpp is deprecated.  Use --gen cpp");
+    string gen_string = "cpp:";
+    if (gen_dense) {
+      gen_string.append("dense,");
+    }
+    if (g_cpp_use_include_prefix) {
+      gen_string.append("include_prefix,");
+    }
+    generator_strings.push_back(gen_string);
+  }
+  if (gen_java) {
+    pwarning(1, "-java is deprecated.  Use --gen java");
+    generator_strings.push_back("java");
+  }
+  if (gen_javabean) {
+    pwarning(1, "-javabean is deprecated.  Use --gen java:beans");
+    generator_strings.push_back("java:beans");
+  }
+  if (gen_csharp) {
+    pwarning(1, "-csharp is deprecated.  Use --gen csharp");
+    generator_strings.push_back("csharp");
+  }
+  if (gen_py) {
+    pwarning(1, "-py is deprecated.  Use --gen py");
+    generator_strings.push_back("py");
+  }
+  if (gen_rb) {
+    pwarning(1, "-rb is deprecated.  Use --gen rb");
+    generator_strings.push_back("rb");
+  }
+  if (gen_perl) {
+    pwarning(1, "-perl is deprecated.  Use --gen perl");
+    generator_strings.push_back("perl");
+  }
+  if (gen_php || gen_phpi) {
+    pwarning(1, "-php is deprecated.  Use --gen php");
+    string gen_string = "php:";
+    if (gen_phpi) {
+      gen_string.append("inlined,");
+    } else if(gen_phps) {
+      gen_string.append("server,");
+    } else if(gen_phpa) {
+      gen_string.append("autoload,");
+    } else if(gen_phpo) {
+      gen_string.append("oop,");
+    } else if(gen_rest) {
+      gen_string.append("rest,");
+    }
+    generator_strings.push_back(gen_string);
+  }
+  if (gen_cocoa) {
+    pwarning(1, "-cocoa is deprecated.  Use --gen cocoa");
+    generator_strings.push_back("cocoa");
+  }
+  if (gen_erl) {
+    pwarning(1, "-erl is deprecated.  Use --gen erl");
+    generator_strings.push_back("erl");
+  }
+  if (gen_st) {
+    pwarning(1, "-st is deprecated.  Use --gen st");
+    generator_strings.push_back("st");
+  }
+  if (gen_ocaml) {
+    pwarning(1, "-ocaml is deprecated.  Use --gen ocaml");
+    generator_strings.push_back("ocaml");
+  }
+  if (gen_hs) {
+    pwarning(1, "-hs is deprecated.  Use --gen hs");
+    generator_strings.push_back("hs");
+  }
+  if (gen_xsd) {
+    pwarning(1, "-xsd is deprecated.  Use --gen xsd");
+    generator_strings.push_back("xsd");
+  }
+
+  // You gotta generate something!
+  if (generator_strings.empty()) {
+    fprintf(stderr, "!!! No output language(s) specified\n\n");
+    usage();
+  }
+
+  // Real-pathify it
+  char rp[PATH_MAX];
+  if (argv[i] == NULL) {
+    fprintf(stderr, "!!! Missing file name\n");
+    usage();
+  }
+  if (saferealpath(argv[i], rp) == NULL) {
+    failure("Could not open input file with realpath: %s", argv[i]);
+  }
+  string input_file(rp);
+
+  // Instance of the global parse tree
+  t_program* program = new t_program(input_file);
+  if (out_path.size()) {
+    program->set_out_path(out_path);
+  }
+
+  // Compute the cpp include prefix.
+  // infer this from the filename passed in
+  string input_filename = argv[i];
+  string include_prefix;
+
+  string::size_type last_slash = string::npos;
+  if ((last_slash = input_filename.rfind("/")) != string::npos) {
+    include_prefix = input_filename.substr(0, last_slash);
+  }
+
+  program->set_include_prefix(include_prefix);
+
+  // Initialize global types
+  g_type_void   = new t_base_type("void",   t_base_type::TYPE_VOID);
+  g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
+  g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING);
+  ((t_base_type*)g_type_binary)->set_binary(true);
+  g_type_slist  = new t_base_type("string", t_base_type::TYPE_STRING);
+  ((t_base_type*)g_type_slist)->set_string_list(true);
+  g_type_bool   = new t_base_type("bool",   t_base_type::TYPE_BOOL);
+  g_type_byte   = new t_base_type("byte",   t_base_type::TYPE_BYTE);
+  g_type_i16    = new t_base_type("i16",    t_base_type::TYPE_I16);
+  g_type_i32    = new t_base_type("i32",    t_base_type::TYPE_I32);
+  g_type_i64    = new t_base_type("i64",    t_base_type::TYPE_I64);
+  g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
+
+  // Parse it!
+  parse(program, NULL);
+
+  // The current path is not really relevant when we are doing generation.
+  // Reset the variable to make warning messages clearer.
+  g_curpath = "generation";
+  // Reset yylineno for the heck of it.  Use 1 instead of 0 because
+  // That is what shows up during argument parsing.
+  yylineno = 1;
+
+  // Generate it!
+  generate(program, generator_strings);
+
+  // Clean up. Who am I kidding... this program probably orphans heap memory
+  // all over the place, but who cares because it is about to exit and it is
+  // all referenced and used by this wacky parse tree up until now anyways.
+
+  delete program;
+  delete g_type_void;
+  delete g_type_string;
+  delete g_type_bool;
+  delete g_type_byte;
+  delete g_type_i16;
+  delete g_type_i32;
+  delete g_type_i64;
+  delete g_type_double;
+
+  // Finished
+  return 0;
+}
diff --git a/compiler/cpp/src/main.h b/compiler/cpp/src/main.h
new file mode 100644
index 0000000..9b7d82d
--- /dev/null
+++ b/compiler/cpp/src/main.h
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_MAIN_H
+#define T_MAIN_H
+
+#include <string>
+#include "parse/t_const.h"
+#include "parse/t_field.h"
+
+/**
+ * Defined in the flex library
+ */
+
+int yylex(void);
+
+int yyparse(void);
+
+/**
+ * Expected to be defined by Flex/Bison
+ */
+void yyerror(const char* fmt, ...);
+
+/**
+ * Parse debugging output, used to print helpful info
+ */
+void pdebug(const char* fmt, ...);
+
+/**
+ * Parser warning
+ */
+void pwarning(int level, const char* fmt, ...);
+
+/**
+ * Failure!
+ */
+void failure(const char* fmt, ...);
+
+/**
+ * Check constant types
+ */
+void validate_const_type(t_const* c);
+
+/**
+ * Check constant types
+ */
+void validate_field_value(t_field* field, t_const_value* cv);
+
+/**
+ * Check members of a throws block
+ */
+bool validate_throws(t_struct* throws);
+
+/**
+ * Converts a string filename into a thrift program name
+ */
+std::string program_name(std::string filename);
+
+/**
+ * Gets the directory path of a filename
+ */
+std::string directory_name(std::string filename);
+
+/**
+ * Get the absolute path for an include file
+ */
+std::string include_file(std::string filename);
+
+/**
+ * Clears any previously stored doctext string.
+ */
+void clear_doctext();
+
+/**
+ * Cleans up text commonly found in doxygen-like comments
+ */
+char* clean_up_doctext(char* doctext);
+
+/**
+ * Flex utilities
+ */
+
+extern int   yylineno;
+extern char  yytext[];
+extern FILE* yyin;
+
+#endif
diff --git a/compiler/cpp/src/md5.c b/compiler/cpp/src/md5.c
new file mode 100644
index 0000000..c35d96c
--- /dev/null
+++ b/compiler/cpp/src/md5.c
@@ -0,0 +1,381 @@
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+	either statically or dynamically; added missing #include <string.h>
+	in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+	type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+	unsigned in ANSI C, signed in traditional"; made test program
+	self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#  define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3    0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6    0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9    0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13    0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16    0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19    0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22    0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25    0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28    0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31    0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35    0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38    0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41    0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44    0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47    0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50    0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53    0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57    0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60    0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63    0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+	a = pms->abcd[0], b = pms->abcd[1],
+	c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+#if BYTE_ORDER > 0
+    /* Define storage only for big-endian CPUs. */
+    md5_word_t X[16];
+#else
+    /* Define storage for little-endian or both types of CPUs. */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+#endif
+
+    {
+#if BYTE_ORDER == 0
+	/*
+	 * Determine dynamically whether this is a big-endian or
+	 * little-endian machine, since we can use a more efficient
+	 * algorithm on the latter.
+	 */
+	static const int w = 1;
+
+	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0		/* little-endian */
+	{
+	    /*
+	     * On little-endian machines, we can process properly aligned
+	     * data without copying it.
+	     */
+	    if (!((data - (const md5_byte_t *)0) & 3)) {
+		/* data are properly aligned */
+		X = (const md5_word_t *)data;
+	    } else {
+		/* not aligned */
+		memcpy(xbuf, data, 64);
+		X = xbuf;
+	    }
+	}
+#endif
+#if BYTE_ORDER == 0
+	else			/* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0		/* big-endian */
+	{
+	    /*
+	     * On big-endian machines, we must arrange the bytes in the
+	     * right order.
+	     */
+	    const md5_byte_t *xp = data;
+	    int i;
+
+#  if BYTE_ORDER == 0
+	    X = xbuf;		/* (dynamic only) */
+#  else
+#    define xbuf X		/* (static only) */
+#  endif
+	    for (i = 0; i < 16; ++i, xp += 4)
+		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+	}
+#endif
+    }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + F(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+     /* Round 2. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + G(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+     /* Round 3. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + H(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+#undef SET
+
+     /* Round 4. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + I(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+#undef SET
+
+     /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+    pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+    const md5_byte_t *p = data;
+    int left = nbytes;
+    int offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+	return;
+
+    /* Update the message length. */
+    pms->count[1] += nbytes >> 29;
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+	pms->count[1]++;
+
+    /* Process an initial partial block. */
+    if (offset) {
+	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+	memcpy(pms->buf + offset, p, copy);
+	if (offset + copy < 64)
+	    return;
+	p += copy;
+	left -= copy;
+	md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+	md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+	memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/compiler/cpp/src/md5.h b/compiler/cpp/src/md5.h
new file mode 100644
index 0000000..698c995
--- /dev/null
+++ b/compiler/cpp/src/md5.h
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.h is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Removed support for non-ANSI compilers; removed
+	references to Ghostscript; clarified derivation from RFC 1321;
+	now handles byte order either statically or dynamically.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+	added conditionalization for C++ compilation from Martin
+	Purschke <purschke@bnl.gov>.
+  1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+#  define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+    md5_word_t count[2];	/* message length in bits, lsw first */
+    md5_word_t abcd[4];		/* digest buffer */
+    md5_byte_t buf[64];		/* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C" 
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
diff --git a/compiler/cpp/src/parse/t_base_type.h b/compiler/cpp/src/parse/t_base_type.h
new file mode 100644
index 0000000..1751df9
--- /dev/null
+++ b/compiler/cpp/src/parse/t_base_type.h
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_BASE_TYPE_H
+#define T_BASE_TYPE_H
+
+#include <cstdlib>
+#include "t_type.h"
+
+/**
+ * A thrift base type, which must be one of the defined enumerated types inside
+ * this definition.
+ *
+ */
+class t_base_type : public t_type {
+ public:
+  /**
+   * Enumeration of thrift base types
+   */
+  enum t_base {
+    TYPE_VOID,
+    TYPE_STRING,
+    TYPE_BOOL,
+    TYPE_BYTE,
+    TYPE_I16,
+    TYPE_I32,
+    TYPE_I64,
+    TYPE_DOUBLE
+  };
+
+  t_base_type(std::string name, t_base base) :
+    t_type(name),
+    base_(base),
+    string_list_(false),
+    binary_(false),
+    string_enum_(false){}
+
+  t_base get_base() const {
+    return base_;
+  }
+
+  bool is_void() const {
+    return base_ == TYPE_VOID;
+  }
+
+  bool is_string() const {
+    return base_ == TYPE_STRING;
+  }
+
+  bool is_bool() const {
+    return base_ == TYPE_BOOL;
+  }
+
+  void set_string_list(bool val) {
+    string_list_ = val;
+  }
+
+  bool is_string_list() const {
+    return (base_ == TYPE_STRING) && string_list_;
+  }
+
+  void set_binary(bool val) {
+    binary_ = val;
+  }
+
+  bool is_binary() const {
+    return (base_ == TYPE_STRING) && binary_;
+  }
+
+  void set_string_enum(bool val) {
+    string_enum_ = true;
+  }
+
+  bool is_string_enum() const {
+    return base_ == TYPE_STRING && string_enum_;
+  }
+
+  void add_string_enum_val(std::string val) {
+    string_enum_vals_.push_back(val);
+  }
+
+  const std::vector<std::string>& get_string_enum_vals() const {
+    return string_enum_vals_;
+  }
+
+  bool is_base_type() const {
+    return true;
+  }
+
+  virtual std::string get_fingerprint_material() const {
+    std::string rv = t_base_name(base_);
+    if (rv == "(unknown)") {
+      throw "BUG: Can't get fingerprint material for this base type.";
+    }
+    return rv;
+  }
+
+  static std::string t_base_name(t_base tbase) {
+    switch (tbase) {
+      case TYPE_VOID   : return      "void"; break;
+      case TYPE_STRING : return    "string"; break;
+      case TYPE_BOOL   : return      "bool"; break;
+      case TYPE_BYTE   : return      "byte"; break;
+      case TYPE_I16    : return       "i16"; break;
+      case TYPE_I32    : return       "i32"; break;
+      case TYPE_I64    : return       "i64"; break;
+      case TYPE_DOUBLE : return    "double"; break;
+      default          : return "(unknown)"; break;
+    }
+  }
+
+ private:
+  t_base base_;
+
+  bool string_list_;
+  bool binary_;
+  bool string_enum_;
+  std::vector<std::string> string_enum_vals_;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_const.h b/compiler/cpp/src/parse/t_const.h
new file mode 100644
index 0000000..7fd81bd
--- /dev/null
+++ b/compiler/cpp/src/parse/t_const.h
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_CONST_H
+#define T_CONST_H
+
+#include "t_type.h"
+#include "t_const_value.h"
+
+/**
+ * A const is a constant value defined across languages that has a type and
+ * a value. The trick here is that the declared type might not match the type
+ * of the value object, since that is not determined until after parsing the
+ * whole thing out.
+ *
+ */
+class t_const : public t_doc {
+ public:
+  t_const(t_type* type, std::string name, t_const_value* value) :
+    type_(type),
+    name_(name),
+    value_(value) {}
+
+  t_type* get_type() const {
+    return type_;
+  }
+
+  std::string get_name() const {
+    return name_;
+  }
+
+  t_const_value* get_value() const {
+    return value_;
+  }
+
+ private:
+  t_type* type_;
+  std::string name_;
+  t_const_value* value_;
+};
+
+#endif
+
diff --git a/compiler/cpp/src/parse/t_const_value.h b/compiler/cpp/src/parse/t_const_value.h
new file mode 100644
index 0000000..a7d6e31
--- /dev/null
+++ b/compiler/cpp/src/parse/t_const_value.h
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_CONST_VALUE_H
+#define T_CONST_VALUE_H
+
+#include "t_const.h"
+#include <stdint.h>
+#include <map>
+#include <vector>
+
+/**
+ * A const value is something parsed that could be a map, set, list, struct
+ * or whatever.
+ *
+ */
+class t_const_value {
+ public:
+
+  enum t_const_value_type {
+    CV_INTEGER,
+    CV_DOUBLE,
+    CV_STRING,
+    CV_MAP,
+    CV_LIST
+  };
+
+  t_const_value() {}
+
+  t_const_value(int64_t val) {
+    set_integer(val);
+  }
+
+  t_const_value(std::string val) {
+    set_string(val);
+  }
+
+  void set_string(std::string val) {
+    valType_ = CV_STRING;
+    stringVal_ = val;
+  }
+
+  std::string get_string() const {
+    return stringVal_;
+  }
+
+  void set_integer(int64_t val) {
+    valType_ = CV_INTEGER;
+    intVal_ = val;
+  }
+
+  int64_t get_integer() const {
+    return intVal_;
+  }
+
+  void set_double(double val) {
+    valType_ = CV_DOUBLE;
+    doubleVal_ = val;
+  }
+
+  double get_double() const {
+    return doubleVal_;
+  }
+
+  void set_map() {
+    valType_ = CV_MAP;
+  }
+
+  void add_map(t_const_value* key, t_const_value* val) {
+    mapVal_[key] = val;
+  }
+
+  const std::map<t_const_value*, t_const_value*>& get_map() const {
+    return mapVal_;
+  }
+
+  void set_list() {
+    valType_ = CV_LIST;
+  }
+
+  void add_list(t_const_value* val) {
+    listVal_.push_back(val);
+  }
+
+  const std::vector<t_const_value*>& get_list() const {
+    return listVal_;
+  }
+
+  t_const_value_type get_type() const {
+    return valType_;
+  }
+
+ private:
+  std::map<t_const_value*, t_const_value*> mapVal_;
+  std::vector<t_const_value*> listVal_;
+  std::string stringVal_;
+  int64_t intVal_;
+  double doubleVal_;
+
+  t_const_value_type valType_;
+
+};
+
+#endif
+
diff --git a/compiler/cpp/src/parse/t_container.h b/compiler/cpp/src/parse/t_container.h
new file mode 100644
index 0000000..6753493
--- /dev/null
+++ b/compiler/cpp/src/parse/t_container.h
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_CONTAINER_H
+#define T_CONTAINER_H
+
+#include "t_type.h"
+
+class t_container : public t_type {
+ public:
+  t_container() :
+    cpp_name_(),
+    has_cpp_name_(false) {}
+
+  virtual ~t_container() {}
+
+  void set_cpp_name(std::string cpp_name) {
+    cpp_name_ = cpp_name;
+    has_cpp_name_ = true;
+  }
+
+  bool has_cpp_name() {
+    return has_cpp_name_;
+  }
+
+  std::string get_cpp_name() {
+    return cpp_name_;
+  }
+
+  bool is_container() const {
+    return true;
+  }
+
+ private:
+  std::string cpp_name_;
+  bool has_cpp_name_;
+
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_doc.h b/compiler/cpp/src/parse/t_doc.h
new file mode 100644
index 0000000..e52068c
--- /dev/null
+++ b/compiler/cpp/src/parse/t_doc.h
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_DOC_H
+#define T_DOC_H
+
+/**
+ * Documentation stubs
+ *
+ */
+class t_doc {
+
+ public:
+  t_doc() : has_doc_(false) {}
+
+  void set_doc(const std::string& doc) {
+    doc_ = doc;
+    has_doc_ = true;
+  }
+
+  const std::string& get_doc() const {
+    return doc_;
+  }
+
+  bool has_doc() {
+    return has_doc_;
+  }
+
+ private:
+  std::string doc_;
+  bool has_doc_;
+
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_enum.h b/compiler/cpp/src/parse/t_enum.h
new file mode 100644
index 0000000..740f95c
--- /dev/null
+++ b/compiler/cpp/src/parse/t_enum.h
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_ENUM_H
+#define T_ENUM_H
+
+#include "t_enum_value.h"
+#include <vector>
+
+/**
+ * An enumerated type. A list of constant objects with a name for the type.
+ *
+ */
+class t_enum : public t_type {
+ public:
+  t_enum(t_program* program) :
+    t_type(program) {}
+
+  void set_name(const std::string& name) {
+    name_ = name;
+  }
+
+  void append(t_enum_value* constant) {
+    constants_.push_back(constant);
+  }
+
+  const std::vector<t_enum_value*>& get_constants() {
+    return constants_;
+  }
+
+  bool is_enum() const {
+    return true;
+  }
+
+  virtual std::string get_fingerprint_material() const {
+    return "enum";
+  }
+
+ private:
+  std::vector<t_enum_value*> constants_;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_enum_value.h b/compiler/cpp/src/parse/t_enum_value.h
new file mode 100644
index 0000000..68e905b
--- /dev/null
+++ b/compiler/cpp/src/parse/t_enum_value.h
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_ENUM_VALUE_H
+#define T_ENUM_VALUE_H
+
+#include <string>
+#include "t_doc.h"
+
+/**
+ * A constant. These are used inside of enum definitions. Constants are just
+ * symbol identifiers that may or may not have an explicit value associated
+ * with them.
+ *
+ */
+class t_enum_value : public t_doc {
+ public:
+  t_enum_value(std::string name) :
+    name_(name),
+    has_value_(false),
+    value_(0) {}
+
+  t_enum_value(std::string name, int value) :
+    name_(name),
+    has_value_(true),
+    value_(value) {}
+
+  ~t_enum_value() {}
+
+  const std::string& get_name() {
+    return name_;
+  }
+
+  bool has_value() {
+    return has_value_;
+  }
+
+  int get_value() {
+    return value_;
+  }
+
+ private:
+  std::string name_;
+  bool has_value_;
+  int value_;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
new file mode 100644
index 0000000..67a2125
--- /dev/null
+++ b/compiler/cpp/src/parse/t_field.h
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_FIELD_H
+#define T_FIELD_H
+
+#include <string>
+#include <boost/lexical_cast.hpp>
+
+#include "t_doc.h"
+
+// Forward declare for xsd_attrs
+class t_struct;
+
+/**
+ * Class to represent a field in a thrift structure. A field has a data type,
+ * a symbolic name, and a numeric identifier.
+ *
+ */
+class t_field : public t_doc {
+ public:
+  t_field(t_type* type, std::string name) :
+    type_(type),
+    name_(name),
+    key_(0),
+    value_(NULL),
+    xsd_optional_(false),
+    xsd_nillable_(false),
+    xsd_attrs_(NULL) {}
+
+  t_field(t_type* type, std::string name, int32_t key) :
+    type_(type),
+    name_(name),
+    key_(key),
+    req_(T_OPT_IN_REQ_OUT),
+    value_(NULL),
+    xsd_optional_(false),
+    xsd_nillable_(false),
+    xsd_attrs_(NULL) {}
+
+  ~t_field() {}
+
+  t_type* get_type() const {
+    return type_;
+  }
+
+  const std::string& get_name() const {
+    return name_;
+  }
+
+  int32_t get_key() const {
+    return key_;
+  }
+
+  enum e_req {
+    T_REQUIRED,
+    T_OPTIONAL,
+    T_OPT_IN_REQ_OUT,
+  };
+
+  void set_req(e_req req) {
+    req_ = req;
+  }
+
+  e_req get_req() const {
+    return req_;
+  }
+
+  void set_value(t_const_value* value) {
+    value_ = value;
+  }
+
+  t_const_value* get_value() {
+    return value_;
+  }
+
+  void set_xsd_optional(bool xsd_optional) {
+    xsd_optional_ = xsd_optional;
+  }
+
+  bool get_xsd_optional() const {
+    return xsd_optional_;
+  }
+
+  void set_xsd_nillable(bool xsd_nillable) {
+    xsd_nillable_ = xsd_nillable;
+  }
+
+  bool get_xsd_nillable() const {
+    return xsd_nillable_;
+  }
+
+  void set_xsd_attrs(t_struct* xsd_attrs) {
+    xsd_attrs_ = xsd_attrs;
+  }
+
+  t_struct* get_xsd_attrs() {
+    return xsd_attrs_;
+  }
+
+  // This is not the same function as t_type::get_fingerprint_material,
+  // but it does the same thing.
+  std::string get_fingerprint_material() const {
+    return boost::lexical_cast<std::string>(key_) + ":" +
+      ((req_ == T_OPTIONAL) ? "opt-" : "") +
+      type_->get_fingerprint_material();
+  }
+
+  /**
+   * Comparator to sort fields in ascending order by key.
+   * Make this a functor instead of a function to help GCC inline it.
+   * The arguments are (const) references to const pointers to const t_fields.
+   */
+  struct key_compare {
+    bool operator()(t_field const * const & a, t_field const * const & b) {
+      return a->get_key() < b->get_key();
+    }
+  };
+
+
+ private:
+  t_type* type_;
+  std::string name_;
+  int32_t key_;
+  e_req req_;
+  t_const_value* value_;
+
+  bool xsd_optional_;
+  bool xsd_nillable_;
+  t_struct* xsd_attrs_;
+
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_function.h b/compiler/cpp/src/parse/t_function.h
new file mode 100644
index 0000000..a72aa6c
--- /dev/null
+++ b/compiler/cpp/src/parse/t_function.h
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_FUNCTION_H
+#define T_FUNCTION_H
+
+#include <string>
+#include "t_type.h"
+#include "t_struct.h"
+#include "t_doc.h"
+
+/**
+ * Representation of a function. Key parts are return type, function name,
+ * optional modifiers, and an argument list, which is implemented as a thrift
+ * struct.
+ *
+ */
+class t_function : public t_doc {
+ public:
+  t_function(t_type* returntype,
+             std::string name,
+             t_struct* arglist,
+             bool oneway=false) :
+    returntype_(returntype),
+    name_(name),
+    arglist_(arglist),
+    oneway_(oneway) {
+    xceptions_ = new t_struct(NULL);
+  }
+
+  t_function(t_type* returntype,
+             std::string name,
+             t_struct* arglist,
+             t_struct* xceptions,
+             bool oneway=false) :
+    returntype_(returntype),
+    name_(name),
+    arglist_(arglist),
+    xceptions_(xceptions),
+    oneway_(oneway)
+  {
+    if (oneway_ && !xceptions_->get_members().empty()) {
+      throw std::string("Oneway methods can't throw exceptions.");
+    }
+  }
+
+  ~t_function() {}
+
+  t_type* get_returntype() const {
+    return returntype_;
+  }
+
+  const std::string& get_name() const {
+    return name_;
+  }
+
+  t_struct* get_arglist() const {
+    return arglist_;
+  }
+
+  t_struct* get_xceptions() const {
+    return xceptions_;
+  }
+
+  bool is_oneway() const {
+    return oneway_;
+  }
+
+ private:
+  t_type* returntype_;
+  std::string name_;
+  t_struct* arglist_;
+  t_struct* xceptions_;
+  bool oneway_;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_list.h b/compiler/cpp/src/parse/t_list.h
new file mode 100644
index 0000000..21a9625
--- /dev/null
+++ b/compiler/cpp/src/parse/t_list.h
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_LIST_H
+#define T_LIST_H
+
+#include "t_container.h"
+
+/**
+ * A list is a lightweight container type that just wraps another data type.
+ *
+ */
+class t_list : public t_container {
+ public:
+  t_list(t_type* elem_type) :
+    elem_type_(elem_type) {}
+
+  t_type* get_elem_type() const {
+    return elem_type_;
+  }
+
+  bool is_list() const {
+    return true;
+  }
+
+  virtual std::string get_fingerprint_material() const {
+    return "list<" + elem_type_->get_fingerprint_material() + ">";
+  }
+
+  virtual void generate_fingerprint() {
+    t_type::generate_fingerprint();
+    elem_type_->generate_fingerprint();
+  }
+
+ private:
+  t_type* elem_type_;
+};
+
+#endif
+
diff --git a/compiler/cpp/src/parse/t_map.h b/compiler/cpp/src/parse/t_map.h
new file mode 100644
index 0000000..c4e358f
--- /dev/null
+++ b/compiler/cpp/src/parse/t_map.h
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_MAP_H
+#define T_MAP_H
+
+#include "t_container.h"
+
+/**
+ * A map is a lightweight container type that just wraps another two data
+ * types.
+ *
+ */
+class t_map : public t_container {
+ public:
+  t_map(t_type* key_type, t_type* val_type) :
+    key_type_(key_type),
+    val_type_(val_type) {}
+
+  t_type* get_key_type() const {
+    return key_type_;
+  }
+
+  t_type* get_val_type() const {
+    return val_type_;
+  }
+
+  bool is_map() const {
+    return true;
+  }
+
+  virtual std::string get_fingerprint_material() const {
+    return "map<" + key_type_->get_fingerprint_material() +
+      "," + val_type_->get_fingerprint_material() + ">";
+  }
+
+  virtual void generate_fingerprint() {
+    t_type::generate_fingerprint();
+    key_type_->generate_fingerprint();
+    val_type_->generate_fingerprint();
+  }
+
+ private:
+  t_type* key_type_;
+  t_type* val_type_;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
new file mode 100644
index 0000000..4e1ab6a
--- /dev/null
+++ b/compiler/cpp/src/parse/t_program.h
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_PROGRAM_H
+#define T_PROGRAM_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+// For program_name()
+#include "main.h"
+
+#include "t_doc.h"
+#include "t_scope.h"
+#include "t_base_type.h"
+#include "t_typedef.h"
+#include "t_enum.h"
+#include "t_const.h"
+#include "t_struct.h"
+#include "t_service.h"
+#include "t_list.h"
+#include "t_map.h"
+#include "t_set.h"
+//#include "t_doc.h"
+
+/**
+ * Top level class representing an entire thrift program. A program consists
+ * fundamentally of the following:
+ *
+ *   Typedefs
+ *   Enumerations
+ *   Constants
+ *   Structs
+ *   Exceptions
+ *   Services
+ *
+ * The program module also contains the definitions of the base types.
+ *
+ */
+class t_program : public t_doc {
+ public:
+  t_program(std::string path, std::string name) :
+    path_(path),
+    name_(name),
+    out_path_("./") {
+    scope_ = new t_scope();
+  }
+
+  t_program(std::string path) :
+    path_(path),
+    out_path_("./") {
+    name_ = program_name(path);
+    scope_ = new t_scope();
+  }
+
+  // Path accessor
+  const std::string& get_path() const { return path_; }
+
+  // Output path accessor
+  const std::string& get_out_path() const { return out_path_; }
+
+  // Name accessor
+  const std::string& get_name() const { return name_; }
+
+  // Namespace
+  const std::string& get_namespace() const { return namespace_; }
+
+  // Include prefix accessor
+  const std::string& get_include_prefix() const { return include_prefix_; }
+
+  // Accessors for program elements
+  const std::vector<t_typedef*>& get_typedefs()  const { return typedefs_;  }
+  const std::vector<t_enum*>&    get_enums()     const { return enums_;     }
+  const std::vector<t_const*>&   get_consts()    const { return consts_;    }
+  const std::vector<t_struct*>&  get_structs()   const { return structs_;   }
+  const std::vector<t_struct*>&  get_xceptions() const { return xceptions_; }
+  const std::vector<t_struct*>&  get_objects()   const { return objects_;   }
+  const std::vector<t_service*>& get_services()  const { return services_;  }
+
+  // Program elements
+  void add_typedef  (t_typedef* td) { typedefs_.push_back(td);  }
+  void add_enum     (t_enum*    te) { enums_.push_back(te);     }
+  void add_const    (t_const*   tc) { consts_.push_back(tc);    }
+  void add_struct   (t_struct*  ts) { objects_.push_back(ts);
+                                      structs_.push_back(ts);   }
+  void add_xception (t_struct*  tx) { objects_.push_back(tx);
+                                      xceptions_.push_back(tx); }
+  void add_service  (t_service* ts) { services_.push_back(ts);  }
+
+  // Programs to include
+  const std::vector<t_program*>& get_includes() const { return includes_; }
+
+  void set_out_path(std::string out_path) {
+    out_path_ = out_path;
+    // Ensure that it ends with a trailing '/' (or '\' for windows machines)
+    char c = out_path_.at(out_path_.size() - 1);
+    if (!(c == '/' || c == '\\')) {
+      out_path_.push_back('/');
+    }
+  }
+
+  // Scoping and namespacing
+  void set_namespace(std::string name) {
+    namespace_ = name;
+  }
+
+  // Scope accessor
+  t_scope* scope() {
+    return scope_;
+  }
+
+  // Includes
+
+  void add_include(std::string path, std::string include_site) {
+    t_program* program = new t_program(path);
+
+    // include prefix for this program is the site at which it was included
+    // (minus the filename)
+    std::string include_prefix;
+    std::string::size_type last_slash = std::string::npos;
+    if ((last_slash = include_site.rfind("/")) != std::string::npos) {
+      include_prefix = include_site.substr(0, last_slash);
+    }
+
+    program->set_include_prefix(include_prefix);
+    includes_.push_back(program);
+  }
+
+  std::vector<t_program*>& get_includes() {
+    return includes_;
+  }
+
+  void set_include_prefix(std::string include_prefix) {
+    include_prefix_ = include_prefix;
+
+    // this is intended to be a directory; add a trailing slash if necessary
+    int len = include_prefix_.size();
+    if (len > 0 && include_prefix_[len - 1] != '/') {
+      include_prefix_ += '/';
+    }
+  }
+
+  // Language neutral namespace / packaging
+  void set_namespace(std::string language, std::string name_space) {
+    namespaces_[language] = name_space;
+  }
+
+  std::string get_namespace(std::string language) const {
+    std::map<std::string, std::string>::const_iterator iter = namespaces_.find(language);
+    if (iter == namespaces_.end()) {
+      return std::string();
+    }
+    return iter->second;
+  }
+
+  // Language specific namespace / packaging
+
+  void add_cpp_include(std::string path) {
+    cpp_includes_.push_back(path);
+  }
+
+  const std::vector<std::string>& get_cpp_includes() {
+    return cpp_includes_;
+  }
+
+ private:
+
+  // File path
+  std::string path_;
+
+  // Name
+  std::string name_;
+
+  // Output directory
+  std::string out_path_;
+
+  // Namespace
+  std::string namespace_;
+
+  // Included programs
+  std::vector<t_program*> includes_;
+
+  // Include prefix for this program, if any
+  std::string include_prefix_;
+
+  // Identifier lookup scope
+  t_scope* scope_;
+
+  // Components to generate code for
+  std::vector<t_typedef*> typedefs_;
+  std::vector<t_enum*>    enums_;
+  std::vector<t_const*>   consts_;
+  std::vector<t_struct*>  objects_;
+  std::vector<t_struct*>  structs_;
+  std::vector<t_struct*>  xceptions_;
+  std::vector<t_service*> services_;
+
+  // Dynamic namespaces
+  std::map<std::string, std::string> namespaces_;
+
+  // C++ extra includes
+  std::vector<std::string> cpp_includes_;
+
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_scope.h b/compiler/cpp/src/parse/t_scope.h
new file mode 100644
index 0000000..122e325
--- /dev/null
+++ b/compiler/cpp/src/parse/t_scope.h
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_SCOPE_H
+#define T_SCOPE_H
+
+#include <map>
+#include <string>
+
+#include "t_type.h"
+#include "t_service.h"
+
+/**
+ * This represents a variable scope used for looking up predefined types and
+ * services. Typically, a scope is associated with a t_program. Scopes are not
+ * used to determine code generation, but rather to resolve identifiers at
+ * parse time.
+ *
+ */
+class t_scope {
+ public:
+  t_scope() {}
+
+  void add_type(std::string name, t_type* type) {
+    types_[name] = type;
+  }
+
+  t_type* get_type(std::string name) {
+    return types_[name];
+  }
+
+  void add_service(std::string name, t_service* service) {
+    services_[name] = service;
+  }
+
+  t_service* get_service(std::string name) {
+    return services_[name];
+  }
+
+  void add_constant(std::string name, t_const* constant) {
+    constants_[name] = constant;
+  }
+
+  t_const* get_constant(std::string name) {
+    return constants_[name];
+  }
+
+  void print() {
+    std::map<std::string, t_type*>::iterator iter;
+    for (iter = types_.begin(); iter != types_.end(); ++iter) {
+      printf("%s => %s\n",
+             iter->first.c_str(),
+             iter->second->get_name().c_str());
+    }
+  }
+
+ private:
+
+  // Map of names to types
+  std::map<std::string, t_type*> types_;
+
+  // Map of names to constants
+  std::map<std::string, t_const*> constants_;
+
+  // Map of names to services
+  std::map<std::string, t_service*> services_;
+
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_service.h b/compiler/cpp/src/parse/t_service.h
new file mode 100644
index 0000000..eee2dac
--- /dev/null
+++ b/compiler/cpp/src/parse/t_service.h
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_SERVICE_H
+#define T_SERVICE_H
+
+#include "t_function.h"
+#include <vector>
+
+class t_program;
+
+/**
+ * A service consists of a set of functions.
+ *
+ */
+class t_service : public t_type {
+ public:
+  t_service(t_program* program) :
+    t_type(program),
+    extends_(NULL) {}
+
+  bool is_service() const {
+    return true;
+  }
+
+  void set_extends(t_service* extends) {
+    extends_ = extends;
+  }
+
+  void add_function(t_function* func) {
+    functions_.push_back(func);
+  }
+
+  const std::vector<t_function*>& get_functions() const {
+    return functions_;
+  }
+
+  t_service* get_extends() {
+    return extends_;
+  }
+
+  virtual std::string get_fingerprint_material() const {
+    // Services should never be used in fingerprints.
+    throw "BUG: Can't get fingerprint material for service.";
+  }
+
+ private:
+  std::vector<t_function*> functions_;
+  t_service* extends_;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_set.h b/compiler/cpp/src/parse/t_set.h
new file mode 100644
index 0000000..d198357
--- /dev/null
+++ b/compiler/cpp/src/parse/t_set.h
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_SET_H
+#define T_SET_H
+
+#include "t_container.h"
+
+/**
+ * A set is a lightweight container type that just wraps another data type.
+ *
+ */
+class t_set : public t_container {
+ public:
+  t_set(t_type* elem_type) :
+    elem_type_(elem_type) {}
+
+  t_type* get_elem_type() const {
+    return elem_type_;
+  }
+
+  bool is_set() const {
+    return true;
+  }
+
+  virtual std::string get_fingerprint_material() const {
+    return "set<" + elem_type_->get_fingerprint_material() + ">";
+  }
+
+  virtual void generate_fingerprint() {
+    t_type::generate_fingerprint();
+    elem_type_->generate_fingerprint();
+  }
+
+ private:
+  t_type* elem_type_;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_struct.h b/compiler/cpp/src/parse/t_struct.h
new file mode 100644
index 0000000..7980f80
--- /dev/null
+++ b/compiler/cpp/src/parse/t_struct.h
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_STRUCT_H
+#define T_STRUCT_H
+
+#include <algorithm>
+#include <vector>
+#include <utility>
+#include <string>
+
+#include "t_type.h"
+#include "t_field.h"
+
+// Forward declare that puppy
+class t_program;
+
+/**
+ * A struct is a container for a set of member fields that has a name. Structs
+ * are also used to implement exception types.
+ *
+ */
+class t_struct : public t_type {
+ public:
+  typedef std::vector<t_field*> members_type;
+
+  t_struct(t_program* program) :
+    t_type(program),
+    is_xception_(false),
+    xsd_all_(false) {}
+
+  t_struct(t_program* program, const std::string& name) :
+    t_type(program, name),
+    is_xception_(false),
+    xsd_all_(false) {}
+
+  void set_name(const std::string& name) {
+    name_ = name;
+  }
+
+  void set_xception(bool is_xception) {
+    is_xception_ = is_xception;
+  }
+
+  void set_xsd_all(bool xsd_all) {
+    xsd_all_ = xsd_all;
+  }
+
+  bool get_xsd_all() const {
+    return xsd_all_;
+  }
+
+  bool append(t_field* elem) {
+    members_.push_back(elem);
+
+    typedef members_type::iterator iter_type;
+    std::pair<iter_type, iter_type> bounds = std::equal_range(
+            members_in_id_order_.begin(), members_in_id_order_.end(), elem, t_field::key_compare()
+        );
+    if (bounds.first != bounds.second) {
+      return false;
+    }
+    members_in_id_order_.insert(bounds.second, elem);
+    return true;
+  }
+
+  const members_type& get_members() {
+    return members_;
+  }
+
+  const members_type& get_sorted_members() {
+    return members_in_id_order_;
+  }
+
+  bool is_struct() const {
+    return !is_xception_;
+  }
+
+  bool is_xception() const {
+    return is_xception_;
+  }
+
+  virtual std::string get_fingerprint_material() const {
+    std::string rv = "{";
+    members_type::const_iterator m_iter;
+    for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
+      rv += (*m_iter)->get_fingerprint_material();
+      rv += ";";
+    }
+    rv += "}";
+    return rv;
+  }
+
+  virtual void generate_fingerprint() {
+    t_type::generate_fingerprint();
+    members_type::const_iterator m_iter;
+    for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
+      (*m_iter)->get_type()->generate_fingerprint();
+    }
+  }
+
+ private:
+
+  members_type members_;
+  members_type members_in_id_order_;
+  bool is_xception_;
+
+  bool xsd_all_;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h
new file mode 100644
index 0000000..4ce2eda
--- /dev/null
+++ b/compiler/cpp/src/parse/t_type.h
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_TYPE_H
+#define T_TYPE_H
+
+#include <string>
+#include <map>
+#include <cstring>
+#include <stdint.h>
+#include "t_doc.h"
+
+// What's worse?  This, or making a src/parse/non_inlined.cc?
+#include "md5.h"
+
+class t_program;
+
+/**
+ * Generic representation of a thrift type. These objects are used by the
+ * parser module to build up a tree of object that are all explicitly typed.
+ * The generic t_type class exports a variety of useful methods that are
+ * used by the code generator to branch based upon different handling for the
+ * various types.
+ *
+ */
+class t_type : public t_doc {
+ public:
+  virtual ~t_type() {}
+
+  virtual void set_name(const std::string& name) {
+    name_ = name;
+  }
+
+  virtual const std::string& get_name() const {
+    return name_;
+  }
+
+  virtual bool is_void()      const { return false; }
+  virtual bool is_base_type() const { return false; }
+  virtual bool is_string()    const { return false; }
+  virtual bool is_bool()      const { return false; }
+  virtual bool is_typedef()   const { return false; }
+  virtual bool is_enum()      const { return false; }
+  virtual bool is_struct()    const { return false; }
+  virtual bool is_xception()  const { return false; }
+  virtual bool is_container() const { return false; }
+  virtual bool is_list()      const { return false; }
+  virtual bool is_set()       const { return false; }
+  virtual bool is_map()       const { return false; }
+  virtual bool is_service()   const { return false; }
+
+  t_program* get_program() {
+    return program_;
+  }
+
+
+  // Return a string that uniquely identifies this type
+  // from any other thrift type in the world, as far as
+  // TDenseProtocol is concerned.
+  // We don't cache this, which is a little sloppy,
+  // but the compiler is so fast that it doesn't really matter.
+  virtual std::string get_fingerprint_material() const = 0;
+
+  // Fingerprint should change whenever (and only when)
+  // the encoding via TDenseProtocol changes.
+  static const int fingerprint_len = 16;
+
+  // Call this before trying get_*_fingerprint().
+  virtual void generate_fingerprint() {
+    std::string material = get_fingerprint_material();
+    md5_state_t ctx;
+    md5_init(&ctx);
+    md5_append(&ctx, (md5_byte_t*)(material.data()), (int)material.size());
+    md5_finish(&ctx, (md5_byte_t*)fingerprint_);
+  }
+
+  bool has_fingerprint() const {
+    for (int i = 0; i < fingerprint_len; i++) {
+      if (fingerprint_[i] != 0) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  const uint8_t* get_binary_fingerprint() const {
+    return fingerprint_;
+  }
+
+  std::string get_ascii_fingerprint() const {
+    std::string rv;
+    const uint8_t* fp = get_binary_fingerprint();
+    for (int i = 0; i < fingerprint_len; i++) {
+      rv += byte_to_hex(fp[i]);
+    }
+    return rv;
+  }
+
+  // This function will break (maybe badly) unless 0 <= num <= 16.
+  static char nybble_to_xdigit(int num) {
+    if (num < 10) {
+      return '0' + num;
+    } else {
+      return 'A' + num - 10;
+    }
+  }
+
+  static std::string byte_to_hex(uint8_t byte) {
+    std::string rv;
+    rv += nybble_to_xdigit(byte >> 4);
+    rv += nybble_to_xdigit(byte & 0x0f);
+    return rv;
+  }
+
+  std::map<std::string, std::string> annotations_;
+
+ protected:
+  t_type() :
+    program_(NULL)
+  {
+    memset(fingerprint_, 0, sizeof(fingerprint_));
+  }
+
+  t_type(t_program* program) :
+    program_(program)
+  {
+    memset(fingerprint_, 0, sizeof(fingerprint_));
+  }
+
+  t_type(t_program* program, std::string name) :
+    program_(program),
+    name_(name)
+  {
+    memset(fingerprint_, 0, sizeof(fingerprint_));
+  }
+
+  t_type(std::string name) :
+    program_(NULL),
+    name_(name)
+  {
+    memset(fingerprint_, 0, sizeof(fingerprint_));
+  }
+
+  t_program* program_;
+  std::string name_;
+
+  uint8_t fingerprint_[fingerprint_len];
+};
+
+
+/**
+ * Placeholder struct for returning the key and value of an annotation
+ * during parsing.
+ */
+struct t_annotation {
+  std::string key;
+  std::string val;
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_typedef.h b/compiler/cpp/src/parse/t_typedef.h
new file mode 100644
index 0000000..4c77d97
--- /dev/null
+++ b/compiler/cpp/src/parse/t_typedef.h
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_TYPEDEF_H
+#define T_TYPEDEF_H
+
+#include <string>
+#include "t_type.h"
+
+/**
+ * A typedef is a mapping from a symbolic name to another type. In dymanically
+ * typed languages (i.e. php/python) the code generator can actually usually
+ * ignore typedefs and just use the underlying type directly, though in C++
+ * the symbolic naming can be quite useful for code clarity.
+ *
+ */
+class t_typedef : public t_type {
+ public:
+  t_typedef(t_program* program, t_type* type, std::string symbolic) :
+    t_type(program, symbolic),
+    type_(type),
+    symbolic_(symbolic) {}
+
+  ~t_typedef() {}
+
+  t_type* get_type() const {
+    return type_;
+  }
+
+  const std::string& get_symbolic() const {
+    return symbolic_;
+  }
+
+  bool is_typedef() const {
+    return true;
+  }
+
+  virtual std::string get_fingerprint_material() const {
+    return type_->get_fingerprint_material();
+  }
+
+  virtual void generate_fingerprint() {
+    t_type::generate_fingerprint();
+    if (!type_->has_fingerprint()) {
+      type_->generate_fingerprint();
+    }
+  }
+
+ private:
+  t_type* type_;
+  std::string symbolic_;
+};
+
+#endif
diff --git a/compiler/cpp/src/platform.h b/compiler/cpp/src/platform.h
new file mode 100644
index 0000000..bd97f68
--- /dev/null
+++ b/compiler/cpp/src/platform.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/**
+ * define for mkdir,since the method signature
+ * is different for the non-POSIX MinGW
+ */
+
+#ifdef MINGW
+#include <io.h>
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#if defined MINGW
+#define MKDIR(x) mkdir(x)
+#else
+#define MKDIR(x) mkdir(x, S_IRWXU | S_IRWXG | S_IRWXO)
+#endif
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
new file mode 100644
index 0000000..2a8ab67
--- /dev/null
+++ b/compiler/cpp/src/thriftl.ll
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+/**
+ * Thrift scanner.
+ *
+ * Tokenizes a thrift definition file.
+ */
+
+%{
+
+#include <string>
+#include <errno.h>
+
+#include "main.h"
+#include "globals.h"
+#include "parse/t_program.h"
+
+/**
+ * Must be included AFTER parse/t_program.h, but I can't remember why anymore
+ * because I wrote this a while ago.
+ */
+#include "thrifty.h"
+
+void thrift_reserved_keyword(char* keyword) {
+  yyerror("Cannot use reserved language keyword: \"%s\"\n", keyword);
+  exit(1);
+}
+
+void integer_overflow(char* text) {
+  yyerror("This integer is too big: \"%s\"\n", text);
+  exit(1);
+}
+
+%}
+
+/**
+ * Provides the yylineno global, useful for debugging output
+ */
+%option lex-compat
+
+/**
+ * Helper definitions, comments, constants, and whatnot
+ */
+
+intconstant   ([+-]?[0-9]+)
+hexconstant   ("0x"[0-9A-Fa-f]+)
+dubconstant   ([+-]?[0-9]*(\.[0-9]+)?([eE][+-]?[0-9]+)?)
+identifier    ([a-zA-Z_][\.a-zA-Z_0-9]*)
+whitespace    ([ \t\r\n]*)
+sillycomm     ("/*""*"*"*/")
+multicomm     ("/*"[^*]"/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
+doctext       ("/**"([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
+comment       ("//"[^\n]*)
+unixcomment   ("#"[^\n]*)
+symbol        ([:;\,\{\}\(\)\=<>\[\]])
+st_identifier ([a-zA-Z-][\.a-zA-Z_0-9-]*)
+literal_begin (['\"])
+
+%%
+
+{whitespace}         { /* do nothing */                 }
+{sillycomm}          { /* do nothing */                 }
+{multicomm}          { /* do nothing */                 }
+{comment}            { /* do nothing */                 }
+{unixcomment}        { /* do nothing */                 }
+
+{symbol}             { return yytext[0];                }
+
+"namespace"          { return tok_namespace;            }
+"cpp_namespace"      { return tok_cpp_namespace;        }
+"cpp_include"        { return tok_cpp_include;          }
+"cpp_type"           { return tok_cpp_type;             }
+"java_package"       { return tok_java_package;         }
+"cocoa_prefix"       { return tok_cocoa_prefix;         }
+"csharp_namespace"   { return tok_csharp_namespace;     }
+"php_namespace"      { return tok_php_namespace;        }
+"py_module"          { return tok_py_module;            }
+"perl_package"       { return tok_perl_package;         }
+"ruby_namespace"     { return tok_ruby_namespace;       }
+"smalltalk_category" { return tok_smalltalk_category;   }
+"smalltalk_prefix"   { return tok_smalltalk_prefix;     }
+"xsd_all"            { return tok_xsd_all;              }
+"xsd_optional"       { return tok_xsd_optional;         }
+"xsd_nillable"       { return tok_xsd_nillable;         }
+"xsd_namespace"      { return tok_xsd_namespace;        }
+"xsd_attrs"          { return tok_xsd_attrs;            }
+"include"            { return tok_include;              }
+"void"               { return tok_void;                 }
+"bool"               { return tok_bool;                 }
+"byte"               { return tok_byte;                 }
+"i16"                { return tok_i16;                  }
+"i32"                { return tok_i32;                  }
+"i64"                { return tok_i64;                  }
+"double"             { return tok_double;               }
+"string"             { return tok_string;               }
+"binary"             { return tok_binary;               }
+"slist"              { return tok_slist;                }
+"senum"              { return tok_senum;                }
+"map"                { return tok_map;                  }
+"list"               { return tok_list;                 }
+"set"                { return tok_set;                  }
+"oneway"             { return tok_oneway;               }
+"typedef"            { return tok_typedef;              }
+"struct"             { return tok_struct;               }
+"exception"          { return tok_xception;             }
+"extends"            { return tok_extends;              }
+"throws"             { return tok_throws;               }
+"service"            { return tok_service;              }
+"enum"               { return tok_enum;                 }
+"const"              { return tok_const;                }
+"required"           { return tok_required;             }
+"optional"           { return tok_optional;             }
+"async" {
+  pwarning(0, "\"async\" is deprecated.  It is called \"oneway\" now.\n");
+  return tok_oneway;
+}
+
+
+"abstract"           { thrift_reserved_keyword(yytext); }
+"and"                { thrift_reserved_keyword(yytext); }
+"args"               { thrift_reserved_keyword(yytext); }
+"as"                 { thrift_reserved_keyword(yytext); }
+"assert"             { thrift_reserved_keyword(yytext); }
+"break"              { thrift_reserved_keyword(yytext); }
+"case"               { thrift_reserved_keyword(yytext); }
+"class"              { thrift_reserved_keyword(yytext); }
+"continue"           { thrift_reserved_keyword(yytext); }
+"declare"            { thrift_reserved_keyword(yytext); }
+"def"                { thrift_reserved_keyword(yytext); }
+"default"            { thrift_reserved_keyword(yytext); }
+"del"                { thrift_reserved_keyword(yytext); }
+"delete"             { thrift_reserved_keyword(yytext); }
+"do"                 { thrift_reserved_keyword(yytext); }
+"elif"               { thrift_reserved_keyword(yytext); }
+"else"               { thrift_reserved_keyword(yytext); }
+"elseif"             { thrift_reserved_keyword(yytext); }
+"except"             { thrift_reserved_keyword(yytext); }
+"exec"               { thrift_reserved_keyword(yytext); }
+"false"              { thrift_reserved_keyword(yytext); }
+"finally"            { thrift_reserved_keyword(yytext); }
+"float"              { thrift_reserved_keyword(yytext); }
+"for"                { thrift_reserved_keyword(yytext); }
+"foreach"            { thrift_reserved_keyword(yytext); }
+"function"           { thrift_reserved_keyword(yytext); }
+"global"             { thrift_reserved_keyword(yytext); }
+"goto"               { thrift_reserved_keyword(yytext); }
+"if"                 { thrift_reserved_keyword(yytext); }
+"implements"         { thrift_reserved_keyword(yytext); }
+"import"             { thrift_reserved_keyword(yytext); }
+"in"                 { thrift_reserved_keyword(yytext); }
+"inline"             { thrift_reserved_keyword(yytext); }
+"instanceof"         { thrift_reserved_keyword(yytext); }
+"interface"          { thrift_reserved_keyword(yytext); }
+"is"                 { thrift_reserved_keyword(yytext); }
+"lambda"             { thrift_reserved_keyword(yytext); }
+"native"             { thrift_reserved_keyword(yytext); }
+"new"                { thrift_reserved_keyword(yytext); }
+"not"                { thrift_reserved_keyword(yytext); }
+"or"                 { thrift_reserved_keyword(yytext); }
+"pass"               { thrift_reserved_keyword(yytext); }
+"public"             { thrift_reserved_keyword(yytext); }
+"print"              { thrift_reserved_keyword(yytext); }
+"private"            { thrift_reserved_keyword(yytext); }
+"protected"          { thrift_reserved_keyword(yytext); }
+"raise"              { thrift_reserved_keyword(yytext); }
+"return"             { thrift_reserved_keyword(yytext); }
+"sizeof"             { thrift_reserved_keyword(yytext); }
+"static"             { thrift_reserved_keyword(yytext); }
+"switch"             { thrift_reserved_keyword(yytext); }
+"synchronized"       { thrift_reserved_keyword(yytext); }
+"this"               { thrift_reserved_keyword(yytext); }
+"throw"              { thrift_reserved_keyword(yytext); }
+"transient"          { thrift_reserved_keyword(yytext); }
+"true"               { thrift_reserved_keyword(yytext); }
+"try"                { thrift_reserved_keyword(yytext); }
+"unsigned"           { thrift_reserved_keyword(yytext); }
+"var"                { thrift_reserved_keyword(yytext); }
+"virtual"            { thrift_reserved_keyword(yytext); }
+"volatile"           { thrift_reserved_keyword(yytext); }
+"while"              { thrift_reserved_keyword(yytext); }
+"with"               { thrift_reserved_keyword(yytext); }
+"union"              { thrift_reserved_keyword(yytext); }
+"yield"              { thrift_reserved_keyword(yytext); }
+
+{intconstant} {
+  errno = 0;
+  yylval.iconst = strtoll(yytext, NULL, 10);
+  if (errno == ERANGE) {
+    integer_overflow(yytext);
+  }
+  return tok_int_constant;
+}
+
+{hexconstant} {
+  errno = 0;
+  yylval.iconst = strtoll(yytext+2, NULL, 16);
+  if (errno == ERANGE) {
+    integer_overflow(yytext);
+  }
+  return tok_int_constant;
+}
+
+{dubconstant} {
+  yylval.dconst = atof(yytext);
+  return tok_dub_constant;
+}
+
+{identifier} {
+  yylval.id = strdup(yytext);
+  return tok_identifier;
+}
+
+{st_identifier} {
+  yylval.id = strdup(yytext);
+  return tok_st_identifier;
+}
+
+{literal_begin} {
+  char mark = yytext[0];
+  std::string result;
+  for(;;)
+  {
+    int ch = yyinput();
+    switch (ch) {
+      case EOF:
+        yyerror("End of file while read string at %d\n", yylineno);
+        exit(1);
+      case '\n':
+        yyerror("End of line while read string at %d\n", yylineno - 1);
+        exit(1);
+      case '\\':
+        ch = yyinput();
+        switch (ch) {
+          case 'r':
+            result.push_back('\r');
+            continue;
+          case 'n':
+            result.push_back('\n');
+            continue;
+          case 't':
+            result.push_back('\t');
+            continue;
+          case '"':
+            result.push_back('"');
+            continue;
+          case '\'':
+            result.push_back('\'');
+            continue;
+          case '\\':
+            result.push_back('\\');
+            continue;
+          default:
+            yyerror("Bad escape character\n");
+            return -1;
+        }
+        break;
+      default:
+        if (ch == mark) {
+          yylval.id = strdup(result.c_str());
+          return tok_literal;
+        } else {
+          result.push_back(ch);
+        }
+    }
+  }
+}
+
+
+{doctext} {
+ /* This does not show up in the parse tree. */
+ /* Rather, the parser will grab it out of the global. */
+  if (g_parse_mode == PROGRAM) {
+    clear_doctext();
+    g_doctext = strdup(yytext + 3);
+    g_doctext[strlen(g_doctext) - 2] = '\0';
+    g_doctext = clean_up_doctext(g_doctext);
+    g_doctext_lineno = yylineno;
+  }
+}
+
+
+%%
+
+/* vim: filetype=lex
+*/
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
new file mode 100644
index 0000000..bf5408e
--- /dev/null
+++ b/compiler/cpp/src/thrifty.yy
@@ -0,0 +1,1127 @@
+%{
+/*
+ * 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.
+ */
+
+/**
+ * Thrift parser.
+ *
+ * This parser is used on a thrift definition file.
+ *
+ */
+
+#define __STDC_LIMIT_MACROS
+#define __STDC_FORMAT_MACROS
+#include <stdio.h>
+#include <inttypes.h>
+#include <limits.h>
+#include "main.h"
+#include "globals.h"
+#include "parse/t_program.h"
+#include "parse/t_scope.h"
+
+/**
+ * This global variable is used for automatic numbering of field indices etc.
+ * when parsing the members of a struct. Field values are automatically
+ * assigned starting from -1 and working their way down.
+ */
+int y_field_val = -1;
+int g_arglist = 0;
+
+%}
+
+/**
+ * This structure is used by the parser to hold the data types associated with
+ * various parse nodes.
+ */
+%union {
+  char*          id;
+  int64_t        iconst;
+  double         dconst;
+  bool           tbool;
+  t_doc*         tdoc;
+  t_type*        ttype;
+  t_base_type*   tbase;
+  t_typedef*     ttypedef;
+  t_enum*        tenum;
+  t_enum_value*  tenumv;
+  t_const*       tconst;
+  t_const_value* tconstv;
+  t_struct*      tstruct;
+  t_service*     tservice;
+  t_function*    tfunction;
+  t_field*       tfield;
+  char*          dtext;
+  t_field::e_req ereq;
+  t_annotation*  tannot;
+}
+
+/**
+ * Strings identifier
+ */
+%token<id>     tok_identifier
+%token<id>     tok_literal
+%token<dtext>  tok_doctext
+%token<id>     tok_st_identifier
+
+/**
+ * Constant values
+ */
+%token<iconst> tok_int_constant
+%token<dconst> tok_dub_constant
+
+/**
+ * Header keywords
+ */
+%token tok_include
+%token tok_namespace
+%token tok_cpp_namespace
+%token tok_cpp_include
+%token tok_cpp_type
+%token tok_php_namespace
+%token tok_py_module
+%token tok_perl_package
+%token tok_java_package
+%token tok_xsd_all
+%token tok_xsd_optional
+%token tok_xsd_nillable
+%token tok_xsd_namespace
+%token tok_xsd_attrs
+%token tok_ruby_namespace
+%token tok_smalltalk_category
+%token tok_smalltalk_prefix
+%token tok_cocoa_prefix
+%token tok_csharp_namespace
+
+/**
+ * Base datatype keywords
+ */
+%token tok_void
+%token tok_bool
+%token tok_byte
+%token tok_string
+%token tok_binary
+%token tok_slist
+%token tok_senum
+%token tok_i16
+%token tok_i32
+%token tok_i64
+%token tok_double
+
+/**
+ * Complex type keywords
+ */
+%token tok_map
+%token tok_list
+%token tok_set
+
+/**
+ * Function modifiers
+ */
+%token tok_oneway
+
+/**
+ * Thrift language keywords
+ */
+%token tok_typedef
+%token tok_struct
+%token tok_xception
+%token tok_throws
+%token tok_extends
+%token tok_service
+%token tok_enum
+%token tok_const
+%token tok_required
+%token tok_optional
+
+/**
+ * Grammar nodes
+ */
+
+%type<ttype>     BaseType
+%type<ttype>     ContainerType
+%type<ttype>     SimpleContainerType
+%type<ttype>     MapType
+%type<ttype>     SetType
+%type<ttype>     ListType
+
+%type<tdoc>      Definition
+%type<ttype>     TypeDefinition
+
+%type<ttypedef>  Typedef
+%type<ttype>     DefinitionType
+
+%type<ttype>     TypeAnnotations
+%type<ttype>     TypeAnnotationList
+%type<tannot>    TypeAnnotation
+
+%type<tfield>    Field
+%type<iconst>    FieldIdentifier
+%type<ereq>      FieldRequiredness
+%type<ttype>     FieldType
+%type<tconstv>   FieldValue
+%type<tstruct>   FieldList
+
+%type<tenum>     Enum
+%type<tenum>     EnumDefList
+%type<tenumv>    EnumDef
+
+%type<ttypedef>  Senum
+%type<tbase>     SenumDefList
+%type<id>        SenumDef
+
+%type<tconst>    Const
+%type<tconstv>   ConstValue
+%type<tconstv>   ConstList
+%type<tconstv>   ConstListContents
+%type<tconstv>   ConstMap
+%type<tconstv>   ConstMapContents
+
+%type<tstruct>   Struct
+%type<tstruct>   Xception
+%type<tservice>  Service
+
+%type<tfunction> Function
+%type<ttype>     FunctionType
+%type<tservice>  FunctionList
+
+%type<tstruct>   Throws
+%type<tservice>  Extends
+%type<tbool>     Oneway
+%type<tbool>     XsdAll
+%type<tbool>     XsdOptional
+%type<tbool>     XsdNillable
+%type<tstruct>   XsdAttributes
+%type<id>        CppType
+
+%type<dtext>     CaptureDocText
+
+%%
+
+/**
+ * Thrift Grammar Implementation.
+ *
+ * For the most part this source file works its way top down from what you
+ * might expect to find in a typical .thrift file, i.e. type definitions and
+ * namespaces up top followed by service definitions using those types.
+ */
+
+Program:
+  HeaderList DefinitionList
+    {
+      pdebug("Program -> Headers DefinitionList");
+      /*
+      TODO(dreiss): Decide whether full-program doctext is worth the trouble.
+      if ($1 != NULL) {
+        g_program->set_doc($1);
+      }
+      */
+      clear_doctext();
+    }
+
+CaptureDocText:
+    {
+      if (g_parse_mode == PROGRAM) {
+        $$ = g_doctext;
+        g_doctext = NULL;
+      } else {
+        $$ = NULL;
+      }
+    }
+
+/* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */
+DestroyDocText:
+    {
+      if (g_parse_mode == PROGRAM) {
+        clear_doctext();
+      }
+    }
+
+/* We have to DestroyDocText here, otherwise it catches the doctext
+   on the first real element. */
+HeaderList:
+  HeaderList DestroyDocText Header
+    {
+      pdebug("HeaderList -> HeaderList Header");
+    }
+|
+    {
+      pdebug("HeaderList -> ");
+    }
+
+Header:
+  Include
+    {
+      pdebug("Header -> Include");
+    }
+| tok_namespace tok_identifier tok_identifier
+    {
+      pdebug("Header -> tok_namespace tok_identifier tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace($2, $3);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_cpp_namespace tok_identifier
+    {
+      pwarning(1, "'cpp_namespace' is deprecated. Use 'namespace cpp' instead");
+      pdebug("Header -> tok_cpp_namespace tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("cpp", $2);
+      }
+    }
+| tok_cpp_include tok_literal
+    {
+      pdebug("Header -> tok_cpp_include tok_literal");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_cpp_include($2);
+      }
+    }
+| tok_php_namespace tok_identifier
+    {
+      pwarning(1, "'php_namespace' is deprecated. Use 'namespace php' instead");
+      pdebug("Header -> tok_php_namespace tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("php", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_py_module tok_identifier
+    {
+      pwarning(1, "'py_module' is deprecated. Use 'namespace py' instead");
+      pdebug("Header -> tok_py_module tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("py", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_perl_package tok_identifier
+    {
+      pwarning(1, "'perl_package' is deprecated. Use 'namespace perl' instead");
+      pdebug("Header -> tok_perl_namespace tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("perl", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_ruby_namespace tok_identifier
+    {
+      pwarning(1, "'ruby_namespace' is deprecated. Use 'namespace rb' instead");
+      pdebug("Header -> tok_ruby_namespace tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("rb", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_smalltalk_category tok_st_identifier
+    {
+      pwarning(1, "'smalltalk_category' is deprecated. Use 'namespace smalltalk.category' instead");
+      pdebug("Header -> tok_smalltalk_category tok_st_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("smalltalk.category", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_smalltalk_prefix tok_identifier
+    {
+      pwarning(1, "'smalltalk_prefix' is deprecated. Use 'namespace smalltalk.prefix' instead");
+      pdebug("Header -> tok_smalltalk_prefix tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("smalltalk.prefix", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_java_package tok_identifier
+    {
+      pwarning(1, "'java_package' is deprecated. Use 'namespace java' instead");
+      pdebug("Header -> tok_java_package tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("java", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_cocoa_prefix tok_identifier
+    {
+      pwarning(1, "'cocoa_prefix' is deprecated. Use 'namespace cocoa' instead");
+      pdebug("Header -> tok_cocoa_prefix tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("cocoa", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_xsd_namespace tok_literal
+    {
+      pwarning(1, "'xsd_namespace' is deprecated. Use 'namespace xsd' instead");
+      pdebug("Header -> tok_xsd_namespace tok_literal");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("cocoa", $2);
+      }
+    }
+/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
+| tok_csharp_namespace tok_identifier
+   {
+     pwarning(1, "'csharp_namespace' is deprecated. Use 'namespace csharp' instead");
+     pdebug("Header -> tok_csharp_namespace tok_identifier");
+     if (g_parse_mode == PROGRAM) {
+       g_program->set_namespace("csharp", $2);
+     }
+   }
+
+Include:
+  tok_include tok_literal
+    {
+      pdebug("Include -> tok_include tok_literal");
+      if (g_parse_mode == INCLUDES) {
+        std::string path = include_file(std::string($2));
+        if (!path.empty()) {
+          g_program->add_include(path, std::string($2));
+        }
+      }
+    }
+
+DefinitionList:
+  DefinitionList CaptureDocText Definition
+    {
+      pdebug("DefinitionList -> DefinitionList Definition");
+      if ($2 != NULL && $3 != NULL) {
+        $3->set_doc($2);
+      }
+    }
+|
+    {
+      pdebug("DefinitionList -> ");
+    }
+
+Definition:
+  Const
+    {
+      pdebug("Definition -> Const");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_const($1);
+      }
+      $$ = $1;
+    }
+| TypeDefinition
+    {
+      pdebug("Definition -> TypeDefinition");
+      if (g_parse_mode == PROGRAM) {
+        g_scope->add_type($1->get_name(), $1);
+        if (g_parent_scope != NULL) {
+          g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1);
+        }
+      }
+      $$ = $1;
+    }
+| Service
+    {
+      pdebug("Definition -> Service");
+      if (g_parse_mode == PROGRAM) {
+        g_scope->add_service($1->get_name(), $1);
+        if (g_parent_scope != NULL) {
+          g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1);
+        }
+        g_program->add_service($1);
+      }
+      $$ = $1;
+    }
+
+TypeDefinition:
+  Typedef
+    {
+      pdebug("TypeDefinition -> Typedef");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_typedef($1);
+      }
+    }
+| Enum
+    {
+      pdebug("TypeDefinition -> Enum");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_enum($1);
+      }
+    }
+| Senum
+    {
+      pdebug("TypeDefinition -> Senum");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_typedef($1);
+      }
+    }
+| Struct
+    {
+      pdebug("TypeDefinition -> Struct");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_struct($1);
+      }
+    }
+| Xception
+    {
+      pdebug("TypeDefinition -> Xception");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_xception($1);
+      }
+    }
+
+Typedef:
+  tok_typedef DefinitionType tok_identifier
+    {
+      pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");
+      t_typedef *td = new t_typedef(g_program, $2, $3);
+      $$ = td;
+    }
+
+CommaOrSemicolonOptional:
+  ','
+    {}
+| ';'
+    {}
+|
+    {}
+
+Enum:
+  tok_enum tok_identifier '{' EnumDefList '}'
+    {
+      pdebug("Enum -> tok_enum tok_identifier { EnumDefList }");
+      $$ = $4;
+      $$->set_name($2);
+    }
+
+EnumDefList:
+  EnumDefList EnumDef
+    {
+      pdebug("EnumDefList -> EnumDefList EnumDef");
+      $$ = $1;
+      $$->append($2);
+    }
+|
+    {
+      pdebug("EnumDefList -> ");
+      $$ = new t_enum(g_program);
+    }
+
+EnumDef:
+  CaptureDocText tok_identifier '=' tok_int_constant CommaOrSemicolonOptional
+    {
+      pdebug("EnumDef -> tok_identifier = tok_int_constant");
+      if ($4 < 0) {
+        pwarning(1, "Negative value supplied for enum %s.\n", $2);
+      }
+      if ($4 > INT_MAX) {
+        pwarning(1, "64-bit value supplied for enum %s.\n", $2);
+      }
+      $$ = new t_enum_value($2, $4);
+      if ($1 != NULL) {
+        $$->set_doc($1);
+      }
+      if (g_parse_mode == PROGRAM) {
+        g_scope->add_constant($2, new t_const(g_type_i32, $2, new t_const_value($4)));
+        if (g_parent_scope != NULL) {
+          g_parent_scope->add_constant(g_parent_prefix + $2, new t_const(g_type_i32, $2, new t_const_value($4)));
+        }
+      }
+    }
+|
+  CaptureDocText tok_identifier CommaOrSemicolonOptional
+    {
+      pdebug("EnumDef -> tok_identifier");
+      $$ = new t_enum_value($2);
+      if ($1 != NULL) {
+        $$->set_doc($1);
+      }
+    }
+
+Senum:
+  tok_senum tok_identifier '{' SenumDefList '}'
+    {
+      pdebug("Senum -> tok_senum tok_identifier { SenumDefList }");
+      $$ = new t_typedef(g_program, $4, $2);
+    }
+
+SenumDefList:
+  SenumDefList SenumDef
+    {
+      pdebug("SenumDefList -> SenumDefList SenumDef");
+      $$ = $1;
+      $$->add_string_enum_val($2);
+    }
+|
+    {
+      pdebug("SenumDefList -> ");
+      $$ = new t_base_type("string", t_base_type::TYPE_STRING);
+      $$->set_string_enum(true);
+    }
+
+SenumDef:
+  tok_literal CommaOrSemicolonOptional
+    {
+      pdebug("SenumDef -> tok_literal");
+      $$ = $1;
+    }
+
+Const:
+  tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional
+    {
+      pdebug("Const -> tok_const FieldType tok_identifier = ConstValue");
+      if (g_parse_mode == PROGRAM) {
+        $$ = new t_const($2, $3, $5);
+        validate_const_type($$);
+
+        g_scope->add_constant($3, $$);
+        if (g_parent_scope != NULL) {
+          g_parent_scope->add_constant(g_parent_prefix + $3, $$);
+        }
+
+      } else {
+        $$ = NULL;
+      }
+    }
+
+ConstValue:
+  tok_int_constant
+    {
+      pdebug("ConstValue => tok_int_constant");
+      $$ = new t_const_value();
+      $$->set_integer($1);
+      if ($1 < INT32_MIN || $1 > INT32_MAX) {
+        pwarning(1, "64-bit constant \"%"PRIi64"\" may not work in all languages.\n", $1);
+      }
+    }
+| tok_dub_constant
+    {
+      pdebug("ConstValue => tok_dub_constant");
+      $$ = new t_const_value();
+      $$->set_double($1);
+    }
+| tok_literal
+    {
+      pdebug("ConstValue => tok_literal");
+      $$ = new t_const_value($1);
+    }
+| tok_identifier
+    {
+      pdebug("ConstValue => tok_identifier");
+      t_const* constant = g_scope->get_constant($1);
+      if (constant != NULL) {
+        $$ = constant->get_value();
+      } else {
+        if (g_parse_mode == PROGRAM) {
+          pwarning(1, "Constant strings should be quoted: %s\n", $1);
+        }
+        $$ = new t_const_value($1);
+      }
+    }
+| ConstList
+    {
+      pdebug("ConstValue => ConstList");
+      $$ = $1;
+    }
+| ConstMap
+    {
+      pdebug("ConstValue => ConstMap");
+      $$ = $1;
+    }
+
+ConstList:
+  '[' ConstListContents ']'
+    {
+      pdebug("ConstList => [ ConstListContents ]");
+      $$ = $2;
+    }
+
+ConstListContents:
+  ConstListContents ConstValue CommaOrSemicolonOptional
+    {
+      pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional");
+      $$ = $1;
+      $$->add_list($2);
+    }
+|
+    {
+      pdebug("ConstListContents =>");
+      $$ = new t_const_value();
+      $$->set_list();
+    }
+
+ConstMap:
+  '{' ConstMapContents '}'
+    {
+      pdebug("ConstMap => { ConstMapContents }");
+      $$ = $2;
+    }
+
+ConstMapContents:
+  ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional
+    {
+      pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional");
+      $$ = $1;
+      $$->add_map($2, $4);
+    }
+|
+    {
+      pdebug("ConstMapContents =>");
+      $$ = new t_const_value();
+      $$->set_map();
+    }
+
+Struct:
+  tok_struct tok_identifier XsdAll '{' FieldList '}' TypeAnnotations
+    {
+      pdebug("Struct -> tok_struct tok_identifier { FieldList }");
+      $5->set_xsd_all($3);
+      $$ = $5;
+      $$->set_name($2);
+      if ($7 != NULL) {
+        $$->annotations_ = $7->annotations_;
+        delete $7;
+      }
+    }
+
+XsdAll:
+  tok_xsd_all
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
+XsdOptional:
+  tok_xsd_optional
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
+XsdNillable:
+  tok_xsd_nillable
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
+XsdAttributes:
+  tok_xsd_attrs '{' FieldList '}'
+    {
+      $$ = $3;
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+Xception:
+  tok_xception tok_identifier '{' FieldList '}'
+    {
+      pdebug("Xception -> tok_xception tok_identifier { FieldList }");
+      $4->set_name($2);
+      $4->set_xception(true);
+      $$ = $4;
+    }
+
+Service:
+  tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}'
+    {
+      pdebug("Service -> tok_service tok_identifier { FunctionList }");
+      $$ = $6;
+      $$->set_name($2);
+      $$->set_extends($3);
+    }
+
+FlagArgs:
+    {
+       g_arglist = 1;
+    }
+
+UnflagArgs:
+    {
+       g_arglist = 0;
+    }
+
+Extends:
+  tok_extends tok_identifier
+    {
+      pdebug("Extends -> tok_extends tok_identifier");
+      $$ = NULL;
+      if (g_parse_mode == PROGRAM) {
+        $$ = g_scope->get_service($2);
+        if ($$ == NULL) {
+          yyerror("Service \"%s\" has not been defined.", $2);
+          exit(1);
+        }
+      }
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+FunctionList:
+  FunctionList Function
+    {
+      pdebug("FunctionList -> FunctionList Function");
+      $$ = $1;
+      $1->add_function($2);
+    }
+|
+    {
+      pdebug("FunctionList -> ");
+      $$ = new t_service(g_program);
+    }
+
+Function:
+  CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws CommaOrSemicolonOptional
+    {
+      $6->set_name(std::string($4) + "_args");
+      $$ = new t_function($3, $4, $6, $8, $2);
+      if ($1 != NULL) {
+        $$->set_doc($1);
+      }
+    }
+
+Oneway:
+  tok_oneway
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
+Throws:
+  tok_throws '(' FieldList ')'
+    {
+      pdebug("Throws -> tok_throws ( FieldList )");
+      $$ = $3;
+      if (g_parse_mode == PROGRAM && !validate_throws($$)) {
+        yyerror("Throws clause may not contain non-exception types");
+        exit(1);
+      }
+    }
+|
+    {
+      $$ = new t_struct(g_program);
+    }
+
+FieldList:
+  FieldList Field
+    {
+      pdebug("FieldList -> FieldList , Field");
+      $$ = $1;
+      if (!($$->append($2))) {
+        yyerror("Field identifier %d for \"%s\" has already been used", $2->get_key(), $2->get_name().c_str());
+        exit(1);
+      }
+    }
+|
+    {
+      pdebug("FieldList -> ");
+      y_field_val = -1;
+      $$ = new t_struct(g_program);
+    }
+
+Field:
+  CaptureDocText FieldIdentifier FieldRequiredness FieldType tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes CommaOrSemicolonOptional
+    {
+      pdebug("tok_int_constant : Field -> FieldType tok_identifier");
+      if ($2 < 0) {
+        pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $5);
+        if (g_strict >= 192) {
+          yyerror("Implicit field keys are deprecated and not allowed with -strict");
+          exit(1);
+        }
+      }
+      $$ = new t_field($4, $5, $2);
+      $$->set_req($3);
+      if ($6 != NULL) {
+        validate_field_value($$, $6);
+        $$->set_value($6);
+      }
+      $$->set_xsd_optional($7);
+      $$->set_xsd_nillable($8);
+      if ($1 != NULL) {
+        $$->set_doc($1);
+      }
+      if ($9 != NULL) {
+        $$->set_xsd_attrs($9);
+      }
+    }
+
+FieldIdentifier:
+  tok_int_constant ':'
+    {
+      if ($1 <= 0) {
+        pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", $1);
+        $1 = y_field_val--;
+      }
+      $$ = $1;
+    }
+|
+    {
+      $$ = y_field_val--;
+    }
+
+FieldRequiredness:
+  tok_required
+    {
+      if (g_arglist) {
+        if (g_parse_mode == PROGRAM) {
+          pwarning(1, "required keyword is ignored in argument lists.\n");
+        }
+        $$ = t_field::T_OPT_IN_REQ_OUT;
+      } else {
+        $$ = t_field::T_REQUIRED;
+      }
+    }
+| tok_optional
+    {
+      if (g_arglist) {
+        if (g_parse_mode == PROGRAM) {
+          pwarning(1, "optional keyword is ignored in argument lists.\n");
+        }
+        $$ = t_field::T_OPT_IN_REQ_OUT;
+      } else {
+        $$ = t_field::T_OPTIONAL;
+      }
+    }
+|
+    {
+      $$ = t_field::T_OPT_IN_REQ_OUT;
+    }
+
+FieldValue:
+  '=' ConstValue
+    {
+      if (g_parse_mode == PROGRAM) {
+        $$ = $2;
+      } else {
+        $$ = NULL;
+      }
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+DefinitionType:
+  BaseType
+    {
+      pdebug("DefinitionType -> BaseType");
+      $$ = $1;
+    }
+| ContainerType
+    {
+      pdebug("DefinitionType -> ContainerType");
+      $$ = $1;
+    }
+
+FunctionType:
+  FieldType
+    {
+      pdebug("FunctionType -> FieldType");
+      $$ = $1;
+    }
+| tok_void
+    {
+      pdebug("FunctionType -> tok_void");
+      $$ = g_type_void;
+    }
+
+FieldType:
+  tok_identifier
+    {
+      pdebug("FieldType -> tok_identifier");
+      if (g_parse_mode == INCLUDES) {
+        // Ignore identifiers in include mode
+        $$ = NULL;
+      } else {
+        // Lookup the identifier in the current scope
+        $$ = g_scope->get_type($1);
+        if ($$ == NULL) {
+          yyerror("Type \"%s\" has not been defined.", $1);
+          exit(1);
+        }
+      }
+    }
+| BaseType
+    {
+      pdebug("FieldType -> BaseType");
+      $$ = $1;
+    }
+| ContainerType
+    {
+      pdebug("FieldType -> ContainerType");
+      $$ = $1;
+    }
+
+BaseType:
+  tok_string
+    {
+      pdebug("BaseType -> tok_string");
+      $$ = g_type_string;
+    }
+| tok_binary
+    {
+      pdebug("BaseType -> tok_binary");
+      $$ = g_type_binary;
+    }
+| tok_slist
+    {
+      pdebug("BaseType -> tok_slist");
+      $$ = g_type_slist;
+    }
+| tok_bool
+    {
+      pdebug("BaseType -> tok_bool");
+      $$ = g_type_bool;
+    }
+| tok_byte
+    {
+      pdebug("BaseType -> tok_byte");
+      $$ = g_type_byte;
+    }
+| tok_i16
+    {
+      pdebug("BaseType -> tok_i16");
+      $$ = g_type_i16;
+    }
+| tok_i32
+    {
+      pdebug("BaseType -> tok_i32");
+      $$ = g_type_i32;
+    }
+| tok_i64
+    {
+      pdebug("BaseType -> tok_i64");
+      $$ = g_type_i64;
+    }
+| tok_double
+    {
+      pdebug("BaseType -> tok_double");
+      $$ = g_type_double;
+    }
+
+ContainerType: SimpleContainerType TypeAnnotations
+    {
+      pdebug("ContainerType -> SimpleContainerType TypeAnnotations");
+      $$ = $1;
+      if ($2 != NULL) {
+        $$->annotations_ = $2->annotations_;
+        delete $2;
+      }
+    }
+
+SimpleContainerType:
+  MapType
+    {
+      pdebug("SimpleContainerType -> MapType");
+      $$ = $1;
+    }
+| SetType
+    {
+      pdebug("SimpleContainerType -> SetType");
+      $$ = $1;
+    }
+| ListType
+    {
+      pdebug("SimpleContainerType -> ListType");
+      $$ = $1;
+    }
+
+MapType:
+  tok_map CppType '<' FieldType ',' FieldType '>'
+    {
+      pdebug("MapType -> tok_map <FieldType, FieldType>");
+      $$ = new t_map($4, $6);
+      if ($2 != NULL) {
+        ((t_container*)$$)->set_cpp_name(std::string($2));
+      }
+    }
+
+SetType:
+  tok_set CppType '<' FieldType '>'
+    {
+      pdebug("SetType -> tok_set<FieldType>");
+      $$ = new t_set($4);
+      if ($2 != NULL) {
+        ((t_container*)$$)->set_cpp_name(std::string($2));
+      }
+    }
+
+ListType:
+  tok_list '<' FieldType '>' CppType
+    {
+      pdebug("ListType -> tok_list<FieldType>");
+      $$ = new t_list($3);
+      if ($5 != NULL) {
+        ((t_container*)$$)->set_cpp_name(std::string($5));
+      }
+    }
+
+CppType:
+  tok_cpp_type tok_literal
+    {
+      $$ = $2;
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+TypeAnnotations:
+  '(' TypeAnnotationList ')'
+    {
+      pdebug("TypeAnnotations -> ( TypeAnnotationList )");
+      $$ = $2;
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+TypeAnnotationList:
+  TypeAnnotationList TypeAnnotation
+    {
+      pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation");
+      $$ = $1;
+      $$->annotations_[$2->key] = $2->val;
+      delete $2;
+    }
+|
+    {
+      /* Just use a dummy structure to hold the annotations. */
+      $$ = new t_struct(g_program);
+    }
+
+TypeAnnotation:
+  tok_identifier '=' tok_literal CommaOrSemicolonOptional
+    {
+      pdebug("TypeAnnotation -> tok_identifier = tok_literal");
+      $$ = new t_annotation;
+      $$->key = $1;
+      $$->val = $3;
+    }
+
+%%