[cig-commits] r6505 - cs/babel/trunk/spike/Spike/Compiler
leif at geodynamics.org
leif at geodynamics.org
Tue Apr 3 20:43:08 PDT 2007
Author: leif
Date: 2007-04-03 20:43:07 -0700 (Tue, 03 Apr 2007)
New Revision: 6505
Modified:
cs/babel/trunk/spike/Spike/Compiler/ExprNodes.py
cs/babel/trunk/spike/Spike/Compiler/Nodes.py
cs/babel/trunk/spike/Spike/Compiler/Symtab.py
Log:
Allow Pyre components to be declared from Pyrex code. This was
prevented by the fact that Pyrex passes an empty dictionary to
PyClass_New() -- and therefore the __init__ methods in Pyre's
metaclasses likewise get fed an empty dictionary.
Currently, Pyrex-based Components must be declared in the CIG-Pyre
abbreviated style:
from pyre.components import Component
class Tomato(Component):
name = "tomato"
import pyre.inventory
color = pyre.inventory.str("color", default="red")
One can't use 'Inventory' because I haven't fixed Pyrex's "no nested
classes" limitation (yet).
(As for Spike: it still doesn't have grammar rules for classes.)
Modified: cs/babel/trunk/spike/Spike/Compiler/ExprNodes.py
===================================================================
--- cs/babel/trunk/spike/Spike/Compiler/ExprNodes.py 2007-04-02 22:08:35 UTC (rev 6504)
+++ cs/babel/trunk/spike/Spike/Compiler/ExprNodes.py 2007-04-04 03:43:07 UTC (rev 6505)
@@ -742,7 +742,7 @@
# Reference to C array turns into pointer to first element.
while self.type.is_array:
self.type = self.type.element_ptr_type()
- if self.entry.is_pyglobal or self.entry.is_builtin:
+ if self.entry.is_pyglobal or self.entry.is_builtin or self.entry.is_pyclass:
assert self.type.is_pyobject, "Python global or builtin not a Python object"
self.is_temp = 1
if Options.intern_names:
@@ -834,6 +834,27 @@
self.entry.name,
self.result_code,
code.error_goto(self.pos)))
+ elif entry.is_pyclass:
+ namespace = entry.dict_cname
+ if Options.intern_names:
+ #assert entry.interned_cname is not None
+ code.putln(
+ '%s = PyDict_GetItem(%s, %s); if (!%s) %s' % (
+ self.result_code,
+ namespace,
+ entry.interned_cname,
+ self.result_code,
+ code.error_goto(self.pos)))
+ else:
+ code.putln(
+ '%s = PyDict_GetItem(%s, "%s"); if (!%s) %s' % (
+ self.result_code,
+ namespace,
+ self.entry.name,
+ self.result_code,
+ code.error_goto(self.pos)))
+ # PyDict_GetItem returns a borrowed reference.
+ code.put_incref(self.result_code, self.ctype())
def generate_assignment_code(self, rhs, code):
entry = self.entry
@@ -859,6 +880,26 @@
print "NameNode.generate_assignment_code:"
print "...generating disposal code for", rhs
rhs.generate_disposal_code(code)
+ elif entry.is_pyclass:
+ namespace = self.entry.dict_cname
+ if Options.intern_names:
+ code.putln(
+ 'if (PyDict_SetItem(%s, %s, %s) < 0) %s' % (
+ namespace,
+ entry.interned_cname,
+ rhs.py_result(),
+ code.error_goto(self.pos)))
+ else:
+ code.putln(
+ 'if (PyDict_SetItemString(%s, "%s", %s) < 0) %s' % (
+ namespace,
+ entry.name,
+ rhs.py_result(),
+ code.error_goto(self.pos)))
+ if debug_disposal_code:
+ print "NameNode.generate_assignment_code:"
+ print "...generating disposal code for", rhs
+ rhs.generate_disposal_code(code)
else:
if self.type.is_pyobject:
#print "NameNode.generate_assignment_code: to", self.name ###
@@ -1981,31 +2022,6 @@
code.error_goto(self.pos)))
-class UnboundMethodNode(ExprNode):
- # Helper class used in the implementation of Python
- # class definitions. Constructs an unbound method
- # object from a class and a function.
- #
- # class_cname string C var holding the class object
- # function ExprNode Function object
-
- subexprs = ['function']
-
- def analyse_types(self, env):
- self.function.analyse_types(env)
- self.type = py_object_type
- self.is_temp = 1
-
- def generate_result_code(self, code):
- code.putln(
- "%s = PyMethod_New(%s, 0, %s); if (!%s) %s" % (
- self.result_code,
- self.function.py_result(),
- self.class_cname,
- self.result_code,
- code.error_goto(self.pos)))
-
-
class PyCFunctionNode(AtomicExprNode):
# Helper class used in the implementation of Python
# class definitions. Constructs a PyCFunction object
@@ -3431,15 +3447,44 @@
PyObject *bases, PyObject *dict, PyObject *name, char *modname)
{
PyObject *py_modname;
+ PyObject *new_class = 0;
+ PyObject *method = 0;
PyObject *result = 0;
+ PyObject *key, *value;
+ int pos;
py_modname = PyString_FromString(modname);
if (!py_modname)
goto bad;
if (PyDict_SetItemString(dict, "__module__", py_modname) < 0)
goto bad;
- result = PyClass_New(bases, dict, name);
+ new_class = PyClass_New(bases, dict, name);
+ if (!new_class)
+ goto bad;
+ /*
+ * Manually wrap PyCFunction objects in PyMethod objects. This is
+ * necessary because -- whereas PyFunction_Type's tp_descr_get
+ * slot points to the func_descr_get "bind a function to an
+ * object" magic function -- PyCFunction_Type's tp_descr_get slot
+ * is null... i.e., "built-in" (native) functions don't get the
+ * object-binding magic.
+ */
+ pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &value)) {
+ if (PyCFunction_Check(value)) {
+ Py_XDECREF(method);
+ method = PyMethod_New(value, 0, new_class);
+ if (!method)
+ goto bad;
+ if (PyObject_SetAttr(new_class, key, method) < 0)
+ goto bad;
+ }
+ }
+ result = new_class;
+ Py_INCREF(result);
bad:
+ Py_XDECREF(method);
+ Py_XDECREF(new_class);
Py_XDECREF(py_modname);
return result;
}
Modified: cs/babel/trunk/spike/Spike/Compiler/Nodes.py
===================================================================
--- cs/babel/trunk/spike/Spike/Compiler/Nodes.py 2007-04-02 22:08:35 UTC (rev 6504)
+++ cs/babel/trunk/spike/Spike/Compiler/Nodes.py 2007-04-04 03:43:07 UTC (rev 6505)
@@ -2200,10 +2200,8 @@
import ExprNodes
self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name),
- rhs = ExprNodes.UnboundMethodNode(self.pos,
- class_cname = env.class_obj_cname,
- function = ExprNodes.PyCFunctionNode(self.pos,
- pymethdef_cname = self.entry.pymethdef_cname)))
+ rhs = ExprNodes.PyCFunctionNode(self.pos,
+ pymethdef_cname = self.entry.pymethdef_cname))
self.assmt.analyse_declarations(env)
self.assmt.analyse_expressions(env)
@@ -2554,14 +2552,13 @@
def analyse_expressions(self, env):
self.dict.analyse_expressions(env)
- self.classobj.analyse_expressions(env)
genv = env.global_scope()
cenv = PyClassScope(name = self.name, outer_scope = genv)
cenv.class_dict_cname = self.dict.result_code
- cenv.class_obj_cname = self.classobj.result_code
self.scope = cenv
self.body.analyse_declarations(cenv)
self.body.analyse_expressions(cenv)
+ self.classobj.analyse_expressions(env)
self.target.analyse_target_expression(env)
self.dict.release_temp(env)
self.classobj.release_temp(env)
@@ -2575,8 +2572,8 @@
def generate_execution_code(self, code):
self.dict.generate_evaluation_code(code)
- self.classobj.generate_evaluation_code(code)
self.body.generate_execution_code(code)
+ self.classobj.generate_evaluation_code(code)
self.target.generate_assignment_code(self.classobj, code)
self.dict.generate_disposal_code(code)
Modified: cs/babel/trunk/spike/Spike/Compiler/Symtab.py
===================================================================
--- cs/babel/trunk/spike/Spike/Compiler/Symtab.py 2007-04-02 22:08:35 UTC (rev 6504)
+++ cs/babel/trunk/spike/Spike/Compiler/Symtab.py 2007-04-04 03:43:07 UTC (rev 6505)
@@ -29,7 +29,7 @@
# is_builtin boolean Is a Python builtin name
# is_cglobal boolean Is a C global variable
# is_pyglobal boolean Is a Python module-level variable
- # or class attribute during
+ # is_pyclass boolean Is a Python class attribute during
# class construction
# is_variable boolean Is a variable
# is_cfunction boolean Is a C function
@@ -72,6 +72,7 @@
is_builtin = 0
is_cglobal = 0
is_pyglobal = 0
+ is_pyclass = 0
is_variable = 0
is_cfunction = 0
is_spikefunction = 0
@@ -902,8 +903,8 @@
# Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
- entry.is_pyglobal = 1
- entry.namespace_cname = self.class_obj_cname
+ entry.is_pyclass = 1
+ entry.dict_cname = self.class_dict_cname
if Options.intern_names:
entry.interned_cname = self.intern(name)
return entry
More information about the cig-commits
mailing list