/DLR_Main/Languages/IronPython/Scripts/make_meta1.py
Python | 263 lines | 236 code | 13 blank | 14 comment | 6 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
16import os, re, string
17
18src_dir = r"c:\Documents and Settings\Jim\My Documents\Visual Studio Projects\IronPython"
19
20meth_pat = r"(?P<ret_type>\w+)\s+(?P<name>\w+)\s*\((?P<params>(?:\w|\s|,)*)\)"
21meth_pat = re.compile(r"public\s+(?P<mods>static\s+)?(virtual\s+)?"+meth_pat)
22
23class_pat = re.compile(r"public\s+(abstract\s+)?class\s+(?P<name>\w+)\s*(:\s*(?P<super_name>\w+))?")
24
25START = "//BEGIN-GENERATED"
26END = "//END-GENERATED"
27
28generated_pat = re.compile(START+".*"+END, re.DOTALL)
29
30from_table = {
31 'int':"Py.asInt(%s)",
32 'double':"Py.asDouble(%s)",
33 'char':"Py.asChar(%s)",
34 'PyObject':"%s",
35}
36
37
38def from_any(totype, name):
39 pat = from_table.get(totype, None)
40 if pat is None:
41 return "(%s)%s" % (totype, name)
42 else:
43 return pat % name
44
45to_table = {
46 'int':"PyInteger.make(%s)",
47 'double':"PyFloat.make(%s)",
48 'bool':"PyBoolean.make(%s)",
49 'char':"PyString.make(%s)",
50 'PyObject':"%s",
51}
52
53
54def to_any(totype, name):
55 pat = to_table.get(totype, None)
56 if pat is None:
57 return name #"(%s)%s" % (totype, name)
58 else:
59 return pat % name
60
61BINOP = """
62public override PyObject __%(name)s__(PyObject other) {
63 %(type)s ov;
64 if (!Py.check%(ctype)s(other, out ov)) return Py.NotImplemented;
65 return %(ret_type)s.make(%(name)s(_value, ov));
66}
67public override PyObject __r%(name)s__(PyObject other) {
68 %(type)s ov;
69 if (!Py.check%(ctype)s(other, out ov)) return Py.NotImplemented;
70 return %(ret_type)s.make(%(name)s(ov, _value));
71}
72"""
73
74UNOP = """
75public override PyObject __%(name)s__() {
76 return %(ret_type)s.make(%(name)s(_value));
77}
78"""
79
80class Method:
81 def __init__(self, ret_type, name, params, mods=None):
82 self.param_list = map(lambda s: s.strip(), string.split(params, ","))
83 self.param_list = filter(lambda s: s, self.param_list)
84 self.ret_type = ret_type
85 self.name = name
86 self.mods = mods
87 self.is_invokable = True
88
89 def get_public_name(self):
90 name = self.name
91 if name.endswith("_") and not name.endswith("__"):
92 name = name[:-1]
93 return name
94
95 def is_any(self):
96 if self.ret_type != ANY or self.mods: return False
97 for p in self.param_list:
98 if not p.startswith(ANY): return False
99 return True
100
101 def is_static(self):
102 return self.mods is not None
103
104 def is_internal(self):
105 return self.name.endswith("__")
106
107 def make_op(self):
108 self.is_invokable = False
109 type = self.param_list[0].split(" ")[0]
110 dict = {
111 'name':self.get_public_name(),
112 'type':type,
113 'ctype':type.capitalize(),
114 'ret_type':to_table[self.ret_type].split('.')[0]
115 }
116
117 if len(self.param_list) == 2:
118 return (BINOP % dict).split("\n")
119 else:
120 return (UNOP % dict).split("\n")
121
122 def make_any(self, in_module=False):
123 if not in_module and self.is_static():
124 return self.make_op()
125
126 name = self.get_public_name()
127 params = []
128 args = []
129 for p in self.param_list:
130 ptype, pname = string.split(p)
131 args.append(from_any(ptype, pname))
132 params.append("PyObject %s" % pname)
133
134 if self.is_internal():
135 mods = "override "
136 self.is_invokable = False
137 else:
138 mods = ""
139
140 if self.is_static():
141 mods += "static "
142
143 ret = ["public %sPyObject %s(%s) {" % (mods, name, string.join(params, ", "))]
144 if self.ret_type == 'void':
145 ret.append(" %s(%s);" % (self.name, string.join(args, ", ")))
146 ret.append(" return Py.None;")
147 else:
148 value = "%s(%s)" % (self.name, string.join(args, ", "))
149 ret.append(" return %s;" % to_any(self.ret_type, value))
150
151 ret.append("}")
152 return ret
153
154 def __repr__(self):
155 return "Method(%s, %s, %s)" % (self.ret_type, self.name, self.param_list)
156
157class Class:
158 def __init__(self, name, super_name, methods):
159 self.name = name
160 self.super_name = super_name
161 self.methods = methods
162 self.strings = {}
163
164 def get_constant_string(self, s):
165 if not self.strings.has_key(s):
166 self.strings[s] = s + "_str"
167
168 return self.strings[s]
169
170 def make_invoke_method(self, nargs):
171 params = ["PyString name"]
172 args = ["name"]
173 for i in range(nargs):
174 params.append("PyObject arg%d" % i)
175 args.append("arg%d" % i)
176 ret = ["public override PyObject invoke(%s) {" % ", ".join(params)]
177 ret.append(" if (name.interned) {")
178
179 #TODO create switch clause when more than 3-8 matches
180 for method in self.methods:
181 if not method.is_invokable or len(method.param_list) != nargs:
182 continue
183 name = method.get_public_name()
184 ret.append(" if (name == %s) return %s(%s);" %
185 (self.get_constant_string(name), name,
186 ", ".join(args[1:])))
187
188 if len(ret) == 2: return []
189
190 ret.append(" }")
191 ret.append(" return base.invoke(%s);" % ", ".join(args))
192 ret.append("}")
193 return ret
194
195 def make_any_methods(self):
196 ret = []
197 # first generate the any forms of each method
198 for method in self.methods:
199 if not method.is_any():
200 ret.extend(method.make_any(self.super_name == 'PyModule'))
201
202 # now generate the various invoke methods
203 for i in range(4):
204 ret.extend(self.make_invoke_method(i))
205 #TODO invokeN
206
207 for value, name in self.strings.items():
208 ret.append('static readonly PyString %s = PyString.intern("%s");' %
209 (name, value))
210
211 return ret
212
213 def __repr__(self):
214 return "Class(%s, %s)" % (self.name, self.super_name)
215
216def collect_methods(text):
217 text = generated_pat.sub("", text)
218
219 ret = []
220 match= class_pat.search(text)
221 #print match
222 if match is None:
223 return None
224 cl = Class(match.group('name'), match.group('super_name'), ret)
225
226 for match in meth_pat.finditer(text):
227 meth = Method(**match.groupdict())
228 if meth.is_static() and meth.name in ['make', 'intern']: continue
229 ret.append(meth)
230
231 return cl
232
233base = collect_methods(open(os.path.join(src_dir, "PyObject.cs")).read())
234ANY = base.name
235
236
237for file in os.listdir(src_dir):
238 filename = os.path.join(src_dir, file)
239 if not filename.endswith(".cs"): continue
240 text = open(filename).read()
241
242 if generated_pat.search(text) is None: continue
243
244 c = collect_methods(text)
245 assert c is not None and c.name != base.name
246 #if c.super_name != 'PyModule':
247 # assert c.super_name == base.name, c.super_name
248
249 print c, c.methods
250 code = c.make_any_methods()
251 code.insert(0, START)
252 code.append(END)
253 generated_code = "\n\t\t".join(code)
254 new_text = generated_pat.sub(generated_code, text)
255 #print new_text
256 if text != new_text:
257 open(filename, 'w').write(new_text)
258
259
260#print c, c.methods
261
262#print meth_pat.search("public void m(int a, float d)").groups()
263