2016-04-17 12:30:14 +03:00
/*
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>
2016-04-17 16:22:00 +03:00
# include <QtCore/QMap>
2016-04-17 12:30:14 +03:00
# include <QtCore/QDir>
# include <QtCore/QRegularExpression>
# include "codegen/common/basic_tokenized_file.h"
# include "codegen/common/logging.h"
using BasicToken = codegen : : common : : BasicTokenizedFile : : Token ;
using BasicType = BasicToken : : Type ;
namespace codegen {
namespace style {
2016-04-18 23:33:43 +03:00
using structure : : logFullName ;
2016-04-17 12:30:14 +03:00
namespace {
2016-04-17 16:22:00 +03:00
constexpr int kErrorInIncluded = 801 ;
constexpr int kErrorTypeMismatch = 802 ;
constexpr int kErrorUnknownField = 803 ;
constexpr int kErrorIdentifierNotFound = 804 ;
2016-04-17 20:52:17 +03:00
constexpr int kErrorAlreadyDefined = 805 ;
constexpr int kErrorBadString = 806 ;
2016-04-17 16:22:00 +03:00
2016-04-20 15:59:25 +03:00
QString findInputFile ( const Options & options ) {
for ( const auto & dir : options . includePaths ) {
QString tryPath = QDir ( dir ) . absolutePath ( ) + ' / ' + options . inputPath ;
if ( QFileInfo ( tryPath ) . exists ( ) ) {
return tryPath ;
}
}
return options . inputPath ;
}
2016-04-17 16:22:00 +03:00
QString tokenValue ( const BasicToken & token ) {
if ( token . type = = BasicType : : String ) {
return token . value ;
}
2016-04-17 12:30:14 +03:00
return token . original . toStringUnchecked ( ) ;
}
2016-04-17 16:22:00 +03:00
bool isValidColor ( const QString & str ) {
auto len = str . size ( ) ;
if ( len ! = 3 & & len ! = 4 & & len ! = 6 & & len ! = 8 ) {
return false ;
}
for ( auto ch : str ) {
auto code = ch . unicode ( ) ;
2016-04-17 20:52:17 +03:00
if ( ( code < ' 0 ' | | code > ' 9 ' ) & & ( code < ' a ' | | code > ' f ' ) ) {
2016-04-17 16:22:00 +03:00
return false ;
}
}
return true ;
}
2016-04-17 20:52:17 +03:00
uchar readHexUchar ( QChar ch ) {
auto code = ch . unicode ( ) ;
2016-04-18 23:33:43 +03:00
return ( code > = ' 0 ' & & code < = ' 9 ' ) ? ( ( code - ' 0 ' ) & 0xFF ) : ( ( code + 10 - ' a ' ) & 0xFF ) ;
2016-04-17 20:52:17 +03:00
}
uchar readHexUchar ( QChar char1 , QChar char2 ) {
return ( ( readHexUchar ( char1 ) & 0x0F ) < < 4 ) | ( readHexUchar ( char2 ) & 0x0F ) ;
}
structure : : data : : color convertWebColor ( const QString & str ) {
uchar r = 0 , g = 0 , b = 0 , a = 255 ;
if ( isValidColor ( str ) ) {
auto len = str . size ( ) ;
if ( len = = 3 | | len = = 4 ) {
r = readHexUchar ( str . at ( 0 ) , str . at ( 0 ) ) ;
g = readHexUchar ( str . at ( 1 ) , str . at ( 1 ) ) ;
b = readHexUchar ( str . at ( 2 ) , str . at ( 2 ) ) ;
if ( len = = 4 ) a = readHexUchar ( str . at ( 3 ) , str . at ( 3 ) ) ;
} else {
r = readHexUchar ( str . at ( 0 ) , str . at ( 1 ) ) ;
g = readHexUchar ( str . at ( 2 ) , str . at ( 3 ) ) ;
b = readHexUchar ( str . at ( 4 ) , str . at ( 5 ) ) ;
if ( len = = 8 ) a = readHexUchar ( str . at ( 6 ) , str . at ( 7 ) ) ;
}
}
return { r , g , b , a } ;
}
structure : : data : : color convertIntColor ( int r , int g , int b , int a ) {
return { uchar ( r & 0xFF ) , uchar ( g & 0xFF ) , uchar ( b & 0xFF ) , uchar ( a & 0xFF ) } ;
}
2016-04-17 16:22:00 +03:00
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 " ) ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 20:52:17 +03:00
bool validateAnsiString ( const QString & value ) {
for ( auto ch : value ) {
if ( ch . unicode ( ) > 127 ) {
return false ;
}
}
return true ;
}
bool validateTransitionString ( const QString & value ) {
return QRegularExpression ( " ^[a-zA-Z_]+$ " ) . match ( value ) . hasMatch ( ) ;
}
bool validateCursorString ( const QString & value ) {
return QRegularExpression ( " ^[a-z_]+$ " ) . match ( value ) . hasMatch ( ) ;
}
bool validateAlignString ( const QString & value ) {
return QRegularExpression ( " ^[a-z_]+$ " ) . match ( value ) . hasMatch ( ) ;
}
2016-04-17 12:30:14 +03:00
} // namespace
ParsedFile : : ParsedFile ( const Options & options )
2016-04-20 15:59:25 +03:00
: filePath_ ( findInputFile ( options ) )
, file_ ( filePath_ )
2016-04-17 12:30:14 +03:00
, options_ ( options ) {
}
bool ParsedFile : : read ( ) {
if ( ! file_ . read ( ) ) {
return false ;
}
2016-04-20 15:59:25 +03:00
auto absolutePath = QFileInfo ( filePath_ ) . absoluteFilePath ( ) ;
module_ = std : : make_unique < structure : : Module > ( absolutePath ) ;
2016-04-17 16:22:00 +03:00
do {
if ( auto startToken = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( startToken ) = = " using " ) {
if ( auto includedResult = readIncluded ( ) ) {
2016-04-18 23:33:43 +03:00
module_ - > addIncluded ( std : : move ( includedResult ) ) ;
2016-04-17 16:22:00 +03:00
continue ;
}
} else if ( auto braceOpen = file_ . getToken ( BasicType : : LeftBrace ) ) {
if ( auto structResult = readStruct ( tokenValue ( startToken ) ) ) {
2016-04-18 23:33:43 +03:00
if ( module_ - > addStruct ( structResult ) ) {
continue ;
2016-04-17 20:52:17 +03:00
}
2016-04-18 23:33:43 +03:00
logError ( kErrorAlreadyDefined ) < < " struct ' " < < logFullName ( structResult . name ) < < " ' already defined " ;
break ;
2016-04-17 16:22:00 +03:00
}
} else if ( auto colonToken = file_ . getToken ( BasicType : : Colon ) ) {
if ( auto variableResult = readVariable ( tokenValue ( startToken ) ) ) {
2016-04-18 23:33:43 +03:00
if ( module_ - > addVariable ( variableResult ) ) {
continue ;
2016-04-17 20:52:17 +03:00
}
2016-04-18 23:33:43 +03:00
logError ( kErrorAlreadyDefined ) < < " variable ' " < < logFullName ( variableResult . name ) < < " ' already defined " ;
break ;
2016-04-17 16:22:00 +03:00
}
2016-04-17 12:30:14 +03:00
}
}
2016-04-18 23:33:43 +03:00
if ( file_ . atEnd ( ) ) {
2016-04-17 16:22:00 +03:00
break ;
}
2016-04-18 23:33:43 +03:00
logErrorUnexpectedToken ( ) < < " using keyword, or struct definition, or variable definition " ;
2016-04-17 16:22:00 +03:00
} while ( ! failed ( ) ) ;
2016-04-18 23:33:43 +03:00
if ( failed ( ) ) {
module_ = nullptr ;
2016-04-17 12:30:14 +03:00
}
2016-04-18 23:33:43 +03:00
return ! failed ( ) ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
common : : LogStream ParsedFile : : logErrorTypeMismatch ( ) {
return logError ( kErrorTypeMismatch ) < < " type mismatch: " ;
}
2016-04-18 23:33:43 +03:00
ParsedFile : : ModulePtr ParsedFile : : readIncluded ( ) {
2016-04-17 20:52:17 +03:00
if ( auto usingFile = assertNextToken ( BasicType : : String ) ) {
if ( assertNextToken ( BasicType : : Semicolon ) ) {
2016-04-17 16:22:00 +03:00
ParsedFile included ( includedOptions ( tokenValue ( usingFile ) ) ) ;
if ( included . read ( ) ) {
2016-04-18 23:33:43 +03:00
return included . getResult ( ) ;
2016-04-17 12:30:14 +03:00
} else {
2016-04-17 16:22:00 +03:00
logError ( kErrorInIncluded ) < < " error while parsing ' " < < tokenValue ( usingFile ) . toStdString ( ) < < " ' " ;
2016-04-17 12:30:14 +03:00
}
}
}
2016-04-18 23:33:43 +03:00
return nullptr ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
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 ) ;
}
2016-04-17 20:52:17 +03:00
} else if ( assertNextToken ( BasicType : : RightBrace ) ) {
2016-04-17 16:22:00 +03:00
if ( result . fields . isEmpty ( ) ) {
logErrorUnexpectedToken ( ) < < " at least one field in struct " ;
}
break ;
}
} while ( ! failed ( ) ) ;
return result ;
}
structure : : Variable ParsedFile : : readVariable ( const QString & name ) {
structure : : Variable result = { composeFullName ( name ) } ;
if ( auto value = readValue ( ) ) {
result . value = value ;
2016-04-17 20:52:17 +03:00
if ( value . type ( ) . tag ! = structure : : TypeTag : : Struct ) {
assertNextToken ( BasicType : : Semicolon ) ;
2016-04-17 16:22:00 +03:00
}
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
return result ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : StructField ParsedFile : : readStructField ( const QString & name ) {
structure : : StructField result = { composeFullName ( name ) } ;
2016-04-17 20:52:17 +03:00
if ( auto colonToken = assertNextToken ( BasicType : : Colon ) ) {
2016-04-17 16:22:00 +03:00
if ( auto type = readType ( ) ) {
result . type = type ;
2016-04-17 20:52:17 +03:00
assertNextToken ( BasicType : : Semicolon ) ;
2016-04-17 12:30:14 +03:00
}
}
2016-04-17 16:22:00 +03:00
return result ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Type ParsedFile : : readType ( ) {
structure : : Type result ;
2016-04-17 20:52:17 +03:00
if ( auto nameToken = assertNextToken ( BasicType : : Name ) ) {
2016-04-17 16:22:00 +03:00
auto name = tokenValue ( nameToken ) ;
if ( auto builtInType = typeNames_ . value ( name . toStdString ( ) ) ) {
result = builtInType ;
} else {
2016-04-17 20:52:17 +03:00
auto fullName = composeFullName ( name ) ;
2016-04-18 23:33:43 +03:00
if ( module_ - > findStruct ( fullName ) ) {
2016-04-17 20:52:17 +03:00
result . tag = structure : : TypeTag : : Struct ;
result . name = fullName ;
} else {
logError ( kErrorIdentifierNotFound ) < < " type name ' " < < logFullName ( fullName ) < < " ' not found " ;
}
2016-04-17 12:30:14 +03:00
}
}
2016-04-17 16:22:00 +03:00
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 ;
2016-04-21 20:57:29 +03:00
} else if ( auto iconValue = readIconValue ( ) ) {
return iconValue ;
2016-04-17 16:22:00 +03:00
} 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 " ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
return { } ;
}
2016-04-17 12:30:14 +03:00
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readStructValue ( ) {
2016-04-17 12:30:14 +03:00
if ( auto structName = file_ . getToken ( BasicType : : Name ) ) {
2016-04-17 16:22:00 +03:00
if ( auto result = defaultConstructedStruct ( composeFullName ( tokenValue ( structName ) ) ) ) {
if ( file_ . getToken ( BasicType : : LeftParenthesis ) ) {
2016-04-17 20:52:17 +03:00
if ( ! readStructParents ( result ) ) {
return { } ;
2016-04-17 16:22:00 +03:00
}
2016-04-17 20:52:17 +03:00
}
if ( assertNextToken ( BasicType : : LeftBrace ) ) {
2016-04-17 16:22:00 +03:00
readStructValueInner ( result ) ;
}
return result ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
file_ . putBack ( ) ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : defaultConstructedStruct ( const structure : : FullName & structName ) {
2016-04-18 23:33:43 +03:00
if ( auto pattern = module_ - > findStruct ( structName ) ) {
QList < structure : : data : : field > fields ;
2016-04-17 20:52:17 +03:00
fields . reserve ( pattern - > fields . size ( ) ) ;
for ( const auto & fieldType : pattern - > fields ) {
2016-04-18 23:33:43 +03:00
fields . push_back ( {
{ // variable
fieldType . name ,
{ fieldType . type , Qt : : Uninitialized } , // value
} ,
structure : : data : : field : : Status : : Uninitialized , // status
} ) ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 20:52:17 +03:00
return { structName , fields } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 20:52:17 +03:00
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
void ParsedFile : : applyStructParent ( structure : : Value & result , const structure : : FullName & parentName ) {
2016-04-18 23:33:43 +03:00
if ( auto parent = module_ - > findVariable ( parentName ) ) {
2016-04-17 20:52:17 +03:00
if ( parent - > value . type ( ) ! = result . type ( ) ) {
logErrorTypeMismatch ( ) < < " parent ' " < < logFullName ( parentName ) < < " ' has type ' " < < logType ( parent - > value . type ( ) ) < < " ' while child value has type " < < logType ( result . type ( ) ) ;
return ;
}
2016-04-18 23:33:43 +03:00
const auto * srcFields ( parent - > value . Fields ( ) ) ;
auto * dstFields ( result . Fields ( ) ) ;
2016-04-17 20:52:17 +03:00
if ( ! srcFields | | ! dstFields ) {
logAssert ( false ) < < " struct data check failed " ;
return ;
}
logAssert ( srcFields - > size ( ) = = dstFields - > size ( ) ) < < " struct size check failed " ;
for ( int i = 0 , s = srcFields - > size ( ) ; i ! = s ; + + i ) {
2016-04-18 23:33:43 +03:00
const auto & srcField ( srcFields - > at ( i ) ) ;
auto & dstField ( ( * dstFields ) [ i ] ) ;
using Status = structure : : data : : field : : Status ;
if ( srcField . status = = Status : : Explicit | |
dstField . status = = Status : : Uninitialized ) {
const auto & srcValue ( srcField . variable . value ) ;
auto & dstValue ( dstField . variable . value ) ;
logAssert ( srcValue . type ( ) = = dstValue . type ( ) ) < < " struct field type check failed " ;
dstValue = srcValue ;
dstField . status = Status : : Implicit ;
}
2016-04-17 16:22:00 +03:00
}
2016-04-17 20:52:17 +03:00
} else {
logError ( kErrorIdentifierNotFound ) < < " parent ' " < < logFullName ( parentName ) < < " ' not found " ;
2016-04-17 12:30:14 +03:00
}
}
2016-04-17 16:22:00 +03:00
bool ParsedFile : : readStructValueInner ( structure : : Value & result ) {
do {
if ( auto fieldName = file_ . getToken ( BasicType : : Name ) ) {
2016-04-17 20:52:17 +03:00
if ( ! assertNextToken ( BasicType : : Colon ) ) {
return false ;
}
2016-04-17 16:22:00 +03:00
if ( auto field = readVariable ( tokenValue ( fieldName ) ) ) {
2016-04-17 20:52:17 +03:00
if ( ! assignStructField ( result , field ) ) {
return false ;
2016-04-17 16:22:00 +03:00
}
}
2016-04-17 20:52:17 +03:00
} else if ( assertNextToken ( BasicType : : RightBrace ) ) {
2016-04-17 16:22:00 +03:00
return true ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
} while ( ! failed ( ) ) ;
return false ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 20:52:17 +03:00
bool ParsedFile : : assignStructField ( structure : : Value & result , const structure : : Variable & field ) {
2016-04-18 23:33:43 +03:00
auto * fields = result . Fields ( ) ;
2016-04-17 20:52:17 +03:00
if ( ! fields ) {
logAssert ( false ) < < " struct data check failed " ;
return false ;
}
for ( auto & already : * fields ) {
2016-04-18 23:33:43 +03:00
if ( already . variable . name = = field . name ) {
if ( already . variable . value . type ( ) = = field . value . type ( ) ) {
already . variable . value = field . value ;
already . status = structure : : data : : field : : Status : : Explicit ;
2016-04-17 20:52:17 +03:00
return true ;
} else {
2016-04-18 23:33:43 +03:00
logErrorTypeMismatch ( ) < < " field ' " < < logFullName ( already . variable . name ) < < " ' has type ' " < < logType ( already . variable . value . type ( ) ) < < " ' while value has type ' " < < logType ( field . value . type ( ) ) < < " ' " ;
2016-04-17 20:52:17 +03:00
return false ;
}
}
}
logError ( kErrorUnknownField ) < < " field ' " < < logFullName ( field . name ) < < " ' was not found in struct of type ' " < < logType ( result . type ( ) ) < < " ' " ;
return false ;
}
2016-04-17 16:22:00 +03:00
bool ParsedFile : : readStructParents ( structure : : Value & result ) {
do {
2016-04-17 20:52:17 +03:00
if ( auto parentName = assertNextToken ( BasicType : : Name ) ) {
2016-04-17 16:22:00 +03:00
applyStructParent ( result , composeFullName ( tokenValue ( parentName ) ) ) ;
if ( file_ . getToken ( BasicType : : RightParenthesis ) ) {
return true ;
2016-04-17 20:52:17 +03:00
} else {
assertNextToken ( BasicType : : Comma ) ;
2016-04-17 16:22:00 +03:00
}
} else {
logErrorUnexpectedToken ( ) < < " struct variable parent " ;
}
} while ( ! failed ( ) ) ;
return false ;
}
structure : : Value ParsedFile : : readPositiveValue ( ) {
2016-04-17 12:30:14 +03:00
auto numericToken = file_ . getAnyToken ( ) ;
if ( numericToken . type = = BasicType : : Int ) {
2016-04-17 20:52:17 +03:00
return { structure : : TypeTag : : Int , tokenValue ( numericToken ) . toInt ( ) } ;
2016-04-17 12:30:14 +03:00
} else if ( numericToken . type = = BasicType : : Double ) {
2016-04-18 23:33:43 +03:00
return { structure : : TypeTag : : Double , tokenValue ( numericToken ) . toDouble ( ) } ;
2016-04-17 12:30:14 +03:00
} else if ( numericToken . type = = BasicType : : Name ) {
2016-04-17 16:22:00 +03:00
auto value = tokenValue ( numericToken ) ;
2016-04-17 12:30:14 +03:00
auto match = QRegularExpression ( " ^ \\ d+px$ " ) . match ( value ) ;
if ( match . hasMatch ( ) ) {
2016-04-17 20:52:17 +03:00
return { structure : : TypeTag : : Pixels , value . mid ( 0 , value . size ( ) - 2 ) . toInt ( ) } ;
2016-04-17 12:30:14 +03:00
}
}
file_ . putBack ( ) ;
2016-04-17 16:22:00 +03:00
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readNumericValue ( ) {
if ( auto value = readPositiveValue ( ) ) {
return value ;
2016-04-17 12:30:14 +03:00
} else if ( auto minusToken = file_ . getToken ( BasicType : : Minus ) ) {
2016-04-17 16:22:00 +03:00
if ( auto positiveValue = readNumericValue ( ) ) {
2016-04-17 20:52:17 +03:00
return { positiveValue . type ( ) . tag , - positiveValue . Int ( ) } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
logErrorUnexpectedToken ( ) < < " numeric value " ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readStringValue ( ) {
if ( auto stringToken = file_ . getToken ( BasicType : : String ) ) {
2016-04-17 20:52:17 +03:00
auto value = tokenValue ( stringToken ) ;
if ( validateAnsiString ( value ) ) {
return { structure : : TypeTag : : String , stringToken . value . toStdString ( ) } ;
}
logError ( kErrorBadString ) < < " unicode symbols are not supported " ;
2016-04-17 16:22:00 +03:00
}
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readColorValue ( ) {
if ( auto numberSign = file_ . getToken ( BasicType : : Number ) ) {
auto color = file_ . getAnyToken ( ) ;
if ( color . type = = BasicType : : Int | | color . type = = BasicType : : Name ) {
2016-04-17 20:52:17 +03:00
auto chars = tokenValue ( color ) . toLower ( ) ;
2016-04-17 16:22:00 +03:00
if ( isValidColor ( chars ) ) {
2016-04-17 20:52:17 +03:00
return { convertWebColor ( chars ) } ;
2016-04-17 16:22:00 +03:00
}
} else {
logErrorUnexpectedToken ( ) < < " color value in #ccc, #ccca, #cccccc or #ccccccaa format " ;
}
2016-04-17 20:52:17 +03:00
} else if ( auto rgbaToken = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( rgbaToken ) = = " rgba " ) {
assertNextToken ( BasicType : : LeftParenthesis ) ;
auto r = readNumericValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto g = readNumericValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto b = readNumericValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto a = readNumericValue ( ) ;
if ( r . type ( ) . tag ! = structure : : TypeTag : : Int | | r . Int ( ) < 0 | | r . Int ( ) > 255 | |
g . type ( ) . tag ! = structure : : TypeTag : : Int | | g . Int ( ) < 0 | | g . Int ( ) > 255 | |
b . type ( ) . tag ! = structure : : TypeTag : : Int | | b . Int ( ) < 0 | | b . Int ( ) > 255 | |
a . type ( ) . tag ! = structure : : TypeTag : : Int | | a . Int ( ) < 0 | | a . Int ( ) > 255 ) {
logErrorTypeMismatch ( ) < < " expected four 0-255 values for the rgba color " ;
}
assertNextToken ( BasicType : : RightParenthesis ) ;
return { convertIntColor ( r . Int ( ) , g . Int ( ) , b . Int ( ) , a . Int ( ) ) } ;
} else if ( tokenValue ( rgbaToken ) = = " rgb " ) {
assertNextToken ( BasicType : : LeftParenthesis ) ;
auto r = readNumericValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto g = readNumericValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto b = readNumericValue ( ) ;
if ( r . type ( ) . tag ! = structure : : TypeTag : : Int | | r . Int ( ) < 0 | | r . Int ( ) > 255 | |
g . type ( ) . tag ! = structure : : TypeTag : : Int | | g . Int ( ) < 0 | | g . Int ( ) > 255 | |
b . type ( ) . tag ! = structure : : TypeTag : : Int | | b . Int ( ) < 0 | | b . Int ( ) > 255 ) {
logErrorTypeMismatch ( ) < < " expected three int values for the rgb color " ;
}
assertNextToken ( BasicType : : RightParenthesis ) ;
return { convertIntColor ( r . Int ( ) , g . Int ( ) , b . Int ( ) , 255 ) } ;
}
file_ . putBack ( ) ;
2016-04-17 16:22:00 +03:00
}
return { } ;
}
structure : : Value ParsedFile : : readPointValue ( ) {
2016-04-17 20:52:17 +03:00
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " point " ) {
assertNextToken ( BasicType : : LeftParenthesis ) ;
2016-05-20 18:35:58 +03:00
auto x = readNumericOrNumericCopyValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto y = readNumericOrNumericCopyValue ( ) ;
2016-04-17 20:52:17 +03:00
if ( x . type ( ) . tag ! = structure : : TypeTag : : Pixels | |
y . type ( ) . tag ! = structure : : TypeTag : : Pixels ) {
logErrorTypeMismatch ( ) < < " expected two px values for the point " ;
}
assertNextToken ( BasicType : : RightParenthesis ) ;
return { structure : : data : : point { x . Int ( ) , y . Int ( ) } } ;
}
file_ . putBack ( ) ;
}
2016-04-17 16:22:00 +03:00
return { } ;
}
structure : : Value ParsedFile : : readSpriteValue ( ) {
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " sprite " ) {
2016-04-17 20:52:17 +03:00
assertNextToken ( BasicType : : LeftParenthesis ) ;
2016-04-17 16:22:00 +03:00
2016-04-17 20:52:17 +03:00
auto x = readNumericValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto y = readNumericValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto w = readNumericValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
2016-04-17 16:22:00 +03:00
auto h = readNumericValue ( ) ;
2016-04-17 20:52:17 +03:00
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 ( ) < < " expected four px values for the sprite " ;
2016-04-17 16:22:00 +03:00
}
2016-04-17 20:52:17 +03:00
assertNextToken ( BasicType : : RightParenthesis ) ;
2016-04-17 16:22:00 +03:00
2016-04-17 20:52:17 +03:00
return { structure : : data : : sprite { x . Int ( ) , y . Int ( ) , w . Int ( ) , h . Int ( ) } } ;
2016-04-17 16:22:00 +03:00
}
file_ . putBack ( ) ;
}
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readSizeValue ( ) {
2016-04-17 20:52:17 +03:00
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " size " ) {
assertNextToken ( BasicType : : LeftParenthesis ) ;
2016-05-20 18:35:58 +03:00
auto w = readNumericOrNumericCopyValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto h = readNumericOrNumericCopyValue ( ) ;
2016-04-17 20:52:17 +03:00
if ( w . type ( ) . tag ! = structure : : TypeTag : : Pixels | |
h . type ( ) . tag ! = structure : : TypeTag : : Pixels ) {
logErrorTypeMismatch ( ) < < " expected two px values for the size " ;
}
assertNextToken ( BasicType : : RightParenthesis ) ;
return { structure : : data : : size { w . Int ( ) , h . Int ( ) } } ;
}
file_ . putBack ( ) ;
}
2016-04-17 16:22:00 +03:00
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readTransitionValue ( ) {
2016-04-17 20:52:17 +03:00
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " transition " ) {
assertNextToken ( BasicType : : LeftParenthesis ) ;
auto transition = tokenValue ( assertNextToken ( BasicType : : Name ) ) ;
assertNextToken ( BasicType : : RightParenthesis ) ;
if ( validateTransitionString ( transition ) ) {
return { structure : : TypeTag : : Transition , transition . toStdString ( ) } ;
} else {
logError ( kErrorBadString ) < < " bad transition value " ;
}
}
file_ . putBack ( ) ;
}
2016-04-17 16:22:00 +03:00
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readCursorValue ( ) {
2016-04-17 20:52:17 +03:00
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " cursor " ) {
assertNextToken ( BasicType : : LeftParenthesis ) ;
auto cursor = tokenValue ( assertNextToken ( BasicType : : Name ) ) ;
assertNextToken ( BasicType : : RightParenthesis ) ;
if ( validateCursorString ( cursor ) ) {
return { structure : : TypeTag : : Cursor , cursor . toStdString ( ) } ;
} else {
logError ( kErrorBadString ) < < " bad cursor string " ;
}
}
file_ . putBack ( ) ;
}
2016-04-17 16:22:00 +03:00
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readAlignValue ( ) {
2016-04-17 20:52:17 +03:00
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " align " ) {
assertNextToken ( BasicType : : LeftParenthesis ) ;
auto align = tokenValue ( assertNextToken ( BasicType : : Name ) ) ;
assertNextToken ( BasicType : : RightParenthesis ) ;
if ( validateAlignString ( align ) ) {
return { structure : : TypeTag : : Align , align . toStdString ( ) } ;
} else {
logError ( kErrorBadString ) < < " bad align string " ;
}
}
file_ . putBack ( ) ;
}
2016-04-17 16:22:00 +03:00
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readMarginsValue ( ) {
2016-04-17 20:52:17 +03:00
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " margins " ) {
assertNextToken ( BasicType : : LeftParenthesis ) ;
2016-05-20 18:35:58 +03:00
auto l = readNumericOrNumericCopyValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto t = readNumericOrNumericCopyValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto r = readNumericOrNumericCopyValue ( ) ; assertNextToken ( BasicType : : Comma ) ;
auto b = readNumericOrNumericCopyValue ( ) ;
2016-04-17 20:52:17 +03:00
if ( l . type ( ) . tag ! = structure : : TypeTag : : Pixels | |
t . type ( ) . tag ! = structure : : TypeTag : : Pixels | |
r . type ( ) . tag ! = structure : : TypeTag : : Pixels | |
b . type ( ) . tag ! = structure : : TypeTag : : Pixels ) {
logErrorTypeMismatch ( ) < < " expected four px values for the margins " ;
}
assertNextToken ( BasicType : : RightParenthesis ) ;
return { structure : : data : : margins { l . Int ( ) , t . Int ( ) , r . Int ( ) , b . Int ( ) } } ;
}
file_ . putBack ( ) ;
}
2016-04-17 16:22:00 +03:00
return { } ;
}
structure : : Value ParsedFile : : readFontValue ( ) {
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " font " ) {
2016-04-17 20:52:17 +03:00
assertNextToken ( BasicType : : LeftParenthesis ) ;
2016-04-17 16:22:00 +03:00
2016-04-17 20:52:17 +03:00
int flags = 0 ;
2016-04-17 16:22:00 +03:00
structure : : Value family , size ;
do {
2016-04-17 20:52:17 +03:00
if ( auto formatToken = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( formatToken ) = = " bold " ) {
flags | = structure : : data : : font : : Bold ;
} else if ( tokenValue ( formatToken ) = = " italic " ) {
flags | = structure : : data : : font : : Italic ;
} else if ( tokenValue ( formatToken ) = = " underline " ) {
flags | = structure : : data : : font : : Underline ;
} else {
file_ . putBack ( ) ;
}
}
2016-05-20 18:35:58 +03:00
if ( auto familyValue = readStringOrStringCopyValue ( ) ) {
2016-04-17 16:22:00 +03:00
family = familyValue ;
2016-05-20 18:35:58 +03:00
} else if ( auto sizeValue = readNumericOrNumericCopyValue ( ) ) {
2016-04-17 16:22:00 +03:00
size = sizeValue ;
} else if ( file_ . getToken ( BasicType : : RightParenthesis ) ) {
break ;
} else {
logErrorUnexpectedToken ( ) < < " font family, font size or ')' " ;
}
} while ( ! failed ( ) ) ;
2016-04-17 20:52:17 +03:00
if ( size . type ( ) . tag ! = structure : : TypeTag : : Pixels ) {
2016-04-17 16:22:00 +03:00
logErrorTypeMismatch ( ) < < " px value for the font size expected " ;
}
2016-04-17 20:52:17 +03:00
return { structure : : data : : font { family . String ( ) , size . Int ( ) , flags } } ;
2016-04-17 16:22:00 +03:00
}
file_ . putBack ( ) ;
}
return { } ;
}
2016-04-21 20:57:29 +03:00
structure : : Value ParsedFile : : readIconValue ( ) {
if ( auto font = file_ . getToken ( BasicType : : Name ) ) {
if ( tokenValue ( font ) = = " icon " ) {
std : : vector < structure : : data : : monoicon > parts ;
if ( file_ . getToken ( BasicType : : LeftBrace ) ) { // complex icon
do {
if ( file_ . getToken ( BasicType : : RightBrace ) ) {
break ;
} else if ( file_ . getToken ( BasicType : : LeftBrace ) ) {
if ( auto part = readMonoIconFields ( ) ) {
assertNextToken ( BasicType : : RightBrace ) ;
parts . push_back ( part ) ;
file_ . getToken ( BasicType : : Comma ) ;
continue ;
}
return { } ;
} else {
logErrorUnexpectedToken ( ) < < " icon part or '}' " ;
return { } ;
}
} while ( true ) ;
} else if ( file_ . getToken ( BasicType : : LeftParenthesis ) ) { // short icon
if ( auto theOnlyPart = readMonoIconFields ( ) ) {
assertNextToken ( BasicType : : RightParenthesis ) ;
parts . push_back ( theOnlyPart ) ;
}
}
if ( parts . empty ( ) ) {
logErrorUnexpectedToken ( ) < < " at least one icon part " ;
return { } ;
}
return { structure : : data : : icon { parts } } ;
}
file_ . putBack ( ) ;
}
return { } ;
}
2016-04-17 16:22:00 +03:00
structure : : Value ParsedFile : : readCopyValue ( ) {
if ( auto copyName = file_ . getToken ( BasicType : : Name ) ) {
structure : : FullName name = { tokenValue ( copyName ) } ;
2016-04-18 23:33:43 +03:00
if ( auto variable = module_ - > findVariable ( name ) ) {
2016-04-17 20:52:17 +03:00
return variable - > value . makeCopy ( variable - > name ) ;
2016-04-17 16:22:00 +03:00
}
2016-05-20 18:35:58 +03:00
file_ . putBack ( ) ;
}
return { } ;
}
structure : : Value ParsedFile : : readNumericOrNumericCopyValue ( ) {
if ( auto result = readNumericValue ( ) ) {
return result ;
} else if ( auto copy = readCopyValue ( ) ) {
auto type = copy . type ( ) . tag ;
if ( type = = structure : : TypeTag : : Int
| | type = = structure : : TypeTag : : Double
| | type = = structure : : TypeTag : : Pixels ) {
return copy ;
} else {
file_ . putBack ( ) ;
}
}
return { } ;
}
structure : : Value ParsedFile : : readStringOrStringCopyValue ( ) {
if ( auto result = readStringValue ( ) ) {
return result ;
} else if ( auto copy = readCopyValue ( ) ) {
auto type = copy . type ( ) . tag ;
if ( type = = structure : : TypeTag : : String ) {
return copy ;
} else {
file_ . putBack ( ) ;
}
2016-04-17 16:22:00 +03:00
}
return { } ;
2016-04-17 12:30:14 +03:00
}
2016-04-21 20:57:29 +03:00
structure : : data : : monoicon ParsedFile : : readMonoIconFields ( ) {
structure : : data : : monoicon result ;
result . filename = readMonoIconFilename ( ) ;
if ( ! result . filename . isEmpty ( ) & & file_ . getToken ( BasicType : : Comma ) ) {
if ( auto color = readValue ( ) ) {
if ( color . type ( ) . tag = = structure : : TypeTag : : Color ) {
result . color = color ;
if ( file_ . getToken ( BasicType : : Comma ) ) {
if ( auto offset = readValue ( ) ) {
if ( offset . type ( ) . tag = = structure : : TypeTag : : Point ) {
result . offset = offset ;
} else {
logErrorUnexpectedToken ( ) < < " icon offset " ;
}
} else {
logErrorUnexpectedToken ( ) < < " icon offset " ;
}
} else {
result . offset = { structure : : data : : point { 0 , 0 } } ;
}
} else {
logErrorUnexpectedToken ( ) < < " icon color " ;
}
} else {
logErrorUnexpectedToken ( ) < < " icon color " ;
}
}
return result ;
}
QString ParsedFile : : readMonoIconFilename ( ) {
if ( auto filename = readValue ( ) ) {
if ( filename . type ( ) . tag = = structure : : TypeTag : : String ) {
auto filepath = QString : : fromStdString ( filename . String ( ) ) ;
for ( const auto & path : options_ . includePaths ) {
QFileInfo fileinfo ( path + ' / ' + filepath + " .png " ) ;
if ( fileinfo . exists ( ) ) {
return path + ' / ' + filepath ;
}
}
for ( const auto & path : options_ . includePaths ) {
QFileInfo fileinfo ( path + " /icons/ " + filepath + " .png " ) ;
if ( fileinfo . exists ( ) ) {
return path + " /icons/ " + filepath ;
}
}
logError ( common : : kErrorFileNotFound ) < < " could not open icon file ' " < < filename . String ( ) < < " ' " ;
} else if ( filename . type ( ) . tag = = structure : : TypeTag : : Size ) {
return QString ( " size://%1,%2 " ) . arg ( filename . Size ( ) . width ) . arg ( filename . Size ( ) . height ) ;
}
}
logErrorUnexpectedToken ( ) < < " icon filename or rect size " ;
return QString ( ) ;
}
2016-04-17 20:52:17 +03:00
BasicToken ParsedFile : : assertNextToken ( BasicToken : : Type type ) {
auto result = file_ . getToken ( type ) ;
if ( ! result ) {
logErrorUnexpectedToken ( ) < < type ;
}
return result ;
}
2016-04-17 16:22:00 +03:00
Options ParsedFile : : includedOptions ( const QString & filepath ) {
auto result = options_ ;
result . inputPath = filepath ;
2016-04-20 15:59:25 +03:00
result . includePaths [ 0 ] = QFileInfo ( filePath_ ) . dir ( ) . absolutePath ( ) ;
2016-04-17 16:22:00 +03:00
return result ;
2016-04-17 12:30:14 +03:00
}
2016-04-17 16:22:00 +03:00
// Compose context-dependent full name.
structure : : FullName ParsedFile : : composeFullName ( const QString & name ) {
return { name } ;
2016-04-17 12:30:14 +03:00
}
} // namespace style
} // namespace codegen