diff options
Diffstat (limited to 'src/symtab.cc')
| -rw-r--r-- | src/symtab.cc | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/symtab.cc b/src/symtab.cc new file mode 100644 index 0000000..3d49f2e --- /dev/null +++ b/src/symtab.cc @@ -0,0 +1,190 @@ +// Copyright 2015 Google Inc. All rights reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build ignore + +//#define ENABLE_TID_CHECK + +#include "symtab.h" + +#ifdef ENABLE_TID_CHECK +#include <pthread.h> +#endif +#include <string.h> + +#include <unordered_map> + +#include "log.h" +#include "strutil.h" +#include "var.h" + +struct SymbolData { + SymbolData() : gv(Var::Undefined()) {} + + Var* gv; +}; + +vector<string*>* g_symbols; +static vector<SymbolData> g_symbol_data; + +Symbol kEmptySym; +Symbol kShellSym; +Symbol kKatiReadonlySym; + +Symbol::Symbol(int v) : v_(v) {} + +Var* Symbol::PeekGlobalVar() const { + if (static_cast<size_t>(v_) >= g_symbol_data.size()) { + return Var::Undefined(); + } + return g_symbol_data[v_].gv; +} + +Var* Symbol::GetGlobalVar() const { + if (static_cast<size_t>(v_) >= g_symbol_data.size()) { + g_symbol_data.resize(v_ + 1); + } + Var* v = g_symbol_data[v_].gv; + if (v->Origin() == VarOrigin::ENVIRONMENT || + v->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE) { + Vars::add_used_env_vars(*this); + } + return v; +} + +void Symbol::SetGlobalVar(Var* v, bool is_override, bool* readonly) const { + if (static_cast<size_t>(v_) >= g_symbol_data.size()) { + g_symbol_data.resize(v_ + 1); + } + Var* orig = g_symbol_data[v_].gv; + if (orig->ReadOnly()) { + if (readonly != nullptr) + *readonly = true; + else + ERROR("*** cannot assign to readonly variable: %s", c_str()); + return; + } else if (readonly != nullptr) { + *readonly = false; + } + if (!is_override && (orig->Origin() == VarOrigin::OVERRIDE || + orig->Origin() == VarOrigin::ENVIRONMENT_OVERRIDE)) { + return; + } + if (orig->Origin() == VarOrigin::COMMAND_LINE && + v->Origin() == VarOrigin::FILE) { + return; + } + if (orig->Origin() == VarOrigin::AUTOMATIC) { + ERROR("overriding automatic variable is not implemented yet"); + } + if (orig->IsDefined()) + delete orig; + g_symbol_data[v_].gv = v; +} + +ScopedGlobalVar::ScopedGlobalVar(Symbol name, Var* var) + : name_(name), orig_(NULL) { + orig_ = name.GetGlobalVar(); + g_symbol_data[name_.val()].gv = var; +} + +ScopedGlobalVar::~ScopedGlobalVar() { + g_symbol_data[name_.val()].gv = orig_; +} + +class Symtab { + public: + Symtab() { +#ifdef ENABLE_TID_CHECK + tid_ = pthread_self(); +#endif + + CHECK(g_symbols == NULL); + g_symbols = &symbols_; + + Symbol s = InternImpl(""); + CHECK(s.v_ == 0); + CHECK(Intern("") == s); + char b[2]; + b[1] = 0; + for (int i = 1; i < 256; i++) { + b[0] = i; + s = InternImpl(b); + CHECK(s.val() == i); + } + + kEmptySym = Intern(""); + kShellSym = Intern("SHELL"); + kKatiReadonlySym = Intern(".KATI_READONLY"); + } + + ~Symtab() { + LOG_STAT("%zu symbols", symbols_.size()); + for (string* s : symbols_) + delete s; + } + + Symbol InternImpl(StringPiece s) { + auto found = symtab_.find(s); + if (found != symtab_.end()) { + return found->second; + } + symbols_.push_back(new string(s.data(), s.size())); + Symbol sym = Symbol(symtab_.size()); + bool ok = symtab_.emplace(*symbols_.back(), sym).second; + CHECK(ok); + return sym; + } + + Symbol Intern(StringPiece s) { +#ifdef ENABLE_TID_CHECK + if (tid_ != pthread_self()) + abort(); +#endif + + if (s.size() <= 1) { + return Symbol(s.empty() ? 0 : (unsigned char)s[0]); + } + return InternImpl(s); + } + + private: + unordered_map<StringPiece, Symbol> symtab_; + vector<string*> symbols_; +#ifdef ENABLE_TID_CHECK + pthread_t tid_; +#endif +}; + +static Symtab* g_symtab; + +void InitSymtab() { + g_symtab = new Symtab; +} + +void QuitSymtab() { + delete g_symtab; +} + +Symbol Intern(StringPiece s) { + return g_symtab->Intern(s); +} + +string JoinSymbols(const vector<Symbol>& syms, const char* sep) { + vector<string> strs; + for (Symbol s : syms) { + strs.push_back(s.str()); + } + return JoinStrings(strs, sep); +} |
