static REBOOL same_fields(REBSER *tgt, REBSER *src) { struct Struct_Field *tgt_fields = (struct Struct_Field *) SERIES_DATA(tgt); struct Struct_Field *src_fields = (struct Struct_Field *) SERIES_DATA(src); REBCNT n; if (SERIES_TAIL(tgt) != SERIES_TAIL(src)) { return FALSE; } for(n = 0; n < SERIES_TAIL(src); n ++) { if (tgt_fields[n].type != src_fields[n].type) { return FALSE; } if (VAL_SYM_CANON(BLK_SKIP(PG_Word_Table.series, tgt_fields[n].sym)) != VAL_SYM_CANON(BLK_SKIP(PG_Word_Table.series, src_fields[n].sym)) || tgt_fields[n].offset != src_fields[n].offset || tgt_fields[n].dimension != src_fields[n].dimension || tgt_fields[n].size != src_fields[n].size) { return FALSE; } if (tgt_fields[n].type == STRUCT_TYPE_STRUCT && ! same_fields(tgt_fields[n].fields, src_fields[n].fields)) { return FALSE; } } return TRUE; }
*/ static REBFLG Get_Struct_Var(REBSTU *stu, REBVAL *word, REBVAL *val) /* ***********************************************************************/ { struct Struct_Field *field = NULL; REBCNT i = 0; field = (struct Struct_Field *)SERIES_DATA(stu->fields); for (i = 0; i < SERIES_TAIL(stu->fields); i ++, field ++) { if (VAL_WORD_CANON(word) == VAL_SYM_CANON(BLK_SKIP(PG_Word_Table.series, field->sym))) { if (field->array) { REBSER *ser = Make_Array(field->dimension); REBCNT n = 0; for (n = 0; n < field->dimension; n ++) { REBVAL elem; get_scalar(stu, field, n, &elem); Append_Value(ser, &elem); } Val_Init_Block(val, ser); } else { get_scalar(stu, field, 0, val); } return TRUE; } } return FALSE; }
xx*/ void Dump_Word_Table() /* ***********************************************************************/ { REBCNT n; REBVAL *words = BLK_HEAD(PG_Word_Table.series); for (n = 1; n < PG_Word_Table.series->tail; n++) { Debug_Fmt("%03d: %s = %d (%d)", n, VAL_SYM_NAME(words+n), VAL_SYM_CANON(words+n), VAL_SYM_ALIAS(words+n)); // if ((n % 40) == 0) getchar(); } }
*/ static REBFLG Set_Struct_Var(REBSTU *stu, REBVAL *word, REBVAL *elem, REBVAL *val) /* ***********************************************************************/ { struct Struct_Field *field = NULL; REBCNT i = 0; field = (struct Struct_Field *)SERIES_DATA(stu->fields); for (i = 0; i < SERIES_TAIL(stu->fields); i ++, field ++) { if (VAL_WORD_CANON(word) == VAL_SYM_CANON(BLK_SKIP(PG_Word_Table.series, field->sym))) { if (field->array) { if (elem == NULL) { //set the whole array REBCNT n = 0; if ((!IS_BLOCK(val) || field->dimension != VAL_LEN(val))) { return FALSE; } for(n = 0; n < field->dimension; n ++) { if (!assign_scalar(stu, field, n, VAL_BLK_SKIP(val, n))) { return FALSE; } } } else {// set only one element if (!IS_INTEGER(elem) || VAL_INT32(elem) <= 0 || VAL_INT32(elem) > cast(REBINT, field->dimension)) { return FALSE; } return assign_scalar(stu, field, VAL_INT32(elem) - 1, val); } return TRUE; } else { return assign_scalar(stu, field, 0, val); } return TRUE; } } return FALSE; }
*/ REBCNT Make_Word(REBYTE *str, REBCNT len) /* ** Given a string and its length, compute its hash value, ** search for a match, and if not found, add it to the table. ** Length of zero indicates you provided a zero terminated string. ** Return the table index for the word (whether found or new). ** ***********************************************************************/ { REBINT hash; REBINT size; REBINT skip; REBINT n; REBCNT h; REBCNT *hashes; REBVAL *words; REBVAL *w; //REBYTE *sss = Get_Sym_Name(1); // (Debugging method) if (len == 0) len = LEN_BYTES(str); // If hash part of word table is too dense, expand it: if (PG_Word_Table.series->tail > PG_Word_Table.hashes->tail/2) Expand_Word_Table(); ASSERT((SERIES_TAIL(PG_Word_Table.series) == SERIES_TAIL(Bind_Table)), RP_BIND_TABLE_SIZE); // If word symbol part of word table is full, expand it: if (SERIES_FULL(PG_Word_Table.series)) { Extend_Series(PG_Word_Table.series, 256); } if (SERIES_FULL(Bind_Table)) { Extend_Series(Bind_Table, 256); CLEAR_SERIES(Bind_Table); } size = (REBINT)PG_Word_Table.hashes->tail; words = BLK_HEAD(PG_Word_Table.series); hashes = (REBCNT *)PG_Word_Table.hashes->data; // Hash the word, including a skip factor for lookup: hash = Hash_Word(str, len); skip = (hash & 0x0000FFFF) % size; if (skip == 0) skip = 1; hash = (hash & 0x00FFFF00) % size; //Debug_Fmt("%s hash %d skip %d", str, hash, skip); // Search hash table for word match: while (NZ(h = hashes[hash])) { while ((n = Compare_UTF8(VAL_SYM_NAME(words+h), str, len)) >= 0) { //if (Match_String("script", str, len)) // Debug_Fmt("---- %s %d %d\n", VAL_SYM_NAME(&words[h]), n, h); if (n == 0) return h; // direct hit if (VAL_SYM_ALIAS(words+h)) h = VAL_SYM_ALIAS(words+h); else goto make_sym; // Create new alias for word } hash += skip; if (hash >= size) hash -= size; } make_sym: n = PG_Word_Table.series->tail; w = words + n; if (h) { // Alias word (h = canon word) VAL_SYM_ALIAS(words+h) = n; VAL_SYM_CANON(w) = VAL_SYM_CANON(words+h); } else { // Canon (base version of) word (h == 0) hashes[hash] = n; VAL_SYM_CANON(w) = n; } VAL_SYM_ALIAS(w) = 0; VAL_SYM_NINDEX(w) = Make_Word_Name(str, len); VAL_SET(w, REB_HANDLE); // These are allowed because of the SERIES_FULL checks above which // add one extra to the TAIL check comparision. However, their // termination values (nulls) will be missing. PG_Word_Table.series->tail++; Bind_Table->tail++; return n; }