Allow field elements to be optional in thrift with xsd_optional keyword

Reviewed By: tbr-dave


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664932 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_xsd_generator.cc b/compiler/cpp/src/generate/t_xsd_generator.cc
index 57c9656..5d4cfa2 100644
--- a/compiler/cpp/src/generate/t_xsd_generator.cc
+++ b/compiler/cpp/src/generate/t_xsd_generator.cc
@@ -38,7 +38,7 @@
   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());
+    generate_element(s_xsd_types_, (*m_iter)->get_name(), (*m_iter)->get_type(), (*m_iter)->get_xsd_optional());
   } 
 
   indent_down();
@@ -55,10 +55,13 @@
 
 void t_xsd_generator::generate_element(ostream& out,
                                        string name,
-                                       t_type* ttype) {
+                                       t_type* ttype,
+                                       bool optional) {
+  string soptional = optional ? " minoccurs=\"0\" maxOccurs=\"1\"" : "";
+
   if (ttype->is_void() || ttype->is_list()) {
     indent(out) <<
-      "<xsd:element name=\"" << name << "\">" << endl;
+      "<xsd:element name=\"" << name << "\"" << soptional << ">" << endl;
     indent_up();
     if (ttype->is_void()) {
       indent(out) << 
@@ -87,7 +90,7 @@
       "</xsd:element>" << endl;
   } else {
     indent(out) <<
-      "<xsd:element name=\"" << name << "\" type=\"" << type_name(ttype) << "\" />" << endl;
+      "<xsd:element name=\"" << name << "\"" << soptional << " type=\"" << type_name(ttype) << "\" />" << endl;
   }
 }
 
diff --git a/compiler/cpp/src/generate/t_xsd_generator.h b/compiler/cpp/src/generate/t_xsd_generator.h
index fc39765..35bcf93 100644
--- a/compiler/cpp/src/generate/t_xsd_generator.h
+++ b/compiler/cpp/src/generate/t_xsd_generator.h
@@ -40,7 +40,7 @@
 
  private:
 
-  void generate_element(std::ostream& out, std::string name, t_type* ttype);
+  void generate_element(std::ostream& out, std::string name, t_type* ttype, bool optional=false);
 
   std::string ns(std::string in, std::string ns) {
     return ns + ":" + in;
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 2fbf913..48552e6 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -435,6 +435,7 @@
   g_program = program;
   g_scope = program->scope();
   try {
+    yylineno = 1;
     if (yyparse() != 0) {
       failure("Parser error during include pass.");
     }
@@ -462,6 +463,7 @@
     failure("Could not open input file: \"%s\"", path.c_str());
   }
   pverbose("Parsing %s for types\n", path.c_str());
+  yylineno = 1;
   if (yyparse() != 0) {
     failure("Parser error during types pass.");
   }
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
index 93e14d8..35414ef 100644
--- a/compiler/cpp/src/parse/t_field.h
+++ b/compiler/cpp/src/parse/t_field.h
@@ -14,12 +14,14 @@
   t_field(t_type* type, std::string name) :
     type_(type),
     name_(name),
-    key_(0) {}
+    key_(0),
+    xsd_optional_(false) {}
 
   t_field(t_type* type, std::string name, int32_t key) :
     type_(type),
     name_(name),
-    key_(key) {}
+    key_(key),
+    xsd_optional_(false) {}
 
   ~t_field() {}
 
@@ -35,10 +37,21 @@
     return key_;
   }
 
+  void set_xsd_optional(bool xsd_optional) {
+    xsd_optional_ = xsd_optional;
+  }
+
+  bool get_xsd_optional() const {
+    return xsd_optional_;
+  }
+
  private:
   t_type* type_;
   std::string name_;
   int32_t key_;
+  
+  bool xsd_optional_;
+
 };
 
 #endif
diff --git a/compiler/cpp/src/thrift.l b/compiler/cpp/src/thrift.l
index b7008c6..80cbf87 100644
--- a/compiler/cpp/src/thrift.l
+++ b/compiler/cpp/src/thrift.l
@@ -60,6 +60,7 @@
 "java_package"  { return tok_java_package;  }
 "php_namespace" { return tok_php_namespace; }
 "xsd_all"       { return tok_xsd_all;       }
+"xsd_optional"  { return tok_xsd_optional;  }
 "include"       { return tok_include;       }
 
 "void"          { return tok_void;          }
diff --git a/compiler/cpp/src/thrift.y b/compiler/cpp/src/thrift.y
index fe56dad..d8f3435 100644
--- a/compiler/cpp/src/thrift.y
+++ b/compiler/cpp/src/thrift.y
@@ -67,6 +67,7 @@
 %token tok_php_namespace
 %token tok_java_package
 %token tok_xsd_all
