| Index: ppapi/generators/idl_parser.py
|
| ===================================================================
|
| --- ppapi/generators/idl_parser.py (revision 90352)
|
| +++ ppapi/generators/idl_parser.py (working copy)
|
| @@ -29,9 +29,10 @@
|
| import re
|
| import sys
|
|
|
| +from idl_ast import IDLAst
|
| from idl_log import ErrOut, InfoOut, WarnOut
|
| from idl_lexer import IDLLexer
|
| -from idl_node import IDLAttribute, IDLAst, IDLNode
|
| +from idl_node import IDLAttribute, IDLFile, IDLNode
|
| from idl_option import GetOption, Option, ParseOptions
|
|
|
| from ply import lex
|
| @@ -41,9 +42,10 @@
|
| Option('parse_debug', 'Debug parse reduction steps.')
|
| Option('token_debug', 'Debug token generation.')
|
| Option('dump_tree', 'Dump the tree.')
|
| -Option('srcdir', 'Working directory', default='.')
|
| +Option('srcroot', 'Working directory.', default='')
|
| +Option('wcomment', 'Disable warning for missing comment.')
|
| +Option('wenum', 'Disable warning for missing enum value.')
|
|
|
| -
|
| #
|
| # ERROR_REMAP
|
| #
|
| @@ -54,7 +56,7 @@
|
| 'Unexpected ")" after ",".' : 'Missing argument.',
|
| 'Unexpected "}" after ",".' : 'Trailing comma in block.',
|
| 'Unexpected "}" after "{".' : 'Unexpected empty block.',
|
| - 'Unexpected comment "/*" after "}".' : 'Unexpected trailing comment.',
|
| + 'Unexpected comment after "}".' : 'Unexpected trailing comment.',
|
| 'Unexpected "{" after keyword "enum".' : 'Enum missing name.',
|
| 'Unexpected "{" after keyword "struct".' : 'Struct missing name.',
|
| 'Unexpected "{" after keyword "interface".' : 'Interface missing name.',
|
| @@ -67,6 +69,7 @@
|
| def DumpReduction(cls, p):
|
| if p[0] is None:
|
| InfoOut.Log("OBJ: %s(%d) - None\n" % (cls, len(p)))
|
| + InfoOut.Log(" [%s]\n" % [str(x) for x in p[1:]])
|
| else:
|
| out = ""
|
| for index in range(len(p) - 1):
|
| @@ -110,23 +113,12 @@
|
| if t.type in ['HEX', 'INT', 'OCT', 'FLOAT']:
|
| return 'value %s' % t.value
|
| if t.type == 'STRING' : return 'string "%s"' % t.value
|
| - if t.type == 'COMMENT' : return 'comment "%s"' % t.value[:2]
|
| + if t.type == 'COMMENT' : return 'comment'
|
| if t.type == t.value: return '"%s"' % t.value
|
| return 'keyword "%s"' % t.value
|
|
|
|
|
| -# StageResult
|
| #
|
| -# The result object stores the result of parsing stage.
|
| -#
|
| -class StageResult(object):
|
| - def __init__(self, name, out, errs):
|
| - self.name = name
|
| - self.out = out
|
| - self.errs = errs
|
| -
|
| -
|
| -#
|
| # IDL Parser
|
| #
|
| # The Parser inherits the from the Lexer to provide PLY with the tokenizing
|
| @@ -199,8 +191,11 @@
|
| # describe_block
|
| # describe_list
|
| # enum_block
|
| -# enum_type
|
| +# enum_item
|
| # interface_block
|
| +# member
|
| +# label_block
|
| +# label_item
|
| # struct_block
|
| # member
|
| # typedef_decl
|
| @@ -220,8 +215,8 @@
|
| def p_top(self, p):
|
| """top : COMMENT COMMENT ext_attr_block top_list"""
|
|
|
| - Copyright = self.BuildProduction('Copyright', p, 1, None)
|
| - Filedoc = self.BuildProduction('Comment', p, 2, None)
|
| + Copyright = self.BuildComment('Copyright', p, 1)
|
| + Filedoc = self.BuildComment('Comment', p, 2)
|
|
|
| p[0] = ListFromConcat(Copyright, Filedoc, p[3], p[4])
|
| if self.parse_debug: DumpReduction('top', p)
|
| @@ -230,9 +225,11 @@
|
| def p_top_list(self, p):
|
| """top_list : describe_block top_list
|
| | enum_block top_list
|
| + | inline top_list
|
| | interface_block top_list
|
| + | label_block top_list
|
| | struct_block top_list
|
| - | typedef_def top_list
|
| + | typedef_decl top_list
|
| | """
|
| if len(p) > 2:
|
| p[0] = ListFromConcat(p[1], p[2])
|
| @@ -262,13 +259,32 @@
|
| """comments : COMMENT comments
|
| | """
|
| if len(p) > 1:
|
| - child = self.BuildProduction('Comment', p, 1, None)
|
| + child = self.BuildComment('Comment', p, 1)
|
| p[0] = ListFromConcat(child, p[2])
|
| if self.parse_debug: DumpReduction('comments', p)
|
| else:
|
| if self.parse_debug: DumpReduction('no comments', p)
|
|
|
| +
|
| #
|
| +# Inline
|
| +#
|
| +# Inline blocks define option code to be emitted based on language tag,
|
| +# in the form of:
|
| +# #inline <LANGUAGE>
|
| +# <CODE>
|
| +# #endinl
|
| +#
|
| + def p_inline(self, p):
|
| + """inline : modifiers INLINE"""
|
| + words = p[2].split()
|
| + name = self.BuildAttribute('NAME', words[1])
|
| + lines = p[2].split('\n')
|
| + value = self.BuildAttribute('VALUE', '\n'.join(lines[1:-1]) + '\n')
|
| + children = ListFromConcat(name, value, p[1])
|
| + p[0] = self.BuildProduction('Inline', p, 2, children)
|
| + if self.parse_debug: DumpReduction('inline', p)
|
| +
|
| # Extended Attributes
|
| #
|
| # Extended Attributes denote properties which will be applied to a node in the
|
| @@ -295,15 +311,22 @@
|
| if self.parse_debug: DumpReduction('no ext_attr_block', p)
|
|
|
| def p_ext_attr_list(self, p):
|
| - """ext_attr_list : SYMBOL '=' value ext_attr_cont
|
| - | SYMBOL '(' attr_arg_list ')' ext_attr_cont
|
| - | SYMBOL ext_attr_cont """
|
| - if len(p) == 3:
|
| - p[0] = ListFromConcat(self.BuildExtAttribute(p[1], 'True'), p[2])
|
| + """ext_attr_list : SYMBOL '=' SYMBOL ext_attr_cont
|
| + | SYMBOL '=' value ext_attr_cont
|
| + | SYMBOL '=' SYMBOL param_list ext_attr_cont
|
| + | SYMBOL ext_attr_cont"""
|
| + # If there are 4 tokens plus a return slot, this must be in the form
|
| + # SYMBOL = SYMBOL|value ext_attr_cont
|
| if len(p) == 5:
|
| - p[0] = ListFromConcat(self.BuildExtAttribute(p[1], p[3]), p[4])
|
| - if len(p) == 6:
|
| - p[0] = ListFromConcat(self.BuildExtAttribute(p[1], p[3]), p[5])
|
| + p[0] = ListFromConcat(self.BuildAttribute(p[1], p[3]), p[4])
|
| + # If there are 5 tokens plus a return slot, this must be in the form
|
| + # SYMBOL = SYMBOL (param_list) ext_attr_cont
|
| + elif len(p) == 6:
|
| + member = self.BuildNamed('Member', p, 3, [p[4]])
|
| + p[0] = ListFromConcat(self.BuildAttribute(p[1], member), p[5])
|
| + # Otherwise, this must be: SYMBOL ext_attr_cont
|
| + else:
|
| + p[0] = ListFromConcat(self.BuildAttribute(p[1], 'True'), p[2])
|
| if self.parse_debug: DumpReduction('ext_attribute_list', p)
|
|
|
| def p_ext_attr_cont(self, p):
|
| @@ -312,17 +335,21 @@
|
| if len(p) > 1: p[0] = p[2]
|
| if self.parse_debug: DumpReduction('ext_attribute_cont', p)
|
|
|
| - def p_attr_arg_list(self, p):
|
| + def p_ext_attr_func(self, p):
|
| + """ext_attr_list : SYMBOL '(' attr_arg_list ')' ext_attr_cont"""
|
| + p[0] = ListFromConcat(self.BuildAttribute(p[1] + '()', p[3]), p[5])
|
| + if self.parse_debug: DumpReduction('attr_arg_func', p)
|
| +
|
| + def p_ext_attr_arg_list(self, p):
|
| """attr_arg_list : SYMBOL attr_arg_cont
|
| - | value attr_arg_cont """
|
| - p[0] = ','.join(ListFromConcat(p[1], p[2]))
|
| - if self.parse_debug: DumpReduction('attr_arg_list', p)
|
| + | value attr_arg_cont"""
|
| + p[0] = ListFromConcat(p[1], p[2])
|
|
|
| def p_attr_arg_cont(self, p):
|
| """attr_arg_cont : ',' attr_arg_list
|
| | """
|
| + if self.parse_debug: DumpReduction('attr_arg_cont', p)
|
| if len(p) > 1: p[0] = p[2]
|
| - if self.parse_debug: DumpReduction('attr_arg_cont', p)
|
|
|
| def p_attr_arg_error(self, p):
|
| """attr_arg_cont : error attr_arg_cont"""
|
| @@ -375,7 +402,7 @@
|
|
|
| def p_value_lshift(self, p):
|
| """value : integer LSHIFT INT"""
|
| - p[0] = "(%s << %s)" % (p[1], p[3])
|
| + p[0] = "%s << %s" % (p[1], p[3])
|
| if self.parse_debug: DumpReduction('value', p)
|
|
|
| # Integers are numbers which may not be floats used in cases like array sizes.
|
| @@ -384,71 +411,79 @@
|
| | INT
|
| | OCT"""
|
| p[0] = p[1]
|
| + if self.parse_debug: DumpReduction('integer', p)
|
|
|
| +# Numbers are integers or floats.
|
| + def p_number(self, p):
|
| + """number : FLOAT
|
| + | HEX
|
| + | INT
|
| + | OCT"""
|
| + p[0] = p[1]
|
| + if self.parse_debug: DumpReduction('number', p)
|
| +
|
| + def p_number_lshift(self, p):
|
| + """number : integer LSHIFT INT"""
|
| + p[0] = "%s << %s" % (p[1], p[3])
|
| + if self.parse_debug: DumpReduction('number_lshift', p)
|
| +
|
| #
|
| +# Array List
|
| +#
|
| +# Defined a list of array sizes (if any).
|
| +#
|
| + def p_arrays(self, p):
|
| + """arrays : '[' ']' arrays
|
| + | '[' integer ']' arrays
|
| + | """
|
| + # If there are 3 tokens plus a return slot it is an unsized array
|
| + if len(p) == 4:
|
| + array = self.BuildProduction('Array', p, 1)
|
| + p[0] = ListFromConcat(array, p[3])
|
| + # If there are 4 tokens plus a return slot it is a fixed array
|
| + elif len(p) == 5:
|
| + count = self.BuildAttribute('FIXED', p[2])
|
| + array = self.BuildProduction('Array', p, 2, [count])
|
| + p[0] = ListFromConcat(array, p[4])
|
| + # If there is only a return slot, do not fill it for this terminator.
|
| + elif len(p) == 1: return
|
| + if self.parse_debug: DumpReduction('arrays', p)
|
| +
|
| +#
|
| # Parameter List
|
| #
|
| # A parameter list is a collection of arguments which are passed to a
|
| # function.
|
| #
|
| def p_param_list(self, p):
|
| - """param_list : param_item param_cont
|
| - | """
|
| - if len(p) > 1:
|
| - args = ListFromConcat(p[1], p[2])
|
| + """param_list : '(' param_item param_cont ')'
|
| + | '(' ')' """
|
| + if len(p) > 3:
|
| + args = ListFromConcat(p[2], p[3])
|
| else:
|
| args = []
|
| - p[0] = self.BuildProduction('Callspec', p, -1, args)
|
| + p[0] = self.BuildProduction('Callspec', p, 1, args)
|
| if self.parse_debug: DumpReduction('param_list', p)
|
|
|
| def p_param_item(self, p):
|
| - """param_item : modifiers typeref SYMBOL param_cont"""
|
| - children = ListFromConcat(p[1], p[2])
|
| - param = self.BuildProduction('Param', p, 3, children)
|
| - p[0] = ListFromConcat(param, p[4])
|
| + """param_item : modifiers SYMBOL arrays SYMBOL"""
|
| + typeref = self.BuildAttribute('TYPEREF', p[2])
|
| + children = ListFromConcat(p[1],typeref, p[3])
|
| + p[0] = self.BuildNamed('Param', p, 4, children)
|
| if self.parse_debug: DumpReduction('param_item', p)
|
|
|
| def p_param_cont(self, p):
|
| """param_cont : ',' param_item param_cont
|
| | """
|
| if len(p) > 1:
|
| - p[0] = p[2]
|
| + p[0] = ListFromConcat(p[2], p[3])
|
| if self.parse_debug: DumpReduction('param_cont', p)
|
|
|
| def p_param_error(self, p):
|
| """param_cont : error param_cont"""
|
| p[0] = p[2]
|
|
|
| -#
|
| -# Typeref
|
| -#
|
| -# A typeref is a reference to a type definition. The type definition may
|
| -# be a built in such as int32_t or a defined type such as an enum, or
|
| -# struct, or typedef. Part of the reference to the type is how it is
|
| -# used, such as directly, a fixed size array, or unsized (pointer). The
|
| -# reference is reduced and becomes a property of the parent Node.
|
| -#
|
| - def p_typeref_data(self, p):
|
| - """typeref : SYMBOL typeref_arrays"""
|
|
|
| - Type = self.BuildExtAttribute('TYPEREF', p[1])
|
| - p[0] = ListFromConcat(Type, p[2])
|
| - if self.parse_debug: DumpReduction('typeref', p)
|
| -
|
| - def p_typeref_arrays(self, p):
|
| - """typeref_arrays : '[' ']' typeref_arrays
|
| - | '[' integer ']' typeref_arrays
|
| - | """
|
| - if len(p) == 1: return
|
| - if len(p) == 5:
|
| - count = self.BuildExtAttribute('FIXED', p[2])
|
| - array = self.BuildProduction('Array', p, 2, ListFromConcat(p[4], count))
|
| - else:
|
| - array = self.BuildProduction('Array', p, 1, p[3])
|
| -
|
| - p[0] = [array]
|
| - if self.parse_debug: DumpReduction('arrays', p)
|
| -
|
| #
|
| # Typedef
|
| #
|
| @@ -456,14 +491,24 @@
|
| # definition as well as a function declaration.
|
| #
|
| def p_typedef_data(self, p):
|
| - """typedef_def : modifiers TYPEDEF typeref SYMBOL ';' """
|
| - p[0] = self.BuildProduction('Typedef', p, 4, ListFromConcat(p[1], p[3]))
|
| + """typedef_decl : modifiers TYPEDEF SYMBOL SYMBOL ';' """
|
| + typeref = self.BuildAttribute('TYPEREF', p[3])
|
| + children = ListFromConcat(p[1], typeref)
|
| + p[0] = self.BuildNamed('Typedef', p, 4, children)
|
| if self.parse_debug: DumpReduction('typedef_data', p)
|
|
|
| + def p_typedef_array(self, p):
|
| + """typedef_decl : modifiers TYPEDEF SYMBOL arrays SYMBOL ';' """
|
| + typeref = self.BuildAttribute('TYPEREF', p[3])
|
| + children = ListFromConcat(p[1], typeref, p[4])
|
| + p[0] = self.BuildNamed('Typedef', p, 5, children)
|
| + if self.parse_debug: DumpReduction('typedef_array', p)
|
| +
|
| def p_typedef_func(self, p):
|
| - """typedef_def : modifiers TYPEDEF typeref SYMBOL '(' param_list ')' ';'"""
|
| - children = ListFromConcat(p[1], p[3], p[6])
|
| - p[0] = self.BuildProduction('Typedef', p, 4, children)
|
| + """typedef_decl : modifiers TYPEDEF SYMBOL SYMBOL param_list ';' """
|
| + typeref = self.BuildAttribute('TYPEREF', p[3])
|
| + children = ListFromConcat(p[1], typeref, p[5])
|
| + p[0] = self.BuildNamed('Typedef', p, 4, children)
|
| if self.parse_debug: DumpReduction('typedef_func', p)
|
|
|
| #
|
| @@ -474,15 +519,19 @@
|
| #
|
| def p_enum_block(self, p):
|
| """enum_block : modifiers ENUM SYMBOL '{' enum_list '}' ';'"""
|
| - Type = self.BuildExtAttribute('TYPEREF', 'enum')
|
| - p[0] = self.BuildProduction('Enum', p, 3, ListFromConcat(Type, p[1], p[5]))
|
| + p[0] = self.BuildNamed('Enum', p, 3, ListFromConcat(p[1], p[5]))
|
| if self.parse_debug: DumpReduction('enum_block', p)
|
|
|
| def p_enum_list(self, p):
|
| - """enum_list : comments SYMBOL '=' value enum_cont"""
|
| - val = self.BuildExtAttribute('VALUE', p[4])
|
| - enum = self.BuildProduction('EnumItem', p, 2, ListFromConcat(val, p[1]))
|
| - p[0] = ListFromConcat(enum, p[5])
|
| + """enum_list : modifiers SYMBOL '=' number enum_cont
|
| + | modifiers SYMBOL enum_cont"""
|
| + if len(p) > 4:
|
| + val = self.BuildAttribute('VALUE', p[4])
|
| + enum = self.BuildNamed('EnumItem', p, 2, ListFromConcat(val, p[1]))
|
| + p[0] = ListFromConcat(enum, p[5])
|
| + else:
|
| + enum = self.BuildNamed('EnumItem', p, 2, p[1])
|
| + p[0] = ListFromConcat(enum, p[3])
|
| if self.parse_debug: DumpReduction('enum_list', p)
|
|
|
| def p_enum_cont(self, p):
|
| @@ -498,30 +547,80 @@
|
|
|
|
|
| #
|
| +# Label
|
| +#
|
| +# A label is a special kind of enumeration which allows us to go from a
|
| +# set of labels
|
| +#
|
| + def p_label_block(self, p):
|
| + """label_block : modifiers LABEL SYMBOL '{' label_list '}' ';'"""
|
| + p[0] = self.BuildNamed('Label', p, 3, ListFromConcat(p[1], p[5]))
|
| + if self.parse_debug: DumpReduction('label_block', p)
|
| +
|
| + def p_label_list(self, p):
|
| + """label_list : modifiers SYMBOL '=' FLOAT label_cont"""
|
| + val = self.BuildAttribute('VALUE', p[4])
|
| + label = self.BuildNamed('LabelItem', p, 2, ListFromConcat(val, p[1]))
|
| + p[0] = ListFromConcat(label, p[5])
|
| + if self.parse_debug: DumpReduction('label_list', p)
|
| +
|
| + def p_label_cont(self, p):
|
| + """label_cont : ',' label_list
|
| + |"""
|
| + if len(p) > 1: p[0] = p[2]
|
| + if self.parse_debug: DumpReduction('label_cont', p)
|
| +
|
| + def p_label_cont_error(self, p):
|
| + """label_cont : error label_cont"""
|
| + p[0] = p[2]
|
| + if self.parse_debug: DumpReduction('label_error', p)
|
| +
|
| +
|
| +#
|
| +# Members
|
| +#
|
| +# A member attribute or function of a struct or interface.
|
| +#
|
| + def p_member_attribute(self, p):
|
| + """member_attribute : modifiers SYMBOL SYMBOL """
|
| + typeref = self.BuildAttribute('TYPEREF', p[2])
|
| + children = ListFromConcat(p[1], typeref)
|
| + p[0] = self.BuildNamed('Member', p, 3, children)
|
| + if self.parse_debug: DumpReduction('attribute', p)
|
| +
|
| + def p_member_attribute_array(self, p):
|
| + """member_attribute : modifiers SYMBOL arrays SYMBOL """
|
| + typeref = self.BuildAttribute('TYPEREF', p[2])
|
| + children = ListFromConcat(p[1], typeref, p[3])
|
| + p[0] = self.BuildNamed('Member', p, 4, children)
|
| + if self.parse_debug: DumpReduction('attribute', p)
|
| +
|
| + def p_member_function(self, p):
|
| + """member_function : modifiers SYMBOL SYMBOL param_list"""
|
| + typeref = self.BuildAttribute('TYPEREF', p[2])
|
| + children = ListFromConcat(p[1], typeref, p[4])
|
| + p[0] = self.BuildNamed('Member', p, 3, children)
|
| + if self.parse_debug: DumpReduction('function', p)
|
| +
|
| +#
|
| # Interface
|
| #
|
| # An interface is a named collection of functions.
|
| #
|
| def p_interface_block(self, p):
|
| - """interface_block : modifiers INTERFACE SYMBOL '{' member_list '}' ';'"""
|
| - p[0] = self.BuildProduction('Interface', p, 3, ListFromConcat(p[1], p[5]))
|
| + """interface_block : modifiers INTERFACE SYMBOL '{' interface_list '}' ';'"""
|
| + p[0] = self.BuildNamed('Interface', p, 3, ListFromConcat(p[1], p[5]))
|
| if self.parse_debug: DumpReduction('interface_block', p)
|
|
|
| - def p_member_list(self, p):
|
| - """member_list : member_function member_list
|
| - | """
|
| + def p_interface_list(self, p):
|
| + """interface_list : member_function ';' interface_list
|
| + | """
|
| if len(p) > 1 :
|
| - p[0] = ListFromConcat(p[1], p[2])
|
| - if self.parse_debug: DumpReduction('member_list', p)
|
| + p[0] = ListFromConcat(p[1], p[3])
|
| + if self.parse_debug: DumpReduction('interface_list', p)
|
|
|
| - def p_member_function(self, p):
|
| - """member_function : modifiers typeref SYMBOL '(' param_list ')' ';'"""
|
| - children = ListFromConcat(p[1], p[2], p[5])
|
| - p[0] = self.BuildProduction('Function', p, 3, children)
|
| - if self.parse_debug: DumpReduction('member_function', p)
|
| -
|
| - def p_member_error(self, p):
|
| - """member_list : error member_list"""
|
| + def p_interface_error(self, p):
|
| + """interface_list : error interface_list"""
|
| p[0] = p[2]
|
|
|
| #
|
| @@ -532,22 +631,20 @@
|
| #
|
| def p_struct_block(self, p):
|
| """struct_block : modifiers STRUCT SYMBOL '{' struct_list '}' ';'"""
|
| - Type = self.BuildExtAttribute('TYPEREF', 'struct')
|
| - children = ListFromConcat(Type, p[1], p[5])
|
| - p[0] = self.BuildProduction('Struct', p, 3, children)
|
| + children = ListFromConcat(p[1], p[5])
|
| + p[0] = self.BuildNamed('Struct', p, 3, children)
|
| if self.parse_debug: DumpReduction('struct_block', p)
|
|
|
| def p_struct_list(self, p):
|
| - """struct_list : modifiers typeref SYMBOL ';' struct_list
|
| - | """
|
| - if len(p) > 1:
|
| - member = self.BuildProduction('Member', p, 3, ListFromConcat(p[1], p[2]))
|
| - p[0] = ListFromConcat(member, p[5])
|
| - if self.parse_debug: DumpReduction('struct_list', p)
|
| + """struct_list : member_attribute ';' struct_list
|
| + | member_function ';' struct_list
|
| + |"""
|
| + if len(p) > 1: p[0] = ListFromConcat(p[1], p[3])
|
|
|
| + def p_struct_error(self, p):
|
| + """struct_list : error struct_list"""
|
| + p[0] = p[2]
|
|
|
| -
|
| -
|
| #
|
| # Parser Errors
|
| #
|
| @@ -581,7 +678,6 @@
|
|
|
| # Log the error
|
| ErrOut.LogLine(filename, lineno, pos, msg)
|
| - self.parse_errors += 1
|
|
|
| def Warn(self, node, msg):
|
| WarnOut.LogLine(node.filename, node.lineno, node.pos, msg)
|
| @@ -619,9 +715,13 @@
|
| #
|
| def VerifyProduction(self, node):
|
| comment = node.GetOneOf('Comment')
|
| - if node.cls in ['Interface', 'Struct', 'Function'] and not comment:
|
| - self.Warn(node, 'Missing comment for %s.' % node)
|
| - if node.cls in ['Param']:
|
| + if node.cls in ['Interface', 'Struct', 'Member'] and not comment:
|
| + if not GetOption('wcomment') and not node.GetProperty('wcomment'):
|
| + self.Warn(node, 'Missing comment for %s.' % node)
|
| + elif node.cls in ['EnumItem'] and not node.GetProperty('VALUE'):
|
| + if not GetOption('wenum'):
|
| + self.Warn(node, 'Missing value for enumeration %s.' % node)
|
| + elif node.cls in ['Param']:
|
| found = False;
|
| for form in ['in', 'inout', 'out']:
|
| if node.GetProperty(form): found = True
|
| @@ -638,30 +738,60 @@
|
| # index - Index into the production of the name for the item being produced.
|
| # cls - The type of item being producted
|
| # childlist - The children of the new item
|
| - def BuildProduction(self, cls, p, index, childlist):
|
| - name = p[index]
|
| + def BuildProduction(self, cls, p, index, childlist=None):
|
| + if not childlist: childlist = []
|
| filename = self.lexobj.filename
|
| lineno = p.lineno(index)
|
| pos = p.lexpos(index)
|
| + out = IDLNode(cls, filename, lineno, pos, childlist)
|
| if self.build_debug:
|
| - InfoOut.Log("Building %s(%s)" % (cls, name))
|
| - out = IDLNode(cls, name, filename, lineno, pos, childlist)
|
| + InfoOut.Log("Building %s" % out)
|
| self.VerifyProduction(out)
|
| return out
|
|
|
| + def BuildNamed(self, cls, p, index, childlist=None):
|
| + if not childlist: childlist = []
|
| + childlist.append(self.BuildAttribute('NAME', p[index]))
|
| + return self.BuildProduction(cls, p, index, childlist)
|
| +
|
| + def BuildComment(self, cls, p, index):
|
| + name = p[index]
|
| +
|
| + # Remove comment markers
|
| + if name[:2] == '//':
|
| + # For C++ style, remove the preceding '//'
|
| + form = 'cc'
|
| + name = name[2:].rstrip()
|
| + else:
|
| + # For C style, remove ending '*/''
|
| + form = 'c'
|
| + lines = []
|
| + for line in name[:-2].split('\n'):
|
| + # Remove characters until start marker for this line '*' if found
|
| + # otherwise it should be blank.
|
| + offs = line.find('*')
|
| + if offs >= 0:
|
| + line = line[offs + 1:].rstrip()
|
| + else:
|
| + line = ''
|
| + lines.append(line)
|
| + name = '\n'.join(lines)
|
| +
|
| + childlist = [self.BuildAttribute('NAME', name),
|
| + self.BuildAttribute('FORM', form)]
|
| + return self.BuildProduction(cls, p, index, childlist)
|
| +
|
| #
|
| -# BuildExtAttribute
|
| +# BuildAttribute
|
| #
|
| # An ExtendedAttribute is a special production that results in a property
|
| # which is applied to the adjacent item. Attributes have no children and
|
| # instead represent key/value pairs.
|
| #
|
| - def BuildExtAttribute(self, name, value):
|
| - if self.build_debug:
|
| - InfoOut.Log("Adding ExtAttribute %s = %s" % (name, str(value)))
|
| - out = IDLAttribute(name, value)
|
| - return out
|
| + def BuildAttribute(self, key, val):
|
| + return IDLAttribute(key, val)
|
|
|
| +
|
| #
|
| # ParseData
|
| #
|
| @@ -684,19 +814,22 @@
|
| # Loads a new file into the lexer and attemps to parse it.
|
| #
|
| def ParseFile(self, filename):
|
| - loadname = os.path.join(GetOption('srcdir'), filename)
|
| - data = open(loadname).read()
|
| + data = open(filename).read()
|
| if self.verbose:
|
| InfoOut.Log("Parsing %s" % filename)
|
| try:
|
| out = self.ParseData(data, filename)
|
| - return StageResult(filename, out, self.parse_errors)
|
|
|
| + # If we have a src root specified, remove it from the path
|
| + srcroot = GetOption('srcroot')
|
| + if srcroot and filename.find(srcroot) == 0:
|
| + filename = filename[len(srcroot) + 1:]
|
| + return IDLFile(filename, out, self.parse_errors)
|
| +
|
| except Exception as e:
|
| ErrOut.LogLine(filename, self.last.lineno, self.last.lexpos,
|
| 'Internal parsing error - %s.' % str(e))
|
| raise
|
| - return StageResult(filename, [], self.parse_errors)
|
|
|
|
|
|
|
| @@ -708,19 +841,20 @@
|
| def FlattenTree(node):
|
| add_self = False
|
| out = []
|
| - for cls in node.children.keys():
|
| - if cls == 'Comment':
|
| + for child in node.children:
|
| + if child.IsA('Comment'):
|
| add_self = True
|
| else:
|
| - for c in node.children[cls]:
|
| - out.extend(FlattenTree(c))
|
| + out.extend(FlattenTree(child))
|
|
|
| if add_self:
|
| out = [str(node)] + out
|
| return out
|
|
|
|
|
| -def TestErrors(filename, nodelist):
|
| +def TestErrors(filename, filenode):
|
| + nodelist = filenode.GetChildren()
|
| +
|
| lexer = IDLLexer()
|
| data = open(filename).read()
|
| lexer.SetData(filename, data)
|
| @@ -731,12 +865,12 @@
|
| tok = lexer.lexobj.token()
|
| if tok == None: break
|
| if tok.type == 'COMMENT':
|
| - args = tok.value.split()
|
| - if args[1] == 'OK':
|
| - pass_comments.append((tok.lineno, ' '.join(args[2:-1])))
|
| + args = tok.value[3:-3].split()
|
| + if args[0] == 'OK':
|
| + pass_comments.append((tok.lineno, ' '.join(args[1:])))
|
| else:
|
| - if args[1] == 'FAIL':
|
| - fail_comments.append((tok.lineno, ' '.join(args[2:-1])))
|
| + if args[0] == 'FAIL':
|
| + fail_comments.append((tok.lineno, ' '.join(args[1:])))
|
| obj_list = []
|
| for node in nodelist:
|
| obj_list.extend(FlattenTree(node))
|
| @@ -797,23 +931,24 @@
|
| ErrOut.SetConsole(False)
|
| ErrOut.SetCapture(True)
|
|
|
| - result = parser.ParseFile(filename)
|
| + filenode = parser.ParseFile(filename)
|
|
|
| # Renable output
|
| ErrOut.SetConsole(True)
|
| ErrOut.SetCapture(False)
|
|
|
| # Compare captured errors
|
| - return TestErrors(filename, result.out)
|
| + return TestErrors(filename, filenode)
|
|
|
|
|
| -def TestErrorFiles():
|
| +def TestErrorFiles(filter):
|
| idldir = os.path.split(sys.argv[0])[0]
|
| idldir = os.path.join(idldir, 'test_parser', '*.idl')
|
| filenames = glob.glob(idldir)
|
| parser = IDLParser()
|
| total_errs = 0
|
| for filename in filenames:
|
| + if filter and filename not in filter: continue
|
| errs = TestFile(parser, filename)
|
| if errs:
|
| ErrOut.Log("%s test failed with %d error(s)." % (filename, errs))
|
| @@ -825,20 +960,31 @@
|
| InfoOut.Log("Passed parsing test.")
|
| return total_errs
|
|
|
| -def TestNamespaceFiles():
|
| +def TestNamespaceFiles(filter):
|
| idldir = os.path.split(sys.argv[0])[0]
|
| idldir = os.path.join(idldir, 'test_namespace', '*.idl')
|
| filenames = glob.glob(idldir)
|
| + testnames = []
|
|
|
| + for filename in filenames:
|
| + if filter and filename not in filter: continue
|
| + testnames.append(filename)
|
| +
|
| + # If we have no files to test, then skip this test
|
| + if not testnames:
|
| + InfoOut.Log('No files to test for namespace.')
|
| + return 0
|
| +
|
| InfoOut.SetConsole(False)
|
| - result = ParseFiles(filenames)
|
| + ast = ParseFiles(testnames)
|
| InfoOut.SetConsole(True)
|
|
|
| - if result.errs:
|
| + errs = ast.GetProperty('ERRORS')
|
| + if errs:
|
| ErrOut.Log("Failed namespace test.")
|
| else:
|
| InfoOut.Log("Passed namespace test.")
|
| - return result.errs
|
| + return errs
|
|
|
|
|
| def ParseFiles(filenames):
|
| @@ -847,47 +993,35 @@
|
| errors = 0
|
|
|
| for filename in filenames:
|
| - result = parser.ParseFile(filename)
|
| - if result.errs:
|
| - ErrOut.Log("%d error(s) parsing %s." % (result.errs, filename))
|
| - errors += result.errs
|
| - else:
|
| + filenode = parser.ParseFile(filename)
|
| + filenodes.append(filenode)
|
| + if GetOption('verbose'):
|
| InfoOut.Log("Parsed %s." % filename)
|
| - filenode = IDLNode('File', filename, filename, 1, 0, result.out)
|
| - filenodes.append(filenode)
|
|
|
| ast = IDLAst(filenodes)
|
| + if GetOption('dump_tree'): ast.Dump(0)
|
| + return ast
|
|
|
| - # Build the links
|
| - ast.BuildTree(None)
|
|
|
| - # Resolve type references
|
| - errors += ast.Resolve()
|
| -
|
| - ast.Resolve()
|
| - return StageResult('Parsing', ast, errors)
|
| -
|
| -
|
| def Main(args):
|
| filenames = ParseOptions(args)
|
|
|
| # If testing...
|
| if GetOption('test'):
|
| - errs = TestErrorFiles()
|
| - errs = TestNamespaceFiles()
|
| + errs = TestErrorFiles(filenames)
|
| + errs = TestNamespaceFiles(filenames)
|
| if errs:
|
| ErrOut.Log("Parser failed with %d errors." % errs)
|
| return -1
|
| return 0
|
|
|
| # Otherwise, build the AST
|
| - result = ParseFiles(filenames)
|
| - if GetOption('dump_tree'):
|
| - result.out.Dump(0)
|
| - if result.errs:
|
| - ErrOut.Log('Found %d error(s).' % result.errors);
|
| + ast = ParseFiles(filenames)
|
| + errs = ast.GetProperty('ERRORS')
|
| + if errs:
|
| + ErrOut.Log('Found %d error(s).' % errs);
|
| InfoOut.Log("%d files processed." % len(filenames))
|
| - return result.errs
|
| + return errs
|
|
|
| if __name__ == '__main__':
|
| sys.exit(Main(sys.argv[1:]))
|
|
|