diff options
| author | Yong He <yonghe@outlook.com> | 2025-05-29 08:05:57 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-29 08:05:57 -0700 |
| commit | faf042ecc3e688a1a3ffbe1ac44d18dd7ddf441a (patch) | |
| tree | b54abb2e65b7791d74335ead396cf762f805ab5c /source/slang/slang-parser.cpp | |
| parent | 45d794f57d453a5564a7360400c5bfc04bf12b31 (diff) | |
Language version + tuple syntax. (#7230)
* Language version + tuple syntax.
* Fix compile error.
* regenerate documentation Table of Contents
* Fix.
* regenerate command line reference
* Fix.
* Fix.
* Fix more test failures.
* revert empty line change,
* Retrigger CI
* #version->#lang
* Update source/core/slang-type-text-util.cpp
Co-authored-by: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com>
* Remove comments.
* Fix parsing logic.
* Fix parser.
* Fix parser.
* update test comment
* Update options.
* regenerate documentation Table of Contents
* regenerate command line reference
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Co-authored-by: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com>
Diffstat (limited to 'source/slang/slang-parser.cpp')
| -rw-r--r-- | source/slang/slang-parser.cpp | 164 |
1 files changed, 120 insertions, 44 deletions
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 565cb2e5f..9eb8c1391 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -1185,6 +1185,14 @@ bool tryParseUsingSyntaxDecl( return tryParseUsingSyntaxDeclImpl<T>(parser, syntaxDecl, outSyntax); } +static void maybeUpgradeLanguageVersionFromLegacy(SlangLanguageVersion& ver) +{ + if (ver == SLANG_LANGUAGE_VERSION_LEGACY) + { + ver = SLANG_LANGUAGE_VERSION_2025; + } +} + static Modifiers ParseModifiers(Parser* parser, LookupMask modifierLookupMask = LookupMask::Default) { Modifiers modifiers; @@ -1216,7 +1224,7 @@ static Modifiers ParseModifiers(Parser* parser, LookupMask modifierLookupMask = if (as<VisibilityModifier>(parsedModifier)) { if (auto currentModule = parser->getCurrentModuleDecl()) - currentModule->isInLegacyLanguage = false; + maybeUpgradeLanguageVersionFromLegacy(currentModule->languageVersion); } AddModifier(&modifierLink, parsedModifier); continue; @@ -1321,7 +1329,7 @@ static NodeBase* parseIncludeDecl(Parser* parser, void* /*userData*/) auto decl = parser->astBuilder->create<IncludeDecl>(); parseFileReferenceDeclBase(parser, decl); if (auto currentModule = parser->getCurrentModuleDecl()) - currentModule->isInLegacyLanguage = false; + maybeUpgradeLanguageVersionFromLegacy(currentModule->languageVersion); return decl; } @@ -1361,7 +1369,7 @@ static NodeBase* parseModuleDeclarationDecl(Parser* parser, void* /*userData*/) } parser->ReadToken(TokenType::Semicolon); if (auto currentModule = parser->getCurrentModuleDecl()) - currentModule->isInLegacyLanguage = false; + maybeUpgradeLanguageVersionFromLegacy(currentModule->languageVersion); return decl; } @@ -5153,7 +5161,20 @@ void Parser::parseSourceFile(ContainerDecl* program) currentModule = getModuleDecl(program); - // If the program already has a scope, then reuse it instead of overwriting it! + // Verify that the language version is valid. + if (sourceLanguage == SourceLanguage::Slang) + { + if (!isValidSlangLanguageVersion(currentModule->languageVersion)) + { + sink->diagnose( + program->loc, + Diagnostics::unknownLanguageVersion, + currentModule->languageVersion); + } + } + + // If the program already has a scope, then + // reuse it instead of overwriting it! if (program->ownedScope) PushScope(program->ownedScope); else @@ -5607,7 +5628,7 @@ static Decl* _tryResolveDecl(Parser* parser, Expr* expr) auto lookupResult = lookUpDirectAndTransparentMembers( parser->astBuilder, - nullptr, // no semantics visitor available yet + parser->semanticsVisitor, staticMemberExpr->name, aggTypeDecl, declRef); @@ -5627,7 +5648,7 @@ static Decl* _tryResolveDecl(Parser* parser, Expr* expr) // Do the lookup in the current scope auto lookupResult = lookUp( parser->astBuilder, - nullptr, // no semantics visitor available yet + parser->semanticsVisitor, varExpr->name, parser->currentScope); if (!lookupResult.isValid() || lookupResult.isOverloaded()) @@ -5641,11 +5662,8 @@ static Decl* _tryResolveDecl(Parser* parser, Expr* expr) static bool isTypeName(Parser* parser, Name* name) { - auto lookupResult = lookUp( - parser->astBuilder, - nullptr, // no semantics visitor available yet - name, - parser->currentScope); + auto lookupResult = + lookUp(parser->astBuilder, parser->semanticsVisitor, name, parser->currentScope); if (!lookupResult.isValid() || lookupResult.isOverloaded()) return false; @@ -7201,17 +7219,23 @@ static bool _isCast(Parser* parser, Expr* expr) return false; } -static bool tryParseExpression(Parser* parser, Expr*& outExpr, TokenType tokenTypeAfter) +template<typename FIsValidFollowToken> +static bool tryParseExpression( + Parser* parser, + Expr*& outExpr, + Precedence exprLevel, + const FIsValidFollowToken& isValidFollowToken) { auto cursor = parser->tokenReader.getCursor(); auto isRecovering = parser->isRecovering; auto oldSink = parser->sink; DiagnosticSink newSink(parser->sink->getSourceManager(), nullptr); parser->sink = &newSink; - outExpr = parser->ParseExpression(); + outExpr = parser->ParseExpression(exprLevel); parser->sink = oldSink; parser->isRecovering = isRecovering; - if (outExpr && newSink.getErrorCount() == 0 && parser->LookAheadToken(tokenTypeAfter)) + if (outExpr && newSink.getErrorCount() == 0 && + isValidFollowToken(parser->tokenReader.peekTokenType())) { return true; } @@ -7297,9 +7321,7 @@ static Expr* parseAtomicExpr(Parser* parser) tcexpr->loc = openParen.loc; tcexpr->functionExpr = varExpr; - - auto arg = parsePrefixExpr(parser); - tcexpr->arguments.add(arg); + tcexpr->arguments.add(parsePrefixExpr(parser)); return tcexpr; } @@ -7313,45 +7335,99 @@ static Expr* parseAtomicExpr(Parser* parser) Expr* base = nullptr; 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(); + if (parser->currentModule->languageVersion >= SLANG_LANGUAGE_VERSION_2026) + { + // We support empty parentheses `()` as a valid expression to construct an + // empty tuple in Slang 2026. + base = parser->astBuilder->create<TupleExpr>(); + base->loc = openParen.loc; + } + else + { + // We don't support empty parentheses `()` as a valid expression prior to + // Slang 2026. + parser->diagnose(openParen, Diagnostics::invalidEmptyParenthesisExpr); + base = parser->astBuilder->create<IncompleteExpr>(); + base->type = parser->astBuilder->getErrorType(); + } } else { - if (!tryParseExpression(parser, base, TokenType::RParent)) + // When language version is 2026 or later, we no longer parse comma as a + // C/C++-style comma operator when it is inside a paranthesis, + // but rather as a tuple element separator. + // + Precedence exprLevel = Precedence::Comma; + if (parser->sourceLanguage == SourceLanguage::Slang && + parser->currentModule->languageVersion >= SLANG_LANGUAGE_VERSION_2026) + { + // Setting exprLevel to Assignment here will allow the following + // tryParseExpression call to parse the expression until the next `)` or + // `,`, instead of consuming any ',' as a comma operator. + exprLevel = Precedence::Assignment; + } + auto isValidFollowToken = [=](TokenType tokenType) + { + if (tokenType == TokenType::RParent) + return true; + if (exprLevel == Precedence::Assignment && tokenType == TokenType::Comma) + return true; + return false; + }; + if (!tryParseExpression(parser, base, exprLevel, isValidFollowToken)) { base = parser->ParseType(); } } - parser->ReadToken(TokenType::RParent); - - // We now try and determine by what base is, if this is actually a cast or an - // expression in parentheses - if (_isCast(parser, base)) + if (parser->LookAheadToken(TokenType::Comma)) { - // Parse as a cast - - TypeCastExpr* tcexpr = parser->astBuilder->create<ExplicitCastExpr>(); - tcexpr->loc = openParen.loc; - - tcexpr->functionExpr = base; - - auto arg = parsePrefixExpr(parser); - tcexpr->arguments.add(arg); - - return tcexpr; + // We have a comma, so we are not done yet. + // If we reach here, the language version must be 2026 or later, + // where we allow (a,b,c,...) syntax as a tuple, otherwise we would have + // parsed it into `base`. + // + List<Expr*> elementExprs; + elementExprs.add(base); + while (AdvanceIf(parser, TokenType::Comma)) + { + if (parser->LookAheadToken(TokenType::RParent)) + break; + auto elementExpr = parser->ParseArgExpr(); + elementExprs.add(elementExpr); + } + parser->ReadToken(TokenType::RParent); + TupleExpr* tupleExpr = parser->astBuilder->create<TupleExpr>(); + tupleExpr->loc = openParen.loc; + tupleExpr->elements = _Move(elementExprs); + return tupleExpr; } else { - // Pass as an expression in parentheses + // We parsed an expression in the form of (expr), without + // any commas in `expr`. + // We now try and determine by what base is, if this is actually a cast or an + // expression in parentheses. + // + parser->ReadToken(TokenType::RParent); + if (_isCast(parser, base)) + { + // Parse as a cast + TypeCastExpr* tcexpr = parser->astBuilder->create<ExplicitCastExpr>(); + tcexpr->loc = openParen.loc; + + tcexpr->functionExpr = base; + tcexpr->arguments.add(parsePrefixExpr(parser)); - ParenExpr* parenExpr = parser->astBuilder->create<ParenExpr>(); - parenExpr->loc = openParen.loc; - parenExpr->base = base; - return parenExpr; + return tcexpr; + } + else + { + ParenExpr* parenExpr = parser->astBuilder->create<ParenExpr>(); + parenExpr->loc = openParen.loc; + parenExpr->base = base; + return parenExpr; + } } } } @@ -8519,7 +8595,7 @@ void parseSourceFile( Parser parser(astBuilder, tokens, sink, outerScope, options); parser.namePool = translationUnit->getNamePool(); - parser.sourceLanguage = translationUnit->sourceLanguage; + parser.sourceLanguage = sourceLanguage; return parser.parseSourceFile(parentDecl); } |
