THRIFT-1651 Support annotations on all elements
Patch: Benjy Weinberger



git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1386848 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/parse/t_enum_value.h b/compiler/cpp/src/parse/t_enum_value.h
index 283a87e..3a4a90a 100644
--- a/compiler/cpp/src/parse/t_enum_value.h
+++ b/compiler/cpp/src/parse/t_enum_value.h
@@ -60,6 +60,8 @@
     value_ = val;
   }
 
+  std::map<std::string, std::string> annotations_;
+
  private:
   std::string name_;
   bool has_value_;
diff --git a/compiler/cpp/src/parse/t_function.h b/compiler/cpp/src/parse/t_function.h
index a72aa6c..0da2fd6 100644
--- a/compiler/cpp/src/parse/t_function.h
+++ b/compiler/cpp/src/parse/t_function.h
@@ -82,6 +82,8 @@
     return oneway_;
   }
 
+  std::map<std::string, std::string> annotations_;
+
  private:
   t_type* returntype_;
   std::string name_;
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index ef53cc3..696fd46 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -504,11 +504,15 @@
     }
 
 Typedef:
-  tok_typedef FieldType tok_identifier
+  tok_typedef FieldType tok_identifier TypeAnnotations
     {
       pdebug("TypeDef -> tok_typedef FieldType tok_identifier");
       t_typedef *td = new t_typedef(g_program, $2, $3);
       $$ = td;
+      if ($4 != NULL) {
+        $$->annotations_ = $4->annotations_;
+        delete $4;
+      }
     }
 
 CommaOrSemicolonOptional:
@@ -520,11 +524,15 @@
     {}
 
 Enum:
-  tok_enum tok_identifier '{' EnumDefList '}'
+  tok_enum tok_identifier '{' EnumDefList '}' TypeAnnotations
     {
       pdebug("Enum -> tok_enum tok_identifier { EnumDefList }");
       $$ = $4;
       $$->set_name($2);
+      if ($6 != NULL) {
+        $$->annotations_ = $6->annotations_;
+        delete $6;
+      }
       $$->resolve_values();
       // make constants for all the enum values
       if (g_parse_mode == PROGRAM) {
@@ -556,7 +564,7 @@
     }
 
 EnumDef:
-  CaptureDocText tok_identifier '=' tok_int_constant CommaOrSemicolonOptional
+  CaptureDocText tok_identifier '=' tok_int_constant TypeAnnotations CommaOrSemicolonOptional
     {
       pdebug("EnumDef -> tok_identifier = tok_int_constant");
       if ($4 < 0) {
@@ -569,22 +577,34 @@
       if ($1 != NULL) {
         $$->set_doc($1);
       }
+      if ($5 != NULL) {
+        $$->annotations_ = $5->annotations_;
+        delete $5;
+      }
     }
 |
-  CaptureDocText tok_identifier CommaOrSemicolonOptional
+  CaptureDocText tok_identifier TypeAnnotations CommaOrSemicolonOptional
     {
       pdebug("EnumDef -> tok_identifier");
       $$ = new t_enum_value($2);
       if ($1 != NULL) {
         $$->set_doc($1);
       }
+      if ($3 != NULL) {
+        $$->annotations_ = $3->annotations_;
+        delete $3;
+      }
     }
 
 Senum:
-  tok_senum tok_identifier '{' SenumDefList '}'
+  tok_senum tok_identifier '{' SenumDefList '}' TypeAnnotations
     {
       pdebug("Senum -> tok_senum tok_identifier { SenumDefList }");
       $$ = new t_typedef(g_program, $4, $2);
+      if ($6 != NULL) {
+        $$->annotations_ = $6->annotations_;
+        delete $6;
+      }
     }
 
 SenumDefList:
@@ -771,21 +791,29 @@
     }
 
 Xception:
-  tok_xception tok_identifier '{' FieldList '}'
+  tok_xception tok_identifier '{' FieldList '}' TypeAnnotations
     {
       pdebug("Xception -> tok_xception tok_identifier { FieldList }");
       $4->set_name($2);
       $4->set_xception(true);
       $$ = $4;
+      if ($6 != NULL) {
+        $$->annotations_ = $6->annotations_;
+        delete $6;
+      }
     }
 
 Service:
-  tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}'
+  tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' TypeAnnotations
     {
       pdebug("Service -> tok_service tok_identifier { FunctionList }");
       $$ = $6;
       $$->set_name($2);
       $$->set_extends($3);
+      if ($9 != NULL) {
+        $$->annotations_ = $9->annotations_;
+        delete $9;
+      }
     }
 
 FlagArgs:
