Skip to content
This repository has been archived by the owner on Jun 12, 2022. It is now read-only.

Commit

Permalink
Properly resolve a script's children to allow indexing
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnnyMorganz committed Mar 31, 2022
1 parent 811f684 commit 3e8b97b
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 54 deletions.
21 changes: 11 additions & 10 deletions RequireResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,15 +241,9 @@ std::optional<ResolvedSourceMap> RojoResolver::parseSourceMap(const std::filesys
return std::nullopt;
}

std::optional<std::filesystem::path> RojoResolver::resolveRequireToRealPath(const std::string& requirePath, const SourceNode& root)
std::optional<SourceNode> RojoResolver::resolveRequireToSourceNode(const std::string& requirePath, const SourceNode& root)
{
auto pathParts = Luau::split(requirePath, '/');
// auto root = pathParts.front();

// if (roots.find(std::string(root)) == roots.end())
// return std::nullopt;

// SourceNode currentNode = roots.at(std::string(root));
SourceNode currentNode = root;

auto it = ++pathParts.begin(); // Skip first element
Expand All @@ -266,12 +260,19 @@ std::optional<std::filesystem::path> RojoResolver::resolveRequireToRealPath(cons
return std::nullopt;
}



it++;
}

return currentNode.path;
return currentNode;
}

std::optional<std::filesystem::path> RojoResolver::resolveRequireToRealPath(const std::string& requirePath, const SourceNode& root)
{
if (auto node = RojoResolver::resolveRequireToSourceNode(requirePath, root))
{
return node.value().path;
}
return std::nullopt;
}

std::optional<std::string> RojoResolver::resolveRealPathToVirtual(const ResolvedSourceMap& sourceMap, const std::filesystem::path& filePath)
Expand Down
1 change: 1 addition & 0 deletions RequireResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct ResolvedSourceMap
namespace RojoResolver
{
std::optional<ResolvedSourceMap> parseSourceMap(const std::filesystem::path& sourceMapPath);
std::optional<SourceNode> resolveRequireToSourceNode(const std::string& requirePath, const SourceNode& root);
std::optional<std::filesystem::path> resolveRequireToRealPath(const std::string& requirePath, const SourceNode& root);
Luau::SourceCode::Type sourceCodeTypeFromPath(const std::filesystem::path& path);
std::optional<std::string> resolveRealPathToVirtual(const ResolvedSourceMap& sourceMap, const std::filesystem::path& filePath);
Expand Down
110 changes: 66 additions & 44 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,36 @@ bool isManagedModule(const Luau::ModuleName& name)
return Luau::startsWith(name, "game/") || Luau::startsWith(name, "ProjectRoot/");
}

std::optional<std::string> getCurrentModuleVirtualPath(
const Luau::ModuleName& name, ResolvedSourceMap sourceMap, std::optional<std::filesystem::path> stdinFilepath)
{
if (isManagedModule(name))
{
return name;
}
else
{
// name is a file path which we need to translate to a Rojo path
std::filesystem::path filePath = name;
if (name == "-")
{
if (stdinFilepath)
{
filePath = stdinFilepath.value();
}
else
{
return std::nullopt;
}
}
auto virtualPath = RojoResolver::resolveRealPathToVirtual(sourceMap, filePath);
if (virtualPath)
return virtualPath.value();
}

return std::nullopt;
}

struct CliFileResolver : Luau::FileResolver
{
ResolvedSourceMap sourceMap;
Expand Down Expand Up @@ -183,30 +213,9 @@ struct CliFileResolver : Luau::FileResolver

if (g->name == "script")
{
// Resolve the current path at context.name
if (isManagedModule(context->name))
if (auto virtualPath = getCurrentModuleVirtualPath(context->name, sourceMap, stdinFilepath))
{
// We can just use this as the starting point
return Luau::ModuleInfo{context->name};
}
else
{
// context->name is a file path which we need to translate to a Rojo path
std::filesystem::path filePath = context->name;
if (context->name == "-")
{
if (stdinFilepath)
{
filePath = stdinFilepath.value();
}
else
{
return std::nullopt;
}
}
auto virtualPath = RojoResolver::resolveRealPathToVirtual(sourceMap, filePath);
if (virtualPath)
return Luau::ModuleInfo{virtualPath.value()};
return Luau::ModuleInfo{virtualPath.value()};
}
}
}
Expand Down Expand Up @@ -320,41 +329,31 @@ struct CliConfigResolver : Luau::ConfigResolver
}
};

