Forum Discussion

cody8411_186897's avatar
cody8411_186897
Icon for Nimbostratus rankNimbostratus
Jan 25, 2016
Solved

Undefined Procedure with elseif when using comments

I am having trouble committing the following iRule when adding in comments above the elseif statements. It always interprets the first comment it finds above an elseif statement as the offender.

01070151:3: Rule [/Common/Main_Website_80_Revised] error: /Common/Main_Website_80_Revised:7: error: [undefined procedure: elseif][elseif {[class match [HTTP::host] eq group_80_encrypt]} {
HTTP::redirect https://[getfield [HTTP::host] ":" 1][HTTP::uri]
}]

Removing all comments (aside from line 2, that one seems fine) will commit the iRule without any issue. Any idea what might be going on?

when HTTP_REQUEST {
    302 redirect to a different URL based on hostname
    if {[class match [HTTP::host] eq group_80_host_redirect]} {
        HTTP::redirect [class match -value [HTTP::host] eq group_80_host_redirect]
    }
    302 redirect to enforce HTTPS based on hostname or URI
    elseif {[class match [HTTP::host] eq group_80_encrypt]} {
        HTTP::redirect https://[getfield [HTTP::host] ":" 1][HTTP::uri]
    }
    Pool selection based on hostname
    elseif {[class match [HTTP::host] eq group_80_host_pool]} {
        pool [class match -value [HTTP::host] eq group_80_host_pool]
    }
    Pool selection based on URI
    elseif {[class match [HTTP::uri] starts_with group_80_uri_pool]} {
        pool [class match -value [HTTP::uri] starts_with group_80_uri_pool]
    }
    else {
        pool Main_80_Pool
    }
}
  • This results from a peculiarity of Tcl. The language doesn't really have built-ins and it doesn't really have blocks. Rather, it has commands and non-interpolated quoted strings. As such,

    if
    is a command (just like
    split
    or
    HTTP::headers
    ). It is followed by a quoted block (the {}s, in Tcl, are really non-interpolating quoting operators, and not really block delimiters as they are in most languages). The quoted block may then be optionally followed by zero or more
    elseif
    literals (each followed by a quoted block) and zero or one
    else
    literals (followed by a quoted block). When a condition is met, the contents of the corresponding quoted block are evaluated.

    Said another way, in Tcl, an

    if
    /
    elseif
    /
    else
    set is really a single statement. The statement command is
    if
    . The
    elseif
    and
    else
    are just parameters to this command. And because the newlines in the blocks are ignored by the parser (because they are inside of the non-interpolating {} quoting operators), the entire statement is effectively on one line.

    As a side-effect of this, in Tcl you MUST cuddle an

    if
    /
    elseif
    /
    else
    block, as in:

    if { ... } {
       ...
    } else {
       ...
    }
    

    This is not allowed:

    if { ... } {
       ...
    }
    else {
       ...
    }
    

    However, this trips up most programmers, so iRules (a Tcl dialect) allows non-cuddled

    if
    blocks. But if you add a comment between the control elements, this effectively inserts a newline. So, with the comments you have above, the parser "sees" this:

    if { ... } 
    elseif { ... } 
    else { ... }
    

    which it thinks is really three different commands:

    if
    ,
    elseif
    and
    else
    . Only
    if
    is a command; the others are not (again, they are just parameters of the
    if
    command).

    Okay, so that's really just a long-winded way of saying: you must move those comments inside the squirly braces ({}). 🙂

5 Replies

  • This results from a peculiarity of Tcl. The language doesn't really have built-ins and it doesn't really have blocks. Rather, it has commands and non-interpolated quoted strings. As such,

    if
    is a command (just like
    split
    or
    HTTP::headers
    ). It is followed by a quoted block (the {}s, in Tcl, are really non-interpolating quoting operators, and not really block delimiters as they are in most languages). The quoted block may then be optionally followed by zero or more
    elseif
    literals (each followed by a quoted block) and zero or one
    else
    literals (followed by a quoted block). When a condition is met, the contents of the corresponding quoted block are evaluated.

    Said another way, in Tcl, an

    if
    /
    elseif
    /
    else
    set is really a single statement. The statement command is
    if
    . The
    elseif
    and
    else
    are just parameters to this command. And because the newlines in the blocks are ignored by the parser (because they are inside of the non-interpolating {} quoting operators), the entire statement is effectively on one line.

    As a side-effect of this, in Tcl you MUST cuddle an

    if
    /
    elseif
    /
    else
    block, as in:

    if { ... } {
       ...
    } else {
       ...
    }
    

    This is not allowed:

    if { ... } {
       ...
    }
    else {
       ...
    }
    

    However, this trips up most programmers, so iRules (a Tcl dialect) allows non-cuddled

    if
    blocks. But if you add a comment between the control elements, this effectively inserts a newline. So, with the comments you have above, the parser "sees" this:

    if { ... } 
    elseif { ... } 
    else { ... }
    

    which it thinks is really three different commands:

    if
    ,
    elseif
    and
    else
    . Only
    if
    is a command; the others are not (again, they are just parameters of the
    if
    command).

    Okay, so that's really just a long-winded way of saying: you must move those comments inside the squirly braces ({}). 🙂

    • cody8411_186897's avatar
      cody8411_186897
      Icon for Nimbostratus rankNimbostratus
      Excellent explanation. That definitely makes sense now that I understand how the code is interpreted in Tcl. Moved the comments down inside the commands and worked as expected, thank you!
  • Vernon_97235's avatar
    Vernon_97235
    Historic F5 Account

    This results from a peculiarity of Tcl. The language doesn't really have built-ins and it doesn't really have blocks. Rather, it has commands and non-interpolated quoted strings. As such,

    if
    is a command (just like
    split
    or
    HTTP::headers
    ). It is followed by a quoted block (the {}s, in Tcl, are really non-interpolating quoting operators, and not really block delimiters as they are in most languages). The quoted block may then be optionally followed by zero or more
    elseif
    literals (each followed by a quoted block) and zero or one
    else
    literals (followed by a quoted block). When a condition is met, the contents of the corresponding quoted block are evaluated.

    Said another way, in Tcl, an

    if
    /
    elseif
    /
    else
    set is really a single statement. The statement command is
    if
    . The
    elseif
    and
    else
    are just parameters to this command. And because the newlines in the blocks are ignored by the parser (because they are inside of the non-interpolating {} quoting operators), the entire statement is effectively on one line.

    As a side-effect of this, in Tcl you MUST cuddle an

    if
    /
    elseif
    /
    else
    block, as in:

    if { ... } {
       ...
    } else {
       ...
    }
    

    This is not allowed:

    if { ... } {
       ...
    }
    else {
       ...
    }
    

    However, this trips up most programmers, so iRules (a Tcl dialect) allows non-cuddled

    if
    blocks. But if you add a comment between the control elements, this effectively inserts a newline. So, with the comments you have above, the parser "sees" this:

    if { ... } 
    elseif { ... } 
    else { ... }
    

    which it thinks is really three different commands:

    if
    ,
    elseif
    and
    else
    . Only
    if
    is a command; the others are not (again, they are just parameters of the
    if
    command).

    Okay, so that's really just a long-winded way of saying: you must move those comments inside the squirly braces ({}). 🙂

    • cody8411_186897's avatar
      cody8411_186897
      Icon for Nimbostratus rankNimbostratus
      Excellent explanation. That definitely makes sense now that I understand how the code is interpreted in Tcl. Moved the comments down inside the commands and worked as expected, thank you!
  • Salvador_del_Re's avatar
    Salvador_del_Re
    Historic F5 Account
    I have the same problema. I insert the comments below and don´t have issues if {[class match [HTTP::host] eq group_80_host_redirect]} { HTTP::redirect [class match -value [HTTP::host] eq group_80_host_redirect] 302 redirect to a different URL based on hostname } elseif {[class match [HTTP::host] eq group_80_encrypt]} { HTTP::redirect https://[getfield [HTTP::host] ":" 1][HTTP::uri] 302 redirect to enforce HTTPS based on hostname or URI }