OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """ Parser for PPAPI IDL """ | 6 """ Parser for PPAPI IDL """ |
7 | 7 |
8 # | 8 # |
9 # IDL Parser | 9 # IDL Parser |
10 # | 10 # |
(...skipping 17 matching lines...) Expand all Loading... |
28 import re | 28 import re |
29 import sys | 29 import sys |
30 import time | 30 import time |
31 | 31 |
32 from idl_ast import IDLAst | 32 from idl_ast import IDLAst |
33 from idl_log import ErrOut, InfoOut, WarnOut | 33 from idl_log import ErrOut, InfoOut, WarnOut |
34 from idl_lexer import IDLLexer | 34 from idl_lexer import IDLLexer |
35 from idl_node import IDLAttribute, IDLFile, IDLNode | 35 from idl_node import IDLAttribute, IDLFile, IDLNode |
36 from idl_option import GetOption, Option, ParseOptions | 36 from idl_option import GetOption, Option, ParseOptions |
37 from idl_lint import Lint | 37 from idl_lint import Lint |
| 38 from idl_visitor import IDLVisitor |
38 | 39 |
39 from ply import lex | 40 from ply import lex |
40 from ply import yacc | 41 from ply import yacc |
41 | 42 |
42 Option('build_debug', 'Debug tree building.') | 43 Option('build_debug', 'Debug tree building.') |
43 Option('parse_debug', 'Debug parse reduction steps.') | 44 Option('parse_debug', 'Debug parse reduction steps.') |
44 Option('token_debug', 'Debug token generation.') | 45 Option('token_debug', 'Debug token generation.') |
45 Option('dump_tree', 'Dump the tree.') | 46 Option('dump_tree', 'Dump the tree.') |
46 Option('srcroot', 'Working directory.', default=os.path.join('..', 'api')) | 47 Option('srcroot', 'Working directory.', default=os.path.join('..', 'api')) |
47 Option('include_private', 'Include private IDL directory in default API paths.') | 48 Option('include_private', 'Include private IDL directory in default API paths.') |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 """top_list : callback_decl top_list | 236 """top_list : callback_decl top_list |
236 | describe_block top_list | 237 | describe_block top_list |
237 | dictionary_block top_list | 238 | dictionary_block top_list |
238 | enum_block top_list | 239 | enum_block top_list |
239 | inline top_list | 240 | inline top_list |
240 | interface_block top_list | 241 | interface_block top_list |
241 | label_block top_list | 242 | label_block top_list |
242 | namespace top_list | 243 | namespace top_list |
243 | struct_block top_list | 244 | struct_block top_list |
244 | typedef_decl top_list | 245 | typedef_decl top_list |
| 246 | bad_decl top_list |
245 | """ | 247 | """ |
246 if len(p) > 2: | 248 if len(p) > 2: |
247 p[0] = ListFromConcat(p[1], p[2]) | 249 p[0] = ListFromConcat(p[1], p[2]) |
248 if self.parse_debug: DumpReduction('top_list', p) | 250 if self.parse_debug: DumpReduction('top_list', p) |
249 | 251 |
250 # Recover from error and continue parsing at the next top match. | 252 # Recover from error and continue parsing at the next top match. |
251 def p_top_error(self, p): | 253 def p_top_error(self, p): |
252 """top_list : error top_list""" | 254 """top_list : error top_list""" |
253 p[0] = p[2] | 255 p[0] = p[2] |
254 | 256 |
| 257 # Recover from error and continue parsing at the next top match. |
| 258 def p_bad_decl(self, p): |
| 259 """bad_decl : modifiers SYMBOL error '}' ';'""" |
| 260 p[0] = [] |
| 261 |
255 # | 262 # |
256 # Modifier List | 263 # Modifier List |
257 # | 264 # |
258 # | 265 # |
259 def p_modifiers(self, p): | 266 def p_modifiers(self, p): |
260 """modifiers : comments ext_attr_block""" | 267 """modifiers : comments ext_attr_block""" |
261 p[0] = ListFromConcat(p[1], p[2]) | 268 p[0] = ListFromConcat(p[1], p[2]) |
262 if self.parse_debug: DumpReduction('modifiers', p) | 269 if self.parse_debug: DumpReduction('modifiers', p) |
263 | 270 |
264 # | 271 # |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 # A describe block is defined at the top level. It provides a mechanism for | 443 # A describe block is defined at the top level. It provides a mechanism for |
437 # attributing a group of ext_attr to a describe_list. Members of the | 444 # attributing a group of ext_attr to a describe_list. Members of the |
438 # describe list are language specific 'Type' declarations | 445 # describe list are language specific 'Type' declarations |
439 # | 446 # |
440 def p_describe_block(self, p): | 447 def p_describe_block(self, p): |
441 """describe_block : modifiers DESCRIBE '{' describe_list '}' ';'""" | 448 """describe_block : modifiers DESCRIBE '{' describe_list '}' ';'""" |
442 children = ListFromConcat(p[1], p[4]) | 449 children = ListFromConcat(p[1], p[4]) |
443 p[0] = self.BuildProduction('Describe', p, 2, children) | 450 p[0] = self.BuildProduction('Describe', p, 2, children) |
444 if self.parse_debug: DumpReduction('describe_block', p) | 451 if self.parse_debug: DumpReduction('describe_block', p) |
445 | 452 |
| 453 # Recover from describe error and continue parsing at the next top match. |
| 454 def p_describe_error(self, p): |
| 455 """describe_list : error describe_list""" |
| 456 p[0] = [] |
| 457 |
446 def p_describe_list(self, p): | 458 def p_describe_list(self, p): |
447 """describe_list : modifiers SYMBOL ';' describe_list | 459 """describe_list : modifiers SYMBOL ';' describe_list |
448 | modifiers ENUM ';' describe_list | 460 | modifiers ENUM ';' describe_list |
449 | modifiers STRUCT ';' describe_list | 461 | modifiers STRUCT ';' describe_list |
450 | modifiers TYPEDEF ';' describe_list | 462 | modifiers TYPEDEF ';' describe_list |
451 | """ | 463 | """ |
452 if len(p) > 1: | 464 if len(p) > 1: |
453 Type = self.BuildNamed('Type', p, 2, p[1]) | 465 Type = self.BuildNamed('Type', p, 2, p[1]) |
454 p[0] = ListFromConcat(Type, p[4]) | 466 p[0] = ListFromConcat(Type, p[4]) |
455 | 467 |
456 def p_describe_error(self, p): | |
457 """describe_list : error describe_list""" | |
458 p[0] = p[2] | |
459 | |
460 # | 468 # |
461 # Constant Values (integer, value) | 469 # Constant Values (integer, value) |
462 # | 470 # |
463 # Constant values can be found at various levels. A Constant value is returns | 471 # Constant values can be found at various levels. A Constant value is returns |
464 # as the string value after validated against a FLOAT, HEX, INT, OCT or | 472 # as the string value after validated against a FLOAT, HEX, INT, OCT or |
465 # STRING pattern as appropriate. | 473 # STRING pattern as appropriate. |
466 # | 474 # |
467 def p_value(self, p): | 475 def p_value(self, p): |
468 """value : FLOAT | 476 """value : FLOAT |
469 | HEX | 477 | HEX |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 # Enumeration | 649 # Enumeration |
642 # | 650 # |
643 # An enumeration is a set of named integer constants. An enumeration | 651 # An enumeration is a set of named integer constants. An enumeration |
644 # is valid type which can be referenced in other definitions. | 652 # is valid type which can be referenced in other definitions. |
645 # | 653 # |
646 def p_enum_block(self, p): | 654 def p_enum_block(self, p): |
647 """enum_block : modifiers ENUM SYMBOL '{' enum_list '}' ';'""" | 655 """enum_block : modifiers ENUM SYMBOL '{' enum_list '}' ';'""" |
648 p[0] = self.BuildNamed('Enum', p, 3, ListFromConcat(p[1], p[5])) | 656 p[0] = self.BuildNamed('Enum', p, 3, ListFromConcat(p[1], p[5])) |
649 if self.parse_debug: DumpReduction('enum_block', p) | 657 if self.parse_debug: DumpReduction('enum_block', p) |
650 | 658 |
| 659 # Recover from enum error and continue parsing at the next top match. |
| 660 def p_enum_errorA(self, p): |
| 661 """enum_block : modifiers ENUM error '{' enum_list '}' ';'""" |
| 662 p[0] = [] |
| 663 |
| 664 def p_enum_errorB(self, p): |
| 665 """enum_block : modifiers ENUM error ';'""" |
| 666 p[0] = [] |
| 667 |
651 def p_enum_list(self, p): | 668 def p_enum_list(self, p): |
652 """enum_list : modifiers SYMBOL '=' expression enum_cont | 669 """enum_list : modifiers SYMBOL '=' expression enum_cont |
653 | modifiers SYMBOL enum_cont""" | 670 | modifiers SYMBOL enum_cont""" |
654 if len(p) > 4: | 671 if len(p) > 4: |
655 val = self.BuildAttribute('VALUE', p[4]) | 672 val = self.BuildAttribute('VALUE', p[4]) |
656 enum = self.BuildNamed('EnumItem', p, 2, ListFromConcat(val, p[1])) | 673 enum = self.BuildNamed('EnumItem', p, 2, ListFromConcat(val, p[1])) |
657 p[0] = ListFromConcat(enum, p[5]) | 674 p[0] = ListFromConcat(enum, p[5]) |
658 else: | 675 else: |
659 enum = self.BuildNamed('EnumItem', p, 2, p[1]) | 676 enum = self.BuildNamed('EnumItem', p, 2, p[1]) |
660 p[0] = ListFromConcat(enum, p[3]) | 677 p[0] = ListFromConcat(enum, p[3]) |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 # | 753 # |
737 # Interface | 754 # Interface |
738 # | 755 # |
739 # An interface is a named collection of functions. | 756 # An interface is a named collection of functions. |
740 # | 757 # |
741 def p_interface_block(self, p): | 758 def p_interface_block(self, p): |
742 """interface_block : modifiers INTERFACE SYMBOL '{' interface_list '}' ';'""
" | 759 """interface_block : modifiers INTERFACE SYMBOL '{' interface_list '}' ';'""
" |
743 p[0] = self.BuildNamed('Interface', p, 3, ListFromConcat(p[1], p[5])) | 760 p[0] = self.BuildNamed('Interface', p, 3, ListFromConcat(p[1], p[5])) |
744 if self.parse_debug: DumpReduction('interface_block', p) | 761 if self.parse_debug: DumpReduction('interface_block', p) |
745 | 762 |
| 763 def p_interface_error(self, p): |
| 764 """interface_block : modifiers INTERFACE error '{' interface_list '}' ';'""" |
| 765 p[0] = [] |
| 766 |
746 def p_interface_list(self, p): | 767 def p_interface_list(self, p): |
747 """interface_list : member_function ';' interface_list | 768 """interface_list : member_function ';' interface_list |
748 | """ | 769 | """ |
749 if len(p) > 1 : | 770 if len(p) > 1 : |
750 p[0] = ListFromConcat(p[1], p[3]) | 771 p[0] = ListFromConcat(p[1], p[3]) |
751 if self.parse_debug: DumpReduction('interface_list', p) | 772 if self.parse_debug: DumpReduction('interface_list', p) |
752 | 773 |
753 def p_interface_error(self, p): | |
754 """interface_list : error interface_list""" | |
755 p[0] = p[2] | |
756 | 774 |
757 # | 775 # |
758 # Struct | 776 # Struct |
759 # | 777 # |
760 # A struct is a named collection of members which in turn reference other | 778 # A struct is a named collection of members which in turn reference other |
761 # types. The struct is a referencable type. | 779 # types. The struct is a referencable type. |
762 # | 780 # |
763 def p_struct_block(self, p): | 781 def p_struct_block(self, p): |
764 """struct_block : modifiers STRUCT SYMBOL '{' struct_list '}' ';'""" | 782 """struct_block : modifiers STRUCT SYMBOL '{' struct_list '}' ';'""" |
765 children = ListFromConcat(p[1], p[5]) | 783 children = ListFromConcat(p[1], p[5]) |
766 p[0] = self.BuildNamed('Struct', p, 3, children) | 784 p[0] = self.BuildNamed('Struct', p, 3, children) |
767 if self.parse_debug: DumpReduction('struct_block', p) | 785 if self.parse_debug: DumpReduction('struct_block', p) |
768 | 786 |
| 787 # Recover from struct error and continue parsing at the next top match. |
| 788 def p_struct_error(self, p): |
| 789 """enum_block : modifiers STRUCT error '{' struct_list '}' ';'""" |
| 790 p[0] = [] |
| 791 |
769 def p_struct_list(self, p): | 792 def p_struct_list(self, p): |
770 """struct_list : member_attribute ';' struct_list | 793 """struct_list : member_attribute ';' struct_list |
771 | member_function ';' struct_list | 794 | member_function ';' struct_list |
772 |""" | 795 |""" |
773 if len(p) > 1: p[0] = ListFromConcat(p[1], p[3]) | 796 if len(p) > 1: p[0] = ListFromConcat(p[1], p[3]) |
774 | 797 |
775 def p_struct_error(self, p): | |
776 """struct_list : error struct_list""" | |
777 p[0] = p[2] | |
778 | 798 |
779 # | 799 # |
780 # Parser Errors | 800 # Parser Errors |
781 # | 801 # |
782 # p_error is called whenever the parser can not find a pattern match for | 802 # p_error is called whenever the parser can not find a pattern match for |
783 # a set of items from the current state. The p_error function defined here | 803 # a set of items from the current state. The p_error function defined here |
784 # is triggered logging an error, and parsing recover happens as the | 804 # is triggered logging an error, and parsing recover happens as the |
785 # p_<type>_error functions defined above are called. This allows the parser | 805 # p_<type>_error functions defined above are called. This allows the parser |
786 # to continue so as to capture more than one error per file. | 806 # to continue so as to capture more than one error per file. |
787 # | 807 # |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1096 ast = ParseFiles(testnames) | 1116 ast = ParseFiles(testnames) |
1097 InfoOut.SetConsole(True) | 1117 InfoOut.SetConsole(True) |
1098 | 1118 |
1099 errs = ast.GetProperty('ERRORS') | 1119 errs = ast.GetProperty('ERRORS') |
1100 if errs: | 1120 if errs: |
1101 ErrOut.Log("Failed namespace test.") | 1121 ErrOut.Log("Failed namespace test.") |
1102 else: | 1122 else: |
1103 InfoOut.Log("Passed namespace test.") | 1123 InfoOut.Log("Passed namespace test.") |
1104 return errs | 1124 return errs |
1105 | 1125 |
| 1126 |
| 1127 |
| 1128 def FindVersionError(releases, node): |
| 1129 err_cnt = 0 |
| 1130 if node.IsA('Interface', 'Struct'): |
| 1131 comment_list = [] |
| 1132 comment = node.GetOneOf('Comment') |
| 1133 if comment: |
| 1134 print comment.GetName() |
| 1135 if comment and comment.GetName()[:4] == 'REL:': |
| 1136 comment_list = comment.GetName()[5:].strip().split(' ') |
| 1137 print comment_list |
| 1138 |
| 1139 if len(comment_list) != len(releases): |
| 1140 node.Error("Mismatch size of releases: %s vs %s." % ( |
| 1141 comment_list, releases)) |
| 1142 err_cnt += 1 |
| 1143 else: |
| 1144 first_list = [node.first_release[rel] for rel in releases] |
| 1145 if first_list != comment_list: |
| 1146 node.Error("Mismatch in releases: %s vs %s." % ( |
| 1147 comment_list, first_list)) |
| 1148 err_cnt += 1 |
| 1149 |
| 1150 for child in node.GetChildren(): |
| 1151 err_cnt += FindVersionError(releases, child) |
| 1152 return err_cnt |
| 1153 |
| 1154 |
| 1155 def TestVersionFiles(filter): |
| 1156 idldir = os.path.split(sys.argv[0])[0] |
| 1157 idldir = os.path.join(idldir, 'test_version', '*.idl') |
| 1158 filenames = glob.glob(idldir) |
| 1159 testnames = [] |
| 1160 |
| 1161 for filename in filenames: |
| 1162 if filter and filename not in filter: continue |
| 1163 testnames.append(filename) |
| 1164 |
| 1165 # If we have no files to test, then skip this test |
| 1166 if not testnames: |
| 1167 InfoOut.Log('No files to test for version.') |
| 1168 return 0 |
| 1169 |
| 1170 ast = ParseFiles(testnames) |
| 1171 errs = FindVersionError(ast.releases, ast) |
| 1172 |
| 1173 if errs: |
| 1174 ErrOut.Log("Failed version test.") |
| 1175 else: |
| 1176 InfoOut.Log("Passed version test.") |
| 1177 return errs |
| 1178 |
| 1179 |
1106 default_dirs = ['.', 'trusted', 'dev', 'private'] | 1180 default_dirs = ['.', 'trusted', 'dev', 'private'] |
1107 def ParseFiles(filenames): | 1181 def ParseFiles(filenames): |
1108 parser = IDLParser() | 1182 parser = IDLParser() |
1109 filenodes = [] | 1183 filenodes = [] |
1110 | 1184 |
1111 if not filenames: | 1185 if not filenames: |
1112 filenames = [] | 1186 filenames = [] |
1113 srcroot = GetOption('srcroot') | 1187 srcroot = GetOption('srcroot') |
1114 dirs = default_dirs | 1188 dirs = default_dirs |
1115 if GetOption('include_private'): | 1189 if GetOption('include_private'): |
(...skipping 17 matching lines...) Expand all Loading... |
1133 return ast | 1207 return ast |
1134 | 1208 |
1135 | 1209 |
1136 def Main(args): | 1210 def Main(args): |
1137 filenames = ParseOptions(args) | 1211 filenames = ParseOptions(args) |
1138 | 1212 |
1139 # If testing... | 1213 # If testing... |
1140 if GetOption('test'): | 1214 if GetOption('test'): |
1141 errs = TestErrorFiles(filenames) | 1215 errs = TestErrorFiles(filenames) |
1142 errs = TestNamespaceFiles(filenames) | 1216 errs = TestNamespaceFiles(filenames) |
| 1217 errs = TestVersionFiles(filenames) |
1143 if errs: | 1218 if errs: |
1144 ErrOut.Log("Parser failed with %d errors." % errs) | 1219 ErrOut.Log("Parser failed with %d errors." % errs) |
1145 return -1 | 1220 return -1 |
1146 return 0 | 1221 return 0 |
1147 | 1222 |
1148 # Otherwise, build the AST | 1223 # Otherwise, build the AST |
1149 ast = ParseFiles(filenames) | 1224 ast = ParseFiles(filenames) |
1150 errs = ast.GetProperty('ERRORS') | 1225 errs = ast.GetProperty('ERRORS') |
1151 if errs: | 1226 if errs: |
1152 ErrOut.Log('Found %d error(s).' % errs); | 1227 ErrOut.Log('Found %d error(s).' % errs); |
1153 InfoOut.Log("%d files processed." % len(filenames)) | 1228 InfoOut.Log("%d files processed." % len(filenames)) |
1154 return errs | 1229 return errs |
1155 | 1230 |
1156 | 1231 |
1157 if __name__ == '__main__': | 1232 if __name__ == '__main__': |
1158 sys.exit(Main(sys.argv[1:])) | 1233 sys.exit(Main(sys.argv[1:])) |
| 1234 |
OLD | NEW |