| 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 |