google / grumpy

Grumpy is a Python to Go source code transcompiler and runtime.
Apache License 2.0
10.56k stars 652 forks source link

Implement generator.throw() #369

Open m4ns0ur opened 6 years ago

m4ns0ur commented 6 years ago

@trotterdylan what is the best approach to test stmt and expr_visitor? could you give me a hint?

m4ns0ur commented 6 years ago

@trotterdylan generator cannot catch the thrown exception, I should check more.

m4ns0ur commented 6 years ago

@trotterdylan sorry for the long delay.

so the problem is generator cannot catch the thrown exception. here is the CPython code (in generator test):

def gen8():
  try:
    yield
  except ValueError as e:
    assert "foo" in str(e)
    yield
  else:
    raise AssertionError
g = gen8()
g.next()
g.throw(ValueError, 'foo')

and Grumpy generated code:

.
.
.
for ; πF.State() >= 0; πF.PopCheckpoint() {
    switch πF.State() {
    case 0:
    case 2: goto Label2
    case 3: goto Label3
    case 5: goto Label5
    default: panic("unexpected function state")
    }
    // line 2: try:
    πF.SetLineno(2)
    πF.PushCheckpoint(2)
    // line 3: yield
    πF.SetLineno(3)
    πF.PushCheckpoint(3)
    return πg.None, nil
Label3:
    if πThrown != nil {
        πE = πThrown
        πThrown = nil
        if πE != nil {
            continue
        }
    }
    πTemp001 = πSent
    πF.PopCheckpoint()
    if πTemp001, πE = πg.ResolveGlobal(πF, ßAssertionError); πE != nil {
        continue
    }
    // line 8: raise AssertionError
    πF.SetLineno(8)
    πE = πF.Raise(πTemp001, nil, nil)
    continue
    goto Label1
Label2:
    if πE == nil {
      continue
    }
    πE = nil
    πTemp002, πTemp003 = πF.ExcInfo()
    if πTemp001, πE = πg.ResolveGlobal(πF, ßValueError); πE != nil {
        continue
    }
    if πTemp004, πE = πg.IsInstance(πF, πTemp002.ToObject(), πTemp001); πE != nil {
        continue
    }
    if πTemp004 {
        goto Label4
    }
    πE = πF.Raise(πTemp002.ToObject(), nil, πTemp003.ToObject())
    continue
    // line 4: except ValueError as e:
    πF.SetLineno(4)
Label4:
    µe = πTemp002.ToObject()
    // line 5: assert "foo" in str(e)
    πF.SetLineno(5)
    πTemp005 = πF.MakeArgs(1)
    if πE = πg.CheckLocal(πF, µe, "e"); πE != nil {
        continue
    }
    πTemp005[0] = µe
    if πTemp006, πE = πg.ResolveGlobal(πF, ßstr); πE != nil {
        continue
    }
    if πTemp007, πE = πTemp006.Call(πF, πTemp005, nil); πE != nil {
        continue
    }
    πF.FreeArgs(πTemp005)
    if πTemp004, πE = πg.Contains(πF, πTemp007, ßfoo.ToObject()); πE != nil {
        continue
    }
    πTemp001 = πg.GetBool(πTemp004).ToObject()
    if πE = πg.Assert(πF, πTemp001, nil); πE != nil {
        continue
    }
    // line 6: yield
    πF.SetLineno(6)
    πF.PushCheckpoint(5)
    return πg.None, nil
Label5:
    if πThrown != nil {
        πE = πThrown
        πThrown = nil
        if πE != nil {
            continue
        }
    }
    πTemp001 = πSent
    πF.RestoreExc(nil, nil)
    goto Label1
Label1:
}
.
.
.

it seems OK to me, do you see anything improper?