prism 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -1
- data/CONTRIBUTING.md +0 -4
- data/README.md +1 -0
- data/config.yml +66 -9
- data/docs/fuzzing.md +1 -1
- data/docs/ripper_translation.md +22 -0
- data/ext/prism/api_node.c +30 -12
- data/ext/prism/extension.c +107 -372
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +138 -70
- data/include/prism/diagnostic.h +7 -2
- data/include/prism/node.h +0 -21
- data/include/prism/parser.h +23 -25
- data/include/prism/regexp.h +17 -8
- data/include/prism/static_literals.h +3 -2
- data/include/prism/util/pm_char.h +1 -2
- data/include/prism/util/pm_constant_pool.h +0 -8
- data/include/prism/util/pm_integer.h +16 -9
- data/include/prism/util/pm_string.h +0 -8
- data/include/prism/version.h +2 -2
- data/include/prism.h +0 -11
- data/lib/prism/compiler.rb +3 -0
- data/lib/prism/dispatcher.rb +14 -0
- data/lib/prism/dot_visitor.rb +22 -3
- data/lib/prism/dsl.rb +7 -2
- data/lib/prism/ffi.rb +24 -3
- data/lib/prism/inspect_visitor.rb +10 -8
- data/lib/prism/mutation_compiler.rb +6 -1
- data/lib/prism/node.rb +166 -241
- data/lib/prism/node_ext.rb +21 -5
- data/lib/prism/parse_result/comments.rb +0 -7
- data/lib/prism/parse_result/newlines.rb +101 -11
- data/lib/prism/parse_result.rb +17 -0
- data/lib/prism/reflection.rb +3 -1
- data/lib/prism/serialize.rb +80 -67
- data/lib/prism/translation/parser/compiler.rb +134 -114
- data/lib/prism/translation/parser.rb +6 -1
- data/lib/prism/translation/ripper.rb +8 -6
- data/lib/prism/translation/ruby_parser.rb +23 -5
- data/lib/prism/visitor.rb +3 -0
- data/lib/prism.rb +0 -4
- data/prism.gemspec +1 -4
- data/rbi/prism/node.rbi +63 -6
- data/rbi/prism/visitor.rbi +3 -0
- data/rbi/prism.rbi +6 -0
- data/sig/prism/dsl.rbs +4 -1
- data/sig/prism/mutation_compiler.rbs +1 -0
- data/sig/prism/node.rbs +28 -4
- data/sig/prism/visitor.rbs +1 -0
- data/sig/prism.rbs +21 -0
- data/src/diagnostic.c +27 -17
- data/src/node.c +408 -1666
- data/src/prettyprint.c +49 -6
- data/src/prism.c +958 -991
- data/src/regexp.c +133 -68
- data/src/serialize.c +6 -1
- data/src/static_literals.c +63 -84
- data/src/token_type.c +2 -2
- data/src/util/pm_constant_pool.c +0 -8
- data/src/util/pm_integer.c +39 -11
- data/src/util/pm_string.c +0 -12
- data/src/util/pm_strpbrk.c +32 -6
- metadata +2 -5
- data/include/prism/util/pm_string_list.h +0 -44
- data/lib/prism/debug.rb +0 -249
- data/src/util/pm_string_list.c +0 -28
data/src/token_type.c
CHANGED
@@ -362,7 +362,7 @@ const char *
|
|
362
362
|
pm_token_type_human(pm_token_type_t token_type) {
|
363
363
|
switch (token_type) {
|
364
364
|
case PM_TOKEN_EOF:
|
365
|
-
return "end
|
365
|
+
return "end-of-input";
|
366
366
|
case PM_TOKEN_MISSING:
|
367
367
|
return "missing token";
|
368
368
|
case PM_TOKEN_NOT_PROVIDED:
|
@@ -684,7 +684,7 @@ pm_token_type_human(pm_token_type_t token_type) {
|
|
684
684
|
case PM_TOKEN_USTAR:
|
685
685
|
return "*";
|
686
686
|
case PM_TOKEN_USTAR_STAR:
|
687
|
-
return "
|
687
|
+
return "**";
|
688
688
|
case PM_TOKEN_WORDS_SEP:
|
689
689
|
return "string separator";
|
690
690
|
case PM_TOKEN___END__:
|
data/src/util/pm_constant_pool.c
CHANGED
@@ -61,14 +61,6 @@ pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id) {
|
|
61
61
|
return false;
|
62
62
|
}
|
63
63
|
|
64
|
-
/**
|
65
|
-
* Get the memory size of a list of constant ids.
|
66
|
-
*/
|
67
|
-
size_t
|
68
|
-
pm_constant_id_list_memsize(pm_constant_id_list_t *list) {
|
69
|
-
return sizeof(pm_constant_id_list_t) + (list->capacity * sizeof(pm_constant_id_t));
|
70
|
-
}
|
71
|
-
|
72
64
|
/**
|
73
65
|
* Free the memory associated with a list of constant ids.
|
74
66
|
*/
|
data/src/util/pm_integer.c
CHANGED
@@ -48,7 +48,7 @@ big_add(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint
|
|
48
48
|
|
49
49
|
/**
|
50
50
|
* Internal use for karatsuba_multiply. Calculates `a - b - c` with the given
|
51
|
-
* base. Assume a, b, c, a - b - c all to be
|
51
|
+
* base. Assume a, b, c, a - b - c all to be positive.
|
52
52
|
* Return pm_integer_t with values allocated. Not normalized.
|
53
53
|
*/
|
54
54
|
static void
|
@@ -471,15 +471,18 @@ pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *
|
|
471
471
|
* has already been validated, as internal validation checks are not performed
|
472
472
|
* here.
|
473
473
|
*/
|
474
|
-
|
474
|
+
void
|
475
475
|
pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end) {
|
476
|
-
// Ignore unary +. Unary
|
476
|
+
// Ignore unary +. Unary - is parsed differently and will not end up here.
|
477
477
|
// Instead, it will modify the parsed integer later.
|
478
478
|
if (*start == '+') start++;
|
479
479
|
|
480
480
|
// Determine the multiplier from the base, and skip past any prefixes.
|
481
481
|
uint32_t multiplier = 10;
|
482
482
|
switch (base) {
|
483
|
+
case PM_INTEGER_BASE_DEFAULT:
|
484
|
+
while (*start == '0') start++; // 01 -> 1
|
485
|
+
break;
|
483
486
|
case PM_INTEGER_BASE_BINARY:
|
484
487
|
start += 2; // 0b
|
485
488
|
multiplier = 2;
|
@@ -533,14 +536,6 @@ pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *s
|
|
533
536
|
integer->value = (uint32_t) value;
|
534
537
|
}
|
535
538
|
|
536
|
-
/**
|
537
|
-
* Return the memory size of the integer.
|
538
|
-
*/
|
539
|
-
size_t
|
540
|
-
pm_integer_memsize(const pm_integer_t *integer) {
|
541
|
-
return sizeof(pm_integer_t) + integer->length * sizeof(uint32_t);
|
542
|
-
}
|
543
|
-
|
544
539
|
/**
|
545
540
|
* Compare two integers. This function returns -1 if the left integer is less
|
546
541
|
* than the right integer, 0 if they are equal, and 1 if the left integer is
|
@@ -572,6 +567,39 @@ pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right) {
|
|
572
567
|
return 0;
|
573
568
|
}
|
574
569
|
|
570
|
+
/**
|
571
|
+
* Reduce a ratio of integers to its simplest form.
|
572
|
+
*/
|
573
|
+
void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator) {
|
574
|
+
// If either the numerator or denominator do not fit into a 32-bit integer,
|
575
|
+
// then this function is a no-op. In the future, we may consider reducing
|
576
|
+
// even the larger numbers, but for now we're going to keep it simple.
|
577
|
+
if (
|
578
|
+
// If the numerator doesn't fit into a 32-bit integer, return early.
|
579
|
+
numerator->length != 0 ||
|
580
|
+
// If the denominator doesn't fit into a 32-bit integer, return early.
|
581
|
+
denominator->length != 0 ||
|
582
|
+
// If the numerator is 0, then return early.
|
583
|
+
numerator->value == 0 ||
|
584
|
+
// If the denominator is 1, then return early.
|
585
|
+
denominator->value == 1
|
586
|
+
) return;
|
587
|
+
|
588
|
+
// Find the greatest common divisor of the numerator and denominator.
|
589
|
+
uint32_t divisor = numerator->value;
|
590
|
+
uint32_t remainder = denominator->value;
|
591
|
+
|
592
|
+
while (remainder != 0) {
|
593
|
+
uint32_t temporary = remainder;
|
594
|
+
remainder = divisor % remainder;
|
595
|
+
divisor = temporary;
|
596
|
+
}
|
597
|
+
|
598
|
+
// Divide the numerator and denominator by the greatest common divisor.
|
599
|
+
numerator->value /= divisor;
|
600
|
+
denominator->value /= divisor;
|
601
|
+
}
|
602
|
+
|
575
603
|
/**
|
576
604
|
* Convert an integer to a decimal string.
|
577
605
|
*/
|
data/src/util/pm_string.c
CHANGED
@@ -245,18 +245,6 @@ pm_string_file_init(pm_string_t *string, const char *filepath) {
|
|
245
245
|
#endif
|
246
246
|
}
|
247
247
|
|
248
|
-
/**
|
249
|
-
* Returns the memory size associated with the string.
|
250
|
-
*/
|
251
|
-
size_t
|
252
|
-
pm_string_memsize(const pm_string_t *string) {
|
253
|
-
size_t size = sizeof(pm_string_t);
|
254
|
-
if (string->type == PM_STRING_OWNED) {
|
255
|
-
size += string->length;
|
256
|
-
}
|
257
|
-
return size;
|
258
|
-
}
|
259
|
-
|
260
248
|
/**
|
261
249
|
* Ensure the string is owned. If it is not, then reinitialize it as owned and
|
262
250
|
* copy over the previous source.
|
data/src/util/pm_strpbrk.c
CHANGED
@@ -8,6 +8,27 @@ pm_strpbrk_invalid_multibyte_character(pm_parser_t *parser, const uint8_t *start
|
|
8
8
|
pm_diagnostic_list_append_format(&parser->error_list, start, end, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *start);
|
9
9
|
}
|
10
10
|
|
11
|
+
/**
|
12
|
+
* Set the explicit encoding for the parser to the current encoding.
|
13
|
+
*/
|
14
|
+
static inline void
|
15
|
+
pm_strpbrk_explicit_encoding_set(pm_parser_t *parser, const uint8_t *source, size_t width) {
|
16
|
+
if (parser->explicit_encoding != NULL) {
|
17
|
+
if (parser->explicit_encoding == parser->encoding) {
|
18
|
+
// Okay, we already locked to this encoding.
|
19
|
+
} else if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
|
20
|
+
// Not okay, we already found a Unicode escape sequence and this
|
21
|
+
// conflicts.
|
22
|
+
pm_diagnostic_list_append_format(&parser->error_list, source, source + width, PM_ERR_MIXED_ENCODING, parser->encoding->name);
|
23
|
+
} else {
|
24
|
+
// Should not be anything else.
|
25
|
+
assert(false && "unreachable");
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
parser->explicit_encoding = parser->encoding;
|
30
|
+
}
|
31
|
+
|
11
32
|
/**
|
12
33
|
* This is the default path.
|
13
34
|
*/
|
@@ -52,7 +73,7 @@ pm_strpbrk_utf8(pm_parser_t *parser, const uint8_t *source, const uint8_t *chars
|
|
52
73
|
* This is the path when the encoding is ASCII-8BIT.
|
53
74
|
*/
|
54
75
|
static inline const uint8_t *
|
55
|
-
pm_strpbrk_ascii_8bit(const uint8_t *source, const uint8_t *charset, size_t maximum) {
|
76
|
+
pm_strpbrk_ascii_8bit(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
|
56
77
|
size_t index = 0;
|
57
78
|
|
58
79
|
while (index < maximum) {
|
@@ -60,6 +81,7 @@ pm_strpbrk_ascii_8bit(const uint8_t *source, const uint8_t *charset, size_t maxi
|
|
60
81
|
return source + index;
|
61
82
|
}
|
62
83
|
|
84
|
+
if (validate && source[index] >= 0x80) pm_strpbrk_explicit_encoding_set(parser, source, 1);
|
63
85
|
index++;
|
64
86
|
}
|
65
87
|
|
@@ -72,6 +94,7 @@ pm_strpbrk_ascii_8bit(const uint8_t *source, const uint8_t *charset, size_t maxi
|
|
72
94
|
static inline const uint8_t *
|
73
95
|
pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
|
74
96
|
size_t index = 0;
|
97
|
+
const pm_encoding_t *encoding = parser->encoding;
|
75
98
|
|
76
99
|
while (index < maximum) {
|
77
100
|
if (strchr((const char *) charset, source[index]) != NULL) {
|
@@ -81,7 +104,8 @@ pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
|
|
81
104
|
if (source[index] < 0x80) {
|
82
105
|
index++;
|
83
106
|
} else {
|
84
|
-
size_t width =
|
107
|
+
size_t width = encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
|
108
|
+
if (validate) pm_strpbrk_explicit_encoding_set(parser, source, width);
|
85
109
|
|
86
110
|
if (width > 0) {
|
87
111
|
index += width;
|
@@ -96,7 +120,7 @@ pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
|
|
96
120
|
|
97
121
|
do {
|
98
122
|
index++;
|
99
|
-
} while (index < maximum &&
|
123
|
+
} while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
|
100
124
|
|
101
125
|
pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
|
102
126
|
}
|
@@ -113,6 +137,7 @@ pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
|
|
113
137
|
static inline const uint8_t *
|
114
138
|
pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
|
115
139
|
size_t index = 0;
|
140
|
+
const pm_encoding_t *encoding = parser->encoding;
|
116
141
|
|
117
142
|
while (index < maximum) {
|
118
143
|
if (strchr((const char *) charset, source[index]) != NULL) {
|
@@ -122,7 +147,8 @@ pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
|
|
122
147
|
if (source[index] < 0x80 || !validate) {
|
123
148
|
index++;
|
124
149
|
} else {
|
125
|
-
size_t width =
|
150
|
+
size_t width = encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
|
151
|
+
pm_strpbrk_explicit_encoding_set(parser, source, width);
|
126
152
|
|
127
153
|
if (width > 0) {
|
128
154
|
index += width;
|
@@ -135,7 +161,7 @@ pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t
|
|
135
161
|
|
136
162
|
do {
|
137
163
|
index++;
|
138
|
-
} while (index < maximum &&
|
164
|
+
} while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
|
139
165
|
|
140
166
|
pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
|
141
167
|
}
|
@@ -171,7 +197,7 @@ pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, p
|
|
171
197
|
} else if (!parser->encoding_changed) {
|
172
198
|
return pm_strpbrk_utf8(parser, source, charset, (size_t) length, validate);
|
173
199
|
} else if (parser->encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
|
174
|
-
return pm_strpbrk_ascii_8bit(source, charset, (size_t) length);
|
200
|
+
return pm_strpbrk_ascii_8bit(parser, source, charset, (size_t) length, validate);
|
175
201
|
} else if (parser->encoding->multibyte) {
|
176
202
|
return pm_strpbrk_multi_byte(parser, source, charset, (size_t) length, validate);
|
177
203
|
} else {
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prism
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.30.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -69,13 +69,11 @@ files:
|
|
69
69
|
- include/prism/util/pm_memchr.h
|
70
70
|
- include/prism/util/pm_newline_list.h
|
71
71
|
- include/prism/util/pm_string.h
|
72
|
-
- include/prism/util/pm_string_list.h
|
73
72
|
- include/prism/util/pm_strncasecmp.h
|
74
73
|
- include/prism/util/pm_strpbrk.h
|
75
74
|
- include/prism/version.h
|
76
75
|
- lib/prism.rb
|
77
76
|
- lib/prism/compiler.rb
|
78
|
-
- lib/prism/debug.rb
|
79
77
|
- lib/prism/desugar_compiler.rb
|
80
78
|
- lib/prism/dispatcher.rb
|
81
79
|
- lib/prism/dot_visitor.rb
|
@@ -155,7 +153,6 @@ files:
|
|
155
153
|
- src/util/pm_memchr.c
|
156
154
|
- src/util/pm_newline_list.c
|
157
155
|
- src/util/pm_string.c
|
158
|
-
- src/util/pm_string_list.c
|
159
156
|
- src/util/pm_strncasecmp.c
|
160
157
|
- src/util/pm_strpbrk.c
|
161
158
|
homepage: https://github.com/ruby/prism
|
@@ -1,44 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @file pm_string_list.h
|
3
|
-
*
|
4
|
-
* A list of strings.
|
5
|
-
*/
|
6
|
-
#ifndef PRISM_STRING_LIST_H
|
7
|
-
#define PRISM_STRING_LIST_H
|
8
|
-
|
9
|
-
#include "prism/defines.h"
|
10
|
-
#include "prism/util/pm_string.h"
|
11
|
-
|
12
|
-
#include <stddef.h>
|
13
|
-
#include <stdlib.h>
|
14
|
-
|
15
|
-
/**
|
16
|
-
* A list of strings.
|
17
|
-
*/
|
18
|
-
typedef struct {
|
19
|
-
/** The length of the string list. */
|
20
|
-
size_t length;
|
21
|
-
|
22
|
-
/** The capacity of the string list that has been allocated. */
|
23
|
-
size_t capacity;
|
24
|
-
|
25
|
-
/** A pointer to the start of the string list. */
|
26
|
-
pm_string_t *strings;
|
27
|
-
} pm_string_list_t;
|
28
|
-
|
29
|
-
/**
|
30
|
-
* Append a pm_string_t to the given string list.
|
31
|
-
*
|
32
|
-
* @param string_list The string list to append to.
|
33
|
-
* @param string The string to append.
|
34
|
-
*/
|
35
|
-
void pm_string_list_append(pm_string_list_t *string_list, pm_string_t *string);
|
36
|
-
|
37
|
-
/**
|
38
|
-
* Free the memory associated with the string list.
|
39
|
-
*
|
40
|
-
* @param string_list The string list to free.
|
41
|
-
*/
|
42
|
-
PRISM_EXPORTED_FUNCTION void pm_string_list_free(pm_string_list_t *string_list);
|
43
|
-
|
44
|
-
#endif
|
data/lib/prism/debug.rb
DELETED
@@ -1,249 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prism
|
4
|
-
# This module is used for testing and debugging and is not meant to be used by
|
5
|
-
# consumers of this library.
|
6
|
-
module Debug
|
7
|
-
# A wrapper around a RubyVM::InstructionSequence that provides a more
|
8
|
-
# convenient interface for accessing parts of the iseq.
|
9
|
-
class ISeq # :nodoc:
|
10
|
-
attr_reader :parts
|
11
|
-
|
12
|
-
def initialize(parts)
|
13
|
-
@parts = parts
|
14
|
-
end
|
15
|
-
|
16
|
-
def type
|
17
|
-
parts[0]
|
18
|
-
end
|
19
|
-
|
20
|
-
def local_table
|
21
|
-
parts[10]
|
22
|
-
end
|
23
|
-
|
24
|
-
def instructions
|
25
|
-
parts[13]
|
26
|
-
end
|
27
|
-
|
28
|
-
def each_child
|
29
|
-
instructions.each do |instruction|
|
30
|
-
# Only look at arrays. Other instructions are line numbers or
|
31
|
-
# tracepoint events.
|
32
|
-
next unless instruction.is_a?(Array)
|
33
|
-
|
34
|
-
instruction.each do |opnd|
|
35
|
-
# Only look at arrays. Other operands are literals.
|
36
|
-
next unless opnd.is_a?(Array)
|
37
|
-
|
38
|
-
# Only look at instruction sequences. Other operands are literals.
|
39
|
-
next unless opnd[0] == "YARVInstructionSequence/SimpleDataFormat"
|
40
|
-
|
41
|
-
yield ISeq.new(opnd)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private_constant :ISeq
|
48
|
-
|
49
|
-
# :call-seq:
|
50
|
-
# Debug::cruby_locals(source) -> Array
|
51
|
-
#
|
52
|
-
# For the given source, compiles with CRuby and returns a list of all of the
|
53
|
-
# sets of local variables that were encountered.
|
54
|
-
def self.cruby_locals(source)
|
55
|
-
verbose, $VERBOSE = $VERBOSE, nil
|
56
|
-
|
57
|
-
begin
|
58
|
-
locals = [] #: Array[Array[Symbol | Integer]]
|
59
|
-
stack = [ISeq.new(RubyVM::InstructionSequence.compile(source).to_a)]
|
60
|
-
|
61
|
-
while (iseq = stack.pop)
|
62
|
-
names = [*iseq.local_table]
|
63
|
-
names.map!.with_index do |name, index|
|
64
|
-
# When an anonymous local variable is present in the iseq's local
|
65
|
-
# table, it is represented as the stack offset from the top.
|
66
|
-
# However, when these are dumped to binary and read back in, they
|
67
|
-
# are replaced with the symbol :#arg_rest. To consistently handle
|
68
|
-
# this, we replace them here with their index.
|
69
|
-
if name == :"#arg_rest"
|
70
|
-
names.length - index + 1
|
71
|
-
else
|
72
|
-
name
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
locals << names
|
77
|
-
iseq.each_child { |child| stack << child }
|
78
|
-
end
|
79
|
-
|
80
|
-
locals
|
81
|
-
ensure
|
82
|
-
$VERBOSE = verbose
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# Used to hold the place of a local that will be in the local table but
|
87
|
-
# cannot be accessed directly from the source code. For example, the
|
88
|
-
# iteration variable in a for loop or the positional parameter on a method
|
89
|
-
# definition that is destructured.
|
90
|
-
AnonymousLocal = Object.new
|
91
|
-
private_constant :AnonymousLocal
|
92
|
-
|
93
|
-
# :call-seq:
|
94
|
-
# Debug::prism_locals(source) -> Array
|
95
|
-
#
|
96
|
-
# For the given source, parses with prism and returns a list of all of the
|
97
|
-
# sets of local variables that were encountered.
|
98
|
-
def self.prism_locals(source)
|
99
|
-
locals = [] #: Array[Array[Symbol | Integer]]
|
100
|
-
stack = [Prism.parse(source).value] #: Array[Prism::node]
|
101
|
-
|
102
|
-
while (node = stack.pop)
|
103
|
-
case node
|
104
|
-
when BlockNode, DefNode, LambdaNode
|
105
|
-
names = node.locals
|
106
|
-
params =
|
107
|
-
if node.is_a?(DefNode)
|
108
|
-
node.parameters
|
109
|
-
elsif node.parameters.is_a?(NumberedParametersNode)
|
110
|
-
nil
|
111
|
-
else
|
112
|
-
node.parameters&.parameters
|
113
|
-
end
|
114
|
-
|
115
|
-
# prism places parameters in the same order that they appear in the
|
116
|
-
# source. CRuby places them in the order that they need to appear
|
117
|
-
# according to their own internal calling convention. We mimic that
|
118
|
-
# order here so that we can compare properly.
|
119
|
-
if params
|
120
|
-
sorted = [
|
121
|
-
*params.requireds.map do |required|
|
122
|
-
if required.is_a?(RequiredParameterNode)
|
123
|
-
required.name
|
124
|
-
else
|
125
|
-
AnonymousLocal
|
126
|
-
end
|
127
|
-
end,
|
128
|
-
*params.optionals.map(&:name),
|
129
|
-
*((params.rest.name || :*) if params.rest && !params.rest.is_a?(ImplicitRestNode)),
|
130
|
-
*params.posts.map do |post|
|
131
|
-
if post.is_a?(RequiredParameterNode)
|
132
|
-
post.name
|
133
|
-
else
|
134
|
-
AnonymousLocal
|
135
|
-
end
|
136
|
-
end,
|
137
|
-
*params.keywords.grep(RequiredKeywordParameterNode).map(&:name),
|
138
|
-
*params.keywords.grep(OptionalKeywordParameterNode).map(&:name),
|
139
|
-
]
|
140
|
-
|
141
|
-
sorted << AnonymousLocal if params.keywords.any?
|
142
|
-
|
143
|
-
if params.keyword_rest.is_a?(ForwardingParameterNode)
|
144
|
-
sorted.push(:*, :**, :&, :"...")
|
145
|
-
elsif params.keyword_rest.is_a?(KeywordRestParameterNode)
|
146
|
-
sorted << (params.keyword_rest.name || :**)
|
147
|
-
end
|
148
|
-
|
149
|
-
# Recurse down the parameter tree to find any destructured
|
150
|
-
# parameters and add them after the other parameters.
|
151
|
-
param_stack = params.requireds.concat(params.posts).grep(MultiTargetNode).reverse
|
152
|
-
while (param = param_stack.pop)
|
153
|
-
case param
|
154
|
-
when MultiTargetNode
|
155
|
-
param_stack.concat(param.rights.reverse)
|
156
|
-
param_stack << param.rest if param.rest&.expression && !sorted.include?(param.rest.expression.name)
|
157
|
-
param_stack.concat(param.lefts.reverse)
|
158
|
-
when RequiredParameterNode
|
159
|
-
sorted << param.name
|
160
|
-
when SplatNode
|
161
|
-
sorted << param.expression.name
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
if params.block
|
166
|
-
sorted << (params.block.name || :&)
|
167
|
-
end
|
168
|
-
|
169
|
-
names = sorted.concat(names - sorted)
|
170
|
-
end
|
171
|
-
|
172
|
-
names.map!.with_index do |name, index|
|
173
|
-
if name == AnonymousLocal
|
174
|
-
names.length - index + 1
|
175
|
-
else
|
176
|
-
name
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
locals << names
|
181
|
-
when ClassNode, ModuleNode, ProgramNode, SingletonClassNode
|
182
|
-
locals << node.locals
|
183
|
-
when ForNode
|
184
|
-
locals << [2]
|
185
|
-
when PostExecutionNode
|
186
|
-
locals.push([], [])
|
187
|
-
when InterpolatedRegularExpressionNode
|
188
|
-
locals << [] if node.once?
|
189
|
-
end
|
190
|
-
|
191
|
-
stack.concat(node.compact_child_nodes)
|
192
|
-
end
|
193
|
-
|
194
|
-
locals
|
195
|
-
end
|
196
|
-
|
197
|
-
# :call-seq:
|
198
|
-
# Debug::newlines(source) -> Array
|
199
|
-
#
|
200
|
-
# For the given source string, return the byte offsets of every newline in
|
201
|
-
# the source.
|
202
|
-
def self.newlines(source)
|
203
|
-
Prism.parse(source).source.offsets
|
204
|
-
end
|
205
|
-
|
206
|
-
# A wrapping around prism's internal encoding data structures. This is used
|
207
|
-
# for reflection and debugging purposes.
|
208
|
-
class Encoding
|
209
|
-
# The name of the encoding, that can be passed to Encoding.find.
|
210
|
-
attr_reader :name
|
211
|
-
|
212
|
-
# Initialize a new encoding with the given name and whether or not it is
|
213
|
-
# a multibyte encoding.
|
214
|
-
def initialize(name, multibyte)
|
215
|
-
@name = name
|
216
|
-
@multibyte = multibyte
|
217
|
-
end
|
218
|
-
|
219
|
-
# Whether or not the encoding is a multibyte encoding.
|
220
|
-
def multibyte?
|
221
|
-
@multibyte
|
222
|
-
end
|
223
|
-
|
224
|
-
# Returns the number of bytes of the first character in the source string,
|
225
|
-
# if it is valid for the encoding. Otherwise, returns 0.
|
226
|
-
def width(source)
|
227
|
-
Encoding._width(name, source)
|
228
|
-
end
|
229
|
-
|
230
|
-
# Returns true if the first character in the source string is a valid
|
231
|
-
# alphanumeric character for the encoding.
|
232
|
-
def alnum?(source)
|
233
|
-
Encoding._alnum?(name, source)
|
234
|
-
end
|
235
|
-
|
236
|
-
# Returns true if the first character in the source string is a valid
|
237
|
-
# alphabetic character for the encoding.
|
238
|
-
def alpha?(source)
|
239
|
-
Encoding._alpha?(name, source)
|
240
|
-
end
|
241
|
-
|
242
|
-
# Returns true if the first character in the source string is a valid
|
243
|
-
# uppercase character for the encoding.
|
244
|
-
def upper?(source)
|
245
|
-
Encoding._upper?(name, source)
|
246
|
-
end
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
data/src/util/pm_string_list.c
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
#include "prism/util/pm_string_list.h"
|
2
|
-
|
3
|
-
/**
|
4
|
-
* Append a pm_string_t to the given string list.
|
5
|
-
*/
|
6
|
-
void
|
7
|
-
pm_string_list_append(pm_string_list_t *string_list, pm_string_t *string) {
|
8
|
-
if (string_list->length + 1 > string_list->capacity) {
|
9
|
-
if (string_list->capacity == 0) {
|
10
|
-
string_list->capacity = 1;
|
11
|
-
} else {
|
12
|
-
string_list->capacity *= 2;
|
13
|
-
}
|
14
|
-
|
15
|
-
string_list->strings = xrealloc(string_list->strings, string_list->capacity * sizeof(pm_string_t));
|
16
|
-
if (string_list->strings == NULL) abort();
|
17
|
-
}
|
18
|
-
|
19
|
-
string_list->strings[string_list->length++] = *string;
|
20
|
-
}
|
21
|
-
|
22
|
-
/**
|
23
|
-
* Free the memory associated with the string list
|
24
|
-
*/
|
25
|
-
void
|
26
|
-
pm_string_list_free(pm_string_list_t *string_list) {
|
27
|
-
xfree(string_list->strings);
|
28
|
-
}
|