From 45bd2dc5fabc7a458c5a9a1ec8b312533ad3f039 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 17 Apr 2016 12:30:14 +0300 Subject: [PATCH] codegen_style: preparing to parse the whole input file. --- Telegram/Resources/all_files.style | 6 +- .../codegen/common/basic_tokenized_file.cpp | 4 +- .../SourceFiles/codegen/style/generator.cpp | 34 +- .../SourceFiles/codegen/style/generator.h | 21 +- Telegram/SourceFiles/codegen/style/main.cpp | 14 +- .../SourceFiles/codegen/style/options.cpp | 90 ++++++ Telegram/SourceFiles/codegen/style/options.h | 40 +++ .../SourceFiles/codegen/style/parsed_file.cpp | 301 ++++++++++++++++++ .../style/{tokenized_file.h => parsed_file.h} | 99 +++--- .../SourceFiles/codegen/style/structure.h | 87 +++++ .../codegen/style/tokenized_file.cpp | 136 -------- .../vc/codegen_style/codegen_style.vcxproj | 7 +- .../codegen_style.vcxproj.filters | 13 +- 13 files changed, 637 insertions(+), 215 deletions(-) create mode 100644 Telegram/SourceFiles/codegen/style/options.cpp create mode 100644 Telegram/SourceFiles/codegen/style/options.h create mode 100644 Telegram/SourceFiles/codegen/style/parsed_file.cpp rename Telegram/SourceFiles/codegen/style/{tokenized_file.h => parsed_file.h} (57%) create mode 100644 Telegram/SourceFiles/codegen/style/structure.h delete mode 100644 Telegram/SourceFiles/codegen/style/tokenized_file.cpp diff --git a/Telegram/Resources/all_files.style b/Telegram/Resources/all_files.style index 93a8e078e..09d45ede9 100644 --- a/Telegram/Resources/all_files.style +++ b/Telegram/Resources/all_files.style @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ // Legacy styles -using "./style_classes.txt"; -using "./style.txt"; +using "Resources/style_classes.txt"; +using "Resources/style.txt"; -//using "./../SourceFiles/overview/overview.style"; +//using "overview/overview.style"; diff --git a/Telegram/SourceFiles/codegen/common/basic_tokenized_file.cpp b/Telegram/SourceFiles/codegen/common/basic_tokenized_file.cpp index 1619fcc80..4bd5cf02e 100644 --- a/Telegram/SourceFiles/codegen/common/basic_tokenized_file.cpp +++ b/Telegram/SourceFiles/codegen/common/basic_tokenized_file.cpp @@ -148,18 +148,18 @@ Type BasicTokenizedFile::uniteLastTokens(Type type) { } Type BasicTokenizedFile::readNameOrNumber() { - bool onlyDigits = true; while (!reader_.atEnd()) { if (!isDigitChar(reader_.currentChar())) { - onlyDigits = false; break; } reader_.skipChar(); } + bool onlyDigits = true; while (!reader_.atEnd()) { if (!isNameChar(reader_.currentChar())) { break; } + onlyDigits = false; reader_.skipChar(); } return saveToken(onlyDigits ? Type::Int : Type::Name); diff --git a/Telegram/SourceFiles/codegen/style/generator.cpp b/Telegram/SourceFiles/codegen/style/generator.cpp index 70a917d3c..031b1ae3f 100644 --- a/Telegram/SourceFiles/codegen/style/generator.cpp +++ b/Telegram/SourceFiles/codegen/style/generator.cpp @@ -21,10 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "codegen/style/generator.h" #include -#include "codegen/style/tokenized_file.h" - -using Token = codegen::style::TokenizedFile::Token; -using Type = Token::Type; +#include "codegen/style/parsed_file.h" namespace codegen { namespace style { @@ -32,30 +29,35 @@ namespace { } // namespace -Generator::Generator(const QString &filepath, bool rebuildDependencies) -: file_(std::make_unique(filepath)) -, rebuild_(rebuildDependencies) { +Generator::Generator(const Options &options) +: parser_(std::make_unique(options)) +, options_(options) { } int Generator::process() { - if (!file_->read()) { + if (!parser_->read()) { return -1; } - while (true) { - auto token = file_->getToken(); - if (token.type == Type::Using) { - continue; - } - if (file_->atEnd() && !file_->failed()) { - break; - } + const auto &result = parser_->data(); + if (!write(result)) { return -1; } + if (options_.rebuildDependencies) { + for (auto included : result.includes) { + if (!write(included)) { + return -1; + } + } + } return 0; } +bool Generator::write(const structure::Module &) const { + return true; +} + Generator::~Generator() = default; } // namespace style diff --git a/Telegram/SourceFiles/codegen/style/generator.h b/Telegram/SourceFiles/codegen/style/generator.h index 57e922267..dbb9601f6 100644 --- a/Telegram/SourceFiles/codegen/style/generator.h +++ b/Telegram/SourceFiles/codegen/style/generator.h @@ -22,16 +22,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include #include +#include + +#include "codegen/style/options.h" namespace codegen { namespace style { - -class TokenizedFile; +namespace structure { +struct Module; +} // namespace structure +class ParsedFile; // Walks through a file, parses it and parses dependency files if necessary. class Generator { public: - Generator(const QString &filepath, bool rebuildDependencies); + Generator(const Options &options); Generator(const Generator &other) = delete; Generator &operator=(const Generator &other) = delete; @@ -41,8 +46,14 @@ public: ~Generator(); private: - std::unique_ptr file_; - bool rebuild_; + bool write(const structure::Module &module) const; + + std::unique_ptr parser_; + const Options &options_; + + // List of files we need to generate with other instance of Generator. + // It is not empty only if rebuild_ flag is true. + QStringList dependenciesToGenerate_; }; diff --git a/Telegram/SourceFiles/codegen/style/main.cpp b/Telegram/SourceFiles/codegen/style/main.cpp index 951f34b32..b61d9ce11 100644 --- a/Telegram/SourceFiles/codegen/style/main.cpp +++ b/Telegram/SourceFiles/codegen/style/main.cpp @@ -22,22 +22,18 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include #include "codegen/style/generator.h" +#include "codegen/style/options.h" using namespace codegen::style; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); - QString filepath; - bool rebuildOtherFiles = false; - for (const auto &arg : app.arguments()) { - if (arg == "--rebuild") { - rebuildOtherFiles = true; - } else { - filepath = arg; - } + Options options = parseOptions(); + if (options.inputPath.isEmpty()) { + return -1; } - Generator generator(filepath, rebuildOtherFiles); + Generator generator(options); return generator.process(); } diff --git a/Telegram/SourceFiles/codegen/style/options.cpp b/Telegram/SourceFiles/codegen/style/options.cpp new file mode 100644 index 000000000..a7d880e17 --- /dev/null +++ b/Telegram/SourceFiles/codegen/style/options.cpp @@ -0,0 +1,90 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "codegen/style/options.h" + +#include +#include +#include "codegen/common/logging.h" + +namespace codegen { +namespace style { +namespace { + +constexpr int kErrorIncludePathExpected = 901; +constexpr int kErrorOutputPathExpected = 902; +constexpr int kErrorInputPathExpected = 903; +constexpr int kErrorSingleInputPathExpected = 904; + +} // namespace + +using common::logError; + +Options parseOptions() { + Options result; + auto args(QCoreApplication::instance()->arguments()); + for (auto i = args.cbegin(), e = args.cend(); i != e; ++i) { + const auto &arg(*i); + + // Rebuild all dependencies + if (arg == "--rebuild") { + result.rebuildDependencies = true; + + // Include paths + } else if (arg == "-I") { + if (++i == e) { + logError(kErrorIncludePathExpected, "Command Line") << "include path expected after -I"; + return Options(); + } else { + result.includePaths.push_back(*i); + } + } else if (arg.startsWith("-I")) { + result.includePaths.push_back(arg.mid(2)); + + // Output path + } else if (arg == "-o") { + if (++i == e) { + logError(kErrorOutputPathExpected, "Command Line") << "output path expected after -o"; + return Options(); + } else { + result.outputPath = *i; + } + } else if (arg.startsWith("-o")) { + result.outputPath = arg.mid(2); + + // Input path + } else { + if (result.inputPath.isEmpty()) { + result.inputPath = arg; + } else { + logError(kErrorSingleInputPathExpected, "Command Line") << "only one input path expected"; + return Options(); + } + } + } + if (result.inputPath.isEmpty()) { + logError(kErrorInputPathExpected, "Command Line") << "input path expected"; + return Options(); + } + return result; +} + +} // namespace style +} // namespace codegen diff --git a/Telegram/SourceFiles/codegen/style/options.h b/Telegram/SourceFiles/codegen/style/options.h new file mode 100644 index 000000000..34746ee2d --- /dev/null +++ b/Telegram/SourceFiles/codegen/style/options.h @@ -0,0 +1,40 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include +#include + +namespace codegen { +namespace style { + +struct Options { + QStringList includePaths = { "." }; + QString outputPath = "."; + QString inputPath; + bool rebuildDependencies = false; +}; + +// Parsing failed if inputPath is empty in the result. +Options parseOptions(); + +} // namespace style +} // namespace codegen diff --git a/Telegram/SourceFiles/codegen/style/parsed_file.cpp b/Telegram/SourceFiles/codegen/style/parsed_file.cpp new file mode 100644 index 000000000..4ca4aa701 --- /dev/null +++ b/Telegram/SourceFiles/codegen/style/parsed_file.cpp @@ -0,0 +1,301 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "codegen/style/parsed_file.h" + +#include +#include +#include +#include "codegen/common/basic_tokenized_file.h" +#include "codegen/common/logging.h" + +using Token = codegen::style::ParsedFile::Token; +using Type = Token::Type; +using BasicToken = codegen::common::BasicTokenizedFile::Token; +using BasicType = BasicToken::Type; + +namespace codegen { +namespace style { +namespace { + +QString plainValue(const BasicToken &token) { + return token.original.toStringUnchecked(); +} + +Token invalidToken() { + return { Type::Invalid, QString() }; +} + +} // namespace + +ParsedFile::ParsedFile(const Options &options) +: file_(options.inputPath) +, options_(options) { +} + +bool ParsedFile::read() { + if (!file_.read()) { + return false; + } + + for (auto token = readInDefault(); token; token = readInDefault()) { + if (token.type == Type::Using) { + auto includedOptions = options_; +// includedOptions.inputPath = findIncludePath(token.value); + ParsedFile included(includedOptions); + if (!included.read()) { + return false; + } + result_.includes.push_back(included.data()); + //} else if (token.type == Type::DefineStructStart) { + // if (!read) + } + } + return !failed(); +} + +Token ParsedFile::readToken() { + switch (state_) { + case State::Default: return readInDefault(); + case State::StructStarted: return readInStructStarted(); + case State::StructFieldName: return readInStructFieldName(); + case State::Variable: return readInVariable(); + case State::VariableParents: return readInVariableParents(); + case State::VariableStarted: return readInVariableStarted(); + case State::VariableChild: return readInVariableChild(); + } + return invalidToken(); +} + +Token ParsedFile::readInDefault() { + if (auto startToken = file_.getToken(BasicType::Name)) { + if (plainValue(startToken) == "using") { + if (auto usingFile = file_.getToken(BasicType::String)) { + if (file_.getToken(BasicType::Semicolon)) { + return { Type::Using, usingFile.value }; + } + logErrorUnexpectedToken("';'"); + } else { + logErrorUnexpectedToken("file path"); + } + return invalidToken(); + } else if (auto braceOpen = file_.getToken(BasicType::LeftBrace)) { + state_ = State::StructStarted; + return { Type::DefineStructStart, plainValue(startToken) }; + } else if (auto colonToken = file_.getToken(BasicType::Colon)) { + state_ = State::Variable; + return { Type::DefineVariable, plainValue(startToken) }; + } + } + if (!file_.atEnd()) { + logErrorUnexpectedToken("using keyword, or struct definition, or variable definition"); + } + return invalidToken(); +} + +Token ParsedFile::readInStructStarted() { + if (auto fieldName = file_.getToken(BasicType::Name)) { + state_ = State::StructFieldName; + return { Type::DefineStructField, plainValue(fieldName) }; + } else if (auto braceClose = file_.getToken(BasicType::RightBrace)) { + state_ = State::Default; + return { Type::DefineStructEnd }; + } + logErrorUnexpectedToken("struct field name or '}'"); + return invalidToken(); +} + +Token ParsedFile::readInStructFieldName() { + if (auto colonToken = file_.getToken(BasicType::Colon)) { + if (auto fieldType = file_.getToken(BasicType::Name)) { + if (file_.getToken(BasicType::Semicolon)) { + state_ = State::StructStarted; + return { Type::StructFieldType, plainValue(fieldType) }; + } + logErrorUnexpectedToken(";"); + } else { + logErrorUnexpectedToken("struct field type name"); + } + } else { + logErrorUnexpectedToken("':'"); + } + return invalidToken(); +} + +Token ParsedFile::readInVariable() { + if (auto value = readValueToken()) { + if (file_.getToken(BasicType::Semicolon)) { + state_ = State::Default; + return value; + } + logErrorUnexpectedToken(";"); + return invalidToken(); + } + if (failed()) { + return invalidToken(); + } + + if (auto structName = file_.getToken(BasicType::Name)) { + if (file_.getToken(BasicType::LeftParenthesis)) { + state_ = State::VariableParents; + return { Type::StructStart, plainValue(structName) }; + } else if (file_.getToken(BasicType::LeftBrace)) { + state_ = State::VariableStarted; + return { Type::StructStart, plainValue(structName) }; + } else { + logErrorUnexpectedToken("'(' or '{'"); + } + } else { + logErrorUnexpectedToken("variable value"); + } + return invalidToken(); +} + +Token ParsedFile::readInVariableParents() { + if (auto parentName = file_.getToken(BasicType::Name)) { + if (file_.getToken(BasicType::Comma)) { + return { Type::StructParent, plainValue(parentName) }; + } else if (file_.getToken(BasicType::RightParenthesis)) { + if (file_.getToken(BasicType::LeftBrace)) { + state_ = State::VariableStarted; + return { Type::StructParent, plainValue(parentName) }; + } + logErrorUnexpectedToken("'{'"); + } else { + logErrorUnexpectedToken("',' or ')'"); + } + } else { + logErrorUnexpectedToken("struct variable parent"); + } + return invalidToken(); +} + +Token ParsedFile::readInVariableStarted() { + if (auto fieldName = file_.getToken(BasicType::Name)) { + state_ = State::VariableChild; + return { Type::VariableField, plainValue(fieldName) }; + } else if (auto braceClose = file_.getToken(BasicType::RightBrace)) { + state_ = State::Default; + return { Type::StructEnd }; + } + logErrorUnexpectedToken("struct variable field name or '}'"); + return invalidToken(); +} + +Token ParsedFile::readInVariableChild() { + if (auto value = readValueToken()) { + if (file_.getToken(BasicType::Semicolon)) { + state_ = State::Default; + return value; + } + logErrorUnexpectedToken(";"); + } else { + logErrorUnexpectedToken("variable field value"); + } + return invalidToken(); +} + +Token ParsedFile::readNumericToken() { + auto numericToken = file_.getAnyToken(); + if (numericToken.type == BasicType::Int) { + return { Type::Int, plainValue(numericToken) }; + } else if (numericToken.type == BasicType::Double) { + return { Type::Double, plainValue(numericToken) }; + } else if (numericToken.type == BasicType::Name) { + auto value = plainValue(numericToken); + auto match = QRegularExpression("^\\d+px$").match(value); + if (match.hasMatch()) { + return { Type::Pixels, value.mid(0, value.size() - 2) }; + } + } + file_.putBack(); + return invalidToken(); +} + +Token ParsedFile::readValueToken() { + if (auto colorValue = readColorToken()) { + return colorValue; + } else if (auto pointValue = readPointToken()) { + return pointValue; + } else if (auto spriteValue = readSpriteToken()) { + return spriteValue; + } else if (auto sizeValue = readSizeToken()) { + return sizeValue; + } else if (auto transitionValue = readTransitionToken()) { + return transitionValue; + } else if (auto cursorValue = readCursorToken()) { + return cursorValue; + } else if (auto alignValue = readAlignToken()) { + return alignValue; + } else if (auto marginsValue = readMarginsToken()) { + return marginsValue; + } else if (auto fontValue = readFontToken()) { + return fontValue; + } else if (auto numericValue = readNumericToken()) { + return numericValue; + } else if (auto stringValue = file_.getToken(BasicType::String)) { + return { Type::String, stringValue.value }; + } else if (auto minusToken = file_.getToken(BasicType::Minus)) { + if (auto positiveValue = readNumericToken()) { + return { positiveValue.type, '-' + positiveValue.value }; + } + logErrorUnexpectedToken("numeric value"); + } + return invalidToken(); +} + +Token ParsedFile::readColorToken() { + return invalidToken(); +} + +Token ParsedFile::readPointToken() { + return invalidToken(); +} + +Token ParsedFile::readSpriteToken() { + return invalidToken(); +} + +Token ParsedFile::readSizeToken() { + return invalidToken(); +} + +Token ParsedFile::readTransitionToken() { + return invalidToken(); +} + +Token ParsedFile::readCursorToken() { + return invalidToken(); +} + +Token ParsedFile::readAlignToken() { + return invalidToken(); +} + +Token ParsedFile::readMarginsToken() { + return invalidToken(); +} + +Token ParsedFile::readFontToken() { + return invalidToken(); +} + +} // namespace style +} // namespace codegen diff --git a/Telegram/SourceFiles/codegen/style/tokenized_file.h b/Telegram/SourceFiles/codegen/style/parsed_file.h similarity index 57% rename from Telegram/SourceFiles/codegen/style/tokenized_file.h rename to Telegram/SourceFiles/codegen/style/parsed_file.h index 5e4ac2afc..9d65f464b 100644 --- a/Telegram/SourceFiles/codegen/style/tokenized_file.h +++ b/Telegram/SourceFiles/codegen/style/parsed_file.h @@ -24,31 +24,35 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include #include #include "codegen/common/basic_tokenized_file.h" +#include "codegen/style/options.h" +#include "codegen/style/structure.h" namespace codegen { namespace style { -// Parses a file as a list of tokens. -class TokenizedFile { +// Parses an input file to the internal struct. +class ParsedFile { public: - TokenizedFile(const QString &filepath); - TokenizedFile(const TokenizedFile &other) = delete; - TokenizedFile &operator=(const TokenizedFile &other) = delete; + ParsedFile(const Options &options); + ParsedFile(const ParsedFile &other) = delete; + ParsedFile &operator=(const ParsedFile &other) = delete; - using ConstUtf8String = common::ConstUtf8String; struct Token { enum class Type { Invalid, - Using, + Using, // value: file path - DefineStruct, - DefineField, - FieldType, + DefineStructStart, // value: struct name + DefineStructField, // value: struct field name + StructFieldType, // value: struct field type name + DefineStructEnd, - DefineVariable, - Struct, - StructParent, + DefineVariable, // value: variable name + StructStart, // value: struct name + StructParent, // value: variable parent name + VariableField, // value: variable field name + StructEnd, Int, Double, @@ -72,27 +76,29 @@ public: } }; - bool read() { - return file_.read(); - } - bool atEnd() const { - return file_.atEnd(); - } + bool read(); - Token getToken(); - bool putBack(); - bool failed() const { - return file_.failed(); - } - - // Log error to std::cerr with 'code' at the current position in file. - common::LogStream logError(int code) const { - return file_.logError(code); + const structure::Module &data() const { + return result_; } private: - using Type = Token::Type; - Type readToken(); + + bool failed() const { + return failed_ || file_.failed(); + } + + // Log error to std::cerr with 'code' at the current position in file. + common::LogStream logError(int code) { + failed_ = true; + return file_.logError(code); + } + common::LogStream logErrorUnexpectedToken(const std::string &expected = std::string()) { + failed_ = true; + return file_.logErrorUnexpectedToken(expected); + } + + Token readToken(); // State value defines what are we waiting next. enum class State { @@ -106,21 +112,34 @@ private: }; // Helper methods for readToken() being in specific State. - Type readInDefault(); - Type readInStructStarted(); - Type readInStructFieldName(); - Type readInVariable(); - Type readInVariableParents(); - Type readInVariableStarted(); - Type readInVariableChild(); + Token readInDefault(); + Token readInStructStarted(); + Token readInStructFieldName(); + Token readInVariable(); + Token readInVariableParents(); + Token readInVariableStarted(); + Token readInVariableChild(); - Type saveToken(Type type, const QString &value = QString()); + Token readNumericToken(); + Token readValueToken(); + Token readColorToken(); + Token readPointToken(); + Token readSpriteToken(); + Token readSizeToken(); + Token readTransitionToken(); + Token readCursorToken(); + Token readAlignToken(); + Token readMarginsToken(); + Token readFontToken(); common::BasicTokenizedFile file_; - QList tokens_; - int currentToken_ = 0; + Options options_; + + bool failed_ = false; State state_ = State::Default; + structure::Module result_; + }; } // namespace style diff --git a/Telegram/SourceFiles/codegen/style/structure.h b/Telegram/SourceFiles/codegen/style/structure.h new file mode 100644 index 000000000..cde1813e8 --- /dev/null +++ b/Telegram/SourceFiles/codegen/style/structure.h @@ -0,0 +1,87 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include +#include +#include + +namespace codegen { +namespace style { +namespace structure { + +// List of names, like overview.document.bg +using FullName = QStringList; + +enum class TypeTag { + Int, + Double, + Pixels, + String, + Color, + Point, + Sprite, + Size, + Transition, + Cursor, + Align, + Margins, + Font, + Struct, +}; + +struct Type { + TypeTag tag; + FullName name; // only for type == ClassType::Struct +}; + +struct Variable; +struct Value { + QString data; // for plain types + QList fields; // for struct types +}; + +struct Variable { + FullName name; + Type type; + Value value; +}; + +struct StructField { + FullName name; + Type type; +}; + +struct Struct { + FullName name; + QList fields; +}; + +struct Module { + QString fullpath; + QList includes; + QList structs; + QList variables; +}; + +} // namespace structure +} // namespace style +} // namespace codegen diff --git a/Telegram/SourceFiles/codegen/style/tokenized_file.cpp b/Telegram/SourceFiles/codegen/style/tokenized_file.cpp deleted file mode 100644 index 784848e85..000000000 --- a/Telegram/SourceFiles/codegen/style/tokenized_file.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop version of Telegram messaging app, see https://telegram.org - -Telegram Desktop is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -It is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -In addition, as a special exception, the copyright holders give permission -to link the code of portions of this program with the OpenSSL library. - -Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE -Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org -*/ -#include "codegen/style/tokenized_file.h" - -#include -#include - -#include "codegen/common/basic_tokenized_file.h" -#include "codegen/common/logging.h" - -using Token = codegen::style::TokenizedFile::Token; -using Type = Token::Type; -using BasicToken = codegen::common::BasicTokenizedFile::Token; -using BasicType = BasicToken::Type; - -namespace codegen { -namespace style { -namespace { - -QString plainValue(const BasicToken &token) { - return token.original.toStringUnchecked(); -} - -Token invalidToken() { - return { Type::Invalid, QString() }; -} - -} // namespace - -TokenizedFile::TokenizedFile(const QString &filepath) : file_(filepath) { -} - -bool TokenizedFile::putBack() { - if (currentToken_ > 0) { - --currentToken_; - return true; - } - return false; -} - -Token TokenizedFile::getToken() { - if (currentToken_ >= tokens_.size()) { - if (readToken() == Type::Invalid) { - return invalidToken(); - } - } - return tokens_.at(currentToken_++); -} - -Type TokenizedFile::readToken() { - switch (state_) { - case State::Default: return readInDefault(); - case State::StructStarted: return readInStructStarted(); - case State::StructFieldName: return readInStructFieldName(); - case State::Variable: return readInVariable(); - case State::VariableParents: return readInVariableParents(); - case State::VariableStarted: return readInVariableStarted(); - case State::VariableChild: return readInVariableChild(); - } - return Type::Invalid; -} - -Type TokenizedFile::readInDefault() { - if (auto basicToken = file_.getToken(BasicType::Name)) { - if (plainValue(basicToken) == "using") { - if (auto usingFile = file_.getToken(BasicType::String)) { - if (file_.getToken(BasicType::Semicolon)) { - return saveToken(Type::Using, usingFile.value); - } - file_.logErrorUnexpectedToken("';'"); - } else { - file_.logErrorUnexpectedToken("file path"); - } - return Type::Invalid; - } - if (auto braceToken = file_.getToken(BasicType::LeftBrace)) { - state_ = State::StructStarted; - return saveToken(Type::DefineStruct, plainValue(basicToken)); - } else if (auto colonToken = file_.getToken(BasicType::Colon)) { - state_ = State::Variable; - return saveToken(Type::DefineVariable, plainValue(basicToken)); - } - file_.logErrorUnexpectedToken("using keyword, or struct definition, or variable definition"); - } - return Type::Invalid; -} - -Type TokenizedFile::readInStructStarted() { - return Type::Invalid; -} - -Type TokenizedFile::readInStructFieldName() { - return Type::Invalid; -} - -Type TokenizedFile::readInVariable() { - return Type::Invalid; -} - -Type TokenizedFile::readInVariableParents() { - return Type::Invalid; -} - -Type TokenizedFile::readInVariableStarted() { - return Type::Invalid; -} - -Type TokenizedFile::readInVariableChild() { - return Type::Invalid; -} - -Type TokenizedFile::saveToken(Type type, const QString &value) { - tokens_.push_back({ type, value }); - return type; -} - -} // namespace style -} // namespace codegen diff --git a/Telegram/build/vc/codegen_style/codegen_style.vcxproj b/Telegram/build/vc/codegen_style/codegen_style.vcxproj index d39bf6a24..967ae2811 100644 --- a/Telegram/build/vc/codegen_style/codegen_style.vcxproj +++ b/Telegram/build/vc/codegen_style/codegen_style.vcxproj @@ -16,7 +16,8 @@ - + + @@ -27,7 +28,9 @@ - + + + {E4DF8176-4DEF-4859-962F-B497E3E7A323} diff --git a/Telegram/build/vc/codegen_style/codegen_style.vcxproj.filters b/Telegram/build/vc/codegen_style/codegen_style.vcxproj.filters index 560b5962e..9c64d8737 100644 --- a/Telegram/build/vc/codegen_style/codegen_style.vcxproj.filters +++ b/Telegram/build/vc/codegen_style/codegen_style.vcxproj.filters @@ -31,7 +31,10 @@ src\common - + + src\style + + src\style @@ -57,7 +60,13 @@ src\common - + + src\style + + + src\style + + src\style