66#include " Luau/TimeTrace.h"
77
88#include < algorithm>
9+ #include < unordered_set>
910
1011#include < errno.h>
1112#include < limits.h>
13+ #include < stdlib.h>
1214#include < string.h>
13- #include < unordered_set>
1415
1516LUAU_FASTINTVARIABLE (LuauRecursionLimit, 1000 )
1617LUAU_FASTINTVARIABLE (LuauTypeLengthLimit, 1000 )
@@ -23,14 +24,16 @@ LUAU_FASTFLAGVARIABLE(LuauSolverV2)
2324LUAU_DYNAMIC_FASTFLAGVARIABLE (DebugLuauReportReturnTypeVariadicWithTypeSuffix, false )
2425LUAU_FASTFLAGVARIABLE (LuauIntegerType2)
2526LUAU_FASTFLAGVARIABLE (LuauExportValueSyntax)
26- LUAU_FLAGVERSION (LuauExportValueSyntax, 4 )
27+ LUAU_FLAGVERSION (LuauExportValueSyntax, 5 )
2728
2829LUAU_FASTFLAGVARIABLE (DebugLuauNoInline)
2930LUAU_FASTFLAGVARIABLE (DebugLuauUserDefinedClasses)
3031LUAU_FASTFLAGVARIABLE (LuauAllowGlobalDeclarationToBeCalledClass)
3132LUAU_FASTFLAGVARIABLE (LuauNoDuplicateBinaryPrefix)
3233LUAU_FASTFLAGVARIABLE (LuauSingleTypeOptionalPackReturnsAttributeParens)
33- LUAU_FASTFLAGVARIABLE (DebugLuauIfLocalSyntax)
34+ LUAU_FASTFLAGVARIABLE (DebugLuauParseExactTables)
35+ LUAU_FASTFLAGVARIABLE (LuauExperimentalIfLocalSyntax)
36+ LUAU_FLAGVERSION (LuauExperimentalIfLocalSyntax, 2 )
3437
3538// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
3639bool luau_telemetry_parsed_return_type_variadic_with_type_suffix = false ;
@@ -579,9 +582,14 @@ AstStat* Parser::parseIf()
579582
580583 nextLexeme (); // if / elseif
581584
582- if (FFlag::DebugLuauIfLocalSyntax &&
583- (lexer.current ().type == Lexeme::ReservedLocal || (lexer.current ().type == Lexeme::Name && AstName (lexer.current ().name ) == " const" )))
584- return parseIfLocalCondition (start);
585+ if (FFlag::LuauExperimentalIfLocalSyntax)
586+ {
587+ if (lexer.current ().type == Lexeme::ReservedLocal)
588+ return parseIfLocalCondition (start);
589+
590+ if (lexer.current ().type == Lexeme::Name && AstName (lexer.current ().name ) == " const" && lexer.lookahead ().type == Lexeme::Name)
591+ return parseIfLocalCondition (start);
592+ }
585593
586594 AstExpr* cond = parseExpr ();
587595
@@ -606,7 +614,7 @@ AstStat* Parser::parseIf()
606614// consumed `if`/`elseif` keyword; the current lexeme is the `local`/`const` keyword.
607615LUAU_NOINLINE AstStat* Parser::parseIfLocalCondition (const Location& start)
608616{
609- LUAU_ASSERT (FFlag::DebugLuauIfLocalSyntax );
617+ LUAU_ASSERT (FFlag::LuauExperimentalIfLocalSyntax );
610618
611619 bool condIsConst = (lexer.current ().type == Lexeme::Name && AstName (lexer.current ().name ) == " const" );
612620 std::optional<Location> condKeywordLocation = lexer.current ().location ;
@@ -649,7 +657,13 @@ LUAU_NOINLINE AstStat* Parser::parseIfLocalCondition(const Location& start)
649657 return node;
650658}
651659
652- AstStat* Parser::parseElseBody (const Location& start, const Lexeme& matchThen, AstStatBlock* thenbody, Location& end, std::optional<Location>& elseLocation)
660+ AstStat* Parser::parseElseBody (
661+ const Location& start,
662+ const Lexeme& matchThen,
663+ AstStatBlock* thenbody,
664+ Location& end,
665+ std::optional<Location>& elseLocation
666+ )
653667{
654668 AstStat* elsebody = nullptr ;
655669 end = start;
@@ -1347,7 +1361,8 @@ AstStat* Parser::parseLocal(
13471361
13481362 Location location{start.begin , body->location .end };
13491363
1350- AstStatLocalFunction* node = allocator.alloc <AstStatLocalFunction>(location, var, body, isConst, isConst ? keywordPosition : Position::missing ());
1364+ AstStatLocalFunction* node =
1365+ allocator.alloc <AstStatLocalFunction>(location, var, body, isConst, isConst ? keywordPosition : Position::missing ());
13511366 if (options.storeCstData )
13521367 {
13531368 cstNodeMap[node] = cstAttrLists != nullptr
@@ -1591,14 +1606,10 @@ LUAU_NOINLINE AstStat* Parser::parseClassStat(const Location& start, bool export
15911606 propType = parseType ();
15921607 }
15931608
1594- if (propName->name == " new" )
1595- report (propName->location , " Class properties cannot be named 'new'. Define a method named '__init' to define a constructor." );
1596- else if (strncmp (propName->name .value , " __" , 2 ) == 0 )
1609+ if (strncmp (propName->name .value , " __" , 2 ) == 0 )
15971610 report (propName->location , " Class properties cannot start with '__'" );
15981611 else if (classMemberNamespace.contains (propName->name ))
1599- {
16001612 report (propName->location , " Duplicate class member '%s'" , propName->name .value );
1601- }
16021613 else
16031614 {
16041615 classMemberNamespace.insert (propName->name );
@@ -1643,9 +1654,7 @@ LUAU_NOINLINE AstStat* Parser::parseClassStat(const Location& start, bool export
16431654 if (body->args .size > 0 && body->args .data [0 ]->name == " self" && body->args .data [0 ]->annotation != nullptr )
16441655 report (body->args .data [0 ]->annotation ->location , " The 'self' parameter cannot have a type annotation" );
16451656
1646- if (name.name == " new" )
1647- report (name.location , " Class methods cannot be named 'new'. Name it '__init' to define a constructor." );
1648- else if (strncmp (name.name .value , " __" , 2 ) == 0 )
1657+ if (strncmp (name.name .value , " __" , 2 ) == 0 )
16491658 {
16501659 if (kExplicitlyDisallowedMetamethods .count (name.name .value ) > 0 )
16511660 report (name.location , " Classes cannot define '%s' as a metamethod" , name.name .value );
@@ -2801,12 +2810,22 @@ AstType* Parser::parseTableType(bool inDeclarationContext)
28012810 expectAndConsume (' {' , " table type" );
28022811
28032812 bool isArray = false ;
2813+ // When the flag is set, tables are exact by default unless ... is present at the end.
2814+ bool isExact = FFlag::DebugLuauParseExactTables;
28042815
28052816 while (lexer.current ().type != ' }' )
28062817 {
28072818 AstTableAccess access = AstTableAccess::ReadWrite;
28082819 std::optional<Location> accessLocation;
28092820
2821+ if (FFlag::DebugLuauParseExactTables && lexer.current ().type == Lexeme::Dot3)
2822+ {
2823+ nextLexeme ();
2824+ isExact = false ;
2825+ // ... is always last.
2826+ break ;
2827+ }
2828+
28102829 if (lexer.current ().type == Lexeme::Name && lexer.lookahead ().type != ' :' )
28112830 {
28122831 if (AstName (lexer.current ().name ) == " read" )
@@ -2913,6 +2932,17 @@ AstType* Parser::parseTableType(bool inDeclarationContext)
29132932 Location nullTypeLocation = Location (start.begin , 0 );
29142933 AstType* index = allocator.alloc <AstTypeReference>(nullTypeLocation, std::nullopt , nameNumber, std::nullopt , nullTypeLocation);
29152934 indexer = allocator.alloc <AstTableIndexer>(AstTableIndexer{index, type, type->location , access, accessLocation});
2935+
2936+ if (FFlag::DebugLuauParseExactTables)
2937+ {
2938+ if (lexer.current ().type == ' ,' && lexer.lookahead ().type == Lexeme::Dot3)
2939+ {
2940+ nextLexeme ();
2941+ nextLexeme ();
2942+ isExact = false ;
2943+ }
2944+ }
2945+
29162946 break ;
29172947 }
29182948 else
@@ -2960,7 +2990,7 @@ AstType* Parser::parseTableType(bool inDeclarationContext)
29602990 if (!expectMatchAndConsume (' }' , matchBrace, /* searchForMissing = */ true ))
29612991 end = lexer.previousLocation ();
29622992
2963- AstTypeTable* node = allocator.alloc <AstTypeTable>(Location (start, end), copy (props), indexer);
2993+ AstTypeTable* node = allocator.alloc <AstTypeTable>(Location (start, end), copy (props), indexer, isExact );
29642994 if (options.storeCstData )
29652995 cstNodeMap[node] = allocator.alloc <CstTypeTable>(copy (cstItems), isArray);
29662996 return node;
@@ -4414,9 +4444,14 @@ AstExpr* Parser::parseIfElseExpr()
44144444
44154445 nextLexeme (); // skip if / elseif
44164446
4417- if (FFlag::DebugLuauIfLocalSyntax &&
4418- (lexer.current ().type == Lexeme::ReservedLocal || (lexer.current ().type == Lexeme::Name && AstName (lexer.current ().name ) == " const" )))
4419- return parseIfElseExprLocalCondition (start);
4447+ if (FFlag::LuauExperimentalIfLocalSyntax)
4448+ {
4449+ if (lexer.current ().type == Lexeme::ReservedLocal)
4450+ return parseIfElseExprLocalCondition (start);
4451+
4452+ if (lexer.current ().type == Lexeme::Name && AstName (lexer.current ().name ) == " const" && lexer.lookahead ().type == Lexeme::Name)
4453+ return parseIfElseExprLocalCondition (start);
4454+ }
44204455
44214456 AstExpr* condition = parseExpr ();
44224457
@@ -4445,7 +4480,7 @@ AstExpr* Parser::parseIfElseExpr()
44454480// consumed `if`/`elseif` keyword; the current lexeme is the `local`/`const` keyword.
44464481LUAU_NOINLINE AstExpr* Parser::parseIfElseExprLocalCondition (const Location& start)
44474482{
4448- LUAU_ASSERT (FFlag::DebugLuauIfLocalSyntax );
4483+ LUAU_ASSERT (FFlag::LuauExperimentalIfLocalSyntax );
44494484
44504485 bool condIsConst = (lexer.current ().type == Lexeme::Name && AstName (lexer.current ().name ) == " const" );
44514486 std::optional<Location> condKeywordLocation = lexer.current ().location ;
0 commit comments