Merging in some Smalltalk changes from Patrick Collison

Reviewed By: mcslee

Test Plan: Rebuild Thrift compiler


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665361 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_st_generator.cc b/compiler/cpp/src/generate/t_st_generator.cc
index 0ac02d4..62a3e5b 100644
--- a/compiler/cpp/src/generate/t_st_generator.cc
+++ b/compiler/cpp/src/generate/t_st_generator.cc
@@ -74,10 +74,14 @@
 
 void t_st_generator::close_generator() {
   generate_force_consts();
-
   f_.close();
 }
 
+string t_st_generator::generated_category() {
+  string cat = program_->get_smalltalk_category();
+  return cat.size() ? cat : "Generated-" + class_name();
+}
+
 /**
  * Generates a typedef. This is not done in Smalltalk, types are all implicit.
  *
@@ -91,7 +95,7 @@
   out << indent() << "instanceVariableNames: ''" << endl <<
     indent() << "classVariableNames: ''" << endl <<
     indent() << "poolDictionaries: ''" << endl <<
-    indent() << "category: 'Thrift-Generated-" << class_name() << "'!" << endl << endl;
+    indent() << "category: '" << generated_category() << "'!" << endl << endl;
 }
 
 void t_st_generator::st_method(std::ofstream &out, string cls, string name) {
@@ -346,7 +350,7 @@
   out << "'\n" <<
     "\tclassVariableNames: ''\n" <<
     "\tpoolDictionaries: ''\n" <<
-    "\tcategory: 'Thrift-Generated-" << class_name() << "'!\n\n";
+    "\tcategory: '" << generated_category() << "'!\n\n";
 
   generate_accessors(out, tstruct);
 }
@@ -378,8 +382,10 @@
 
   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()));
+      st_accessors(out,
+                   capitalize(type_name(tstruct)),
+                   sanitize((*m_iter)->get_name()),
+                   a_type((*m_iter)->get_type()));
     }
     out << endl;
   }
@@ -547,14 +553,14 @@
   indent_up();
 
   for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-		bool optional = (*fld_iter)->get_req() == t_field::OPTIONAL;
+    bool optional = (*fld_iter)->get_req() == t_field::OPTIONAL;
     string fname = (*fld_iter)->get_name();
-		string accessor = sname + " " + sanitize(fname);
+    string accessor = sname + " " + sanitize(fname);
 
-		if (optional) {
-			out << indent() << accessor << " ifNotNil: [" << endl;
-			indent_up();
-		}
+    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()) <<
@@ -563,15 +569,15 @@
     out << indent() << write_val((*fld_iter)->get_type(), accessor) << "." << endl <<
       indent() << "oprot writeFieldEnd";
 
-		if(optional) {
-			out << "]";
-			indent_down();
-		}
+    if (optional) {
+      out << "]";
+      indent_down();
+    }
 
-		out << "." << endl;
+    out << "." << endl;
   }
 
-	out << indent() << "oprot writeFieldStop; writeStructEnd] value";
+  out << indent() << "oprot writeFieldStop; writeStructEnd] value";
   indent_down();
 
   return out.str();
@@ -585,8 +591,9 @@
   string desc = temp_name();
   string found = temp_name();
 
-  if(clsName.size() == 0)
+  if (clsName.size() == 0) {
     clsName = tstruct->get_name();
+  }
 
   out << "[|" << desc << " " << val << "|" << endl;
   indent_up();
@@ -606,48 +613,48 @@
 
     out << indent() << found << " := true." << endl <<
       indent() << val << " " << sanitize((*fld_iter)->get_name()) << ": " <<
-        read_val((*fld_iter)->get_type());
+      read_val((*fld_iter)->get_type());
     indent_down();
 
-		out << "]." << endl;
+    out << "]." << endl;
   }
 
   out << indent() << found << " ifNil: [iprot skip: " << desc << " type]]." << endl;
   indent_down();
 
   out << indent() << "oprot readStructEnd." << endl <<
-		indent() << val << "] value";
+    indent() << val << "] value";
   indent_down();
 
   return out.str();
 }
 
 string t_st_generator::write_val(t_type *t, string fname) {
-	t = get_true_type(t);
+  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()) {
+  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()) {
+  } else if (t->is_struct() || t->is_xception()) {
     return struct_writer((t_struct*) t, fname);
-  } else if(t->is_list()) {
+  } else if (t->is_list()) {
     return list_writer((t_list*) t, fname);
-  } else if(t->is_set()) {
+  } else if (t->is_set()) {
     return set_writer((t_set*) t, fname);
-  } else if(t->is_enum()) {
+  } else if (t->is_enum()) {
     return "iprot writeI32: " + fname;
   } else {
     throw "Sorry, I don't know how to write this: " + type_name(t);
@@ -655,19 +662,19 @@
 }
 
 string t_st_generator::read_val(t_type *t) {
-	t = get_true_type(t);
+  t = get_true_type(t);
 
-  if(t->is_base_type()) {
+  if (t->is_base_type()) {
     return "iprot read" + capitalize(type_name(t));
-  } else if(t->is_map()) {
+  } else if (t->is_map()) {
     return map_reader((t_map*) t);
-  } else if(t->is_struct() || t->is_xception()) {
+  } else if (t->is_struct() || t->is_xception()) {
     return struct_reader((t_struct*) t);
-  } else if(t->is_list()) {
+  } else if (t->is_list()) {
     return list_reader((t_list*) t);
-  } else if(t->is_set()) {
+  } else if (t->is_set()) {
     return set_reader((t_set*) t);
-  } else if(t->is_enum()) {
+  } else if (t->is_enum()) {
     return "iprot readI32";
   } else {
     throw "Sorry, I don't know how to read this: " + type_name(t);
@@ -744,21 +751,22 @@
 }
 
 string t_st_generator::function_types_comment(t_function* fn) {
-	std::ostringstream out;
+  std::ostringstream out;
   const vector<t_field*>& fields = fn->get_arglist()->get_members();
   vector<t_field*>::const_iterator f_iter;
 
-	out << "\"";
+  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 << (*f_iter)->get_name() << ": " << type_name((*f_iter)->get_type());
+    if ((f_iter + 1) != fields.end()) {
+      out << ", ";
+    }
+  }
 
-	out << "\"";
+  out << "\"";
 
-	return out.str();
+  return out.str();
 }
 
 /**
@@ -781,44 +789,47 @@
     "\tinstanceVariableNames: ''\n" <<
     "\tclassVariableNames: ''\n" <<
     "\tpoolDictionaries: ''\n" <<
-    "\tcategory: 'ThriftGenerated-" << class_name() << "'!\n\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;
+    f_ << function_types_comment(*f_iter) << endl <<
+      indent() << "self send" << capitalize(signature) << "." << endl;
 
-    if(!(*f_iter)->is_async())
+    if (!(*f_iter)->is_async()) {
       f_ << indent() << "^ self recv" << capitalize(funname) << " success " << endl;
+    }
 
     st_close_method(f_);
 
     generate_send_method(*f_iter);
-    if(!(*f_iter)->is_async()) generate_recv_method(*f_iter);
+    if (!(*f_iter)->is_async()) {
+      generate_recv_method(*f_iter);
+    }
   }
 }
 
 string t_st_generator::sanitize(string s) {
-	std::ostringstream out;
-	bool underscore = false;
+  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];
-	}
+  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();
+  return out.str();
 }
 
 /**
@@ -878,7 +889,7 @@
     case t_base_type::TYPE_VOID:
       throw "NO T_VOID CONSTRUCT";
     case t_base_type::TYPE_STRING:
-        return "TType string";
+      return "TType string";
     case t_base_type::TYPE_BOOL:
       return "TType bool";
     case t_base_type::TYPE_BYTE:
diff --git a/compiler/cpp/src/generate/t_st_generator.h b/compiler/cpp/src/generate/t_st_generator.h
index 141555f..6491cbd 100644
--- a/compiler/cpp/src/generate/t_st_generator.h
+++ b/compiler/cpp/src/generate/t_st_generator.h
@@ -111,6 +111,7 @@
 	std::string a_type(t_type* type);
   bool is_vowel(char c);
   std::string temp_name();
+  std::string generated_category();
 
  private:
 
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index 224c9d5..ddc121c 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -192,6 +192,14 @@
     return cocoa_prefix_;
   }
 
+  void set_smalltalk_category(std::string smalltalk_category) {
+    smalltalk_category_ = smalltalk_category;
+  }
+
+  const std::string& get_smalltalk_category() const {
+    return smalltalk_category_;
+  }
+
  private:
 
   // File path
@@ -247,6 +255,8 @@
   // Cocoa/Objective-C naming prefix
   std::string cocoa_prefix_;
 
+  // Smalltalk category
+  std::string smalltalk_category_;
 
 };
 
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
index baaef5c..d371658 100644
--- a/compiler/cpp/src/thriftl.ll
+++ b/compiler/cpp/src/thriftl.ll
@@ -41,139 +41,141 @@
  * 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       ([:;\,\{\}\(\)\=<>\[\]])
-dliteral     ("\""[^"]*"\"")
-sliteral     ("'"[^']*"'")
+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        ([:;\,\{\}\(\)\=<>\[\]])
+dliteral      ("\""[^"]*"\"")
+sliteral      ("'"[^']*"'")
+st_identifier ([a-zA-Z-][\.a-zA-Z_0-9-]*)
 
 
 %%
 
-{whitespace}  { /* do nothing */ }
-{sillycomm}   { /* do nothing */ }
-{multicomm}   { /* do nothing */ }
-{comment}     { /* do nothing */ }
-{unixcomment} { /* do nothing */ }
+{whitespace}         { /* do nothing */                 }
+{sillycomm}          { /* do nothing */                 }
+{multicomm}          { /* do nothing */                 }
+{comment}            { /* do nothing */                 }
+{unixcomment}        { /* do nothing */                 }
 
