summaryrefslogtreecommitdiffstats
path: root/tools/idl_parser
diff options
context:
space:
mode:
authornoelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-12 18:48:47 +0000
committernoelallen@google.com <noelallen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-12 18:48:47 +0000
commitac7b49d82dee3e690968139b610553386f6f1f3c (patch)
tree3701977bff91385289785992d6f016aa2ed66ee9 /tools/idl_parser
parent7a54a4316797f7afebeb013b20631f90bba9eecb (diff)
downloadchromium_src-ac7b49d82dee3e690968139b610553386f6f1f3c.zip
chromium_src-ac7b49d82dee3e690968139b610553386f6f1f3c.tar.gz
chromium_src-ac7b49d82dee3e690968139b610553386f6f1f3c.tar.bz2
Add WebIDL and Pepper compliant lexer/parser tool.
This CL is the first step towards supporting automatic doc generation. This lexer more closely follows the WebIDL spec. Please review idl_node, idl_parser, idl_node idl_log.py is unchanged from the original This is a complete re-write of the original lexer/parser, as well as simplifications to IDLNode. All *.in and *.idl files are for test purposes only. To test: python idl_lexer.py OR python idl_parser.py NOTRY=true R=sehr@chromium.org BUG=224150 Review URL: https://codereview.chromium.org/13498002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@193973 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/idl_parser')
-rwxr-xr-xtools/idl_parser/idl_lexer.py88
-rwxr-xr-xtools/idl_parser/idl_node.py217
-rwxr-xr-xtools/idl_parser/idl_parser.py1029
-rwxr-xr-xtools/idl_parser/idl_parser_test.py61
-rw-r--r--tools/idl_parser/idl_ppapi_lexer.py41
-rwxr-xr-xtools/idl_parser/run_tests.py13
-rw-r--r--tools/idl_parser/test_lexer/keywords.in3
-rw-r--r--tools/idl_parser/test_parser/callback.idl116
-rw-r--r--tools/idl_parser/test_parser/dictionary.idl95
-rw-r--r--tools/idl_parser/test_parser/enum.idl119
-rw-r--r--tools/idl_parser/test_parser/exception.idl87
-rw-r--r--tools/idl_parser/test_parser/implements.idl52
-rw-r--r--tools/idl_parser/test_parser/interface.idl127
-rw-r--r--tools/idl_parser/test_parser/typedef.idl190
14 files changed, 2181 insertions, 57 deletions
diff --git a/tools/idl_parser/idl_lexer.py b/tools/idl_parser/idl_lexer.py
index 9a07ac6..aa0da06 100755
--- a/tools/idl_parser/idl_lexer.py
+++ b/tools/idl_parser/idl_lexer.py
@@ -100,31 +100,24 @@ class IDLLexer(object):
'void' : 'VOID'
}
- # Add keywords
- for key in keywords:
- tokens.append(keywords[key])
-
- # 'literals' is a value expected by lex which specifies a list of valid
- # literal tokens, meaning the token type and token value are identical.
- literals = '"*.(){}[],;:=+-/~|&^?<>'
-
# Token definitions
#
# Lex assumes any value or function in the form of 't_<TYPE>' represents a
# regular expression where a match will emit a token of type <TYPE>. In the
# case of a function, the function is called when a match is made. These
# definitions come from WebIDL.
+ def t_ELLIPSIS(self, t):
+ r'\.\.\.'
+ return t
- # 't_ignore' is a special match of items to ignore
- t_ignore = ' \t'
+ def t_float(self, t):
+ r'-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)'
+ return t
- # Ellipsis operator
- t_ELLIPSIS = r'\.\.\.'
+ def t_integer(self, t):
+ r'-?(0([0-7]*|[Xx][0-9A-Fa-f]+)|[1-9][0-9]*)'
+ return t
- # Constant values
- t_integer = r'-?(0([0-7]*|[Xx][0-9A-Fa-f]+)|[1-9][0-9]*)'
- t_float = r'-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)'
- t_float += r'([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)'
# A line ending '\n', we use this to increment the line number
def t_LINE_END(self, t):
@@ -160,7 +153,7 @@ class IDLLexer(object):
def t_ANY_error(self, t):
msg = 'Unrecognized input'
- line = self.lexobj.lineno
+ line = self.Lexer().lineno
# If that line has not been accounted for, then we must have hit
# EoF, so compute the beginning of the line that caused the problem.
@@ -169,10 +162,10 @@ class IDLLexer(object):
word = t.value.split()[0]
offs = self.lines[line - 1].find(word)
# Add the computed line's starting position
- self.index.append(self.lexobj.lexpos - offs)
+ self.index.append(self.Lexer().lexpos - offs)
msg = 'Unexpected EoF reached after'
- pos = self.lexobj.lexpos - self.index[line]
+ pos = self.Lexer().lexpos - self.index[line]
out = self.ErrorMessage(line, pos, msg)
sys.stderr.write(out + '\n')
self._lex_errors += 1
@@ -183,13 +176,13 @@ class IDLLexer(object):
# of multiple lines, tokens can not exist on any of the lines except the
# last one, so the recorded value for previous lines are unused. We still
# fill the array however, to make sure the line count is correct.
- self.lexobj.lineno += count
+ self.Lexer().lineno += count
for _ in range(count):
- self.index.append(self.lexobj.lexpos)
+ self.index.append(self.Lexer().lexpos)
def FileLineMsg(self, line, msg):
# Generate a message containing the file and line number of a token.
- filename = self.lexobj.filename
+ filename = self.Lexer().filename
if filename:
return "%s(%d) : %s" % (filename, line + 1, msg)
return "<BuiltIn> : %s" % msg
@@ -213,7 +206,7 @@ class IDLLexer(object):
# against the leaf paterns.
#
def token(self):
- tok = self.lexobj.token()
+ tok = self.Lexer().token()
if tok:
self.last = tok
return tok
@@ -222,21 +215,60 @@ class IDLLexer(object):
def GetTokens(self):
outlist = []
while True:
- t = self.lexobj.token()
+ t = self.Lexer().token()
if not t:
break
outlist.append(t)
return outlist
def Tokenize(self, data, filename='__no_file__'):
- self.lexobj.filename = filename
- self.lexobj.input(data)
+ lexer = self.Lexer()
+ lexer.lineno = 1
+ lexer.filename = filename
+ lexer.input(data)
self.lines = data.split('\n')
+ def KnownTokens(self):
+ return self.tokens
+
+ def Lexer(self):
+ if not self._lexobj:
+ self._lexobj = lex.lex(object=self, lextab=None, optimize=0)
+ return self._lexobj
+
+ def _AddConstDefs(self):
+ # 'literals' is a value expected by lex which specifies a list of valid
+ # literal tokens, meaning the token type and token value are identical.
+ self.literals = r'"*.(){}[],;:=+-/~|&^?<>'
+ self.t_ignore = ' \t'
+
+ def _AddToken(self, token):
+ if token in self.tokens:
+ raise RuntimeError('Same token: ' + token)
+ self.tokens.append(token)
+
+ def _AddTokens(self, tokens):
+ for token in tokens:
+ self._AddToken(token)
+
+ def _AddKeywords(self, keywords):
+ for key in keywords:
+ value = key.upper()
+ self._AddToken(value)
+ self.keywords[key] = value
+
def __init__(self):
self.index = [0]
self._lex_errors = 0
self.linex = []
self.filename = None
- self.lexobj = lex.lex(object=self, lextab=None, optimize=0)
-
+ self.keywords = {}
+ self.tokens = []
+ self._AddConstDefs()
+ self._AddTokens(IDLLexer.tokens)
+ self._AddKeywords(IDLLexer.keywords)
+ self._lexobj = None
+
+# If run by itself, attempt to build the lexer
+if __name__ == '__main__':
+ lexer = IDLLexer()
diff --git a/tools/idl_parser/idl_node.py b/tools/idl_parser/idl_node.py
new file mode 100755
index 0000000..2e31d9a
--- /dev/null
+++ b/tools/idl_parser/idl_node.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+#
+# IDL Node
+#
+# IDL Node defines the IDLAttribute and IDLNode objects which are constructed
+# by the parser as it processes the various 'productions'. The IDLAttribute
+# objects are assigned to the IDLNode's property dictionary instead of being
+# applied as children of The IDLNodes, so they do not exist in the final tree.
+# The AST of IDLNodes is the output from the parsing state and will be used
+# as the source data by the various generators.
+#
+
+
+#
+# CopyToList
+#
+# Takes an input item, list, or None, and returns a new list of that set.
+def CopyToList(item):
+ # If the item is 'Empty' make it an empty list
+ if not item:
+ item = []
+
+ # If the item is not a list
+ if type(item) is not type([]):
+ item = [item]
+
+ # Make a copy we can modify
+ return list(item)
+
+
+# IDLSearch
+#
+# A temporary object used by the parsing process to hold an Extended Attribute
+# which will be passed as a child to a standard IDLNode.
+#
+class IDLSearch(object):
+ def __init__(self):
+ self.depth = 0
+
+ def Enter(self, node):
+ pass
+
+ def Exit(self, node):
+ pass
+
+
+# IDLAttribute
+#
+# A temporary object used by the parsing process to hold an Extended Attribute
+# which will be passed as a child to a standard IDLNode.
+#
+class IDLAttribute(object):
+ def __init__(self, name, value):
+ self._cls = 'Property'
+ self.name = name
+ self.value = value
+
+ def __str__(self):
+ return '%s=%s' % (self.name, self.value)
+
+ def GetClass(self):
+ return self._cls
+
+#
+# IDLNode
+#
+# This class implements the AST tree, providing the associations between
+# parents and children. It also contains a namepsace and propertynode to
+# allow for look-ups. IDLNode is derived from IDLRelease, so it is
+# version aware.
+#
+class IDLNode(object):
+ def __init__(self, cls, filename, lineno, pos, children=None):
+ self._cls = cls
+ self._properties = {
+ 'ERRORS' : [],
+ 'WARNINGS': [],
+ 'FILENAME': filename,
+ 'LINENO' : lineno,
+ 'POSSITION' : pos,
+ }
+
+ self._children = []
+ self._parent = None
+ self.AddChildren(children)
+
+#
+#
+#
+ # Return a string representation of this node
+ def __str__(self):
+ name = self.GetProperty('NAME','')
+ return '%s(%s)' % (self._cls, name)
+
+ def GetLogLine(self, msg):
+ filename, lineno = self.GetFileAndLine()
+ return '%s(%d) : %s\n' % (filename, lineno, msg)
+
+ # Log an error for this object
+ def Error(self, msg):
+ self.GetProperty('ERRORS').append(msg)
+ sys.stderr.write(self.GetLogLine('error: ' + msg))
+
+ # Log a warning for this object
+ def Warning(self, msg):
+ self.GetProperty('WARNINGS').append(msg)
+ sys.stdout.write(self.GetLogLine('warning:' + msg))
+
+ # Return file and line number for where node was defined
+ def GetFileAndLine(self):
+ return self.GetProperty('FILENAME'), self.GetProperty('LINENO')
+
+ def GetClass(self):
+ return self._cls
+
+ def GetName(self):
+ return self.GetProperty('NAME')
+
+ def GetParent(self):
+ return self._parent
+
+ def Traverse(self, search, filter_nodes):
+ if self._cls in filter_nodes:
+ return ''
+
+ search.Enter(self)
+ search.depth += 1
+ for child in self._children:
+ child.Traverse(search, filter_nodes)
+ search.depth -= 1
+ search.Exit(self)
+
+
+ def Tree(self, filter_nodes=None, accept_props=None):
+ class DumpTreeSearch(IDLSearch):
+ def __init__(self, props):
+ IDLSearch.__init__(self)
+ self.out = []
+ self.props = props
+
+ def Enter(self, node):
+ tab = ''.rjust(self.depth * 2)
+ self.out.append(tab + str(node))
+ if self.props:
+ for key, value in node.GetProperties().iteritems():
+ proplist = []
+ if key in self.props:
+ proplist.append(tab + ' %s: %s' % (key, str(value)))
+ if proplist:
+ self.out.append(tab + ' PROPERTIES')
+ self.out.extend(proplist)
+
+ if filter_nodes == None:
+ filter_nodes = ['Comment', 'Copyright']
+
+ search = DumpTreeSearch(accept_props)
+ self.Traverse(search, filter_nodes)
+ return search.out
+
+#
+# Search related functions
+#
+ # Check if node is of a given type
+ def IsA(self, *typelist):
+ if self._cls in typelist:
+ return True
+ return False
+
+ # Get a list of all children
+ def GetChildren(self):
+ return self._children
+
+ def GetListOf(self, *keys):
+ out = []
+ for child in self.GetChildren():
+ if child.GetClass() in keys:
+ out.append(child)
+ return out
+
+ def GetOneOf(self, *keys):
+ out = self.GetListOf(*keys)
+ if out:
+ return out[0]
+ return None
+
+ def AddChildren(self, children):
+ children = CopyToList(children)
+ for child in children:
+ if not child:
+ continue
+ if type(child) == IDLAttribute:
+ self.SetProperty(child.name, child.value)
+ continue
+ if type(child) == IDLNode:
+ child._parent = self
+ self._children.append(child)
+ continue
+ raise RuntimeError('Adding child of type .\n' % type(child).__name__)
+
+
+#
+# Property Functions
+#
+ def SetProperty(self, name, val):
+ self._properties[name] = val
+
+ def GetProperty(self, name, default=None):
+ return self._properties.get(name, default)
+
+ def GetProperties(self):
+ return self._properties
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py
new file mode 100755
index 0000000..3e57295
--- /dev/null
+++ b/tools/idl_parser/idl_parser.py
@@ -0,0 +1,1029 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Parser for PPAPI IDL """
+
+#
+# IDL Parser
+#
+# The parser is uses the PLY yacc library to build a set of parsing rules based
+# on WebIDL.
+#
+# WebIDL, and WebIDL grammar can be found at:
+# http://dev.w3.org/2006/webapi/WebIDL/
+# PLY can be found at:
+# http://www.dabeaz.com/ply/
+#
+# The parser generates a tree by recursively matching sets of items against
+# defined patterns. When a match is made, that set of items is reduced
+# to a new item. The new item can provide a match for parent patterns.
+# In this way an AST is built (reduced) depth first.
+#
+
+#
+# Disable check for line length and Member as Function due to how grammar rules
+# are defined with PLY
+#
+# pylint: disable=R0201
+# pylint: disable=C0301
+
+import os.path
+import sys
+import time
+
+from idl_lexer import IDLLexer
+from idl_node import IDLAttribute, IDLNode
+
+from ply import lex
+from ply import yacc
+
+#
+# ERROR_REMAP
+#
+# Maps the standard error formula into a more friendly error message.
+#
+ERROR_REMAP = {
+ 'Unexpected ")" after "(".' : 'Empty argument list.',
+ 'Unexpected ")" after ",".' : 'Missing argument.',
+ 'Unexpected "}" after ",".' : 'Trailing comma in block.',
+ 'Unexpected "}" after "{".' : 'Unexpected empty block.',
+ '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.',
+}
+
+
+def Boolean(val):
+ """Convert to strict boolean type."""
+ if val:
+ return True
+ return False
+
+
+def ListFromConcat(*items):
+ """Generate list by concatenating inputs"""
+ itemsout = []
+ for item in items:
+ if item is None:
+ continue
+ if type(item) is not type([]):
+ itemsout.append(item)
+ else:
+ itemsout.extend(item)
+
+ return itemsout
+
+def ExpandProduction(p):
+ if type(p) == list:
+ return '[' + ', '.join([ExpandProduction(x) for x in p]) + ']'
+ if type(p) == IDLNode:
+ return 'Node:' + str(p)
+ if type(p) == IDLAttribute:
+ return 'Attr:' + str(p)
+ if type(p) == str:
+ return 'str:' + p
+ return '%s:%s' % (p.__class__.__name__, str(p))
+
+# TokenTypeName
+#
+# Generate a string which has the type and value of the token.
+#
+def TokenTypeName(t):
+ if t.type == 'SYMBOL':
+ return 'symbol %s' % t.value
+ 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'
+ if t.type == t.value:
+ return '"%s"' % t.value
+ if t.type == ',':
+ return 'Comma'
+ if t.type == 'identifier':
+ return 'identifier "%s"' % t.value
+ return 'keyword "%s"' % t.value
+
+
+#
+# IDL Parser
+#
+# The Parser inherits the from the Lexer to provide PLY with the tokenizing
+# definitions. Parsing patterns are encoded as functions where p_<name> is
+# is called any time a patern matching the function documentation is found.
+# Paterns are expressed in the form of:
+# """ <new item> : <item> ....
+# | <item> ...."""
+#
+# Where new item is the result of a match against one or more sets of items
+# separated by the "|".
+#
+# The function is called with an object 'p' where p[0] is the output object
+# and p[n] is the set of inputs for positive values of 'n'. Len(p) can be
+# used to distinguish between multiple item sets in the pattern.
+#
+# For more details on parsing refer to the PLY documentation at
+# http://www.dabeaz.com/ply/
+#
+# The parser is based on the WebIDL standard. See:
+# http://www.w3.org/TR/WebIDL/#idl-grammar
+#
+# The various productions are annotated so that the WHOLE number greater than
+# zero in the comment denotes the matching WebIDL grammar definition.
+#
+# Productions with a fractional component in the comment denote additions to
+# the WebIDL spec, such as comments.
+#
+
+
+class IDLParser(object):
+#
+# We force all input files to start with two comments. The first comment is a
+# Copyright notice followed by a file comment and finally by file level
+# productions.
+#
+ # [0] Insert a TOP definition for Copyright and Comments
+ def p_Top(self, p):
+ """Top : COMMENT COMMENT Definitions"""
+ Copyright = self.BuildComment('Copyright', p, 1)
+ Filedoc = self.BuildComment('Comment', p, 2)
+ p[0] = ListFromConcat(Copyright, Filedoc, p[3])
+
+ # [0.1] Add support for Multiple COMMENTS
+ def p_Comments(self, p):
+ """Comments : CommentsRest"""
+ if len(p) > 1:
+ p[0] = p[1]
+
+ # [0.2] Produce a COMMENT and aggregate sibling comments
+ def p_CommentsRest(self, p):
+ """CommentsRest : COMMENT CommentsRest
+ | """
+ if len(p) > 1:
+ p[0] = ListFromConcat(self.BuildComment('Comment', p, 1), p[2])
+
+
+#
+#The parser is based on the WebIDL standard. See:
+# http://www.w3.org/TR/WebIDL/#idl-grammar
+#
+ # [1]
+ def p_Definitions(self, p):
+ """Definitions : ExtendedAttributeList Definition Definitions
+ | """
+ if len(p) > 1:
+ p[2].AddChildren(p[1])
+ p[0] = ListFromConcat(p[2], p[3])
+
+ # [2] Add INLINE definition
+ def p_Definition(self, p):
+ """Definition : CallbackOrInterface
+ | Partial
+ | Dictionary
+ | Exception
+ | Enum
+ | Typedef
+ | ImplementsStatement"""
+ p[0] = p[1]
+
+ # [2.1] Error recovery for definition
+ def p_DefinitionError(self, p):
+ """Definition : error ';'"""
+ p[0] = self.BuildError(p, 'Definition')
+
+ # [3]
+ def p_CallbackOrInterface(self, p):
+ """CallbackOrInterface : CALLBACK CallbackRestOrInterface
+ | Interface"""
+ if len(p) > 2:
+ p[0] = p[2]
+ else:
+ p[0] = p[1]
+
+ # [4]
+ def p_CallbackRestOrInterface(self, p):
+ """CallbackRestOrInterface : CallbackRest
+ | Interface"""
+ p[0] = p[1]
+
+ # [5]
+ def p_Interface(self, p):
+ """Interface : INTERFACE identifier Inheritance '{' InterfaceMembers '}' ';'"""
+ p[0] = self.BuildNamed('Interface', p, 2, ListFromConcat(p[3], p[5]))
+
+ # [6] Error recovery for PARTIAL
+ def p_Partial(self, p):
+ """Partial : PARTIAL PartialDefinition"""
+ p[2].AddChildren(self.BuildTrue('Partial'))
+ p[0] = p[2]
+
+ # [6.1] Error recovery for Enums
+ def p_PartialError(self, p):
+ """Partial : PARTIAL error"""
+ p[0] = self.BuildError(p, 'Partial')
+
+ # [7]
+ def p_PartialDefinition(self, p):
+ """PartialDefinition : PartialDictionary
+ | PartialInterface"""
+ p[0] = p[1]
+
+ # [8]
+ def p_PartialInterface(self, p):
+ """PartialInterface : INTERFACE identifier '{' InterfaceMembers '}' ';'"""
+ p[0] = self.BuildNamed('Interface', p, 2, p[4])
+
+ # [9]
+ def p_InterfaceMembers(self, p):
+ """InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers
+ |"""
+ if len(p) > 1:
+ p[2].AddChildren(p[1])
+ p[0] = ListFromConcat(p[2], p[3])
+
+ # [10]
+ def p_InterfaceMember(self, p):
+ """InterfaceMember : Const
+ | AttributeOrOperation"""
+ p[0] = p[1]
+
+ # [11]
+ def p_Dictionary(self, p):
+ """Dictionary : DICTIONARY identifier Inheritance '{' DictionaryMembers '}' ';'"""
+ p[0] = self.BuildNamed('Dictionary', p, 2, ListFromConcat(p[3], p[5]))
+
+ # [11.1] Error recovery for regular Dictionary
+ def p_DictionaryError(self, p):
+ """Dictionary : DICTIONARY error ';'"""
+ p[0] = self.BuildError(p, 'Dictionary')
+
+ # [12]
+ def p_DictionaryMembers(self, p):
+ """DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers
+ |"""
+ if len(p) > 1:
+ p[2].AddChildren(p[1])
+ p[0] = ListFromConcat(p[2], p[3])
+
+ # [13]
+ def p_DictionaryMember(self, p):
+ """DictionaryMember : Type identifier Default ';'"""
+ p[0] = self.BuildNamed('Key', p, 2, ListFromConcat(p[1], p[3]))
+
+ # [14]
+ def p_PartialDictionary(self, p):
+ """PartialDictionary : DICTIONARY identifier '{' DictionaryMembers '}' ';'"""
+ partial = self.BuildTrue('Partial')
+ p[0] = self.BuildNamed('Dictionary', p, 2, ListFromConcat(p[4], partial))
+
+ # [14.1] Error recovery for Partial Dictionary
+ def p_PartialDictionaryError(self, p):
+ """PartialDictionary : DICTIONARY error ';'"""
+ p[0] = self.BuildError(p, 'PartialDictionary')
+
+ # [15]
+ def p_Default(self, p):
+ """Default : '=' DefaultValue
+ |"""
+ if len(p) > 1:
+ p[0] = self.BuildProduction('Default', p, 2, p[2])
+
+ # [16]
+ def p_DefaultValue(self, p):
+ """DefaultValue : ConstValue
+ | string"""
+ if type(p[1]) == str:
+ p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'DOMString'),
+ self.BuildAttribute('NAME', p[1]))
+ else:
+ p[0] = p[1]
+
+ # [17]
+ def p_Exception(self, p):
+ """Exception : EXCEPTION identifier Inheritance '{' ExceptionMembers '}' ';'"""
+ p[0] = self.BuildNamed('Exception', p, 2, ListFromConcat(p[3], p[5]))
+
+ # [18]
+ def p_ExceptionMembers(self, p):
+ """ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers
+ |"""
+ if len(p) > 1:
+ p[2].AddChildren(p[1])
+ p[0] = ListFromConcat(p[2], p[3])
+
+ # [18.1] Error recovery for ExceptionMembers
+ def p_ExceptionMembersError(self, p):
+ """ExceptionMembers : error"""
+ p[0] = self.BuildError(p, 'ExceptionMembers')
+
+ # [19]
+ def p_Inheritance(self, p):
+ """Inheritance : ':' identifier
+ |"""
+ if len(p) > 1:
+ p[0] = self.BuildNamed('Inherit', p, 2)
+
+ # [20]
+ def p_Enum(self, p):
+ """Enum : ENUM identifier '{' EnumValueList '}' ';'"""
+ p[0] = self.BuildNamed('Enum', p, 2, p[4])
+
+ # [20.1] Error recovery for Enums
+ def p_EnumError(self, p):
+ """Enum : ENUM error ';'"""
+ p[0] = self.BuildError(p, 'Enum')
+
+ # [21]
+ def p_EnumValueList(self, p):
+ """EnumValueList : ExtendedAttributeList string EnumValues"""
+ enum = self.BuildNamed('EnumItem', p, 2, p[1])
+ p[0] = ListFromConcat(enum, p[3])
+
+ # [22]
+ def p_EnumValues(self, p):
+ """EnumValues : ',' ExtendedAttributeList string EnumValues
+ |"""
+ if len(p) > 1:
+ enum = self.BuildNamed('EnumItem', p, 3, p[2])
+ p[0] = ListFromConcat(enum, p[4])
+
+ # [23]
+ def p_CallbackRest(self, p):
+ """CallbackRest : identifier '=' ReturnType '(' ArgumentList ')' ';'"""
+ arguments = self.BuildProduction('Arguments', p, 4, p[5])
+ p[0] = self.BuildNamed('Callback', p, 1, ListFromConcat(p[3], arguments))
+
+ # [24]
+ def p_Typedef(self, p):
+ """Typedef : TYPEDEF ExtendedAttributeList Type identifier ';'"""
+ p[0] = self.BuildNamed('Typedef', p, 4, ListFromConcat(p[2], p[3]))
+
+ # [24.1] Error recovery for Typedefs
+ def p_TypedefError(self, p):
+ """Typedef : TYPEDEF error ';'"""
+ p[0] = self.BuildError(p, 'Typedef')
+
+ # [25]
+ def p_ImplementsStatement(self, p):
+ """ImplementsStatement : identifier IMPLEMENTS identifier ';'"""
+ name = self.BuildAttribute('REFERENCE', p[3])
+ p[0] = self.BuildNamed('Implements', p, 1, name)
+
+ # [26]
+ def p_Const(self, p):
+ """Const : CONST ConstType identifier '=' ConstValue ';'"""
+ value = self.BuildProduction('Value', p, 5, p[5])
+ p[0] = self.BuildNamed('Const', p, 3, ListFromConcat(p[2], value))
+
+ # [27]
+ def p_ConstValue(self, p):
+ """ConstValue : BooleanLiteral
+ | FloatLiteral
+ | integer
+ | null"""
+ if type(p[1]) == str:
+ p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'integer'),
+ self.BuildAttribute('NAME', p[1]))
+ else:
+ p[0] = p[1]
+
+ # [27.1] Add definition for NULL
+ def p_null(self, p):
+ """null : NULL"""
+ p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'NULL'),
+ self.BuildAttribute('NAME', 'NULL'))
+
+ # [28]
+ def p_BooleanLiteral(self, p):
+ """BooleanLiteral : TRUE
+ | FALSE"""
+ value = self.BuildAttribute('NAME', Boolean(p[1] == 'true'))
+ p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'boolean'), value)
+
+ # [29]
+ def p_FloatLiteral(self, p):
+ """FloatLiteral : float
+ | '-' INFINITY
+ | INFINITY
+ | NAN """
+ if len(p) > 2:
+ val = '-Infinity'
+ else:
+ val = p[1]
+ p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'float'),
+ self.BuildAttribute('VALUE', val))
+
+ # [30]
+ def p_AttributeOrOperation(self, p):
+ """AttributeOrOperation : STRINGIFIER StringifierAttributeOrOperation
+ | Attribute
+ | Operation"""
+ if len(p) > 2:
+ p[0] = p[2]
+ else:
+ p[0] = p[1]
+
+ # [31]
+ def p_StringifierAttributeOrOperation(self, p):
+ """StringifierAttributeOrOperation : Attribute
+ | OperationRest
+ | ';'"""
+ if p[1] == ';':
+ p[0] = self.BuildAttribute('STRINGIFIER', Boolean(True))
+ else:
+ p[0] = ListFromConcat(self.BuildAttribute('STRINGIFIER', p[1]), p[1])
+
+ # [32]
+ def p_Attribute(self, p):
+ """Attribute : Inherit ReadOnly ATTRIBUTE Type identifier ';'"""
+ p[0] = self.BuildNamed('Attribute', p, 5,
+ ListFromConcat(p[1], p[2], p[4]))
+
+ # [33]
+ def p_Inherit(self, p):
+ """Inherit : INHERIT
+ |"""
+ if len(p) > 1:
+ p[0] = self.BuildTrue('INHERIT')
+
+ # [34]
+ def p_ReadOnly(self, p):
+ """ReadOnly : READONLY
+ |"""
+ if len(p) > 1:
+ p[0] = self.BuildTrue('READONLY')
+
+ # [35]
+ def p_Operation(self, p):
+ """Operation : Qualifiers OperationRest"""
+ p[2].AddChildren(p[1])
+ p[0] = p[2]
+
+ # [36]
+ def p_Qualifiers(self, p):
+ """Qualifiers : STATIC
+ | Specials"""
+ if p[1] == 'static':
+ p[0] = self.BuildTrue('STATIC')
+ else:
+ p[0] = p[1]
+
+ # [37]
+ def p_Specials(self, p):
+ """Specials : Special Specials
+ | """
+ if len(p) > 1:
+ p[0] = ListFromConcat(p[1], p[2])
+
+ # [38]
+ def p_Special(self, p):
+ """Special : GETTER
+ | SETTER
+ | CREATOR
+ | DELETER
+ | LEGACYCALLER"""
+ p[0] = self.BuildTrue(p[1].upper())
+
+
+ # [39]
+ def p_OperationRest(self, p):
+ """OperationRest : ReturnType OptionalIdentifier '(' ArgumentList ')' ';'"""
+ arguments = self.BuildProduction('Arguments', p, 3, p[4])
+ p[0] = self.BuildNamed('Operation', p, 2, ListFromConcat(p[1], arguments))
+
+ # [40]
+ def p_OptionalIdentifier(self, p):
+ """OptionalIdentifier : identifier
+ |"""
+ if len(p) > 1:
+ p[0] = p[1]
+ else:
+ p[0] = '_unnamed_'
+
+ # [41]
+ def p_ArgumentList(self, p):
+ """ArgumentList : Argument Arguments
+ |"""
+ if len(p) > 1:
+ p[0] = ListFromConcat(p[1], p[2])
+
+ # [41.1] ArgumentList error recovery
+ def p_ArgumentListError(self, p):
+ """ArgumentList : error """
+ p[0] = self.BuildError(p, 'ArgumentList')
+
+ # [42]
+ def p_Arguments(self, p):
+ """Arguments : ',' Argument Arguments
+ |"""
+ if len(p) > 1:
+ p[0] = ListFromConcat(p[2], p[3])
+
+ # [43]
+ def p_Argument(self, p):
+ """Argument : ExtendedAttributeList OptionalOrRequiredArgument"""
+ p[2].AddChildren(p[1])
+ p[0] = p[2]
+
+
+ # [44]
+ def p_OptionalOrRequiredArgument(self, p):
+ """OptionalOrRequiredArgument : OPTIONAL Type ArgumentName Default
+ | Type Ellipsis ArgumentName"""
+ if len(p) > 4:
+ arg = self.BuildNamed('Argument', p, 3, ListFromConcat(p[2], p[4]))
+ arg.AddChildren(self.BuildTrue('OPTIONAL'))
+ else:
+ arg = self.BuildNamed('Argument', p, 3, ListFromConcat(p[1], p[2]))
+ p[0] = arg
+
+ # [45]
+ def p_ArgumentName(self, p):
+ """ArgumentName : ArgumentNameKeyword
+ | identifier"""
+ p[0] = p[1]
+
+ # [46]
+ def p_Ellipsis(self, p):
+ """Ellipsis : ELLIPSIS
+ |"""
+ if len(p) > 1:
+ p[0] = self.BuildNamed('Argument', p, 1)
+ p[0].AddChildren(self.BuildTrue('ELLIPSIS'))
+
+ # [47]
+ def p_ExceptionMember(self, p):
+ """ExceptionMember : Const
+ | ExceptionField"""
+ p[0] = p[1]
+
+ # [48]
+ def p_ExceptionField(self, p):
+ """ExceptionField : Type identifier ';'"""
+ p[0] = self.BuildNamed('ExceptionField', p, 2, p[1])
+
+ # [48.1] Error recovery for ExceptionMembers
+ def p_ExceptionFieldError(self, p):
+ """ExceptionField : error"""
+ p[0] = self.BuildError(p, 'ExceptionField')
+
+ # [49] Add optional comment field
+ def p_ExtendedAttributeList(self, p):
+ """ExtendedAttributeList : Comments '[' ExtendedAttribute ExtendedAttributes ']'
+ | Comments """
+ if len(p) > 2:
+ items = ListFromConcat(p[3], p[4])
+ attribs = self.BuildProduction('ExtAttributes', p, 2, items)
+ p[0] = ListFromConcat(p[1], attribs)
+ else:
+ p[0] = p[1]
+
+ # [50]
+ def p_ExtendedAttributes(self, p):
+ """ExtendedAttributes : ',' ExtendedAttribute ExtendedAttributes
+ |"""
+ if len(p) > 1:
+ p[0] = ListFromConcat(p[2], p[3])
+
+ # We only support:
+ # [ identifier ]
+ # [ identifier = identifier ]
+ # [ identifier ( ArgumentList )]
+ # [ identifier = identifier ( ArgumentList )]
+ # [51] map directly to 74-77
+ # [52-54, 56] are unsupported
+ def p_ExtendedAttribute(self, p):
+ """ExtendedAttribute : ExtendedAttributeNoArgs
+ | ExtendedAttributeArgList
+ | ExtendedAttributeIdent
+ | ExtendedAttributeNamedArgList"""
+ p[0] = p[1]
+
+ # [55]
+ def p_ArgumentNameKeyword(self, p):
+ """ArgumentNameKeyword : ATTRIBUTE
+ | CALLBACK
+ | CONST
+ | CREATOR
+ | DELETER
+ | DICTIONARY
+ | ENUM
+ | EXCEPTION
+ | GETTER
+ | IMPLEMENTS
+ | INHERIT
+ | LEGACYCALLER
+ | PARTIAL
+ | SETTER
+ | STATIC
+ | STRINGIFIER
+ | TYPEDEF
+ | UNRESTRICTED"""
+ p[0] = p[1]
+
+ # [57]
+ def p_Type(self, p):
+ """Type : SingleType
+ | UnionType TypeSuffix"""
+ if len(p) == 2:
+ p[0] = self.BuildProduction('Type', p, 1, p[1])
+ else:
+ p[0] = self.BuildProduction('Type', p, 1, ListFromConcat(p[1], p[2]))
+
+ # [58]
+ def p_SingleType(self, p):
+ """SingleType : NonAnyType
+ | ANY TypeSuffixStartingWithArray"""
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = ListFromConcat(self.BuildProduction('Any', p, 1), p[2])
+
+ # [59]
+ def p_UnionType(self, p):
+ """UnionType : '(' UnionMemberType OR UnionMemberType UnionMemberTypes ')'"""
+
+ # [60]
+ def p_UnionMemberType(self, p):
+ """UnionMemberType : NonAnyType
+ | UnionType TypeSuffix
+ | ANY '[' ']' TypeSuffix"""
+ # [61]
+ def p_UnionMemberTypes(self, p):
+ """UnionMemberTypes : OR UnionMemberType UnionMemberTypes
+ |"""
+
+ # [62] Moved DATE, DOMSTRING, OBJECT to PrimitiveType
+ def p_NonAnyType(self, p):
+ """NonAnyType : PrimitiveType TypeSuffix
+ | identifier TypeSuffix
+ | SEQUENCE '<' Type '>' Null"""
+ if len(p) == 3:
+ if type(p[1]) == str:
+ typeref = self.BuildNamed('Typeref', p, 1)
+ else:
+ typeref = p[1]
+ p[0] = ListFromConcat(typeref, p[2])
+
+ if len(p) == 6:
+ p[0] = self.BuildProduction('Sequence', p, 1, ListFromConcat(p[3], p[5]))
+
+
+ # [63]
+ def p_ConstType(self, p):
+ """ConstType : PrimitiveType Null
+ | identifier Null"""
+ if type(p[1]) == str:
+ p[0] = self.BuildNamed('Typeref', p, 1, p[2])
+ else:
+ p[1].AddChildren(p[2])
+ p[0] = p[1]
+
+
+ # [64]
+ def p_PrimitiveType(self, p):
+ """PrimitiveType : UnsignedIntegerType
+ | UnrestrictedFloatType
+ | BOOLEAN
+ | BYTE
+ | OCTET
+ | DOMSTRING
+ | DATE
+ | OBJECT"""
+ if type(p[1]) == str:
+ p[0] = self.BuildNamed('PrimitiveType', p, 1)
+ else:
+ p[0] = p[1]
+
+
+ # [65]
+ def p_UnrestrictedFloatType(self, p):
+ """UnrestrictedFloatType : UNRESTRICTED FloatType
+ | FloatType"""
+ if len(p) == 2:
+ typeref = self.BuildNamed('PrimitiveType', p, 1)
+ else:
+ typeref = self.BuildNamed('PrimitiveType', p, 2)
+ typeref.AddChildren(self.BuildTrue('UNRESTRICTED'))
+ p[0] = typeref
+
+
+ # [66]
+ def p_FloatType(self, p):
+ """FloatType : FLOAT
+ | DOUBLE"""
+ p[0] = p[1]
+
+ # [67]
+ def p_UnsignedIntegerType(self, p):
+ """UnsignedIntegerType : UNSIGNED IntegerType
+ | IntegerType"""
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = 'unsigned ' + p[2]
+
+ # [68]
+ def p_IntegerType(self, p):
+ """IntegerType : SHORT
+ | LONG OptionalLong"""
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = p[1] + p[2]
+
+ # [69]
+ def p_OptionalLong(self, p):
+ """OptionalLong : LONG
+ | """
+ if len(p) > 1:
+ p[0] = ' ' + p[1]
+ else:
+ p[0] = ''
+
+
+ # [70] Add support for sized array
+ def p_TypeSuffix(self, p):
+ """TypeSuffix : '[' integer ']' TypeSuffix
+ | '[' ']' TypeSuffix
+ | '?' TypeSuffixStartingWithArray
+ |"""
+ if len(p) == 5:
+ p[0] = self.BuildNamed('Array', p, 2, p[4])
+
+ if len(p) == 4:
+ p[0] = self.BuildProduction('Array', p, 1, p[3])
+
+ if len(p) == 3:
+ p[0] = ListFromConcat(self.BuildTrue('NULLABLE'), p[2])
+
+
+ # [71]
+ def p_TypeSuffixStartingWithArray(self, p):
+ """TypeSuffixStartingWithArray : '[' ']' TypeSuffix
+ | """
+ if len(p) > 1:
+ p[0] = self.BuildProduction('Array', p, 0, p[3])
+
+ # [72]
+ def p_Null(self, p):
+ """Null : '?'
+ |"""
+ if len(p) > 1:
+ p[0] = self.BuildTrue('NULLABLE')
+
+ # [73]
+ def p_ReturnType(self, p):
+ """ReturnType : Type
+ | VOID"""
+ if p[1] == 'void':
+ p[0] = self.BuildProduction('Type', p, 1)
+ p[0].AddChildren(self.BuildNamed('PrimitiveType', p, 1))
+ else:
+ p[0] = p[1]
+
+ # [74]
+ def p_ExtendedAttributeNoArgs(self, p):
+ """ExtendedAttributeNoArgs : identifier"""
+ p[0] = self.BuildNamed('ExtAttribute', p, 1)
+
+ # [75]
+ def p_ExtendedAttributeArgList(self, p):
+ """ExtendedAttributeArgList : identifier '(' ArgumentList ')'"""
+ arguments = self.BuildProduction('Arguments', p, 2, p[3])
+ p[0] = self.BuildNamed('ExtAttribute', p, 1, arguments)
+
+ # [76]
+ def p_ExtendedAttributeIdent(self, p):
+ """ExtendedAttributeIdent : identifier '=' identifier"""
+ value = self.BuildAttribute('VALUE', p[3])
+ p[0] = self.BuildNamed('ExtAttribute', p, 1, value)
+
+ # [77]
+ def p_ExtendedAttributeNamedArgList(self, p):
+ """ExtendedAttributeNamedArgList : identifier '=' identifier '(' ArgumentList ')'"""
+ args = self.BuildProduction('Arguments', p, 4, p[5])
+ value = self.BuildNamed('Call', p, 3, args)
+ p[0] = self.BuildNamed('ExtAttribute', p, 1, value)
+
+#
+# Parser Errors
+#
+# p_error is called whenever the parser can not find a pattern match for
+# a set of items from the current state. The p_error function defined here
+# is triggered logging an error, and parsing recovery happens as the
+# p_<type>_error functions defined above are called. This allows the parser
+# to continue so as to capture more than one error per file.
+#
+ def p_error(self, t):
+ if t:
+ lineno = t.lineno
+ pos = t.lexpos
+ prev = self.yaccobj.symstack[-1]
+ if type(prev) == lex.LexToken:
+ msg = "Unexpected %s after %s." % (
+ TokenTypeName(t), TokenTypeName(prev))
+ else:
+ msg = "Unexpected %s." % (t.value)
+ else:
+ last = self.LastToken()
+ lineno = last.lineno
+ pos = last.lexpos
+ msg = "Unexpected end of file after %s." % TokenTypeName(last)
+ self.yaccobj.restart()
+
+ # Attempt to remap the error to a friendlier form
+ if msg in ERROR_REMAP:
+ msg = ERROR_REMAP[msg]
+
+ self._last_error_msg = msg
+ self._last_error_lineno = lineno
+ self._last_error_pos = pos
+
+ def Warn(self, node, msg):
+ sys.stdout.write(node.GetLogLine(msg))
+ self.parse_warnings += 1
+
+ def LastToken(self):
+ return self.lexer.last
+
+ def __init__(self, lexer, verbose=False, debug=False, mute_error=False):
+ self.lexer = lexer
+ self.tokens = lexer.KnownTokens()
+ self.yaccobj = yacc.yacc(module=self, tabmodule=None, debug=False,
+ optimize=0, write_tables=0)
+ self.parse_debug = debug
+ self.verbose = verbose
+ self.mute_error = mute_error
+ self._parse_errors = 0
+ self._parse_warnings = 0
+ self._last_error_msg = None
+ self._last_error_lineno = 0
+ self._last_error_pos = 0
+
+
+#
+# BuildProduction
+#
+# Production is the set of items sent to a grammar rule resulting in a new
+# item being returned.
+#
+# p - Is the Yacc production object containing the stack of items
+# 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=None):
+ try:
+ if not childlist:
+ childlist = []
+
+ filename = self.lexer.Lexer().filename
+ lineno = p.lineno(index)
+ pos = p.lexpos(index)
+ out = IDLNode(cls, filename, lineno, pos, childlist)
+ return out
+ except:
+ print 'Exception while parsing:'
+ for num, item in enumerate(p):
+ print ' [%d] %s' % (num, ExpandProduction(item))
+ if self.LastToken():
+ print 'Last token: %s' % str(self.LastToken())
+ raise
+
+ def BuildNamed(self, cls, p, index, childlist=None):
+ childlist = ListFromConcat(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
+ lines = []
+ if name[:2] == '//':
+ # For C++ style, remove any leading whitespace and the '//' marker from
+ # each line.
+ form = 'cc'
+ for line in name.split('\n'):
+ start = line.find('//')
+ lines.append(line[start+2:])
+ else:
+ # For C style, remove ending '*/''
+ form = 'c'
+ 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)
+
+#
+# BuildError
+#
+# Build and Errror node as part of the recovery process.
+#
+#
+ def BuildError(self, p, prod):
+ self._parse_errors += 1
+ name = self.BuildAttribute('NAME', self._last_error_msg)
+ line = self.BuildAttribute('LINE', self._last_error_lineno)
+ pos = self.BuildAttribute('POS', self._last_error_pos)
+ prod = self.BuildAttribute('PROD', prod)
+
+ node = self.BuildProduction('Error', p, 1,
+ ListFromConcat(name, line, pos, prod))
+ if not self.mute_error:
+ node.Error(self._last_error_msg)
+
+ return node
+
+#
+# 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 BuildAttribute(self, key, val):
+ return IDLAttribute(key, val)
+
+ def BuildFalse(self, key):
+ return IDLAttribute(key, Boolean(False))
+
+ def BuildTrue(self, key):
+ return IDLAttribute(key, Boolean(True))
+
+ def GetErrors(self):
+ return self._parse_errors + self.lexer._lex_errors
+
+#
+# ParseData
+#
+# Attempts to parse the current data loaded in the lexer.
+#
+ def ParseText(self, filename, data):
+ self._parse_errors = 0
+ self._parse_warnings = 0
+ self._last_error_msg = None
+ self._last_error_lineno = 0
+ self._last_error_pos = 0
+
+ try:
+ self.lexer.Tokenize(data, filename)
+ nodes = self.yaccobj.parse(lexer=self.lexer)
+ name = self.BuildAttribute('NAME', filename)
+ return IDLNode('File', filename, 0, 0, nodes + [name])
+
+ except lex.LexError as lexError:
+ sys.stderr.write('Error in token: %s\n' % str(lexError))
+ return None
+
+
+
+def ParseFile(parser, filename):
+ """Parse a file and return a File type of node."""
+ with open(filename) as fileobject:
+ try:
+ out = parser.ParseText(filename, fileobject.read())
+ out.SetProperty('DATETIME', time.ctime(os.path.getmtime(filename)))
+ out.SetProperty('ERRORS', parser.GetErrors())
+ return out
+
+ except Exception as e:
+ last = parser.LastToken()
+ sys.stderr.write('%s(%d) : Internal parsing error - %s.' % (
+ filename, last.lineno, str(e)))
+
+
+def main(argv):
+ nodes = []
+ parser = IDLParser(IDLLexer())
+ errors = 0
+ for filename in argv:
+ filenode = ParseFile(parser, filename)
+ errors += filenode.GetProperty('ERRORS')
+ nodes.append(filenode)
+
+ ast = IDLNode('AST', '__AST__', 0, 0, nodes)
+
+ print '\n'.join(ast.Tree(accept_props=['PROD']))
+ if errors:
+ print '\nFound %d errors.\n' % errors
+
+
+ return errors
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:])) \ No newline at end of file
diff --git a/tools/idl_parser/idl_parser_test.py b/tools/idl_parser/idl_parser_test.py
new file mode 100755
index 0000000..5b7669e
--- /dev/null
+++ b/tools/idl_parser/idl_parser_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import glob
+import unittest
+
+from idl_lexer import IDLLexer
+from idl_parser import IDLParser, ParseFile
+
+def ParseCommentTest(comment):
+ comment = comment.strip()
+ comments = comment.split(None, 1)
+ return comments[0], comments[1]
+
+
+class WebIDLParser(unittest.TestCase):
+ def setUp(self):
+ self.parser = IDLParser(IDLLexer(), mute_error=True)
+ self.filenames = glob.glob('test_parser/*.idl')
+
+ def _TestNode(self, node):
+ comments = node.GetListOf('Comment')
+ for comment in comments:
+ check, value = ParseCommentTest(comment.GetName())
+ if check == 'BUILD':
+ msg = 'Expecting %s, but found %s.\n' % (value, str(node))
+ self.assertEqual(value, str(node), msg)
+
+ if check == 'ERROR':
+ msg = node.GetLogLine('Expecting\n\t%s\nbut found \n\t%s\n' % (
+ value, str(node)))
+ self.assertEqual(value, node.GetName(), msg)
+
+ if check == 'PROP':
+ key, expect = value.split('=')
+ actual = str(node.GetProperty(key))
+ msg = 'Mismatched property %s: %s vs %s.\n' % (key, expect, actual)
+ self.assertEqual(expect, actual, msg)
+
+ if check == 'TREE':
+ quick = '\n'.join(node.Tree())
+ lineno = node.GetProperty('LINENO')
+ msg = 'Mismatched tree at line %d:\n%sVS\n%s' % (lineno, value, quick)
+ self.assertEqual(value, quick, msg)
+
+ def testExpectedNodes(self):
+ for filename in self.filenames:
+ filenode = ParseFile(self.parser, filename)
+ children = filenode.GetChildren()
+ self.assertTrue(len(children) > 2, 'Expecting children in %s.' %
+ filename)
+
+ for node in filenode.GetChildren()[2:]:
+ self._TestNode(node)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
+
diff --git a/tools/idl_parser/idl_ppapi_lexer.py b/tools/idl_parser/idl_ppapi_lexer.py
index 3accd2d..f615c77 100644
--- a/tools/idl_parser/idl_ppapi_lexer.py
+++ b/tools/idl_parser/idl_ppapi_lexer.py
@@ -23,32 +23,27 @@ import sys
# IDL PPAPI Lexer
#
class IDLPPAPILexer(IDLLexer):
- # 'tokens' is a value required by lex which specifies the complete list
- # of valid token types. To WebIDL we add the following token types
- IDLLexer.tokens += [
- # Operators
- 'LSHIFT',
- 'RSHIFT',
-
- # Pepper Extras
- 'INLINE',
- ]
-
- # 'keywords' is a map of string to token type. All tokens matching
- # KEYWORD_OR_SYMBOL are matched against keywords dictionary, to determine
- # if the token is actually a keyword. Add the new keywords to the
- # dictionary and set of tokens
- ppapi_keywords = ['LABEL', 'NAMESPACE', 'STRUCT']
- for keyword in ppapi_keywords:
- IDLLexer.keywords[ keyword.lower() ] = keyword
- IDLLexer.tokens.append(keyword)
-
# Special multi-character operators
- t_LSHIFT = r'<<'
- t_RSHIFT = r'>>'
+ def t_LSHIFT(self, t):
+ r'<<'
+ return t;
+
+ def t_RSHIFT(self, t):
+ r'>>'
+ return t;
- # Return a "preprocessor" inline block
def t_INLINE(self, t):
r'\#inline (.|\n)*?\#endinl.*'
self.AddLines(t.value.count('\n'))
return t
+
+ # Return a "preprocessor" inline block
+ def __init__(self):
+ IDLLexer.__init__(self)
+ self._AddTokens(['LSHIFT', 'RSHIFT', 'INLINE'])
+ self._AddKeywords(['label', 'namespace', 'struct'])
+
+
+# If run by itself, attempt to build the lexer
+if __name__ == '__main__':
+ lexer = IDLPPAPILexer()
diff --git a/tools/idl_parser/run_tests.py b/tools/idl_parser/run_tests.py
index 9bb1356..cf26759 100755
--- a/tools/idl_parser/run_tests.py
+++ b/tools/idl_parser/run_tests.py
@@ -8,6 +8,13 @@ import sys
import unittest
if __name__ == '__main__':
- testlist = glob.glob('*_test.py')
- for testname in testlist:
- unittest.main(verbosity=2, module=testname[:-3]) \ No newline at end of file
+ suite = unittest.TestSuite()
+ for testname in glob.glob('*_test.py'):
+ print 'Adding Test: ' + testname
+ module = __import__(testname[:-3])
+ suite.addTests(unittest.defaultTestLoader.loadTestsFromModule(module))
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ if result.wasSuccessful():
+ sys.exit(0)
+ else:
+ sys.exit(1)
diff --git a/tools/idl_parser/test_lexer/keywords.in b/tools/idl_parser/test_lexer/keywords.in
index e155753..11baff9 100644
--- a/tools/idl_parser/test_lexer/keywords.in
+++ b/tools/idl_parser/test_lexer/keywords.in
@@ -17,10 +17,8 @@ GETTER getter
IMPLEMENTS implements
INFINITY Infinity
INTERFACE interface
-LABEL label
LEGACYCALLER legacycaller
LONG long
-NAMESPACE namespace
NAN Nan
NULL null
OBJECT object
@@ -32,7 +30,6 @@ SETTER setter
SHORT short
STATIC static
STRINGIFIER stringifier
-STRUCT struct
TYPEDEF typedef
TRUE true
UNSIGNED unsigned
diff --git a/tools/idl_parser/test_parser/callback.idl b/tools/idl_parser/test_parser/callback.idl
new file mode 100644
index 0000000..b16b6b5
--- /dev/null
+++ b/tools/idl_parser/test_parser/callback.idl
@@ -0,0 +1,116 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. */
+
+/* Test Callback productions
+
+Run with --test to generate an AST and verify that all comments accurately
+reflect the state of the Nodes.
+
+BUILD Type(Name)
+This comment signals that a node of type <Type> is created with the
+name <Name>.
+
+ERROR Error String
+This comment signals that a error of <Error String> is generated. The error
+is not assigned to a node, but are expected in order.
+
+PROP Key=Value
+This comment signals that a property has been set on the Node such that
+<Key> = <Value>.
+
+TREE
+Type(Name)
+ Type(Name)
+ Type(Name)
+ Type(Name)
+ ...
+This comment signals that a tree of nodes matching the BUILD comment
+symatics should exist. This is an exact match.
+*/
+
+
+/* TREE
+ *Callback(VoidFunc)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ */
+callback VoidFunc = void();
+
+/* TREE
+ *Callback(VoidFuncLongErr)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ * Error(Unexpected ).)
+ */
+callback VoidFuncLongErr = void ( long );
+
+/* TREE
+ *Callback(VoidFuncLong)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ * Argument(L1)
+ * Type()
+ * PrimitiveType(long)
+ */
+callback VoidFuncLong = void ( long L1 );
+
+/* TREE
+ *Callback(VoidFuncLongArray)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ * Argument(L1)
+ * Type()
+ * PrimitiveType(long)
+ * Array()
+ */
+callback VoidFuncLongArray = void ( long[] L1 );
+
+/* TREE
+ *Callback(VoidFuncLongArray5)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ * Argument(L1)
+ * Type()
+ * PrimitiveType(long)
+ * Array(5)
+ */
+callback VoidFuncLongArray5 = void ( long[5] L1 );
+
+
+/* TREE
+ *Callback(VoidFuncLongArray54)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ * Argument(L1)
+ * Type()
+ * PrimitiveType(long)
+ * Array(5)
+ * Argument(L2)
+ * Type()
+ * PrimitiveType(long long)
+ * Array(4)
+ */
+callback VoidFuncLongArray54 = void ( long[5] L1, long long [4] L2 );
+
+
+/* TREE
+ *Callback(VoidFuncLongIdent)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ * Argument(L1)
+ * Type()
+ * PrimitiveType(long)
+ * Array(5)
+ * Argument(L2)
+ * Type()
+ * Typeref(VoidFuncLongArray)
+ */
+callback VoidFuncLongIdent = void ( long[5] L1, VoidFuncLongArray L2 );
diff --git a/tools/idl_parser/test_parser/dictionary.idl b/tools/idl_parser/test_parser/dictionary.idl
new file mode 100644
index 0000000..5030686
--- /dev/null
+++ b/tools/idl_parser/test_parser/dictionary.idl
@@ -0,0 +1,95 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. */
+
+/* Test Dictionary productions
+
+Run with --test to generate an AST and verify that all comments accurately
+reflect the state of the Nodes.
+
+BUILD Type(Name)
+This comment signals that a node of type <Type> is created with the
+name <Name>.
+
+ERROR Error String
+This comment signals that a error of <Error String> is generated. The error
+is not assigned to a node, but are expected in order.
+
+PROP Key=Value
+This comment signals that a property has been set on the Node such that
+<Key> = <Value>.
+
+TREE
+Type(Name)
+ Type(Name)
+ Type(Name)
+ Type(Name)
+ ...
+This comment signals that a tree of nodes matching the BUILD comment
+symatics should exist. This is an exact match.
+*/
+
+
+/* TREE
+ *Dictionary(MyDict)
+ */
+dictionary MyDict { };
+
+/* TREE
+ *Dictionary(MyDictInherit)
+ * Inherit(Foo)
+ */
+dictionary MyDictInherit : Foo {};
+
+/* TREE
+ *Dictionary(MyDictPartial)
+ */
+partial dictionary MyDictPartial { };
+
+/* ERROR Unexpected ":" after identifier "MyDictInherit". */
+partial dictionary MyDictInherit : Foo {};
+
+/* TREE
+ *Dictionary(MyDictBig)
+ * Key(setString)
+ * Type()
+ * PrimitiveType(DOMString)
+ * Default(Foo)
+ * Key(setLong)
+ * Type()
+ * PrimitiveType(unsigned long long)
+ * Default(123)
+ * Key(unsetLong)
+ * Type()
+ * PrimitiveType(long)
+ */
+dictionary MyDictBig {
+ DOMString setString = "Foo";
+ unsigned long long setLong = 123;
+ long unsetLong;
+};
+
+
+/* ERROR Unexpected "{" after keyword "dictionary". */
+dictionary {
+ DOMString? setString = null;
+};
+
+
+/* ERROR Unexpected identifier "NoColon" after identifier "ForParent". */
+dictionary ForParent NoColon {
+ DOMString? setString = null;
+};
+
+/* TREE
+ *Dictionary(MyDictNull)
+ * Key(setString)
+ * Type()
+ * PrimitiveType(DOMString)
+ * Default(NULL)
+ */
+dictionary MyDictNull {
+ DOMString? setString = null;
+};
+
+
diff --git a/tools/idl_parser/test_parser/enum.idl b/tools/idl_parser/test_parser/enum.idl
new file mode 100644
index 0000000..233410c
--- /dev/null
+++ b/tools/idl_parser/test_parser/enum.idl
@@ -0,0 +1,119 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. */
+
+/* Test Enum productions
+
+Run with --test to generate an AST and verify that all comments accurately
+reflect the state of the Nodes.
+
+BUILD Type(Name)
+This comment signals that a node of type <Type> is created with the
+name <Name>.
+
+ERROR Error String
+This comment signals that a error of <Error String> is generated. The error
+is not assigned to a node, but are expected in order.
+
+PROP Key=Value
+This comment signals that a property has been set on the Node such that
+<Key> = <Value>.
+
+TREE
+Type(Name)
+ Type(Name)
+ Type(Name)
+ Type(Name)
+ ...
+This comment signals that a tree of nodes matching the BUILD comment
+symatics should exist. This is an exact match.
+*/
+
+/* TREE
+ *Enum(MealType1)
+ * EnumItem(rice)
+ * EnumItem(noodles)
+ * EnumItem(other)
+*/
+enum MealType1 {
+ /* BUILD EnumItem (rice) */
+ "rice",
+ /* BUILD EnumItem (noodles) */
+ "noodles",
+ /* BUILD EnumItem(other) */
+ "other"
+};
+
+/* BUILD Error(Enum missing name.) */
+/* ERROR Enum missing name. */
+enum {
+ "rice",
+ "noodles",
+ "other"
+};
+
+/* TREE
+ *Enum(MealType2)
+ * EnumItem(rice)
+ * EnumItem(noodles)
+ * EnumItem(other)
+*/
+enum MealType2 {
+ /* BUILD EnumItem(rice) */
+ "rice",
+ /* BUILD EnumItem(noodles) */
+ "noodles",
+ /* BUILD EnumItem(other) */
+ "other"
+};
+
+/* BUILD Error(Unexpected string "noodles" after string "rice".) */
+/* ERROR Unexpected string "noodles" after string "rice". */
+enum MissingComma {
+ "rice"
+ "noodles",
+ "other"
+};
+
+/* BUILD Error(Trailing comma in block.) */
+/* ERROR Trailing comma in block. */
+enum TrailingComma {
+ "rice",
+ "noodles",
+ "other",
+};
+
+/* BUILD Error(Unexpected "," after ",".) */
+/* ERROR Unexpected "," after ",". */
+enum ExtraComma {
+ "rice",
+ "noodles",
+ ,"other",
+};
+
+/* BUILD Error(Unexpected keyword "interface" after "{".) */
+/* ERROR Unexpected keyword "interface" after "{". */
+enum ExtraComma {
+ interface,
+ "noodles",
+ ,"other",
+};
+
+/* BUILD Error(Unexpected identifier "somename" after "{".) */
+/* ERROR Unexpected identifier "somename" after "{". */
+enum ExtraComma {
+ somename,
+ "noodles",
+ ,"other",
+};
+
+/* BUILD Enum(MealType3) */
+enum MealType3 {
+ /* BUILD EnumItem(rice) */
+ "rice",
+ /* BUILD EnumItem(noodles) */
+ "noodles",
+ /* BUILD EnumItem(other) */
+ "other"
+};
+
diff --git a/tools/idl_parser/test_parser/exception.idl b/tools/idl_parser/test_parser/exception.idl
new file mode 100644
index 0000000..3801a4a
--- /dev/null
+++ b/tools/idl_parser/test_parser/exception.idl
@@ -0,0 +1,87 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. */
+
+/* Test Exception productions
+
+Run with --test to generate an AST and verify that all comments accurately
+reflect the state of the Nodes.
+
+BUILD Type(Name)
+This comment signals that a node of type <Type> is created with the
+name <Name>.
+
+ERROR Error String
+This comment signals that a error of <Error String> is generated. The error
+is not assigned to a node, but are expected in order.
+
+PROP Key=Value
+This comment signals that a property has been set on the Node such that
+<Key> = <Value>.
+
+TREE
+Type(Name)
+ Type(Name)
+ Type(Name)
+ Type(Name)
+ ...
+This comment signals that a tree of nodes matching the BUILD comment
+symatics should exist. This is an exact match.
+*/
+
+
+/* TREE
+ *Exception(MyExc)
+ */
+exception MyExc { };
+
+/* TREE
+ *Exception(MyExcInherit)
+ * Inherit(Foo)
+ */
+exception MyExcInherit : Foo {};
+
+/* ERROR Unexpected keyword "exception" after keyword "partial". */
+partial exception MyExcPartial { };
+
+/* TREE
+ *Exception(MyExcBig)
+ * ExceptionField(MyString)
+ * Type()
+ * PrimitiveType(DOMString)
+ * Error(Unexpected "=" after identifier "ErrorSetLong".)
+ * ExceptionField(MyLong)
+ * Type()
+ * PrimitiveType(long)
+ */
+exception MyExcBig {
+ DOMString MyString;
+ unsigned long long ErrorSetLong = 123;
+ long MyLong;
+};
+
+
+/* ERROR Unexpected "{" after keyword "exception". */
+exception {
+ DOMString? setString = null;
+};
+
+
+/* ERROR Unexpected identifier "NoColon" after identifier "ForParent". */
+exception ForParent NoColon {
+ DOMString? setString = null;
+};
+
+/* TREE
+ *Exception(MyExcConst)
+ * Const(setString)
+ * PrimitiveType(DOMString)
+ * Value(NULL)
+ */
+exception MyExcConst {
+ const DOMString? setString = null;
+};
+
+
+
+
diff --git a/tools/idl_parser/test_parser/implements.idl b/tools/idl_parser/test_parser/implements.idl
new file mode 100644
index 0000000..252dd4b
--- /dev/null
+++ b/tools/idl_parser/test_parser/implements.idl
@@ -0,0 +1,52 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. */
+
+/* Test Implements productions
+
+Run with --test to generate an AST and verify that all comments accurately
+reflect the state of the Nodes.
+
+BUILD Type(Name)
+This comment signals that a node of type <Type> is created with the
+name <Name>.
+
+ERROR Error String
+This comment signals that a error of <Error String> is generated. The error
+is not assigned to a node, but are expected in order.
+
+PROP Key=Value
+This comment signals that a property has been set on the Node such that
+<Key> = <Value>.
+
+TREE
+Type(Name)
+ Type(Name)
+ Type(Name)
+ Type(Name)
+ ...
+This comment signals that a tree of nodes matching the BUILD comment
+symatics should exist. This is an exact match.
+*/
+
+/* BUILD Implements(A) */
+/* PROP REFERENCE=B */
+A implements B;
+
+/* ERROR Unexpected ";" after keyword "implements". */
+A implements;
+
+/* BUILD Implements(B) */
+/* PROP REFERENCE=C */
+B implements C;
+
+/* ERROR Unexpected keyword "implements" after "]". */
+[foo] implements B;
+
+/* BUILD Implements(D) */
+/* PROP REFERENCE=E */
+D implements E;
+
+/* ERROR Unexpected keyword "implements" after comment. */
+implements C;
+
diff --git a/tools/idl_parser/test_parser/interface.idl b/tools/idl_parser/test_parser/interface.idl
new file mode 100644
index 0000000..a8a4135
--- /dev/null
+++ b/tools/idl_parser/test_parser/interface.idl
@@ -0,0 +1,127 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. */
+
+/* Test Interface productions
+
+Run with --test to generate an AST and verify that all comments accurately
+reflect the state of the Nodes.
+
+BUILD Type(Name)
+This comment signals that a node of type <Type> is created with the
+name <Name>.
+
+ERROR Error String
+This comment signals that a error of <Error String> is generated. The error
+is not assigned to a node, but are expected in order.
+
+PROP Key=Value
+This comment signals that a property has been set on the Node such that
+<Key> = <Value>.
+
+TREE
+Type(Name)
+ Type(Name)
+ Type(Name)
+ Type(Name)
+ ...
+This comment signals that a tree of nodes matching the BUILD comment
+symatics should exist. This is an exact match.
+*/
+
+
+/* TREE
+ *Interface(MyIFace)
+ */
+interface MyIFace { };
+
+/* TREE
+ *Interface(MyIFaceInherit)
+ * Inherit(Foo)
+ */
+interface MyIFaceInherit : Foo {};
+
+/* TREE
+ *Interface(MyIFacePartial)
+ */
+partial interface MyIFacePartial { };
+
+/* ERROR Unexpected ":" after identifier "MyIFaceInherit". */
+partial interface MyIFaceInherit : Foo {};
+
+/* TREE
+ *Interface(MyIFaceBig)
+ * Const(setString)
+ * PrimitiveType(DOMString)
+ * Value(NULL)
+ */
+interface MyIFaceBig {
+ const DOMString? setString = null;
+};
+
+/* TREE
+ *Interface(MyIFaceBig2)
+ * Const(nullValue)
+ * PrimitiveType(DOMString)
+ * Value(NULL)
+ * Const(longValue)
+ * PrimitiveType(long)
+ * Value(123)
+ * Const(longValue2)
+ * PrimitiveType(long long)
+ * Value(123)
+ * Attribute(myString)
+ * Type()
+ * PrimitiveType(DOMString)
+ * Attribute(readOnlyString)
+ * Type()
+ * PrimitiveType(DOMString)
+ * Operation(myFunction)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ * Argument(myLong)
+ * Type()
+ * PrimitiveType(long long)
+ */
+interface MyIFaceBig2 {
+ const DOMString? nullValue = null;
+ const long longValue = 123;
+ const long long longValue2 = 123;
+ attribute DOMString myString;
+ readonly attribute DOMString readOnlyString;
+ void myFunction(long long myLong);
+};
+
+
+/* TREE
+ *Interface(MyIFaceSpecials)
+ * Operation(set)
+ * Type()
+ * PrimitiveType(void)
+ * Arguments()
+ * Argument(property)
+ * Type()
+ * PrimitiveType(DOMString)
+ * Operation(_unnamed_)
+ * Type()
+ * PrimitiveType(double)
+ * Arguments()
+ * Argument(property)
+ * Type()
+ * PrimitiveType(DOMString)
+ * Operation(GetFiveSix)
+ * Type()
+ * PrimitiveType(long long)
+ * Array(5)
+ * Array(6)
+ * Arguments()
+ * Argument(arg)
+ * Type()
+ * Typeref(SomeType)
+ */
+interface MyIFaceSpecials {
+ setter creator void set(DOMString property);
+ getter double (DOMString property);
+ long long [5][6] GetFiveSix(SomeType arg);
+};
diff --git a/tools/idl_parser/test_parser/typedef.idl b/tools/idl_parser/test_parser/typedef.idl
new file mode 100644
index 0000000..ba95db7c
--- /dev/null
+++ b/tools/idl_parser/test_parser/typedef.idl
@@ -0,0 +1,190 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. */
+
+/* Test Typedef productions
+
+Run with --test to generate an AST and verify that all comments accurately
+reflect the state of the Nodes.
+
+BUILD Type(Name)
+This comment signals that a node of type <Type> is created with the
+name <Name>.
+
+ERROR Error String
+This comment signals that a error of <Error String> is generated. The error
+is not assigned to a node, but are expected in order.
+
+PROP Key=Value
+This comment signals that a property has been set on the Node such that
+<Key> = <Value>.
+
+TREE
+Type(Name)
+ Type(Name)
+ Type(Name)
+ Type(Name)
+ ...
+This comment signals that a tree of nodes matching the BUILD comment
+symatics should exist. This is an exact match.
+*/
+
+
+/* TREE
+ *Typedef(MyLong)
+ * Type()
+ * PrimitiveType(long)
+ */
+typedef long MyLong;
+
+/* TREE
+ *Typedef(MyLong)
+ * ExtAttributes()
+ * ExtAttribute(foo)
+ * Type()
+ * PrimitiveType(long)
+ */
+typedef [foo] long MyLong;
+
+/* TREE
+ *Typedef(MyLongArray)
+ * Type()
+ * PrimitiveType(long)
+ * Array()
+ */
+typedef long[] MyLongArray;
+
+/* TREE
+ *Typedef(MyLongSizedArray)
+ * Type()
+ * PrimitiveType(long)
+ * Array(4)
+ */
+typedef long[4] MyLongSizedArray;
+
+/* TREE
+ *Typedef(MyLongSizedArrayArray)
+ * Type()
+ * PrimitiveType(long)
+ * Array(4)
+ * Array(5)
+ */
+typedef long[4][5] MyLongSizedArrayArray;
+
+/* TREE
+ *Typedef(MyLongArraySizedArray)
+ * Type()
+ * PrimitiveType(long)
+ * Array()
+ * Array(5)
+ */
+typedef long[][5] MyLongArraySizedArray;
+
+/* TREE
+ *Typedef(MyTypeFive)
+ * Type()
+ * Typeref(MyType)
+ * Array(5)
+ */
+typedef MyType[5] MyTypeFive;
+
+/* TREE
+ *Typedef(MyTypeUnsizedFive)
+ * Type()
+ * Typeref(MyType)
+ * Array()
+ * Array(5)
+ */
+typedef MyType[][5] MyTypeUnsizedFive;
+
+/* TREE
+ *Typedef(MyLongLong)
+ * Type()
+ * PrimitiveType(long long)
+ */
+typedef long long MyLongLong;
+
+/* TREE
+ *Typedef(MyULong)
+ * Type()
+ * PrimitiveType(unsigned long)
+ */
+typedef unsigned long MyULong;
+
+/* TREE
+ *Typedef(MyULongLong)
+ * Type()
+ * PrimitiveType(unsigned long long)
+ */
+typedef unsigned long long MyULongLong;
+
+/* TREE
+ *Typedef(MyString)
+ * Type()
+ * PrimitiveType(DOMString)
+ */
+typedef DOMString MyString;
+
+/* TREE
+ *Typedef(MyObject)
+ * Type()
+ * PrimitiveType(object)
+ */
+typedef object MyObject;
+
+/* TREE
+ *Typedef(MyDate)
+ * Type()
+ * PrimitiveType(Date)
+ */
+typedef Date MyDate;
+
+/* TREE
+ *Typedef(MyFloat)
+ * Type()
+ * PrimitiveType(float)
+ */
+typedef float MyFloat;
+
+/* TREE
+ *Typedef(MyUFloat)
+ * Type()
+ * PrimitiveType(float)
+ */
+typedef unrestricted float MyUFloat;
+
+/* TREE
+ *Typedef(MyDouble)
+ * Type()
+ * PrimitiveType(double)
+ */
+typedef double MyDouble;
+
+/* TREE
+ *Typedef(MyUDouble)
+ * Type()
+ * PrimitiveType(double)
+ */
+typedef unrestricted double MyUDouble;
+
+/* TREE
+ *Typedef(MyBool)
+ * Type()
+ * PrimitiveType(boolean)
+ */
+typedef boolean MyBool;
+
+/* TREE
+ *Typedef(MyByte)
+ * Type()
+ * PrimitiveType(byte)
+ */
+typedef byte MyByte;
+
+/* TREE
+ *Typedef(MyOctet)
+ * Type()
+ * PrimitiveType(octet)
+ */
+typedef octet MyOctet;
+