Skip to content

[5.7][SwiftSyntax] Add an API to enable or disable bare slash regex literals from SwiftSyntax #59150

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
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
9 changes: 9 additions & 0 deletions include/swift-c/SyntaxParser/SwiftSyntaxParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ swiftparse_parser_create(void);
SWIFTPARSE_PUBLIC void
swiftparse_parser_dispose(swiftparse_parser_t);

/// Set the language version that should be used to parse the Swift source file.
SWIFTPARSE_PUBLIC void
swiftparse_parser_set_language_version(swiftparse_parser_t c_parser,
const char *version);

/// Set whether bare slash regex literals are enabled.
SWIFTPARSE_PUBLIC void swiftparse_parser_set_enable_bare_slash_regex_literal(
swiftparse_parser_t c_parser, bool enabled);

/// Invoked by the parser when a syntax node is parsed. The client should
/// return a pointer to associate with that particular node.
typedef swiftparse_client_node_t
Expand Down
2 changes: 1 addition & 1 deletion test/Syntax/Parser/unterminated_regex.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %swift-syntax-parser-test -dump-diags %s | %FileCheck %s
// RUN: %swift-syntax-parser-test -dump-diags --swift-version 5 --enable-bare-slash-regex %s | %FileCheck %s
// CHECK: 6:21 Error: unterminated regex literal
// CHECK: 1 error(s) 0 warnings(s) 0 note(s)

