yodk icon indicating copy to clipboard operation
yodk copied to clipboard

Switch case like feature

Open LupusTheCanine opened this issue 2 years ago • 7 comments

Is your feature request related to a problem? Please describe. I am working on a device that has an interface, this interface works on a variable that can be set to specific integer values that initiate certain actions. In order for an interface to be responsive I would like to use switch case like structure.

Describe the solution you'd like I would like to be able to tell compiler that these groups of statements are to be organized in a way that places each group on an individual line and each group is placed on a fixed number of lines. cases can be placed in three ways

  • case 0 as a first case means that an action is taken always.
  • case 1 as a first case means that switch waits until non 0 var is sent repeating all actions that were crammed before this statement on a line, this can be desired or not. Better syntax that allows for preparatory statements to be placed on the line is desirable.
  • case n as a first cases consecutive cases numbered in descending order to case 1, if var is 0 then the switch is skipped in one tick.

Break cause execution to jump to first line after switch has ended Continue causes execution to jump to the line switch begins (one containing goto with var).

could compile (without variable name optimization) to
1.  goto var+2
2.  a+=4 goto 5
3.  b+=5 goto 1
4.  c+=10
5.  ...
similarly 
switch var do
  case 1
    a+=4
  case 2
    b+=5 // case doesn't fit in one line
    continue
  case 3
    c+=10
end

could compile to
1.  goto var*2-var>0+1
2.  a+=4 goto 7
3. 
4.  b+=5  //entire line filed
5.  goto 1
6.  c+=10
7.  ....

and
switch var do
  case 3
    a+=1
    break
  case 2
    b+=2
    break
  case 1
    c+=3
    break
could compile to
1.  goto 5-var
2.  a+=1 goto 5
3.  b+=2 goto 5
4.  c+=3 goto 5
5.  ...

Describe alternatives you've considered I could implement such structures manually in a way that is similar to what is shown in documentation here (second example). but for more complex cases such as multiline statements this would provide more readable and automated way of implementing switch case.

LupusTheCanine avatar Sep 02 '21 20:09 LupusTheCanine

I am not completely sure if I understand what you are trying to say. I think you want some kind of semi-automatic jump-table?

The hard part here seems to be to create an expression that evaluates to the correct jump-line for every case. The naive implementation (var==case1)*line1+(var==case2)*line2 ... would probably be far too long.

Also I am wondering if it would be better to simply re-use the multiline-ifs for this. The compiler could try to detect if your if-statements could be described as a jump-table. But I am not sure if that is actually possible at the moment. It might need type-information about the used variables, which it currently doesn't have.

dbaumgarten avatar Sep 07 '21 14:09 dbaumgarten

I think you want some kind of semi-automatic jump-table?

Exactly

The hard part here seems to be to create an expression that evaluates to the correct jump-line for every case. The naive implementation (var==case1)*line1+(var==case2)*line2 ... would probably be far too long.

This is why I proposed fixed line count per expression and assuming argument is integers only

Also I am wondering if it would be better to simply re-use the multiline-ifs for this. The compiler could try to detect if your if-statements could be described as a jump-table. But I am not sure if that is actually possible at the moment. It might need type-information about the used variables, which it currently doesn't have.

Yes automatic syntax identification requires knowledge of argument's type.

IMO for early implementation it should be able to

  1. identify the size of each case
  2. identify if goto should by default jump to its line or the next one (presence of case 0) or use reverse order.
  3. Warn on unorderly cases
  4. produce a goto that generates correct jumps assuming integer input.
  5. put code in correct lines and warn if it can't fit code in 20 lines

LupusTheCanine avatar Sep 08 '21 19:09 LupusTheCanine

I think the thingy with "case 0" is a little un-intuitve. And enforcing a strict order (but allowing a reverse order) will confuse programmers which are used to "proper" switch-statements.

Maybe it would be batter to name it differently to make clear what is going on?

jmptable var do
  line 1:
      :x="a"
  line 2:
      :x="b"; break
  line 3:
      :x="c"
end

Would make things more obvious. But only being able to have single-line cases will probably confuse someone. Yes, variable-length stuff makes the expression more complicated but it might still be worth it?

The question is, is it that much better than doing the table manually that it justifies adding a new sytnax-feature to the language? Especially if the (already planned) type-system might enable optimizations that will make this obsolete? Tbh, I have no idea...

dbaumgarten avatar Sep 09 '21 16:09 dbaumgarten

I understand that my idea for case 0 is intuitive. I included it as a way of having a script get looped back to the line so response time can be minimized. I intended cases to be fixed size of n lines for simplicity's sake as figuring a way to get a jump with nonlinear length is significantly more complicated. Few ideas:

  1. Allow not every label to be present. If label is absent expression can spill over to the next line
  2. Introduce init statement that must be short enough to fit before jump.
jmptable var do
  init:
      var=var*(var>0)
  line 1:
      :x="a"; continue
  line 2:
      :x="b"; break
  line 3:
      :x="c"; continue
end

or

init var=var*(var>0); :x="" jmptable var do
  init:
      
  line 1:
      :x="a"; continue
  line 2:
      :x="b"; break
  line 3:
      :x="c"; continue
end

Perosnally I like second option a bit more but I am open to other placement of the init statement.

generating the folowing code

var=var*(var>0) :x="" goto var+1
:x="a" 
:x="b" goto 5
:x="c" goto 1

LupusTheCanine avatar Sep 10 '21 16:09 LupusTheCanine

I think somehow integrating the "setup" into the head of the block is a good idea. I thas similarities to how a for-loop is written in many languages.

Maybe something like:

jmptable var; var=var*(var>0) do
  line 1:
      :x="a"; continue
  line 2:
      :x="b"; break
  line 3:
      :x="c"; continue
end

(with the init-statement being optional)?

I am not sure if allowing cases to be missing is a good idea. It adds additional complexity. If the user wants a line to "spill-over" he could just leave-out the break-statement. Execution would continue on the next line.

dbaumgarten avatar Sep 19 '21 17:09 dbaumgarten

I am not sure if allowing cases to be missing is a good idea. It adds additional complexity. If the user wants a line to "spill-over" he could just leave-out the break-statement. Execution would continue on the next line.

The problrm is that in this case user would have to place "line n:" at a specific point to optimize line fill, this point could end up inside a macro or move easily due to for example variable name change which places a burden of chosing and updating its placement every time code changes.

I think compilation could go as follows, after variable substitution and optimization compile each block of code separated by a label ("line n:") checking if it fits within lines that are free so if there are line 1, 3 6, 7 labels then block 1 has to fit within 2 lines othervise it is an error, block 3 can be three lines, block 6 can be only one line and block 7 can fill the rest of the chip.

LupusTheCanine avatar Sep 19 '21 23:09 LupusTheCanine

You're correct, allowing lines to be missing reduces the need for manual line-management. Good point.

I guess the only thing missing now is the time (and motivation) to actually implement this.

dbaumgarten avatar Sep 29 '21 07:09 dbaumgarten