mirror of https://github.com/procxx/kepka.git
codegen_style: preparing to parse the whole input file.
This commit is contained in:
parent
19f9b56d2c
commit
45bd2dc5fa
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Legacy styles
|
// Legacy styles
|
||||||
using "./style_classes.txt";
|
using "Resources/style_classes.txt";
|
||||||
using "./style.txt";
|
using "Resources/style.txt";
|
||||||
|
|
||||||
//using "./../SourceFiles/overview/overview.style";
|
//using "overview/overview.style";
|
||||||
|
|
|
@ -148,18 +148,18 @@ Type BasicTokenizedFile::uniteLastTokens(Type type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Type BasicTokenizedFile::readNameOrNumber() {
|
Type BasicTokenizedFile::readNameOrNumber() {
|
||||||
bool onlyDigits = true;
|
|
||||||
while (!reader_.atEnd()) {
|
while (!reader_.atEnd()) {
|
||||||
if (!isDigitChar(reader_.currentChar())) {
|
if (!isDigitChar(reader_.currentChar())) {
|
||||||
onlyDigits = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reader_.skipChar();
|
reader_.skipChar();
|
||||||
}
|
}
|
||||||
|
bool onlyDigits = true;
|
||||||
while (!reader_.atEnd()) {
|
while (!reader_.atEnd()) {
|
||||||
if (!isNameChar(reader_.currentChar())) {
|
if (!isNameChar(reader_.currentChar())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
onlyDigits = false;
|
||||||
reader_.skipChar();
|
reader_.skipChar();
|
||||||
}
|
}
|
||||||
return saveToken(onlyDigits ? Type::Int : Type::Name);
|
return saveToken(onlyDigits ? Type::Int : Type::Name);
|
||||||
|
|
|
@ -21,10 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "codegen/style/generator.h"
|
#include "codegen/style/generator.h"
|
||||||
|
|
||||||
#include <QtGui/QImage>
|
#include <QtGui/QImage>
|
||||||
#include "codegen/style/tokenized_file.h"
|
#include "codegen/style/parsed_file.h"
|
||||||
|
|
||||||
using Token = codegen::style::TokenizedFile::Token;
|
|
||||||
using Type = Token::Type;
|
|
||||||
|
|
||||||
namespace codegen {
|
namespace codegen {
|
||||||
namespace style {
|
namespace style {
|
||||||
|
@ -32,30 +29,35 @@ namespace {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Generator::Generator(const QString &filepath, bool rebuildDependencies)
|
Generator::Generator(const Options &options)
|
||||||
: file_(std::make_unique<TokenizedFile>(filepath))
|
: parser_(std::make_unique<ParsedFile>(options))
|
||||||
, rebuild_(rebuildDependencies) {
|
, options_(options) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Generator::process() {
|
int Generator::process() {
|
||||||
if (!file_->read()) {
|
if (!parser_->read()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
const auto &result = parser_->data();
|
||||||
auto token = file_->getToken();
|
if (!write(result)) {
|
||||||
if (token.type == Type::Using) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (file_->atEnd() && !file_->failed()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (options_.rebuildDependencies) {
|
||||||
|
for (auto included : result.includes) {
|
||||||
|
if (!write(included)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Generator::write(const structure::Module &) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Generator::~Generator() = default;
|
Generator::~Generator() = default;
|
||||||
|
|
||||||
} // namespace style
|
} // namespace style
|
||||||
|
|
|
@ -22,16 +22,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
|
#include <QtCore/QStringList>
|
||||||
|
|
||||||
|
#include "codegen/style/options.h"
|
||||||
|
|
||||||
namespace codegen {
|
namespace codegen {
|
||||||
namespace style {
|
namespace style {
|
||||||
|
namespace structure {
|
||||||
class TokenizedFile;
|
struct Module;
|
||||||
|
} // namespace structure
|
||||||
|
class ParsedFile;
|
||||||
|
|
||||||
// Walks through a file, parses it and parses dependency files if necessary.
|
// Walks through a file, parses it and parses dependency files if necessary.
|
||||||
class Generator {
|
class Generator {
|
||||||
public:
|
public:
|
||||||
Generator(const QString &filepath, bool rebuildDependencies);
|
Generator(const Options &options);
|
||||||
Generator(const Generator &other) = delete;
|
Generator(const Generator &other) = delete;
|
||||||
Generator &operator=(const Generator &other) = delete;
|
Generator &operator=(const Generator &other) = delete;
|
||||||
|
|
||||||
|
@ -41,8 +46,14 @@ public:
|
||||||
~Generator();
|
~Generator();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<TokenizedFile> file_;
|
bool write(const structure::Module &module) const;
|
||||||
bool rebuild_;
|
|
||||||
|
std::unique_ptr<ParsedFile> 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_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,22 +22,18 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
|
|
||||||
#include "codegen/style/generator.h"
|
#include "codegen/style/generator.h"
|
||||||
|
#include "codegen/style/options.h"
|
||||||
|
|
||||||
using namespace codegen::style;
|
using namespace codegen::style;
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
QString filepath;
|
Options options = parseOptions();
|
||||||
bool rebuildOtherFiles = false;
|
if (options.inputPath.isEmpty()) {
|
||||||
for (const auto &arg : app.arguments()) {
|
return -1;
|
||||||
if (arg == "--rebuild") {
|
|
||||||
rebuildOtherFiles = true;
|
|
||||||
} else {
|
|
||||||
filepath = arg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Generator generator(filepath, rebuildOtherFiles);
|
Generator generator(options);
|
||||||
return generator.process();
|
return generator.process();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 <ostream>
|
||||||
|
#include <QtCore/QCoreApplication>
|
||||||
|
#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
|
|
@ -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 <QtCore/QString>
|
||||||
|
#include <QtCore/QStringList>
|
||||||
|
|
||||||
|
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
|
|
@ -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 <iostream>
|
||||||
|
#include <QtCore/QDir>
|
||||||
|
#include <QtCore/QRegularExpression>
|
||||||
|
#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
|
|
@ -24,31 +24,35 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtCore/QFileInfo>
|
#include <QtCore/QFileInfo>
|
||||||
#include "codegen/common/basic_tokenized_file.h"
|
#include "codegen/common/basic_tokenized_file.h"
|
||||||
|
#include "codegen/style/options.h"
|
||||||
|
#include "codegen/style/structure.h"
|
||||||
|
|
||||||
namespace codegen {
|
namespace codegen {
|
||||||
namespace style {
|
namespace style {
|
||||||
|
|
||||||
// Parses a file as a list of tokens.
|
// Parses an input file to the internal struct.
|
||||||
class TokenizedFile {
|
class ParsedFile {
|
||||||
public:
|
public:
|
||||||
TokenizedFile(const QString &filepath);
|
ParsedFile(const Options &options);
|
||||||
TokenizedFile(const TokenizedFile &other) = delete;
|
ParsedFile(const ParsedFile &other) = delete;
|
||||||
TokenizedFile &operator=(const TokenizedFile &other) = delete;
|
ParsedFile &operator=(const ParsedFile &other) = delete;
|
||||||
|
|
||||||
using ConstUtf8String = common::ConstUtf8String;
|
|
||||||
struct Token {
|
struct Token {
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Invalid,
|
Invalid,
|
||||||
|
|
||||||
Using,
|
Using, // value: file path
|
||||||
|
|
||||||
DefineStruct,
|
DefineStructStart, // value: struct name
|
||||||
DefineField,
|
DefineStructField, // value: struct field name
|
||||||
FieldType,
|
StructFieldType, // value: struct field type name
|
||||||
|
DefineStructEnd,
|
||||||
|
|
||||||
DefineVariable,
|
DefineVariable, // value: variable name
|
||||||
Struct,
|
StructStart, // value: struct name
|
||||||
StructParent,
|
StructParent, // value: variable parent name
|
||||||
|
VariableField, // value: variable field name
|
||||||
|
StructEnd,
|
||||||
|
|
||||||
Int,
|
Int,
|
||||||
Double,
|
Double,
|
||||||
|
@ -72,27 +76,29 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool read() {
|
bool read();
|
||||||
return file_.read();
|
|
||||||
}
|
|
||||||
bool atEnd() const {
|
|
||||||
return file_.atEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
Token getToken();
|
const structure::Module &data() const {
|
||||||
bool putBack();
|
return result_;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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.
|
// State value defines what are we waiting next.
|
||||||
enum class State {
|
enum class State {
|
||||||
|
@ -106,21 +112,34 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper methods for readToken() being in specific State.
|
// Helper methods for readToken() being in specific State.
|
||||||
Type readInDefault();
|
Token readInDefault();
|
||||||
Type readInStructStarted();
|
Token readInStructStarted();
|
||||||
Type readInStructFieldName();
|
Token readInStructFieldName();
|
||||||
Type readInVariable();
|
Token readInVariable();
|
||||||
Type readInVariableParents();
|
Token readInVariableParents();
|
||||||
Type readInVariableStarted();
|
Token readInVariableStarted();
|
||||||
Type readInVariableChild();
|
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_;
|
common::BasicTokenizedFile file_;
|
||||||
QList<Token> tokens_;
|
Options options_;
|
||||||
int currentToken_ = 0;
|
|
||||||
|
bool failed_ = false;
|
||||||
State state_ = State::Default;
|
State state_ = State::Default;
|
||||||
|
|
||||||
|
structure::Module result_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace style
|
} // namespace style
|
|
@ -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 <QtCore/QString>
|
||||||
|
#include <QtCore/QList>
|
||||||
|
#include <QtCore/QStringList>
|
||||||
|
|
||||||
|
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<Variable> fields; // for struct types
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Variable {
|
||||||
|
FullName name;
|
||||||
|
Type type;
|
||||||
|
Value value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StructField {
|
||||||
|
FullName name;
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
FullName name;
|
||||||
|
QList<StructField> fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Module {
|
||||||
|
QString fullpath;
|
||||||
|
QList<Module> includes;
|
||||||
|
QList<Struct> structs;
|
||||||
|
QList<Variable> variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace structure
|
||||||
|
} // namespace style
|
||||||
|
} // namespace codegen
|
|
@ -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 <iostream>
|
|
||||||
#include <QtCore/QDir>
|
|
||||||
|
|
||||||
#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
|
|
|
@ -16,7 +16,8 @@
|
||||||
<ClCompile Include="..\..\..\SourceFiles\codegen\common\clean_file.cpp" />
|
<ClCompile Include="..\..\..\SourceFiles\codegen\common\clean_file.cpp" />
|
||||||
<ClCompile Include="..\..\..\SourceFiles\codegen\common\logging.cpp" />
|
<ClCompile Include="..\..\..\SourceFiles\codegen\common\logging.cpp" />
|
||||||
<ClCompile Include="..\..\..\SourceFiles\codegen\style\generator.cpp" />
|
<ClCompile Include="..\..\..\SourceFiles\codegen\style\generator.cpp" />
|
||||||
<ClCompile Include="..\..\..\SourceFiles\codegen\style\tokenized_file.cpp" />
|
<ClCompile Include="..\..\..\SourceFiles\codegen\style\options.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\SourceFiles\codegen\style\parsed_file.cpp" />
|
||||||
<ClCompile Include="..\..\..\SourceFiles\codegen\style\main.cpp" />
|
<ClCompile Include="..\..\..\SourceFiles\codegen\style\main.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -27,7 +28,9 @@
|
||||||
<ClInclude Include="..\..\..\SourceFiles\codegen\common\const_utf8_string.h" />
|
<ClInclude Include="..\..\..\SourceFiles\codegen\common\const_utf8_string.h" />
|
||||||
<ClInclude Include="..\..\..\SourceFiles\codegen\common\logging.h" />
|
<ClInclude Include="..\..\..\SourceFiles\codegen\common\logging.h" />
|
||||||
<ClInclude Include="..\..\..\SourceFiles\codegen\style\generator.h" />
|
<ClInclude Include="..\..\..\SourceFiles\codegen\style\generator.h" />
|
||||||
<ClInclude Include="..\..\..\SourceFiles\codegen\style\tokenized_file.h" />
|
<ClInclude Include="..\..\..\SourceFiles\codegen\style\options.h" />
|
||||||
|
<ClInclude Include="..\..\..\SourceFiles\codegen\style\structure.h" />
|
||||||
|
<ClInclude Include="..\..\..\SourceFiles\codegen\style\parsed_file.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{E4DF8176-4DEF-4859-962F-B497E3E7A323}</ProjectGuid>
|
<ProjectGuid>{E4DF8176-4DEF-4859-962F-B497E3E7A323}</ProjectGuid>
|
||||||
|
|
|
@ -31,7 +31,10 @@
|
||||||
<ClCompile Include="..\..\..\SourceFiles\codegen\common\basic_tokenized_file.cpp">
|
<ClCompile Include="..\..\..\SourceFiles\codegen\common\basic_tokenized_file.cpp">
|
||||||
<Filter>src\common</Filter>
|
<Filter>src\common</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\SourceFiles\codegen\style\tokenized_file.cpp">
|
<ClCompile Include="..\..\..\SourceFiles\codegen\style\options.cpp">
|
||||||
|
<Filter>src\style</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\SourceFiles\codegen\style\parsed_file.cpp">
|
||||||
<Filter>src\style</Filter>
|
<Filter>src\style</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -57,7 +60,13 @@
|
||||||
<ClInclude Include="..\..\..\SourceFiles\codegen\common\basic_tokenized_file.h">
|
<ClInclude Include="..\..\..\SourceFiles\codegen\common\basic_tokenized_file.h">
|
||||||
<Filter>src\common</Filter>
|
<Filter>src\common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\..\SourceFiles\codegen\style\tokenized_file.h">
|
<ClInclude Include="..\..\..\SourceFiles\codegen\style\options.h">
|
||||||
|
<Filter>src\style</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\SourceFiles\codegen\style\structure.h">
|
||||||
|
<Filter>src\style</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\SourceFiles\codegen\style\parsed_file.h">
|
||||||
<Filter>src\style</Filter>
|
<Filter>src\style</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
Loading…
Reference in New Issue