Expand Down
38 changes: 37 additions & 1 deletion tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "swift/AST/Module.h"
#include "swift/Basic/LangOptions.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Version.h"
#include "swift/Parse/Parser.h"
#include "swift/Parse/SyntaxParseActions.h"
#include "swift/Parse/SyntaxRegexFallbackLexing.h"
Expand Down Expand Up @@ -58,6 +59,13 @@ class SynParser {
swiftparse_node_handler_t NodeHandler = nullptr;
swiftparse_node_lookup_t NodeLookup = nullptr;
swiftparse_diagnostic_handler_t DiagHandler = nullptr;
/// The language version that should be used to parse the Swift source file.
/// If \c None this is the default langauge version specified in LangOptions.h
Optional<version::Version> EffectiveLanguageVersion;

/// Whether bare slash regex literals are enabled.
/// If \c None this is the default specified in LangOptions.h
Optional<bool> EnableBareSlashRegexLiteral;

public:
swiftparse_node_handler_t getNodeHandler() const {
Expand Down Expand Up @@ -90,6 +98,17 @@ class SynParser {
Block_release(prevBlk);
}

void setLanguageVersion(const char *versionString) {
if (auto version = version::Version::parseVersionString(
versionString, SourceLoc(), /*Diags=*/nullptr)) {
this->EffectiveLanguageVersion = version;
}
}

void setEnableBareSlashRegexLiteral(bool EnableBareSlashRegexLiteral) {
this->EnableBareSlashRegexLiteral = EnableBareSlashRegexLiteral;
}

~SynParser() {
setNodeHandler(nullptr);
setNodeLookup(nullptr);
Expand Down Expand Up @@ -493,7 +512,12 @@ swiftparse_client_node_t SynParser::parse(const char *source, size_t len) {

// Always enable bare /.../ regex literal in syntax parser.
langOpts.EnableExperimentalStringProcessing = true;
langOpts.EnableBareSlashRegexLiterals = true;
if (EnableBareSlashRegexLiteral && *EnableBareSlashRegexLiteral) {
langOpts.EnableBareSlashRegexLiterals = true;
}
if (EffectiveLanguageVersion) {
langOpts.EffectiveLanguageVersion = *EffectiveLanguageVersion;
}

auto parseActions =
std::make_shared<CLibParseActions>(*this, SM, bufID);
Expand All @@ -517,6 +541,18 @@ swiftparse_parser_create(void) {
return new SynParser();
}

void swiftparse_parser_set_language_version(swiftparse_parser_t c_parser,
const char *version) {
SynParser *parser = static_cast<SynParser *>(c_parser);
parser->setLanguageVersion(version);
}

void swiftparse_parser_set_enable_bare_slash_regex_literal(
swiftparse_parser_t c_parser, bool enabled) {
SynParser *parser = static_cast<SynParser *>(c_parser);
parser->setEnableBareSlashRegexLiteral(enabled);
}

void
swiftparse_parser_dispose(swiftparse_parser_t c_parser) {
SynParser *parser = static_cast<SynParser*>(c_parser);
Expand Down
2 changes: 2 additions & 0 deletions tools/libSwiftSyntaxParser/libSwiftSyntaxParser.exports
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
swiftparse_parse_string
swiftparse_parser_create
swiftparse_parser_set_language_version
swiftparse_parser_set_enable_bare_slash_regex_literal
swiftparse_parser_dispose
swiftparse_parser_set_node_handler
swiftparse_parser_set_node_lookup
Expand Down
45 changes: 34 additions & 11 deletions tools/swift-syntax-parser-test/swift-syntax-parser-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ Filename(cl::Positional, cl::desc("source file"), cl::Required);
static cl::opt<unsigned>
NumParses("n", cl::desc("number of invocations"), cl::init(1));

static cl::opt<std::string>
SwiftVersion("swift-version",
cl::desc("Interpret input according to a specific Swift "
"language version number"));

static cl::opt<bool>
EnableBareSlashRegex("enable-bare-slash-regex",
cl::desc("Enable or disable the use of forward slash "
"regular-expression literal syntax"));
}

namespace {
Expand Down Expand Up @@ -136,8 +145,14 @@ makeNode(const swiftparse_syntax_node_t *raw_node, StringRef source) {

static swiftparse_client_node_t
parse(StringRef source, swiftparse_node_handler_t node_handler,
StringRef swift_version, bool enable_bare_slash_regex,
swiftparse_diagnostic_handler_t diag_handler = nullptr) {
swiftparse_parser_t parser = swiftparse_parser_create();
if (!swift_version.empty()) {
swiftparse_parser_set_language_version(parser, swift_version.str().c_str());
}
swiftparse_parser_set_enable_bare_slash_regex_literal(
parser, enable_bare_slash_regex);
swiftparse_parser_set_node_handler(parser, node_handler);
swiftparse_parser_set_diagnostic_handler(parser, diag_handler);
swiftparse_client_node_t top =
Expand All @@ -146,13 +161,15 @@ parse(StringRef source, swiftparse_node_handler_t node_handler,
return top;
}

static int dumpTree(StringRef source) {
static int dumpTree(StringRef source, StringRef swiftVersion,
bool enableBareSlashRegex) {
swiftparse_node_handler_t nodeHandler =
^swiftparse_client_node_t(const swiftparse_syntax_node_t *raw_node) {
return makeNode(raw_node, source);
};

std::unique_ptr<SPNode> top = convertClientNode(parse(source, nodeHandler));
std::unique_ptr<SPNode> top = convertClientNode(
parse(source, nodeHandler, swiftVersion, enableBareSlashRegex));
top->dump(outs());

return 0;
Expand Down Expand Up @@ -217,16 +234,18 @@ static void printDiagInfo(const swiftparser_diagnostic_t diag,
}

static int dumpDiagnostics(StringRef source, llvm::SourceMgr &SM,
unsigned BufferId) {
unsigned BufferId, StringRef swiftVersion,
bool enableBareSlashRegex) {
swiftparse_node_handler_t nodeHandler =
^swiftparse_client_node_t(const swiftparse_syntax_node_t *raw_node) {
return makeNode(raw_node, source);
};
std::shared_ptr<PrintDiagData> pData = std::make_shared<PrintDiagData>();
convertClientNode(parse(source, nodeHandler,
convertClientNode(parse(
source, nodeHandler, swiftVersion, enableBareSlashRegex,
^(const swiftparser_diagnostic_t diag) {
printDiagInfo(diag, SM, BufferId, const_cast<PrintDiagData&>(*pData));
}));
printDiagInfo(diag, SM, BufferId, const_cast<PrintDiagData &>(*pData));
}));
return 0;
}

Expand Down Expand Up @@ -255,7 +274,8 @@ static void printTimeRecord(unsigned numInvoks, const TimeRecord &total,
OS << '\n';
}

static int timeParsing(StringRef source, unsigned numInvoks) {
static int timeParsing(StringRef source, unsigned numInvoks,
StringRef swiftVersion, bool enableBareSlashRegex) {
swiftparse_node_handler_t nodeHandler =
^swiftparse_client_node_t(const swiftparse_syntax_node_t *raw_node) {
return nullptr;
Expand All @@ -264,7 +284,7 @@ static int timeParsing(StringRef source, unsigned numInvoks) {
Timer timer;
timer.startTimer();
for (unsigned i = 0; i != numInvoks; ++i) {
parse(source, nodeHandler);
parse(source, nodeHandler, swiftVersion, enableBareSlashRegex);
}
timer.stopTimer();

Expand All @@ -288,10 +308,13 @@ int main(int argc, char *argv[]) {
auto BufferId = SM.AddNewSourceBuffer(std::move(*fileBufOrErr), SMLoc());
switch (options::Action) {
case ActionType::DumpTree:
return dumpTree(source);
return dumpTree(source, options::SwiftVersion,
options::EnableBareSlashRegex);
case ActionType::Time:
return timeParsing(source, options::NumParses);
return timeParsing(source, options::NumParses, options::SwiftVersion,
options::EnableBareSlashRegex);
case ActionType::Diagnostics:
return dumpDiagnostics(source, SM, BufferId);
return dumpDiagnostics(source, SM, BufferId, options::SwiftVersion,
options::EnableBareSlashRegex);
}
}