15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" Generator for C style prototypes and definitions """
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import glob
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_log import ErrOut, InfoOut, WarnOut
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_node import IDLAttribute, IDLNode
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_ast import IDLAst
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_option import GetOption, Option, ParseOptions
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_outfile import IDLOutFile
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_parser import ParseFiles
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_c_proto import CGen, GetNodeComments, CommentLines, Comment
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_generator import Generator, GeneratorByFile
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from idl_visitor import IDLVisitor
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('dstroot', 'Base directory of output', default=os.path.join('..', 'c'))
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('guard', 'Include guard prefix', default=os.path.join('ppapi', 'c'))
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# PrototypeResolver
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# A specialized visitor which traverses the AST, building a mapping of
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Release names to Versions numbers and calculating a min version.
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# The mapping is applied to the File nodes within the AST.
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ProtoResolver(IDLVisitor):
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __init__(self):
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IDLVisitor.__init__(self)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.struct_map = {}
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.interface_map = {}
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Arrive(self, node, ignore):
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if node.IsA('Member') and node.GetProperty('ref'):
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      typeref = node.typelist.GetReleases()[0]
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if typeref.IsA('Struct'):
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        nodelist = self.struct_map.get(typeref.GetName(), [])
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        nodelist.append(node)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.struct_map[typeref.GetName()] = nodelist
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if node.IsA('Param'):
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      typeref = node.typelist.GetReleases()[0]
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if typeref.IsA('Interface'):
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        nodelist = self.struct_map.get(typeref.GetName(), [])
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        nodelist.append(node)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self.interface_map[typeref.GetName()] = nodelist
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return None
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def GetPathFromNode(filenode, relpath=None, ext=None):
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path, name = os.path.split(filenode.GetProperty('NAME'))
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ext: name = os.path.splitext(name)[0] + ext
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if path: name = os.path.join(path, name)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if relpath: name = os.path.join(relpath, name)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  name = os.path.normpath(name)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return name
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def GetHeaderFromNode(filenode, relpath=None):
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return GetPathFromNode(filenode, relpath, ext='.h')
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def WriteGroupMarker(out, node, last_group):
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # If we are part of a group comment marker...
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if last_group and last_group != node.cls:
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pre = CommentLines(['*',' @}', '']) + '\n'
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pre = '\n'
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if node.cls in ['Typedef', 'Interface', 'Struct', 'Enum']:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if last_group != node.cls:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pre += CommentLines(['*',' @addtogroup %ss' % node.cls, ' @{', ''])
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_group = node.cls
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_group = None
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out.Write(pre)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return last_group
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GenerateHeader(out, filenode, releases):
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cgen = CGen()
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref = ''
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do_comments = True
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Generate definitions.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_group = None
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  top_types = ['Typedef', 'Interface', 'Struct', 'Enum', 'Inline']
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for node in filenode.GetListOf(*top_types):
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Skip if this node is not in this release
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not node.InReleases(releases):
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "Skiping %s" % node
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # End/Start group marker
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if do_comments:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_group = WriteGroupMarker(out, node, last_group)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if node.IsA('Inline'):
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item = node.GetProperty('VALUE')
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # If 'C++' use __cplusplus wrapper
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.GetName() == 'cc':
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        item = '#ifdef __cplusplus\n%s\n#endif  /* __cplusplus */\n\n' % item
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # If not C++ or C, then skip it
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif not node.GetName() == 'c':
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if item: out.Write(item)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Otherwise we are defining a file level object, so generate the
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # correct document notation.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    item = cgen.Define(node, releases, prefix=pref, comment=True)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not item: continue
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asize = node.GetProperty('assert_size()')
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if asize:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = '%s%s' % (pref, node.GetName())
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.IsA('Struct'):
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        form = 'PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(%s, %s);\n'
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.IsA('Enum'):
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if node.GetProperty('notypedef'):
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          form = 'PP_COMPILE_ASSERT_ENUM_SIZE_IN_BYTES(%s, %s);\n'
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n'
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        form = 'PP_COMPILE_ASSERT_SIZE_IN_BYTES(%s, %s);\n'
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item += form % (name, asize[0])
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if item: out.Write(item)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if last_group:
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out.Write(CommentLines(['*',' @}', '']) + '\n')
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def CheckTypedefs(filenode, releases):
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  """Checks that typedefs don't specify callbacks that take some structs.
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  See http://crbug.com/233439 for details.
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  """
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cgen = CGen()
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # TODO(teravest): Fix the following callback to pass PP_Var by pointer
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  # instead of by value.
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  node_whitelist = ['PP_Ext_Alarms_OnAlarm_Func_Dev_0_1']
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for node in filenode.GetListOf('Typedef'):
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if node.GetName() in node_whitelist:
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    build_list = node.GetUniqueReleases(releases)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callnode = node.GetOneOf('Callspec')
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if callnode:
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for param in callnode.GetListOf('Param'):
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if param.GetListOf('Array'):
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          continue
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if cgen.GetParamMode(param) != 'in':
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          continue
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        t = param.GetType(build_list[0])
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        while t.IsA('Typedef'):
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          t = t.GetType(build_list[0])
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if t.IsA('Struct'):
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          raise Exception('%s is a struct in callback %s. '
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          'See http://crbug.com/233439' %
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          (t.GetName(), node.GetName()))
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def CheckPassByValue(filenode, releases):
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """Checks that new pass-by-value structs are not introduced.
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  See http://crbug.com/233439 for details.
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  cgen = CGen()
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  # DO NOT add any more entries to this whitelist.
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  # http://crbug.com/233439
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  type_whitelist = ['PP_ArrayOutput', 'PP_CompletionCallback',
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                    'PP_Ext_EventListener', 'PP_FloatPoint',
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    'PP_Point', 'PP_TouchPoint', 'PP_Var']
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  nodes_to_check = filenode.GetListOf('Struct')
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  nodes_to_check.extend(filenode.GetListOf('Union'))
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for node in nodes_to_check:
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if node.GetName() in type_whitelist:
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    build_list = node.GetUniqueReleases(releases)
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if node.GetProperty('passByValue'):
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      raise Exception('%s is a new passByValue struct or union. '
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      'See http://crbug.com/233439' % node.GetName())
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if node.GetProperty('returnByValue'):
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      raise Exception('%s is a new returnByValue struct or union. '
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      'See http://crbug.com/233439' % node.GetName())
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HGen(GeneratorByFile):
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Generator.__init__(self, 'C Header', 'cgen', 'Generate the C headers.')
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateFile(self, filenode, releases, options):
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CheckTypedefs(filenode, releases)
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CheckPassByValue(filenode, releases)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    savename = GetHeaderFromNode(filenode, GetOption('dstroot'))
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my_min, my_max = filenode.GetMinMax(releases)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if my_min > releases[-1] or my_max < releases[0]:
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.isfile(savename):
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print "Removing stale %s for this range." % filenode.GetName()
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        os.remove(os.path.realpath(savename))
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out = IDLOutFile(savename)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.GenerateHead(out, filenode, releases, options)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.GenerateBody(out, filenode, releases, options)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.GenerateTail(out, filenode, releases, options)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return out.Close()
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateHead(self, out, filenode, releases, options):
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __pychecker__ = 'unusednames=options'
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    proto = ProtoResolver()
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    proto.Visit(filenode, None)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cgen = CGen()
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gpath = GetOption('guard')
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def_guard = GetHeaderFromNode(filenode, relpath=gpath)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def_guard = def_guard.replace(os.sep,'_').replace('.','_').upper() + '_'
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cright_node = filenode.GetChildren()[0]
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert(cright_node.IsA('Copyright'))
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fileinfo = filenode.GetChildren()[1]
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert(fileinfo.IsA('Comment'))
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out.Write('%s\n' % cgen.Copyright(cright_node))
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Wrap the From ... modified ... comment if it would be >80 characters.
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    from_text = 'From %s' % GetPathFromNode(filenode).replace(os.sep, '/')
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    modified_text = 'modified %s.' % (
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        filenode.GetProperty('DATETIME'))
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(from_text) + len(modified_text) < 74:
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out.Write('/* %s %s */\n\n' % (from_text, modified_text))
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out.Write('/* %s,\n *   %s\n */\n\n' % (from_text, modified_text))
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out.Write('#ifndef %s\n#define %s\n\n' % (def_guard, def_guard))
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generate set of includes
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    deps = set()
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for release in releases:
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      deps |= filenode.GetDeps(release)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    includes = set([])
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for dep in deps:
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      depfile = dep.GetProperty('FILE')
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if depfile:
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        includes.add(depfile)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    includes = [GetHeaderFromNode(
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        include, relpath=gpath).replace(os.sep, '/') for include in includes]
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    includes.append('ppapi/c/pp_macros.h')
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Assume we need stdint if we "include" C or C++ code
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if filenode.GetListOf('Include'):
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      includes.append('ppapi/c/pp_stdint.h')
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    includes = sorted(set(includes))
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cur_include = GetHeaderFromNode(filenode,
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    relpath=gpath).replace(os.sep, '/')
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for include in includes:
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if include == cur_include: continue
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out.Write('#include "%s"\n' % include)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Generate Prototypes
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if proto.struct_map:
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      out.Write('\n/* Struct prototypes */\n')
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for struct in proto.struct_map:
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        out.Write('struct %s;\n' % struct)
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Create a macro for the highest available release number.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if filenode.GetProperty('NAME').endswith('pp_macros.idl'):
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      releasestr = ' '.join(releases)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if releasestr:
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        release_numbers = re.findall('[\d\_]+', releasestr)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        release = re.findall('\d+', release_numbers[-1])[0]
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if release:
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          out.Write('\n#define PPAPI_RELEASE %s\n' % release)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generate all interface defines
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out.Write('\n')
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for node in filenode.GetListOf('Interface'):
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      idefs = ''
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      macro = cgen.GetInterfaceMacro(node)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unique = node.GetUniqueReleases(releases)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Skip this interface if there are no matching versions
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not unique: continue
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for rel in unique:
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        version = node.GetVersion(rel)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name = cgen.GetInterfaceString(node, version)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        strver = str(version).replace('.', '_')
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        idefs += cgen.GetDefine('%s_%s' % (macro, strver), '"%s"' % name)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      idefs += cgen.GetDefine(macro, '%s_%s' % (macro, strver)) + '\n'
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out.Write(idefs)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generate the @file comment
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out.Write('%s\n' % Comment(fileinfo, prefix='*\n @file'))
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateBody(self, out, filenode, releases, options):
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __pychecker__ = 'unusednames=options'
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GenerateHeader(out, filenode, releases)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateTail(self, out, filenode, releases, options):
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __pychecker__ = 'unusednames=options,releases'
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gpath = GetOption('guard')
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def_guard = GetPathFromNode(filenode, relpath=gpath, ext='.h')
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def_guard = def_guard.replace(os.sep,'_').replace('.','_').upper() + '_'
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out.Write('#endif  /* %s */\n\n' % def_guard)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hgen = HGen()
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def main(args):
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Default invocation will verify the golden files are unchanged.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  failed = 0
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not args:
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args = ['--wnone', '--diff', '--test', '--dstroot=.']
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ParseOptions(args)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  idldir = os.path.split(sys.argv[0])[0]
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  idldir = os.path.join(idldir, 'test_cgen', '*.idl')
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filenames = glob.glob(idldir)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ast = ParseFiles(filenames)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if hgen.GenerateRelease(ast, 'M14', {}):
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print "Golden file for M14 failed."
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    failed = 1
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print "Golden file for M14 passed."
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  idldir = os.path.split(sys.argv[0])[0]
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  idldir = os.path.join(idldir, 'test_cgen_range', '*.idl')
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filenames = glob.glob(idldir)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ast = ParseFiles(filenames)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if hgen.GenerateRange(ast, ['M13', 'M14', 'M15'], {}):
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print "Golden file for M13-M15 failed."
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    failed =1
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print "Golden file for M13-M15 passed."
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return failed
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sys.exit(main(sys.argv[1:]))
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
356