+%token tok_xsd_optional
 
 /**
  * Base datatype keywords
@@ -143,11 +144,12 @@
 %type<ttype>     FunctionType
 %type<tservice>  FunctionList
 
-%type<tstruct>   ThrowsOptional
-%type<tservice>  ExtendsOptional
-%type<tbool>     AsyncOptional
-%type<tbool>     XsdAllOptional
-%type<id>        CppTypeOptional
+%type<tstruct>   Throws
+%type<tservice>  Extends
+%type<tbool>     Async
+%type<tbool>     XsdAll
+%type<tbool>     XsdOptional
+%type<id>        CppType
 
 %%
 
@@ -443,7 +445,7 @@
     }
 
 Struct:
-  tok_struct tok_identifier XsdAllOptional '{' FieldList '}'
+  tok_struct tok_identifier XsdAll '{' FieldList '}'
     {
       pdebug("Struct -> tok_struct tok_identifier { FieldList }");
       $5->set_name($2);
@@ -452,7 +454,7 @@
       y_field_val = -1;
     }
 
-XsdAllOptional:
+XsdAll:
   tok_xsd_all
     {
       $$ = true;
@@ -462,6 +464,16 @@
       $$ = false;
     }
 
+XsdOptional:
+  tok_xsd_optional
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
 Xception:
   tok_xception tok_identifier '{' FieldList '}'
     {
@@ -473,7 +485,7 @@
     }
 
 Service:
-  tok_service tok_identifier ExtendsOptional '{' FunctionList '}'
+  tok_service tok_identifier Extends '{' FunctionList '}'
     {
       pdebug("Service -> tok_service tok_identifier { FunctionList }");
       $$ = $5;
@@ -481,10 +493,10 @@
       $$->set_extends($3);
     }
 
-ExtendsOptional:
+Extends:
   tok_extends tok_identifier
     {
-      pdebug("ExtendsOptional -> tok_extends tok_identifier");
+      pdebug("Extends -> tok_extends tok_identifier");
       $$ = NULL;
       if (g_parse_mode == PROGRAM) {
         $$ = g_scope->get_service($2);
@@ -513,14 +525,14 @@
     }
 
 Function:
-  AsyncOptional FunctionType tok_identifier '(' FieldList ')' ThrowsOptional CommaOrSemicolonOptional
+  Async FunctionType tok_identifier '(' FieldList ')' Throws CommaOrSemicolonOptional
     {
       $5->set_name(std::string($3) + "_args");
       $$ = new t_function($2, $3, $5, $7, $1);
       y_field_val = -1;
     }
 
-AsyncOptional:
+Async:
   tok_async
     {
       $$ = true;
@@ -530,10 +542,10 @@
       $$ = false;
     }
 
-ThrowsOptional:
+Throws:
   tok_throws '(' FieldList ')'
     {
-      pdebug("ThrowsOptional -> tok_throws ( FieldList )");
+      pdebug("Throws -> tok_throws ( FieldList )");
       $$ = $3;
     }
 |
@@ -555,7 +567,7 @@
     }
 
 Field:
-  tok_int_constant ':' FieldType tok_identifier CommaOrSemicolonOptional
+  tok_int_constant ':' FieldType tok_identifier XsdOptional CommaOrSemicolonOptional
     {
       pdebug("tok_int_constant : Field -> FieldType tok_identifier");
       if ($1 <= 0) {
@@ -563,12 +575,14 @@
         $1 = y_field_val--;
       }
       $$ = new t_field($3, $4, $1);
+      $$->set_xsd_optional($5);
     }
-| FieldType tok_identifier CommaOrSemicolonOptional
+| FieldType tok_identifier XsdOptional CommaOrSemicolonOptional
     {
       pdebug("Field -> FieldType tok_identifier");
       pwarning(2, "No field key specified for '%s', resulting protocol may have conflicts or not be backwards compatible!\n", $2);
       $$ = new t_field($1, $2, y_field_val--);
+      $$->set_xsd_optional($3);
     }
 | FieldType tok_identifier '=' tok_int_constant CommaOrSemicolonOptional
     {
@@ -692,7 +706,7 @@
     }
 
 MapType:
-  tok_map CppTypeOptional '<' FieldType ',' FieldType '>'
+  tok_map CppType '<' FieldType ',' FieldType '>'
     {
       pdebug("MapType -> tok_map <FieldType, FieldType>");
       $$ = new t_map($4, $6);
@@ -702,7 +716,7 @@
     }
 
 SetType:
-  tok_set CppTypeOptional '<' FieldType '>'
+  tok_set CppType '<' FieldType '>'
     {
       pdebug("SetType -> tok_set<FieldType>");
       $$ = new t_set($4);
@@ -712,7 +726,7 @@
     }
 
 ListType:
-  tok_list '<' FieldType '>' CppTypeOptional
+  tok_list '<' FieldType '>' CppType
     {
       pdebug("ListType -> tok_list<FieldType>");
       $$ = new t_list($3);
@@ -721,7 +735,7 @@
       }
     }
 
-CppTypeOptional:
+CppType:
   '[' tok_cpp_type tok_literal ']'
     {
       $$ = $3;