import libc.(abort);
import errors.backtrace.(showBacktrace);
import io.files.raw.(stderrRawFile);



//
// error (exceptions disabled)
//

errorNoThrow(..e) {
    var err = stderrRawFile();
    printlnTo(err, "error: ", ..e);
    showBacktrace();
    abort();
}

[ | not ExceptionsEnabled?]
error(..e) {
    errorNoThrow(..e);
}



//
// error (exceptions enabled)
//

record Error (msg : String);

instance Exception (Error);

[ | ExceptionsEnabled?]
overload error(..e) {
    var buf = String();
    printTo(buf, ..e);
    throw Error(move(buf));
}



//
// assert
//

AllAssertionsEnabled?() = not Flag?(#"clay.DisableAssertions");
AssertionEnabled?(tag) = not Flag?(IdentifierConcat(#"clay.DisableAssertions.", tag));

[..tags | allValues?(Identifier?, ..tags)]
record assert[..tags] ();

[..tags]
alias overload assert[..tags](..whatever) {}

alias overload assert(..whatever) {}

[| AllAssertionsEnabled?()]
alias overload assert(cond:Bool, ..message) {
    if (not cond)
        errorNoThrow(StaticName(__FILE__), "(", __LINE__, ",", __COLUMN__, "): assertion ", __ARG__ cond, " failed: ", ..message);
}

[..tags | AllAssertionsEnabled?() and allValues?(AssertionEnabled?, ..tags)]
alias overload assert[..tags](cond:Bool, ..message) {
    if (not cond)
        errorNoThrow(StaticName(__FILE__), "(", __LINE__, ",", __COLUMN__, "): assertion ", __ARG__ cond, " failed: ", ..message);
}

[| AllAssertionsEnabled?()]
alias overload assert(cond:Bool) {
    if (not cond)
        errorNoThrow(StaticName(__FILE__), "(", __LINE__, ",", __COLUMN__, "): assertion ", __ARG__ cond, " failed");
}

[..tags | AllAssertionsEnabled?() and allValues?(AssertionEnabled?, ..tags)]
alias overload assert[..tags](cond:Bool) {
    if (not cond)
        errorNoThrow(StaticName(__FILE__), "(", __LINE__, ",", __COLUMN__, "): assertion ", __ARG__ cond, " failed");
}


//
// sourceLocation(), argAndValue() helpers
//

alias sourceLocation() = StaticName(__FILE__), __LINE__, __COLUMN__;

alias argAndValue(x) = __ARG__ x, x;

