/*
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
*
* This program 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.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "glsl.h"
#include "../Constants.h"
#include
static const QSet GLSLStatementKeyWords {
"if",
"for",
"try",
"catch",
"else",
"while"
};
const QSet SynEditGLSLHighlighter::Keywords {
"const", "uniform", "buffer", "shared", "attribute", "varying",
"coherent", "volatile", "restrict", "readonly", "writeonly",
"atomic_uint",
"layout",
"centroid", "flat", "smooth", "noperspective",
"patch", "sample",
"invariant", "precise",
"break", "continue", "do", "for", "while", "switch", "case", "default",
"if", "else",
"subroutine",
"in", "out", "inout",
"int", "void", "bool", "true", "false", "float", "double",
"discard", "return",
"vec2", "vec3", "vec4", "ivec2", "ivec3", "ivec4", "bvec2", "bvec3", "bvec4",
"uint", "uvec2", "uvec3", "uvec4",
"dvec2", "dvec3", "dvec4",
"mat2", "mat3", "mat4",
"mat2x2", "mat2x3", "mat2x4",
"mat3x2", "mat3x3", "mat3x4",
"mat4x2", "mat4x3", "mat4x4",
"dmat2", "dmat3", "dmat4",
"dmat2x2", "dmat2x3", "dmat2x4",
"dmat3x2", "dmat3x3", "dmat3x4",
"dmat4x2", "dmat4x3", "dmat4x4",
"lowp", "mediump", "highp", "precision",
"sampler1D", "sampler1DShadow", "sampler1DArray", "sampler1DArrayShadow",
"isampler1D", "isampler1DArray", "usampler1D", "usampler1DArray",
"sampler2D", "sampler2DShadow", "sampler2DArray", "sampler2DArrayShadow",
"isampler2D", "isampler2DArray", "usampler2D", "usampler2DArray",
"sampler2DRect", "sampler2DRectShadow", "isampler2DRect", "usampler2DRect",
"sampler2DMS", "isampler2DMS", "usampler2DMS",
"sampler2DMSArray", "isampler2DMSArray", "usampler2DMSArray",
"sampler3D", "isampler3D", "usampler3D",
"samplerCube", "samplerCubeShadow", "isamplerCube", "usamplerCube",
"samplerCubeArray", "samplerCubeArrayShadow",
"isamplerCubeArray", "usamplerCubeArray",
"samplerBuffer", "isamplerBuffer", "usamplerBuffer",
"image1D", "iimage1D", "uimage1D",
"image1DArray", "iimage1DArray", "uimage1DArray",
"image2D", "iimage2D", "uimage2D",
"image2DArray", "iimage2DArray", "uimage2DArray",
"image2DRect", "iimage2DRect", "uimage2DRect",
"image2DMS", "iimage2DMS", "uimage2DMS",
"image2DMSArray", "iimage2DMSArray", "uimage2DMSArray",
"image3D", "iimage3D", "uimage3D",
"imageCube", "iimageCube", "uimageCube",
"imageCubeArray", "iimageCubeArray", "uimageCubeArray",
"imageBuffer", "iimageBuffer", "uimageBuffer",
"struct"
};
SynEditGLSLHighlighter::SynEditGLSLHighlighter(): SynHighlighter()
{
mAsmAttribute = std::make_shared(SYNS_AttrAssembler);
addAttribute(mAsmAttribute);
mCharAttribute = std::make_shared(SYNS_AttrCharacter);
addAttribute(mCharAttribute);
mCommentAttribute = std::make_shared(SYNS_AttrComment);
addAttribute(mCommentAttribute);
mClassAttribute = std::make_shared(SYNS_AttrClass);
addAttribute(mClassAttribute);
mFloatAttribute = std::make_shared(SYNS_AttrFloat);
addAttribute(mFloatAttribute);
mFunctionAttribute = std::make_shared(SYNS_AttrFunction);
addAttribute(mFunctionAttribute);
mGlobalVarAttribute = std::make_shared(SYNS_AttrGlobalVariable);
addAttribute(mGlobalVarAttribute);
mHexAttribute = std::make_shared(SYNS_AttrHexadecimal);
addAttribute(mHexAttribute);
mIdentifierAttribute = std::make_shared(SYNS_AttrIdentifier);
addAttribute(mIdentifierAttribute);
mInvalidAttribute = std::make_shared(SYNS_AttrIllegalChar);
addAttribute(mInvalidAttribute);
mLocalVarAttribute = std::make_shared(SYNS_AttrLocalVariable);
addAttribute(mLocalVarAttribute);
mNumberAttribute = std::make_shared(SYNS_AttrNumber);
addAttribute(mNumberAttribute);
mOctAttribute = std::make_shared(SYNS_AttrOctal);
addAttribute(mOctAttribute);
mPreprocessorAttribute = std::make_shared(SYNS_AttrPreprocessor);
addAttribute(mPreprocessorAttribute);
mKeywordAttribute = std::make_shared(SYNS_AttrReservedWord);
addAttribute(mKeywordAttribute);
mWhitespaceAttribute = std::make_shared(SYNS_AttrSpace);
addAttribute(mWhitespaceAttribute);
mStringAttribute = std::make_shared(SYNS_AttrString);
addAttribute(mStringAttribute);
mStringEscapeSequenceAttribute = std::make_shared(SYNS_AttrStringEscapeSequences);
addAttribute(mStringEscapeSequenceAttribute);
mSymbolAttribute = std::make_shared(SYNS_AttrSymbol);
addAttribute(mSymbolAttribute);
mVariableAttribute = std::make_shared(SYNS_AttrVariable);
addAttribute(mVariableAttribute);
resetState();
}
PSynHighlighterAttribute SynEditGLSLHighlighter::asmAttribute() const
{
return mAsmAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::preprocessorAttribute() const
{
return mPreprocessorAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::invalidAttribute() const
{
return mInvalidAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::numberAttribute() const
{
return mNumberAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::floatAttribute() const
{
return mFloatAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::hexAttribute() const
{
return mHexAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::octAttribute() const
{
return mOctAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::stringEscapeSequenceAttribute() const
{
return mStringEscapeSequenceAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::charAttribute() const
{
return mCharAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::variableAttribute() const
{
return mVariableAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::functionAttribute() const
{
return mFunctionAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::classAttribute() const
{
return mClassAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::globalVarAttribute() const
{
return mGlobalVarAttribute;
}
PSynHighlighterAttribute SynEditGLSLHighlighter::localVarAttribute() const
{
return mLocalVarAttribute;
}
SynEditGLSLHighlighter::ExtTokenKind SynEditGLSLHighlighter::getExtTokenId()
{
return mExtTokenId;
}
SynTokenKind SynEditGLSLHighlighter::getTokenId()
{
if ((mRange.state == RangeState::rsAsm || mRange.state == RangeState::rsAsmBlock)
&& !mAsmStart && !(mTokenId == TokenKind::Comment || mTokenId == TokenKind::Space
|| mTokenId == TokenKind::Null)) {
return TokenKind::Asm;
} else {
return mTokenId;
}
}
void SynEditGLSLHighlighter::andSymbolProc()
{
mTokenId = TokenKind::Symbol;
switch (mLine[mRun+1].unicode()) {
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::AndAssign;
break;
case '&':
mRun+=2;
mExtTokenId = ExtTokenKind::LogAnd;
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::And;
}
}
void SynEditGLSLHighlighter::ansiCppProc()
{
mTokenId = TokenKind::Comment;
if (mLine[mRun]==0) {
nullProc();
if ( (mRun<1) || (mLine[mRun-1]!='\\')) {
mRange.state = RangeState::rsUnknown;
return;
}
}
while (mLine[mRun]!=0) {
mRun+=1;
}
mRange.state = RangeState::rsCppCommentEnded;
if (mLine[mRun-1] == '\\' && mLine[mRun]==0) { // continues on next line
mRange.state = RangeState::rsCppComment;
}
}
void SynEditGLSLHighlighter::ansiCProc()
{
bool finishProcess = false;
mTokenId = TokenKind::Comment;
if (mLine[mRun].unicode() == 0) {
nullProc();
return;
}
while (mLine[mRun]!=0) {
switch(mLine[mRun].unicode()) {
case '*':
if (mLine[mRun+1] == '/') {
mRun += 2;
if (mRange.state == RangeState::rsAnsiCAsm) {
mRange.state = RangeState::rsAsm;
} else if (mRange.state == RangeState::rsAnsiCAsmBlock){
mRange.state = RangeState::rsAsmBlock;
} else if (mRange.state == RangeState::rsDirectiveComment &&
mLine[mRun] != 0 && mLine[mRun]!='\r' && mLine[mRun]!='\n') {
mRange.state = RangeState::rsMultiLineDirective;
} else {
mRange.state = RangeState::rsUnknown;
}
finishProcess = true;
} else
mRun+=1;
break;
default:
mRun+=1;
}
if (finishProcess)
break;
}
}
void SynEditGLSLHighlighter::asciiCharProc()
{
mTokenId = TokenKind::Char;
do {
if (mLine[mRun] == '\\') {
if (mLine[mRun+1] == '\'' || mLine[mRun+1] == '\\') {
mRun+=1;
}
}
mRun+=1;
} while (mLine[mRun]!=0 && mLine[mRun]!='\'');
if (mLine[mRun] == '\'')
mRun+=1;
mRange.state = RangeState::rsUnknown;
}
void SynEditGLSLHighlighter::atSymbolProc()
{
mTokenId = TokenKind::Unknown;
mRun+=1;
}
void SynEditGLSLHighlighter::braceCloseProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::BraceClose;
if (mRange.state == RangeState::rsAsmBlock) {
mRange.state = rsUnknown;
}
mRange.braceLevel -= 1;
if (mRange.braceLevel<0)
mRange.braceLevel = 0;
if (mRange.leftBraces>0) {
mRange.leftBraces--;
} else {
mRange.rightBraces++ ;
}
popIndents(sitBrace);
}
void SynEditGLSLHighlighter::braceOpenProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::BraceOpen;
if (mRange.state == RangeState::rsAsm) {
mRange.state = RangeState::rsAsmBlock;
mAsmStart = true;
}
mRange.braceLevel += 1;
mRange.leftBraces++;
if (mRange.getLastIndent() == sitStatement) {
// if last indent is started by 'if' 'for' etc
// just replace it
while (mRange.getLastIndent() == sitStatement)
popIndents(sitStatement);
pushIndents(sitBrace);
// int idx = mRange.indents.length()-1;
// if (idx < mRange.firstIndentThisLine) {
// mRange.firstIndentThisLine = idx;
// }
// mRange.indents.replace(idx,1,BraceIndentType);
} else {
pushIndents(sitBrace);
}
}
void SynEditGLSLHighlighter::colonProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1]==':') {
mRun+=2;
mExtTokenId = ExtTokenKind::ScopeResolution;
} else {
mRun+=1;
mExtTokenId = ExtTokenKind::Colon;
}
}
void SynEditGLSLHighlighter::commaProc()
{
mRun+=1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::Comma;
}
void SynEditGLSLHighlighter::directiveProc()
{
QString preContents = mLineString.left(mRun).trimmed();
if (!preContents.isEmpty()) { // '#' is not first non-space char on the line, treat it as an invalid char
mTokenId = TokenKind::Unknown;
mRun+=1;
return;
}
mTokenId = TokenKind::Directive;
mRun+=1;
//skip spaces
while (mLine[mRun]!=0 && isSpaceChar(mLine[mRun])) {
mRun+=1;
}
while (mLine[mRun]!=0 && isIdentChar(mLine[mRun])) {
mRun+=1;
}
mRange.state = RangeState::rsUnknown;
// do {
// switch(mLine[mRun].unicode()) {
// case '/': //comment?
// switch (mLine[mRun+1].unicode()) {
// case '/': // is end of directive as well
// mRange.state = RangeState::rsUnknown;
// return;
// case '*': // might be embeded only
// mRange.state = RangeState::rsDirectiveComment;
// return;
// }
// break;
// case '\\': // yet another line?
// if (mLine[mRun+1] == 0) {
// mRun+=1;
// mRange.state = RangeState::rsMultiLineDirective;
// return;
// }
// break;
// }
// mRun+=1;
// } while (mLine[mRun]!=0);
}
void SynEditGLSLHighlighter::directiveEndProc()
{
mTokenId = TokenKind::Directive;
if (mLine[mRun] == 0) {
nullProc();
return;
}
mRange.state = RangeState::rsUnknown;
do {
switch(mLine[mRun].unicode()) {
case '/': //comment?
switch (mLine[mRun+1].unicode()) {
case '/': // is end of directive as well
mRange.state = RangeState::rsUnknown;
return;
case '*': // might be embeded only
mRange.state = RangeState::rsDirectiveComment;
return;
}
break;
case '\\': // yet another line?
if (mLine[mRun+1] == 0) {
mRun+=1;
mRange.state = RangeState::rsMultiLineDirective;
return;
}
break;
}
mRun+=1;
} while (mLine[mRun]!=0);
}
void SynEditGLSLHighlighter::equalProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1] == '=') {
mRun += 2;
mExtTokenId = ExtTokenKind::LogEqual;
} else {
mRun += 1;
mExtTokenId = ExtTokenKind::Assign;
}
}
void SynEditGLSLHighlighter::greaterProc()
{
mTokenId = TokenKind::Symbol;
switch (mLine[mRun + 1].unicode()) {
case '=':
mRun += 2;
mExtTokenId = ExtTokenKind::GreaterThanEqual;
break;
case '>':
if (mLine[mRun+2] == '=') {
mRun+=3;
mExtTokenId = ExtTokenKind::ShiftRightAssign;
} else {
mRun += 2;
mExtTokenId = ExtTokenKind::ShiftRight;
}
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::GreaterThan;
}
}
void SynEditGLSLHighlighter::identProc()
{
int wordEnd = mRun;
while (isIdentChar(mLine[wordEnd])) {
wordEnd+=1;
}
QString word = mLineString.mid(mRun,wordEnd-mRun);
mRun=wordEnd;
if (isKeyword(word)) {
mTokenId = TokenKind::Key;
if (GLSLStatementKeyWords.contains(word)) {
pushIndents(sitStatement);
}
} else {
mTokenId = TokenKind::Identifier;
}
}
void SynEditGLSLHighlighter::lowerProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun+1].unicode()) {
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::LessThanEqual;
break;
case '<':
if (mLine[mRun+2] == '=') {
mRun+=3;
mExtTokenId = ExtTokenKind::ShiftLeftAssign;
} else {
mRun+=2;
mExtTokenId = ExtTokenKind::ShiftLeft;
}
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::LessThan;
}
}
void SynEditGLSLHighlighter::minusProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun+1].unicode()) {
case '=':
mRun += 2;
mExtTokenId = ExtTokenKind::SubtractAssign;
break;
case '-':
mRun += 2;
mExtTokenId = ExtTokenKind::Decrement;
break;
case '>':
if (mLine[mRun+2]=='*') {
mRun += 3;
mExtTokenId = ExtTokenKind::PointerToMemberOfPointer;
} else {
mRun += 2;
mExtTokenId = ExtTokenKind::Arrow;
}
break;
default:
mRun += 1;
mExtTokenId = ExtTokenKind::Subtract;
}
}
void SynEditGLSLHighlighter::modSymbolProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun + 1].unicode()) {
case '=':
mRun += 2;
mExtTokenId = ExtTokenKind::ModAssign;
break;
default:
mRun += 1;
mExtTokenId = ExtTokenKind::Mod;
}
}
void SynEditGLSLHighlighter::notSymbolProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun + 1].unicode()) {
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::NotEqual;
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::LogComplement;
}
}
void SynEditGLSLHighlighter::nullProc()
{
if ((mRun-1>=0) && isSpaceChar(mLine[mRun-1]) &&
(mRange.state == RangeState::rsCppComment
|| mRange.state == RangeState::rsDirective
|| mRange.state == RangeState::rsString
|| mRange.state == RangeState::rsMultiLineString
|| mRange.state == RangeState::rsMultiLineDirective) ) {
mRange.state = RangeState::rsUnknown;
} else
mTokenId = TokenKind::Null;
}
void SynEditGLSLHighlighter::numberProc()
{
int idx1; // token[1]
idx1 = mRun;
mRun+=1;
mTokenId = TokenKind::Number;
bool shouldExit = false;
while (mLine[mRun]!=0) {
switch(mLine[mRun].unicode()) {
case '\'':
if (mTokenId != TokenKind::Number) {
mTokenId = TokenKind::Symbol;
return;
}
break;
case '.':
if (mLine[mRun+1] == '.') {
mRun+=2;
mTokenId = TokenKind::Unknown;
return;
} else if (mTokenId != TokenKind::Hex) {
mTokenId = TokenKind::Float;
} else {
mTokenId = TokenKind::Unknown;
return;
}
break;
case '-':
case '+':
if (mTokenId != TokenKind::Float) // number <> float. an arithmetic operator
return;
if (mLine[mRun-1]!= 'e' && mLine[mRun-1]!='E') // number = float, but no exponent. an arithmetic operator
return;
if (mLine[mRun+1]<'0' || mLine[mRun+1]>'9') {// invalid
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
if ((mRun == idx1+1) && (mLine[idx1] == '0')) { // octal number
mTokenId = TokenKind::Octal;
}
break;
case '8':
case '9':
if ( (mLine[idx1]=='0') && (mTokenId != TokenKind::Hex) && (mTokenId != TokenKind::Float) ) // invalid octal char
mTokenId = TokenKind::Unknown; // we must continue parse, it may be an float number
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'A':
case 'B':
case 'C':
case 'D':
if (mTokenId!=TokenKind::Hex) { //invalid
mTokenId = TokenKind::Unknown;
return;
}
break;
case 'e':
case 'E':
if (mTokenId!=TokenKind::Hex) {
if (mLine[mRun-1]>='0' || mLine[mRun-1]<='9' ) {//exponent
for (int i=idx1;i='0' && mLine[mRun+1]<='9')) {
return;
} else {
mTokenId = TokenKind::Float;
}
} else {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
}
break;
case 'f':
case 'F':
if (mTokenId!=TokenKind::Hex) {
for (int i=idx1;i='0' && mLine[mRun+1]<='9')
|| (mLine[mRun+1]>='a' && mLine[mRun+1]<='f')
|| (mLine[mRun+1]>='A' && mLine[mRun+1]<='F')) ) {
mTokenId = TokenKind::Hex;
} else {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
break;
default:
shouldExit=true;
}
if (shouldExit) {
break;
}
mRun+=1;
}
if (mLine[mRun-1] == '\'') {
mTokenId = TokenKind::Unknown;
}
}
void SynEditGLSLHighlighter::orSymbolProc()
{
mTokenId = TokenKind::Symbol;
switch ( mLine[mRun+1].unicode()) {
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::IncOrAssign;
break;
case '|':
mRun+=2;
mExtTokenId = ExtTokenKind::LogOr;
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::IncOr;
}
}
void SynEditGLSLHighlighter::plusProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun+1].unicode()){
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::AddAssign;
break;
case '+':
mRun+=2;
mExtTokenId = ExtTokenKind::Increment;
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::Add;
}
}
void SynEditGLSLHighlighter::pointProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1] == '*' ) {
mRun+=2;
mExtTokenId = ExtTokenKind::PointerToMemberOfObject;
} else if (mLine[mRun+1] == '.' && mLine[mRun+2] == '.') {
mRun+=3;
mExtTokenId = ExtTokenKind::Ellipse;
} else if (mLine[mRun+1]>='0' && mLine[mRun+1]<='9') {
numberProc();
} else {
mRun+=1;
mExtTokenId = ExtTokenKind::Point;
}
}
void SynEditGLSLHighlighter::questionProc()
{
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::Question;
mRun+=1;
}
void SynEditGLSLHighlighter::rawStringProc()
{
bool noEscaping = false;
if (mRange.state == RangeState::rsRawStringNotEscaping)
noEscaping = true;
mTokenId = TokenKind::RawString;
mRange.state = RangeState::rsRawString;
while (mLine[mRun]!=0) {
if ((!noEscaping) && (mLine[mRun]=='"')) {
mRun+=1;
break;
}
switch (mLine[mRun].unicode()) {
case '(':
noEscaping = true;
break;
case ')':
noEscaping = false;
break;
}
mRun+=1;
}
mRange.state = RangeState::rsUnknown;
}
void SynEditGLSLHighlighter::roundCloseProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::RoundClose;
mRange.parenthesisLevel--;
if (mRange.parenthesisLevel<0)
mRange.parenthesisLevel=0;
popIndents(sitParenthesis);
}
void SynEditGLSLHighlighter::roundOpenProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::RoundOpen;
mRange.parenthesisLevel++;
pushIndents(sitParenthesis);
}
void SynEditGLSLHighlighter::semiColonProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::SemiColon;
if (mRange.state == RangeState::rsAsm)
mRange.state = RangeState::rsUnknown;
while (mRange.getLastIndent() == sitStatement) {
popIndents(sitStatement);
}
}
void SynEditGLSLHighlighter::slashProc()
{
switch(mLine[mRun+1].unicode()) {
case '/': // Cpp style comment
mTokenId = TokenKind::Comment;
mRun+=2;
mRange.state = RangeState::rsCppComment;
return;
case '*': // C style comment
mTokenId = TokenKind::Comment;
if (mRange.state == RangeState::rsAsm) {
mRange.state = RangeState::rsAnsiCAsm;
} else if (mRange.state == RangeState::rsAsmBlock) {
mRange.state = RangeState::rsAnsiCAsmBlock;
} else if (mRange.state == RangeState::rsDirective) {
mRange.state = RangeState::rsDirectiveComment;
} else {
mRange.state = RangeState::rsAnsiC;
}
mRun += 2;
if (mLine[mRun]!=0)
ansiCProc();
break;
case '=':
mRun+=2;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::DivideAssign;
break;
default:
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::Divide;
}
}
void SynEditGLSLHighlighter::spaceProc()
{
mRun += 1;
mTokenId = TokenKind::Space;
while (mLine[mRun]>=1 && mLine[mRun]<=32)
mRun+=1;
mRange.state = RangeState::rsUnknown;
}
void SynEditGLSLHighlighter::squareCloseProc()
{
mRun+=1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::SquareClose;
mRange.bracketLevel--;
if (mRange.bracketLevel<0)
mRange.bracketLevel=0;
popIndents(sitBracket);
}
void SynEditGLSLHighlighter::squareOpenProc()
{
mRun+=1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::SquareOpen;
mRange.bracketLevel++;
pushIndents(sitBracket);
}
void SynEditGLSLHighlighter::starProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1] == '=') {
mRun += 2;
mExtTokenId = ExtTokenKind::MultiplyAssign;
} else {
mRun += 1;
mExtTokenId = ExtTokenKind::Star;
}
}
void SynEditGLSLHighlighter::stringEndProc()
{
mTokenId = TokenKind::String;
if (mLine[mRun]==0) {
nullProc();
return;
}
mRange.state = RangeState::rsUnknown;
while (mLine[mRun]!=0) {
if (mLine[mRun]=='"') {
mRun += 1;
break;
}
if (mLine[mRun].unicode()=='\\') {
switch(mLine[mRun+1].unicode()) {
case '\'':
case '"':
case '\\':
case '?':
case 'a':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'x':
case 'u':
case 'U':
mRange.state = RangeState::rsMultiLineStringEscapeSeq;
return;
case 0:
mRun+=1;
mRange.state = RangeState::rsMultiLineString;
return;
}
}
mRun += 1;
}
}
void SynEditGLSLHighlighter::stringEscapeSeqProc()
{
mTokenId = TokenKind::StringEscapeSeq;
mRun+=1;
switch(mLine[mRun].unicode()) {
case '\'':
case '"':
case '?':
case 'a':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '\\':
mRun+=1;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
for (int i=0;i<3;i++) {
if (mLine[mRun]<'0' || mLine[mRun]>'7')
break;
mRun+=1;
}
break;
case '8':
case '9':
mTokenId = TokenKind::Unknown;
mRun+=1;
break;
case 'x':
mRun+=1;
if ( !(
(mLine[mRun]>='0' && mLine[mRun]<='9')
|| (mLine[mRun]>='a' && mLine[mRun]<='f')
|| (mLine[mRun]>='A' && mLine[mRun]<='F')
)) {
mTokenId = TokenKind::Unknown;
} else {
while (
(mLine[mRun]>='0' && mLine[mRun]<='9')
|| (mLine[mRun]>='a' && mLine[mRun]<='f')
|| (mLine[mRun]>='A' && mLine[mRun]<='F')
) {
mRun+=1;
}
}
break;
case 'u':
mRun+=1;
for (int i=0;i<4;i++) {
if (mLine[mRun]<'0' || mLine[mRun]>'7') {
mTokenId = TokenKind::Unknown;
return;
}
mRun+=1;
}
break;
case 'U':
mRun+=1;
for (int i=0;i<8;i++) {
if (mLine[mRun]<'0' || mLine[mRun]>'7') {
mTokenId = TokenKind::Unknown;
return;
}
mRun+=1;
}
break;
}
if (mRange.state == RangeState::rsMultiLineStringEscapeSeq)
mRange.state = RangeState::rsMultiLineString;
else
mRange.state = RangeState::rsString;
}
void SynEditGLSLHighlighter::stringProc()
{
if (mLine[mRun] == 0) {
mRange.state = RangeState::rsUnknown;
return;
}
mTokenId = TokenKind::String;
mRange.state = RangeState::rsString;
while (mLine[mRun]!=0) {
if (mLine[mRun]=='"') {
mRun+=1;
break;
}
if (mLine[mRun].unicode()=='\\') {
switch(mLine[mRun+1].unicode()) {
case '\'':
case '"':
case '\\':
case '?':
case 'a':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'x':
case 'u':
case 'U':
mRange.state = RangeState::rsStringEscapeSeq;
return;
case 0:
mRun+=1;
mRange.state = RangeState::rsMultiLineString;
return;
}
}
mRun+=1;
}
mRange.state = RangeState::rsUnknown;
}
void SynEditGLSLHighlighter::stringStartProc()
{
mTokenId = TokenKind::String;
mRun += 1;
if (mLine[mRun]==0) {
mRange.state = RangeState::rsUnknown;
return;
}
stringProc();
}
void SynEditGLSLHighlighter::tildeProc()
{
mRun+=1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::BitComplement;
}
void SynEditGLSLHighlighter::unknownProc()
{
mRun+=1;
mTokenId = TokenKind::Unknown;
}
void SynEditGLSLHighlighter::xorSymbolProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1]=='=') {
mRun+=2;
mExtTokenId = ExtTokenKind::XorAssign;
} else {
mRun+=1;
mExtTokenId = ExtTokenKind::Xor;
}
}
void SynEditGLSLHighlighter::processChar()
{
switch(mLine[mRun].unicode()) {
case '&':
andSymbolProc();
break;
case '\'':
asciiCharProc();
break;
case '@':
atSymbolProc();
break;
case '}':
braceCloseProc();
break;
case '{':
braceOpenProc();
break;
case '\r':
case '\n':
spaceProc();
break;
case ':':
colonProc();
break;
case ',':
commaProc();
break;
case '#':
directiveProc();
break;
case '=':
equalProc();
break;
case '>':
greaterProc();
break;
case '?':
questionProc();
break;
case '<':
lowerProc();
break;
case '-':
minusProc();
break;
case '%':
modSymbolProc();
break;
case '!':
notSymbolProc();
break;
case 0:
nullProc();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
numberProc();
break;
case '|':
orSymbolProc();
break;
case '+':
plusProc();
break;
case '.':
pointProc();
break;
case ')':
roundCloseProc();
break;
case '(':
roundOpenProc();
break;
case ';':
semiColonProc();
break;
case '/':
slashProc();
break;
case ']':
squareCloseProc();
break;
case '[':
squareOpenProc();
break;
case '*':
starProc();
break;
case '"':
stringStartProc();
break;
case '~':
tildeProc();
break;
case '^':
xorSymbolProc();
break;
default:
if (isIdentChar(mLine[mRun])) {
identProc();
} else if (isSpaceChar(mLine[mRun])) {
spaceProc();
} else {
unknownProc();
}
}
}
void SynEditGLSLHighlighter::popIndents(int indentType)
{
while (!mRange.indents.isEmpty() && mRange.indents.back()!=indentType) {
mRange.indents.pop_back();
}
if (!mRange.indents.isEmpty()) {
int idx = mRange.indents.length()-1;
if (idx < mRange.firstIndentThisLine) {
mRange.matchingIndents.append(mRange.indents[idx]);
}
mRange.indents.pop_back();
}
}
void SynEditGLSLHighlighter::pushIndents(int indentType)
{
int idx = mRange.indents.length();
if (idx='a' && ch<='z') || (ch>='A' && ch<='Z') || (ch>='0' && ch<='9');
}
QSet SynEditGLSLHighlighter::keywords() const
{
return Keywords;
}