-{symbol}      { return yytext[0]; }
+{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;   }
-"php_namespace"  { return tok_php_namespace;  }
-"py_module"      { return tok_py_module;      }
-"perl_package"   { return tok_perl_package;   }
-"ruby_namespace" { return tok_ruby_namespace; }
-"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;        }
+"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;         }
+"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;   }
+"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;                  }
+"async"              { return tok_async;                }
+"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;             }
 
-"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;            }
-"async"          { return tok_async;          }
-"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;       }
 
-"abstract" { thrift_reserved_keyword(yytext); }
-"and" { 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); }
-"final" { 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); }
+"abstract"           { thrift_reserved_keyword(yytext); }
+"and"                { 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); }
+"final"              { 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} {
   yylval.iconst = atoi(yytext);
@@ -195,6 +197,11 @@
   return tok_identifier;
 }
 
+{st_identifier} {
+  yylval.id = strdup(yytext);
+  return tok_st_identifier;
+}
+
 {dliteral} {
   yylval.id = strdup(yytext+1);
   yylval.id[strlen(yylval.id)-1] = '\0';
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index cd727c1..5d7cfcc 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -60,6 +60,7 @@
 %token<id>     tok_identifier
 %token<id>     tok_literal
 %token<dtext>  tok_doctext
+%token<id>     tok_st_identifier
 
 /**
  * Constant values
@@ -85,6 +86,7 @@
 %token tok_xsd_namespace
 %token tok_xsd_attrs
 %token tok_ruby_namespace
+%token tok_smalltalk_category
 %token tok_cocoa_prefix
 
 /**
@@ -211,7 +213,7 @@
 CaptureDocText:
     {
       if (g_parse_mode == PROGRAM) {
-        $$ = g_doctext; 
+        $$ = g_doctext;
         g_doctext = NULL;
       } else {
         $$ = NULL;
@@ -293,6 +295,13 @@
         g_program->set_ruby_namespace($2);
       }
     }
+| tok_smalltalk_category tok_st_identifier
+    {
+      pdebug("Header -> tok_smalltalk_category tok_st_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_smalltalk_category($2);
+      }
+    }
 | tok_java_package tok_identifier
     {
       pdebug("Header -> tok_java_package tok_identifier");
@@ -346,7 +355,7 @@
       pdebug("Definition -> Const");
       if (g_parse_mode == PROGRAM) {
         g_program->add_const($1);
-      }    
+      }
       $$ = $1;
     }
 | TypeDefinition
@@ -411,7 +420,7 @@
     }
 
 Typedef:
-  tok_typedef DefinitionType tok_identifier 
+  tok_typedef DefinitionType tok_identifier
     {
       pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");
       t_typedef *td = new t_typedef(g_program, $2, $3);