Statistics
| Branch: | Tag: | Revision:

root / autotools / convert-constants @ 36c70d4d

History | View | Annotate | Download (5.1 kB)

1 d99d1e36 Iustin Pop
#!/usr/bin/python
2 d99d1e36 Iustin Pop
#
3 d99d1e36 Iustin Pop
4 d99d1e36 Iustin Pop
# Copyright (C) 2011 Google Inc.
5 d99d1e36 Iustin Pop
#
6 d99d1e36 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 d99d1e36 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 d99d1e36 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 d99d1e36 Iustin Pop
# (at your option) any later version.
10 d99d1e36 Iustin Pop
#
11 d99d1e36 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 d99d1e36 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 d99d1e36 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 d99d1e36 Iustin Pop
# General Public License for more details.
15 d99d1e36 Iustin Pop
#
16 d99d1e36 Iustin Pop
# You should have received a copy of the GNU General Public License
17 d99d1e36 Iustin Pop
# along with this program; if not, write to the Free Software
18 d99d1e36 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 d99d1e36 Iustin Pop
# 02110-1301, USA.
20 d99d1e36 Iustin Pop
21 d99d1e36 Iustin Pop
"""Script for converting Python constants to Haskell code fragments.
22 d99d1e36 Iustin Pop
23 d99d1e36 Iustin Pop
"""
24 d99d1e36 Iustin Pop
25 d99d1e36 Iustin Pop
import re
26 d99d1e36 Iustin Pop
27 d99d1e36 Iustin Pop
from ganeti import constants
28 2325bfcf Iustin Pop
from ganeti import compat
29 d99d1e36 Iustin Pop
30 26fce8df Iustin Pop
#: Constant name regex
31 8751c041 Iustin Pop
CONSTANT_RE = re.compile("^[A-Z][A-Z0-9_-]+$")
32 d99d1e36 Iustin Pop
33 26fce8df Iustin Pop
#: The type of regex objects
34 26fce8df Iustin Pop
RE_TYPE = type(CONSTANT_RE)
35 26fce8df Iustin Pop
36 d99d1e36 Iustin Pop
37 d99d1e36 Iustin Pop
def NameRules(name):
38 d99d1e36 Iustin Pop
  """Converts the upper-cased Python name to Haskell camelCase.
39 d99d1e36 Iustin Pop
40 d99d1e36 Iustin Pop
  """
41 8751c041 Iustin Pop
  name = name.replace("-", "_")
42 d99d1e36 Iustin Pop
  elems = name.split("_")
43 d99d1e36 Iustin Pop
  return elems[0].lower() + "".join(e.capitalize() for e in elems[1:])
44 d99d1e36 Iustin Pop
45 d99d1e36 Iustin Pop
46 d99d1e36 Iustin Pop
def StringValueRules(value):
47 d99d1e36 Iustin Pop
  """Converts a string value from Python to Haskell.
48 d99d1e36 Iustin Pop
49 d99d1e36 Iustin Pop
  """
50 d99d1e36 Iustin Pop
  value = value.encode("string_escape") # escapes backslashes
51 d99d1e36 Iustin Pop
  value = value.replace("\"", "\\\"")
52 d99d1e36 Iustin Pop
  return value
53 d99d1e36 Iustin Pop
54 d99d1e36 Iustin Pop
55 8751c041 Iustin Pop
def DictKeyName(dict_name, key_name):
56 8751c041 Iustin Pop
  """Converts a dict plus key name to a full name.
57 8751c041 Iustin Pop
58 8751c041 Iustin Pop
  """
59 8751c041 Iustin Pop
  return"%s_%s" % (dict_name, str(key_name).upper())
