static bool is_special_global_name(UChar *ptr, long len) { if (len <= 0) { return false; } long pos = 0; switch (ptr[pos]) { case '~': case '*': case '$': case '?': case '!': case '@': case '/': case '\\': case ';': case ',': case '.': case '=': case ':': case '<': case '>': case '\"': case '&': case '`': case '\'': case '+': case '0': pos++; break; case '-': pos++; if (pos < len && is_identchar(ptr[pos])) { pos++; } break; default: if (!isdigit(ptr[pos])) { return false; } do { pos++; } while (pos < len && isdigit(ptr[pos])); break; } return pos == len; }
static mrb_bool is_special_global_name(const char* m) { switch (*m) { case '~': case '*': case '$': case '?': case '!': case '@': case '/': case '\\': case ';': case ',': case '.': case '=': case ':': case '<': case '>': case '\"': case '&': case '`': case '\'': case '+': case '0': ++m; break; case '-': ++m; if (is_identchar(*m)) m += 1; break; default: if (!ISDIGIT(*m)) return FALSE; do ++m; while (ISDIGIT(*m)); break; } return !*m; }
static mrb_bool symname_p(const char *name) { const char *m = name; mrb_bool localid = FALSE; if (!m) return FALSE; switch (*m) { case '\0': return FALSE; case '$': if (is_special_global_name(++m)) return TRUE; goto id; case '@': if (*++m == '@') ++m; goto id; case '<': switch (*++m) { case '<': ++m; break; case '=': if (*++m == '>') ++m; break; default: break; } break; case '>': switch (*++m) { case '>': case '=': ++m; break; default: break; } break; case '=': switch (*++m) { case '~': ++m; break; case '=': if (*++m == '=') ++m; break; default: return FALSE; } break; case '*': if (*++m == '*') ++m; break; case '!': if (*++m == '=') ++m; break; case '+': case '-': if (*++m == '@') ++m; break; case '|': if (*++m == '|') ++m; break; case '&': if (*++m == '&') ++m; break; case '^': case '/': case '%': case '~': case '`': ++m; break; case '[': if (*++m != ']') return FALSE; if (*++m == '=') ++m; break; default: localid = !ISUPPER(*m); id: if (*m != '_' && !ISALPHA(*m)) return FALSE; while (is_identchar(*m)) m += 1; if (localid) { switch (*m) { case '!': case '?': case '=': ++m; default: break; } } break; } return *m ? FALSE : TRUE; }
static ID rb_intern_uchars(const UChar *chars, const size_t chars_len, VALUE str) { const unsigned long name_hash = rb_str_hash_uchars(chars, chars_len); LOCK(); ID id = (ID)CFDictionaryGetValue(sym_id, (const void *)name_hash); UNLOCK(); if (id != 0) { goto return_id; } if (str == Qnil) { str = rb_unicode_str_new(chars, chars_len); } rb_sym_t *sym = NULL; long pos = 0; if (chars_len > 0) { UChar c = chars[0]; switch (c) { case '$': id = ID_GLOBAL; goto new_id; case '@': if (chars_len > 1 && chars[1] == '@') { pos++; id = ID_CLASS; } else { id = ID_INSTANCE; } pos++; break; default: if (chars_len > 1 && chars[chars_len - 1] == '=') { // Attribute assignment. id = rb_intern_str(rb_str_substr(str, 0, chars_len - 1)); if (!is_attrset_id(id)) { id = rb_id_attrset(id); goto id_register; } id = ID_ATTRSET; } else if (iswupper(c)) { id = ID_CONST; } else { id = ID_LOCAL; } break; } } if (pos < chars_len && !isdigit(chars[pos])) { for (; pos < chars_len; pos++) { if (!is_identchar(chars[pos])) { break; } } } if (pos < chars_len) { id = ID_JUNK; } new_id: id |= ++last_id << ID_SCOPE_SHIFT; id_register: //printf("register %s hash %ld id %ld\n", RSTRING_PTR(str), name_hash, id); sym = sym_alloc(str, id); LOCK(); CFDictionarySetValue(sym_id, (const void *)name_hash, (const void *)id); CFDictionarySetValue(id_str, (const void *)id, (const void *)sym); UNLOCK(); return_id: return id; }
static bool sym_should_be_escaped(VALUE sym) { RB_STR_GET_UCHARS(RSYM(sym)->str, chars, chars_len); if (chars_len == 0) { return true; } bool escape = false; for (long i = 0; i < chars_len; i++) { if (!isprint(chars[i])) { escape = true; break; } } if (escape) { goto bail; } long pos = 0; bool localid = false; switch (chars[pos]) { case '\0': escape = true; break; case '$': pos++; if (pos < chars_len && is_special_global_name(&chars[pos], chars_len - pos)) { goto bail; } goto id; case '@': pos++; if (pos < chars_len && chars[pos] == '@') { pos++; } goto id; case '<': pos++; if (pos < chars_len) { if (chars[pos] == '<') { pos++; } else if (chars[pos] == '=') { pos++; if (pos < chars_len && chars[pos] == '>') { pos++; } } } break; case '>': pos++; if (pos < chars_len) { if (chars[pos] == '>' || chars[pos] == '=') { pos++; } } break; case '=': pos++; if (pos == chars_len) { escape = true; goto bail; } else { if (chars[pos] == '~') { pos++; } else if (chars[pos] == '=') { pos++; if (pos < chars_len && chars[pos] == '=') { pos++; } } else { escape = true; goto bail; } } break; case '*': pos++; if (pos < chars_len && chars[pos] == '*') { pos++; } break; case '+': case '-': pos++; if (pos < chars_len && chars[pos] == '@') { pos++; } break; case '|': case '^': case '&': case '/': case '%': case '~': case '`': pos++; break; case '[': pos++; if (pos < chars_len && chars[pos] != ']') { escape = true; goto bail; } pos++; if (pos < chars_len && chars[pos] == '=') { pos++; } break; case '!': pos++; if (pos == chars_len) { goto bail; } else { if (chars[pos] == '=' || chars[pos] == '~') { pos++; } else { escape = true; goto bail; } } break; default: localid = !isupper(chars[pos]); // fall through id: if (pos >= chars_len || (chars[pos] != '_' && !isalpha(chars[pos]) && isascii(chars[pos]))) { escape = true; goto bail; } while (pos < chars_len && is_identchar(chars[pos])) { pos++; } if (localid) { if (pos < chars_len && (chars[pos] == '!' || chars[pos] == '?' || chars[pos] == '=')) { pos++; } } break; } if (pos < chars_len) { escape = true; } bail: return escape; }