Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

222 lines (179 sloc) 5.8 kB
#include "vm/symboltable.hpp"
#include "vm/exception.hpp"
#include "configuration.hpp"
#include "builtin/array.hpp"
#include "builtin/exception.hpp"
#include "builtin/string.hpp"
#include "builtin/symbol.hpp"
#include <iostream>
#include <iomanip>
namespace rubinius {
SymbolTable::Kind SymbolTable::detect_kind(const char* str, int size) {
const char one = str[0];
// A constant begins with an uppercase letter.
if(one >= 'A' && one <= 'Z') {
// Make sure that the rest of it is only alphanumerics
for(int i = 1; i < size; i++) {
if((isalnum(str[i]) || str[i] == '_') == false)
return SymbolTable::Normal;
}
return SymbolTable::Constant;
}
if(one == '@') {
// A class variable begins with @@
if(size > 1 && str[1] == '@') {
return SymbolTable::CVar;
}
// An instance variable begins with @
return SymbolTable::IVar;
}
// A system variable begins with __
if(size > 2 && one == '_' && str[1] == '_') {
return SymbolTable::System;
}
// Everything else is normal
return SymbolTable::Normal;
}
SymbolTable::Kind SymbolTable::kind(STATE, const Symbol* sym) {
return kinds[sym->index()];
}
size_t SymbolTable::add(std::string str) {
bytes_used_ += (str.size() + sizeof(str));
strings.push_back(str);
kinds.push_back(detect_kind(str.data(), str.size()));
return strings.size() - 1;
}
Symbol* SymbolTable::lookup(STATE, const char* str, size_t length) {
if(length == 0 && LANGUAGE_18_ENABLED(state)) {
Exception::argument_error(state, "Cannot create a symbol from an empty string");
return NULL;
}
return lookup(str, length);
}
struct SpecialOperator {
const char* name;
const char* symbol;
};
// These are a set of special operators that MRI
// changes the symbol value of.
static SpecialOperator SpecialOperators[] = {
{"+(binary)", "+"},
{"-(binary)", "-"},
{"+(unary)", "+@"},
{"-(unary)", "-@"},
{"!(unary)", "!"},
{"~(unary)", "~"},
{"!@", "!"},
{"~@", "~"}
};
const static int cNumSpecialOperators = 8;
static const char* find_special(const char* check, size_t length) {
for(int i = 0; i < cNumSpecialOperators; i++) {
SpecialOperator* op = &SpecialOperators[i];
if(*op->name == *check && strncmp(op->name, check, length) == 0) {
return op->symbol;
}
}
return 0;
}
Symbol* SymbolTable::lookup(std::string str) {
return lookup(str.data(), str.size());
}
Symbol* SymbolTable::lookup(STATE, std::string str) {
return lookup(str.data(), str.size());
}
Symbol* SymbolTable::lookup(const char* str, size_t length) {
size_t sym;
if(const char* op = find_special(str, length)) {
str = op;
length = strlen(str);
}
hashval hash = String::hash_str((unsigned char*)str, length);
// Symbols can be looked up by multiple threads at the same time.
// This is fast operation, so we protect this with a spinlock.
{
thread::SpinLock::LockGuard guard(lock_);
SymbolMap::iterator entry = symbols.find(hash);
if(entry == symbols.end()) {
sym = add(std::string(str, length));
SymbolIds v(1, sym);
symbols[hash] = v;
} else {
SymbolIds& v = entry->second;
for(SymbolIds::iterator i = v.begin(); i != v.end(); ++i) {
std::string& s = strings[*i];
if(!strncmp(s.data(), str, length)) return Symbol::from_index(*i);
}
sym = add(std::string(str, length));
v.push_back(sym);
}
}
return Symbol::from_index(sym);
}
Symbol* SymbolTable::lookup(STATE, String* str) {
if(str->nil_p()) {
Exception::argument_error(state, "Cannot look up Symbol from nil");
return NULL;
}
const char* bytes = str->c_str(state);
size_t size = str->size();
if(LANGUAGE_18_ENABLED(state)) {
for(size_t i = 0; i < size; i++) {
if(bytes[i] == 0) {
Exception::argument_error(state,
"cannot create a symbol from a string containing `\\0'");
return NULL;
}
}
}
return lookup(state, bytes, size);
}
String* SymbolTable::lookup_string(STATE, const Symbol* sym) {
if(sym->nil_p()) {
Exception::argument_error(state, "Cannot look up Symbol from nil");
return NULL;
}
std::string& str = strings[sym->index()];
return String::create(state, str.data(), str.size());
}
std::string& SymbolTable::lookup_cppstring(const Symbol* sym) {
return strings[sym->index()];
}
std::string SymbolTable::lookup_debug_string(const Symbol* sym) {
std::string str = lookup_cppstring(sym);
std::ostringstream os;
unsigned char* cstr = (unsigned char*) str.data();
size_t size = str.size();
for(size_t i = 0; i < size; ++i) {
if(isprint(cstr[i])) {
os << cstr[i];
} else {
os << "\\x" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)cstr[i];
}
}
return os.str();
}
size_t SymbolTable::size() {
return strings.size();
}
int SymbolTable::byte_size() {
int total = 0;
for(SymbolStrings::iterator i = strings.begin();
i != strings.end();
++i) {
total += i->size();
total += sizeof(std::string);
}
return total;
}
Array* SymbolTable::all_as_array(STATE) {
size_t idx = 0;
Array* ary = Array::create(state, this->size());
for(SymbolMap::iterator s = symbols.begin(); s != symbols.end(); ++s) {
for(SymbolIds::iterator i = s->second.begin(); i != s->second.end(); ++i) {
ary->set(state, idx++, (Object*)Symbol::from_index(state, *i));
}
}
return ary;
}
}
Jump to Line
Something went wrong with that request. Please try again.