/DLR_Main/Languages/IronPython/Scripts/make_meta1.py

https://bitbucket.org/mdavid/dlr · Python · 263 lines · 185 code · 54 blank · 24 comment · 41 complexity · 25609b256a0ff8c7dc0021a7d6c9cae7 MD5 · raw file

  1. #####################################################################################
  2. #
  3. # Copyright (c) Microsoft Corporation. All rights reserved.
  4. #
  5. # This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. # copy of the license can be found in the License.html file at the root of this distribution. If
  7. # you cannot locate the Apache License, Version 2.0, please send an email to
  8. # ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. # by the terms of the Apache License, Version 2.0.
  10. #
  11. # You must not remove this notice, or any other, from this software.
  12. #
  13. #
  14. #####################################################################################
  15. import os, re, string
  16. src_dir = r"c:\Documents and Settings\Jim\My Documents\Visual Studio Projects\IronPython"
  17. meth_pat = r"(?P<ret_type>\w+)\s+(?P<name>\w+)\s*\((?P<params>(?:\w|\s|,)*)\)"
  18. meth_pat = re.compile(r"public\s+(?P<mods>static\s+)?(virtual\s+)?"+meth_pat)
  19. class_pat = re.compile(r"public\s+(abstract\s+)?class\s+(?P<name>\w+)\s*(:\s*(?P<super_name>\w+))?")
  20. START = "//BEGIN-GENERATED"
  21. END = "//END-GENERATED"
  22. generated_pat = re.compile(START+".*"+END, re.DOTALL)
  23. from_table = {
  24. 'int':"Py.asInt(%s)",
  25. 'double':"Py.asDouble(%s)",
  26. 'char':"Py.asChar(%s)",
  27. 'PyObject':"%s",
  28. }
  29. def from_any(totype, name):
  30. pat = from_table.get(totype, None)
  31. if pat is None:
  32. return "(%s)%s" % (totype, name)
  33. else:
  34. return pat % name
  35. to_table = {
  36. 'int':"PyInteger.make(%s)",
  37. 'double':"PyFloat.make(%s)",
  38. 'bool':"PyBoolean.make(%s)",
  39. 'char':"PyString.make(%s)",
  40. 'PyObject':"%s",
  41. }
  42. def to_any(totype, name):
  43. pat = to_table.get(totype, None)
  44. if pat is None:
  45. return name #"(%s)%s" % (totype, name)
  46. else:
  47. return pat % name
  48. BINOP = """
  49. public override PyObject __%(name)s__(PyObject other) {
  50. %(type)s ov;
  51. if (!Py.check%(ctype)s(other, out ov)) return Py.NotImplemented;
  52. return %(ret_type)s.make(%(name)s(_value, ov));
  53. }
  54. public override PyObject __r%(name)s__(PyObject other) {
  55. %(type)s ov;
  56. if (!Py.check%(ctype)s(other, out ov)) return Py.NotImplemented;
  57. return %(ret_type)s.make(%(name)s(ov, _value));
  58. }
  59. """
  60. UNOP = """
  61. public override PyObject __%(name)s__() {
  62. return %(ret_type)s.make(%(name)s(_value));
  63. }
  64. """
  65. class Method:
  66. def __init__(self, ret_type, name, params, mods=None):
  67. self.param_list = map(lambda s: s.strip(), string.split(params, ","))
  68. self.param_list = filter(lambda s: s, self.param_list)
  69. self.ret_type = ret_type
  70. self.name = name
  71. self.mods = mods
  72. self.is_invokable = True
  73. def get_public_name(self):
  74. name = self.name
  75. if name.endswith("_") and not name.endswith("__"):
  76. name = name[:-1]
  77. return name
  78. def is_any(self):
  79. if self.ret_type != ANY or self.mods: return False
  80. for p in self.param_list:
  81. if not p.startswith(ANY): return False
  82. return True
  83. def is_static(self):
  84. return self.mods is not None
  85. def is_internal(self):
  86. return self.name.endswith("__")
  87. def make_op(self):
  88. self.is_invokable = False
  89. type = self.param_list[0].split(" ")[0]
  90. dict = {
  91. 'name':self.get_public_name(),
  92. 'type':type,
  93. 'ctype':type.capitalize(),
  94. 'ret_type':to_table[self.ret_type].split('.')[0]
  95. }
  96. if len(self.param_list) == 2:
  97. return (BINOP % dict).split("\n")
  98. else:
  99. return (UNOP % dict).split("\n")
  100. def make_any(self, in_module=False):
  101. if not in_module and self.is_static():
  102. return self.make_op()
  103. name = self.get_public_name()
  104. params = []
  105. args = []
  106. for p in self.param_list:
  107. ptype, pname = string.split(p)
  108. args.append(from_any(ptype, pname))
  109. params.append("PyObject %s" % pname)
  110. if self.is_internal():
  111. mods = "override "
  112. self.is_invokable = False
  113. else:
  114. mods = ""
  115. if self.is_static():
  116. mods += "static "
  117. ret = ["public %sPyObject %s(%s) {" % (mods, name, string.join(params, ", "))]
  118. if self.ret_type == 'void':
  119. ret.append(" %s(%s);" % (self.name, string.join(args, ", ")))
  120. ret.append(" return Py.None;")
  121. else:
  122. value = "%s(%s)" % (self.name, string.join(args, ", "))
  123. ret.append(" return %s;" % to_any(self.ret_type, value))
  124. ret.append("}")
  125. return ret
  126. def __repr__(self):
  127. return "Method(%s, %s, %s)" % (self.ret_type, self.name, self.param_list)
  128. class Class:
  129. def __init__(self, name, super_name, methods):
  130. self.name = name
  131. self.super_name = super_name
  132. self.methods = methods
  133. self.strings = {}
  134. def get_constant_string(self, s):
  135. if not self.strings.has_key(s):
  136. self.strings[s] = s + "_str"
  137. return self.strings[s]
  138. def make_invoke_method(self, nargs):
  139. params = ["PyString name"]
  140. args = ["name"]
  141. for i in range(nargs):
  142. params.append("PyObject arg%d" % i)
  143. args.append("arg%d" % i)
  144. ret = ["public override PyObject invoke(%s) {" % ", ".join(params)]
  145. ret.append(" if (name.interned) {")
  146. #TODO create switch clause when more than 3-8 matches
  147. for method in self.methods:
  148. if not method.is_invokable or len(method.param_list) != nargs:
  149. continue
  150. name = method.get_public_name()
  151. ret.append(" if (name == %s) return %s(%s);" %
  152. (self.get_constant_string(name), name,
  153. ", ".join(args[1:])))
  154. if len(ret) == 2: return []
  155. ret.append(" }")
  156. ret.append(" return base.invoke(%s);" % ", ".join(args))
  157. ret.append("}")
  158. return ret
  159. def make_any_methods(self):
  160. ret = []
  161. # first generate the any forms of each method
  162. for method in self.methods:
  163. if not method.is_any():
  164. ret.extend(method.make_any(self.super_name == 'PyModule'))
  165. # now generate the various invoke methods
  166. for i in range(4):
  167. ret.extend(self.make_invoke_method(i))
  168. #TODO invokeN
  169. for value, name in self.strings.items():
  170. ret.append('static readonly PyString %s = PyString.intern("%s");' %
  171. (name, value))
  172. return ret
  173. def __repr__(self):
  174. return "Class(%s, %s)" % (self.name, self.super_name)
  175. def collect_methods(text):
  176. text = generated_pat.sub("", text)
  177. ret = []
  178. match= class_pat.search(text)
  179. #print match
  180. if match is None:
  181. return None
  182. cl = Class(match.group('name'), match.group('super_name'), ret)
  183. for match in meth_pat.finditer(text):
  184. meth = Method(**match.groupdict())
  185. if meth.is_static() and meth.name in ['make', 'intern']: continue
  186. ret.append(meth)
  187. return cl
  188. base = collect_methods(open(os.path.join(src_dir, "PyObject.cs")).read())
  189. ANY = base.name
  190. for file in os.listdir(src_dir):
  191. filename = os.path.join(src_dir, file)
  192. if not filename.endswith(".cs"): continue
  193. text = open(filename).read()
  194. if generated_pat.search(text) is None: continue
  195. c = collect_methods(text)
  196. assert c is not None and c.name != base.name
  197. #if c.super_name != 'PyModule':
  198. # assert c.super_name == base.name, c.super_name
  199. print c, c.methods
  200. code = c.make_any_methods()
  201. code.insert(0, START)
  202. code.append(END)
  203. generated_code = "\n\t\t".join(code)
  204. new_text = generated_pat.sub(generated_code, text)
  205. #print new_text
  206. if text != new_text:
  207. open(filename, 'w').write(new_text)
  208. #print c, c.methods
  209. #print meth_pat.search("public void m(int a, float d)").groups()