Skip to content

add support for continue statement#112

Merged
lolleko merged 6 commits intoTypeScriptToLua:masterfrom
InfiniteRain:master
Jun 7, 2018
Merged

add support for continue statement#112
lolleko merged 6 commits intoTypeScriptToLua:masterfrom
InfiniteRain:master

Conversation

@InfiniteRain
Copy link
Contributor

This implements the support for TS's continue statement. Normally, tstl would throw an exception whenever the continue statement is used, saying that Lua does not support the statement.

However, while Lua indeed does not support the continue statement, it is still perfectly possible to implement the functionality of a continue statement by changing how loops get transpiled.

Here's a simple example:

The following TS

for (let i = 1; i <= 100; i++) {
  if (i < 25) {
    continue;
  }
  
  print(i);
}

Gets transpiled to

local i = 1
while(i<=100) do
    local ____continue = false
    repeat
        if i<25 then
            ____continue = true
            break
        end
        print(i)
        ____continue = true
    until true
    i=i+1
    if not ____continue then break end
end

As can be seen from the example above, the functionality of a continue statement gets achieved via a clever usage of the repeat until true block, which acts a simple do end block, but allows for a possibility of stopping the execution of the block via a break statement. The ____continue local allows for differentiation between a break statement for the repeat until true and the parent loop. If a break statement was used without setting the ____continue local to true, then it will have an effect of a normal break (break from repeat until true and break from the parent loop). However, if a break statement was used after setting the ____continue local to true, then it will act with accordance to how the effect of the continue statement should be, which is: stop executing the current cycle, and jump to the next one (break repeat until true, but do not break the parent loop). The ____continue = true gets automatically added at the end of the body of the parent loop.

So, the continue statement simply gets transpiled to:

____continue = true
break

With this implementation, you can nest multiple loops inside of each other, and the ____continue locals of the nested loops will not interfere with each other, thanks to how scoping works in Lua.

The following loops were used for testing:

declare function print(...messages: any[]): void;

for (let i = 1; i <= 100; i++) {
  if (i < 25) {
    continue;
  }
  print(i);

  for (let x = 1; x <= 10; x++) {
    if (x < 5) {
      continue;
    }
    print(x)
  }
}

let d = 10
while (d > 0) {
  d--;
  if (d > 5) {
    let o = 4;
    while (o > 0) {
      o--;
      if (o > 2) {
        continue;
      }
      print(o);
    }
    continue;
  }
  if (d == 2) {
    continue;
  }
  print(d);
}

let e = 10
do {
  e--;
  if (e > 5) {
    let o = 4;
    do {
      o--;
      if (o > 2) {
        continue;
      }
      print(o);
    } while (o > 0)
    continue;
  }
  if (e == 2) {
    continue;
  }
  print(e);
} while (e > 0)

for (let i of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {
  if (i < 3) {
    continue;
  }

  for (let i of [5, 6, 7, 8]) {
    if (i !== 6) {
      continue
    }
    print(i)
  }

  if (i > 8) {
    continue;
  }

  print(i);
}

for (let i in {
  a: 1,
  b: 2,
  c: 3,
  d: 4
}) {
 if (i == 'a') {
   continue;
 }

 if (i == 'b') {
   continue;
 }

 print(i);
}

The transpiled code:

-- Generated by TypescriptToLua v0.2.1
-- https://github.com/Perryvw/TypescriptToLua
require("typescript_lualib")
local i = 1
while(i<=100) do
    local ____continue = false
    repeat
        if i<25 then
            ____continue = true
            break
        end
        print(i)
        local x = 1
        while(x<=10) do
            local ____continue = false
            repeat
                if x<5 then
                    ____continue = true
                    break
                end
                print(x)
                ____continue = true
            until true
            x=x+1
            if not ____continue then break end
        end
        ____continue = true
    until true
    i=i+1
    if not ____continue then break end
end
local d = 10

while d>0 do
    local ____continue = false
    repeat
        d=d-1
        if d>5 then
            local o = 4

            while o>0 do
                local ____continue = false
                repeat
                    o=o-1
                    if o>2 then
                        ____continue = true
                        break
                    end
                    print(o)
                    ____continue = true
                until true
                if not ____continue then break end
            end
            ____continue = true
            break
        end
        if d==2 then
            ____continue = true
            break
        end
        print(d)
        ____continue = true
    until true
    if not ____continue then break end
end
local e = 10

repeat
    local ____continue = false
    repeat
        e=e-1
        if e>5 then
            local o = 4

            repeat
                local ____continue = false
                repeat
                    o=o-1
                    if o>2 then
                        ____continue = true
                        break
                    end
                    print(o)
                    ____continue = true
                until true
                if not ____continue then break end
            until not (o>0)
            ____continue = true
            break
        end
        if e==2 then
            ____continue = true
            break
        end
        print(e)
        ____continue = true
    until true
    if not ____continue then break end
until not (e>0)
for _, i in ipairs({1,2,3,4,5,6,7,8,9,10}) do
    local ____continue = false
    repeat
        if i<3 then
            ____continue = true
            break
        end
        for _, i in ipairs({5,6,7,8}) do
            local ____continue = false
            repeat
                if i~=6 then
                    ____continue = true
                    break
                end
                print(i)
                ____continue = true
            until true
            if not ____continue then break end
        end
        if i>8 then
            ____continue = true
            break
        end
        print(i)
        ____continue = true
    until true
    if not ____continue then break end
end
for i, _ in pairs({a = 1,b = 2,c = 3,d = 4}) do
    local ____continue = false
    repeat
        if i=="a" then
            ____continue = true
            break
        end
        if i=="b" then
            ____continue = true
            break
        end
        print(i)
        ____continue = true
    until true
    if not ____continue then break end
end

The outcomes match.

I don't really know if there's a certain way that the pull requests should be made, or if there's some kind of standard for the workflow. If I've done something wrong with the presentation, then please don't hesitate to correct me. :)

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants