#!/usr/bin/env python
# Copyright 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.

"""Translate parse tree to Mojom IR"""


import os
import sys


def MapKind(kind):
  map_to_kind = { 'bool': 'b',
                  'int8': 'i8',
                  'int16': 'i16',
                  'int32': 'i32',
                  'int64': 'i64',
                  'uint8': 'u8',
                  'uint16': 'u16',
                  'uint32': 'u32',
                  'uint64': 'u64',
                  'float': 'f',
                  'double': 'd',
                  'string': 's',
                  'handle': 'h',
                  'handle<message_pipe>': 'h:m' }
  if kind.endswith('[]'):
    return 'a:' + MapKind(kind[0:len(kind)-2])
  if kind in map_to_kind:
    return map_to_kind[kind]
  return 'x:' + kind


def MapOrdinal(ordinal):
  if ordinal == None:
    return None;
  return int(ordinal[1:])  # Strip leading '@'


def GetAttribute(attributes, name):
  out = None
  for attribute in attributes:
    if attribute[0] == 'ATTRIBUTE' and attribute[1] == name:
      out = attribute[2]
  return out


def MapFields(fields):
  out = []
  for field in fields:
    if field[0] == 'FIELD':
      out.append({'name': field[2],
                  'kind': MapKind(field[1]),
                  'ordinal': MapOrdinal(field[3])})
  return out


def MapParameters(parameters):
  out = []
  for parameter in parameters:
    if parameter[0] == 'PARAM':
      out.append({'name': parameter[2],
                  'kind': MapKind(parameter[1]),
                  'ordinal': MapOrdinal(parameter[3])})
  return out


def MapMethods(methods):
  out = []
  for method in methods:
    if method[0] == 'METHOD':
      out.append({'name': method[1],
                  'parameters': MapParameters(method[2]),
                  'ordinal': MapOrdinal(method[3])})
  return out

def MapEnumFields(fields):
  out = []
  for field in fields:
    if field[0] == 'ENUM_FIELD':
      out.append({'name': field[1],
                  'value': field[2]})
  return out

class MojomBuilder():

  def __init__(self):
    self.mojom = {}

  def AddStruct(self, name, attributes, fields):
    struct = {}
    struct['name'] = name
    # TODO(darin): Add support for |attributes|
    #struct['attributes'] = MapAttributes(attributes)
    struct['fields'] = MapFields(fields)
    self.mojom['structs'].append(struct)

  def AddInterface(self, name, attributes, methods):
    interface = {}
    interface['name'] = name
    interface['peer'] = GetAttribute(attributes, 'Peer')
    interface['methods'] = MapMethods(methods)
    self.mojom['interfaces'].append(interface)

  def AddEnum(self, name, fields):
    # TODO(mpcomplete): add support for specifying enums as types. Right now
    # we just use int32.
    enum = {}
    enum['name'] = name
    enum['fields'] = MapEnumFields(fields)
    self.mojom['enums'].append(enum)

  def AddModule(self, name, namespace, contents):
    self.mojom['name'] = name
    self.mojom['namespace'] = namespace
    self.mojom['structs'] = []
    self.mojom['interfaces'] = []
    self.mojom['enums'] = []
    for item in contents:
      if item[0] == 'STRUCT':
        self.AddStruct(name=item[1], attributes=item[2], fields=item[3])
      elif item[0] == 'INTERFACE':
        self.AddInterface(name=item[1], attributes=item[2], methods=item[3])
      elif item[0] == 'ENUM':
        self.AddEnum(name=item[1], fields=item[2])

  def Build(self, tree, name):
    if tree[0] == 'MODULE':
      self.AddModule(name=name, namespace=tree[1], contents=tree[2])
    return self.mojom


def Translate(tree, name):
  return MojomBuilder().Build(tree, name)


def Main():
  if len(sys.argv) < 2:
    print("usage: %s filename" % (sys.argv[0]))
    sys.exit(1)
  tree = eval(open(sys.argv[1]).read())
  name = os.path.splitext(os.path.basename(sys.argv[1]))[0]
  result = Translate(tree, name)
  print(result)


if __name__ == '__main__':
  Main()