# crash

Definition: | crash(string msg, object args={}, integer nFrames=1)
Description: | Terminate the running program, displaying a formatted error message the way printf() does. msg: the message text, optionally with embedded sprintf format specifiers. args: if not {}, then msg = sprintf(msg,args) is performed first of all. nFrames: number of frames to pop from the stack, see below.
pwa/p2js: | Supported, however nFrames is ignored (any error handling is the responsibility of the browser development tools anyway), plus the message is (always) displayed before being caught by any containing try/catch.
Comments: | The default value for nFrames pops the crash routine itself, and that is suitable for most application code, whereas a value of 2 is suitable for some global library routines, and 3 for some private library routines. Several builtins\ and builtins\VM\ files try to report the error on the calling statement rather than in themselves, for instance it is easily several thousand times more likely that the wrong parameters were passed to printf(), than some percieved problem being a bug within printf() itself. Obviously you should normally test that the crash actually occurs, and that it leads the developer directly to the most likely source of error, as opposed to [builtin] code that does not usually need fixing. A few well-placed without debug, in the builtin files themselves, can remove the need to fiddle with nFrames, however I cannot guarantee they will remain in place from one release to the next. The program terminates as for any runtime error, unless there is a containing try/catch statement. Note that while [s]printf() allows an integer/atom/string args, for compatibility with pwa/p2js both crash() and assert() require a dword-sequence. In particular there is some special (legacy) handling of `printf(1,"Hello %s\n",{'P','e','t','e'})` and therefore `crash("Hello %s\n",{'P','e','t','e'})` on desktop/Phix such that both result in "Hello Pete" being displayed, but you’ll get "Hello P" under pwa/p2js instead, although both are fine as long as you double-up on the containing {}.
Auxillary Functions | assert(bool condition, string msg="", object args={}, integer nFrames=1) asserteq(object a, b, string msg="==", object args={}, integer nFrames=1) Trivial wrappers: assert is simply if not condition then crash("assertion failure:"&msg,args,nFrames+1) end if, whereas asserteq is ever so slightly more fiddly, with a msg in {"==","=","!=","<","<=","=>",">"} overriding the equality test and then being treated as "". Obviously with the latter the error report contains the actual mismatching values of inlined expressions/function calls which the former would probably not. See builtins\pCrashN.e for more precise details, such as asserteq() actually works identically whether msg is [defaulted to] "==", "=", or "". Should a specific use of either not be immediately intuitive or not behave precisely as expected/wanted my advice would be to revert to [multiple] longhand tests that invoke crash(). Note there is as yet no option to suppress code generation for a production build, for that define DEBUG as a true/false constant, wrap all assert() in `if DEBUG then`, and let me know if that becomes too cumbersome in one of your projects.
Example: |
    if fn=-1 then
        crash("cannot open config file")                -- [1]
    -- or
        crash("cannot open %s",{"path/to/file"})        -- [2]
    end if
    -- or
    assert(fn!=-1)                                      -- [3]
    -- or
    assert(fn!=-1,"cannot open config file")            -- [4]
    -- or
    asserteq(fn,-1,"!=")                                -- [5]
    -- or
    asserteq(2+2,5)                                     -- [6]
    -- or
    asserteq(2+2,5,"!=")                        -- (no output)
    -- or
    assert(2+2!=5)                              -- (no output)
    -- or
    asserteq(2+2,5,"maths broken")                      -- [7]
    -- collected output on failure (silent on success):
    -- cannot open config file                          -- [1]
    -- cannot open path/to/file                         -- [2]
    -- assertion failure                                -- [3]
    -- assertion failure:cannot open config file        -- [4]
    -- assertion failure: -1 != -1                      -- [5]
    -- assertion failure: 4 == 5                        -- [6]
    -- assertion failure: 4 == 5 (maths broken)         -- [7]
In all cases the source file and line number is also shown, and a "Press Enter..." pause occurs. I briefly considered trying to "flip" the equality operator in the asserteq message, before quickly realising that would probably cause just as much confusion, if not more, but as ever I’m open to suggestions for improvement.
Implementation: | Partly in builtins\pCrashN.e (an autoinclude), but mainly via crash_message() and :!iDiag in builtins\VM\pDiag.e (also an autoinclude) - be warned however it is low-level complicated stuff that you do not need to know.
See Also: | printf, sprintf, crash_file, crash_message