Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try/catch in update assignment #2220

Closed
odnoletkov opened this issue Dec 4, 2020 · 2 comments · Fixed by #2750
Closed

Try/catch in update assignment #2220

odnoletkov opened this issue Dec 4, 2020 · 2 comments · Fixed by #2750

Comments

@odnoletkov
Copy link

Describe the bug

try/catch produce unexpected results when used in the rhs of the update assignment |=

To Reproduce

$ jq -n '1 | . |= 2' # OK
2

$ jq -n '1 | . |= try 2' # BUG, expected: 2 
null

$ jq -n '1 | . |= try 2 catch 3' # BUG, expected: 2
3

$ jq -n '1 | . |= try 2 catch .' # BUG, expected: 2
{
  "__jq": 0
}

$ jq -n '["1", "2a", "3", 4] | .[] |= try tonumber' # BUG, expected: [1, null, 3, 4]
[
  "2a",
  4
]

Plain assignment = and surprisingly even arithmetic update-assignments such as += work as expected:

$ jq -n '1 | . = try 2' # OK
2

$ jq -n '1 | . += try 2' # OK
3

Throwing the error also works as expected

$ jq -n '1 | . |= try error("err")' # OK
null

$ jq -n '1 | . |= try error("err") catch 2' # OK
2

Environment

% jq --version; uname; sw_vers -productVersion
jq-1.6
Darwin
10.15.7
$ jq --version; uname
jq-1.6
Linux
@itchyny
Copy link
Contributor

itchyny commented Dec 10, 2020

Maybe related issue: #1859, #2140.

@odnoletkov
Copy link
Author

@itchyny thanks for the pointers, just checked master at a17dd32: turns out e74eab8 fixed both catch cases above:

$ jq -n '1 | . |= try 2 catch 3' # OK
2

$ jq -n '1 | . |= try 2 catch .' # OK
2

But try without catch is still broken:

$ jq -n '1 | . |= try 2' # BUG, expected: 2 
null

$ jq -n '["1", "2a", "3", 4] | .[] |= try tonumber' # BUG, expected: [1, null, 3, 4]
[
  "2a",
  4
]

@wtlangford thanks for the fix! Do you think e74eab8 should have fixed the case w/o catch as well or is this a separate issue?

Closing this as a duplicate of #2140

nicowilliams added a commit to nicowilliams/jq that referenced this issue Jul 24, 2023
Close jqlang#1885, jqlang#2140, jqlang#2011, jqlang#2220, jqlang#2485, 2073

Rename the FORK_OPT opcode to TRY_BEGIN, add a TRY_END opcode, and wrap
errors when raising through a TRY_END so that they will not be caught by
the matching TRY_BEGIN.

Now a `try exp catch handler` expression generates code like:

    TRY_BEGIN handler
    <exp>
    TRY_END
    JUMP past_handler
    handler: <handler>
    past_handler:
    ...

On backtrack through TRY_BEGIN it just backtracks.

If anything past the whole thing raises when <exp> produced a value,
then the TRY_END will catch the error, wrap it in another, and
backtrack.  The TRY_BEGIN will see a wrapped error and then it will
unwrap and re-raise the error.

If <exp> raises, then TRY_BEGIN will catch the error and jump to the
handler, but the TRY_BEGIN will not stack_save() in that case, so on
raise/backtrack the TRY_BEGIN will not execute again (nor will the
TRY_END).
emanuele6 pushed a commit that referenced this issue Jul 24, 2023
Close #1885, #2140, #2011, #2220, #2485, #2073

Rename the FORK_OPT opcode to TRY_BEGIN, add a TRY_END opcode, and wrap
errors when raising through a TRY_END so that they will not be caught by
the matching TRY_BEGIN.

Now a `try exp catch handler` expression generates code like:

    TRY_BEGIN handler
    <exp>
    TRY_END
    JUMP past_handler
    handler: <handler>
    past_handler:
    ...

On backtrack through TRY_BEGIN it just backtracks.

If anything past the whole thing raises when <exp> produced a value,
then the TRY_END will catch the error, wrap it in another, and
backtrack.  The TRY_BEGIN will see a wrapped error and then it will
unwrap and re-raise the error.

If <exp> raises, then TRY_BEGIN will catch the error and jump to the
handler, but the TRY_BEGIN will not stack_save() in that case, so on
raise/backtrack the TRY_BEGIN will not execute again (nor will the
TRY_END).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants