aboutsummaryrefslogtreecommitdiffstats
path: root/src/symtab.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/symtab.cc')
-rw-r--r--src/symtab.cc190
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);
+}