Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion tslang/include/TypeScript/DataStructs.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "TypeScript/TypeScriptCompiler/Defines.h"

#include <string>
#include <vector>

struct CompileOptions
{
Expand All @@ -29,7 +30,9 @@ struct CompileOptions
// `--entry-point`. Without that, a library whose root merely initializes a variable would
// define `main` too, and two of them fail to link with "duplicate symbol: main".
bool generateEntryPoint;
enum Exports exportOpt;
// --export filters: `all`, `none`, names or globs, `!name` to exclude; empty means the
// `export` keyword decides (see MLIRExportFilter.h)
std::vector<std::string> exportFilters;
bool embedExportDeclarations;
std::string outputFolder;
bool appendGCtorsToMethod;
Expand Down
63 changes: 63 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/MLIRExportFilter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#ifndef TYPESCRIPT_MLIRGENLOGIC_EXPORTFILTER_H
#define TYPESCRIPT_MLIRGENLOGIC_EXPORTFILTER_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/GlobPattern.h"

#include <string>

namespace typescript
{
// A filter is `all`, `none`, a name or glob matched against the short or namespaced
// name, or any of those prefixed with `!` to exclude.
inline bool matchesExportFilter(llvm::StringRef pattern, llvm::StringRef name, llvm::StringRef fullName)
{
if (pattern == "all")
{
return true;
}

if (pattern == "none")
{
return false;
}

auto glob = llvm::GlobPattern::create(pattern);
if (!glob)
{
llvm::consumeError(glob.takeError());
return pattern == name || pattern == fullName;
}

return (!name.empty() && glob->match(name)) || (!fullName.empty() && glob->match(fullName));
}

// Exclusions always win; without any including filter the `export` keyword decides.
inline bool isExportedByFilters(llvm::ArrayRef<std::string> filters, llvm::StringRef name, llvm::StringRef fullName,
bool hasExportKeyword)
{
auto hasIncluding = false;
auto included = false;
for (auto &filter : filters)
{
llvm::StringRef pattern(filter);
if (pattern.consume_front("!"))
{
if (matchesExportFilter(pattern, name, fullName))
{
return false;
}

continue;
}

hasIncluding = true;
included |= matchesExportFilter(pattern, name, fullName);
}

return hasIncluding ? included : hasExportKeyword;
}
} // namespace typescript

#endif // TYPESCRIPT_MLIRGENLOGIC_EXPORTFILTER_H
7 changes: 0 additions & 7 deletions tslang/include/TypeScript/TypeScriptCompiler/Defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,6 @@ enum Action
RunJIT
};

enum Exports
{
ExportsNotSet,
ExportAll,
IgnoreAll
};

// How compiled code reclaims heap memory. There have always been three of these - the flag
// this replaced meant "leak everything", not "collect differently" - but they were spelled
// as one boolean. See docs/reference-counting-evaluation.md.
Expand Down
53 changes: 47 additions & 6 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "TypeScript/MLIRLogic/MLIRDebugInfoHelper.h"
#include "TypeScript/MLIRLogic/MLIRPrinter.h"
#include "TypeScript/MLIRLogic/MLIRDeclarationPrinter.h"
#include "TypeScript/MLIRLogic/MLIRExportFilter.h"
#include "TypeScript/MLIRLogic/TypeOfOpHelper.h"
#include "TypeScript/VisitorAST.h"

Expand Down Expand Up @@ -2275,19 +2276,59 @@ class MLIRGenImpl

mlir::LogicalResult mlirGen(VariableDeclaration item, VariableClass varClass, const GenContext &genContext);

auto getExportModifier(Node node) -> boolean
// members are filtered by the name of the class or interface they belong to
StringRef getExportFilterName(Node node)
{
if (compileOptions.exportOpt == ExportAll)
if (node->parent == SyntaxKind::ClassDeclaration || node->parent == SyntaxKind::ClassExpression
|| node->parent == SyntaxKind::InterfaceDeclaration)
{
return true;
node = node->parent;
}

if (compileOptions.exportOpt == IgnoreAll)
if (node == SyntaxKind::ClassDeclaration || node == SyntaxKind::ClassExpression)
{
return false;
return MLIRHelper::getName(node.as<ClassLikeDeclaration>()->name, stringAllocator);
}

return hasModifier(node, SyntaxKind::ExportKeyword);
if (node == SyntaxKind::InterfaceDeclaration)
{
return MLIRHelper::getName(node.as<InterfaceDeclaration>()->name, stringAllocator);
}

if (node == SyntaxKind::EnumDeclaration)
{
return MLIRHelper::getName(node.as<EnumDeclaration>()->name, stringAllocator);
}

if (node == SyntaxKind::TypeAliasDeclaration)
{
return MLIRHelper::getName(node.as<TypeAliasDeclaration>()->name, stringAllocator);
}

if (node == SyntaxKind::FunctionDeclaration || node == SyntaxKind::FunctionExpression
|| node == SyntaxKind::ArrowFunction || node == SyntaxKind::MethodDeclaration)
{
return MLIRHelper::getName(node.as<FunctionLikeDeclarationBase>()->name, stringAllocator);
}

return StringRef();
}