60 8751c041 Iustin Pop
61 8751c041 Iustin Pop
62 df41d855 Iustin Pop
def HaskellTypeVal(value):
63 df41d855 Iustin Pop
  """Returns the Haskell type and value for a Python value.
64 df41d855 Iustin Pop
65 df41d855 Iustin Pop
  Note that this only work for 'plain' Python types.
66 df41d855 Iustin Pop
67 df41d855 Iustin Pop
  @returns: (string, string) or None, if we can't determine the type.
68 df41d855 Iustin Pop
69 df41d855 Iustin Pop
  """
70 df41d855 Iustin Pop
  if isinstance(value, basestring):
71 df41d855 Iustin Pop
    return ("String", "\"%s\"" % StringValueRules(value))
72 df41d855 Iustin Pop
  elif isinstance(value, int):
73 df41d855 Iustin Pop
    return ("Int", "%d" % value)
74 df41d855 Iustin Pop
  elif isinstance(value, long):
75 df41d855 Iustin Pop
    return ("Integer", "%d" % value)
76 df41d855 Iustin Pop
  elif isinstance(value, float):
77 df41d855 Iustin Pop
    return ("Double", "%f" % value)
78 df41d855 Iustin Pop
  else:
79 df41d855 Iustin Pop
    return None
80 df41d855 Iustin Pop
81 df41d855 Iustin Pop
82 8751c041 Iustin Pop
def ConvertVariable(name, value):
83 8751c041 Iustin Pop
  """Converts a given variable to Haskell code.
84 8751c041 Iustin Pop
85 8751c041 Iustin Pop
  @param name: the Python name
86 8751c041 Iustin Pop
  @param value: the value
87 8751c041 Iustin Pop
  @return: a list of Haskell code lines
88 8751c041 Iustin Pop
89 8751c041 Iustin Pop
  """
90 8751c041 Iustin Pop
  lines = []
91 8751c041 Iustin Pop
  hs_name = NameRules(name)
92 df41d855 Iustin Pop
  hs_typeval = HaskellTypeVal(value)
93 8751c041 Iustin Pop
  if not CONSTANT_RE.match(name):
94 8751c041 Iustin Pop
    lines.append("-- Skipped %s, not constant" % name)
95 df41d855 Iustin Pop
  elif hs_typeval is not None:
96 df41d855 Iustin Pop
    # this is a simple value
97 df41d855 Iustin Pop
    (hs_type, hs_val) = hs_typeval
98 8751c041 Iustin Pop
    lines.append("-- | Converted from Python constant %s" % name)
99 df41d855 Iustin Pop
    lines.append("%s :: %s" % (hs_name, hs_type))
100 df41d855 Iustin Pop
    lines.append("%s = %s" % (hs_name, hs_val))
101 8751c041 Iustin Pop
  elif isinstance(value, dict):
102 8751c041 Iustin Pop
    if value:
103 8751c041 Iustin Pop
      lines.append("-- Following lines come from dictionary %s" % name)
104 8751c041 Iustin Pop
      for k in sorted(value.keys()):
105 8751c041 Iustin Pop
        lines.extend(ConvertVariable(DictKeyName(name, k), value[k]))
106 2325bfcf Iustin Pop
  elif isinstance(value, tuple):
107 2325bfcf Iustin Pop
    tvs = [HaskellTypeVal(elem) for elem in value]
108 2325bfcf Iustin Pop
    if compat.all(e is not None for e in tvs):
109 2325bfcf Iustin Pop
      ttypes = ", ".join(e[0] for e in tvs)
110 2325bfcf Iustin Pop
      tvals = ", ".join(e[1] for e in tvs)
111 2325bfcf Iustin Pop
      lines.append("-- | Converted from Python tuple %s" % name)
112 2325bfcf Iustin Pop
      lines.append("%s :: (%s)" % (hs_name, ttypes))
113 2325bfcf Iustin Pop
      lines.append("%s = (%s)" % (hs_name, tvals))
114 2325bfcf Iustin Pop
    else:
115 2325bfcf Iustin Pop
      lines.append("-- Skipped tuple %s, cannot convert all elements" % name)
116 cf57f778 Iustin Pop
  elif isinstance(value, (list, set, frozenset)):
