mirror of https://github.com/procxx/kepka.git
Parsing of color and sprite values started in codegen_style.
This commit is contained in:
parent
45bd2dc5fa
commit
e0160f7d4c
|
@ -18,6 +18,8 @@ to link the code of portions of this program with the OpenSSL library.
|
||||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
|
using "Resources/style_classes.txt";
|
||||||
|
|
||||||
defaultFontFamily: "Open Sans";
|
defaultFontFamily: "Open Sans";
|
||||||
semibold: "Open Sans Semibold";
|
semibold: "Open Sans Semibold";
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ bool isNameChar(char ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWhitespaceChar(char ch) {
|
bool isWhitespaceChar(char ch) {
|
||||||
return (ch == '\n' || ch == ' ' || ch == '\t');
|
return (ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t');
|
||||||
}
|
}
|
||||||
|
|
||||||
Token invalidToken() {
|
Token invalidToken() {
|
||||||
|
@ -224,7 +224,7 @@ Type BasicTokenizedFile::readString() {
|
||||||
Type BasicTokenizedFile::readSingleLetter() {
|
Type BasicTokenizedFile::readSingleLetter() {
|
||||||
auto type = singleLetterTokens_.value(reader_.currentChar(), Type::Invalid);
|
auto type = singleLetterTokens_.value(reader_.currentChar(), Type::Invalid);
|
||||||
if (type == Type::Invalid) {
|
if (type == Type::Invalid) {
|
||||||
reader_.logError(kErrorIncorrectToken, lineNumber_) << "incorrect token '" << reader_.currentChar() << "'.";
|
reader_.logError(kErrorIncorrectToken, lineNumber_) << "incorrect token '" << reader_.currentChar() << "'";
|
||||||
return Type::Invalid;
|
return Type::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,16 +253,12 @@ LogStream BasicTokenizedFile::logError(int code) const {
|
||||||
return reader_.logError(code, lineNumber_);
|
return reader_.logError(code, lineNumber_);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogStream BasicTokenizedFile::logErrorUnexpectedToken(const std::string &expected) const {
|
LogStream BasicTokenizedFile::logErrorUnexpectedToken() const {
|
||||||
std::string expectedTail;
|
|
||||||
if (!expected.empty()) {
|
|
||||||
expectedTail = ", expected " + expected;
|
|
||||||
}
|
|
||||||
if (currentToken_ < tokens_.size()) {
|
if (currentToken_ < tokens_.size()) {
|
||||||
auto token = tokens_.at(currentToken_).original.toStdString();
|
auto token = tokens_.at(currentToken_).original.toStdString();
|
||||||
return logError(kErrorUnexpectedToken) << "unexpected token '" << token << '\'' << expectedTail << '.';
|
return logError(kErrorUnexpectedToken) << "unexpected token '" << token << "', expected ";
|
||||||
}
|
}
|
||||||
return logError(kErrorUnexpectedToken) << "unexpected token" << expectedTail << '.';
|
return logError(kErrorUnexpectedToken) << "unexpected token, expected ";
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicTokenizedFile::~BasicTokenizedFile() = default;
|
BasicTokenizedFile::~BasicTokenizedFile() = default;
|
||||||
|
|
|
@ -21,8 +21,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QtCore/QString>
|
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
|
#include <QtCore/QString>
|
||||||
#include <QtCore/QList>
|
#include <QtCore/QList>
|
||||||
|
|
||||||
#include "codegen/common/const_utf8_string.h"
|
#include "codegen/common/const_utf8_string.h"
|
||||||
|
@ -89,7 +89,7 @@ public:
|
||||||
|
|
||||||
// Log error to std::cerr with 'code' at the current position in file.
|
// Log error to std::cerr with 'code' at the current position in file.
|
||||||
LogStream logError(int code) const;
|
LogStream logError(int code) const;
|
||||||
LogStream logErrorUnexpectedToken(const std::string &expected = std::string()) const;
|
LogStream logErrorUnexpectedToken() const;
|
||||||
|
|
||||||
~BasicTokenizedFile();
|
~BasicTokenizedFile();
|
||||||
|
|
||||||
|
|
|
@ -29,29 +29,36 @@ namespace common {
|
||||||
// Wrapper around std::ostream that adds '\n' to the end of the logging line.
|
// Wrapper around std::ostream that adds '\n' to the end of the logging line.
|
||||||
class LogStream {
|
class LogStream {
|
||||||
public:
|
public:
|
||||||
explicit LogStream(std::ostream &stream) : stream_(stream) {
|
enum NullType {
|
||||||
|
Null,
|
||||||
|
};
|
||||||
|
explicit LogStream(NullType) : final_(false) {
|
||||||
|
}
|
||||||
|
explicit LogStream(std::ostream &stream) : stream_(&stream) {
|
||||||
}
|
}
|
||||||
LogStream(LogStream &&other) : stream_(other.stream_) {
|
LogStream(LogStream &&other) : stream_(other.stream_) {
|
||||||
other.final_ = false;
|
other.final_ = false;
|
||||||
}
|
}
|
||||||
std::ostream &stream() const {
|
std::ostream *stream() const {
|
||||||
return stream_;
|
return stream_;
|
||||||
}
|
}
|
||||||
~LogStream() {
|
~LogStream() {
|
||||||
if (final_) {
|
if (final_) {
|
||||||
stream_ << '\n';
|
*stream_ << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::ostream &stream_;
|
std::ostream *stream_ = nullptr;
|
||||||
bool final_ = true;
|
bool final_ = true;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
LogStream operator<<(LogStream &&stream, T &&value) {
|
LogStream operator<<(LogStream &&stream, T &&value) {
|
||||||
stream.stream() << value;
|
if (auto ostream = stream.stream()) {
|
||||||
|
*ostream << std::forward<T>(value);
|
||||||
|
}
|
||||||
return std::forward<LogStream>(stream);
|
return std::forward<LogStream>(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,5 +66,7 @@ LogStream operator<<(LogStream &&stream, T &&value) {
|
||||||
// logError(kErrorFileTooLarge, filepath) << "file too large, size=" << size;
|
// logError(kErrorFileTooLarge, filepath) << "file too large, size=" << size;
|
||||||
LogStream logError(int code, const QString &filepath, int line = 0);
|
LogStream logError(int code, const QString &filepath, int line = 0);
|
||||||
|
|
||||||
|
static constexpr int kErrorInternal = 666;
|
||||||
|
|
||||||
} // namespace common
|
} // namespace common
|
||||||
} // namespace codegen
|
} // namespace codegen
|
||||||
|
|
|
@ -22,8 +22,7 @@ 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/common/qstringlist_safe.h"
|
||||||
|
|
||||||
#include "codegen/style/options.h"
|
#include "codegen/style/options.h"
|
||||||
|
|
||||||
namespace codegen {
|
namespace codegen {
|
||||||
|
|
|
@ -40,8 +40,8 @@ using common::logError;
|
||||||
Options parseOptions() {
|
Options parseOptions() {
|
||||||
Options result;
|
Options result;
|
||||||
auto args(QCoreApplication::instance()->arguments());
|
auto args(QCoreApplication::instance()->arguments());
|
||||||
for (auto i = args.cbegin(), e = args.cend(); i != e; ++i) {
|
for (int i = 1, count = args.size(); i < count; ++i) { // skip first
|
||||||
const auto &arg(*i);
|
const auto &arg(args.at(i));
|
||||||
|
|
||||||
// Rebuild all dependencies
|
// Rebuild all dependencies
|
||||||
if (arg == "--rebuild") {
|
if (arg == "--rebuild") {
|
||||||
|
@ -49,22 +49,22 @@ Options parseOptions() {
|
||||||
|
|
||||||
// Include paths
|
// Include paths
|
||||||
} else if (arg == "-I") {
|
} else if (arg == "-I") {
|
||||||
if (++i == e) {
|
if (++i == count) {
|
||||||
logError(kErrorIncludePathExpected, "Command Line") << "include path expected after -I";
|
logError(kErrorIncludePathExpected, "Command Line") << "include path expected after -I";
|
||||||
return Options();
|
return Options();
|
||||||
} else {
|
} else {
|
||||||
result.includePaths.push_back(*i);
|
result.includePaths.push_back(args.at(i));
|
||||||
}
|
}
|
||||||
} else if (arg.startsWith("-I")) {
|
} else if (arg.startsWith("-I")) {
|
||||||
result.includePaths.push_back(arg.mid(2));
|
result.includePaths.push_back(arg.mid(2));
|
||||||
|
|
||||||
// Output path
|
// Output path
|
||||||
} else if (arg == "-o") {
|
} else if (arg == "-o") {
|
||||||
if (++i == e) {
|
if (++i == count) {
|
||||||
logError(kErrorOutputPathExpected, "Command Line") << "output path expected after -o";
|
logError(kErrorOutputPathExpected, "Command Line") << "output path expected after -o";
|
||||||
return Options();
|
return Options();
|
||||||
} else {
|
} else {
|
||||||
result.outputPath = *i;
|
result.outputPath = args.at(i);
|
||||||
}
|
}
|
||||||
} else if (arg.startsWith("-o")) {
|
} else if (arg.startsWith("-o")) {
|
||||||
result.outputPath = arg.mid(2);
|
result.outputPath = arg.mid(2);
|
||||||
|
|
|
@ -21,13 +21,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "codegen/style/parsed_file.h"
|
#include "codegen/style/parsed_file.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <QtCore/QMap>
|
||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QRegularExpression>
|
#include <QtCore/QRegularExpression>
|
||||||
#include "codegen/common/basic_tokenized_file.h"
|
#include "codegen/common/basic_tokenized_file.h"
|
||||||
#include "codegen/common/logging.h"
|
#include "codegen/common/logging.h"
|
||||||
|
|
||||||
using Token = codegen::style::ParsedFile::Token;
|
|
||||||
using Type = Token::Type;
|
|
||||||
using BasicToken = codegen::common::BasicTokenizedFile::Token;
|
using BasicToken = codegen::common::BasicTokenizedFile::Token;
|
||||||
using BasicType = BasicToken::Type;
|
using BasicType = BasicToken::Type;
|
||||||
|
|
||||||
|
@ -35,12 +34,57 @@ namespace codegen {
|
||||||
namespace style {
|
namespace style {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
QString plainValue(const BasicToken &token) {
|
constexpr int kErrorInIncluded = 801;
|
||||||
|
constexpr int kErrorTypeMismatch = 802;
|
||||||
|
constexpr int kErrorUnknownField = 803;
|
||||||
|
constexpr int kErrorIdentifierNotFound = 804;
|
||||||
|
|
||||||
|
QString tokenValue(const BasicToken &token) {
|
||||||
|
if (token.type == BasicType::String) {
|
||||||
|
return token.value;
|
||||||
|
}
|
||||||
return token.original.toStringUnchecked();
|
return token.original.toStringUnchecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
Token invalidToken() {
|
bool isValidColor(const QString &str) {
|
||||||
return { Type::Invalid, QString() };
|
auto len = str.size();
|
||||||
|
if (len != 3 && len != 4 && len != 6 && len != 8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto ch : str) {
|
||||||
|
auto code = ch.unicode();
|
||||||
|
if ((code < '0' || code > '9') && (code < 'a' || code > 'f') && (code < 'A' || code > 'F')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string logFullName(const structure::FullName &name) {
|
||||||
|
return name.join('.').toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string logType(const structure::Type &type) {
|
||||||
|
if (type.tag == structure::TypeTag::Struct) {
|
||||||
|
return "struct " + logFullName(type.name);
|
||||||
|
}
|
||||||
|
static auto builtInTypes = new QMap<structure::TypeTag, std::string> {
|
||||||
|
{ structure::TypeTag::Int , "int" },
|
||||||
|
{ structure::TypeTag::Double , "double" },
|
||||||
|
{ structure::TypeTag::Pixels , "pixels" },
|
||||||
|
{ structure::TypeTag::String , "string" },
|
||||||
|
{ structure::TypeTag::Color , "color" },
|
||||||
|
{ structure::TypeTag::Point , "point" },
|
||||||
|
{ structure::TypeTag::Sprite , "sprite" },
|
||||||
|
{ structure::TypeTag::Size , "size" },
|
||||||
|
{ structure::TypeTag::Transition, "transition" },
|
||||||
|
{ structure::TypeTag::Cursor , "cursor" },
|
||||||
|
{ structure::TypeTag::Align , "align" },
|
||||||
|
{ structure::TypeTag::Margins , "margins" },
|
||||||
|
{ structure::TypeTag::Font , "font" },
|
||||||
|
};
|
||||||
|
return builtInTypes->value(type.tag, "invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -55,246 +99,437 @@ bool ParsedFile::read() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto token = readInDefault(); token; token = readInDefault()) {
|
bool noErrors = false;
|
||||||
if (token.type == Type::Using) {
|
do {
|
||||||
auto includedOptions = options_;
|
if (auto startToken = file_.getToken(BasicType::Name)) {
|
||||||
// includedOptions.inputPath = findIncludePath(token.value);
|
if (tokenValue(startToken) == "using") {
|
||||||
ParsedFile included(includedOptions);
|
if (auto includedResult = readIncluded()) {
|
||||||
if (!included.read()) {
|
result_.includes.push_back(includedResult);
|
||||||
return false;
|
continue;
|
||||||
}
|
|
||||||
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 if (auto braceOpen = file_.getToken(BasicType::LeftBrace)) {
|
||||||
|
if (auto structResult = readStruct(tokenValue(startToken))) {
|
||||||
|
result_.structs.push_back(structResult);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (auto colonToken = file_.getToken(BasicType::Colon)) {
|
||||||
|
if (auto variableResult = readVariable(tokenValue(startToken))) {
|
||||||
|
result_.variables.push_back(variableResult);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!file_.atEnd()) {
|
||||||
|
logErrorUnexpectedToken() << "using keyword, or struct definition, or variable definition";
|
||||||
|
} else {
|
||||||
|
noErrors = !failed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (!failed());
|
||||||
|
|
||||||
|
if (noErrors) {
|
||||||
|
result_.fullpath = QFileInfo(options_.inputPath).absoluteFilePath();
|
||||||
|
}
|
||||||
|
return noErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
common::LogStream ParsedFile::logErrorTypeMismatch() {
|
||||||
|
return logError(kErrorTypeMismatch) << "type mismatch: ";
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Module ParsedFile::readIncluded() {
|
||||||
|
structure::Module result;
|
||||||
|
if (auto usingFile = file_.getToken(BasicType::String)) {
|
||||||
|
if (file_.getToken(BasicType::Semicolon)) {
|
||||||
|
ParsedFile included(includedOptions(tokenValue(usingFile)));
|
||||||
|
if (included.read()) {
|
||||||
|
result = included.data();
|
||||||
} else {
|
} else {
|
||||||
logErrorUnexpectedToken("file path");
|
logError(kErrorInIncluded) << "error while parsing '" << tokenValue(usingFile).toStdString() << "'";
|
||||||
}
|
}
|
||||||
return invalidToken();
|
} else {
|
||||||
} else if (auto braceOpen = file_.getToken(BasicType::LeftBrace)) {
|
logErrorUnexpectedToken() << "';'";
|
||||||
state_ = State::StructStarted;
|
}
|
||||||
return { Type::DefineStructStart, plainValue(startToken) };
|
} else {
|
||||||
} else if (auto colonToken = file_.getToken(BasicType::Colon)) {
|
logErrorUnexpectedToken() << "file path";
|
||||||
state_ = State::Variable;
|
}
|
||||||
return { Type::DefineVariable, plainValue(startToken) };
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Struct ParsedFile::readStruct(const QString &name) {
|
||||||
|
structure::Struct result = { composeFullName(name) };
|
||||||
|
do {
|
||||||
|
if (auto fieldName = file_.getToken(BasicType::Name)) {
|
||||||
|
if (auto field = readStructField(tokenValue(fieldName))) {
|
||||||
|
result.fields.push_back(field);
|
||||||
|
}
|
||||||
|
} else if (auto braceClose = file_.getToken(BasicType::RightBrace)) {
|
||||||
|
if (result.fields.isEmpty()) {
|
||||||
|
logErrorUnexpectedToken() << "at least one field in struct";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
logErrorUnexpectedToken() << "struct field name or '}'";
|
||||||
|
}
|
||||||
|
} while (!failed());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Variable ParsedFile::readVariable(const QString &name) {
|
||||||
|
structure::Variable result = { composeFullName(name) };
|
||||||
|
if (auto value = readValue()) {
|
||||||
|
result.value = value;
|
||||||
|
if (!file_.getToken(BasicType::Semicolon)) {
|
||||||
|
logErrorUnexpectedToken() << "';'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!file_.atEnd()) {
|
return result;
|
||||||
logErrorUnexpectedToken("using keyword, or struct definition, or variable definition");
|
|
||||||
}
|
|
||||||
return invalidToken();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readInStructStarted() {
|
structure::StructField ParsedFile::readStructField(const QString &name) {
|
||||||
if (auto fieldName = file_.getToken(BasicType::Name)) {
|
structure::StructField result = { composeFullName(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 colonToken = file_.getToken(BasicType::Colon)) {
|
||||||
if (auto fieldType = file_.getToken(BasicType::Name)) {
|
if (auto type = readType()) {
|
||||||
if (file_.getToken(BasicType::Semicolon)) {
|
result.type = type;
|
||||||
state_ = State::StructStarted;
|
if (!file_.getToken(BasicType::Semicolon)) {
|
||||||
return { Type::StructFieldType, plainValue(fieldType) };
|
logErrorUnexpectedToken() << "';'";
|
||||||
}
|
}
|
||||||
logErrorUnexpectedToken(";");
|
|
||||||
} else {
|
|
||||||
logErrorUnexpectedToken("struct field type name");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logErrorUnexpectedToken("':'");
|
logErrorUnexpectedToken() << "':'";
|
||||||
}
|
}
|
||||||
return invalidToken();
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readInVariable() {
|
structure::Type ParsedFile::readType() {
|
||||||
if (auto value = readValueToken()) {
|
structure::Type result;
|
||||||
if (file_.getToken(BasicType::Semicolon)) {
|
if (auto nameToken = file_.getToken(BasicType::Name)) {
|
||||||
state_ = State::Default;
|
auto name = tokenValue(nameToken);
|
||||||
return value;
|
if (auto builtInType = typeNames_.value(name.toStdString())) {
|
||||||
|
result = builtInType;
|
||||||
|
} else {
|
||||||
|
result.tag = structure::TypeTag::Struct;
|
||||||
|
result.name = composeFullName(name);
|
||||||
}
|
}
|
||||||
logErrorUnexpectedToken(";");
|
} else {
|
||||||
return invalidToken();
|
logErrorUnexpectedToken() << "type name";
|
||||||
}
|
|
||||||
if (failed()) {
|
|
||||||
return invalidToken();
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Value ParsedFile::readValue() {
|
||||||
|
if (auto colorValue = readColorValue()) {
|
||||||
|
return colorValue;
|
||||||
|
} else if (auto pointValue = readPointValue()) {
|
||||||
|
return pointValue;
|
||||||
|
} else if (auto spriteValue = readSpriteValue()) {
|
||||||
|
return spriteValue;
|
||||||
|
} else if (auto sizeValue = readSizeValue()) {
|
||||||
|
return sizeValue;
|
||||||
|
} else if (auto transitionValue = readTransitionValue()) {
|
||||||
|
return transitionValue;
|
||||||
|
} else if (auto cursorValue = readCursorValue()) {
|
||||||
|
return cursorValue;
|
||||||
|
} else if (auto alignValue = readAlignValue()) {
|
||||||
|
return alignValue;
|
||||||
|
} else if (auto marginsValue = readMarginsValue()) {
|
||||||
|
return marginsValue;
|
||||||
|
} else if (auto fontValue = readFontValue()) {
|
||||||
|
return fontValue;
|
||||||
|
} else if (auto numericValue = readNumericValue()) {
|
||||||
|
return numericValue;
|
||||||
|
} else if (auto stringValue = readStringValue()) {
|
||||||
|
return stringValue;
|
||||||
|
} else if (auto structValue = readStructValue()) {
|
||||||
|
return structValue;
|
||||||
|
} else if (auto copyValue = readCopyValue()) {
|
||||||
|
return copyValue;
|
||||||
|
} else {
|
||||||
|
logErrorUnexpectedToken() << "variable value";
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Value ParsedFile::readStructValue() {
|
||||||
if (auto structName = file_.getToken(BasicType::Name)) {
|
if (auto structName = file_.getToken(BasicType::Name)) {
|
||||||
if (file_.getToken(BasicType::LeftParenthesis)) {
|
if (auto result = defaultConstructedStruct(composeFullName(tokenValue(structName)))) {
|
||||||
state_ = State::VariableParents;
|
if (file_.getToken(BasicType::LeftParenthesis)) {
|
||||||
return { Type::StructStart, plainValue(structName) };
|
if (readStructParents(result)) {
|
||||||
} else if (file_.getToken(BasicType::LeftBrace)) {
|
if (file_.getToken(BasicType::LeftBrace)) {
|
||||||
state_ = State::VariableStarted;
|
readStructValueInner(result);
|
||||||
return { Type::StructStart, plainValue(structName) };
|
} else {
|
||||||
} else {
|
logErrorUnexpectedToken() << "'{'";
|
||||||
logErrorUnexpectedToken("'(' or '{'");
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (file_.getToken(BasicType::LeftBrace)) {
|
||||||
logErrorUnexpectedToken("variable value");
|
readStructValueInner(result);
|
||||||
}
|
} else {
|
||||||
return invalidToken();
|
logErrorUnexpectedToken() << "'(' or '{'";
|
||||||
}
|
|
||||||
|
|
||||||
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("'{'");
|
return result;
|
||||||
|
}
|
||||||
|
file_.putBack();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Value ParsedFile::defaultConstructedStruct(const structure::FullName &structName) {
|
||||||
|
structure::Value result;
|
||||||
|
for (const auto &structType : result_.structs) {
|
||||||
|
if (structType.name == structName) {
|
||||||
|
result.fields.reserve(structType.fields.size());
|
||||||
|
for (const auto &fieldType : structType.fields) {
|
||||||
|
result.fields.push_back({ fieldType.name, fieldType.type });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParsedFile::applyStructParent(structure::Value &result, const structure::FullName &parentName) {
|
||||||
|
for (const auto &structValue : result_.variables) {
|
||||||
|
if (structValue.name == parentName) {
|
||||||
|
if (structValue.value.type == result.type) {
|
||||||
|
const auto &srcFields(structValue.value.fields);
|
||||||
|
auto &dstFields(result.fields);
|
||||||
|
logAssert(srcFields.size() == dstFields.size()) << "struct size check failed";
|
||||||
|
|
||||||
|
for (int i = 0, s = srcFields.size(); i != s; ++i) {
|
||||||
|
logAssert(srcFields.at(i).value.type == dstFields.at(i).value.type) << "struct field type check failed";
|
||||||
|
dstFields[i].value = srcFields.at(i).value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logErrorTypeMismatch() << "parent '" << logFullName(parentName) << "' has type '" << logType(structValue.value.type) << "' while child value has type " << logType(result.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParsedFile::readStructValueInner(structure::Value &result) {
|
||||||
|
do {
|
||||||
|
if (auto fieldName = file_.getToken(BasicType::Name)) {
|
||||||
|
if (auto field = readVariable(tokenValue(fieldName))) {
|
||||||
|
for (auto &already : result.fields) {
|
||||||
|
if (already.name == field.name) {
|
||||||
|
if (already.value.type == field.value.type) {
|
||||||
|
already.value = field.value;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
logErrorTypeMismatch() << "field '" << logFullName(already.name) << "' has type '" << logType(already.value.type) << "' while value has type " << logType(field.value.type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logError(kErrorUnknownField) << "field '" << logFullName(field.name) << "' was not found in struct of type '" << logType(result.type) << "'";
|
||||||
|
}
|
||||||
|
} else if (file_.getToken(BasicType::RightBrace)) {
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
logErrorUnexpectedToken("',' or ')'");
|
logErrorUnexpectedToken() << "variable field name or '}'";
|
||||||
}
|
}
|
||||||
} else {
|
} while (!failed());
|
||||||
logErrorUnexpectedToken("struct variable parent");
|
return false;
|
||||||
}
|
|
||||||
return invalidToken();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readInVariableStarted() {
|
bool ParsedFile::readStructParents(structure::Value &result) {
|
||||||
if (auto fieldName = file_.getToken(BasicType::Name)) {
|
do {
|
||||||
state_ = State::VariableChild;
|
if (auto parentName = file_.getToken(BasicType::Name)) {
|
||||||
return { Type::VariableField, plainValue(fieldName) };
|
applyStructParent(result, composeFullName(tokenValue(parentName)));
|
||||||
} else if (auto braceClose = file_.getToken(BasicType::RightBrace)) {
|
if (file_.getToken(BasicType::RightParenthesis)) {
|
||||||
state_ = State::Default;
|
return true;
|
||||||
return { Type::StructEnd };
|
} else if (!file_.getToken(BasicType::Comma)) {
|
||||||
}
|
logErrorUnexpectedToken() << "',' or ')'";
|
||||||
logErrorUnexpectedToken("struct variable field name or '}'");
|
}
|
||||||
return invalidToken();
|
} else {
|
||||||
}
|
logErrorUnexpectedToken() << "struct variable parent";
|
||||||
|
|
||||||
Token ParsedFile::readInVariableChild() {
|
|
||||||
if (auto value = readValueToken()) {
|
|
||||||
if (file_.getToken(BasicType::Semicolon)) {
|
|
||||||
state_ = State::Default;
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
logErrorUnexpectedToken(";");
|
} while (!failed());
|
||||||
} else {
|
return false;
|
||||||
logErrorUnexpectedToken("variable field value");
|
|
||||||
}
|
|
||||||
return invalidToken();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readNumericToken() {
|
//ParsedFile::Token ParsedFile::readInVariableChild() {
|
||||||
|
// if (auto value = readValue()) {
|
||||||
|
// if (file_.getToken(BasicType::Semicolon)) {
|
||||||
|
// state_ = State::Default;
|
||||||
|
// return value;
|
||||||
|
// }
|
||||||
|
// logErrorUnexpectedToken(";");
|
||||||
|
// } else {
|
||||||
|
// logErrorUnexpectedToken("variable field value");
|
||||||
|
// }
|
||||||
|
// return invalidToken();
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
structure::Value ParsedFile::readPositiveValue() {
|
||||||
auto numericToken = file_.getAnyToken();
|
auto numericToken = file_.getAnyToken();
|
||||||
if (numericToken.type == BasicType::Int) {
|
if (numericToken.type == BasicType::Int) {
|
||||||
return { Type::Int, plainValue(numericToken) };
|
return { { structure::TypeTag::Int }, tokenValue(numericToken) };
|
||||||
} else if (numericToken.type == BasicType::Double) {
|
} else if (numericToken.type == BasicType::Double) {
|
||||||
return { Type::Double, plainValue(numericToken) };
|
return { { structure::TypeTag::Double }, tokenValue(numericToken) };
|
||||||
} else if (numericToken.type == BasicType::Name) {
|
} else if (numericToken.type == BasicType::Name) {
|
||||||
auto value = plainValue(numericToken);
|
auto value = tokenValue(numericToken);
|
||||||
auto match = QRegularExpression("^\\d+px$").match(value);
|
auto match = QRegularExpression("^\\d+px$").match(value);
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
return { Type::Pixels, value.mid(0, value.size() - 2) };
|
return { { structure::TypeTag::Pixels }, value.mid(0, value.size() - 2) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_.putBack();
|
file_.putBack();
|
||||||
return invalidToken();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readValueToken() {
|
structure::Value ParsedFile::readNumericValue() {
|
||||||
if (auto colorValue = readColorToken()) {
|
if (auto value = readPositiveValue()) {
|
||||||
return colorValue;
|
return value;
|
||||||
} 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)) {
|
} else if (auto minusToken = file_.getToken(BasicType::Minus)) {
|
||||||
if (auto positiveValue = readNumericToken()) {
|
if (auto positiveValue = readNumericValue()) {
|
||||||
return { positiveValue.type, '-' + positiveValue.value };
|
return { positiveValue.type, '-' + positiveValue.data };
|
||||||
}
|
}
|
||||||
logErrorUnexpectedToken("numeric value");
|
logErrorUnexpectedToken() << "numeric value";
|
||||||
}
|
}
|
||||||
return invalidToken();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readColorToken() {
|
structure::Value ParsedFile::readStringValue() {
|
||||||
return invalidToken();
|
if (auto stringToken = file_.getToken(BasicType::String)) {
|
||||||
|
return { { structure::TypeTag::String }, stringToken.value };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readPointToken() {
|
structure::Value ParsedFile::readColorValue() {
|
||||||
return invalidToken();
|
if (auto numberSign = file_.getToken(BasicType::Number)) {
|
||||||
|
auto color = file_.getAnyToken();
|
||||||
|
if (color.type == BasicType::Int || color.type == BasicType::Name) {
|
||||||
|
auto chars = tokenValue(color);
|
||||||
|
if (isValidColor(chars)) {
|
||||||
|
return { { structure::TypeTag::Color }, chars.toLower() };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logErrorUnexpectedToken() << "color value in #ccc, #ccca, #cccccc or #ccccccaa format";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readSpriteToken() {
|
structure::Value ParsedFile::readPointValue() {
|
||||||
return invalidToken();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readSizeToken() {
|
structure::Value ParsedFile::readSpriteValue() {
|
||||||
return invalidToken();
|
if (auto font = file_.getToken(BasicType::Name)) {
|
||||||
|
if (tokenValue(font) == "sprite") {
|
||||||
|
if (!file_.getToken(BasicType::LeftParenthesis)) {
|
||||||
|
logErrorUnexpectedToken() << "'(' and sprite definition";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto x = readNumericValue(); file_.getToken(BasicType::Comma);
|
||||||
|
auto y = readNumericValue(); file_.getToken(BasicType::Comma);
|
||||||
|
auto w = readNumericValue(); file_.getToken(BasicType::Comma);
|
||||||
|
auto h = readNumericValue();
|
||||||
|
if (x.type.tag != structure::TypeTag::Pixels ||
|
||||||
|
y.type.tag != structure::TypeTag::Pixels ||
|
||||||
|
w.type.tag != structure::TypeTag::Pixels ||
|
||||||
|
h.type.tag != structure::TypeTag::Pixels) {
|
||||||
|
logErrorTypeMismatch() << "px rect for the sprite expected";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_.getToken(BasicType::RightParenthesis)) {
|
||||||
|
logErrorUnexpectedToken() << "')'";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { { structure::TypeTag::Sprite }, x.data + ',' + y.data + ',' + w.data + ',' + h.data };
|
||||||
|
}
|
||||||
|
file_.putBack();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readTransitionToken() {
|
structure::Value ParsedFile::readSizeValue() {
|
||||||
return invalidToken();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readCursorToken() {
|
structure::Value ParsedFile::readTransitionValue() {
|
||||||
return invalidToken();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readAlignToken() {
|
structure::Value ParsedFile::readCursorValue() {
|
||||||
return invalidToken();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readMarginsToken() {
|
structure::Value ParsedFile::readAlignValue() {
|
||||||
return invalidToken();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Token ParsedFile::readFontToken() {
|
structure::Value ParsedFile::readMarginsValue() {
|
||||||
return invalidToken();
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Value ParsedFile::readFontValue() {
|
||||||
|
if (auto font = file_.getToken(BasicType::Name)) {
|
||||||
|
if (tokenValue(font) == "font") {
|
||||||
|
if (!file_.getToken(BasicType::LeftParenthesis)) {
|
||||||
|
logErrorUnexpectedToken() << "'(' and font definition";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Value family, size;
|
||||||
|
do {
|
||||||
|
if (auto familyValue = readStringValue()) {
|
||||||
|
family = familyValue;
|
||||||
|
} else if (auto sizeValue = readNumericValue()) {
|
||||||
|
size = sizeValue;
|
||||||
|
} else if (auto copyValue = readCopyValue()) {
|
||||||
|
if (copyValue.type.tag == structure::TypeTag::String) {
|
||||||
|
family = copyValue;
|
||||||
|
} else if (copyValue.type.tag == structure::TypeTag::Pixels) {
|
||||||
|
size = copyValue;
|
||||||
|
} else {
|
||||||
|
logErrorUnexpectedToken() << "font family, font size or ')'";
|
||||||
|
}
|
||||||
|
} else if (file_.getToken(BasicType::RightParenthesis)) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
logErrorUnexpectedToken() << "font family, font size or ')'";
|
||||||
|
}
|
||||||
|
} while (!failed());
|
||||||
|
|
||||||
|
if (size.type.tag != structure::TypeTag::Pixels) {
|
||||||
|
logErrorTypeMismatch() << "px value for the font size expected";
|
||||||
|
}
|
||||||
|
return { { structure::TypeTag::Font }, size.data + ',' + family.data };
|
||||||
|
}
|
||||||
|
file_.putBack();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
structure::Value ParsedFile::readCopyValue() {
|
||||||
|
if (auto copyName = file_.getToken(BasicType::Name)) {
|
||||||
|
structure::FullName name = { tokenValue(copyName) };
|
||||||
|
for (const auto &variable : result_.variables) {
|
||||||
|
if (variable.name == name) {
|
||||||
|
auto result = variable.value;
|
||||||
|
result.copy = variable.name;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logError(kErrorIdentifierNotFound) << "identifier '" << logFullName(name) << "' not found";
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Options ParsedFile::includedOptions(const QString &filepath) {
|
||||||
|
auto result = options_;
|
||||||
|
result.inputPath = filepath;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compose context-dependent full name.
|
||||||
|
structure::FullName ParsedFile::composeFullName(const QString &name) {
|
||||||
|
return { name };
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace style
|
} // namespace style
|
||||||
|
|
|
@ -21,8 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QtCore/QString>
|
#include <string>
|
||||||
#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/options.h"
|
||||||
#include "codegen/style/structure.h"
|
#include "codegen/style/structure.h"
|
||||||
|
@ -37,45 +36,6 @@ public:
|
||||||
ParsedFile(const ParsedFile &other) = delete;
|
ParsedFile(const ParsedFile &other) = delete;
|
||||||
ParsedFile &operator=(const ParsedFile &other) = delete;
|
ParsedFile &operator=(const ParsedFile &other) = delete;
|
||||||
|
|
||||||
struct Token {
|
|
||||||
enum class Type {
|
|
||||||
Invalid,
|
|
||||||
|
|
||||||
Using, // value: file path
|
|
||||||
|
|
||||||
DefineStructStart, // value: struct name
|
|
||||||
DefineStructField, // value: struct field name
|
|
||||||
StructFieldType, // value: struct field type name
|
|
||||||
DefineStructEnd,
|
|
||||||
|
|
||||||
DefineVariable, // value: variable name
|
|
||||||
StructStart, // value: struct name
|
|
||||||
StructParent, // value: variable parent name
|
|
||||||
VariableField, // value: variable field name
|
|
||||||
StructEnd,
|
|
||||||
|
|
||||||
Int,
|
|
||||||
Double,
|
|
||||||
Pixels,
|
|
||||||
String,
|
|
||||||
Color,
|
|
||||||
Point,
|
|
||||||
Sprite,
|
|
||||||
Size,
|
|
||||||
Transition,
|
|
||||||
Cursor,
|
|
||||||
Align,
|
|
||||||
Margins,
|
|
||||||
Font,
|
|
||||||
};
|
|
||||||
Type type;
|
|
||||||
QString value;
|
|
||||||
|
|
||||||
explicit operator bool() const {
|
|
||||||
return type != Type::Invalid;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool read();
|
bool read();
|
||||||
|
|
||||||
const structure::Module &data() const {
|
const structure::Module &data() const {
|
||||||
|
@ -93,53 +53,75 @@ private:
|
||||||
failed_ = true;
|
failed_ = true;
|
||||||
return file_.logError(code);
|
return file_.logError(code);
|
||||||
}
|
}
|
||||||
common::LogStream logErrorUnexpectedToken(const std::string &expected = std::string()) {
|
common::LogStream logErrorUnexpectedToken() {
|
||||||
failed_ = true;
|
failed_ = true;
|
||||||
return file_.logErrorUnexpectedToken(expected);
|
return file_.logErrorUnexpectedToken();
|
||||||
|
}
|
||||||
|
common::LogStream logErrorTypeMismatch();
|
||||||
|
common::LogStream logAssert(bool assertion) {
|
||||||
|
if (!assertion) {
|
||||||
|
return logError(common::kErrorInternal) << "internal - ";
|
||||||
|
}
|
||||||
|
return common::LogStream(common::LogStream::Null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token readToken();
|
// Helper methods for context-dependent reading.
|
||||||
|
structure::Module readIncluded();
|
||||||
|
structure::Struct readStruct(const QString &name);
|
||||||
|
structure::Variable readVariable(const QString &name);
|
||||||
|
|
||||||
// State value defines what are we waiting next.
|
structure::StructField readStructField(const QString &name);
|
||||||
enum class State {
|
structure::Type readType();
|
||||||
Default, // [ using | struct name | variable name | end ]
|
structure::Value readValue();
|
||||||
StructStarted, // [ struct field name | struct end ]
|
|
||||||
StructFieldName, // [ struct field type ]
|
|
||||||
Variable, // [ struct name | variable value ]
|
|
||||||
VariableParents, // [ variable parent name | variable start ]
|
|
||||||
VariableStarted, // [ variable field name | variable end]
|
|
||||||
VariableChild, // [ variable child value ]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper methods for readToken() being in specific State.
|
structure::Value readStructValue();
|
||||||
Token readInDefault();
|
structure::Value defaultConstructedStruct(const structure::FullName &name);
|
||||||
Token readInStructStarted();
|
void applyStructParent(structure::Value &result, const structure::FullName &parentName);
|
||||||
Token readInStructFieldName();
|
bool readStructValueInner(structure::Value &result);
|
||||||
Token readInVariable();
|
bool readStructParents(structure::Value &result);
|
||||||
Token readInVariableParents();
|
|
||||||
Token readInVariableStarted();
|
|
||||||
Token readInVariableChild();
|
|
||||||
|
|
||||||
Token readNumericToken();
|
// Simple methods for reading value types.
|
||||||
Token readValueToken();
|
structure::Value readPositiveValue();
|
||||||
Token readColorToken();
|
structure::Value readNumericValue();
|
||||||
Token readPointToken();
|
structure::Value readStringValue();
|
||||||
Token readSpriteToken();
|
structure::Value readColorValue();
|
||||||
Token readSizeToken();
|
structure::Value readPointValue();
|
||||||
Token readTransitionToken();
|
structure::Value readSpriteValue();
|
||||||
Token readCursorToken();
|
structure::Value readSizeValue();
|
||||||
Token readAlignToken();
|
structure::Value readTransitionValue();
|
||||||
Token readMarginsToken();
|
structure::Value readCursorValue();
|
||||||
Token readFontToken();
|
structure::Value readAlignValue();
|
||||||
|
structure::Value readMarginsValue();
|
||||||
|
structure::Value readFontValue();
|
||||||
|
structure::Value readCopyValue();
|
||||||
|
|
||||||
|
// Look through include directories in options_ and find absolute include path.
|
||||||
|
Options includedOptions(const QString &filepath);
|
||||||
|
|
||||||
|
// Compose context-dependent full name.
|
||||||
|
structure::FullName composeFullName(const QString &name);
|
||||||
|
|
||||||
common::BasicTokenizedFile file_;
|
common::BasicTokenizedFile file_;
|
||||||
Options options_;
|
Options options_;
|
||||||
|
|
||||||
bool failed_ = false;
|
bool failed_ = false;
|
||||||
State state_ = State::Default;
|
|
||||||
|
|
||||||
structure::Module result_;
|
structure::Module result_;
|
||||||
|
|
||||||
|
QMap<std::string, structure::Type> typeNames_ = {
|
||||||
|
{ "int" , { structure::TypeTag::Int } },
|
||||||
|
{ "double" , { structure::TypeTag::Double } },
|
||||||
|
{ "pixels" , { structure::TypeTag::Pixels } },
|
||||||
|
{ "string" , { structure::TypeTag::String } },
|
||||||
|
{ "color" , { structure::TypeTag::Color } },
|
||||||
|
{ "point" , { structure::TypeTag::Point } },
|
||||||
|
{ "sprite" , { structure::TypeTag::Sprite } },
|
||||||
|
{ "size" , { structure::TypeTag::Size } },
|
||||||
|
{ "transition", { structure::TypeTag::Transition } },
|
||||||
|
{ "cursor" , { structure::TypeTag::Cursor } },
|
||||||
|
{ "align" , { structure::TypeTag::Align } },
|
||||||
|
{ "margins" , { structure::TypeTag::Margins } },
|
||||||
|
{ "font" , { structure::TypeTag::Font } },
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace style
|
} // namespace style
|
||||||
|
|
|
@ -21,7 +21,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtCore/QList>
|
|
||||||
#include <QtCore/QStringList>
|
#include <QtCore/QStringList>
|
||||||
|
|
||||||
namespace codegen {
|
namespace codegen {
|
||||||
|
@ -32,6 +31,7 @@ namespace structure {
|
||||||
using FullName = QStringList;
|
using FullName = QStringList;
|
||||||
|
|
||||||
enum class TypeTag {
|
enum class TypeTag {
|
||||||
|
Invalid,
|
||||||
Int,
|
Int,
|
||||||
Double,
|
Double,
|
||||||
Pixels,
|
Pixels,
|
||||||
|
@ -51,28 +51,55 @@ enum class TypeTag {
|
||||||
struct Type {
|
struct Type {
|
||||||
TypeTag tag;
|
TypeTag tag;
|
||||||
FullName name; // only for type == ClassType::Struct
|
FullName name; // only for type == ClassType::Struct
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return (tag != TypeTag::Invalid);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
inline bool operator==(const Type &a, const Type &b) {
|
||||||
|
return (a.tag == b.tag) && (a.name == b.name);
|
||||||
|
}
|
||||||
|
inline bool operator!=(const Type &a, const Type &b) {
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
struct Variable;
|
struct Variable;
|
||||||
struct Value {
|
struct Value {
|
||||||
|
Type type;
|
||||||
QString data; // for plain types
|
QString data; // for plain types
|
||||||
QList<Variable> fields; // for struct types
|
QList<Variable> fields; // for struct types
|
||||||
|
FullName copy; // for copies of existing named values
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return !data.isEmpty() || !fields.isEmpty() || !copy.isEmpty();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Variable {
|
struct Variable {
|
||||||
FullName name;
|
FullName name;
|
||||||
Type type;
|
|
||||||
Value value;
|
Value value;
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return !name.isEmpty();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StructField {
|
struct StructField {
|
||||||
FullName name;
|
FullName name;
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return !name.isEmpty();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Struct {
|
struct Struct {
|
||||||
FullName name;
|
FullName name;
|
||||||
QList<StructField> fields;
|
QList<StructField> fields;
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return !name.isEmpty();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Module {
|
struct Module {
|
||||||
|
@ -80,6 +107,10 @@ struct Module {
|
||||||
QList<Module> includes;
|
QList<Module> includes;
|
||||||
QList<Struct> structs;
|
QList<Struct> structs;
|
||||||
QList<Variable> variables;
|
QList<Variable> variables;
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return !fullpath.isEmpty();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace structure
|
} // namespace structure
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>UNICODE;WIN32;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>UNICODE;WIN32;QT_CORE_LIB;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
|
Loading…
Reference in New Issue