*/ REBINT CT_Datatype(REBVAL *a, REBVAL *b, REBINT mode) /* ***********************************************************************/ { if (mode >= 0) return (VAL_DATATYPE(a) == VAL_DATATYPE(b)); return -1; }
*/ REBFLG MT_Datatype(REBVAL *out, REBVAL *data, REBCNT type) /* ***********************************************************************/ { if (!IS_WORD(data)) return FALSE; type = VAL_WORD_CANON(data); if (type > REB_MAX) return FALSE; VAL_SET(out, REB_DATATYPE); VAL_DATATYPE(out) = type-1; VAL_TYPE_SPEC(out) = 0; return TRUE; }
*/ static REBOOL Is_Of_Type(REBVAL *value, REBVAL *types) /* ** Types can be: word or block. Each element must be either ** a datatype or a typeset. ** ***********************************************************************/ { REBVAL *val; val = IS_WORD(types) ? Get_Var(types) : types; if (IS_DATATYPE(val)) { return (VAL_DATATYPE(val) == (REBINT)VAL_TYPE(value)); } if (IS_TYPESET(val)) { return (TYPE_CHECK(val, VAL_TYPE(value))); } if (IS_BLOCK(val)) { for (types = VAL_BLK_DATA(val); NOT_END(types); types++) { val = IS_WORD(types) ? Get_Var(types) : types; if (IS_DATATYPE(val)) if (VAL_DATATYPE(val) == (REBINT)VAL_TYPE(value)) return TRUE; else if (IS_TYPESET(val)) if (TYPE_CHECK(val, VAL_TYPE(value))) return TRUE; else Trap1(RE_INVALID_TYPE, Of_Type(val)); } return FALSE; } Trap_Arg(types); return 0; // for compiler }
*/ REBFLG Make_Typeset(REBVAL *block, REBVAL *value, REBFLG load) /* ** block - block of datatypes (datatype words ok too) ** value - value to hold result (can be word-spec type too) ** ***********************************************************************/ { const REBVAL *val; REBCNT sym; REBSER *types = VAL_SERIES(ROOT_TYPESETS); VAL_TYPESET(value) = 0; for (; NOT_END(block); block++) { val = NULL; if (IS_WORD(block)) { //Print("word: %s", Get_Word_Name(block)); sym = VAL_WORD_SYM(block); if (VAL_WORD_FRAME(block)) { // Get word value val = GET_VAR(block); } else if (sym < REB_MAX) { // Accept datatype word TYPE_SET(value, VAL_WORD_SYM(block)-1); continue; } // Special typeset symbols: else if (sym >= SYM_ANY_TYPEX && sym <= SYM_ANY_BLOCKX) val = BLK_SKIP(types, sym - SYM_ANY_TYPEX + 1); } if (!val) val = block; if (IS_DATATYPE(val)) { TYPE_SET(value, VAL_DATATYPE(val)); } else if (IS_TYPESET(val)) { VAL_TYPESET(value) |= VAL_TYPESET(val); } else { if (load) return FALSE; Trap_Arg_DEAD_END(block); } } return TRUE; }
*/ 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); }
*/ REBCNT Find_Block(REBSER *series, REBCNT index, REBCNT end, REBVAL *target, REBCNT len, REBCNT flags, REBINT skip) /* ** Flags are set according to: ALL_FIND_REFS ** ** Main Parameters: ** start - index to start search ** end - ending position ** len - length of target ** skip - skip factor ** dir - direction ** ** Comparison Parameters: ** case - case sensitivity ** wild - wild cards/keys ** ** Final Parmameters: ** tail - tail position ** match - sequence ** SELECT - (value that follows) ** ***********************************************************************/ { REBVAL *value; REBVAL *val; REBCNT cnt; REBCNT start = index; if (flags & (AM_FIND_REVERSE | AM_FIND_LAST)) { skip = -1; start = 0; if (flags & AM_FIND_LAST) index = end - len; else index--; } // Optimized find word in block: if (ANY_WORD(target)) { for (; index >= start && index < end; index += skip) { value = BLK_SKIP(series, index); if (ANY_WORD(value)) { cnt = (VAL_WORD_SYM(value) == VAL_WORD_SYM(target)); if (flags & AM_FIND_CASE) { // Must be same type and spelling: if (cnt && VAL_TYPE(value) == VAL_TYPE(target)) return index; } else { // Can be different type or alias: if (cnt || VAL_WORD_CANON(value) == VAL_WORD_CANON(target)) return index; } } if (flags & AM_FIND_MATCH) break; } return NOT_FOUND; } // Match a block against a block: else if (ANY_BLOCK(target) && !(flags & AM_FIND_ONLY)) { for (; index >= start && index < end; index += skip) { cnt = 0; value = BLK_SKIP(series, index); for (val = VAL_BLK_DATA(target); NOT_END(val); val++, value++) { if (0 != Cmp_Value(value, val, (REBOOL)(flags & AM_FIND_CASE))) break; if (++cnt >= len) { return index; } } if (flags & AM_FIND_MATCH) break; } return NOT_FOUND; } // Find a datatype in block: else if (IS_DATATYPE(target) || IS_TYPESET(target)) { for (; index >= start && index < end; index += skip) { value = BLK_SKIP(series, index); // Used if's so we can trace it... if (IS_DATATYPE(target)) { if ((REBINT)VAL_TYPE(value) == VAL_DATATYPE(target)) return index; if (IS_DATATYPE(value) && VAL_DATATYPE(value) == VAL_DATATYPE(target)) return index; } if (IS_TYPESET(target)) { if (TYPE_CHECK(target, VAL_TYPE(value))) return index; if (IS_DATATYPE(value) && TYPE_CHECK(target, VAL_DATATYPE(value))) return index; if (IS_TYPESET(value) && EQUAL_TYPESET(value, target)) return index; } if (flags & AM_FIND_MATCH) break; } return NOT_FOUND; } // All other cases: else { for (; index >= start && index < end; index += skip) { value = BLK_SKIP(series, index); if (0 == Cmp_Value(value, target, (REBOOL)(flags & AM_FIND_CASE))) return index; if (flags & AM_FIND_MATCH) break; } return NOT_FOUND; } }
*/ void Make_Block_Type(REBFLG make, REBVAL *value, REBVAL *arg) /* ** Value can be: ** 1. a datatype (e.g. BLOCK!) ** 2. a value (e.g. [...]) ** ** Arg can be: ** 1. integer (length of block) ** 2. block (copy it) ** 3. value (convert to a block) ** ***********************************************************************/ { REBCNT type; REBCNT len; REBSER *ser; // make block! ... if (IS_DATATYPE(value)) type = VAL_DATATYPE(value); else // make [...] .... type = VAL_TYPE(value); // make block! [1 2 3] if (ANY_BLOCK(arg)) { len = VAL_BLK_LEN(arg); if (len > 0 && type >= REB_PATH && type <= REB_LIT_PATH) No_Nones(arg); ser = Copy_Values(VAL_BLK_DATA(arg), len); goto done; } if (IS_STRING(arg)) { REBCNT index, len = 0; VAL_SERIES(arg) = Prep_Bin_Str(arg, &index, &len); // (keeps safe) ser = Scan_Source(VAL_BIN(arg), VAL_LEN(arg)); goto done; } if (IS_BINARY(arg)) { ser = Scan_Source(VAL_BIN_DATA(arg), VAL_LEN(arg)); goto done; } if (IS_MAP(arg)) { ser = Map_To_Block(VAL_SERIES(arg), 0); goto done; } if (ANY_OBJECT(arg)) { ser = Make_Object_Block(VAL_OBJ_FRAME(arg), 3); goto done; } if (IS_VECTOR(arg)) { ser = Make_Vector_Block(arg); goto done; } // if (make && IS_NONE(arg)) { // ser = Make_Block(0); // goto done; // } // to block! typset if (!make && IS_TYPESET(arg) && type == REB_BLOCK) { Set_Block(value, Typeset_To_Block(arg)); return; } if (make) { // make block! 10 if (IS_INTEGER(arg) || IS_DECIMAL(arg)) { len = Int32s(arg, 0); Set_Series(type, value, Make_Block(len)); return; } Trap_Arg(arg); } ser = Copy_Values(arg, 1); done: Set_Series(type, value, ser); return; }
*/ static REBINT Add_Arg(REBDIA *dia, REBVAL *value) /* ** Add an actual argument to the output block. ** ** Note that the argument may be out sequence with the formal ** arguments so we must scan for a slot that matches. ** ** Returns: ** 1: arg matches a formal arg and has been stored ** 0: no arg of that type was found ** -N: error (type block contains a bad value) ** ***********************************************************************/ { REBINT type = 0; REBINT accept = 0; REBVAL *fargs; REBINT fargi; REBVAL *outp; REBINT rept = 0; outp = BLK_SKIP(dia->out, dia->outi); // Scan all formal args, looking for one that matches given value: for (fargi = dia->fargi;; fargi++) { //Debug_Fmt("Add_Arg fargi: %d outi: %d", fargi, outi); if (IS_END(fargs = BLK_SKIP(dia->fargs, fargi))) return 0; again: // Formal arg can be a word (type or refinement), datatype, or * (repeater): if (IS_WORD(fargs)) { // If word is a datatype name: type = VAL_WORD_CANON(fargs); if (type < REB_MAX) { type--; // the type id } else if (type == SYM__P) { // repeat: * integer! rept = 1; fargs++; goto again; } else { // typeset or refinement REBVAL *temp; type = -1; // Is it a refinement word? if (IS_WORD(value) && VAL_WORD_CANON(fargs) == VAL_WORD_CANON(value)) { accept = 4; } // Is it a typeset? else if (NZ(temp = Get_Var_No_Trap(fargs)) && IS_TYPESET(temp)) { if (TYPE_CHECK(temp, VAL_TYPE(value))) accept = 1; } else if (!IS_WORD(value)) return 0; // do not search past a refinement //else return -REB_DIALECT_BAD_SPEC; } } // It's been reduced and is an actual datatype or typeset: else if (IS_DATATYPE(fargs)) { type = VAL_DATATYPE(fargs); } else if (IS_TYPESET(fargs)) { if (TYPE_CHECK(fargs, VAL_TYPE(value))) accept = 1; } else return -REB_DIALECT_BAD_SPEC; // Make room for it in the output block: if (IS_END(outp)) outp = Append_Value(dia->out); else if (!IS_NONE(outp)) { // There's already an arg in this slot, so skip it... if (dia->cmd > 1) outp++; if (!rept) continue; // see if there's another farg that will work for it // Look for first empty slot: while (NOT_END(outp) && !IS_NONE(outp)) outp++; if (IS_END(outp)) outp = Append_Value(dia->out); } // The datatype was correct from above! if (accept) break; //Debug_Fmt("want: %d got: %d rept: %d", type, VAL_TYPE(value), rept); // Direct match to datatype or to integer/decimal coersions: if (type == (REBINT)VAL_TYPE(value)) { accept = 1; break; } else if (type == REB_INTEGER && IS_DECIMAL(value)) { accept = 2; break; } else if (type == REB_DECIMAL && IS_INTEGER(value)) { accept = 3; break; } dia->missed++; // for debugging // Repeat did not match, so stop repeating and remove unused output slot: if (rept) { Remove_Last(dia->out); outp--; rept = 0; continue; } if (dia->cmd > 1) outp++; // skip output slot (for non-default values) } // Process the result: switch (accept) { case 1: *outp = *value; break; case 2: SET_INTEGER(outp, (REBI64)VAL_DECIMAL(value)); break; case 3: SET_DECIMAL(outp, (REBDEC)VAL_INT64(value)); break; case 4: // refinement: dia->fargi = fargs - BLK_HEAD(dia->fargs) + 1; dia->outi = outp - BLK_HEAD(dia->out) + 1; *outp = *value; return 1; case 0: return 0; } // Optimization: arg was in correct order: if (!rept && fargi == (signed)(dia->fargi)) { dia->fargi++; dia->outi++; } return 1; }
*/ 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; }
*/ static REBCNT Parse_Next_Block(REBPARSE *parse, REBCNT index, REBVAL *item, REBCNT depth) /* ** Used for parsing blocks to match the next item in the ruleset. ** If it matches, return the index just past it. Otherwise, return zero. ** ***********************************************************************/ { // !!! THIS CODE NEEDS CLEANUP AND REWRITE BASED ON OTHER CHANGES REBSER *series = parse->series; REBVAL *blk = BLK_SKIP(series, index); if (Trace_Level) { Trace_Value(7, item); Trace_Value(8, blk); } switch (VAL_TYPE(item)) { // Look for specific datattype: case REB_DATATYPE: index++; if (VAL_TYPE(blk) == (REBYTE)VAL_DATATYPE(item)) break; goto no_result; // Look for a set of datatypes: case REB_TYPESET: index++; if (TYPE_CHECK(item, VAL_TYPE(blk))) break; goto no_result; // 'word case REB_LIT_WORD: index++; if (IS_WORD(blk) && (VAL_WORD_CANON(blk) == VAL_WORD_CANON(item))) break; goto no_result; case REB_LIT_PATH: index++; if (IS_PATH(blk) && !Cmp_Block(blk, item, 0)) break; goto no_result; case REB_NONE: break; // Parse a sub-rule block: case REB_BLOCK: index = Parse_Rules_Loop(parse, index, VAL_BLK_DATA(item), depth); break; // Do an expression: case REB_PAREN: item = Do_Block_Value_Throw(item); // might GC // old: if (IS_ERROR(item)) Throw_Error(VAL_ERR_OBJECT(item)); index = MIN(index, series->tail); // may affect tail break; // Match with some other value: default: index++; if (Cmp_Value(blk, item, (REBOOL)HAS_CASE(parse))) goto no_result; } return index; no_result: return NOT_FOUND; }