summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/prism/ffi.rb3
-rw-r--r--prism/extension.c10
-rw-r--r--prism/options.c28
-rw-r--r--prism/options.h40
-rw-r--r--prism/parser.h10
-rw-r--r--prism/prism.c10
-rw-r--r--test/prism/snapshots/arrays.txt8
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/assignment.txt8
-rw-r--r--test/prism/snapshots/whitequark/masgn_attr.txt2
9 files changed, 106 insertions, 13 deletions
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb
index 8324f722a7..4c42e5061b 100644
--- a/lib/prism/ffi.rb
+++ b/lib/prism/ffi.rb
@@ -314,6 +314,9 @@ module Prism
template << "C"
values << (options.fetch(:verbose, true) ? 0 : 1)
+ template << "C"
+ values << { nil => 0, "3.3.0" => 1, "latest" => 0 }.fetch(options[:version])
+
template << "L"
if (scopes = options[:scopes])
values << scopes.length
diff --git a/prism/extension.c b/prism/extension.c
index 6cf007b4df..6dc1993657 100644
--- a/prism/extension.c
+++ b/prism/extension.c
@@ -22,6 +22,7 @@ ID rb_option_id_encoding;
ID rb_option_id_line;
ID rb_option_id_frozen_string_literal;
ID rb_option_id_verbose;
+ID rb_option_id_version;
ID rb_option_id_scopes;
/******************************************************************************/
@@ -131,6 +132,14 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, value == Qtrue);
} else if (key_id == rb_option_id_verbose) {
pm_options_suppress_warnings_set(options, value != Qtrue);
+ } else if (key_id == rb_option_id_version) {
+ if (!NIL_P(value)) {
+ const char *version = check_string(value);
+
+ if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
+ rb_raise(rb_eArgError, "invalid version: %"PRIsVALUE, value);
+ }
+ }
} else if (key_id == rb_option_id_scopes) {
if (!NIL_P(value)) build_options_scopes(options, value);
} else {
@@ -1013,6 +1022,7 @@ Init_prism(void) {
rb_option_id_line = rb_intern_const("line");
rb_option_id_frozen_string_literal = rb_intern_const("frozen_string_literal");
rb_option_id_verbose = rb_intern_const("verbose");
+ rb_option_id_version = rb_intern_const("version");
rb_option_id_scopes = rb_intern_const("scopes");
/**
diff --git a/prism/options.c b/prism/options.c
index 85d04d6272..0dcae0d16f 100644
--- a/prism/options.c
+++ b/prism/options.c
@@ -41,6 +41,33 @@ pm_options_suppress_warnings_set(pm_options_t *options, bool suppress_warnings)
}
/**
+ * Set the version option on the given options struct by parsing the given
+ * string. If the string contains an invalid option, this returns false.
+ * Otherwise, it returns true.
+ */
+PRISM_EXPORTED_FUNCTION bool
+pm_options_version_set(pm_options_t *options, const char *version, size_t length) {
+ if (version == NULL && length == 0) {
+ options->version = PM_OPTIONS_VERSION_LATEST;
+ return true;
+ }
+
+ if (length == 5) {
+ if (strncmp(version, "3.3.0", 5) == 0) {
+ options->version = PM_OPTIONS_VERSION_CRUBY_3_3_0;
+ return true;
+ }
+
+ if (strncmp(version, "latest", 6) == 0) {
+ options->version = PM_OPTIONS_VERSION_LATEST;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
* Allocate and zero out the scopes array on the given options struct.
*/
PRISM_EXPORTED_FUNCTION void
@@ -163,6 +190,7 @@ pm_options_read(pm_options_t *options, const char *data) {
options->frozen_string_literal = *data++;
options->suppress_warnings = *data++;
+ options->version = (pm_options_version_t) *data++;
uint32_t scopes_count = pm_options_read_u32(data);
data += 4;
diff --git a/prism/options.h b/prism/options.h
index 8608838da8..130d635b98 100644
--- a/prism/options.h
+++ b/prism/options.h
@@ -25,6 +25,19 @@ typedef struct pm_options_scope {
} pm_options_scope_t;
/**
+ * The version of prism that we should be parsing with. This is used to allow
+ * consumers to specify which behavior they want in case they need to parse
+ * exactly as a specific version of CRuby.
+ */
+typedef enum {
+ /** The current version of prism. */
+ PM_OPTIONS_VERSION_LATEST = 0,
+
+ /** The vendored version of prism in CRuby 3.3.0. */
+ PM_OPTIONS_VERSION_CRUBY_3_3_0 = 1
+} pm_options_version_t;
+
+/**
* The options that can be passed to the parser.
*/
typedef struct {
@@ -55,6 +68,13 @@ typedef struct {
*/
pm_options_scope_t *scopes;
+ /**
+ * The version of prism that we should be parsing with. This is used to
+ * allow consumers to specify which behavior they want in case they need to
+ * parse exactly as a specific version of CRuby.
+ */
+ pm_options_version_t version;
+
/** Whether or not the frozen string literal option has been set. */
bool frozen_string_literal;
@@ -107,6 +127,18 @@ PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *
PRISM_EXPORTED_FUNCTION void pm_options_suppress_warnings_set(pm_options_t *options, bool suppress_warnings);
/**
+ * Set the version option on the given options struct by parsing the given
+ * string. If the string contains an invalid option, this returns false.
+ * Otherwise, it returns true.
+ *
+ * @param options The options struct to set the version on.
+ * @param version The version to set.
+ * @param length The length of the version string.
+ * @return Whether or not the version was parsed successfully.
+ */
+PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length);
+
+/**
* Allocate and zero out the scopes array on the given options struct.
*
* @param options The options struct to initialize the scopes array on.
@@ -167,9 +199,17 @@ PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
* | ... | the encoding bytes |
* | `1` | frozen string literal |
* | `1` | suppress warnings |
+ * | `1` | the version |
* | `4` | the number of scopes |
* | ... | the scopes |
*
+ * The version field is an enum, so it should be one of the following values:
+ *
+ * | value | version |
+ * | ----- | ------------------------- |
+ * | `0` | use the latest version of prism |
+ * | `1` | use the version of prism that is vendored in CRuby 3.3.0 |
+ *
* Each scope is layed out as follows:
*
* | # bytes | field |
diff --git a/prism/parser.h b/prism/parser.h
index 2c58131b19..9f38dc5830 100644
--- a/prism/parser.h
+++ b/prism/parser.h
@@ -9,6 +9,7 @@
#include "prism/ast.h"
#include "prism/defines.h"
#include "prism/encoding.h"
+#include "prism/options.h"
#include "prism/util/pm_constant_pool.h"
#include "prism/util/pm_list.h"
#include "prism/util/pm_newline_list.h"
@@ -662,6 +663,12 @@ struct pm_parser {
*/
const pm_encoding_t *explicit_encoding;
+ /** The current parameter name id on parsing its default value. */
+ pm_constant_id_t current_param_name;
+
+ /** The version of prism that we should use to parse. */
+ pm_options_version_t version;
+
/** Whether or not we're at the beginning of a command. */
bool command_start;
@@ -684,9 +691,6 @@ struct pm_parser {
/** This flag indicates that we are currently parsing a keyword argument. */
bool in_keyword_arg;
- /** The current parameter name id on parsing its default value. */
- pm_constant_id_t current_param_name;
-
/**
* Whether or not the parser has seen a token that has semantic meaning
* (i.e., a token that is not a comment or whitespace).
diff --git a/prism/prism.c b/prism/prism.c
index ec319f2cac..03df698449 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -2172,11 +2172,16 @@ pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
static pm_index_target_node_t *
pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
pm_index_target_node_t *node = PM_ALLOC_NODE(parser, pm_index_target_node_t);
+ pm_node_flags_t flags = target->base.flags;
+
+ if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3_0) {
+ flags |= PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE;
+ }
*node = (pm_index_target_node_t) {
{
.type = PM_INDEX_TARGET_NODE,
- .flags = target->base.flags,
+ .flags = flags,
.location = target->base.location
},
.receiver = target->receiver,
@@ -17320,6 +17325,9 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
parser->suppress_warnings = true;
}
+ // version option
+ parser->version = options->version;
+
// scopes option
for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
const pm_options_scope_t *scope = pm_options_scope_get(options, scope_index);
diff --git a/test/prism/snapshots/arrays.txt b/test/prism/snapshots/arrays.txt
index 93f5c8fbc1..40d4cbed4f 100644
--- a/test/prism/snapshots/arrays.txt
+++ b/test/prism/snapshots/arrays.txt
@@ -430,7 +430,7 @@
├── @ MultiWriteNode (location: (41,0)-(41,21))
│ ├── lefts: (length: 2)
│ │ ├── @ IndexTargetNode (location: (41,0)-(41,6))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: attribute_write
│ │ │ ├── receiver:
│ │ │ │ @ CallNode (location: (41,0)-(41,3))
│ │ │ │ ├── flags: variable_call
@@ -452,7 +452,7 @@
│ │ │ ├── closing_loc: (41,5)-(41,6) = "]"
│ │ │ └── block: ∅
│ │ └── @ IndexTargetNode (location: (41,8)-(41,14))
- │ │ ├── flags: ∅
+ │ │ ├── flags: attribute_write
│ │ ├── receiver:
│ │ │ @ CallNode (location: (41,8)-(41,11))
│ │ │ ├── flags: variable_call
@@ -2166,7 +2166,7 @@
│ │ │ ├── operator_loc: (140,17)-(140,19) = "=>"
│ │ │ ├── reference:
│ │ │ │ @ IndexTargetNode (location: (140,20)-(140,24))
- │ │ │ │ ├── flags: ∅
+ │ │ │ │ ├── flags: attribute_write
│ │ │ │ ├── receiver:
│ │ │ │ │ @ CallNode (location: (140,20)-(140,21))
│ │ │ │ │ ├── flags: variable_call
@@ -2229,7 +2229,7 @@
│ │ ├── operator_loc: (142,17)-(142,19) = "=>"
│ │ ├── reference:
│ │ │ @ IndexTargetNode (location: (142,20)-(142,27))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: attribute_write
│ │ │ ├── receiver:
│ │ │ │ @ CallNode (location: (142,20)-(142,21))
│ │ │ │ ├── flags: variable_call
diff --git a/test/prism/snapshots/unparser/corpus/literal/assignment.txt b/test/prism/snapshots/unparser/corpus/literal/assignment.txt
index 18edafe415..4cb19d2867 100644
--- a/test/prism/snapshots/unparser/corpus/literal/assignment.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/assignment.txt
@@ -319,7 +319,7 @@
├── @ MultiWriteNode (location: (15,0)-(15,24))
│ ├── lefts: (length: 2)
│ │ ├── @ IndexTargetNode (location: (15,1)-(15,8))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: attribute_write
│ │ │ ├── receiver:
│ │ │ │ @ LocalVariableReadNode (location: (15,1)-(15,2))
│ │ │ │ ├── name: :a
@@ -338,7 +338,7 @@
│ │ │ ├── closing_loc: (15,7)-(15,8) = "]"
│ │ │ └── block: ∅
│ │ └── @ IndexTargetNode (location: (15,10)-(15,14))
- │ │ ├── flags: ∅
+ │ │ ├── flags: attribute_write
│ │ ├── receiver:
│ │ │ @ LocalVariableReadNode (location: (15,10)-(15,11))
│ │ │ ├── name: :a
@@ -370,7 +370,7 @@
├── @ MultiWriteNode (location: (16,0)-(16,21))
│ ├── lefts: (length: 2)
│ │ ├── @ IndexTargetNode (location: (16,1)-(16,5))
- │ │ │ ├── flags: ∅
+ │ │ │ ├── flags: attribute_write
│ │ │ ├── receiver:
│ │ │ │ @ LocalVariableReadNode (location: (16,1)-(16,2))
│ │ │ │ ├── name: :a
@@ -385,7 +385,7 @@
│ │ │ ├── closing_loc: (16,4)-(16,5) = "]"
│ │ │ └── block: ∅
│ │ └── @ IndexTargetNode (location: (16,7)-(16,11))
- │ │ ├── flags: ∅
+ │ │ ├── flags: attribute_write
│ │ ├── receiver:
│ │ │ @ LocalVariableReadNode (location: (16,7)-(16,8))
│ │ │ ├── name: :a
diff --git a/test/prism/snapshots/whitequark/masgn_attr.txt b/test/prism/snapshots/whitequark/masgn_attr.txt
index d87d7a6cb1..2a4dc38b7c 100644
--- a/test/prism/snapshots/whitequark/masgn_attr.txt
+++ b/test/prism/snapshots/whitequark/masgn_attr.txt
@@ -34,7 +34,7 @@
│ │ │ ├── name: :a=
│ │ │ └── message_loc: (3,5)-(3,6) = "a"
│ │ └── @ IndexTargetNode (location: (3,8)-(3,18))
- │ │ ├── flags: ∅
+ │ │ ├── flags: attribute_write
│ │ ├── receiver:
│ │ │ @ SelfNode (location: (3,8)-(3,12))
│ │ ├── opening_loc: (3,12)-(3,13) = "["