*/ REBSER *Make_Error(REBINT code, REBVAL *arg1, REBVAL *arg2, REBVAL *arg3) /* ** Create and init a new error object. ** ***********************************************************************/ { REBSER *err; // Error object ERROR_OBJ *error; // Error object values if (PG_Boot_Phase < BOOT_ERRORS) Crash(RP_EARLY_ERROR, code); // Not far enough! // Make a copy of the error object template: err = CLONE_OBJECT(VAL_OBJ_FRAME(ROOT_ERROBJ)); error = ERR_VALUES(err); // Set error number: SET_INTEGER(&error->code, (REBINT)code); Set_Error_Type(error); // Set error argument values: if (arg1) error->arg1 = *arg1; if (arg2) error->arg2 = *arg2; if (arg3) error->arg3 = *arg3; // Set backtrace and location information: if (DSF > 0) { // Where (what function) is the error: Set_Block(&error->where, Make_Backtrace(0)); // Nearby location of the error (in block being evaluated): error->nearest = *DSF_BACK(DSF); } return err; }
static void Mold_Error(const REBVAL *value, REB_MOLD *mold, REBFLG molded) { ERROR_OBJ *err; REBVAL *msg; // Error message block REBSER *frame; // Protect against recursion. !!!! if (molded) { if (VAL_OBJ_FRAME(value) && VAL_ERR_NUM(value) >= RE_NOTE && VAL_ERR_OBJECT(value)) Mold_Object(value, mold); else { // Happens if throw or return is molded. // make error! 0-3 Pre_Mold(value, mold); Append_Int(mold->series, VAL_ERR_NUM(value)); End_Mold(mold); } return; } if (VAL_ERR_NUM(value) < RE_THROW_MAX) { // Though we generally do not make error objects for THROWN() errors, // we do make one here for the purposes of molding. frame = Make_Error(VAL_ERR_NUM(value), value, 0, 0); err = ERR_VALUES(frame); } else { frame = VAL_ERR_OBJECT(value); err = VAL_ERR_VALUES(value); } // Form: ** <type> Error: Emit(mold, "** WB", &err->type, RS_ERRS+0); // Append: error message ARG1, ARG2, etc. msg = Find_Error_Info(err, 0); if (msg) { if (!IS_BLOCK(msg)) Mold_Value(mold, msg, 0); else { //start = DSP + 1; //Reduce_In_Frame(frame, VAL_BLK_DATA(msg)); //SERIES_TAIL(DS_Series) = DSP + 1; //Form_Block_Series(DS_Series, start, mold, 0); Form_Block_Series(VAL_SERIES(msg), 0, mold, frame); } } else Append_Boot_Str(mold->series, RS_ERRS+1); Append_Byte(mold->series, '\n'); // Form: ** Where: function value = &err->where; if (VAL_TYPE(value) > REB_NONE) { Append_Boot_Str(mold->series, RS_ERRS+2); Mold_Value(mold, value, 0); Append_Byte(mold->series, '\n'); } // Form: ** Near: location value = &err->nearest; if (VAL_TYPE(value) > REB_NONE) { Append_Boot_Str(mold->series, RS_ERRS+3); if (IS_STRING(value)) // special case: source file line number Append_String(mold->series, VAL_SERIES(value), 0, VAL_TAIL(value)); else if (IS_BLOCK(value)) Mold_Simple_Block(mold, VAL_BLK_DATA(value), 60); Append_Byte(mold->series, '\n'); } }
*/ void Make_Error_Object(REBVAL *arg, REBVAL *value) /* ** Creates an error object from arg and puts it in value. ** The arg can be a string or an object body block. ** This function is called by MAKE ERROR!. ** ***********************************************************************/ { REBSER *err; // Error object ERROR_OBJ *error; // Error object values REBINT code = 0; // Create a new error object from another object, including any non-standard fields: if (IS_ERROR(arg) || IS_OBJECT(arg)) { err = Merge_Frames(VAL_OBJ_FRAME(ROOT_ERROBJ), IS_ERROR(arg) ? VAL_OBJ_FRAME(arg) : VAL_ERR_OBJECT(arg)); error = ERR_VALUES(err); // if (!IS_INTEGER(&error->code)) { if (!Find_Error_Info(error, &code)) code = RE_INVALID_ERROR; SET_INTEGER(&error->code, code); // } SET_ERROR(value, VAL_INT32(&error->code), err); return; } // Make a copy of the error object template: err = CLONE_OBJECT(VAL_OBJ_FRAME(ROOT_ERROBJ)); error = ERR_VALUES(err); SET_NONE(&error->id); SET_ERROR(value, 0, err); // If block arg, evaluate object values (checking done later): // If user set error code, use it to setup type and id fields. if (IS_BLOCK(arg)) { DISABLE_GC; Do_Bind_Block(err, arg); // GC-OK (disabled) ENABLE_GC; if (IS_INTEGER(&error->code) && VAL_INT64(&error->code)) { Set_Error_Type(error); } else { if (Find_Error_Info(error, &code)) { SET_INTEGER(&error->code, code); } } // The error code is not valid: if (IS_NONE(&error->id)) { SET_INTEGER(&error->code, RE_INVALID_ERROR); Set_Error_Type(error); } if (VAL_INT64(&error->code) < 100 || VAL_INT64(&error->code) > 1000) Trap_Arg(arg); } // If string arg, setup other fields else if (IS_STRING(arg)) { SET_INTEGER(&error->code, RE_USER); // user error Set_String(&error->arg1, Copy_Series_Value(arg)); Set_Error_Type(error); } // No longer allowed: // else if (IS_INTEGER(arg)) { // error->code = *arg; // Set_Error_Type(error); // } else Trap_Arg(arg); if (!(VAL_ERR_NUM(value) = VAL_INT32(&error->code))) { Trap_Arg(arg); } }