- add sources.
[platform/framework/web/crosswalk.git] / src / mojo / public / bindings / parser / mojo_parser.py
1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Generates a syntax tree from a Mojo IDL file."""
7
8
9 import sys
10 import os.path
11
12
13 # Try to load the ply module, if not, then assume it is in the third_party
14 # directory.
15 try:
16   # Disable lint check which fails to find the ply module.
17   # pylint: disable=F0401
18   from ply import lex
19   from ply import yacc
20 except ImportError:
21   module_path, module_name = os.path.split(__file__)
22   third_party = os.path.join(
23       module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party')
24   sys.path.append(third_party)
25   # pylint: disable=F0401
26   from ply import lex
27   from ply import yacc
28
29
30 def ListFromConcat(*items):
31   """Generate list by concatenating inputs"""
32   itemsout = []
33   for item in items:
34     if item is None:
35       continue
36     if type(item) is not type([]):
37       itemsout.append(item)
38     else:
39       itemsout.extend(item)
40
41   return itemsout
42
43
44 class Lexer(object):
45
46   # This field is required by lex to specify the complete list of valid tokens.
47   tokens = (
48     'NAME',
49     'NUMBER',
50
51     'ARRAY',
52     'ORDINAL',
53
54     'MODULE',
55     'STRUCT',
56     'INTERFACE',
57     'VOID',
58
59     'LCURLY',
60     'RCURLY',
61     'LPAREN',
62     'RPAREN',
63     'LBRACKET',
64     'RBRACKET',
65     'COMMA',
66     'SEMICOLON',
67     'EQUALS',
68   )
69
70   t_LCURLY     = r'{'
71   t_RCURLY     = r'}'
72   t_LPAREN     = r'\('
73   t_RPAREN     = r'\)'
74   t_LBRACKET   = r'\['
75   t_RBRACKET   = r'\]'
76   t_COMMA      = r','
77   t_SEMICOLON  = r';'
78   t_EQUALS     = r'='
79   t_NAME       = r'[a-zA-Z_][a-zA-Z0-9_]*'
80   t_ARRAY      = r'[a-zA-Z_][a-zA-Z0-9_]*\[\]'
81   t_NUMBER     = r'\d+'
82   t_ORDINAL    = r'@[0-9]*'
83
84   def t_MODULE(self, t):
85     r'module'
86     return t
87
88   def t_STRUCT(self, t):
89     r'struct'
90     return t
91
92   def t_INTERFACE(self, t):
93     r'interface'
94     return t
95
96   def t_VOID(self, t):
97     r'void'
98     return t
99
100   # Ignore C and C++ style comments
101   def t_COMMENT(self, t):
102     r'(/\*(.|\n)*?\*/)|(//.*(\n[ \t]*//.*)*)'
103     pass
104
105   # Ignored characters
106   t_ignore = " \t"
107
108   def t_newline(self, t):
109     r'\n+'
110     t.lexer.lineno += t.value.count("\n")
111
112   def t_error(self, t):
113     print("Illegal character '%s'" % t.value[0])
114     t.lexer.skip(1)
115
116
117 class Parser(object):
118
119   def __init__(self, lexer):
120     self.tokens = lexer.tokens
121
122   def p_module(self, p):
123     """module : MODULE NAME LCURLY definitions RCURLY"""
124     p[0] = ('MODULE', p[2], p[4])
125
126   def p_definitions(self, p):
127     """definitions : definition definitions
128                    |"""
129     if len(p) > 1:
130       p[0] = ListFromConcat(p[1], p[2])
131
132   def p_definition(self, p):
133     """definition : struct
134                   | interface"""
135     p[0] = p[1]
136
137   def p_attribute_section(self, p):
138     """attribute_section : LBRACKET attributes RBRACKET
139                          | """
140     if len(p) > 3:
141       p[0] = p[2]
142
143   def p_attributes(self, p):
144     """attributes : attribute
145                   | attribute COMMA attributes
146                   | """
147     if len(p) == 2:
148       p[0] = ListFromConcat(p[1])
149     elif len(p) > 3:
150       p[0] = ListFromConcat(p[1], p[3])
151
152   def p_attribute(self, p):
153     """attribute : NAME EQUALS NUMBER"""
154     p[0] = ('ATTRIBUTE', p[1], p[3])
155
156   def p_struct(self, p):
157     """struct : attribute_section STRUCT NAME LCURLY fields RCURLY SEMICOLON"""
158     p[0] = ('STRUCT', p[3], p[1], p[5])
159
160   def p_fields(self, p):
161     """fields : field fields
162               |"""
163     if len(p) > 1:
164       p[0] = ListFromConcat(p[1], p[2])
165
166   def p_field(self, p):
167     """field : typename NAME ordinal SEMICOLON"""
168     p[0] = ('FIELD', p[1], p[2], p[3])
169
170   def p_interface(self, p):
171     """interface : INTERFACE NAME LCURLY methods RCURLY SEMICOLON"""
172     p[0] = ('INTERFACE', p[2], p[4])
173
174   def p_methods(self, p):
175     """methods : method methods
176                | """
177     if len(p) > 1:
178       p[0] = ListFromConcat(p[1], p[2])
179
180   def p_method(self, p):
181     """method : VOID NAME LPAREN parameters RPAREN ordinal SEMICOLON"""
182     p[0] = ('METHOD', p[2], p[4], p[6])
183
184   def p_parameters(self, p):
185     """parameters : parameter
186                   | parameter COMMA parameters
187                   | """
188     if len(p) == 2:
189       p[0] = p[1]
190     elif len(p) > 3:
191       p[0] = ListFromConcat(p[1], p[3])
192
193   def p_parameter(self, p):
194     """parameter : typename NAME ordinal"""
195     p[0] = ('PARAM', p[1], p[2], p[3])
196
197   def p_typename(self, p):
198     """typename : NAME
199                 | ARRAY"""
200     p[0] = p[1]
201
202   def p_ordinal(self, p):
203     """ordinal : ORDINAL
204                | """
205     if len(p) > 1:
206       p[0] = p[1]
207
208   def p_error(self, e):
209     print('error: %s'%e)
210
211
212 def Parse(filename):
213   lexer = Lexer()
214   parser = Parser(lexer)
215
216   lex.lex(object=lexer)
217   yacc.yacc(module=parser, debug=0, write_tables=0)
218
219   tree = yacc.parse(open(filename).read())
220   return tree
221
222
223 def Main():
224   if len(sys.argv) < 2:
225     print("usage: %s filename" % (sys.argv[0]))
226     sys.exit(1)
227   tree = Parse(filename=sys.argv[1])
228   print(tree)
229
230
231 if __name__ == '__main__':
232   Main()