diff --git a/TestPlugin/cmake/TranslationUtils.cmake b/TestPlugin/cmake/TranslationUtils.cmake index 07028b9..7f6b926 100644 --- a/TestPlugin/cmake/TranslationUtils.cmake +++ b/TestPlugin/cmake/TranslationUtils.cmake @@ -4,7 +4,7 @@ # You can redistribute this file and/or modify it under the terms of the BSD # 3-Clause. # -# THIS FILE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND +# THIS FILE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE diff --git a/src/class/ascompletion.cpp b/src/class/ascompletion.cpp index 277ed98..40a691c 100644 --- a/src/class/ascompletion.cpp +++ b/src/class/ascompletion.cpp @@ -64,8 +64,10 @@ AsCompletion::AsCompletion(WingCodeEdit *p) AsCompletion::~AsCompletion() {} -void AsCompletion::applyEmptyNsNode(QList &nodes) { +void AsCompletion::applyEmptyNsNode(QList &nodes, + const QList &docNodes) { static QList emptyNsNodes; + if (emptyNsNodes.isEmpty()) { auto &hn = parser.headerNodes(); for (auto p = hn.constKeyValueBegin(); p != hn.constKeyValueEnd(); @@ -81,6 +83,24 @@ void AsCompletion::applyEmptyNsNode(QList &nodes) { } emptyNsNodes.append(parser.keywordNodes()); } + + nodes.clear(); + + for (auto &p : docNodes) { + if (p.nameSpace.isEmpty()) { + nodes.append(p); + } else { + if (p.dontAddGlobal) { + continue; + } + + CodeInfoTip tip; + tip.type = CodeInfoTip::Type::Group; + tip.name = p.nameSpace; + nodes.append(tip); + } + } + nodes.append(emptyNsNodes); } @@ -134,9 +154,10 @@ void AsCompletion::processTrigger(const QString &trigger, auto code = content.toUtf8(); QList nodes; + QList docNodes; if (m_parseDocument) { - nodes.append(parseDocument()); + docNodes = parseDocument(); } if (!trigger.isEmpty() && trigger != *DOT_TRIGGER) { @@ -213,7 +234,7 @@ void AsCompletion::processTrigger(const QString &trigger, prefix = etoken.content; tokens.removeLast(); if (tokens.isEmpty()) { - applyEmptyNsNode(nodes); + applyEmptyNsNode(nodes, docNodes); } else { etoken = tokens.back(); // checking later } @@ -231,7 +252,7 @@ void AsCompletion::processTrigger(const QString &trigger, setCompletionPrefix(prefix); return; } else { - applyEmptyNsNode(nodes); + applyEmptyNsNode(nodes, docNodes); } } else if (etoken.type != asTC_IDENTIFIER) { popup()->hide(); @@ -251,7 +272,14 @@ void AsCompletion::processTrigger(const QString &trigger, return; } } - nodes = parser.headerNodes().value(ns); + nodes = parser.headerNodes().value(ns) + + parser.enumsNodes().value(ns); + for (auto &n : docNodes) { + if (n.nameSpace == ns) { + nodes.append(n); + } + } + if (nodes.isEmpty()) { return; } @@ -272,9 +300,11 @@ void AsCompletion::processTrigger(const QString &trigger, return; } } + nodes = parser.headerNodes().value(ns); + if (nodes.isEmpty()) { - applyEmptyNsNode(nodes); + applyEmptyNsNode(nodes, docNodes); } } } @@ -291,9 +321,10 @@ QList AsCompletion::parseDocument() { } auto code = editor->toPlainText(); + auto engine = ScriptMachine::instance().engine(); // first preprocess the code - AsPreprocesser prepc(ScriptMachine::instance().engine()); + AsPreprocesser prepc(engine); // TODO: set include callback // prepc.setIncludeCallback(); @@ -307,7 +338,7 @@ QList AsCompletion::parseDocument() { QList ret; for (auto &d : data) { - QAsCodeParser parser(ScriptMachine::instance().engine()); + QAsCodeParser parser(engine); auto syms = parser.parseAndIntell(editor->textCursor().position(), d.script); @@ -326,12 +357,28 @@ QList AsCompletion::parseDocument() { break; case QAsCodeParser::SymbolType::Enum: tip.type = CodeInfoTip::Type::Enum; + for (auto &e : sym.children) { + CodeInfoTip en; + en.dontAddGlobal = true; + en.name = e.name; + en.nameSpace = QString::fromUtf8(e.scope.join("::")); + en.type = CodeInfoTip::Type::Enumerater; + if (!e.additonalInfo.isEmpty()) { + en.addinfo.insert(CodeInfoTip::Comment, + en.name + QStringLiteral(" = ") + + e.additonalInfo); + } + ret.append(en); + } + break; + case QAsCodeParser::SymbolType::TypeDef: + tip.type = CodeInfoTip::Type::KeyWord; break; case QAsCodeParser::SymbolType::Variable: + tip.type = CodeInfoTip::Type::Variable; + break; case QAsCodeParser::SymbolType::Class: - case QAsCodeParser::SymbolType::TypeDef: case QAsCodeParser::SymbolType::FnDef: - case QAsCodeParser::SymbolType::VarsDecl: case QAsCodeParser::SymbolType::Invalid: continue; } diff --git a/src/class/ascompletion.h b/src/class/ascompletion.h index 4879de7..525e01a 100644 --- a/src/class/ascompletion.h +++ b/src/class/ascompletion.h @@ -51,7 +51,8 @@ public: virtual bool eventFilter(QObject *watched, QEvent *event) override; private: - void applyEmptyNsNode(QList &nodes); + void applyEmptyNsNode(QList &nodes, + const QList &docNodes); void applyClassNodes(QList &nodes); private: diff --git a/src/class/asdatabase.cpp b/src/class/asdatabase.cpp index 1678271..9412fe7 100644 --- a/src/class/asdatabase.cpp +++ b/src/class/asdatabase.cpp @@ -177,6 +177,10 @@ const QHash> &ASDataBase::headerNodes() const { return _headerNodes; } +const QHash> &ASDataBase::enumsNodes() const { + return _enumsNodes; +} + void ASDataBase::addGlobalFunctionCompletion(asIScriptEngine *engine) { Q_ASSERT(engine); @@ -210,6 +214,13 @@ void ASDataBase::addEnumCompletion(asIScriptEngine *engine) { einfo.name = etype->GetName(); einfo.type = CodeInfoTip::Type::Enum; + auto ens = einfo.nameSpace; + if (ens.isEmpty()) { + ens = einfo.name; + } else { + ens += QStringLiteral("::") + einfo.name; + } + for (asUINT i = 0; i < etype->GetEnumValueCount(); ++i) { int v; auto e = etype->GetEnumValueByIndex(i, &v); @@ -221,6 +232,7 @@ void ASDataBase::addEnumCompletion(asIScriptEngine *engine) { QStringLiteral(" = ") + QString::number(v)); einfo.children.append(en); + _enumsNodes[ens].append(en); } etype->Release(); diff --git a/src/class/asdatabase.h b/src/class/asdatabase.h index 278d5a1..695ac8d 100644 --- a/src/class/asdatabase.h +++ b/src/class/asdatabase.h @@ -42,6 +42,7 @@ private: public: const QHash> &headerNodes() const; + const QHash> &enumsNodes() const; const QList &keywordNodes() const; @@ -55,6 +56,7 @@ private: private: // QHash> _headerNodes; + QHash> _enumsNodes; QList _keywordNode; }; diff --git a/src/class/codeinfotip.h b/src/class/codeinfotip.h index e1ed2a1..7c17167 100644 --- a/src/class/codeinfotip.h +++ b/src/class/codeinfotip.h @@ -78,6 +78,7 @@ public: public: QString name; + bool dontAddGlobal = false; Type type = Type::Unknown; QString nameSpace; CodeInfoVisibility visualpo = CodeInfoVisibility::VISIBILITY_DEFAULT; diff --git a/src/class/qascodeparser.cpp b/src/class/qascodeparser.cpp index c35bacc..c337c0a 100644 --- a/src/class/qascodeparser.cpp +++ b/src/class/qascodeparser.cpp @@ -25,19 +25,21 @@ * * Strings are also included. * * AngelScript's class and enum can not be nested unlike C++. * * We only support class / mixin class / interface / function / enum. + * + * * auto type can not be derived by this class, PRs are welcomed */ QAsCodeParser::QAsCodeParser(asCScriptEngine *engine) : engine(engine) { Q_ASSERT(engine); - checkValidTypes = false; - isParsingAppInterface = false; + _checkValidTypes = false; + _isParsingAppInterface = false; } QAsCodeParser::QAsCodeParser(asIScriptEngine *engine) { this->engine = dynamic_cast(engine); Q_ASSERT(engine); - checkValidTypes = false; - isParsingAppInterface = false; + _checkValidTypes = false; + _isParsingAppInterface = false; } QAsCodeParser::~QAsCodeParser() {} @@ -45,7 +47,7 @@ QAsCodeParser::~QAsCodeParser() {} QList QAsCodeParser::parse(const QByteArray &codes) { reset(); - code = codes; + _code = codes; return parseScript(false); } @@ -57,11 +59,16 @@ QAsCodeParser::parseAndIntell(qsizetype offset, const QByteArray &codes) { QList QAsCodeParser::parseIntell(qsizetype offset, const QList &segs) { + reset(); QList ret; // first: global entries for (auto &seg : segs) { + if (!seg.isValid()) { + continue; + } + Symbol sym; sym.symtype = seg.type; sym.scope = seg.scope; @@ -73,14 +80,29 @@ QAsCodeParser::parseIntell(qsizetype offset, sym.type = seg.additonalInfos.at(0); sym.additonalInfo = seg.additonalInfos.at(1); sym.name = seg.name; + if (offset > seg.offset && offset < seg.length()) { + // TODO: deep parsing + } } break; case SymbolType::Enum: + if (offset < seg.offset || offset >= seg.length()) { + sym.children = + parseEnumerationContent(sym.scope, sym.name, seg.codes); + } + break; + case SymbolType::TypeDef: + if (offset < seg.offset || offset >= seg.length()) { + sym = parseTypedefContent(sym.scope, seg.codes); + } break; case SymbolType::Variable: + if (offset < seg.offset || offset >= seg.length()) { + ret << parseGlobalVarDecls(sym.scope, seg.codes); + continue; + } + break; case SymbolType::Class: - case SymbolType::TypeDef: case SymbolType::FnDef: - case SymbolType::VarsDecl: case SymbolType::Invalid: continue; } @@ -94,21 +116,24 @@ QAsCodeParser::parseIntell(qsizetype offset, } void QAsCodeParser::reset() { - errorWhileParsing = false; - isSyntaxError = false; - checkValidTypes = false; - isParsingAppInterface = false; + _errorWhileParsing = false; + _isSyntaxError = false; + _checkValidTypes = false; + _isParsingAppInterface = false; - sourcePos = 0; + _sourcePos = 0; + _code.clear(); - lastToken.pos = size_t(-1); + _lastToken.length = 0; + _lastToken.type = ttUnrecognizedToken; + _lastToken.pos = size_t(-1); } void QAsCodeParser::getToken(sToken *token) { // Check if the token has already been parsed - if (lastToken.pos == sourcePos) { - *token = lastToken; - sourcePos += token->length; + if (_lastToken.pos == _sourcePos) { + *token = _lastToken; + _sourcePos += token->length; if (token->type == ttWhiteSpace || token->type == ttOnelineComment || token->type == ttMultilineComment) @@ -118,20 +143,20 @@ void QAsCodeParser::getToken(sToken *token) { } // Parse new token - size_t sourceLength = code.length(); + size_t sourceLength = _code.length(); do { - if (sourcePos >= sourceLength) { + if (_sourcePos >= sourceLength) { token->type = ttEnd; token->length = 0; } else token->type = - engine->tok.GetToken(code.data() + sourcePos, - sourceLength - sourcePos, &token->length); + engine->tok.GetToken(_code.data() + _sourcePos, + sourceLength - _sourcePos, &token->length); - token->pos = sourcePos; + token->pos = _sourcePos; // Update state - sourcePos += token->length; + _sourcePos += token->length; } // Filter out whitespace and comments while (token->type == ttWhiteSpace || token->type == ttOnelineComment || @@ -145,40 +170,40 @@ void QAsCodeParser::rewindTo(const sToken *token) { // no token will have to be tokenized more than once. // Store the token so it doesn't have to be tokenized again - lastToken = *token; + _lastToken = *token; - sourcePos = token->pos; + _sourcePos = token->pos; } -void QAsCodeParser::SetPos(size_t pos) { - lastToken.pos = size_t(-1); - sourcePos = pos; +void QAsCodeParser::setPos(size_t pos) { + _lastToken.pos = size_t(-1); + _sourcePos = pos; } void QAsCodeParser::rewindErrorTo(sToken *token) { rewindTo(token); - isSyntaxError = true; - errorWhileParsing = true; + _isSyntaxError = true; + _errorWhileParsing = true; } QAsCodeParser::Symbol QAsCodeParser::parseFunctionDefinition() { auto ret = parseType(true); - if (isSyntaxError) + if (_isSyntaxError) return {}; ParseTypeMod(false); - if (isSyntaxError) + if (_isSyntaxError) return {}; - auto ns = ParseOptionalScope(); + auto ns = parseOptionalScope(); auto id = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return {}; auto params = parseParameterListContent(); - if (isSyntaxError) + if (_isSyntaxError) return {}; // ok, add symbol @@ -233,12 +258,12 @@ QList QAsCodeParser::parseParameterListContent() { for (;;) { // Parse data type - auto t = parseType(true, isParsingAppInterface); - if (isSyntaxError) + auto t = parseType(true, _isParsingAppInterface); + if (_isSyntaxError) return ret; ParseTypeMod(true); - if (isSyntaxError) + if (_isSyntaxError) return ret; // Parse optional identifier @@ -253,7 +278,7 @@ QList QAsCodeParser::parseParameterListContent() { // se.typeStr = getSymbolString(t); ret.append(se); - if (isSyntaxError) + if (_isSyntaxError) return ret; getToken(&t1); @@ -265,7 +290,7 @@ QList QAsCodeParser::parseParameterListContent() { // The actual parsing will be done when the argument is compiled // for a function call superficiallyParseExpression(); - if (isSyntaxError) + if (_isSyntaxError) return ret; getToken(&t1); @@ -347,6 +372,30 @@ void QAsCodeParser::superficiallyParseExpression() { } } +void QAsCodeParser::superficiallyParseTemplateList() { + sToken t; + + // Starts with '<' + getToken(&t); + if (t.type != ttLessThan) { + return; + } + + // End with '>' + // Accept >> and >>> tokens too. But then force the tokenizer to move + // only 1 character ahead (thus splitting the token in two). + while (true) { + getToken(&t); + if (_code.length() <= t.pos) { + break; + } + if (_code[QString::size_type(t.pos)] == '>') { + setPos(t.pos + 1); + break; + } + } +} + sToken QAsCodeParser::parseType(bool allowConst, bool allowVariableType, bool allowAuto) { sToken t; @@ -356,17 +405,17 @@ sToken QAsCodeParser::parseType(bool allowConst, bool allowVariableType, rewindTo(&t); if (t.type == ttConst) { parseToken(ttConst); - if (isSyntaxError) + if (_isSyntaxError) return t; } } // Parse scope prefix - ParseOptionalScope(); + parseOptionalScope(); // Parse the actual type auto dt = parseDataType(allowVariableType, allowAuto); - if (isSyntaxError) + if (_isSyntaxError) return t; // If the datatype is a template type, then parse the subtype within the < > @@ -375,9 +424,7 @@ sToken QAsCodeParser::parseType(bool allowConst, bool allowVariableType, tempString = getSymbolString(dt); if (engine->IsTemplateType(tempString) && t.type == ttLessThan) { - parseTemplTypeList(); - if (isSyntaxError) - return t; + superficiallyParseTemplateList(); } // Parse [] and @ @@ -386,7 +433,7 @@ sToken QAsCodeParser::parseType(bool allowConst, bool allowVariableType, while (t.type == ttOpenBracket || t.type == ttHandle) { if (t.type == ttOpenBracket) { parseToken(ttOpenBracket); - if (isSyntaxError) + if (_isSyntaxError) return t; getToken(&t); @@ -396,14 +443,14 @@ sToken QAsCodeParser::parseType(bool allowConst, bool allowVariableType, } } else { parseToken(ttHandle); - if (isSyntaxError) + if (_isSyntaxError) return t; getToken(&t); rewindTo(&t); if (t.type == ttConst) { parseToken(ttConst); - if (isSyntaxError) + if (_isSyntaxError) return t; } } @@ -423,7 +470,7 @@ void QAsCodeParser::ParseTypeMod(bool isParam) { rewindTo(&t); if (t.type == ttAmp) { parseToken(ttAmp); - if (isSyntaxError) + if (_isSyntaxError) return; if (isParam) { @@ -442,7 +489,7 @@ void QAsCodeParser::ParseTypeMod(bool isParam) { rewindTo(&t); if (t.type == ttPlus) { parseToken(ttPlus); - if (isSyntaxError) + if (_isSyntaxError) return; } @@ -451,12 +498,12 @@ void QAsCodeParser::ParseTypeMod(bool isParam) { rewindTo(&t); if (identifierIs(t, IF_HANDLE_TOKEN)) { parseToken(ttIdentifier); - if (isSyntaxError) + if (_isSyntaxError) return; } } -QByteArrayList QAsCodeParser::ParseOptionalScope() { +QByteArrayList QAsCodeParser::parseOptionalScope() { QByteArrayList scopes; sToken t1, t2; @@ -483,19 +530,18 @@ QByteArrayList QAsCodeParser::ParseOptionalScope() { if (engine->IsTemplateType(tempString)) { rewindTo(&t1); parseIdentifier(); - if (parseTemplTypeList(false)) { - getToken(&t2); - if (t2.type == ttScope) { - // Template type is part of the scope - // Nothing more needs to be done + superficiallyParseTemplateList(); + getToken(&t2); + if (t2.type == ttScope) { + // Template type is part of the scope + // Nothing more needs to be done - return scopes; - } else { - // The template type is not part of the scope - // Rewind to the template type and end the scope - rewindTo(&t1); - return scopes; - } + return scopes; + } else { + // The template type is not part of the scope + // Rewind to the template type and end the scope + rewindTo(&t1); + return scopes; } } } @@ -510,7 +556,7 @@ sToken QAsCodeParser::parseRealType() { sToken t1; getToken(&t1); - if (!isRealType(t1.type)) { + if (!isPrimType(t1.type)) { rewindErrorTo(&t1); } @@ -541,60 +587,6 @@ sToken QAsCodeParser::parseIdentifier() { return t1; } -bool QAsCodeParser::parseTemplTypeList(bool required) { - sToken t; - bool isValid = true; - - // Remember the last child, so we can restore the state if needed - // asCScriptNode *last = node->lastChild; - - // Starts with '<' - getToken(&t); - if (t.type != ttLessThan) { - if (required) { - rewindErrorTo(&t); - } - return false; - } - - // At least one type - // TODO: child funcdef: Make this work with !required - parseType(true, false); - if (isSyntaxError) - return false; - - getToken(&t); - - // Parse template types by list separator - while (t.type == ttListSeparator) { - // TODO: child funcdef: Make this work with !required - parseType(true, false); - if (isSyntaxError) - return false; - getToken(&t); - } - - // End with '>' - // Accept >> and >>> tokens too. But then force the tokenizer to move - // only 1 character ahead (thus splitting the token in two). - if (code[QString::size_type(t.pos)] != '>') { - if (required) { - rewindErrorTo(&t); - } else - isValid = false; - } else { - // Break the token so that only the first > is parsed - SetPos(t.pos + 1); - } - - if (!required && !isValid) { - return false; - } - - // The template type list was parsed OK - return true; -} - void QAsCodeParser::parseMethodAttributes() { sToken t1; @@ -624,7 +616,7 @@ void QAsCodeParser::ParseListPattern() { bool isBeginning = true; bool afterType = false; - while (!isSyntaxError) { + while (!_isSyntaxError) { getToken(&t1); if (t1.type == ttEndStatementBlock) { if (!afterType) { @@ -668,7 +660,7 @@ void QAsCodeParser::ParseListPattern() { } } -bool QAsCodeParser::isRealType(int tokenType) { +bool QAsCodeParser::isPrimType(int tokenType) { if (tokenType == ttVoid || tokenType == ttInt || tokenType == ttInt8 || tokenType == ttInt16 || tokenType == ttInt64 || tokenType == ttUInt || tokenType == ttUInt8 || tokenType == ttUInt16 || @@ -682,7 +674,7 @@ bool QAsCodeParser::isRealType(int tokenType) { bool QAsCodeParser::isDataType(const sToken &token) { if (token.type == ttIdentifier) { #ifndef AS_NO_COMPILER - if (checkValidTypes) { + if (_checkValidTypes) { // Check if this is an existing type, regardless of namespace tempString = getSymbolString(token); if (!typeExist(tempString)) @@ -692,7 +684,7 @@ bool QAsCodeParser::isDataType(const sToken &token) { return true; } - if (isRealType(token.type)) + if (isPrimType(token.type)) return true; return false; @@ -702,7 +694,7 @@ bool QAsCodeParser::identifierIs(const sToken &t, const char *str) { if (t.type != ttIdentifier) return false; - return code.sliced(t.pos, t.length) == QByteArray(str); + return _code.sliced(t.pos, t.length) == QByteArray(str); } sToken QAsCodeParser::superficiallyParseStatementBlock() { @@ -719,7 +711,7 @@ sToken QAsCodeParser::superficiallyParseStatementBlock() { sToken start = t1; int level = 1; - while (level > 0 && !isSyntaxError) { + while (level > 0 && !_isSyntaxError) { getToken(&t1); if (t1.type == ttEndStatementBlock) level--; @@ -749,7 +741,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction() { identifierIs(t1, EXTERNAL_TOKEN)) { rewindTo(&t1); parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return seg; } else break; @@ -757,7 +749,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction() { getToken(&t1); } - if (isSyntaxError) + if (_isSyntaxError) return seg; // If it is a global function, or a method, except constructor and @@ -770,12 +762,12 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction() { if (t1.type != ttBitNot && t2.type != ttOpenParenthesis) { auto id = parseType(true); - if (isSyntaxError) + if (_isSyntaxError) return seg; rettype = getSymbolString(id); ParseTypeMod(false); - if (isSyntaxError) + if (_isSyntaxError) return seg; } else { rewindErrorTo(&t1); @@ -786,7 +778,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction() { seg.additonalInfos.append(rettype); auto iden = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return seg; seg.name = getSymbolString(iden); seg.offset = iden.pos; @@ -823,13 +815,13 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction() { } auto end = t1.pos; - seg.additonalInfos.append(code.sliced(begin, end - begin)); + seg.additonalInfos.append(_code.sliced(begin, end - begin)); } // TODO: Should support abstract methods, in which case no statement block // should be provided parseMethodAttributes(); - if (isSyntaxError) + if (_isSyntaxError) return seg; // External shared functions must be ended with ';' @@ -848,7 +840,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction() { // We should just find the end of the statement block here. t1 = superficiallyParseStatementBlock(); auto end = t1.pos; - seg.codes = code.sliced(begin, end - begin + 1); + seg.codes = _code.sliced(begin, end - begin + 1); return seg; } @@ -861,7 +853,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFuncDef() { while (identifierIs(t1, SHARED_TOKEN) || identifierIs(t1, EXTERNAL_TOKEN)) { rewindTo(&t1); - if (isSyntaxError) + if (_isSyntaxError) return seg; getToken(&t1); @@ -881,7 +873,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFuncDef() { seg.scope = currentNs; seg.offset = begin; seg.type = SymbolType::FnDef; - seg.codes = code.sliced(begin, end - begin + 1); + seg.codes = _code.sliced(begin, end - begin + 1); return seg; } @@ -895,7 +887,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseInterface() { rewindTo(&t); parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return seg; getToken(&t); @@ -924,46 +916,43 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseInterface() { rewindTo(&t); t = superficiallyParseStatementBlock(); auto end = t.pos; - seg.codes = code.sliced(begin, end - begin + 1); + seg.codes = _code.sliced(begin, end - begin + 1); return seg; } -sToken QAsCodeParser::superficiallyParseVarInit() { +void QAsCodeParser::superficiallyParseVarInit() { sToken t; getToken(&t); if (t.type == ttAssignment) { getToken(&t); sToken start = t; + rewindTo(&t); // Find the end of the expression int indentParan = 0; int indentBrace = 0; - while (indentParan || indentBrace || - (t.type != ttListSeparator && t.type != ttEndStatement && - t.type != ttEndStatementBlock)) { - if (t.type == ttOpenParenthesis) + do { + getToken(&t); + if (t.type == ttOpenParenthesis) { indentParan++; - else if (t.type == ttCloseParenthesis) + } else if (t.type == ttCloseParenthesis) { indentParan--; - else if (t.type == ttStartStatementBlock) + } else if (t.type == ttStartStatementBlock) { indentBrace++; - else if (t.type == ttEndStatementBlock) + } else if (t.type == ttEndStatementBlock) { indentBrace--; - else if (t.type == ttNonTerminatedStringConstant) { + } else if (t.type == ttNonTerminatedStringConstant) { rewindErrorTo(&t); break; } else if (t.type == ttEnd) { - rewindErrorTo(&start); + rewindErrorTo(&t); break; } - getToken(&t); - } - - // Rewind so that the next token read is the list separator, end - // statement, or end statement block - rewindTo(&t); + } while (indentParan || indentBrace || + (t.type != ttListSeparator && t.type != ttEndStatement && + t.type != ttEndStatementBlock)); } else if (t.type == ttOpenParenthesis) { sToken start = t; @@ -986,8 +975,6 @@ sToken QAsCodeParser::superficiallyParseVarInit() { } else { rewindErrorTo(&t); } - - return t; } void QAsCodeParser::parseStatementBlock() { @@ -1002,7 +989,7 @@ void QAsCodeParser::parseStatementBlock() { sToken start = t1; for (;;) { - while (!isSyntaxError) { + while (!_isSyntaxError) { getToken(&t1); if (t1.type == ttEndStatementBlock) { @@ -1011,14 +998,14 @@ void QAsCodeParser::parseStatementBlock() { } else { rewindTo(&t1); - if (isVarDecl()) - parseDeclaration(); - else - parseStatement(); + // if (isVarDecl()) + // parseDeclaration(); + // else + // parseStatement(); } } - if (isSyntaxError) { + if (_isSyntaxError) { // Search for either ';', '{', '}', or end getToken(&t1); while (t1.type != ttEndStatement && t1.type != ttEnd && @@ -1047,7 +1034,7 @@ void QAsCodeParser::parseStatementBlock() { return; } - isSyntaxError = false; + _isSyntaxError = false; } } UNREACHABLE_RETURN; @@ -1098,7 +1085,7 @@ void QAsCodeParser::ParseExpressionStatement() { rewindTo(&t); ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1123,7 +1110,7 @@ void QAsCodeParser::ParseSwitch() { } ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1138,7 +1125,7 @@ void QAsCodeParser::ParseSwitch() { return; } - while (!isSyntaxError) { + while (!_isSyntaxError) { getToken(&t); if (t.type == ttEndStatementBlock) @@ -1152,7 +1139,7 @@ void QAsCodeParser::ParseSwitch() { } ParseCase(); - if (isSyntaxError) + if (_isSyntaxError) return; } @@ -1185,13 +1172,12 @@ void QAsCodeParser::ParseCase() { rewindTo(&t); while (t.type != ttCase && t.type != ttDefault && t.type != ttEndStatementBlock && t.type != ttBreak) { - if (isVarDecl()) - // Variable declarations are not allowed, but we parse it anyway to - // give a good error message - parseDeclaration(); - else - parseStatement(); - if (isSyntaxError) + // if (isVarDecl()) + // Variable declarations are not allowed, but we parse it anyway to + // give a good error message + // parseDeclaration(); + // else parseStatement(); + if (_isSyntaxError) return; getToken(&t); @@ -1218,7 +1204,7 @@ void QAsCodeParser::ParseIf() { } ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1228,7 +1214,7 @@ void QAsCodeParser::ParseIf() { } parseStatement(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1256,15 +1242,15 @@ void QAsCodeParser::ParseFor() { return; } - if (isVarDecl()) - parseDeclaration(); - else - ParseExpressionStatement(); - if (isSyntaxError) + // if (isVarDecl()) + // parseDeclaration(); + // else + // ParseExpressionStatement(); + if (_isSyntaxError) return; ParseExpressionStatement(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1275,7 +1261,7 @@ void QAsCodeParser::ParseFor() { for (;;) { ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1308,7 +1294,7 @@ void QAsCodeParser::ParseWhile() { } ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1330,7 +1316,7 @@ void QAsCodeParser::ParseDoWhile() { } parseStatement(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1346,7 +1332,7 @@ void QAsCodeParser::ParseDoWhile() { } ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1379,7 +1365,7 @@ void QAsCodeParser::ParseReturn() { rewindTo(&t); ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1428,7 +1414,7 @@ void QAsCodeParser::ParseTryCatch() { } parseStatementBlock(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -1438,13 +1424,13 @@ void QAsCodeParser::ParseTryCatch() { } parseStatementBlock(); - if (isSyntaxError) + if (_isSyntaxError) return; } -QList QAsCodeParser::parseDeclaration(bool isClassProp, - bool isGlobalVar) { - +QList +QAsCodeParser::parseDeclaration(const QByteArrayList &ns, bool isClassProp, + bool isGlobalVar) { QList ret; Symbol sym; @@ -1463,19 +1449,20 @@ QList QAsCodeParser::parseDeclaration(bool isClassProp, // Parse data type auto dt = parseType(true, false, !isClassProp); - if (isSyntaxError) + if (_isSyntaxError) return ret; - // sym.typeStr = getSymbolString(dt); + sym.type = getSymbolString(dt); for (;;) { // Parse identifier auto id = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return ret; sym.name = getSymbolString(id); - // sym.nameInSrc = id.pos; + sym.offset = id.pos; + sym.symtype = QAsCodeParser::SymbolType::Variable; if (isClassProp || isGlobalVar) { // Only superficially parse the initialization RewindErrorTo for the @@ -1484,7 +1471,7 @@ QList QAsCodeParser::parseDeclaration(bool isClassProp, rewindTo(&t); if (t.type == ttAssignment || t.type == ttOpenParenthesis) { superficiallyParseVarInit(); - if (isSyntaxError) + if (_isSyntaxError) return ret; } } else { @@ -1493,18 +1480,18 @@ QList QAsCodeParser::parseDeclaration(bool isClassProp, if (t.type == ttOpenParenthesis) { rewindTo(&t); parseArgList(); - if (isSyntaxError) + if (_isSyntaxError) return ret; } else if (t.type == ttAssignment) { getToken(&t); rewindTo(&t); if (t.type == ttStartStatementBlock) { ParseInitList(); - if (isSyntaxError) + if (_isSyntaxError) return ret; } else { ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return ret; } } else @@ -1514,11 +1501,9 @@ QList QAsCodeParser::parseDeclaration(bool isClassProp, // continue if list separator, else terminate with end statement getToken(&t); if (t.type == ttListSeparator) { - // sym.type = SymbolType::Variable; ret.append(sym); continue; } else if (t.type == ttEndStatement) { - // sym.type = SymbolType::Variable; ret.append(sym); return ret; } else { @@ -1533,7 +1518,7 @@ QList QAsCodeParser::parseScript(bool inBlock) { QList segs; for (;;) { - while (!isSyntaxError) { + while (!_isSyntaxError) { sToken tStart; getToken(&tStart); @@ -1550,18 +1535,20 @@ QList QAsCodeParser::parseScript(bool inBlock) { if (t1.type == ttImport) { // import we don't support just skip skipCodeBlock(); + // add empty invalid segment + segs << CodeSegment(); } else if (t1.type == ttEnum) // Handle enumerations - appendValidSeg(segs, parseEnumeration()); + segs << parseEnumeration(); else if (t1.type == ttTypedef) // Handle primitive typedefs - appendValidSeg(segs, parseTypedef()); + segs << parseTypedef(); else if (t1.type == ttClass) - appendValidSeg(segs, parseClass()); + segs << parseClass(); else if (t1.type == ttMixin) - appendValidSeg(segs, parseMixin()); + segs << parseMixin(); else if (t1.type == ttInterface) - appendValidSeg(segs, parseInterface()); + segs << parseInterface(); else if (t1.type == ttFuncDef) { - appendValidSeg(segs, parseFuncDef()); + segs << parseFuncDef(); } else if (t1.type == ttConst || t1.type == ttScope || t1.type == ttAuto || isDataType(t1)) { // class properties parsing now are in deep parsing, @@ -1576,13 +1563,13 @@ QList QAsCodeParser::parseScript(bool inBlock) { // seg.name is empty seg.offset = begin; seg.scope = currentNs; - seg.type = SymbolType::VarsDecl; - seg.codes = code.sliced(begin, end - begin + 1); + seg.type = SymbolType::Variable; + seg.codes = _code.sliced(begin, end - begin + 1); rewindTo(&t1); segs.append(seg); } else { - appendValidSeg(segs, parseFunction()); + segs << parseFunction(); } } else if (t1.type == ttEndStatement) { // Ignore a semicolon by itself @@ -1598,21 +1585,14 @@ QList QAsCodeParser::parseScript(bool inBlock) { } } - if (isSyntaxError) { + if (_isSyntaxError) { skipCodeBlock(); - isSyntaxError = false; + _isSyntaxError = false; } } UNREACHABLE_RETURN; } -void QAsCodeParser::appendValidSeg(QList &container, - CodeSegment seg) { - if (seg.isValid()) { - container.append(seg); - } -} - void QAsCodeParser::skipCodeBlock() { // Search for either ';' or '{' or end sToken t1; @@ -1637,15 +1617,7 @@ void QAsCodeParser::skipCodeBlock() { } QByteArray QAsCodeParser::getSymbolString(const sToken &t) { - return QByteArray(code.data() + t.pos, t.length); -} - -QByteArrayList QAsCodeParser::getRealNamespace(const QByteArrayList &ns) { - // if (ns.isEmpty()) { - // return _curns + ns; - // } else { - return ns; - // } + return QByteArray(_code.data() + t.pos, t.length); } QAsCodeParser::CodeSegment QAsCodeParser::parseMixin() { @@ -1705,7 +1677,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseClass() { auto begin = t.pos; t = superficiallyParseStatementBlock(); auto end = t.pos; - seg.codes = code.sliced(begin, end - begin + 1); + seg.codes = _code.sliced(begin, end - begin + 1); return seg; } @@ -1728,7 +1700,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseTypedef() { seg.scope = currentNs; seg.offset = begin; seg.type = SymbolType::TypeDef; - seg.codes = code.sliced(begin, end - begin + 1); + seg.codes = _code.sliced(begin, end - begin); return seg; } @@ -1738,13 +1710,14 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseEnumeration() { // Optional 'shared' and 'external' token getToken(&token); + auto ebegin = token.pos; while (identifierIs(token, SHARED_TOKEN) || identifierIs(token, EXTERNAL_TOKEN)) { rewindTo(&token); parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return seg; getToken(&token); @@ -1765,7 +1738,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseEnumeration() { seg.name = getSymbolString(token); seg.scope = currentNs; - seg.offset = token.pos; + seg.offset = ebegin; seg.type = SymbolType::Enum; // External shared declarations are ended with ';' @@ -1780,7 +1753,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseEnumeration() { rewindTo(&token); token = superficiallyParseStatementBlock(); auto end = token.pos; - seg.codes = code.sliced(begin, end - begin + 1); + seg.codes = _code.sliced(begin, end - begin + 1); return seg; } @@ -1794,7 +1767,7 @@ void QAsCodeParser::parseNamespace() { } auto id = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return; ns.append(getSymbolString(id)); @@ -1803,7 +1776,7 @@ void QAsCodeParser::parseNamespace() { while (t1.type == ttScope) { auto id = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return; ns.append(getSymbolString(id)); @@ -1820,7 +1793,7 @@ void QAsCodeParser::parseNamespace() { parseScript(true); currentNs.clear(); - if (!isSyntaxError) { + if (!_isSyntaxError) { getToken(&t1); if (t1.type != ttEndStatementBlock) { rewindErrorTo(&start); @@ -1829,6 +1802,13 @@ void QAsCodeParser::parseNamespace() { } } +QList +QAsCodeParser::parseGlobalVarDecls(const QByteArrayList &ns, + const QByteArray &code) { + _code = code; + return parseDeclaration(ns, false, true); +} + QAsCodeParser::CodeSegment QAsCodeParser::parseFunction(bool isMethod) { CodeSegment fn; @@ -1843,7 +1823,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction(bool isMethod) { identifierIs(t1, EXTERNAL_TOKEN)) { rewindTo(&t1); parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return fn; } else break; @@ -1862,7 +1842,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction(bool isMethod) { parseToken(ttProtected); getToken(&t1); } - if (isSyntaxError) + if (_isSyntaxError) return fn; // If it is a global function, or a method, except constructor and @@ -1872,12 +1852,12 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction(bool isMethod) { rewindTo(&t1); if (!isMethod || (t1.type != ttBitNot && t2.type != ttOpenParenthesis)) { auto id = parseType(true); - if (isSyntaxError) + if (_isSyntaxError) return fn; // fn.ret = getSymbolString(id); ParseTypeMod(false); - if (isSyntaxError) + if (_isSyntaxError) return fn; } @@ -1885,18 +1865,18 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction(bool isMethod) { // is declared if (isMethod && t1.type == ttBitNot) { parseToken(ttBitNot); - if (isSyntaxError) + if (_isSyntaxError) return fn; } auto iden = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return fn; fn.name = getSymbolString(iden); // fn.nameInSrc = iden.pos; auto params = parseParameterListContent(); - if (isSyntaxError) + if (_isSyntaxError) return fn; // fn.args = params; @@ -1912,7 +1892,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFunction(bool isMethod) { // TODO: Should support abstract methods, in which case no statement block // should be provided parseMethodAttributes(); - if (isSyntaxError) + if (_isSyntaxError) return fn; // External shared functions must be ended with ';' @@ -1942,7 +1922,7 @@ QAsCodeParser::Symbol QAsCodeParser::parseFuncDefContent() { while (identifierIs(t1, SHARED_TOKEN) || identifierIs(t1, EXTERNAL_TOKEN)) { rewindTo(&t1); - if (isSyntaxError) + if (_isSyntaxError) return sym; getToken(&t1); @@ -1954,21 +1934,21 @@ QAsCodeParser::Symbol QAsCodeParser::parseFuncDefContent() { } parseType(true); - if (isSyntaxError) + if (_isSyntaxError) return sym; ParseTypeMod(false); - if (isSyntaxError) + if (_isSyntaxError) return sym; auto iden = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return sym; sym.name = getSymbolString(iden); // sym.nameInSrc = iden.pos; auto args = parseParameterListContent(); - if (isSyntaxError) + if (_isSyntaxError) return sym; // sym.content = args; @@ -2027,11 +2007,11 @@ void QAsCodeParser::parseClassContent() { // are being inherited if (t.type == ttColon) { // TODO: dont support temperily, later - ParseOptionalScope(); + parseOptionalScope(); parseIdentifier(); getToken(&t); while (t.type == ttListSeparator) { - ParseOptionalScope(); + parseOptionalScope(); parseIdentifier(); getToken(&t); } @@ -2063,7 +2043,7 @@ void QAsCodeParser::parseClassContent() { // clssym.content.append(vp); // } } else if (isVarDecl()) { - auto decl = parseDeclaration(true); + // auto decl = parseDeclaration(true); // clssym.content.append(decl); } else if (t.type == ttEndStatement) // Skip empty declarations @@ -2073,7 +2053,7 @@ void QAsCodeParser::parseClassContent() { return; } - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -2136,7 +2116,7 @@ void QAsCodeParser::ParseInitList() { rewindTo(&t1); ParseInitList(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t1); @@ -2154,7 +2134,7 @@ void QAsCodeParser::ParseInitList() { rewindTo(&t1); // NOTE ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t1); @@ -2184,7 +2164,7 @@ void QAsCodeParser::parseInterfaceContent() { rewindTo(&t); parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -2209,11 +2189,11 @@ void QAsCodeParser::parseInterfaceContent() { // Can optionally have a list of interfaces that are inherited if (t.type == ttColon) { - ParseOptionalScope(); + parseOptionalScope(); parseIdentifier(); getToken(&t); while (t.type == ttListSeparator) { - ParseOptionalScope(); + parseOptionalScope(); parseIdentifier(); getToken(&t); } @@ -2244,7 +2224,7 @@ void QAsCodeParser::parseInterfaceContent() { // } } - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -2262,22 +2242,22 @@ QAsCodeParser::Symbol QAsCodeParser::parseInterfaceMethod() { Symbol sym; auto ret = parseType(true); - if (isSyntaxError) + if (_isSyntaxError) return sym; // sym.typeStr = getSymbolString(ret); ParseTypeMod(false); - if (isSyntaxError) + if (_isSyntaxError) return sym; auto id = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return sym; sym.name = getSymbolString(id); // sym.nameInSrc = id.pos; auto args = parseParameterListContent(); - if (isSyntaxError) + if (_isSyntaxError) return sym; // sym.content = args; @@ -2316,20 +2296,20 @@ QAsCodeParser::parseVirtualPropertyDecl(bool isMethod, bool isInterface) { sym.vis = Visiblity::Protected; } - if (isSyntaxError) + if (_isSyntaxError) return sym; auto id = parseType(true); - if (isSyntaxError) + if (_isSyntaxError) return sym; // sym.typeStr = getSymbolString(id); ParseTypeMod(false); - if (isSyntaxError) + if (_isSyntaxError) return sym; auto iden = parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return sym; sym.name = getSymbolString(iden); // sym.nameInSrc = iden.pos; @@ -2360,7 +2340,7 @@ QAsCodeParser::parseVirtualPropertyDecl(bool isMethod, bool isInterface) { if (!isInterface) { parseMethodAttributes(); - if (isSyntaxError) + if (_isSyntaxError) return sym; } } @@ -2375,12 +2355,12 @@ QAsCodeParser::parseVirtualPropertyDecl(bool isMethod, bool isInterface) { // seg.code = code.mid(t1.pos, sourcePos - t1.pos); // sym.codesegs.insert(t1.pos, seg); - if (isSyntaxError) + if (_isSyntaxError) return sym; } else if (t1.type == ttEndStatement) { rewindTo(&t1); parseToken(ttEndStatement); - if (isSyntaxError) + if (_isSyntaxError) return sym; } else { rewindErrorTo(&t1); @@ -2391,7 +2371,7 @@ QAsCodeParser::parseVirtualPropertyDecl(bool isMethod, bool isInterface) { if (t1.type == ttEndStatement) { rewindTo(&t1); parseToken(ttEndStatement); - if (isSyntaxError) + if (_isSyntaxError) return sym; } else { rewindErrorTo(&t1); @@ -2410,58 +2390,27 @@ QAsCodeParser::parseVirtualPropertyDecl(bool isMethod, bool isInterface) { return sym; } -void QAsCodeParser::parseEnumerationContent() { - Symbol sym; +QList QAsCodeParser::parseEnumerationContent( + const QByteArrayList &ns, const QByteArray &name, const QByteArray &code) { + reset(); + _code = code; + + QList syms; sToken token; size_t eoff; - // Optional 'shared' and 'external' token - getToken(&token); - while (identifierIs(token, SHARED_TOKEN) || - identifierIs(token, EXTERNAL_TOKEN)) { - rewindTo(&token); - - parseIdentifier(); - - if (isSyntaxError) - return; - - getToken(&token); - } - - // Check for enum - if (token.type != ttEnum) { - rewindErrorTo(&token); - return; - } - - // Get the identifier - getToken(&token); - if (ttIdentifier != token.type) { - rewindErrorTo(&token); - return; - } - - // ok, init symbol - eoff = token.pos; - sym.name = getSymbolString(token); - // sym.nameInSrc = token.pos; - // sym.type = SymbolType::Enum; - // sym.ns = _curns; - - // External shared declarations are ended with ';' getToken(&token); if (token.type == ttEndStatement) { rewindTo(&token); parseToken(ttEndStatement); - return; + return syms; } // check for the start of the declaration block if (token.type != ttStartStatementBlock) { rewindTo(&token); rewindErrorTo(&token); - return; + return syms; } while (ttEnd != token.type) { @@ -2474,27 +2423,31 @@ void QAsCodeParser::parseEnumerationContent() { if (ttIdentifier != token.type) { rewindErrorTo(&token); - return; + return syms; } // Add the enum element Symbol se; - // se.type = SymbolType::Value; + se.type = "int"; + se.symtype = SymbolType::Enum; se.name = getSymbolString(token); - getToken(&token); - // sym.content.append(se); + se.scope = ns; + se.scope.append(name); + syms.append(se); if (token.type == ttAssignment) { rewindTo(&token); superficiallyParseVarInit(); - if (isSyntaxError) - return; + if (_isSyntaxError) { + return syms; + } - getToken(&token); + // se.additonalInfo = getSymbolString(t); } + getToken(&token); if (ttListSeparator != token.type) { rewindTo(&token); break; @@ -2506,34 +2459,36 @@ void QAsCodeParser::parseEnumerationContent() { if (token.type != ttEndStatementBlock) { rewindTo(&token); rewindErrorTo(&token); - return; + return syms; } - // _symtable.insert(eoff, sym); + return syms; } -void QAsCodeParser::parseTypedefContent() { - Symbol sym; - size_t eoff; +QAsCodeParser::Symbol +QAsCodeParser::parseTypedefContent(const QByteArrayList &ns, + const QByteArray &code) { + reset(); + _code = code; + QAsCodeParser::Symbol sym; sToken token; getToken(&token); + auto begin = token.length; if (token.type != ttTypedef) { rewindErrorTo(&token); - return; + return sym; } - eoff = token.pos; - // Parse the base type getToken(&token); rewindTo(&token); // Make sure it is a primitive type (except ttVoid) - if (!isRealType(token.type) || token.type == ttVoid) { + if (!isPrimType(token.type) || token.type == ttVoid) { rewindErrorTo(&token); - return; + return sym; } auto r = parseRealType(); @@ -2547,14 +2502,12 @@ void QAsCodeParser::parseTypedefContent() { } sym.name = getSymbolString(i); + sym.type = getSymbolString(r); + sym.symtype = SymbolType::TypeDef; + sym.offset = begin; + sym.scope = currentNs; - Symbol st; - st.name = getSymbolString(r); - - // sym.content.append(st); - // sym.ns = _curns; - - // _symtable.insert(eoff, sym); + return sym; } bool QAsCodeParser::isVarDecl() { @@ -2839,7 +2792,7 @@ bool QAsCodeParser::isFunctionCall() { void QAsCodeParser::ParseAssignment() { ParseCondition(); - if (isSyntaxError) + if (_isSyntaxError) return; sToken t; @@ -2848,11 +2801,11 @@ void QAsCodeParser::ParseAssignment() { if (isAssignOperator(t.type)) { ParseAssignOperator(); - if (isSyntaxError) + if (_isSyntaxError) return; ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; } } @@ -2869,14 +2822,14 @@ void QAsCodeParser::ParseAssignOperator() { void QAsCodeParser::ParseCondition() { ParseExpression(); - if (isSyntaxError) + if (_isSyntaxError) return; sToken t; getToken(&t); if (t.type == ttQuestion) { ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t); @@ -2886,7 +2839,7 @@ void QAsCodeParser::ParseCondition() { } ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; } else rewindTo(&t); @@ -2894,7 +2847,7 @@ void QAsCodeParser::ParseCondition() { void QAsCodeParser::ParseExpression() { ParseExprTerm(); - if (isSyntaxError) + if (_isSyntaxError) return; for (;;) { @@ -2906,11 +2859,11 @@ void QAsCodeParser::ParseExpression() { return; ParseExprOperator(); - if (isSyntaxError) + if (_isSyntaxError) return; ParseExprTerm(); - if (isSyntaxError) + if (_isSyntaxError) return; } UNREACHABLE_RETURN; @@ -2956,12 +2909,12 @@ void QAsCodeParser::ParseExprTerm() { break; ParseExprPreOp(); - if (isSyntaxError) + if (_isSyntaxError) return; } ParseExprValue(); - if (isSyntaxError) + if (_isSyntaxError) return; for (;;) { @@ -2971,7 +2924,7 @@ void QAsCodeParser::ParseExprTerm() { return; ParseExprPostOp(); - if (isSyntaxError) + if (_isSyntaxError) return; } UNREACHABLE_RETURN; @@ -3037,7 +2990,7 @@ void QAsCodeParser::ParseExprValue() { // for skipping output arguments) if (t1.type == ttVoid) parseToken(ttVoid); - else if (isRealType(t1.type)) + else if (isPrimType(t1.type)) ParseConstructCall(); else if (t1.type == ttIdentifier || t1.type == ttScope) { // Check if the expression is an anonymous function @@ -3090,7 +3043,7 @@ void QAsCodeParser::ParseExprValue() { else if (t1.type == ttOpenParenthesis) { getToken(&t1); ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t1); @@ -3155,7 +3108,7 @@ void QAsCodeParser::parseArgList(bool withParenthesis) { } else ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; // Check if list continues @@ -3178,11 +3131,11 @@ void QAsCodeParser::parseArgList(bool withParenthesis) { void QAsCodeParser::ParseFunctionCall() { // Parse scope prefix - ParseOptionalScope(); + parseOptionalScope(); // Parse the function name followed by the argument list parseIdentifier(); - if (isSyntaxError) + if (_isSyntaxError) return; parseArgList(); @@ -3190,7 +3143,7 @@ void QAsCodeParser::ParseFunctionCall() { void QAsCodeParser::ParseVariableAccess() { // Parse scope prefix - ParseOptionalScope(); + parseOptionalScope(); // Parse the variable name parseIdentifier(); @@ -3200,7 +3153,7 @@ void QAsCodeParser::ParseConstructCall() { // NOTE parseType(false); - if (isSyntaxError) + if (_isSyntaxError) return; parseArgList(); @@ -3222,7 +3175,7 @@ void QAsCodeParser::ParseCast() { // Parse the data type parseType(true); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t1); @@ -3238,7 +3191,7 @@ void QAsCodeParser::ParseCast() { } ParseAssignment(); - if (isSyntaxError) + if (_isSyntaxError) return; getToken(&t1); @@ -3334,7 +3287,7 @@ void QAsCodeParser::ParseLambda() { if (t.type == ttIdentifier) { // NOTE // param->children().append(ParseIdentifier()); - if (isSyntaxError) + if (_isSyntaxError) return; } @@ -3403,7 +3356,7 @@ bool QAsCodeParser::findTokenAfterType( // moment as it may wrongly identify the statement as a non-declaration if // the user typed the name incorrectly. The real type is validated in // ParseDeclaration where a proper error message can be given. - if (!isRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto) { + if (!isPrimType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto) { rewindTo(&t); return false; } @@ -3618,12 +3571,12 @@ bool QAsCodeParser::checkTemplateType(const sToken &t) { // Accept >> and >>> tokens too. But then force the tokenizer to move // only 1 character ahead (thus splitting the token in two). - if (code[QString::size_type(t1.pos)] != '>') + if (_code[QString::size_type(t1.pos)] != '>') return false; else if (t1.length != 1) { // We need to break the token, so that only the first character is // parsed - SetPos(t1.pos + 1); + setPos(t1.pos + 1); } } diff --git a/src/class/qascodeparser.h b/src/class/qascodeparser.h index 1c985fc..aaf5aee 100644 --- a/src/class/qascodeparser.h +++ b/src/class/qascodeparser.h @@ -47,7 +47,6 @@ public: Function, // a function TypeDef, // a typedef FnDef, // a funcdef - VarsDecl, // global variable decalration }; enum class Visiblity { Public, Private, Protected }; @@ -57,22 +56,34 @@ public: */ struct CodeSegment { QByteArrayList scope; - QString name; + QByteArray name; SymbolType type = QAsCodeParser::SymbolType::Invalid; - int offset = -1; - QString codes; + qsizetype offset = -1; + QByteArray codes; QByteArrayList additonalInfos; // for other additonal infos public: - bool isValid() const { return type != SymbolType::Invalid; } - bool hasCodes() const { return !codes.isEmpty(); } + inline bool isValid() const { + return offset >= 0 && type != SymbolType::Invalid; + } + + inline qsizetype end() const { + if (offset < 0) { + return -1; + } + return offset + codes.length(); + } + + inline qsizetype length() const { return codes.length(); } + + inline bool hasCodes() const { return !codes.isEmpty(); } }; struct Symbol { SymbolType symtype = QAsCodeParser::SymbolType::Invalid; QByteArrayList scope; - QString name; + QByteArray name; QByteArray type; int offset = -1; Visiblity vis = QAsCodeParser::Visiblity::Public; @@ -95,16 +106,15 @@ public: private: QList parseScript(bool inBlock); - void appendValidSeg(QList &container, - QAsCodeParser::CodeSegment seg); - void skipCodeBlock(); QByteArray getSymbolString(const sToken &t); - QByteArrayList getRealNamespace(const QByteArrayList &ns); // Statements - sToken superficiallyParseVarInit(); + void superficiallyParseVarInit(); sToken superficiallyParseStatementBlock(); + void superficiallyParseExpression(); + void superficiallyParseTemplateList(); + void parseMethodAttributes(); private: @@ -131,12 +141,24 @@ private: private: // deep parsing - void parseStatementBlock(); - void parseStatement(); + QList parseEnumerationContent(const QByteArrayList &ns, + const QByteArray &name, + const QByteArray &code); + Symbol parseTypedefContent(const QByteArrayList &ns, + const QByteArray &code); + + QList parseGlobalVarDecls(const QByteArrayList &ns, + const QByteArray &code); + + QByteArrayList parseOptionalScope(); + + QList parseDeclaration(const QByteArrayList &ns, + bool isClassProp = false, + bool isGlobalVar = false); private: - void parseEnumerationContent(); - void parseTypedefContent(); + void parseStatementBlock(); + void parseStatement(); void parseClassContent(); void parseMixinContent(); void parseInterfaceContent(); @@ -166,8 +188,6 @@ private: void ParseExprPostOp(); void ParseExprValue(); - QByteArrayList ParseOptionalScope(); - Symbol parseVirtualPropertyDecl(bool isMethod, bool isInterface); QList parseParameterListContent(); @@ -192,20 +212,17 @@ private: void getToken(sToken *token); void rewindTo(const sToken *token); void rewindErrorTo(sToken *token); - void SetPos(size_t pos); + void setPos(size_t pos); - bool isRealType(int tokenType); + bool isPrimType(int tokenType); bool identifierIs(const sToken &t, const char *str); bool isDataType(const sToken &token); private: bool checkTemplateType(const sToken &t); - bool parseTemplTypeList(bool required = true); void parseArgList(bool withParenthesis = true); - void superficiallyParseExpression(); - private: bool findTokenAfterType(sToken &nextToken); bool findIdentifierAfterScope(sToken &nextToken); @@ -219,28 +236,25 @@ private: Symbol parseFunctionDefinition(); - QList parseDeclaration(bool isClassProp = false, - bool isGlobalVar = false); - Symbol parseInterfaceMethod(); void ParseStringConstant(); private: - bool errorWhileParsing; - bool isSyntaxError; - bool checkValidTypes; - bool isParsingAppInterface; + bool _errorWhileParsing; + bool _isSyntaxError; + bool _checkValidTypes; + bool _isParsingAppInterface; asCScriptEngine *engine; // size_t _curscope = 0; - QByteArray code; + QByteArray _code; QByteArray tempString; // Used for reduzing amount of dynamic allocations - sToken lastToken; - size_t sourcePos; + sToken _lastToken; + size_t _sourcePos; QByteArrayList currentNs; };