"""generates code for binops in PyObject and for all "simple" ops in PyInstance"""

binops = \
	[('add', '+'), ('sub', '-'), ('mul', '*'), ('div', '/'),
         ('floordiv', '//'), ('truediv', '/'),
	 ('mod', '%'), ('divmod', 'divmod'), ('pow', '**'), 
	 ('lshift', '<<'), ('rshift', '>>'), ('and', '&'), ('or', '|'), ('xor', '^')]

#
# this bit is superseded by src/templates/make_binops.py
#
## template = """\
##     /**
##      * Equivalent to the standard Python __%(name)s__ method
##      * @param     other the object to perform this binary operation with
##      *            (the right-hand operand).
##      * @return    the result of the %(name)s, or null if this operation
##      *            is not defined
##      **/
##     public PyObject __%(name)s__(PyObject other) { %(function)s }

##     /**
##      * Equivalent to the standard Python __r%(name)s__ method
##      * @param     other the object to perform this binary operation with
##      *            (the left-hand operand).
##      * @return    the result of the %(name)s, or null if this operation
##      *            is not defined.
##      **/
##     public PyObject __r%(name)s__(PyObject other) { %(rfunction)s }

##     /**
##      * Equivalent to the standard Python __i%(name)s__ method
##      * @param     other the object to perform this binary operation with
##      *            (the right-hand operand).
##      * @return    the result of the %(name)s, or null if this operation
##      *            is not defined
##      **/
##     public PyObject __i%(name)s__(PyObject other) { return _%(name)s(other); }

##     /**
##      * Implements the Python expression <code>this %(op)s other</code>
##      * @param     other the object to perform this binary operation with.
##      * @return    the result of the %(name)s.
##      * @exception PyTypeError if this operation can't be performed
##      *            with these operands.
##      **/
##     public final PyObject _%(name)s(PyObject o2) {%(divhook)s
##         PyObject x = __%(name)s__(o2);
##         if (x != null)
##             return x;
##         x = o2.__r%(name)s__(this);
##         if (x != null)
##             return x;
##         throw Py.TypeError(
##                  "__%(name)s__ nor __r%(name)s__ defined for these operands");
##     }

## """

## fp = open('binops.txt', 'w')

## fp.write('    // Generated by make_binops.py (Begin)\n\n')

## for name, op in binops:
## 	rfunction = function = 'return null;'
##         divhook = ""

## 	if name == 'pow':
## 		function = 'return __pow__(other, null);'
## 	if name == 'div':
## 		divhook = '''
##         if (Options.Qnew)
##             return _truediv(o2);'''
                    
## 	fp.write(template % {
##             'name':name,
##             'op':op,
##             'function':function,
##             'rfunction':rfunction,
##             'divhook':divhook
##         })

## fp.write('    // Generated by make_binops.py (End)\n\n')

## fp.close()



fp = open('binopsi.txt', 'w')

fp.write('    // Generated by make_binops.py\n\n')

comment = """\
    /**
     * Implements the __%(name)s__ method by looking it up
     * in the instance's dictionary and calling it if it is found.
     **/
"""

template1 = """\
    @Override
    public %(ret)s __%(name)s__() {
        return instance___%(name)s__();
    }

""" + comment + """\
    @ExposedMethod
    final %(ret)s instance___%(name)s__() {
        PyObject ret = invoke("__%(name)s__");
        if (%(checks)s)
            return %(cast)sret;
        throw Py.TypeError("__%(name)s__() should return a %(retname)s");
    }

"""

template2 = """\
    @Override
    public PyObject __%(name)s__() {
        return instance___%(name)s__();
    }

""" + comment + """\
    @ExposedMethod
    public PyObject instance___%(name)s__() {
        return invoke("__%(name)s__");
    }

"""

string = 'PyString', 'string'
ops = [('hex', string), ('oct', string), 
		('int', ('PyObject', 'int'), ('PyLong', 'PyInteger')),
		('float', ('PyFloat', 'float')), 
		('long', ('PyObject', 'long'), ('PyLong', 'PyInteger')),
		('complex', ('PyComplex', 'complex')),
		('pos', None), ('neg', None), ('abs', None), ('invert', None)]
	
fp.write('    // Unary ops\n\n')	
for item in ops:
        checks = None
        if len(item) == 2:
                name, ret = item
        else:
                name, ret, checks = item
	if ret is None:
		fp.write(template2 % {'name':name})
	else:
		ret, retname = ret
		if checks:
                        checks = ' || '.join(['ret instanceof %s' % check for check in checks])
                else:
                        checks = 'ret instanceof %s' % ret
                if ret == 'PyObject':
                        cast = ''
                else:
                        cast = '(%s)' % ret
		fp.write(template1 % {'name':name, 'ret':ret, 'retname':retname,
                                      'checks':checks, 'cast':cast})



template = """\
    @Override
    public PyObject __%(name)s__(PyObject o) {
        return instance___%(name)s__(o);
    }

""" + comment + """\
    @ExposedMethod(type = MethodType.BINARY)
    public PyObject instance___%(name)s__(PyObject o) {
        Object ctmp = __coerce_ex__(o);
        if (ctmp == null || ctmp == Py.None)
            return invoke_ex("__%(name)s__", o);
        else {
            PyObject o1 = ((PyObject[])ctmp)[0];
            PyObject o2 = ((PyObject[])ctmp)[1];
            if (this == o1) {
                // Prevent recusion if __coerce__ return self
                return invoke_ex("__%(name)s__", o2);
            }
            else {
                ThreadState ts = Py.getThreadState();
                if (ts.recursion_depth++ > ts.systemState.getrecursionlimit())
                    throw Py.RuntimeError("maximum recursion depth exceeded");
                try {
                    return %(function)s;
                } finally {
                    --ts.recursion_depth;
                }
            }
        }
    }

"""


template2 = """\
    @Override
    public PyObject __%(name)s__(PyObject o) {
        return instance___%(name)s__(o);
    }

""" + comment + """\
    @ExposedMethod(type = MethodType.BINARY)
    public PyObject instance___%(name)s__(PyObject o) {
        PyObject ret = invoke_ex("__%(name)s__", o);
        if (ret != null)
            return ret;
        return super.__%(name)s__(o);
    }

"""

fp.write('    // Binary ops\n\n')
for name, op in binops:	
	fp.write(template % {'name':name, 'function':'o1._%s(o2)' % name })
	fp.write(template % {'name':'r'+name, 'function':'o2._%s(o1)' % name })
        if name != 'divmod':
		fp.write(template2 % {'name':'i'+name
})


fp.close()

