Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lute/luau/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
add_library(Lute.Luau STATIC)

target_sources(Lute.Luau PRIVATE
include/lute/configresolver.h
include/lute/luau.h
include/lute/moduleresolver.h
include/lute/resolverequire.h

src/configresolver.cpp
src/luau.cpp
src/moduleresolver.cpp
src/resolverequire.cpp
)

target_compile_features(Lute.Luau PUBLIC cxx_std_17)
target_include_directories(Lute.Luau PUBLIC "include" ${LIBUV_INCLUDE_DIR})
target_link_libraries(Lute.Luau PRIVATE Lute.Require Lute.Runtime uv_a Luau.Analysis Luau.Ast Luau.Compiler Luau.Require Luau.VM)
target_link_libraries(Lute.Luau PRIVATE Lute.Require Lute.Runtime uv_a Luau.Analysis Luau.Ast Luau.Compiler Luau.CLI.lib Luau.Require Luau.VM)
target_compile_options(Lute.Luau PRIVATE ${LUTE_OPTIONS})
22 changes: 22 additions & 0 deletions lute/luau/include/lute/configresolver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "Luau/LuauConfig.h"
Comment thread
vrn-sn marked this conversation as resolved.
Outdated

namespace Luau
{

// Based on LuteConfigResolver in tc.cpp.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait are we just duplicating this right now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah this one is more comprehensive than tc.cpp

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not exactly the same @Vighnesh-V did you say we wanted to use this one in configresolver instead of the implementation in tc.cpp?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have guessed we were pulling these file/config resolvers out into their own files so that tc.cpp could use them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea I think the version in this PR is the tc.cpp LuteConfigResolverwith the addition of handling.config.luau(bc thetc.cpponly handles.luaurc`

struct LuteConfigResolver : Luau::ConfigResolver
{
Luau::Config defaultConfig;
mutable std::unordered_map<std::string, Luau::Config> configCache;
mutable std::vector<std::pair<std::string, std::string>> configErrors;

LuteConfigResolver(Luau::Mode mode);

const Luau::Config& getConfig(const Luau::ModuleName& name) const override;

const Luau::Config& readConfigRec(const std::string& path) const;
};

} // namespace Luau
19 changes: 19 additions & 0 deletions lute/luau/include/lute/moduleresolver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "Luau/FileResolver.h"

namespace Luau
{

// Based on CliFileResolver in Analyze.cpp.
struct LuteModuleResolver : Luau::FileResolver
{
LuteModuleResolver() = default;

std::optional<Luau::SourceCode> readSource(const Luau::ModuleName& name) override;

// We are currently resolving modules and requires only, and will add support for Roblox globals / types in a subsequent PR.
std::optional<Luau::ModuleInfo> resolveModule(const Luau::ModuleInfo* context, Luau::AstExpr* node) override;
};

} // namespace Luau
79 changes: 79 additions & 0 deletions lute/luau/src/configresolver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "lute/configresolver.h"

#include "Luau/ParseResult.h"
#include "Luau/FileUtils.h"
#include "Luau/LuauConfig.h"
Comment thread
vrn-sn marked this conversation as resolved.
Outdated

namespace Luau
{

LuteConfigResolver::LuteConfigResolver(Luau::Mode mode)
{
defaultConfig.mode = mode;
}

const Luau::Config& LuteConfigResolver::getConfig(const Luau::ModuleName& name) const
{
std::optional<std::string> path = getParentPath(name);
if (!path)
return defaultConfig;

return readConfigRec(*path);
}

const Luau::Config& LuteConfigResolver::readConfigRec(const std::string& path) const
{
auto it = configCache.find(path);
if (it != configCache.end())
return it->second;

std::optional<std::string> parent = getParentPath(path);
Luau::Config result = parent ? readConfigRec(*parent) : defaultConfig;

std::optional<std::string> configPath = joinPaths(path, Luau::kConfigName);
if (!isFile(*configPath))
configPath = std::nullopt;

std::optional<std::string> luauConfigPath = joinPaths(path, Luau::kLuauConfigName);
if (!isFile(*luauConfigPath))
luauConfigPath = std::nullopt;

if (configPath && luauConfigPath)
{
std::string ambiguousError = Luau::format("Both %s and %s files exist", Luau::kConfigName, Luau::kLuauConfigName);
configErrors.emplace_back(*configPath, std::move(ambiguousError));
}
else if (configPath)
{
if (std::optional<std::string> contents = readFile(*configPath))
{
Luau::ConfigOptions::AliasOptions aliasOpts;
aliasOpts.configLocation = *configPath;
aliasOpts.overwriteAliases = true;

Luau::ConfigOptions opts;
opts.aliasOptions = std::move(aliasOpts);

std::optional<std::string> error = Luau::parseConfig(*contents, result, opts);
if (error)
configErrors.emplace_back(*configPath, *error);
}
}
else if (luauConfigPath)
{
if (std::optional<std::string> contents = readFile(*luauConfigPath))
{
Luau::ConfigOptions::AliasOptions aliasOpts;
aliasOpts.configLocation = *luauConfigPath;
aliasOpts.overwriteAliases = true;

std::optional<std::string> error = Luau::extractLuauConfig(*contents, result, aliasOpts, Luau::InterruptCallbacks{});
if (error)
configErrors.emplace_back(*luauConfigPath, *error);
}
}

return configCache[path] = result;
}

} // namespace Luau
40 changes: 40 additions & 0 deletions lute/luau/src/moduleresolver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "lute/moduleresolver.h"

#include "Luau/Ast.h"
Comment thread
vrn-sn marked this conversation as resolved.
#include "Luau/FileUtils.h"

#include "lute/resolverequire.h"

namespace Luau
{

std::optional<Luau::SourceCode> LuteModuleResolver::readSource(const Luau::ModuleName& name)
{
if (std::optional<std::string> source = readFile(name))
return Luau::SourceCode{*source, Luau::SourceCode::Module};
return std::nullopt;
}

// We are currently resolving modules and requires only, and will add support for Roblox globals / types in a subsequent PR.
std::optional<Luau::ModuleInfo> LuteModuleResolver::resolveModule(const Luau::ModuleInfo* context, Luau::AstExpr* node)
{
if (auto expr = node->as<Luau::AstExprConstantString>())
{
std::string requirePath(expr->value.data, expr->value.size);

std::string error;
std::string requirerChunkname = "@" + context->name;
std::optional<std::string> absolutePath = resolveRequire(requirePath, std::move(requirerChunkname), &error);
if (!absolutePath)
{
printf("Failed to resolve require: %s\n", error.c_str());
return std::nullopt;
}

return Luau::ModuleInfo{*absolutePath};
}

return std::nullopt;
}

} // namespace Luau
8 changes: 5 additions & 3 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ target_sources(Lute.Test PRIVATE
src/stdsystem.test.cpp
src/staticrequires.test.cpp
src/stdsystem.test.cpp
src/compile.test.cpp)
src/compile.test.cpp
Comment thread
vrn-sn marked this conversation as resolved.
Outdated
src/moduleresolver.test.cpp
src/configresolver.test.cpp)

set_target_properties(Lute.Test PROPERTIES OUTPUT_NAME lute-tests)
target_compile_features(Lute.Test PUBLIC cxx_std_17)
target_link_libraries(Lute.Test PRIVATE Lute.CLI.lib Lute.Require Lute.Runtime Luau.CLI.lib Luau.Compiler Luau.VM)
target_compile_options(Lute.Test PRIVATE ${LUTE_OPTIONS})
target_link_libraries(Lute.Test PRIVATE Lute.CLI.lib Lute.Luau Lute.Require Lute.Runtime Luau.CLI.lib Luau.Analysis Luau.Compiler Luau.VM)
target_compile_options(Lute.Test PRIVATE ${LUTE_OPTIONS})
35 changes: 35 additions & 0 deletions tests/src/configresolver.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Tests for configuration resolver inheritance and ambiguity.
#include "doctest.h"
#include "luteprojectroot.h"

#include "lute/configresolver.h"

#include "Luau/FileUtils.h"
#include "Luau/LuauConfig.h"
Comment thread
vrn-sn marked this conversation as resolved.
Outdated

#include <sys/stat.h>
#include <sys/types.h>
Comment thread
vrn-sn marked this conversation as resolved.
Outdated

TEST_CASE("configresolver")
{
std::string root = getLuteProjectRootAbsolute();
std::string baseDir = joinPaths(root, "tests/src/resolver");
std::string file = joinPaths(baseDir, "mainmodule.luau");

// There is a .luaurc in tests/src/resolver; verify resolver reads it without crashing
Luau::LuteConfigResolver configResolver(Luau::Mode::Nonstrict);
const Luau::Config& cfg = configResolver.getConfig(file);

// check that mode was set to strict per .luaurc
CHECK(cfg.mode == Luau::Mode::Strict);

// check the alias root was set
const Luau::Config::AliasInfo* aliasInfo = cfg.aliases.find("root");
CHECK(aliasInfo != nullptr);
CHECK(aliasInfo->value == "./");

// run readConfigRec on parent directory to verify inheritance
const Luau::Config& parentCfg = configResolver.readConfigRec(baseDir);
// mode should be the same as child since no override
CHECK(parentCfg.mode == Luau::Mode::Strict);
}
24 changes: 24 additions & 0 deletions tests/src/moduleresolver.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Simplified tests for module resolver functionality using public APIs.
#include "doctest.h"
#include "luteprojectroot.h"

#include "Luau/Ast.h"
#include "Luau/FileUtils.h"

#include "lute/moduleresolver.h"
#include "lute/resolverequire.h"

#include <string>

TEST_CASE("moduleresolver_read_source")
{
std::string root = getLuteProjectRootAbsolute();
std::string file = joinPaths(root, "tests/src/resolver/mainmodule.luau");
Luau::LuteModuleResolver resolver;
auto source = resolver.readSource(file);
REQUIRE(source);
CHECK(source->type == Luau::SourceCode::Module);
CHECK(source->source.find("require") != std::string::npos);
}

// TODO: add tests for resolveModule
6 changes: 6 additions & 0 deletions tests/src/resolver/.luaurc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"languageMode": "strict",
"aliases": {
"root": "./"
}
}
27 changes: 27 additions & 0 deletions tests/src/resolver/mainmodule.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
local types = require("@root/types")
local tableext = require("@std/tableext")

local testFilter: { [string]: number } = {
["a"] = 1,
["b"] = 2,
}

local a = {}
type tb = tableext.dictionary<number>

function a._a(a: number)
return function(s: string): types.test
return types(s, a)
end
end

a._b = tableext.map(testFilter, function(value)
return tostring(value)
end)

a._metadata = {
key = -1,
id = "nice",
}

return a
7 changes: 7 additions & 0 deletions tests/src/resolver/types.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type test = { [string]: number }

return function(s: string, n: number): test
return {
[s] = n,
}
end