123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- #include "config.h"
- #include "markup.h"
- #include "ini.h"
- #include <library/cpp/archive/yarchive.h>
- #include <library/cpp/json/json_reader.h>
- #include <library/cpp/json/json_writer.h>
- #include <library/cpp/lua/eval.h>
- #include <util/string/cast.h>
- #include <util/string/strip.h>
- #include <util/string/type.h>
- #include <util/stream/output.h>
- #include <util/stream/file.h>
- #include <util/memory/blob.h>
- #include <util/generic/singleton.h>
- #include <util/stream/str.h>
- using namespace NConfig;
- using namespace NJson;
- namespace {
- const unsigned char CODE[] = {
- #include "code.inc"
- };
- struct TCode: public TArchiveReader {
- inline TCode()
- : TArchiveReader(TBlob::NoCopy(CODE, sizeof(CODE)))
- {
- }
- static inline TCode& Instance() {
- return *Singleton<TCode>();
- }
- };
- class TPreprocessor: public IInputStream {
- public:
- inline TPreprocessor(const TGlobals& g, IInputStream* in)
- : I_(nullptr, 0)
- , S_(in)
- {
- E_.SetVars(g);
- }
- size_t DoRead(void* ptr, size_t len) override {
- while (true) {
- const size_t read = I_.Read(ptr, len);
- if (read) {
- return read;
- }
- do {
- if (!S_.ReadLine(C_)) {
- return 0;
- }
- } while (IsComment(C_));
- C_ = E_.Preprocess(C_);
- C_.append('\n');
- I_.Reset(C_.data(), C_.size());
- }
- }
- static inline bool IsComment(TStringBuf s) {
- s = StripString(s);
- return !s.empty() && s[0] == '#';
- }
- private:
- TMemoryInput I_;
- TBufferedInput S_;
- TLuaEval E_;
- TString C_;
- };
- }
- void TConfig::DumpJson(IOutputStream& out) const {
- TString tmp;
- {
- TStringOutput out2(tmp);
- ToJson(out2);
- }
- {
- TJsonValue v;
- TStringInput in(tmp);
- ReadJsonTree(&in, &v);
- WriteJson(&out, &v, true, true);
- }
- }
- TConfig TConfig::FromJson(IInputStream& in, const TGlobals& g) {
- class TJSONReader: public TJsonCallbacks {
- public:
- inline TJSONReader()
- : Cur(nullptr)
- {
- }
- inline bool OnBoolean(bool b) override {
- *Next() = ConstructValue(b);
- return true;
- }
- inline bool OnInteger(long long i) override {
- *Next() = ConstructValue((i64)i);
- return true;
- }
- inline bool OnUInteger(unsigned long long i) override {
- *Next() = ConstructValue((ui64)i);
- return true;
- }
- inline bool OnDouble(double d) override {
- *Next() = ConstructValue(d);
- return true;
- }
- inline bool OnString(const TStringBuf& s) override {
- *Next() = ConstructValue(ToString(s));
- return true;
- }
- inline bool OnOpenMap() override {
- Push(ConstructValue(TDict()));
- return true;
- }
- inline bool OnCloseMap() override {
- Pop();
- return true;
- }
- inline bool OnOpenArray() override {
- Push(ConstructValue(TArray()));
- return true;
- }
- inline bool OnCloseArray() override {
- Pop();
- return true;
- }
- inline bool OnMapKey(const TStringBuf& k) override {
- if (S.empty()) {
- ythrow yexception() << "shit happen";
- }
- Cur = &S.back().GetNonConstant<TDict>()[ToString(k)];
- return true;
- }
- inline void Push(const TConfig& el) {
- *Next() = el;
- S.push_back(el);
- }
- inline void Pop() {
- if (S.empty()) {
- ythrow yexception() << "shit happen";
- }
- S.pop_back();
- }
- inline TConfig* Next() {
- if (S.empty()) {
- return &Root;
- }
- TConfig& top = S.back();
- if (top.IsA<TArray>()) {
- TArray& arr = top.GetNonConstant<TArray>();
- arr.emplace_back();
- return &arr.back();
- }
- if (top.IsA<TDict>()) {
- if (Cur) {
- TConfig* ret = Cur;
- Cur = nullptr;
- return ret;
- }
- }
- ythrow yexception() << "shit happen";
- }
- inline void OnError(size_t off, TStringBuf reason) override {
- Y_UNUSED(off);
- if (!FirstErrorReason) {
- FirstErrorReason = reason;
- }
- }
- TConfig Root;
- TConfig* Cur;
- TVector<TConfig> S;
- TString FirstErrorReason;
- };
- TJSONReader r;
- TString data = in.ReadAll();
- TMemoryInput mi(data.data(), data.size());
- TPreprocessor p(g, &mi);
- if (!NJson::ReadJson(&p, false, true, &r)) {
- if (!!r.FirstErrorReason) {
- ythrow TConfigParseError() << "Error parsing json: " << r.FirstErrorReason;
- } else {
- ythrow TConfigParseError() << "Could not parse json " << data.Quote();
- }
- }
- return r.Root;
- }
- namespace {
- struct TData {
- const char* Prologue;
- const char* Epilogue;
- };
- const TData DATA[] = {
- {"", "\nassert(not (instance == nil))\nreturn instance\n"},
- {"", "\nassert(not (main == nil))\nreturn main\n"},
- {"return ", "\n"},
- {"", "\n"},
- };
- }
- TConfig TConfig::FromLua(IInputStream& in, const TGlobals& g) {
- const TString& data = in.ReadAll();
- TString json;
- for (size_t i = 0; i < Y_ARRAY_SIZE(DATA); ++i) {
- TStringStream ss;
- ss << TStringBuf("local function configgen()")
- << DATA[i].Prologue << data << DATA[i].Epilogue
- << TStringBuf("end\n\nreturn require('json').encode(configgen())\n");
- try {
- json = TLuaEval().SetVars(g).EvalRaw(ss.Str());
- break;
- } catch (...) {
- if (i == (Y_ARRAY_SIZE(DATA) - 1)) {
- throw;
- }
- }
- }
- TMemoryInput mi(json.data(), json.size());
- return FromJson(mi);
- }
- TConfig TConfig::FromMarkup(IInputStream& in, const TGlobals& g) {
- TPreprocessor pin(g, &in);
- return ParseRawMarkup(pin);
- }
- TConfig TConfig::FromIni(IInputStream& in, const TGlobals& g) {
- TPreprocessor pin(g, &in);
- return ParseIni(pin);
- }
- void TConfig::DumpLua(IOutputStream& out) const {
- TLuaEval e;
- TStringStream ss;
- ToJson(ss);
- e.SetVariable("jsonval", ss.Str());
- out << "return " << e.EvalRaw(TCode::Instance().ObjectByKey("/pp.lua")->ReadAll() + "\nreturn prettify(require('json').decode(jsonval))\n");
- }
- TConfig TConfig::FromStream(IInputStream& in, const TGlobals& g) {
- const TString& tmp = in.ReadAll();
- TString luaParsingError = "";
- try {
- TMemoryInput mi(tmp.data(), tmp.size());
- return FromLua(mi, g);
- } catch (const yexception& e) {
- luaParsingError = e.AsStrBuf();
- } catch (...) {
- luaParsingError = "unknown error";
- }
- TMemoryInput mi(tmp.data(), tmp.size());
- try {
- return FromJson(mi, g);
- } catch (const yexception& e) {
- const TStringBuf& jsonParsingError = e.AsStrBuf();
- ythrow yexception() << "Could not parse config:\nParsing as lua: " << luaParsingError << "\nParsing as json: " << jsonParsingError;
- }
- }
- TConfig TConfig::ReadJson(TStringBuf in, const TGlobals& g) {
- TMemoryInput mi(in.data(), in.size());
- return FromJson(mi, g);
- }
- TConfig TConfig::ReadLua(TStringBuf in, const TGlobals& g) {
- TMemoryInput mi(in.data(), in.size());
- return FromLua(mi, g);
- }
- TConfig TConfig::ReadMarkup(TStringBuf in, const TGlobals& g) {
- TMemoryInput mi(in.data(), in.size());
- return FromMarkup(mi, g);
- }
- TConfig TConfig::ReadIni(TStringBuf in, const TGlobals& g) {
- TMemoryInput mi(in.data(), in.size());
- return FromIni(mi, g);
- }
- void TConfig::Load(IInputStream* input) {
- TString string;
- ::Load(input, string);
- TStringInput stream(string);
- *this = FromJson(stream);
- }
- void TConfig::Save(IOutputStream* output) const {
- TString result;
- TStringOutput stream(result);
- DumpJson(stream);
- ::Save(output, result);
- }
- bool TConfig::Has(const TStringBuf& key) const {
- return !operator[](key).IsNull();
- }
- const TConfig& TConfig::operator[](const TStringBuf& key) const {
- return Get<TDict>().Find(key);
- }
- const TConfig& TConfig::At(const TStringBuf& key) const {
- return Get<TDict>().At(key);
- }
- const TConfig& TConfig::operator[](size_t index) const {
- return Get<TArray>().Index(index);
- }
- size_t TConfig::GetArraySize() const {
- return Get<TArray>().size();
- }
- const TConfig& TDict::Find(const TStringBuf& key) const {
- const_iterator it = find(key);
- if (it == end()) {
- return Default<TConfig>();
- }
- return it->second;
- }
- const TConfig& TDict::At(const TStringBuf& key) const {
- const_iterator it = find(key);
- Y_ENSURE_BT(it != end(), "missing key '" << key << "'");
- return it->second;
- }
- const TConfig& TArray::Index(size_t index) const {
- if (index < size()) {
- return (*this)[index];
- }
- return Default<TConfig>();
- }
- const TConfig& TArray::At(size_t index) const {
- Y_ENSURE_BT(index < size(), "index " << index << " is out of bounds");
- return (*this)[index];
- }
- THolder<IInputStream> NConfig::CreatePreprocessor(const TGlobals& g, IInputStream& in) {
- return MakeHolder<TPreprocessor>(g, &in);
- }
|