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 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; }