-
Notifications
You must be signed in to change notification settings - Fork 42
Feature: Lute Config and Module Resolvers #535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
fb1891b
split lute config and module resolvers into separate files
annieetang 15c79ce
syntax/setup fixes
annieetang 9de6bf5
add newline to eof
annieetang 7c84839
working changes and partially working tests
annieetang 3c9437b
format and remove wip tests
annieetang a525d5c
stylua
annieetang 91198b4
Merge branch 'primary' into annietang/lute_config_and_module_resolvers
annieetang b331981
address comments
annieetang bc80966
Merge branch 'annietang/lute_config_and_module_resolvers' of https://…
annieetang 6d73377
newline at eof
annieetang 60e6b11
fix includes
annieetang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| #pragma once | ||
|
|
||
| #include "Luau/Config.h" | ||
|
|
||
| namespace Luau | ||
| { | ||
|
|
||
| // Based on LuteConfigResolver in tc.cpp. | ||
| 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 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| #include "lute/configresolver.h" | ||
|
|
||
| #include "Luau/LuauConfig.h" | ||
| #include "Luau/FileUtils.h" | ||
| #include "Luau/StringUtils.h" | ||
|
|
||
| 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 = 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| #include "lute/moduleresolver.h" | ||
|
|
||
| #include "Luau/Ast.h" | ||
|
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 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| // Tests for configuration resolver inheritance and ambiguity. | ||
| #include "doctest.h" | ||
| #include "luteprojectroot.h" | ||
|
|
||
| #include "lute/configresolver.h" | ||
|
|
||
| #include "Luau/FileUtils.h" | ||
|
|
||
| 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); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "languageMode": "strict", | ||
| "aliases": { | ||
| "root": "./" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.cppThere was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.cppLuteConfigResolverwith the addition of handling.config.luau(bc thetc.cpponly handles.luaurc`