*/ REBINT CT_Logic(REBVAL *a, REBVAL *b, REBINT mode) /* ***********************************************************************/ { if (mode >= 0) return (VAL_LOGIC(a) == VAL_LOGIC(b)); return -1; }
*/ REBINT Get_Num_Arg(REBVAL *val) /* ** Get the amount to skip or pick. ** Allow multiple types. Throw error if not valid. ** Note that the result is one-based. ** ***********************************************************************/ { REBINT n; if (IS_INTEGER(val)) { if (VAL_INT64(val) > (i64)MAX_I32 || VAL_INT64(val) < (i64)MIN_I32) Trap_Range(val); n = VAL_INT32(val); } else if (IS_DECIMAL(val) || IS_PERCENT(val)) { if (VAL_DECIMAL(val) > MAX_I32 || VAL_DECIMAL(val) < MIN_I32) Trap_Range(val); n = (REBINT)VAL_DECIMAL(val); } else if (IS_LOGIC(val)) n = (VAL_LOGIC(val) ? 1 : 2); else Trap_Arg(val); return n; }
*/ REBFLG Get_Logic_Arg(REBVAL *arg) /* ***********************************************************************/ { if (IS_NONE(arg)) return 0; if (IS_INTEGER(arg)) return (VAL_INT64(arg) != 0); if (IS_LOGIC(arg)) return (VAL_LOGIC(arg) != 0); if (IS_DECIMAL(arg) || IS_PERCENT(arg)) return (VAL_DECIMAL(arg) != 0.0); Trap_Arg(arg); DEAD_END; }
*/ REBINT Awake_System(REBSER *ports, REBINT only) /* ** Returns: ** -1 for errors ** 0 for nothing to do ** 1 for wait is satisifed ** ***********************************************************************/ { REBVAL *port; REBVAL *state; REBVAL *waked; REBVAL *awake; REBVAL tmp; REBVAL ref_only; REBINT result; REBVAL out; // Get the system port object: port = Get_System(SYS_PORTS, PORTS_SYSTEM); if (!IS_PORT(port)) return -10; // verify it is a port object // Get wait queue block (the state field): state = VAL_OBJ_VALUE(port, STD_PORT_STATE); if (!IS_BLOCK(state)) return -10; //Debug_Num("S", VAL_TAIL(state)); // Get waked queue block: waked = VAL_OBJ_VALUE(port, STD_PORT_DATA); if (!IS_BLOCK(waked)) return -10; // If there is nothing new to do, return now: if (VAL_TAIL(state) == 0 && VAL_TAIL(waked) == 0) return -1; //Debug_Num("A", VAL_TAIL(waked)); // Get the system port AWAKE function: awake = VAL_OBJ_VALUE(port, STD_PORT_AWAKE); if (!ANY_FUNC(awake)) return -1; if (ports) Val_Init_Block(&tmp, ports); else SET_NONE(&tmp); if (only) SET_TRUE(&ref_only); else SET_NONE(&ref_only); // Call the system awake function: if (Apply_Func_Throws(&out, awake, port, &tmp, &ref_only, 0)) raise Error_No_Catch_For_Throw(&out); // Awake function returns 1 for end of WAIT: result = (IS_LOGIC(&out) && VAL_LOGIC(&out)) ? 1 : 0; return result; }
STOID Mold_Logic(REB_MOLD *mold, REBVAL *value) { REBYTE buf[20]; Pre_Mold(value, mold); INT_TO_STR(VAL_LOGIC(value), buf); Append_Bytes(mold->series, buf); Append_Byte(mold->series, ' '); old_Block_Series(mold, BLK_HEAD(VAL_LOGIC_WORDS(value)), 0); End_Mold(mold); }
*/ void Do_Action(REBVAL *func) /* ***********************************************************************/ { REBVAL *ds = DS_OUT; REBCNT type = VAL_TYPE(D_ARG(1)); Eval_Natives++; assert(type < REB_MAX); // Handle special datatype test cases (eg. integer?) if (VAL_FUNC_ACT(func) == 0) { VAL_SET(D_OUT, REB_LOGIC); VAL_LOGIC(D_OUT) = (type == VAL_INT64(BLK_LAST(VAL_FUNC_SPEC(func)))); return; } Do_Act(D_OUT, type, VAL_FUNC_ACT(func)); }
// // Get_Num_From_Arg: C // // Get the amount to skip or pick. // Allow multiple types. Throw error if not valid. // Note that the result is one-based. // REBINT Get_Num_From_Arg(const REBVAL *val) { REBINT n; if (IS_INTEGER(val)) { if (VAL_INT64(val) > (i64)MAX_I32 || VAL_INT64(val) < (i64)MIN_I32) fail (Error_Out_Of_Range(val)); n = VAL_INT32(val); } else if (IS_DECIMAL(val) || IS_PERCENT(val)) { if (VAL_DECIMAL(val) > MAX_I32 || VAL_DECIMAL(val) < MIN_I32) fail (Error_Out_Of_Range(val)); n = (REBINT)VAL_DECIMAL(val); } else if (IS_LOGIC(val)) n = (VAL_LOGIC(val) ? 1 : 2); else fail (Error_Invalid_Arg(val)); return n; }
// // Do_Breakpoint_Throws: C // // A call to Do_Breakpoint_Throws does delegation to a hook in the host, which // (if registered) will generally start an interactive session for probing the // environment at the break. The `resume` native cooperates by being able to // give back a value (or give back code to run to produce a value) that the // call to breakpoint returns. // // RESUME has another feature, which is to be able to actually unwind and // simulate a return /AT a function *further up the stack*. (This may be // switched to a feature of a "STEP OUT" command at some point.) // REBOOL Do_Breakpoint_Throws( REBVAL *out, REBOOL interrupted, // Ctrl-C (as opposed to a BREAKPOINT) const REBVAL *default_value, REBOOL do_default ) { REBVAL *target = NONE_VALUE; REBVAL temp; VAL_INIT_WRITABLE_DEBUG(&temp); if (!PG_Breakpoint_Quitting_Hook) { // // Host did not register any breakpoint handler, so raise an error // about this as early as possible. // fail (Error(RE_HOST_NO_BREAKPOINT)); } // We call the breakpoint hook in a loop, in order to keep running if any // inadvertent FAILs or THROWs occur during the interactive session. // Only a conscious call of RESUME speaks the protocol to break the loop. // while (TRUE) { struct Reb_State state; REBCTX *error; push_trap: PUSH_TRAP(&error, &state); // The host may return a block of code to execute, but cannot // while evaluating do a THROW or a FAIL that causes an effective // "resumption". Halt is the exception, hence we PUSH_TRAP and // not PUSH_UNHALTABLE_TRAP. QUIT is also an exception, but a // desire to quit is indicated by the return value of the breakpoint // hook (which may or may not decide to request a quit based on the // QUIT command being run). // // The core doesn't want to get involved in presenting UI, so if // an error makes it here and wasn't trapped by the host first that // is a bug in the host. It should have done its own PUSH_TRAP. // if (error) { #if !defined(NDEBUG) REBVAL error_value; VAL_INIT_WRITABLE_DEBUG(&error_value); Val_Init_Error(&error_value, error); PROBE_MSG(&error_value, "Error not trapped during breakpoint:"); Panic_Array(CTX_VARLIST(error)); #endif // In release builds, if an error managed to leak out of the // host's breakpoint hook somehow...just re-push the trap state // and try it again. // goto push_trap; } // Call the host's breakpoint hook. // if (PG_Breakpoint_Quitting_Hook(&temp, interrupted)) { // // If a breakpoint hook returns TRUE that means it wants to quit. // The value should be the /WITH value (as in QUIT/WITH) // assert(!THROWN(&temp)); *out = *ROOT_QUIT_NATIVE; CONVERT_NAME_TO_THROWN(out, &temp, FALSE); return TRUE; // TRUE = threw } // If a breakpoint handler returns FALSE, then it should have passed // back a "resume instruction" triggered by a call like: // // resume/do [fail "This is how to fail from a breakpoint"] // // So now that the handler is done, we will allow any code handed back // to do whatever FAIL it likes vs. trapping that here in a loop. // DROP_TRAP_SAME_STACKLEVEL_AS_PUSH(&state); // Decode and process the "resume instruction" { struct Reb_Frame *frame; REBVAL *mode; REBVAL *payload; assert(IS_GROUP(&temp)); assert(VAL_LEN_HEAD(&temp) == RESUME_INST_MAX); mode = VAL_ARRAY_AT_HEAD(&temp, RESUME_INST_MODE); payload = VAL_ARRAY_AT_HEAD(&temp, RESUME_INST_PAYLOAD); target = VAL_ARRAY_AT_HEAD(&temp, RESUME_INST_TARGET); // The first thing we need to do is determine if the target we // want to return to has another breakpoint sandbox blocking // us. If so, what we need to do is actually retransmit the // resume instruction so it can break that wall, vs. transform // it into an EXIT/FROM that would just get intercepted. // if (!IS_NONE(target)) { #if !defined(NDEBUG) REBOOL found = FALSE; #endif for (frame = FS_TOP; frame != NULL; frame = frame->prior) { if (frame->mode != CALL_MODE_FUNCTION) continue; if ( frame != FS_TOP && FUNC_CLASS(frame->func) == FUNC_CLASS_NATIVE && ( FUNC_CODE(frame->func) == &N_pause || FUNC_CODE(frame->func) == &N_breakpoint ) ) { // We hit a breakpoint (that wasn't this call to // breakpoint, at the current FS_TOP) before finding // the sought after target. Retransmit the resume // instruction so that level will get it instead. // *out = *ROOT_RESUME_NATIVE; CONVERT_NAME_TO_THROWN(out, &temp, FALSE); return TRUE; // TRUE = thrown } if (IS_FRAME(target)) { if (NOT(frame->flags & DO_FLAG_FRAME_CONTEXT)) continue; if ( VAL_CONTEXT(target) == AS_CONTEXT(frame->data.context) ) { // Found a closure matching the target before we // reached a breakpoint, no need to retransmit. // #if !defined(NDEBUG) found = TRUE; #endif break; } } else { assert(IS_FUNCTION(target)); if (frame->flags & DO_FLAG_FRAME_CONTEXT) continue; if (VAL_FUNC(target) == frame->func) { // // Found a function matching the target before we // reached a breakpoint, no need to retransmit. // #if !defined(NDEBUG) found = TRUE; #endif break; } } } // RESUME should not have been willing to use a target that // is not on the stack. // #if !defined(NDEBUG) assert(found); #endif } if (IS_NONE(mode)) { // // If the resume instruction had no /DO or /WITH of its own, // then it doesn't override whatever the breakpoint provided // as a default. (If neither the breakpoint nor the resume // provided a /DO or a /WITH, result will be UNSET.) // goto return_default; // heeds `target` } assert(IS_LOGIC(mode)); if (VAL_LOGIC(mode)) { if (DO_VAL_ARRAY_AT_THROWS(&temp, payload)) { // // Throwing is not compatible with /AT currently. // if (!IS_NONE(target)) fail (Error_No_Catch_For_Throw(&temp)); // Just act as if the BREAKPOINT call itself threw // *out = temp; return TRUE; // TRUE = thrown } // Ordinary evaluation result... } else temp = *payload; } // The resume instruction will be GC'd. // goto return_temp; } DEAD_END; return_default: if (do_default) { if (DO_VAL_ARRAY_AT_THROWS(&temp, default_value)) { // // If the code throws, we're no longer in the sandbox...so we // bubble it up. Note that breakpoint runs this code at its // level... so even if you request a higher target, any throws // will be processed as if they originated at the BREAKPOINT // frame. To do otherwise would require the EXIT/FROM protocol // to add support for DO-ing at the receiving point. // *out = temp; return TRUE; // TRUE = thrown } } else temp = *default_value; // generally UNSET! if no /WITH return_temp: // The easy case is that we just want to return from breakpoint // directly, signaled by the target being NONE!. // if (IS_NONE(target)) { *out = temp; return FALSE; // FALSE = not thrown } // If the target is a function, then we're looking to simulate a return // from something up the stack. This uses the same mechanic as // definitional returns--a throw named by the function or closure frame. // // !!! There is a weak spot in definitional returns for FUNCTION! that // they can only return to the most recent invocation; which is a weak // spot of FUNCTION! in general with stack relative variables. Also, // natives do not currently respond to definitional returns...though // they can do so just as well as FUNCTION! can. // *out = *target; CONVERT_NAME_TO_THROWN(out, &temp, TRUE); return TRUE; // TRUE = thrown }
*/ void Mold_Value(REB_MOLD *mold, REBVAL *value, REBFLG molded) /* ** Mold or form any value to string series tail. ** ***********************************************************************/ { REBYTE buf[60]; REBINT len; REBSER *ser = mold->series; CHECK_STACK(&len); ASSERT2(SERIES_WIDE(mold->series) == sizeof(REBUNI), RP_BAD_SIZE); ASSERT2(ser, RP_NO_BUFFER); // Special handling of string series: { if (ANY_STR(value) && !IS_TAG(value)) { // Forming a string: if (!molded) { Insert_String(ser, -1, VAL_SERIES(value), VAL_INDEX(value), VAL_LEN(value), 0); return; } // Special format for ALL string series when not at head: if (GET_MOPT(mold, MOPT_MOLD_ALL) && VAL_INDEX(value) != 0) { Mold_All_String(value, mold); return; } } switch (VAL_TYPE(value)) { case REB_NONE: Emit(mold, "+N", SYM_NONE); break; case REB_LOGIC: // if (!molded || !VAL_LOGIC_WORDS(value) || !GET_MOPT(mold, MOPT_MOLD_ALL)) Emit(mold, "+N", VAL_LOGIC(value) ? SYM_TRUE : SYM_FALSE); // else // Mold_Logic(mold, value); break; case REB_INTEGER: len = Emit_Integer(buf, VAL_INT64(value)); goto append; case REB_DECIMAL: case REB_PERCENT: len = Emit_Decimal(buf, VAL_DECIMAL(value), IS_PERCENT(value)?DEC_MOLD_PERCENT:0, Punctuation[GET_MOPT(mold, MOPT_COMMA_PT) ? PUNCT_COMMA : PUNCT_DOT], mold->digits); goto append; case REB_MONEY: len = Emit_Money(value, buf, mold->opts); goto append; case REB_CHAR: Mold_Uni_Char(ser, VAL_CHAR(value), (REBOOL)molded, (REBOOL)GET_MOPT(mold, MOPT_MOLD_ALL)); break; case REB_PAIR: len = Emit_Decimal(buf, VAL_PAIR_X(value), DEC_MOLD_MINIMAL, Punctuation[PUNCT_DOT], mold->digits/2); Append_Bytes_Len(ser, buf, len); Append_Byte(ser, 'x'); len = Emit_Decimal(buf, VAL_PAIR_Y(value), DEC_MOLD_MINIMAL, Punctuation[PUNCT_DOT], mold->digits/2); Append_Bytes_Len(ser, buf, len); //Emit(mold, "IxI", VAL_PAIR_X(value), VAL_PAIR_Y(value)); break; case REB_TUPLE: len = Emit_Tuple(value, buf); goto append; case REB_TIME: //len = Emit_Time(value, buf, Punctuation[GET_MOPT(mold, MOPT_COMMA_PT) ? PUNCT_COMMA : PUNCT_DOT]); Emit_Time(mold, value); break; case REB_DATE: Emit_Date(mold, value); break; case REB_STRING: // FORM happens in top section. Mold_String_Series(value, mold); break; case REB_BINARY: if (GET_MOPT(mold, MOPT_MOLD_ALL) && VAL_INDEX(value) != 0) { Mold_All_String(value, mold); return; } Mold_Binary(value, mold); break; case REB_FILE: if (VAL_LEN(value) == 0) { Append_Bytes(ser, "%\"\""); break; } Mold_File(value, mold); break; case REB_EMAIL: case REB_URL: Mold_Url(value, mold); break; case REB_TAG: if (GET_MOPT(mold, MOPT_MOLD_ALL) && VAL_INDEX(value) != 0) { Mold_All_String(value, mold); return; } Mold_Tag(value, mold); break; // Mold_Issue(value, mold); // break; case REB_BITSET: Pre_Mold(value, mold); // #[bitset! or make bitset! Mold_Bitset(value, mold); End_Mold(mold); break; case REB_IMAGE: Pre_Mold(value, mold); if (!GET_MOPT(mold, MOPT_MOLD_ALL)) { Append_Byte(ser, '['); Mold_Image_Data(value, mold); Append_Byte(ser, ']'); End_Mold(mold); } else { REBVAL val = *value; VAL_INDEX(&val) = 0; // mold all of it Mold_Image_Data(&val, mold); Post_Mold(value, mold); } break; case REB_BLOCK: case REB_PAREN: if (!molded) Form_Block_Series(VAL_SERIES(value), VAL_INDEX(value), mold, 0); else Mold_Block(value, mold); break; case REB_PATH: case REB_SET_PATH: case REB_GET_PATH: case REB_LIT_PATH: Mold_Block(value, mold); break; case REB_VECTOR: Mold_Vector(value, mold, molded); break; case REB_DATATYPE: if (!molded) Emit(mold, "N", VAL_DATATYPE(value) + 1); else Emit(mold, "+DN", SYM_DATATYPE_TYPE, VAL_DATATYPE(value) + 1); break; case REB_TYPESET: Mold_Typeset(value, mold, molded); break; case REB_WORD: // This is a high frequency function, so it is optimized. Append_UTF8(ser, Get_Sym_Name(VAL_WORD_SYM(value)), -1); break; case REB_SET_WORD: Emit(mold, "W:", value); break; case REB_GET_WORD: Emit(mold, ":W", value); break; case REB_LIT_WORD: Emit(mold, "\'W", value); break; case REB_REFINEMENT: Emit(mold, "/W", value); break; case REB_ISSUE: Emit(mold, "#W", value); break; case REB_CLOSURE: case REB_FUNCTION: case REB_NATIVE: case REB_ACTION: case REB_COMMAND: Mold_Function(value, mold); break; case REB_OBJECT: case REB_MODULE: case REB_PORT: if (!molded) Form_Object(value, mold); else Mold_Object(value, mold); break; case REB_TASK: Mold_Object(value, mold); //// | (1<<MOPT_NO_NONE)); break; case REB_ERROR: Mold_Error(value, mold, molded); break; case REB_MAP: Mold_Map(value, mold, molded); break; case REB_GOB: { REBSER *blk; Pre_Mold(value, mold); blk = Gob_To_Block(VAL_GOB(value)); Mold_Block_Series(mold, blk, 0, 0); End_Mold(mold); } break; case REB_EVENT: Mold_Event(value, mold); break; case REB_REBCODE: case REB_OP: case REB_FRAME: case REB_HANDLE: case REB_STRUCT: case REB_LIBRARY: case REB_UTYPE: // Value has no printable form, so just print its name. if (!molded) Emit(mold, "?T?", value); else Emit(mold, "+T", value); break; case REB_END: case REB_UNSET: if (molded) Emit(mold, "+T", value); break; default: Crash(RP_DATATYPE+5, VAL_TYPE(value)); } return; append: Append_Bytes_Len(ser, buf, len); }
*/ REBINT Text_Gob(void *richtext, REBSER *block) /* ** Handles all commands for the TEXT dialect as specified ** in the system/dialects/text object. ** ** This function calls the REBOL_Dialect interpreter to ** parse the dialect and build and return the command number ** (the index offset in the text object above) and a block ** of arguments. (For now, just a REBOL block, but this could ** be changed to isolate it from changes in REBOL's internals). ** ** Each arg will be of the specified datatype (given in the ** dialect) or NONE when no argument of that type was given ** and this code must determine the proper default value. ** ** If the cmd result is zero, then it is either the end of ** the block, or an error has occurred. If the error value ** is non-zero, then it was an error. ** ***********************************************************************/ { REBCNT index = 0; REBINT cmd; REBSER *args = 0; REBVAL *arg; REBCNT nargs; //font object conversion related values REBFNT* font; REBVAL* val; REBPAR offset; REBPAR space; //para object conversion related values REBPRA* para; REBPAR origin; REBPAR margin; REBPAR indent; REBPAR scroll; do { cmd = Reb_Dialect(DIALECTS_TEXT, block, &index, &args); if (cmd == 0) return 0; if (cmd < 0) { // Reb_Print("ERROR: %d, Index %d", -cmd, index); return -((REBINT)index+1); } // else // Reb_Print("TEXT: Cmd %d, Index %d, Args %m", cmd, index, args); arg = BLK_HEAD(args); nargs = SERIES_TAIL(args); // Reb_Print("Number of args: %d", nargs); switch (cmd) { case TW_TYPE_SPEC: if (IS_STRING(arg)) { rt_text(richtext, ARG_STRING(0), index); } else if (IS_TUPLE(arg)) { rt_color(richtext, ARG_TUPLE(0)); } break; case TW_ANTI_ALIAS: rt_anti_alias(richtext, ARG_OPT_LOGIC(0)); break; case TW_SCROLL: rt_scroll(richtext, ARG_PAIR(0)); break; case TW_BOLD: case TW_B: rt_bold(richtext, ARG_OPT_LOGIC(0)); break; case TW_ITALIC: case TW_I: rt_italic(richtext, ARG_OPT_LOGIC(0)); break; case TW_UNDERLINE: case TW_U: rt_underline(richtext, ARG_OPT_LOGIC(0)); break; case TW_CENTER: rt_center(richtext); break; case TW_LEFT: rt_left(richtext); break; case TW_RIGHT: rt_right(richtext); break; case TW_FONT: if (!IS_OBJECT(arg)) break; font = (REBFNT*)rt_get_font(richtext); val = BLK_HEAD(ARG_OBJECT(0))+1; if (IS_STRING(val)) { font->name = VAL_STRING(val); } // Reb_Print("font/name: %s", font->name); val++; if (IS_BLOCK(val)) { REBSER* styles = VAL_SERIES(val); REBVAL* slot = BLK_HEAD(styles); REBCNT len = SERIES_TAIL(styles) ,i; for (i = 0;i<len;i++){ if (IS_WORD(slot+i)){ set_font_styles(font, slot+i); } } } else if (IS_WORD(val)) { set_font_styles(font, val); } val++; if (IS_INTEGER(val)) { font->size = VAL_INT32(val); } // Reb_Print("font/size: %d", font->size); val++; if ((IS_TUPLE(val)) || (IS_NONE(val))) { COPY_MEM(font->color,VAL_TUPLE(val), 4); } // Reb_Print("font/color: %d.%d.%d.%d", font->color[0],font->color[1],font->color[2],font->color[3]); val++; if ((IS_PAIR(val)) || (IS_NONE(val))) { offset = VAL_PAIR(val); font->offset_x = offset.x; font->offset_y = offset.y; } // Reb_Print("font/offset: %dx%d", offset.x,offset.y); val++; if ((IS_PAIR(val)) || (IS_NONE(val))) { space = VAL_PAIR(val); font->space_x = space.x; font->space_y = space.y; } // Reb_Print("font/space: %dx%d", space.x, space.y); val++; font->shadow_x = 0; font->shadow_y = 0; if (IS_BLOCK(val)) { REBSER* ser = VAL_SERIES(val); REBVAL* slot = BLK_HEAD(ser); REBCNT len = SERIES_TAIL(ser) ,i; for (i = 0;i<len;i++){ if (IS_PAIR(slot)) { REBPAR shadow = VAL_PAIR(slot); font->shadow_x = shadow.x; font->shadow_y = shadow.y; } else if (IS_TUPLE(slot)) { COPY_MEM(font->shadow_color,VAL_TUPLE(slot), 4); } else if (IS_INTEGER(slot)) { font->shadow_blur = VAL_INT32(slot); } slot++; } } else if (IS_PAIR(val)) { REBPAR shadow = VAL_PAIR(val); font->shadow_x = shadow.x; font->shadow_y = shadow.y; } rt_font(richtext, font); break; case TW_PARA: if (!IS_OBJECT(arg)) break; para = (REBPRA*)rt_get_para(richtext); val = BLK_HEAD(ARG_OBJECT(0))+1; if (IS_PAIR(val)) { origin = VAL_PAIR(val); para->origin_x = origin.x; para->origin_y = origin.y; } // Reb_Print("para/origin: %dx%d", origin.x, origin.y); val++; if (IS_PAIR(val)) { margin = VAL_PAIR(val); para->margin_x = margin.x; para->margin_y = margin.y; } // Reb_Print("para/margin: %dx%d", margin.x, margin.y); val++; if (IS_PAIR(val)) { indent = VAL_PAIR(val); para->indent_x = indent.x; para->indent_y = indent.y; } // Reb_Print("para/indent: %dx%d", indent.x, indent.y); val++; if (IS_INTEGER(val)) { para->tabs = VAL_INT32(val); } // Reb_Print("para/tabs: %d", para->tabs); val++; if (IS_LOGIC(val)) { para->wrap = VAL_LOGIC(val); } // Reb_Print("para/wrap?: %d", para->wrap); val++; if (IS_PAIR(val)) { scroll = VAL_PAIR(val); para->scroll_x = scroll.x; para->scroll_y = scroll.y; } // Reb_Print("para/scroll: %dx%d", scroll.x, scroll.y); val++; if (IS_WORD(val)) { REBINT result = Reb_Find_Word(VAL_WORD_SYM(val), Symbol_Ids, 0); switch (result){ case SW_RIGHT: case SW_LEFT: case SW_CENTER: para->align = result; break; default: para->align = SW_LEFT; break; } } val++; if (IS_WORD(val)) { REBINT result = Reb_Find_Word(VAL_WORD_SYM(val), Symbol_Ids, 0); switch (result){ case SW_TOP: case SW_BOTTOM: case SW_MIDDLE: para->valign = result; break; default: para->valign = SW_TOP; break; } } rt_para(richtext, para); break; case TW_SIZE: rt_font_size(richtext, ARG_INTEGER(0)); break; case TW_SHADOW: rt_shadow(richtext, &ARG_PAIR(0), ARG_TUPLE(1), ARG_INTEGER(2)); break; case TW_DROP: rt_drop(richtext, ARG_OPT_INTEGER(0)); break; case TW_NEWLINE: case TW_NL: rt_newline(richtext, index); break; case TW_CARET: { REBPAR caret = {0,0}; REBPAR highlightStart = {0,0}; REBPAR highlightEnd = {0,0}; REBVAL *slot; if (!IS_OBJECT(arg)) break; val = BLK_HEAD(ARG_OBJECT(0))+1; if (IS_BLOCK(val)) { slot = BLK_HEAD(VAL_SERIES(val)); if (SERIES_TAIL(VAL_SERIES(val)) == 2 && IS_BLOCK(slot) && IS_STRING(slot+1)){ caret.x = 1 + slot->data.series.index; caret.y = 1 + (slot+1)->data.series.index;; //Reb_Print("caret %d, %d", caret.x, caret.y); } } val++; if (IS_BLOCK(val)) { slot = BLK_HEAD(VAL_SERIES(val)); if (SERIES_TAIL(VAL_SERIES(val)) == 2 && IS_BLOCK(slot) && IS_STRING(slot+1)){ highlightStart.x = 1 + slot->data.series.index; highlightStart.y = 1 + (slot+1)->data.series.index;; //Reb_Print("highlight-start %d, %d", highlightStart.x, highlightStart.y); } } val++; if (IS_BLOCK(val)) { slot = BLK_HEAD(VAL_SERIES(val)); if (SERIES_TAIL(VAL_SERIES(val)) == 2 && IS_BLOCK(slot) && IS_STRING(slot+1)){ highlightEnd.x = 1 + slot->data.series.index; highlightEnd.y = 1 + (slot+1)->data.series.index;; //Reb_Print("highlight-End %d, %d", highlightEnd.x, highlightEnd.y); } } rt_caret(richtext, &caret, &highlightStart,&highlightEnd); } break; } } while (TRUE); }
*/ REBINT Cmp_Value(REBVAL *s, REBVAL *t, REBFLG is_case) /* ** Compare two values and return the difference. ** ** is_case TRUE for case sensitive compare ** ***********************************************************************/ { REBDEC d1, d2; if (VAL_TYPE(t) != VAL_TYPE(s) && !(IS_NUMBER(s) && IS_NUMBER(t))) return VAL_TYPE(s) - VAL_TYPE(t); switch(VAL_TYPE(s)) { case REB_INTEGER: if (IS_DECIMAL(t)) { d1 = (REBDEC)VAL_INT64(s); d2 = VAL_DECIMAL(t); goto chkDecimal; } return THE_SIGN(VAL_INT64(s) - VAL_INT64(t)); case REB_LOGIC: return VAL_LOGIC(s) - VAL_LOGIC(t); case REB_CHAR: if (is_case) return THE_SIGN(VAL_CHAR(s) - VAL_CHAR(t)); return THE_SIGN((REBINT)(UP_CASE(VAL_CHAR(s)) - UP_CASE(VAL_CHAR(t)))); case REB_DECIMAL: case REB_MONEY: d1 = VAL_DECIMAL(s); if (IS_INTEGER(t)) d2 = (REBDEC)VAL_INT64(t); else d2 = VAL_DECIMAL(t); chkDecimal: if (Eq_Decimal(d1, d2)) return 0; if (d1 < d2) return -1; return 1; case REB_PAIR: return Cmp_Pair(s, t); case REB_EVENT: return Cmp_Event(s, t); case REB_GOB: return Cmp_Gob(s, t); case REB_TUPLE: return Cmp_Tuple(s, t); case REB_TIME: return Cmp_Time(s, t); case REB_DATE: return Cmp_Date(s, t); case REB_BLOCK: case REB_PAREN: case REB_MAP: case REB_PATH: case REB_SET_PATH: case REB_GET_PATH: case REB_LIT_PATH: return Cmp_Block(s, t, is_case); case REB_STRING: case REB_FILE: case REB_EMAIL: case REB_URL: case REB_TAG: return Compare_String_Vals(s, t, (REBOOL)!is_case); case REB_BITSET: case REB_BINARY: case REB_IMAGE: return Compare_Binary_Vals(s, t); case REB_VECTOR: return Compare_Vector(s, t); case REB_DATATYPE: return VAL_DATATYPE(s) - VAL_DATATYPE(t); case REB_WORD: case REB_SET_WORD: case REB_GET_WORD: case REB_LIT_WORD: case REB_REFINEMENT: case REB_ISSUE: return Compare_Word(s,t,is_case); case REB_ERROR: return VAL_ERR_NUM(s) - VAL_ERR_NUM(s); case REB_OBJECT: case REB_MODULE: case REB_PORT: return VAL_OBJ_FRAME(s) - VAL_OBJ_FRAME(t); case REB_NATIVE: return &VAL_FUNC_CODE(s) - &VAL_FUNC_CODE(t); case REB_ACTION: case REB_COMMAND: case REB_OP: case REB_FUNCTION: return VAL_FUNC_BODY(s) - VAL_FUNC_BODY(t); case REB_NONE: case REB_UNSET: case REB_END: default: break; } return 0; }
// // MAKE_Decimal: C // void MAKE_Decimal(REBVAL *out, enum Reb_Kind kind, const REBVAL *arg) { REBDEC d; switch (VAL_TYPE(arg)) { case REB_DECIMAL: d = VAL_DECIMAL(arg); goto dont_divide_if_percent; case REB_PERCENT: d = VAL_DECIMAL(arg); goto dont_divide_if_percent; case REB_INTEGER: d = cast(REBDEC, VAL_INT64(arg)); goto dont_divide_if_percent; case REB_MONEY: d = deci_to_decimal(VAL_MONEY_AMOUNT(arg)); goto dont_divide_if_percent; case REB_LOGIC: d = VAL_LOGIC(arg) ? 1.0 : 0.0; goto dont_divide_if_percent; case REB_CHAR: d = cast(REBDEC, VAL_CHAR(arg)); goto dont_divide_if_percent; case REB_TIME: d = VAL_TIME(arg) * NANO; break; case REB_STRING: { REBYTE *bp; REBCNT len; bp = Temp_Byte_Chars_May_Fail(arg, MAX_SCAN_DECIMAL, &len, FALSE); VAL_RESET_HEADER(out, kind); if (!Scan_Decimal( &d, bp, len, LOGICAL(kind != REB_PERCENT) )) { goto bad_make; } break; } case REB_BINARY: Binary_To_Decimal(arg, out); VAL_RESET_HEADER(out, kind); d = VAL_DECIMAL(out); break; #ifdef removed // case REB_ISSUE: { REBYTE *bp; REBCNT len; bp = Temp_Byte_Chars_May_Fail(arg, MAX_HEX_LEN, &len, FALSE); if (Scan_Hex(&VAL_INT64(out), bp, len, len) == 0) fail (Error_Bad_Make(REB_DECIMAL, val)); d = VAL_DECIMAL(out); break; } #endif default: if (ANY_ARRAY(arg) && VAL_ARRAY_LEN_AT(arg) == 2) { RELVAL *item = VAL_ARRAY_AT(arg); if (IS_INTEGER(item)) d = cast(REBDEC, VAL_INT64(item)); else if (IS_DECIMAL(item) || IS_PERCENT(item)) d = VAL_DECIMAL(item); else { REBVAL specific; COPY_VALUE(&specific, item, VAL_SPECIFIER(arg)); fail (Error_Invalid_Arg(&specific)); } ++item; REBDEC exp; if (IS_INTEGER(item)) exp = cast(REBDEC, VAL_INT64(item)); else if (IS_DECIMAL(item) || IS_PERCENT(item)) exp = VAL_DECIMAL(item); else { REBVAL specific; COPY_VALUE(&specific, item, VAL_SPECIFIER(arg)); fail (Error_Invalid_Arg(&specific)); } while (exp >= 1) { // // !!! Comment here said "funky. There must be a better way" // --exp; d *= 10.0; if (!FINITE(d)) fail (Error(RE_OVERFLOW)); } while (exp <= -1) { ++exp; d /= 10.0; } } else fail (Error_Bad_Make(kind, arg)); } if (kind == REB_PERCENT) d /= 100.0; dont_divide_if_percent: if (!FINITE(d)) fail (Error(RE_OVERFLOW)); VAL_RESET_HEADER(out, kind); VAL_DECIMAL(out) = d; return; bad_make: fail (Error_Bad_Make(kind, arg)); }
// // Cmp_Value: C // // Compare two values and return the difference. // // is_case TRUE for case sensitive compare // REBINT Cmp_Value(const RELVAL *s, const RELVAL *t, REBOOL is_case) { REBDEC d1, d2; if (VAL_TYPE(t) != VAL_TYPE(s) && !(ANY_NUMBER(s) && ANY_NUMBER(t))) return VAL_TYPE(s) - VAL_TYPE(t); assert(NOT_END(s) && NOT_END(t)); switch(VAL_TYPE(s)) { case REB_INTEGER: if (IS_DECIMAL(t)) { d1 = (REBDEC)VAL_INT64(s); d2 = VAL_DECIMAL(t); goto chkDecimal; } return THE_SIGN(VAL_INT64(s) - VAL_INT64(t)); case REB_LOGIC: return VAL_LOGIC(s) - VAL_LOGIC(t); case REB_CHAR: if (is_case) return THE_SIGN(VAL_CHAR(s) - VAL_CHAR(t)); return THE_SIGN((REBINT)(UP_CASE(VAL_CHAR(s)) - UP_CASE(VAL_CHAR(t)))); case REB_PERCENT: case REB_DECIMAL: case REB_MONEY: if (IS_MONEY(s)) d1 = deci_to_decimal(VAL_MONEY_AMOUNT(s)); else d1 = VAL_DECIMAL(s); if (IS_INTEGER(t)) d2 = cast(REBDEC, VAL_INT64(t)); else if (IS_MONEY(t)) d2 = deci_to_decimal(VAL_MONEY_AMOUNT(t)); else d2 = VAL_DECIMAL(t); chkDecimal: if (Eq_Decimal(d1, d2)) return 0; if (d1 < d2) return -1; return 1; case REB_PAIR: return Cmp_Pair(s, t); case REB_EVENT: return Cmp_Event(s, t); case REB_GOB: return Cmp_Gob(s, t); case REB_TUPLE: return Cmp_Tuple(s, t); case REB_TIME: return Cmp_Time(s, t); case REB_DATE: return Cmp_Date(s, t); case REB_BLOCK: case REB_GROUP: case REB_MAP: case REB_PATH: case REB_SET_PATH: case REB_GET_PATH: case REB_LIT_PATH: return Cmp_Array(s, t, is_case); case REB_STRING: case REB_FILE: case REB_EMAIL: case REB_URL: case REB_TAG: return Compare_String_Vals(s, t, NOT(is_case)); case REB_BITSET: case REB_BINARY: case REB_IMAGE: return Compare_Binary_Vals(s, t); case REB_VECTOR: return Compare_Vector(s, t); case REB_DATATYPE: return VAL_TYPE_KIND(s) - VAL_TYPE_KIND(t); case REB_WORD: case REB_SET_WORD: case REB_GET_WORD: case REB_LIT_WORD: case REB_REFINEMENT: case REB_ISSUE: return Compare_Word(s,t,is_case); case REB_ERROR: return VAL_ERR_NUM(s) - VAL_ERR_NUM(t); case REB_OBJECT: case REB_MODULE: case REB_PORT: return VAL_CONTEXT(s) - VAL_CONTEXT(t); case REB_FUNCTION: return VAL_FUNC_PARAMLIST(s) - VAL_FUNC_PARAMLIST(t); case REB_LIBRARY: return VAL_LIBRARY(s) - VAL_LIBRARY(t); case REB_STRUCT: return Cmp_Struct(s, t); case REB_BLANK: case REB_MAX_VOID: default: break; } return 0; }