@@ -830,13 +858,17 @@
     }
 
 Function:
-  CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws CommaOrSemicolonOptional
+  CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws TypeAnnotations CommaOrSemicolonOptional
     {
       $6->set_name(std::string($4) + "_args");
       $$ = new t_function($3, $4, $6, $8, $2);
       if ($1 != NULL) {
         $$->set_doc($1);
       }
+      if ($9 != NULL) {
+        $$->annotations_ = $9->annotations_;
+        delete $9;
+      }
     }
 
 Oneway:
diff --git a/compiler/cpp/test_parser.sh b/compiler/cpp/test_parser.sh
new file mode 100644
index 0000000..066e09a
--- /dev/null
+++ b/compiler/cpp/test_parser.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Tests the parser, independently of whether any generators
+# are correct or useful.
+# Currently only tests that valid .thrift files parse cleanly.
+# Doesn't test that correct information is extracted from them.
+
+shopt -s extglob
+
+MY_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+ROOT_DIR=`cd $MY_DIR/../../ && pwd`
+TEST_THRIFT_DIR=${ROOT_DIR}/test
+THRIFT_FILES=`find ${TEST_THRIFT_DIR} -type f -name *.thrift ! -name BrokenConstants.thrift`
+
+OUTPUT_DIR=`mktemp -d -t test_thrift_parser.XXXXX`
+
+PASS=0
+FAIL=0
+for f in ${THRIFT_FILES};
+do
+  echo "Parsing ${f}"
+  ${MY_DIR}/thrift -o ${OUTPUT_DIR} -nowarn --allow-64bit-consts --gen cpp ${f}
+  EXIT_CODE=$?
+  if [ ${EXIT_CODE} -eq 0 ]; then
+    let PASS=PASS+1
+  else
+    let FAIL=FAIL+1
+  fi
+done
+echo
+echo "${PASS} files parsed correctly. ${FAIL} files failed to parse."
diff --git a/test/AnnotationTest.thrift b/test/AnnotationTest.thrift
index 1a34320..dac476f 100644
--- a/test/AnnotationTest.thrift
+++ b/test/AnnotationTest.thrift
@@ -30,5 +30,33 @@
   java.final = "",
 )
 
-typedef string ( unicode.encoding = "UTF-16" ) non_latin_string
+exception foo_error {
+  1: i32 error_code ( foo="bar" )
+  2: string error_msg
+} (foo = "bar")
+
+typedef string ( unicode.encoding = "UTF-16" ) non_latin_string (foo="bar")
 typedef list< double ( cpp.fixed_point = "16" ) > tiny_float_list
+
+enum weekdays {
+  SUNDAY ( weekend = "yes" ),
+  MONDAY,
+  TUESDAY,
+  WEDNESDAY,
+  THURSDAY,
+  FRIDAY,
+  SATURDAY ( weekend = "yes" )
+} (foo.bar="baz")
+
+/* Note that annotations on senum values are not supported. */
+senum seasons {
+  "Spring",
+  "Summer", 
+  "Fall",
+  "Winter"
+} ( foo = "bar" )
+
+service foo_service {
+  void foo() ( foo = "bar" )
+} (a.b="c")
+