stdVBA icon indicating copy to clipboard operation
stdVBA copied to clipboard

Addition of loops in stdlambda

Open Almesi opened this issue 7 months ago โ€ข 7 comments

2 Things are added: Do loops and for loops. Do loops work by running an infinite loop through a jump operation until a statement is true. For loops work by running the loop n times. Do-Loop syntax is the same as VBAs For-Loops are the same too, only that putting a word behind "next" will do nothing useful. Just write "next" at the end for that loop. Both loops need all their variables defined before the loop. If not, an error occures where the variable-name will be pushed onto stack instead of its value. I added some new subs to work with these two loops. I did not change anything major in the operation-creation. Only exception to that is how for loops are interpreted, as they requiere more inline creation of tokens. (for example it needs i = i + 1 to increment its index, otherwise it would run infinetly. Mind the line 1082. This is a proof of concept, feedback would be nice.

Almesi avatar May 21 '25 13:05 Almesi

To test:

Public Sub Test()
    Dim doloop As stdLambda
    Set doloop = stdLambda.CreateMultiline(Array( _
        "let i = 0", _
        "let x = 0", _
        "do until i > 10", _
            "let x = 2 + i", _
            "let i = i + 1", _
        "loop")) 
    Debug.Print doloop.Run()

    Dim doloop2 As stdLambda
    Set doloop2 = stdLambda.CreateMultiline(Array( _
        "let i = 0", _
        "let x = 0", _
        "do while i =< 10", _
            "let x = 2 + i", _
            "let i = i + 1", _
        "loop"))
    Debug.Print doloop2.Run()


    Dim forloop As stdLambda
    Set forloop = stdLambda.CreateMultiline(Array( _
    "let i = 0", _
    "let x = 0", _
    "for i = 1 To 10", _
    "let x = 2 + i", _
    "next"))
    Debug.Print forloop.Run()

    Dim forloop2 As stdLambda
    Set forloop2 = stdLambda.CreateMultiline(Array( _
    "let i = 0", _
    "let x = 0", _
    "for i = 1 To 10 Step +2", _
    "let x = 2 + i", _
    "next"))
    Debug.Print forloop2.Run()

    Dim forloop3 As stdLambda
    Set forloop3 = stdLambda.CreateMultiline(Array( _
    "let i = 0", _
    "let x = 0", _
    "for let i = 1 To 10", _
    "let x = 2 + i", _
    "next"))
    Debug.Print forloop3.Run()

    Dim forloop4 As stdLambda
    Set forloop4 = stdLambda.CreateMultiline(Array( _
    "let i = 0", _
    "let x = 0", _
    "for let i = 1 To 10 Step +2", _
    "let x = 2 + i", _
    "next"))
    Debug.Print forloop4.Run()
End Sub

Almesi avatar May 21 '25 13:05 Almesi

Was this generated with AI? lol

sancarn avatar May 21 '25 22:05 sancarn

Needs more testing, expressions can be embedded within the for loop, currently token stream gets messed up. Example:

  Dim lambda As stdLambda
  Set lambda = stdLambda.CreateMultiline(Array( _
    "let x = $1", _
    "For i = 0 to If x > 10 Then 10 Else 20 End Step 2", _
    "  let x = x / 2", _
    "next" _
  ))
  
  Debug.Print lambda.Run(9)
  Debug.Print lambda.Run(10)
  Debug.Print lambda.Run(11)

or even

  Dim lambda As stdLambda
  Set lambda = stdLambda.CreateMultiline(Array( _
    "let x = $1", _
    "let i = 0", _
    "For i = 0 to (10+2) Step +2", _
    "  let x = x / 2", _
    "next" _
  ))
  
  Debug.Print lambda.Run(9)
  Debug.Print lambda.Run(10)
  Debug.Print lambda.Run(11)

and the following infinite loops:

  Dim lambda As stdLambda
  Set lambda = stdLambda.CreateMultiline(Array( _
    "let x = $1", _
    "let i = 0", _
    "For i = 0 to 10+2 Step +2", _
    "  let x = x / 2", _
    "next" _
  ))
  
  Debug.Print lambda.Run(9)
  Debug.Print lambda.Run(10)
  Debug.Print lambda.Run(11)

Also not a fan that you have to define the variable first else it will fail. I.E.

Dim forloop As stdLambda
Set forloop = stdLambda.CreateMultiline(Array( _
"let i = 0", _
"let x = 0", _
"for i = 1 To 10", _
"  let x = 2 + i", _
"next"))
Debug.Print forloop.Run()

Works but

Dim forloop As stdLambda
Set forloop = stdLambda.CreateMultiline(Array( _
"let x = 0", _
"for i = 1 To 10", _
"  let x = 2 + i", _
"next"))
Debug.Print forloop.Run()

fails...

Ultimately syntax should be:

for {var} = {expr} to {expr} Step {expr}
   {block}
next

sancarn avatar May 21 '25 22:05 sancarn

Was this generated with AI? lol

ouch. Did you also test the do loop or am i to assume that that one works?

Almesi avatar May 22 '25 06:05 Almesi

Im sorry if my pull requests are a mess, im new to this. I updated the code for the points mentioned for you. Here are the used tests for this request.

' Very creative names i know

Public Sub Testing()
    Dim i As Long
    For i = 0 To 20
        Debug.Print i & "-------------------------------"
        Debug.Print "TestForLoop                          " & i & ": " & TestForLoop(i)
        Debug.Print "TestIfInUbound                       " & i & ": " & TestIfInUbound(i)
        Debug.Print "TestParantInUbound                   " & i & ": " & TestParantInUbound(i)
        Debug.Print "TestExprInUbound                     " & i & ": " & TestExprInUbound(i)
        Debug.Print "TestForLoopPredeclared               " & i & ": " & TestForLoopPredeclared(i)
        Debug.Print "TestFunctionInForLoop                " & i & ": " & TestFunctionInForLoop(i)
        ' Debug.Print "TestFunctionInForLoop2             " & i & ": " & TestFunctionInForLoop2(i)
        Debug.Print "TestFunctionInDoLoop                 " & i & ": " & TestFunctionInDoLoop(i)
        Debug.Print "TestFunctionInDoLoopWithWhileAtEnd   " & i & ": " & TestFunctionInDoLoopWithWhileAtEnd(i)
        Debug.Print "TestFunctionInDoLoopExit             " & i & ": " & TestFunctionInDoLoopExit(i)
    Next i
End Sub

Function TestForLoop(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "for i = 1 To $1", _
        "   let x = 2 + i", _
        "next"))
    TestForLoop = Lambda.Run(index)
