dan-da / py2php

py2php is a utility that will auto-translate python code into PHP code.
GNU General Public License v2.0
99 stars 32 forks source link

genexpr & listcomp #6

Closed gareth-ib closed 6 years ago

gareth-ib commented 6 years ago

Hey, any chance you can implement these? I'd do it but I don't really understand wtf python is doing in these scenarios

https://github.com/dan-da/py2php/blob/e0b6a2177fbb04db715c10f48adc758a65e2c9a7/py2php#L1500-L1506

They come up against things like..

        fit = ((b.fitness(width, height),  b) for b in self._open_bins)
        fit = (b for b in fit if b[0] is not None)
        rectangles = [r for r in self]
        if len(rectangles) <= 1:
            return
            sides = sorted(side for rect in self._rectangles for side in rect)
            max_height = sum(max(r[0], r[1]) for r in self._rectangles)
            min_width = max(min(r[0], r[1]) for r in self._rectangles)

etc etc... trying to run against this project: https://github.com/secnot/rectpack/

dan-da commented 6 years ago

thx for the suggestion. I just added support for generator expressions in c2d5713. There is a test case in tests/genexpr.py.

List comprehension expressions should be similar, I hope.

dan-da commented 6 years ago

I added support for list comprehension in 72a3f8fa33bba7fac8f17bd1a63b289b3e056da6.

There are some cases where the generated php will throw an error if a variable is referenced from outside the expression. This is because in PHP these are implemented as anonymous generator functions. That's tricky to deal with and I don't have a good solution in mind yet. Examples of this type of failing usage are presented but commented out in the testcase files.

may revisit later. closing this.

dan-da commented 6 years ago

ha! I figured out an easy way to fix variable scoping for the disabled test cases. The fix is in e08dc167c654151a4e33dbe4a039906c4c5808d2.

gareth-ib commented 6 years ago

thanks! I'll try it out right now!

gareth-ib commented 6 years ago

I'm getting an error from it now... I don't know how to find what line in the PHP causes the problem, but here is the error output

$ ./py2php ../python/rectpack/enclose.py
<?php
Traceback (most recent call last):
  File "./py2php", line 1859, in <module>
    print translate(file_name, module_name),
  File "./py2php", line 1690, in translate
    t = Translator(module_name, mod, output)
  File "./py2php", line 102, in __init__
    buf += self._class(child)
  File "./py2php", line 708, in _class
    buf += self._method(child, current_klass, class_name)
  File "./py2php", line 795, in _method
    buf += self._function(node, True, staticmethod)
  File "./py2php", line 247, in _function
    buf += self._stmt(child, None)
  File "./py2php", line 882, in _stmt
    buf += self._assign(node, current_klass)
  File "./py2php", line 1084, in _assign
    rhs = self.expr(node.expr, current_klass)
  File "./py2php", line 1664, in expr
    return self._listcomp(node, current_klass)
  File "./py2php", line 1552, in _listcomp
    buf += self._listcompfor(node.quals[0], node.expr, node.quals, current_klass)
  File "./py2php", line 1575, in _listcompfor
    buf += self._listcompif(if_cond, current_klass)
  File "./py2php", line 1587, in _listcompif
    return "if " + self._compare(node.test, current_klass)
  File "./py2php", line 1194, in _compare
    for nodeop in node.ops:
AttributeError: Not instance has no attribute 'ops'
dan-da commented 6 years ago

hmm, that's failing in the new list comprehension code. Is the python source code online? Can you post a link to it, or attach the file or the line(s) that fail?

not surprisingly, real world code has more complex cases than the tests I come up with.

gareth-ib commented 6 years ago

Yeah here are the two files that crashed

https://github.com/secnot/rectpack/blob/master/rectpack/enclose.py
https://github.com/secnot/rectpack/blob/master/rectpack/guillotine.py

others in the same path seem to have successfully fully encoded

dan-da commented 6 years ago

I just committed a fix. enclose.py works now. I haven't tried guillotine.py yet.

dan-da commented 6 years ago

confirmed guillotine.py is working.

gareth-ib commented 6 years ago

awesome! thanks so much!

dan-da commented 6 years ago

bedtime here. please let me know if you are able to translate all the files successfully or have other issues. I would be curious to hear how your porting project goes in the end, as I've received very little feedback to date.

gareth-ib commented 6 years ago

yeah I'll letcha know how it turns out, thanks! I did miss one more "fixme"

function float2dec($ft,$decimal_digits) {
// py2php.fixme "with" unsupported.
}

in the packer.py


# Float to Decimal helper
def float2dec(ft, decimal_digits):
    """
    Convert float (or int) to Decimal (rounding up) with the
    requested number of decimal digits.

    Arguments:
        ft (float, int): Number to convert
        decimal (int): Number of digits after decimal point

    Return:
        Decimal: Number converted to decima
    """
    with decimal.localcontext() as ctx:
        ctx.rounding = decimal.ROUND_UP
        places = decimal.Decimal(10)**(-decimal_digits)
        return decimal.Decimal.from_float(float(ft)).quantize(places)
gareth-ib commented 6 years ago

oooh man I didn't even think of all the dependency libraries that need to get converted as well... this'll be interesting... haha

dan-da commented 6 years ago

haha, that's the last py2php.fixme. you've found code that certainly exercises a lot python functionality. I'll check it out tomorrow. I'm not sure how difficult 'with' would be to support/emulate, since I don't believe php has a native construct for it.

yes, deps can be a showstopper. code translation is best used for "pure" standalone projects. often one can find similar libraries in your target language and substitute instead.

gareth-ib commented 6 years ago

hah of course it'd be the most difficult possible :) thanks!

gareth-ib commented 6 years ago

it's using things like itertools and operator. I'm looking into them... some seem not needed