Skip to content

Commit 8b833b9

Browse files
committed
v0.20.4+luau724
1 parent 2e06bf3 commit 8b833b9

32 files changed

Lines changed: 1736 additions & 333 deletions

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "luau0-src"
3-
version = "0.20.3+luau723"
3+
version = "0.20.4+luau724"
44
authors = ["Aleksandr Orlenko <zxteam@protonmail.com>"]
55
edition = "2024"
66
repository = "https://github.com/mlua-rs/luau-src-rs"

luau/Ast/include/Luau/Cst.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ class CstStatLocal : public CstNode
272272

273273
CstStatLocal(AstArray<Position> varsAnnotationColonPositions, AstArray<Position> varsCommaPositions, AstArray<Position> valuesCommaPositions);
274274

275+
// if the StatLocal is being exported, this is the position of `const` or `local`
276+
Position declarationKeywordPosition;
275277
AstArray<Position> varsAnnotationColonPositions;
276278
AstArray<Position> varsCommaPositions;
277279
AstArray<Position> valuesCommaPositions;

luau/Ast/include/Luau/PrettyPrinter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ std::string toString(AstNode* node);
2323
void dump(AstNode* node);
2424

2525
// Never fails on a well-formed AST
26-
std::string prettyPrint(AstStatBlock& ast);
26+
std::string prettyPrint(AstStatBlock& block);
27+
std::string prettyPrint(AstStatBlock& block, const CstNodeMap& cstNodeMap);
2728
std::string prettyPrintWithTypes(AstStatBlock& block);
2829
std::string prettyPrintWithTypes(AstStatBlock& block, const CstNodeMap& cstNodeMap);
2930

luau/Ast/src/Cst.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ CstStatLocal::CstStatLocal(
123123
AstArray<Position> valuesCommaPositions
124124
)
125125
: CstNode(CstClassIndex())
126+
, declarationKeywordPosition(Position::missing())
126127
, varsAnnotationColonPositions(varsAnnotationColonPositions)
127128
, varsCommaPositions(varsCommaPositions)
128129
, valuesCommaPositions(valuesCommaPositions)

luau/Ast/src/Parser.cpp

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ LUAU_FASTFLAGVARIABLE(LuauConst2)
2727
// NOTE: this implicitly depends on LuauConst2
2828
LUAU_FASTFLAGVARIABLE(LuauExportValueSyntax)
2929
LUAU_FASTFLAGVARIABLE(DebugLuauNoInline)
30-
LUAU_FASTFLAGVARIABLE(LuauExternReadWriteAttributes)
3130
LUAU_FASTFLAGVARIABLE(LuauConstJustReportErrorForUnderfill)
3231
LUAU_FASTFLAGVARIABLE(DebugLuauUserDefinedClasses)
3332
LUAU_FASTFLAGVARIABLE(LuauAllowGlobalDeclarationToBeCalledClass)
3433
LUAU_FASTFLAGVARIABLE(LuauCstExprGroup)
3534
LUAU_FASTFLAGVARIABLE(LuauCstTypeGroup)
35+
LUAU_FASTFLAGVARIABLE(LuauTableEntriesDontNeedToMatchIndent)
3636

3737
// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
3838
bool luau_telemetry_parsed_return_type_variadic_with_type_suffix = false;
@@ -501,26 +501,29 @@ AstStat* Parser::parseStat()
501501

