Skip to content

Commit 2647b8c

Browse files
committed
Split trivia between leading and trailing trivia
1 parent f89d483 commit 2647b8c

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
@@ -124,6 +124,8 @@ struct AstSerialize : public Luau::AstVisitor
124124

125125
// absolute index for the table where we're storing locals
126126
int localTableIndex;
127+
// reference to previously serialized token
128+
int lastTokenRef = LUA_NOREF;
127129

128130
AstSerialize(lua_State* L, std::string_view source, Luau::CstNodeMap cstNodeMap, std::vector<Luau::Comment> commentLocations)
129131
: L(L)
@@ -253,6 +255,26 @@ struct AstSerialize : public Luau::AstVisitor
253255
return result;
254256
}
255257

258+
// Splits a list of trivia into trailing trivia for the previos token, and leading trivia for the next token
259+
// The trailing trivia consists of all trivia up to and including the first '\n' character seen
260+
static std::pair<std::vector<Trivia>, std::vector<Trivia>> splitTrivia(std::vector<Trivia> trivia)
261+
{
262+
size_t i = 0;
263+
for (i = 0; i < trivia.size(); i++)
264+
{
265+
if (trivia[i].kind == Trivia::Whitespace && trivia[i].text.find('\n') != std::string::npos)
266+
break;
267+
}
268+
269+
if (i == trivia.size())
270+
return {trivia, {}};
271+
272+
auto middleIter(trivia.begin());
273+
std::advance(middleIter, i + 1);
274+
275+
return {std::vector<Trivia>(trivia.begin(), middleIter), std::vector<Trivia>(middleIter, trivia.end())};
276+
}
277+
256278
void serialize(Luau::Position position)
257279
{
258280
lua_rawcheckstack(L, 2);
@@ -407,9 +429,27 @@ struct AstSerialize : public Luau::AstVisitor
407429
lua_rawcheckstack(L, 2);
408430
lua_createtable(L, 0, nrec + 3);
409431

410-
// TODO: split up into leading / trailing trivia
411-
const auto leadingTrivia = extractTrivia(position);
412-
serializeTrivia(leadingTrivia);
432+
const auto trivia = extractTrivia(position);
433+
if (lastTokenRef != LUA_NOREF)
434+
{
435+
const auto [trailingTrivia, leadingTrivia] = splitTrivia(trivia);
436+
437+
lua_getref(L, lastTokenRef);
438+
LUAU_ASSERT(lua_istable(L, -1));
439+
440+
serializeTrivia(trailingTrivia);
441+
lua_setfield(L, -2, "trailingTrivia");
442+
lua_pop(L, 1);
443+
lua_unref(L, lastTokenRef);
444+
lastTokenRef = LUA_NOREF;
445+
446+
serializeTrivia(leadingTrivia);
447+
}
448+
else
449+
{
450+
serializeTrivia(trivia);
451+
}
452+
LUAU_ASSERT(lua_istable(L, -2));
413453
lua_setfield(L, -2, "leadingTrivia");
414454

415455
serialize(position);
@@ -422,6 +462,8 @@ struct AstSerialize : public Luau::AstVisitor
422462
lua_rawcheckstack(L, 2);
423463
lua_createtable(L, 0, 0);
424464
lua_setfield(L, -2, "trailingTrivia");
465+
466+
lastTokenRef = lua_ref(L, -1);
425467
}
426468

427469
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)