From 7fd186081a35d7efbadd43cdd533ef160ffed851 Mon Sep 17 00:00:00 2001 From: Alexander Momchilov Date: Fri, 13 Sep 2024 11:38:22 -0400 Subject: [PATCH 1/3] Provide non-null `pm_options_t` --- parser/prism/Parser.cc | 10 +++++----- parser/prism/Parser.h | 32 ++++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/parser/prism/Parser.cc b/parser/prism/Parser.cc index 4a6b62fb9d0..9fb669727a0 100644 --- a/parser/prism/Parser.cc +++ b/parser/prism/Parser.cc @@ -3,23 +3,23 @@ namespace sorbet::parser::Prism { pm_parser_t *Parser::get_raw_parser_pointer() { - return parser.get(); + return &storage->parser; } Node Parser::parse_root() { - pm_node_t *root = pm_parse(parser.get()); + pm_node_t *root = pm_parse(get_raw_parser_pointer()); return Node{*this, root}; }; core::LocOffsets Parser::translateLocation(pm_location_t *location) { - uint32_t start = static_cast(location->start - parser->start); - uint32_t end = static_cast(location->end - parser->start); + uint32_t start = static_cast(location->start - storage->parser.start); + uint32_t end = static_cast(location->end - storage->parser.start); return core::LocOffsets{start, end}; } std::string_view Parser::resolveConstant(pm_constant_id_t constant_id) { - pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id); + pm_constant_t *constant = pm_constant_pool_id_to_constant(&storage->parser.constant_pool, constant_id); return std::string_view(reinterpret_cast(constant->start), constant->length); } diff --git a/parser/prism/Parser.h b/parser/prism/Parser.h index 1fe080efde5..1f998a8aba2 100644 --- a/parser/prism/Parser.h +++ b/parser/prism/Parser.h @@ -14,22 +14,34 @@ namespace sorbet::parser::Prism { class Node; +// A backing implemenation detail of `Parser`, which stores a Prism parser and its options in a single allocation. +struct ParserStorage { + pm_parser_t parser; + pm_options_t options; + + ParserStorage(std::string_view source_code) : parser{}, options{} { + pm_parser_init(&parser, reinterpret_cast(source_code.data()), source_code.size(), &options); + } + + ~ParserStorage() { + pm_parser_free(&parser); + pm_options_free(&options); + } + + ParserStorage(const ParserStorage &) = delete; + ParserStorage &operator=(const ParserStorage &) = delete; + ParserStorage(ParserStorage &&) = delete; + ParserStorage &operator=(ParserStorage &&) = delete; +}; + class Parser final { friend class Node; friend struct NodeDeleter; - std::shared_ptr parser; + std::shared_ptr storage; public: - Parser(std::string_view source_code) - : parser(new pm_parser_t, [](auto p) { - pm_parser_free(p); - delete (p); - }) { - const pm_options_t *options = nullptr; - pm_parser_init(parser.get(), reinterpret_cast(source_code.data()), source_code.size(), - options); - } + Parser(std::string_view source_code) : storage(std::make_shared(source_code)) {} Parser(const Parser &) = default; Parser &operator=(const Parser &) = default; From 74b5caa8c9129b5ee0276857191243bce25ca016 Mon Sep 17 00:00:00 2001 From: Alexander Momchilov Date: Fri, 13 Sep 2024 11:59:21 -0400 Subject: [PATCH 2/3] Parse using Ruby 3.3 syntax --- parser/prism/Parser.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/parser/prism/Parser.h b/parser/prism/Parser.h index 1f998a8aba2..8625e807558 100644 --- a/parser/prism/Parser.h +++ b/parser/prism/Parser.h @@ -16,10 +16,14 @@ class Node; // A backing implemenation detail of `Parser`, which stores a Prism parser and its options in a single allocation. struct ParserStorage { + // The version of Ruby syntax that we're parsing with Prism. This determines what syntax is supported or not. + static constexpr std::string_view ParsedRubyVersion = "3.3.0"; pm_parser_t parser; pm_options_t options; ParserStorage(std::string_view source_code) : parser{}, options{} { + pm_options_version_set(&options, ParsedRubyVersion.data(), ParsedRubyVersion.size()); + pm_parser_init(&parser, reinterpret_cast(source_code.data()), source_code.size(), &options); } From 082c0c9a19bb96cdb300886ab90c49ffad930110 Mon Sep 17 00:00:00 2001 From: Alexander Momchilov Date: Fri, 13 Sep 2024 12:02:15 -0400 Subject: [PATCH 3/3] Implement translation for `it` keyword --- parser/prism/Translator.cc | 10 +++- .../keyword_it.parse-tree.exp | 49 +++++++++++++++++++ test/prism_regression/keyword_it.rb | 15 ++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 test/prism_regression/keyword_it.parse-tree.exp create mode 100644 test/prism_regression/keyword_it.rb diff --git a/parser/prism/Translator.cc b/parser/prism/Translator.cc index ce0d9c20f7d..dbe580944ed 100644 --- a/parser/prism/Translator.cc +++ b/parser/prism/Translator.cc @@ -862,8 +862,14 @@ std::unique_ptr Translator::translate(pm_node_t *node) { case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: case PM_INTERPOLATED_SYMBOL_NODE: case PM_INTERPOLATED_X_STRING_NODE: - case PM_IT_LOCAL_VARIABLE_READ_NODE: - case PM_IT_PARAMETERS_NODE: + case PM_IT_LOCAL_VARIABLE_READ_NODE: { + // See Prism::ParserStorage::ParsedRubyVersion + unreachable("The `it` keyword was introduced in Ruby 3.4, which isn't supported by Sorbet yet."); + } + case PM_IT_PARAMETERS_NODE: { + // See Prism::ParserStorage::ParsedRubyVersion + unreachable("The `it` keyword was introduced in Ruby 3.4, which isn't supported by Sorbet yet."); + } case PM_LAMBDA_NODE: case PM_MATCH_LAST_LINE_NODE: case PM_MATCH_PREDICATE_NODE: diff --git a/test/prism_regression/keyword_it.parse-tree.exp b/test/prism_regression/keyword_it.parse-tree.exp new file mode 100644 index 00000000000..30a72d62e1a --- /dev/null +++ b/test/prism_regression/keyword_it.parse-tree.exp @@ -0,0 +1,49 @@ +Begin { + stmts = [ + Block { + send = Send { + receiver = Const { + scope = NULL + name = > + } + method = + args = [ + ] + } + args = NULL + body = Send { + receiver = NULL + method = + args = [ + ] + } + } + Block { + send = Send { + receiver = Const { + scope = NULL + name = > + } + method = + args = [ + ] + } + args = NULL + body = Begin { + stmts = [ + Assign { + lhs = LVarLhs { + name = + } + rhs = Integer { + val = "123" + } + } + LVar { + name = + } + ] + } + } + ] +} diff --git a/test/prism_regression/keyword_it.rb b/test/prism_regression/keyword_it.rb new file mode 100644 index 00000000000..a9f5c455486 --- /dev/null +++ b/test/prism_regression/keyword_it.rb @@ -0,0 +1,15 @@ +# typed: false + +# The `it` keyword was introduced in Ruby 3.4, which isn't supported by Sorbet yet. +# https://bugs.ruby-lang.org/issues/18980 +# +# For now, we'll just treat it like a local variable read or method call. + +Proc.new do + it # Prior to Ruby 3.4, this would just be a regular method call +end + +Proc.new do + it = 123 # Prior to Ruby 3.4, this would just be a local variable write + it # ... and this is a local variable read. +end