PageRenderTime 148ms CodeModel.GetById 21ms app.highlight 100ms RepoModel.GetById 4ms app.codeStats 0ms

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

https://bitbucket.org/mdavid/dlr
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