std::optional<Luau::TypeFun> findExportedType(Luau::TypeChecker& typeChecker, const std::string& name)
{

if (typeChecker.globalScope->exportedTypeBindings.find(name) != typeChecker.globalScope->exportedTypeBindings.end())
{
return typeChecker.globalScope->exportedTypeBindings.at(name);
}
return std::nullopt;
}

Luau::TypeId makeInstanceType(Luau::TypeChecker& typeChecker, const SourceNode& node)
Luau::TypeId makeInstanceType(Luau::TypeArena& typeArena, const Luau::ScopePtr& globalScope, SourceNode& node)
{
std::optional<Luau::TypeFun> baseType;
if (node.className.has_value())
{
baseType = findExportedType(typeChecker, node.className.value());
baseType = globalScope->lookupType(node.className.value());
}
if (!baseType.has_value())
{
baseType = findExportedType(typeChecker, "Instance");
baseType = globalScope->lookupType("Instance");
}
LUAU_ASSERT(baseType); // TODO: is this ensured??
auto typeId = baseType.value().type;

if (node.children.size() > 0)
{
// Add the children
Luau::TableTypeVar children{Luau::TableState::Sealed, typeChecker.globalScope->level};
Luau::TableTypeVar children{Luau::TableState::Sealed, globalScope->level};
for (const auto& child : node.children)
{
auto childProperty = Luau::makeProperty(makeInstanceType(typeChecker, *child.second), "@luau/instance");
auto childProperty = Luau::makeProperty(makeInstanceType(typeArena, globalScope, *child.second), "@luau/instance");
children.props[child.first] = childProperty;
}
Luau::TypeId childId = typeChecker.globalTypes.addType(children);
typeId = Luau::makeIntersection(typeChecker.globalTypes, {typeId, childId});
Luau::TypeId childId = typeArena.addType(children);
typeId = Luau::makeIntersection(typeArena, {typeId, childId});
}
return typeId;
}
Expand Down Expand Up @@ -433,7 +432,6 @@ int main(int argc, char** argv)

CliConfigResolver configResolver;
Luau::Frontend frontend(&fileResolver, &configResolver, frontendOptions);

Luau::registerBuiltinTypes(frontend.typeChecker);

// If global definitions have been provided, then also register them
Expand Down Expand Up @@ -465,16 +463,17 @@ int main(int argc, char** argv)
{
for (const auto& services : root.children)
{
auto serviceType = findExportedType(frontend.typeChecker, services.first);
auto serviceType = frontend.typeChecker.globalScope->lookupType(services.first);
if (serviceType.has_value())
{
if (Luau::ClassTypeVar* ctv = Luau::getMutable<Luau::ClassTypeVar>(serviceType.value().type))
{
// Extend the props to include the children
for (const auto& child : (*services.second).children)
{
ctv->props[child.first] =
makeProperty(makeInstanceType(frontend.typeChecker, *(child.second)), "@luau/serviceChild");
ctv->props[child.first] = makeProperty(
makeInstanceType(frontend.typeChecker.globalTypes, frontend.typeChecker.globalScope, *(child.second)),
"@luau/serviceChild");
}
}
}
Expand All @@ -484,6 +483,29 @@ int main(int argc, char** argv)
}
}

auto moduleResolver = frontend.moduleResolver;

frontend.typeChecker.prepareModuleScope = [&moduleResolver, fileResolver, stdinFilepath](
const Luau::ModuleName& name, const Luau::ScopePtr& scope)
{
auto virtualPath = getCurrentModuleVirtualPath(name, fileResolver.sourceMap, stdinFilepath);
if (!virtualPath.has_value())
return;

auto node = RojoResolver::resolveRequireToSourceNode(virtualPath.value(), fileResolver.sourceMap.root);
if (!node.has_value())
return;

// HACK: we need a way to get the typeArena for the module, but I don't know how
// we can see that moduleScope->returnType is assigned before prepareModuleScope is called in TypeInfer, so we could try it this way...
LUAU_ASSERT(scope->returnType);
auto typeArena = scope->returnType->owningArena;
LUAU_ASSERT(typeArena);
auto ty = makeInstanceType(*typeArena, scope, node.value());

scope->bindings[Luau::AstName("script")] = Luau::Binding{ty, Luau::Location{}, {}, {}, std::nullopt};
};

Luau::freeze(frontend.typeChecker.globalTypes);

std::vector<std::filesystem::path> files = getSourceFiles(argc, argv);
Expand Down

0 comments on commit 3e8b97b

Please sign in to comment.