End Function

Function TestIfInUbound(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "let x = $1", _
        "For i = 0 to If x > 10 Then 10 Else 20 End Step +2", _
        "  let x = x / 2", _
        "next" _
    ))
    TestIfInUbound = Lambda.Run(index)
End Function

Function TestParantInUbound(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "let x = $1", _
        "let i = 0", _
        "For i = 0 to (10+2) Step +2", _
        "  let x = x / 2", _
        "next" _
    ))
    TestParantInUbound = Lambda.Run(index)
End Function

Function TestExprInUbound(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "let x = $1", _
        "let i = 0", _
        "For i = 0 to 10+2 Step +2", _
        "    let x = x / 2", _
        "next" _
    ))
    TestExprInUbound = Lambda.Run(index)
End Function

Function TestForLoopPredeclared(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "let i = 0", _
        "let x = 0", _
        "for i = 1 To $1", _
        "   let x = 2 + i", _
        "next"))
    TestForLoopPredeclared = Lambda.Run(index)
End Function

Function TestFunctionInForLoop(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "let x = 0", _
        "fun fib(v)", _
        "    if v<=1 then", _
        "        v", _
        "    else ", _
        "         fib(v-2) + fib(v-1)", _
        "    end", _
        "end", _
        " ", _
        "for i = 1 To 10", _
        "   let x = x + fib($1)", _
        "next"))
    TestFunctionInForLoop = Lambda.Run(index)
End Function

' This will not work, as x is not defined previously
' meaning the moment lambda tries to do let x = x + duuble($1) it will view the second x as "x", since it wasnt initialised before
Function TestFunctionInForLoop2(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "fun duuble(v)", _
        "    let v * 2", _
        "end", _
        " ", _
        "For i = 1 To $1", _
        "    let x = x + duuble($1)", _
        "next"))
    TestFunctionInForLoop2 = Lambda.Run(index)
End Function

Function TestFunctionInDoLoop(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "let x = 1", _
        "let i = 0", _
        "fun duuble(v)", _
        "    let v * 2", _
        "end", _
        " ", _
        "Do While i < $1", _
        "    let i = i + 1", _
        "    let x = x + duuble($1)", _
        "loop"))
    TestFunctionInDoLoop = Lambda.Run(index)
End Function

Function TestFunctionInDoLoopWithWhileAtEnd(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "let x = 1", _
        "let i = 0", _
        "fun duuble(v)", _
        "    let v * 2", _
        "end", _
        " ", _
        "Do", _
        "    let i = i + 1", _
        "    let x = x + duuble($1)", _
        "loop  While i < $1"))
    TestFunctionInDoLoopWithWhileAtEnd = Lambda.Run(index)
End Function

' This will not work at the moment, as i dont know thow to find the index to jump to depending on where it is at the moment
Function TestFunctionInDoLoopExit(index As Long)
    Static Lambda As stdLambda
    If Lambda Is Nothing Then Set Lambda = stdLambda.CreateMultiline(Array( _
        "let x = 1", _
        "let i = 0", _
        "Do", _
        "    let i = i + 1", _
        "if $1 > 10 then Exit do end", _
        "    let x = x * 2", _
        "loop  While i < $1"))
    TestFunctionInDoLoopExit = Lambda.Run(index)
End Function




Almesi avatar May 23 '25 13:05 Almesi

Thanks for the extensive tests, I'm not ignoring this PR, will look at it hopefully this next week. Just have a lot going on at the moment! ๐Ÿ‘

No need to apologise either! There is only one way to learn and that's by doing ๐Ÿ‘

sancarn avatar May 25 '25 23:05 sancarn

Hi @Almesi I will try to get to this PR soon, recently there were pretty large scale changes to the stdLambda VM which have boosted speed significantly, and it's re-reminded me of how the VM works. So while it's fresh I think looking at this PR makes a lot of sense! But I will have to make some changes to your PR as the VM upgrade was pretty major๐Ÿ‘

sancarn avatar Jun 07 '25 00:06 sancarn