byte-physics / igortest

Igor Pro Universal Testing Framework
https://docs.byte-physics.de/igor-unit-testing-framework/
BSD 3-Clause "New" or "Revised" License
7 stars 2 forks source link

Tracing: Track each case label separately #251

Open t-b opened 2 years ago

t-b commented 2 years ago

In the following code example:

switch(var)
case 1:
case 2:

the counting for case 2 is wrong as it is the sum of case 1 and 2.

To fix that one can think about something like:


// Z::ll: Only count line number if true
Function Dostuff()
    variable var
    string str

    switch(var++) // TODO
        case 1:
            Z_(0, 0, ll=(1==(var)))
        case 2:
            Z_(0, 0, ll=(2==var))
    endswitch

    strswitch(str)
        case "a":
            Z_(0, 0, ll=(!CmpStr((str), "a")))
        case "b":
            Z_(0, 0, ll=(!CmpStr((str), "b")))
    endswitch
End

but that will give wrong results if the switch expression is not idempotent. A solution for that would be to have a Z function in the switch statement, such that the expression is only executed once. Since Z needs to know now the target line where the case x: in question is in the source, we need to gather that information beforehand on instrumentation. Then we can look the line numbers up on actual execution of Z_. This will be slow.

Garados007 commented 1 year ago

I propose the following solution. This includes several steps, waves and functions that have to be introduced.

Instrumentation

During the instrumentation step we are counting each switch statement and assign each of them a unique id (must be unique during the full instrumentation run). For each switch statement we search for the corresponding endswitch statement (be careful that switch statements can be nested!). Between the switch statement and the endswitch statements are all case statement tagged with a reference number that is only valid for the current switch scope. Only case statements that are directly associated with the switch statement and not nested switch statement can be tagged!

This tagging and unique id information has to be stored for later usage because the analytics in a later stage needs them.

Inside the switch call is a new Z_ like function added ZS_ which receives the switch-ID and the argument of the switch statement as optional argument. After the endswitch is a call to ZS_ introduced without any optional arguments.

After each case statement is a call ZC_ introduced which receive the current switch-ID and the case number.

For example, we have this Igor code:

switch(SomeArguments())
    case 1:
    case 2:
        print "Hello"
        break
    case 3:
        print "Hi"
        break
endswitch

After instrumentation we have this code (without the usual Z_ calls):

switch(ZS_(1337, v=SomeArguments()))
    case 1:
        ZC_(1337, 0)
    case 2:
        ZC_(1337, 1)
        print "Hello"
        break
    case 3:
        ZC_(1337, 2)
        print "Hi"
        break
endswitch
ZS_(1337)

This has to be repeated for each nested switch statement.

The ZS_ function

This function activates the current switch statement given by the provided switch-ID. This activation is only done for the current thread. If this function is called without any optional argument the given switch statement is deactivated.

The return of the ZS_ function is the same as provided by the optional parameter v.

For strswitch is another function ZSS_ introduced.

The ZC_ function

This function increments the case counter given by the switch-ID and case-index. This is only done if the switch-Statement is activated. After incrementing the switch is deactivated again.

The counter for each switch case is stored as a wave reference wave. The outside wave has as many elements as switch statements exists. For each switch statement is another wave created which has as many elements as case statement inside the switch.

Considerations

  1. Each switch is only activated by test code and disabled right after it. There is no user code in between!
  2. There can be no more than one switch statement activated for each thread.

Data

We need to store the following data: