rokucommunity / brighterscript

A superset of Roku's BrightScript language
MIT License
151 stars 47 forks source link

support switch statements #15

Open ronenlh opened 4 years ago

ronenlh commented 4 years ago
switch something
   case somethingElse1:
            ' ...
   case somethingElse2:
            ' ...
   case somethingElse3:
            ' ...
   default:
            ' ...
end switch

should transpile to:

if something = somethingElse1 then
    ' ...
else if  something = somethingElse2 then
    ' ...
else if  something = somethingElse3 then
    ' ...
else
   ' ...
end if

may because of the if else, the break statement is implied, otherwise it might be transpiled with goto statements to support fallthrough.

if something = somethingElse1 then
   goto somethingElse1Label
else if ...
somethingElse1Label:
   '...
TwitchBronBron commented 4 years ago

Great idea! We need to decide whether we want to support the fall-through concept, or if each case statement has an implicit break. I think I prefer the way Visual Basic handles it, where each case is an implicit break, but where you can specify a list of items in the case. And of course people can get around this by using goto...in their own code.


switch something
   case somethingElse1, somethingElse2:
            ' ...
   case somethingElse3:
            ' ...
   default:
            ' ...
end switch
TwitchBronBron commented 4 years ago

I also don't want to restrict something to being a variable: expressions should also be supported. However, we don't want to re-evaluate the expression on every check because that could be expensive. We will probably need to store that as a variable before the conditions:

switch 1 + 1
    case somethingElse1:
        '...
    case 2:
        '...
    default: 
       '...
end switch

Transpiles to:

bs_switch_val = 1+1
if bs_switch_val = somethingElse1 then
    '...
else if bs_switch_val = 2 then
    '...
else
    '...
end if
chrisdp commented 2 years ago

Just to add as it looks like it is missing but for this example:

switch something
   case somethingElse1, somethingElse2:
            ' ...
   case somethingElse3:
            ' ...
   default:
            ' ...
end switch

The output code would likely look something like this:

if  something = somethingElse1 or something = somethingElse2 then
        '...
else if something = somethingElse3 then
        '...
else
       '...
end if
chrisdp commented 2 years ago

@TwitchBronBron @georgejecook In response to the above do we want to support the following:

switch something
   case somethingElse1:
   case somethingElse2:
            ' ...
   case somethingElse3:
            ' ...
   default:
            ' ...
end switch

I can see times where it would be nice to support both as the first one in the comment above is nice for smaller checks where the second is nice if you have larger variables to compare too or just a lot of them. Forcing one line could make it harder in some cases.

philippe-elsass-deltatre commented 2 years ago

No fallthrough please. Also it needs am indexed temp variable in case you nest switch expressions:

switch evaluateValue()
   case value1: ...
   default: ...
end switch

Which could compile like:

bs_switch_val1 = evaluateValue() ' maps to `switch evaluateValue()` line
if bs_switch_val1 = value1 ' maps to case line
   ...
else ' maps to default line
   ...
end if
chrisdp commented 2 years ago

Also need to consider conditions as cases:

switch evaluateValue()
   case 1+2: ...
   default: ...
end switch

to:

bs_switch_val = evaluateValue() ' maps to `switch evaluateValue()` line
if bs_switch_val = (1 + 2) ' maps to case line
   ...
else ' maps to default line
   ...
end if
philippe-elsass-deltatre commented 2 years ago

Should there be something special for switching on Nodes? (isSameNode)

livecano commented 2 years ago

I like this feature. Here is an interesting point from Swift lang:

Switch statements don’t fall through the bottom of each case and into the next one by default. Instead, the entire switch statement finishes its execution as soon as the first matching switch case is completed, without requiring an explicit break statement.

Also:

The body of each case must contain at least one executable statement. It isn’t valid to write the following code, because the first case is empty:

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // Invalid, the case has an empty body
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// This will report a compile-time error.

meaning, case somethingElse1 won't be valid because of the empty body.

switch something
   case somethingElse1:
   case somethingElse2:
            ' ...
   case somethingElse3:
            ' ...
   default:
            ' ...
end switch
chrisdp commented 2 years ago

After some additional thinking I am proposing that, where possible we try to mimic the syntax of VB. BrightScript, and by extension BrighterScript, are heavily based off VB. Here is an example of a new proposal:

Select [ Case ] testexpression  
    [ Case expressionlist  
        [ statements ] ]  
    [ Case Else  
        [ elsestatements ] ]  
End Select  

An example of the select statment in use:

number = 8
Select Case number
    Case 1
        Debug.WriteLine("Case 1")
    Case 6, 7, 8
        Debug.WriteLine("Between 6 and 8, inclusive")
    Case Else
        Debug.WriteLine("No matching case")
End Select

We should also support multi line for enhanced readability. The same example with multi line:

number = 8
Select Case number
    Case 1
        Debug.WriteLine("Case 1")
    Case 6,
        7,
        8
            Debug.WriteLine("Between 6 and 8, inclusive")
    Case Else
        Debug.WriteLine("No matching case")
End Select
elsassph commented 2 years ago

@chrisdp you're making a very valid point and I support the suggestion (although the VB syntax is a bit ugly)

elsassph commented 2 years ago

It should also logically support colons as expression separators (with or without newlines), e.g.

  case 1: print "1"
  case 2
      print "2"
  case 3:
     print "3"
     print "4"