diff options
| author | Yong He <yonghe@outlook.com> | 2025-02-05 12:32:56 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-05 12:32:56 -0800 |
| commit | 7911c9437333692db275d2dff41264f4c8023be8 (patch) | |
| tree | dd83ca191f47aed0bd512dfb9412038a7b7d3f0e /source | |
| parent | 613f43a080f84e2680fb78dc4ed60a553da3b418 (diff) | |
Use two-stage parsing to disambiguate generic app and comparison. (#6281)
* Use two-stage parsing to disambiguate generic app and comparison.
* Typo fix.
* Update doc.
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-ast-base.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ast-dump.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-ast-stmt.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-ast-support-types.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-check-conversion.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 28 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 12 | ||||
| -rw-r--r-- | source/slang/slang-check-stmt.cpp | 31 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-language-server-document-symbols.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-lookup.cpp | 4 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 238 | ||||
| -rw-r--r-- | source/slang/slang-parser.h | 13 |
14 files changed, 327 insertions, 30 deletions
diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h index 8c2f7afa7..9cc36e530 100644 --- a/source/slang/slang-ast-base.h +++ b/source/slang/slang-ast-base.h @@ -791,6 +791,8 @@ public: // Track the decl reference that caused the requirement of a capability atom. SLANG_UNREFLECTED List<DeclReferenceWithLoc> capabilityRequirementProvenance; + SLANG_UNREFLECTED bool hiddenFromLookup = false; + private: SLANG_UNREFLECTED DeclRefBase* m_defaultDeclRef = nullptr; }; diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp index 85d2d0d9f..f6cdf50d8 100644 --- a/source/slang/slang-ast-dump.cpp +++ b/source/slang/slang-ast-dump.cpp @@ -645,6 +645,8 @@ struct ASTDumpContext m_writer->emit(info->m_name); } + void dump(SourceLanguage language) { m_writer->emit((int)language); } + void dump(KeyValuePair<DeclRefBase*, SubtypeWitness*> pair) { m_writer->emit("("); diff --git a/source/slang/slang-ast-stmt.h b/source/slang/slang-ast-stmt.h index 8c21f78a5..eba7027c2 100644 --- a/source/slang/slang-ast-stmt.h +++ b/source/slang/slang-ast-stmt.h @@ -52,6 +52,10 @@ class UnparsedStmt : public Stmt // The tokens that were contained between `{` and `}` List<Token> tokens; + Scope* currentScope = nullptr; + Scope* outerScope = nullptr; + SourceLanguage sourceLanguage; + bool isInVariadicGenerics = false; }; class EmptyStmt : public Stmt diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 2581630dd..72707ab38 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -419,6 +419,10 @@ enum class DeclCheckState : uint8_t /// Unchecked, + /// The declaration is parsed and inserted into the initial scope, + /// ready for future lookups from within the parser for disambiguation purposes. + ReadyForParserLookup, + /// Basic checks on the modifiers of the declaration have been applied. /// /// For example, when a declaration has attributes, the transformation diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index d89997bad..6bbdc1477 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -1254,6 +1254,7 @@ bool SemanticsVisitor::_coerce( auto resultExpr = getASTBuilder()->create<MakeOptionalExpr>(); resultExpr->loc = fromExpr->loc; resultExpr->type = toType; + resultExpr->checked = true; *outToExpr = resultExpr; } return true; @@ -1379,6 +1380,7 @@ bool SemanticsVisitor::_coerce( derefExpr = m_astBuilder->create<DerefExpr>(); derefExpr->base = fromExpr; derefExpr->type = QualType(fromElementType); + derefExpr->checked = true; } if (!_coerce(site, toType, outToExpr, fromElementType, derefExpr, &subCost)) @@ -1407,6 +1409,7 @@ bool SemanticsVisitor::_coerce( refExpr->base = fromExpr; refExpr->type = QualType(refType); refExpr->type.isLeftValue = false; + refExpr->checked = true; *outToExpr = refExpr; } if (outCost) diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index b03126512..ab3335bfb 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -16,6 +16,7 @@ #include "slang-ast-reflect.h" #include "slang-ast-synthesis.h" #include "slang-lookup.h" +#include "slang-parser.h" #include "slang-syntax.h" #include <limits> @@ -4558,6 +4559,7 @@ void SemanticsVisitor::addRequiredParamsToSynthesizedDecl( synMemberExpr->elementIndices.add((uint32_t)i); synMemberExpr->type = elementType; synMemberExpr->type.isLeftValue = paramType.isLeftValue; + synMemberExpr->checked = true; synArgs.add(synMemberExpr); } } @@ -8165,6 +8167,7 @@ SemanticsContext SemanticsDeclBodyVisitor::registerDifferentiableTypesForFunc( void SemanticsDeclBodyVisitor::visitFunctionDeclBase(FunctionDeclBase* decl) { auto newContext = registerDifferentiableTypesForFunc(decl); + decl->body = maybeParseStmt(decl->body, newContext); if (const auto body = decl->body) { checkStmt(decl->body, newContext); @@ -9472,6 +9475,28 @@ void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl) } } +Stmt* SemanticsVisitor::maybeParseStmt(Stmt* stmt, const SemanticsContext& context) +{ + if (auto unparsedStmt = as<UnparsedStmt>(stmt)) + { + // Parse the statement now, and check it. + SemanticsVisitor subVisitor(context); + TokenList tokenList; + tokenList.m_tokens = _Move(unparsedStmt->tokens); + return parseUnparsedStmt( + m_astBuilder, + &subVisitor, + getShared()->getTranslationUnitRequest(), + unparsedStmt->sourceLanguage, + unparsedStmt->isInVariadicGenerics, + tokenList, + getShared()->getSink(), + unparsedStmt->currentScope, + unparsedStmt->outerScope); + } + return stmt; +} + void SemanticsDeclHeaderVisitor::cloneModifiers(Decl* dest, Decl* src) { dest->modifiers = src->modifiers; @@ -11182,6 +11207,9 @@ static void _dispatchDeclCheckingVisitor(Decl* decl, DeclCheckState state, Seman { switch (state) { + case DeclCheckState::ReadyForParserLookup: + // We don't need to do anything to make a decl ready for parser lookup. + break; case DeclCheckState::ModifiersChecked: SemanticsDeclModifiersVisitor(shared).dispatch(decl); break; diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 7726fd6c8..7d4fbdf4c 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -167,7 +167,7 @@ Expr* SemanticsVisitor::openExistential(Expr* expr, DeclRef<InterfaceDecl> inter openedValue->declRef = varDeclRef; openedValue->type = QualType(openedType); openedValue->originalExpr = expr; - + openedValue->checked = true; // The result of opening an existential is an l-value // if the original existential is an l-value. // @@ -226,6 +226,7 @@ Expr* SemanticsVisitor::maybeOpenRef(Expr* expr) openRef->innerExpr = expr; openRef->type.isLeftValue = (as<RefType>(exprType) != nullptr); openRef->type.type = refType->getValueType(); + openRef->checked = true; return openRef; } return expr; @@ -522,6 +523,7 @@ Expr* SemanticsVisitor::constructDerefExpr(Expr* base, QualType elementType, Sou derefExpr->loc = loc; derefExpr->base = base; derefExpr->type = QualType(elementType); + derefExpr->checked = true; if (as<PtrType>(base->type) || as<RefType>(base->type)) { @@ -3918,6 +3920,7 @@ Expr* SemanticsExprVisitor::visitAsTypeExpr(AsTypeExpr* expr) makeOptional->type = optType; makeOptional->value = castToSuperType; makeOptional->typeExpr = typeExpr.exp; + makeOptional->checked = true; return makeOptional; } @@ -4125,6 +4128,7 @@ Expr* SemanticsVisitor::CheckMatrixSwizzleExpr( swizExpr->loc = memberRefExpr->loc; swizExpr->base = memberRefExpr->baseExpression; swizExpr->memberOpLoc = memberRefExpr->memberOperatorLoc; + swizExpr->checked = true; // We can have up to 4 swizzles of two elements each MatrixCoord elementCoords[4]; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 3276b7534..e6520cfd3 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2035,6 +2035,8 @@ public: void checkStmt(Stmt* stmt, SemanticsContext const& context); + Stmt* maybeParseStmt(Stmt* stmt, const SemanticsContext& context); + void getGenericParams( GenericDecl* decl, List<Decl*>& outParams, @@ -2877,14 +2879,8 @@ public: // deal with this cases here, even if they are no-ops. // -#define CASE(NAME) \ - Expr* visit##NAME(NAME* expr) \ - { \ - if (!getShared()->isInLanguageServer()) \ - SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "should not appear in input syntax"); \ - expr->type = m_astBuilder->getErrorType(); \ - return expr; \ - } +#define CASE(NAME) \ + Expr* visit##NAME(NAME* expr) { return expr; } CASE(DerefExpr) CASE(MakeRefExpr) diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp index 550993957..151c9324a 100644 --- a/source/slang/slang-check-stmt.cpp +++ b/source/slang/slang-check-stmt.cpp @@ -54,6 +54,8 @@ void SemanticsStmtVisitor::visitDeclStmt(DeclStmt* stmt) // that need to be recursively checked. // ensureDeclBase(stmt->decl, DeclCheckState::DefinitionChecked, this); + if (auto decl = as<Decl>(stmt->decl)) + decl->hiddenFromLookup = false; } void SemanticsStmtVisitor::visitBlockStmt(BlockStmt* stmt) @@ -66,14 +68,41 @@ void SemanticsStmtVisitor::visitBlockStmt(BlockStmt* stmt) if (as<AggTypeDeclBase>(decl)) ensureAllDeclsRec(decl, DeclCheckState::DefinitionChecked); } + + // Consider this code: + // ``` + // { + // int a = 5 + b; // should error. + // int b = 3; + // } + // + // ``` + // In order to detect the error trying to use `b` before it's declared within + // a block, our lookup logic contains a condition that ignores a decl if its + // `hiddenFromLookup` field is set to `true`. + // See _lookUpDirectAndTransparentMembers(). + // This field will be set to false when we reach the decl through the DeclStmt. + // + if (auto seqStmt = as<SeqStmt>(stmt->body)) + { + for (auto subStmt : seqStmt->stmts) + { + if (auto declStmt = as<DeclStmt>(subStmt)) + { + if (auto decl = as<Decl>(declStmt->decl)) + decl->hiddenFromLookup = true; + } + } + } } checkStmt(stmt->body); } void SemanticsStmtVisitor::visitSeqStmt(SeqStmt* stmt) { - for (auto ss : stmt->stmts) + for (auto& ss : stmt->stmts) { + ss = maybeParseStmt(ss, *this); checkStmt(ss); } } diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 682980107..4d037b68e 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -456,6 +456,11 @@ DIAGNOSTIC( Error, unexpectedTokenExpectedComponentDefinition, "unexpected token '$0', only component definitions are allowed in a shader scope.") +DIAGNOSTIC( + 20005, + Error, + invalidEmptyParenthesisExpr, + "empty parenthesis '()' is not a valid expression.") DIAGNOSTIC(20008, Error, invalidOperator, "invalid operator '$0'.") DIAGNOSTIC(20011, Error, unexpectedColon, "unexpected ':'.") DIAGNOSTIC( diff --git a/source/slang/slang-language-server-document-symbols.cpp b/source/slang/slang-language-server-document-symbols.cpp index c13316a71..e8a041ca8 100644 --- a/source/slang/slang-language-server-document-symbols.cpp +++ b/source/slang/slang-language-server-document-symbols.cpp @@ -90,6 +90,11 @@ static SourceLoc _findClosingSourceLoc(Decl* decl) { return block->closingSourceLoc; } + else if (auto unparsedStmt = as<UnparsedStmt>(func->body)) + { + if (unparsedStmt->tokens.getCount()) + return unparsedStmt->tokens.getLast().getLoc(); + } else if (func->body) { return func->body->loc; diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp index 72fbed581..9b9034c63 100644 --- a/source/slang/slang-lookup.cpp +++ b/source/slang/slang-lookup.cpp @@ -161,8 +161,8 @@ static void _lookUpMembersInValue( static bool _isUncheckedLocalVar(const Decl* decl) { auto checkStateExt = decl->checkState; - auto isUnchecked = - checkStateExt.getState() == DeclCheckState::Unchecked || checkStateExt.isBeingChecked(); + auto isUnchecked = checkStateExt.getState() == DeclCheckState::Unchecked || + checkStateExt.isBeingChecked() || decl->hiddenFromLookup; return isUnchecked && isLocalVar(decl); } diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 0d7281e3f..342ac9e55 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -1,6 +1,7 @@ #include "slang-parser.h" #include "../core/slang-semantic-version.h" +#include "slang-check-impl.h" #include "slang-compiler.h" #include "slang-lookup-spirv.h" #include "slang-lookup.h" @@ -75,11 +76,18 @@ enum Precedence : int Postfix, }; +enum class ParsingStage +{ + Decl, + Body, +}; + struct ParserOptions { bool enableEffectAnnotations = false; bool allowGLSLInput = false; bool isInLanguageServer = false; + ParsingStage stage = ParsingStage::Body; CompilerOptionSet optionSet; }; @@ -91,6 +99,7 @@ public: NamePool* namePool; SourceLanguage sourceLanguage; ASTBuilder* astBuilder; + SemanticsVisitor* semanticsVisitor = nullptr; NamePool* getNamePool() { return namePool; } SourceLanguage getSourceLanguage() { return sourceLanguage; } @@ -156,6 +165,8 @@ public: resetLookupScope(); } + ParsingStage getStage() { return options.stage; } + ModuleDecl* getCurrentModuleDecl() { return currentModule; } Parser( @@ -1811,14 +1822,62 @@ static Stmt* parseOptBody(Parser* parser) if (peekTokenType(parser) == TokenType::LBrace) { parser->sink->diagnose(semiColonToken.loc, Diagnostics::unexpectedBodyAfterSemicolon); - return parser->parseBlockStatement(); + + // Fall through to parse the block stmt. + } + else + { + return nullptr; } - return nullptr; } - else + + if (parser->getStage() == ParsingStage::Decl) { - return parser->parseBlockStatement(); + // If we are at the initial parsing stage, just collect the tokens + // without actually parsing them. + if (peekTokenType(parser) != TokenType::LBrace) + { + return parser->parseBlockStatement(); + } + auto unparsedStmt = parser->astBuilder->create<UnparsedStmt>(); + unparsedStmt->currentScope = parser->currentScope; + unparsedStmt->outerScope = parser->outerScope; + unparsedStmt->sourceLanguage = parser->getSourceLanguage(); + unparsedStmt->isInVariadicGenerics = parser->isInVariadicGenerics; + parser->FillPosition(unparsedStmt); + List<Token>& tokens = unparsedStmt->tokens; + int braceDepth = 0; + for (;;) + { + auto token = parser->ReadToken(); + if (token.type == TokenType::EndOfFile) + { + break; + } + if (token.type == TokenType::LBrace) + { + braceDepth++; + } + else if (token.type == TokenType::RBrace) + { + braceDepth--; + } + tokens.add(token); + if (braceDepth == 0) + { + break; + } + } + Token eofToken; + eofToken.type = TokenType::EndOfFile; + eofToken.loc = parser->tokenReader.peekLoc(); + tokens.add(eofToken); + return unparsedStmt; } + + // If we are in the second stage of parsing, then we need to actually + // parse the block statement for real. + return parser->parseBlockStatement(); } /// Complete parsing of a function using traditional (C-like) declarator syntax @@ -1867,9 +1926,12 @@ static Decl* parseTraditionalFuncDecl(Parser* parser, DeclaratorInfo const& decl parser->PushScope(funcScope); decl->body = parseOptBody(parser); - if (auto block = as<BlockStmt>(decl->body)) + if (auto blockStmt = as<BlockStmt>(decl->body)) + decl->closingSourceLoc = blockStmt->closingSourceLoc; + else if (auto unparsedStmt = as<UnparsedStmt>(decl->body)) { - decl->closingSourceLoc = block->closingSourceLoc; + if (unparsedStmt->tokens.getCount()) + decl->closingSourceLoc = unparsedStmt->tokens.getLast().getLoc(); } parser->PopScope(); @@ -2311,15 +2373,79 @@ static bool isGenericName(Parser* parser, Name* name) return lookupResult.item.declRef.is<GenericDecl>(); } +enum class BaseGenericKind +{ + Unknown, + Generic, + NonGeneric, +}; + static Expr* tryParseGenericApp(Parser* parser, Expr* base) { Name* baseName = nullptr; - if (auto varExpr = as<VarExpr>(base)) - baseName = varExpr->name; - // if base is a known generics, parse as generics - if (baseName && isGenericName(parser, baseName)) + BaseGenericKind baseKind = BaseGenericKind::Unknown; + if (parser->semanticsVisitor) + { + // If we have access to a semantic visitor, we can check the base + // and see if it refers to a generic. + auto checkedBase = parser->semanticsVisitor->CheckTerm(base); + if (auto declRefExpr = as<DeclRefExpr>(checkedBase)) + { + if (declRefExpr->declRef.is<GenericDecl>()) + { + baseKind = BaseGenericKind::Generic; + } + else if ( + declRefExpr->declRef.is<FunctionDeclBase>() || + declRefExpr->declRef.is<AggTypeDeclBase>()) + { + // If declref is a function or type, even if it is not a generic, + // we should parse the `<` as a generic application for better error + // messages. This is because functions or types can never precede a + // `<` in valid Slang code, and it is more likely that the user assumed + // the function or type is generic by mistake. + // + baseKind = BaseGenericKind::Generic; + } + else + { + baseKind = BaseGenericKind::NonGeneric; + } + } + else if (auto overloadedExpr = as<OverloadedExpr>(checkedBase)) + { + baseKind = BaseGenericKind::NonGeneric; + for (auto candidate : overloadedExpr->lookupResult2) + { + if (candidate.declRef.is<GenericDecl>() || + declRefExpr->declRef.is<FunctionDeclBase>() || + declRefExpr->declRef.is<AggTypeDeclBase>()) + { + baseKind = BaseGenericKind::Generic; + break; + } + } + } + } + else + { + // Without a semantic visitor, we fallback to a more simplistic lookup + // and guessing. + if (auto varExpr = as<VarExpr>(base)) + baseName = varExpr->name; + // if base is a known generics, parse as generics + if (baseName && isGenericName(parser, baseName)) + baseKind = BaseGenericKind::Generic; + } + + // If base is known to be a generic, just parse as generic app. + if (baseKind == BaseGenericKind::Generic) return parseGenericApp(parser, base); + // If base is known to be non-generic, just return base. + if (baseKind == BaseGenericKind::NonGeneric) + return base; + // otherwise, we speculate as generics, and fallback to comparison when parsing failed TokenSpan tokenSpan; tokenSpan.m_begin = parser->tokenReader.m_cursor; @@ -3844,8 +3970,13 @@ static NodeBase* parseConstructorDecl(Parser* parser, void* /*userData*/) decl->body = parseOptBody(parser); - if (auto block = as<BlockStmt>(decl->body)) - decl->closingSourceLoc = block->closingSourceLoc; + if (auto blockStmt = as<BlockStmt>(decl->body)) + decl->closingSourceLoc = blockStmt->closingSourceLoc; + else if (auto unparsedStmt = as<UnparsedStmt>(decl->body)) + { + if (unparsedStmt->tokens.getCount()) + decl->closingSourceLoc = unparsedStmt->tokens.getLast().getLoc(); + } parser->PopScope(); return decl; @@ -3898,10 +4029,13 @@ static AccessorDecl* parseAccessorDecl(Parser* parser) if (parser->tokenReader.peekTokenType() == TokenType::LBrace) { - decl->body = parser->parseBlockStatement(); - if (auto block = as<BlockStmt>(decl->body)) + decl->body = parseOptBody(parser); + if (auto blockStmt = as<BlockStmt>(decl->body)) + decl->closingSourceLoc = blockStmt->closingSourceLoc; + else if (auto unparsedStmt = as<UnparsedStmt>(decl->body)) { - decl->closingSourceLoc = block->closingSourceLoc; + if (unparsedStmt->tokens.getCount()) + decl->closingSourceLoc = unparsedStmt->tokens.getLast().getLoc(); } } else @@ -4184,6 +4318,11 @@ static NodeBase* parseFuncDecl(Parser* parser, void* /*userData*/) decl->body = parseOptBody(parser); if (auto blockStmt = as<BlockStmt>(decl->body)) decl->closingSourceLoc = blockStmt->closingSourceLoc; + else if (auto unparsedStmt = as<UnparsedStmt>(decl->body)) + { + if (unparsedStmt->tokens.getCount()) + decl->closingSourceLoc = unparsedStmt->tokens.getLast().getLoc(); + } parser->PopScope(); return decl; }); @@ -4734,6 +4873,19 @@ static void CompleteDecl( AddMember(containerDecl, decl); } } + + if (parser->semanticsVisitor && parser->getStage() == ParsingStage::Body) + { + // When we are in a deferred parsing stage for function bodies, + // we will mark all local var decls as `ReadyForParserLookup` so they can + // be returned via lookup. + // Note that our lookup logic will ignore all unchecked decls, but during + // parsing we don't want to ignore them, so we mark them as `ReadyForParserLookup` + // here, which is a pseudo state that is only used during parsing. + // Before checking the decl in semantic checking, we will mark them back as + // `Unchecked`. + decl->checkState = DeclCheckState::ReadyForParserLookup; + } } static DeclBase* ParseDeclWithModifiers( @@ -5482,6 +5634,7 @@ Stmt* parseCompileTimeForStmt(Parser* parser) VarDecl* varDecl = parser->astBuilder->create<VarDecl>(); varDecl->nameAndLoc = varNameAndLoc; varDecl->loc = varNameAndLoc.loc; + varDecl->checkState = DeclCheckState::ReadyForParserLookup; stmt->varDecl = varDecl; @@ -5863,7 +6016,6 @@ DeclStmt* Parser::parseVarDeclrStatement(Modifiers modifiers) { sink->diagnose(decl->loc, Diagnostics::declNotAllowed, decl->astNodeType); } - return varDeclrStatement; } @@ -5902,6 +6054,11 @@ Stmt* Parser::parseIfLetStatement() tempVarDecl->nameAndLoc = NameLoc(getName(this, "$OptVar"), identifierToken.loc); tempVarDecl->initExpr = initExpr; AddMember(currentScope->containerDecl, tempVarDecl); + if (semanticsVisitor) + semanticsVisitor->ensureDecl( + (Decl*)tempVarDecl, + DeclCheckState::DefinitionChecked, + nullptr); DeclStmt* tmpVarDeclStmt = astBuilder->create<DeclStmt>(); FillPosition(tmpVarDeclStmt); @@ -6991,9 +7148,19 @@ static Expr* parseAtomicExpr(Parser* parser) // as an expression. Expr* base = nullptr; - if (!tryParseExpression(parser, base, TokenType::RParent)) + if (parser->LookAheadToken(TokenType::RParent)) + { + // We don't support empty parentheses `()` as a valid expression. + parser->diagnose(openParen, Diagnostics::invalidEmptyParenthesisExpr); + base = parser->astBuilder->create<IncompleteExpr>(); + base->type = parser->astBuilder->getErrorType(); + } + else { - base = parser->ParseType(); + if (!tryParseExpression(parser, base, TokenType::RParent)) + { + base = parser->ParseType(); + } } parser->ReadToken(TokenType::RParent); @@ -8086,6 +8253,7 @@ Expr* parseTermFromSourceFile( { ParserOptions options; options.allowGLSLInput = sourceLanguage == SourceLanguage::GLSL; + options.stage = ParsingStage::Body; Parser parser(astBuilder, tokens, sink, outerScope, options); parser.currentScope = outerScope; parser.namePool = namePool; @@ -8093,6 +8261,39 @@ Expr* parseTermFromSourceFile( return parser.ParseExpression(); } +Stmt* parseUnparsedStmt( + ASTBuilder* astBuilder, + SemanticsVisitor* semanticsVisitor, + TranslationUnitRequest* translationUnit, + SourceLanguage sourceLanguage, + bool isInVariadicGenerics, + TokenSpan const& tokens, + DiagnosticSink* sink, + Scope* currentScope, + Scope* outerScope) +{ + ParserOptions options = {}; + options.stage = ParsingStage::Body; + options.enableEffectAnnotations = translationUnit->compileRequest->optionSet.getBoolOption( + CompilerOptionName::EnableEffectAnnotations); + options.allowGLSLInput = + translationUnit->compileRequest->optionSet.getBoolOption(CompilerOptionName::AllowGLSL) || + sourceLanguage == SourceLanguage::GLSL; + options.isInLanguageServer = + translationUnit->compileRequest->getLinkage()->isInLanguageServer(); + options.optionSet = translationUnit->compileRequest->optionSet; + + Parser parser(astBuilder, tokens, sink, outerScope, options); + parser.currentScope = outerScope; + parser.namePool = translationUnit->getNamePool(); + parser.sourceLanguage = sourceLanguage; + parser.semanticsVisitor = semanticsVisitor; + parser.currentScope = parser.currentLookupScope = currentScope; + parser.currentModule = semanticsVisitor->getShared()->getModule()->getModuleDecl(); + parser.isInVariadicGenerics = isInVariadicGenerics; + return parser.parseBlockStatement(); +} + // Parse a source file into an existing translation unit void parseSourceFile( ASTBuilder* astBuilder, @@ -8104,6 +8305,7 @@ void parseSourceFile( ContainerDecl* parentDecl) { ParserOptions options = {}; + options.stage = ParsingStage::Decl; options.enableEffectAnnotations = translationUnit->compileRequest->optionSet.getBoolOption( CompilerOptionName::EnableEffectAnnotations); options.allowGLSLInput = diff --git a/source/slang/slang-parser.h b/source/slang/slang-parser.h index bef03c9fe..9f9f4972a 100644 --- a/source/slang/slang-parser.h +++ b/source/slang/slang-parser.h @@ -25,6 +25,19 @@ Expr* parseTermFromSourceFile( NamePool* namePool, SourceLanguage sourceLanguage); +struct SemanticsVisitor; + +Stmt* parseUnparsedStmt( + ASTBuilder* astBuilder, + SemanticsVisitor* semantics, + TranslationUnitRequest* translationUnit, + SourceLanguage sourceLanguage, + bool isInVariadicGenerics, + TokenSpan const& tokens, + DiagnosticSink* sink, + Scope* currentScope, + Scope* outerScope); + ModuleDecl* populateBaseLanguageModule(ASTBuilder* astBuilder, Scope* scope); /// Information used to set up SyntaxDecl. Such decls |