auto getExportModifier(Node node, StringRef name) -> boolean
{
auto hasExportKeyword = hasModifier(node, SyntaxKind::ExportKeyword);
if (compileOptions.exportFilters.empty())
{
return hasExportKeyword;
}

auto fullName = name.empty() ? StringRef() : getFullNamespaceName(name);
return isExportedByFilters(compileOptions.exportFilters, name, fullName, hasExportKeyword);
}

auto getExportModifier(Node node) -> boolean
{
return getExportModifier(node, compileOptions.exportFilters.empty() ? StringRef() : getExportFilterName(node));
}

mlir::LogicalResult mlirGen(VariableDeclarationList variableDeclarationListAST, const GenContext &genContext);
Expand Down
24 changes: 17 additions & 7 deletions tslang/lib/TypeScript/MLIRGenVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -874,13 +874,14 @@ namespace mlirgen

varClass.isUsing = isUsing;

auto exportByDecorator = false;
if (variableDeclarationListAST->parent)
{
varClass.isPublic = hasModifier(variableDeclarationListAST->parent, SyntaxKind::ExportKeyword);
varClass.isExport = getExportModifier(variableDeclarationListAST->parent);
iterateDecorators(variableDeclarationListAST->parent, genContext, [&](StringRef name, SmallVector<StringRef> args) {
if (name == DLL_EXPORT)
{
exportByDecorator = true;
varClass.isExport = true;
}

Expand Down Expand Up @@ -943,16 +944,25 @@ namespace mlirgen
// folded away inside its module - a const function becomes the function and its global is
// erased (isGlobalConstLambda) - but other modules reach it by symbol, so it has to be the
// global they import: an importer reads `export const f = () => ...` out of variable `f`.
if (varClass.type == VariableType::Const && !isUsing && varClass.isExport && !varClass.isImport && !genContext.funcOp)
{
varClass.type = VariableType::Let;
}

for (auto &item : variableDeclarationListAST->declarations)
{
// we need it for support "undefined type" in 'let' without initialization
item->parent = variableDeclarationListAST;
if (mlir::failed(mlirGen(item, varClass, genContext)))

// --export filters by name, and one statement can declare several names
auto itemVarClass = varClass;
if (variableDeclarationListAST->parent && !exportByDecorator)
{
itemVarClass.isExport = getExportModifier(
variableDeclarationListAST->parent, MLIRHelper::getName(item->name, stringAllocator));
}

if (itemVarClass.type == VariableType::Const && !isUsing && itemVarClass.isExport && !itemVarClass.isImport && !genContext.funcOp)
{
itemVarClass.type = VariableType::Let;
}

if (mlir::failed(mlirGen(item, itemVarClass, genContext)))
{
return mlir::failure();
}
Expand Down
4 changes: 2 additions & 2 deletions tslang/tslang/opts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ extern cl::opt<bool> disableWarnings;
extern cl::opt<bool> generateDebugInfo;
extern cl::opt<bool> lldbDebugInfo;
extern cl::opt<std::string> TargetTriple;
extern cl::opt<enum Exports> exportAction;
extern cl::list<std::string> exportFilters;
extern cl::opt<bool> enableBuiltins;
extern cl::opt<bool> noDefaultLib;
extern cl::opt<std::string> outputFilename;
Expand All @@ -47,7 +47,7 @@ CompileOptions prepareOptions()
compileOptions.enableBuiltins = enableBuiltins.getValue();
compileOptions.noDefaultLib = noDefaultLib.getValue();
compileOptions.disableWarnings = disableWarnings.getValue();
compileOptions.exportOpt = exportAction.getValue();
compileOptions.exportFilters.assign(exportFilters.begin(), exportFilters.end());
compileOptions.embedExportDeclarations = embedExportDeclarationsAction.getValue();
compileOptions.generateDebugInfo = generateDebugInfo.getValue();
compileOptions.lldbDebugInfo = lldbDebugInfo.getValue();
Expand Down
5 changes: 2 additions & 3 deletions tslang/tslang/tslang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,8 @@ cl::opt<bool> disableWarnings("nowarn", cl::desc("Disable Warnings"), cl::cat(Ty
cl::opt<bool> verifyOwnership("verify-ownership", cl::desc("Check that every slot taking a reference gives it back on every path out of the function, unwind paths included"), cl::cat(TypeScriptCompilerCategory));
cl::opt<bool> generateDebugInfo("di", cl::desc("Generate Debug Infomation"), cl::cat(TypeScriptCompilerCategory));
cl::opt<bool> lldbDebugInfo("lldb", cl::desc("Debug Infomation for LLDB"), cl::cat(TypeScriptCompilerCategory));
cl::opt<enum Exports> exportAction("export", cl::desc("Export Symbols. (Useful to compile the same code into 'lib' (static library) and/or 'dll/so' (dynamic library)) "),
cl::values(clEnumValN(ExportAll, "all", "export all symbols")),
cl::values(clEnumValN(IgnoreAll, "none", "ignore all exports")),
cl::list<std::string> exportFilters("export", cl::desc("Export Symbols, comma separated: 'all', 'none', names or globs (short or namespaced, e.g. 'add' or 'M.*') to export, '!name' to exclude. Without an including filter the 'export' keyword decides. (Useful to compile the same code into 'lib' (static library) and/or 'dll/so' (dynamic library))"),
cl::value_desc("all|none|name|!name"), cl::ZeroOrMore, cl::MiscFlags::CommaSeparated,
cl::cat(TypeScriptCompilerCategory));

cl::opt<bool> embedExportDeclarationsAction("embed-declarations", cl::desc("Embed declarations as member __decls_lib_XXXX. (Needed in 'import' statement)"), cl::init(true), cl::cat(TypeScriptCompilerCategory));
Expand Down
1 change: 1 addition & 0 deletions tslang/unittests/MLIRGen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
add_mlir_unittest(MLIRGenTests
TypeToString.cpp
DeclarationPrinter.cpp
ExportFilter.cpp
TypeHelper.cpp
)
get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
Expand Down
62 changes: 62 additions & 0 deletions tslang/unittests/MLIRGen/ExportFilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "TypeScript/MLIRLogic/MLIRExportFilter.h"

#include "gtest/gtest.h"

using namespace typescript;

namespace
{
bool exported(std::vector<std::string> filters, llvm::StringRef name, llvm::StringRef fullName, bool keyword)
{
return isExportedByFilters(filters, name, fullName, keyword);
}
} // namespace

TEST(ExportFilterTest, no_filters_follow_export_keyword)
{
EXPECT_TRUE(exported({}, "add", "M.add", true));
EXPECT_FALSE(exported({}, "add", "M.add", false));
}

TEST(ExportFilterTest, all_and_none_keep_their_meaning)
{
EXPECT_TRUE(exported({"all"}, "add", "M.add", false));
EXPECT_FALSE(exported({"none"}, "add", "M.add", true));
}

TEST(ExportFilterTest, name_filter_exports_only_matching_names)
{
EXPECT_TRUE(exported({"add"}, "add", "M.add", false));
EXPECT_TRUE(exported({"M.add"}, "add", "M.add", false));
EXPECT_FALSE(exported({"add"}, "sub", "M.sub", true));
EXPECT_TRUE(exported({"add", "sub"}, "sub", "M.sub", false));
}

TEST(ExportFilterTest, glob_filter_matches_short_or_namespaced_name)
{
EXPECT_TRUE(exported({"M.*"}, "add", "M.add", false));
EXPECT_FALSE(exported({"N.*"}, "add", "M.add", true));
EXPECT_TRUE(exported({"calc_?"}, "calc_1", "M.calc_1", false));
}

TEST(ExportFilterTest, exclusion_only_filters_the_export_keyword)
{
EXPECT_TRUE(exported({"!sub"}, "add", "M.add", true));
EXPECT_FALSE(exported({"!sub"}, "add", "M.add", false));
EXPECT_FALSE(exported({"!sub"}, "sub", "M.sub", true));
}

TEST(ExportFilterTest, exclusion_wins_over_inclusion)
{
EXPECT_FALSE(exported({"all", "!add"}, "add", "M.add", true));
EXPECT_TRUE(exported({"all", "!add"}, "sub", "M.sub", false));
EXPECT_FALSE(exported({"M.*", "!M.internal*"}, "internalHelper", "M.internalHelper", true));
EXPECT_FALSE(exported({"!add", "add"}, "add", "M.add", true));
}

TEST(ExportFilterTest, unnamed_declaration_matches_only_all)
{
EXPECT_TRUE(exported({"all"}, "", "", false));
EXPECT_FALSE(exported({"*"}, "", "", true));
EXPECT_TRUE(exported({"!add"}, "", "", true));
}
Loading