temperlang / temper

3 stars 0 forks source link

Generated lua function can't finish successfully #100

Closed tjpalmer closed 8 months ago

tjpalmer commented 8 months ago

This temper code:

let hi(ncols: Int, length: Int): Int | Bubble {
  if (length % ncols != 0) { bubble() }
  length / ncols
}

Translates to this in lua:

hi = function(ncols__2, length__3)
  local return__0, t_0, local_1, local_2, local_3, local_9, local_10, local_11;
  ::continue_1::local_1, local_2, local_3 = temper.pcall(function()
    t_0 = temper.imod(length__3, ncols__2);
  end);
  if local_1 then
  else
    goto break_0;
  end
  if (t_0 ~= 0.0) then
    local local_5, local_6, local_7;
    local_5, local_6, local_7 = temper.pcall(function()
      temper.bubble();
    end);
    if local_5 then
    else
      goto break_0;
    end
  end
  local_9, local_10, local_11 = temper.pcall(function()
    return__0 = temper.idiv(length__3, ncols__2);
    return return__0, 'return';
  end);
  if local_9 then
  end
  ::break_0::temper.bubble();
end;

But all paths eventually lead to that final bubble. I suspect something else ought to happen in the if local_9 block.

This is boiled down from larger code that works in the other backends.

ben-509 commented 8 months ago

I think the same issue is showing up with the generated Lua for the new functions/local* tests. It's not the local capturing that's the issue, but the show function from these tests:

let show(x: Listed<Int>): String {
  let s = new ListBuilder<String>();
  s.add("[");
  var c = "";
  for (var i = 0; i < x.length; i++) {
    s.add(c);
    s.add(x[i].toString());
    c = ", ";
  }
  s.add("]");
  // this seems a bit verbose for identity :-/
  return s.join("") { (v: String): String ;; v };
}

Generates the following Lua code that hangs; the problem seems to be at the end.

local temper = require('temper-core/prelude');
local show__3, constantCapture__4, exports;
show__3 = function(x__5)
  local return__1, t_0, t_1, s__7, local_2, local_3, local_4, c__8, i__9;
  s__7 = temper.listbuilder_constructor();
  ::continue_1::local_2, local_3, local_4 = temper.pcall(function()
    temper.listbuilder_add(s__7, '[');
  end);
  if local_2 then
  else
    goto break_0;
  end
  c__8 = '';
  i__9 = 0.0;
  while true do
    t_0 = temper.listed_length(x__5);
    if (i__9 < t_0) then
      local local_6, local_7, local_8;
      local_6, local_7, local_8 = temper.pcall(function()
        temper.listbuilder_add(s__7, c__8);
        t_1 = temper.listed_get(x__5, i__9);
        temper.listbuilder_add(s__7, temper.int_tostring(t_1));
      end);
      if local_6 then
      else
        break;
      end
      c__8 = ', ';
      i__9 = (i__9 + 1.0);
    else
      local local_10, local_11, local_12;
      local_10, local_11, local_12 = temper.pcall(function()
        local fn__71;
        temper.listbuilder_add(s__7, ']');
        fn__71 = function(v__10)
          return v__10, 'return';
        end;
        return__1 = temper.listbuilder_join(s__7, '', fn__71);
        return return__1, 'return';
      end);
      if local_10 then  -- seems like this should return from the function.
      else
        goto break_0;
      end
    end
  end
  ::break_0::temper.bubble();
end;
tjpalmer commented 8 months ago

I think the same issue is showing up with the generated Lua for the new functions/local* tests.

That does look similar. On my new branch, I've already added a some code to a funtest for this case also, and I'm planning to dig into it either today or Monday.

Have you started looking into causes/fixes yet on your end?

ben-509 commented 8 months ago

Not yet... I ran it through a debugger to find the hang, and once I confirmed it's not related to local functions, I wanted to note that here and get back to adding some tests and such to the PR.

tjpalmer commented 8 months ago

Sounds good. I'll work it from my end, then.

tjpalmer commented 8 months ago

I think it's possible this relates to #101 because both involve if statements. No guarantee because they're very different in other ways, but it doesn't seem impossible.

tjpalmer commented 8 months ago

Just got #101 fixed on my branch, although with some efficiency concerns, and it doesn't fix this one here, so definitely different issues.

ShawSumma commented 8 months ago

It looks to me that when a temper.pcall ends with a return, it fails to add the return to the list of things it should check for.

if local_9 then end

Is what needs to be changed to something like

if local_9 then
else
  if local_11 == 'return' then
    return local_10
  end
end

There is labelsUsed and usedLabels for this. But "return" never gets added to either in this case, oddly.