/* * 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; }