502502
if (ident == "export")
503503
{
504-
// TODO: update export surface to support classes
505-
if (FFlag::DebugLuauUserDefinedClasses && AstName(lexer.current().name) == "class")
504+
if (FFlag::LuauExportValueSyntax && FFlag::LuauConst2)
506505
{
507-
nextLexeme();
508-
return parseClassStat(start, /*exported*/ true);
509-
}
510-
else if (FFlag::LuauExportValueSyntax && FFlag::LuauConst2)
511-
{
512-
if (lexer.current().type == Lexeme::ReservedLocal || lexer.current().type == Lexeme::ReservedFunction ||
513-
(lexer.current().type == Lexeme::Name && AstName(lexer.current().name) == "const"))
506+
Lexeme current = lexer.current();
507+
508+
if (current.type == Lexeme::ReservedLocal || current.type == Lexeme::ReservedFunction ||
509+
(current.type == Lexeme::Name && AstName(current.name) == "const") ||
510+
((FFlag::DebugLuauUserDefinedClasses && current.type == Lexeme::Name) && AstName(current.name) == "class"))
514511
{
515512
return parseExportValue(expr->location, expr->location.begin, AstArray<AstAttr*>({nullptr, 0}));
516513
}
517-
else if (lexer.current().type == Lexeme::Name && AstName(lexer.current().name) == "type")
514+
else if (current.type == Lexeme::Name && AstName(current.name) == "type")
518515
{
519-
Position typeKeywordPosition = lexer.current().location.begin;
516+
Position typeKeywordPosition = current.location.begin;
520517
nextLexeme();
521518
return parseTypeAlias(expr->location, /* exported= */ true, typeKeywordPosition);
522519
}
523520
}
521+
// TODO: remove with LuauExportValueSyntax
522+
else if (FFlag::DebugLuauUserDefinedClasses && AstName(lexer.current().name) == "class")
523+
{
524+
nextLexeme();
525+
return parseClassStat(start, /*exported*/ true);
526+
}
524527
else
525528
{
526529
if (lexer.current().type == Lexeme::Name && AstName(lexer.current().name) == "type")
@@ -1816,10 +1819,9 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
18161819
// global variable declaration whose name is `class`, not as a malformed class declaration. This allows
18171820
// us to support a global table like string/math/bit32 called `class`. CLI-203833 tracks the work to actually
18181821
// remove support for `declare class X [extends Y]` syntax.
1819-
else if (
1820-
(AstName(lexer.current().name) == "class" && (FFlag::LuauAllowGlobalDeclarationToBeCalledClass ? lexer.lookahead().type != ':' : true)) ||
1821-
AstName(lexer.current().name) == "extern"
1822-
)
1822+
else if ((AstName(lexer.current().name) == "class" &&
1823+
(FFlag::LuauAllowGlobalDeclarationToBeCalledClass ? lexer.lookahead().type != ':' : true)) ||
1824+
AstName(lexer.current().name) == "extern")
18231825
{
18241826
bool foundExtern = false;
18251827
if (AstName(lexer.current().name) == "extern")
@@ -1934,25 +1936,22 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
19341936
{
19351937
AstTableAccess access = AstTableAccess::ReadWrite;
19361938

1937-
if (FFlag::LuauExternReadWriteAttributes)
1939+
if (lexer.current().type == Lexeme::Name && lexer.lookahead().type != ':')
19381940
{
1939-
if (lexer.current().type == Lexeme::Name && lexer.lookahead().type != ':')
1941+
if (AstName(lexer.current().name) == "read")
19401942
{
1941-
if (AstName(lexer.current().name) == "read")
1942-
{
1943-
access = AstTableAccess::Read;
1944-
lexer.next();
1945-
}
1946-
else if (AstName(lexer.current().name) == "write")
1947-
{
1948-
access = AstTableAccess::Write;
1949-
lexer.next();
1950-
}
1951-
else
1952-
{
1953-
report(lexer.current().location, "Expected blank or 'read' or 'write' attribute, got '%s'", lexer.current().name);
1954-
lexer.next();
1955-
}
1943+
access = AstTableAccess::Read;
1944+
lexer.next();
1945+
}
1946+
else if (AstName(lexer.current().name) == "write")
1947+
{
1948+
access = AstTableAccess::Write;
1949+
lexer.next();
1950+
}
1951+
else
1952+
{
1953+
report(lexer.current().location, "Expected blank or 'read' or 'write' attribute, got '%s'", lexer.current().name);
1954+
lexer.next();
19561955
}
19571956
}
19581957

@@ -2060,7 +2059,7 @@ AstStat* Parser::parseExportValue(const Location& start, const Position keywordP
20602059
return true;
20612060
};
20622061

2063-
auto exportLocalStat = [&](AstStat* stat) -> AstStat*
2062+
auto exportLocalStat = [&](AstStat* stat, const Position& keywordPosition) -> AstStat*
20642063
{
20652064
if (AstStatLocal* localStat = stat->as<AstStatLocal>())
20662065
{
@@ -2073,6 +2072,14 @@ AstStat* Parser::parseExportValue(const Location& start, const Position keywordP
20732072

20742073
local->isExported = true;
20752074
}
2075+
2076+
if (options.storeCstData)
2077+
{
2078+
// if storeCstData is set, then when we parsed the local the cst data should be stored
2079+
CstStatLocal* cstStatLocal = cstNodeMap[stat]->as<CstStatLocal>();
2080+
LUAU_ASSERT(cstStatLocal);
2081+
cstStatLocal->declarationKeywordPosition = keywordPosition;
2082+
}
20762083
}
20772084
else
20782085
LUAU_ASSERT(!"Expected export local/const to parse as AstStatLocal");
@@ -2091,14 +2098,20 @@ AstStat* Parser::parseExportValue(const Location& start, const Position keywordP
20912098

20922099
if (lexer.current().type == Lexeme::ReservedLocal)
20932100
{
2101+
Position localKeywordPosition = lexer.current().location.begin;
2102+
20942103
if (lexer.lookahead().type == Lexeme::ReservedFunction)
20952104
return reportStatError(start, {}, {}, "'export' must be followed by an identifier or 'function'; try removing 'local'");
20962105

2097-
return exportLocalStat(parseLocal(start, keywordPosition, {nullptr, 0}, false));
2106+
return exportLocalStat(parseLocal(start, keywordPosition, {nullptr, 0}, false), localKeywordPosition);
20982107
}
20992108
else if (lexer.current().type == Lexeme::ReservedFunction)
21002109
{
21012110
auto funcStat = parseLocal(start, keywordPosition, attributes, true);
2111+
if (!funcStat->is<AstStatLocalFunction>())
2112+
// parseLocal returned a parse error
2113+
return funcStat;
2114+
21022115
auto func = funcStat->as<AstStatLocalFunction>();
21032116

21042117
if (!checkDuplicateExport(func->name->name, func->name->location))
@@ -2118,7 +2131,22 @@ AstStat* Parser::parseExportValue(const Location& start, const Position keywordP
21182131
if (lexer.current().type == Lexeme::ReservedFunction)
21192132
return reportStatError(start, {}, {}, "'export' must be followed by an identifier or 'function'");
21202133

2121-
return exportLocalStat(parseLocal(start, constKeywordPosition, {nullptr, 0}, true));
2134+
return exportLocalStat(parseLocal(start, constKeywordPosition, {nullptr, 0}, true), constKeywordPosition);
2135+
}
2136+
else if (FFlag::DebugLuauUserDefinedClasses && lexer.current().type == Lexeme::Name && AstName(lexer.current().name) == "class")
2137+
{
2138+
nextLexeme();
2139+
auto stat = parseClassStat(start, /*exported*/ true);
2140+
if (auto classStat = stat->as<AstStatClass>())
2141+
{
2142+
if (!checkDuplicateExport(classStat->name->name, classStat->name->location))
2143+
return reportStatError(
2144+
classStat->name->location, {}, copy<AstStat*>({classStat}), "Duplicate exported class '%s'", classStat->name->name.value
2145+
);
2146+
2147+
classStat->name->isExported = true;
2148+
}
2149+
return stat;
21222150
}
21232151

21242152
return reportStatError(start, {}, {}, "'export' must be followed by an identifier or 'function'");
@@ -3486,9 +3514,8 @@ std::optional<AstExprBinary::Op> Parser::checkBinaryConfusables(const BinaryOpPr
34863514
report(Location(start, next.location), "Unexpected '||'; did you mean 'or'?");
34873515
return AstExprBinary::Or;
34883516
}
3489-
else if (
3490-
curr.type == '!' && next.type == '=' && curr.location.end == next.location.begin && binaryPriority[AstExprBinary::CompareNe].left > limit
3491-
)
3517+
else if (curr.type == '!' && next.type == '=' && curr.location.end == next.location.begin &&
3518+
binaryPriority[AstExprBinary::CompareNe].left > limit)
34923519
{
34933520
nextLexeme();
34943521
report(Location(start, next.location), "Unexpected '!='; did you mean '~='?");
@@ -3948,10 +3975,8 @@ AstExpr* Parser::parseSimpleExpr()
39483975
{
39493976
return parseNumber();
39503977
}
3951-
else if (
3952-
lexer.current().type == Lexeme::RawString || lexer.current().type == Lexeme::QuotedString ||
3953-
lexer.current().type == Lexeme::InterpStringSimple
3954-
)
3978+
else if (lexer.current().type == Lexeme::RawString || lexer.current().type == Lexeme::QuotedString ||
3979+
lexer.current().type == Lexeme::InterpStringSimple)
39553980
{
39563981
return parseString();
39573982
}
@@ -4151,11 +4176,13 @@ AstExpr* Parser::parseTableConstructor()
41514176

41524177
MatchLexeme matchBrace = lexer.current();
41534178
expectAndConsume('{', "table literal");
4154-
unsigned lastElementIndent = 0;
4179+
// Clip with LuauTableEntriesDontNeedToMatchIndent
4180+
unsigned lastElementIndent_DEPRECATED = 0;
41554181

41564182
while (lexer.current().type != '}')
41574183
{
4158-
lastElementIndent = lexer.current().location.begin.column;
4184+
if (!FFlag::LuauTableEntriesDontNeedToMatchIndent)
4185+
lastElementIndent_DEPRECATED = lexer.current().location.begin.column;
41594186

41604187
if (lexer.current().type == '[')
41614188
{
@@ -4238,7 +4265,8 @@ AstExpr* Parser::parseTableConstructor()
42384265
{
42394266
nextLexeme();
42404267
}
4241-
else if ((lexer.current().type == '[' || lexer.current().type == Lexeme::Name) && lexer.current().location.begin.column == lastElementIndent)
4268+
else if ((lexer.current().type == '[' || lexer.current().type == Lexeme::Name) &&
4269+
(FFlag::LuauTableEntriesDontNeedToMatchIndent ? true : lexer.current().location.begin.column == lastElementIndent_DEPRECATED))
42424270
{
42434271
report(lexer.current().location, "Expected ',' after table constructor element");
42444272
}

luau/Ast/src/PrettyPrinter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,10 @@ struct Printer
988988
if (FFlag::LuauExportValueSyntax && FFlag::LuauConst2 && a->isExported)
989989
{
990990
writer.keyword("export");
991+
992+
if (cstNode)
993+
advance(cstNode->declarationKeywordPosition);
994+
991995
writer.keyword(a->isConst ? "const" : "local");
992996
}
993997
else if (FFlag::LuauConst2 && a->isConst)
@@ -2064,6 +2068,11 @@ std::string prettyPrint(AstStatBlock& block, const CstNodeMap& cstNodeMap)
20642068
return writer.str();
20652069
}
20662070

2071+
std::string prettyPrint(AstStatBlock& block)
2072+
{
2073+
return prettyPrint(block, CstNodeMap{nullptr});
2074+
}
2075+
20672076
std::string prettyPrintWithTypes(AstStatBlock& block, const CstNodeMap& cstNodeMap)
20682077
{
20692078
StringWriter writer;

0 commit comments

Comments
 (0)