Skip to content

Commit 1ec5d7c

Browse files
committed
Split trivia between leading and trailing trivia
1 parent f52c277 commit 1ec5d7c

File tree

2 files changed

+69
-3
lines changed

2 files changed

+69
-3
lines changed

luau/src/luau.cpp

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ struct AstSerialize : public Luau::AstVisitor
118118

119119
// absolute index for the table where we're storing locals
120120
int localTableIndex;
121+
// reference to previously serialized token
122+
int lastTokenRef = LUA_NOREF;
121123

122124
AstSerialize(lua_State* L, std::string_view source, Luau::CstNodeMap cstNodeMap, std::vector<Luau::Comment> commentLocations)
123125
: L(L)
@@ -247,6 +249,26 @@ struct AstSerialize : public Luau::AstVisitor
247249
return result;
248250
}
249251

252+
// Splits a list of trivia into trailing trivia for the previos token, and leading trivia for the next token
253+
// The trailing trivia consists of all trivia up to and including the first '\n' character seen
254+
static std::pair<std::vector<Trivia>, std::vector<Trivia>> splitTrivia(std::vector<Trivia> trivia)
255+
{
256+
size_t i = 0;
257+
for (i = 0; i < trivia.size(); i++)
258+
{
259+
if (trivia[i].kind == Trivia::Whitespace && trivia[i].text.find('\n') != std::string::npos)
260+
break;
261+
}
262+
263+
if (i == trivia.size())
264+
return {trivia, {}};
265+
266+
auto middleIter(trivia.begin());
267+
std::advance(middleIter, i + 1);
268+
269+
return {std::vector<Trivia>(trivia.begin(), middleIter), std::vector<Trivia>(middleIter, trivia.end())};
270+
}
271+
250272
void serialize(Luau::Position position)
251273
{
252274
lua_rawcheckstack(L, 2);
@@ -401,9 +423,27 @@ struct AstSerialize : public Luau::AstVisitor
401423
lua_rawcheckstack(L, 2);
402424
lua_createtable(L, 0, nrec + 3);
403425

404-
// TODO: split up into leading / trailing trivia
405-
const auto leadingTrivia = extractTrivia(position);
406-
serializeTrivia(leadingTrivia);
426+
const auto trivia = extractTrivia(position);
427+
if (lastTokenRef != LUA_NOREF)
428+
{
429+
const auto [trailingTrivia, leadingTrivia] = splitTrivia(trivia);
430+
431+
lua_getref(L, lastTokenRef);
432+
LUAU_ASSERT(lua_istable(L, -1));
433+
434+
serializeTrivia(trailingTrivia);
435+
lua_setfield(L, -2, "trailingTrivia");
436+
lua_pop(L, 1);
437+
lua_unref(L, lastTokenRef);
438+
lastTokenRef = LUA_NOREF;
439+
440+
serializeTrivia(leadingTrivia);
441+
}
442+
else
443+
{
444+
serializeTrivia(trivia);
445+
}
446+
LUAU_ASSERT(lua_istable(L, -2));
407447
lua_setfield(L, -2, "leadingTrivia");
408448

409449
serialize(position);
@@ -416,6 +456,8 @@ struct AstSerialize : public Luau::AstVisitor
416456
lua_rawcheckstack(L, 2);
417457
lua_createtable(L, 0, 0);
418458
lua_setfield(L, -2, "trailingTrivia");
459+
460+
lastTokenRef = lua_ref(L, -1);
419461
}
420462

421463
void serializeLocals(Luau::AstArray<Luau::AstLocal*>& locals, size_t nrec = 0)

tests/testAstSerializer.spec.luau

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,29 @@ local function test_tokenizeWhitespace()
9494
assert(token.leadingTrivia[3].text == "\n")
9595
end
9696

97+
local function test_triviaSplitBetweenLeadingAndTrailing()
98+
local block = luau.parse("local x = 'test' -- comment\n" .. "-- comment 2\nlocal y = 'value'").root
99+
assert(#block.statements == 2)
100+
101+
local firstStmt = block.statements[1]
102+
assert(firstStmt.tag == "local")
103+
104+
local trailingToken = firstStmt.values[1].node
105+
assert(trailingToken.tag == "string")
106+
assert(#trailingToken.trailingTrivia == 3)
107+
assert(trailingToken.trailingTrivia[1].text == " ")
108+
assert(trailingToken.trailingTrivia[2].text == "-- comment")
109+
assert(trailingToken.trailingTrivia[3].text == "\n")
110+
111+
local secondStmt = block.statements[2]
112+
assert(secondStmt.tag == "local")
113+
114+
local leadingToken = secondStmt["local"]
115+
assert(#leadingToken.leadingTrivia == 2)
116+
assert(leadingToken.leadingTrivia[1].text == "-- comment 2")
117+
assert(leadingToken.leadingTrivia[2].text == "\n")
118+
end
119+
97120
local function test_roundtrippableAst()
98121
local files = {
99122
"examples/a.luau",
@@ -116,4 +139,5 @@ test_tokenContainsLeadingNewline()
116139
test_tokenContainsLeadingSingleLineComment()
117140
test_tokenContainsLeadingBlockComment()
118141
test_tokenizeWhitespace()
142+
test_triviaSplitBetweenLeadingAndTrailing()
119143
test_roundtrippableAst()

0 commit comments

Comments
 (0)