117 cf57f778 Iustin Pop
    # Lists and frozensets are handled the same in Haskell: as lists,
118 cf57f778 Iustin Pop
    # since lists are immutable and we don't need for constants the
119 cf57f778 Iustin Pop
    # high-speed of an actual Set type. However, we can only convert
120 cf57f778 Iustin Pop
    # them if they have the same type for all elements (which is a
121 cf57f778 Iustin Pop
    # normal expectation for constants, our code should be well
122 cf57f778 Iustin Pop
    # behaved); note that this is different from the tuples case,
123 cf57f778 Iustin Pop
    # where we always (for some values of always) can convert
124 cf57f778 Iustin Pop
    tvs = [HaskellTypeVal(elem) for elem in value]
125 cf57f778 Iustin Pop
    if compat.all(e is not None for e in tvs):
126 cf57f778 Iustin Pop
      ttypes, tvals = zip(*tvs)
127 cf57f778 Iustin Pop
      uniq_types = set(ttypes)
128 cf57f778 Iustin Pop
      if len(uniq_types) == 1:
129 cf57f778 Iustin Pop
        lines.append("-- | Converted from Python list or set %s" % name)
130 cf57f778 Iustin Pop
        lines.append("%s :: [%s]" % (hs_name, uniq_types.pop()))
131 cf57f778 Iustin Pop
        lines.append("%s = [%s]" % (hs_name, ", ".join(tvals)))
132 cf57f778 Iustin Pop
      else:
133 cf57f778 Iustin Pop
        lines.append("-- | Skipped list/set %s, is not homogeneous" % name)
134 cf57f778 Iustin Pop
    else:
135 cf57f778 Iustin Pop
      lines.append("-- | Skipped list/set %s, cannot convert all elems" % name)
136 26fce8df Iustin Pop
  elif isinstance(value, RE_TYPE):
137 26fce8df Iustin Pop
    tvs = HaskellTypeVal(value.pattern)
138 26fce8df Iustin Pop
    assert tvs is not None
139 26fce8df Iustin Pop
    lines.append("-- | Converted from Python RE object %s" % name)
140 26fce8df Iustin Pop
    lines.append("%s :: %s" % (hs_name, tvs[0]))
141 26fce8df Iustin Pop
    lines.append("%s = %s" % (hs_name, tvs[1]))
142 8751c041 Iustin Pop
  else:
143 8751c041 Iustin Pop
    lines.append("-- Skipped %s, %s not handled" % (name, type(value)))
144 8751c041 Iustin Pop
  return lines
145 8751c041 Iustin Pop
146 8751c041 Iustin Pop
147 d99d1e36 Iustin Pop
def Convert():
148 d99d1e36 Iustin Pop
  """Converts the constants to Haskell.
149 d99d1e36 Iustin Pop
150 d99d1e36 Iustin Pop
  """
151 d99d1e36 Iustin Pop
  lines = [""]
152 d99d1e36 Iustin Pop
153 d99d1e36 Iustin Pop
  all_names = dir(constants)
154 d99d1e36 Iustin Pop
155 d99d1e36 Iustin Pop
  for name in all_names:
156 d99d1e36 Iustin Pop
    value = getattr(constants, name)
157 8751c041 Iustin Pop
    lines.extend(ConvertVariable(name, value))
158 d99d1e36 Iustin Pop
    lines.append("")
159 d99d1e36 Iustin Pop
160 d99d1e36 Iustin Pop
  return "\n".join(lines)
161 d99d1e36 Iustin Pop
162 d99d1e36 Iustin Pop
163 d99d1e36 Iustin Pop
def main():
164 d99d1e36 Iustin Pop
  print Convert()
165 d99d1e36 Iustin Pop
166 d99d1e36 Iustin Pop
167 d99d1e36 Iustin Pop
if __name__ == "__main__":
168 d99d1e36 Iustin Pop
  main()