syntax_tree 6.2.0 → 6.3.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/.github/workflows/auto-merge.yml +1 -1
- data/.github/workflows/gh-pages.yml +5 -5
- data/.github/workflows/main.yml +2 -1
- data/.rubocop.yml +6 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +29 -25
- data/README.md +1 -1
- data/lib/syntax_tree/cli.rb +69 -14
- data/lib/syntax_tree/language_server.rb +8 -2
- data/lib/syntax_tree/node.rb +54 -35
- data/lib/syntax_tree/parser.rb +8 -3
- data/lib/syntax_tree/pattern.rb +1 -0
- data/lib/syntax_tree/version.rb +1 -1
- data/lib/syntax_tree/yarv/assembler.rb +2 -2
- data/lib/syntax_tree/yarv/calldata.rb +1 -1
- data/lib/syntax_tree/yarv/decompiler.rb +6 -6
- data/lib/syntax_tree/yarv/instruction_sequence.rb +35 -8
- data/lib/syntax_tree/yarv/instructions.rb +147 -0
- data/tasks/whitequark.rake +7 -2
- metadata +3 -8
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d2e2bb8b41f091f6895ef5207081790c08ddaab126e8d5ddac324d9c13ea012
|
4
|
+
data.tar.gz: 9383e5f306415f9ad9e52c1cc58766fc629ae612644006a794229641a68cc7e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1da6c505691e7a07716c26c57e536f38cae5b4c13a370a9e95e75aeda01e460bb6c9d7e21bc2cc8c226cdba412d064d4a386a8b6418e729af2243913b86c1087
|
7
|
+
data.tar.gz: b72d5dc5173edbeba46427278297f6b5c90d755f5806fa154084faef72978895e1a84ebb2cb3a52401b231b1c73e07c3f90f7268c14d115dc4036cee0632c0c2
|
@@ -5,8 +5,8 @@ on:
|
|
5
5
|
branches:
|
6
6
|
- main
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
# Allows you to run this workflow manually from the Actions tab
|
9
|
+
workflow_dispatch:
|
10
10
|
|
11
11
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
12
12
|
permissions:
|
@@ -27,7 +27,7 @@ jobs:
|
|
27
27
|
- name: Checkout
|
28
28
|
uses: actions/checkout@v4
|
29
29
|
- name: Setup Pages
|
30
|
-
uses: actions/configure-pages@
|
30
|
+
uses: actions/configure-pages@v5
|
31
31
|
- name: Set up Ruby
|
32
32
|
uses: ruby/setup-ruby@v1
|
33
33
|
with:
|
@@ -39,7 +39,7 @@ jobs:
|
|
39
39
|
rdoc --main README.md --op _site --exclude={Gemfile,Rakefile,"coverage/*","vendor/*","bin/*","test/*","tmp/*"}
|
40
40
|
cp -r doc _site/doc
|
41
41
|
- name: Upload artifact
|
42
|
-
uses: actions/upload-pages-artifact@
|
42
|
+
uses: actions/upload-pages-artifact@v3
|
43
43
|
|
44
44
|
# Deployment job
|
45
45
|
deploy:
|
@@ -51,4 +51,4 @@ jobs:
|
|
51
51
|
steps:
|
52
52
|
- name: Deploy to GitHub Pages
|
53
53
|
id: deployment
|
54
|
-
uses: actions/deploy-pages@
|
54
|
+
uses: actions/deploy-pages@v4
|
data/.github/workflows/main.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -136,6 +136,9 @@ Style/KeywordParametersOrder:
|
|
136
136
|
Style/MissingRespondToMissing:
|
137
137
|
Enabled: false
|
138
138
|
|
139
|
+
Style/MultipleComparison:
|
140
|
+
Enabled: false
|
141
|
+
|
139
142
|
Style/MutableConstant:
|
140
143
|
Enabled: false
|
141
144
|
|
@@ -157,6 +160,9 @@ Style/PerlBackrefs:
|
|
157
160
|
Style/RedundantArrayConstructor:
|
158
161
|
Enabled: false
|
159
162
|
|
163
|
+
Style/RedundantParentheses:
|
164
|
+
Enabled: false
|
165
|
+
|
160
166
|
Style/SafeNavigation:
|
161
167
|
Enabled: false
|
162
168
|
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [6.3.0] - 2025-07-16
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- The `--extension` command line option has been added to the CLI to specify what type of content is coming from stdin.
|
14
|
+
- The `--config` command line option has been added to the CLI to specify the path to the configuration file.
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
- Fix formatting of character literals when single quotes is enabled.
|
19
|
+
- Pass ignore files option to the language server.
|
20
|
+
- Hash keys should remain unchanged when there are any omitted values in the hash.
|
21
|
+
- We now properly handle compilation errors in the parser.
|
22
|
+
|
9
23
|
## [6.2.0] - 2023-09-20
|
10
24
|
|
11
25
|
### Added
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,50 +1,53 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
syntax_tree (6.
|
4
|
+
syntax_tree (6.3.0)
|
5
5
|
prettier_print (>= 1.2.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
ast (2.4.
|
11
|
-
|
12
|
-
|
13
|
-
json (2.
|
14
|
-
language_server-protocol (3.17.0.
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
ast (2.4.3)
|
11
|
+
docile (1.4.1)
|
12
|
+
fiddle (1.1.8)
|
13
|
+
json (2.12.2)
|
14
|
+
language_server-protocol (3.17.0.5)
|
15
|
+
lint_roller (1.1.0)
|
16
|
+
minitest (5.25.5)
|
17
|
+
parallel (1.27.0)
|
18
|
+
parser (3.3.8.0)
|
18
19
|
ast (~> 2.4.1)
|
19
20
|
racc
|
20
21
|
prettier_print (1.2.1)
|
21
|
-
|
22
|
+
prism (1.4.0)
|
23
|
+
racc (1.8.1)
|
22
24
|
rainbow (3.1.1)
|
23
|
-
rake (13.0
|
24
|
-
regexp_parser (2.
|
25
|
-
|
26
|
-
rubocop (1.56.3)
|
27
|
-
base64 (~> 0.1.1)
|
25
|
+
rake (13.3.0)
|
26
|
+
regexp_parser (2.10.0)
|
27
|
+
rubocop (1.78.0)
|
28
28
|
json (~> 2.3)
|
29
|
-
language_server-protocol (
|
29
|
+
language_server-protocol (~> 3.17.0.2)
|
30
|
+
lint_roller (~> 1.1.0)
|
30
31
|
parallel (~> 1.10)
|
31
|
-
parser (>= 3.
|
32
|
+
parser (>= 3.3.0.2)
|
32
33
|
rainbow (>= 2.2.2, < 4.0)
|
33
|
-
regexp_parser (>=
|
34
|
-
|
35
|
-
rubocop-ast (>= 1.28.1, < 2.0)
|
34
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
35
|
+
rubocop-ast (>= 1.45.1, < 2.0)
|
36
36
|
ruby-progressbar (~> 1.7)
|
37
|
-
unicode-display_width (>= 2.4.0, <
|
38
|
-
rubocop-ast (1.
|
39
|
-
parser (>= 3.
|
37
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
38
|
+
rubocop-ast (1.45.1)
|
39
|
+
parser (>= 3.3.7.2)
|
40
|
+
prism (~> 1.4)
|
40
41
|
ruby-progressbar (1.13.0)
|
41
42
|
simplecov (0.22.0)
|
42
43
|
docile (~> 1.1)
|
43
44
|
simplecov-html (~> 0.11)
|
44
45
|
simplecov_json_formatter (~> 0.1)
|
45
|
-
simplecov-html (0.
|
46
|
+
simplecov-html (0.13.1)
|
46
47
|
simplecov_json_formatter (0.1.4)
|
47
|
-
unicode-display_width (
|
48
|
+
unicode-display_width (3.1.4)
|
49
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
50
|
+
unicode-emoji (4.0.4)
|
48
51
|
|
49
52
|
PLATFORMS
|
50
53
|
arm64-darwin-21
|
@@ -55,6 +58,7 @@ PLATFORMS
|
|
55
58
|
|
56
59
|
DEPENDENCIES
|
57
60
|
bundler
|
61
|
+
fiddle
|
58
62
|
minitest
|
59
63
|
rake
|
60
64
|
rubocop
|
data/README.md
CHANGED
@@ -187,7 +187,7 @@ SyntaxTree::Binary[
|
|
187
187
|
|
188
188
|
### format
|
189
189
|
|
190
|
-
This command will output the formatted version of each of the listed files. Importantly, it will not write that content back to the source files
|
190
|
+
This command will output the formatted version of each of the listed files to stdout. Importantly, it will not write that content back to the source files – for that, you want [`write`](#write).
|
191
191
|
|
192
192
|
```sh
|
193
193
|
stree format path/to/file.rb
|
data/lib/syntax_tree/cli.rb
CHANGED
@@ -63,12 +63,13 @@ module SyntaxTree
|
|
63
63
|
class ScriptItem
|
64
64
|
attr_reader :source
|
65
65
|
|
66
|
-
def initialize(source)
|
66
|
+
def initialize(source, extension)
|
67
67
|
@source = source
|
68
|
+
@extension = extension
|
68
69
|
end
|
69
70
|
|
70
71
|
def handler
|
71
|
-
HANDLERS[
|
72
|
+
HANDLERS[@extension]
|
72
73
|
end
|
73
74
|
|
74
75
|
def filepath
|
@@ -82,8 +83,12 @@ module SyntaxTree
|
|
82
83
|
|
83
84
|
# An item of work that correspond to the content passed in via stdin.
|
84
85
|
class STDINItem
|
86
|
+
def initialize(extension)
|
87
|
+
@extension = extension
|
88
|
+
end
|
89
|
+
|
85
90
|
def handler
|
86
|
-
HANDLERS[
|
91
|
+
HANDLERS[@extension]
|
87
92
|
end
|
88
93
|
|
89
94
|
def filepath
|
@@ -159,7 +164,7 @@ module SyntaxTree
|
|
159
164
|
attr_reader :entries
|
160
165
|
|
161
166
|
def initialize(options)
|
162
|
-
super
|
167
|
+
super
|
163
168
|
@entries = []
|
164
169
|
end
|
165
170
|
|
@@ -450,14 +455,26 @@ module SyntaxTree
|
|
450
455
|
#{Color.bold("stree write [--plugins=...] [--print-width=NUMBER] [-e SCRIPT] FILE")}
|
451
456
|
Read, format, and write back the source of the given files
|
452
457
|
|
458
|
+
--ignore-files=...
|
459
|
+
A glob pattern to ignore files when processing. This can be specified
|
460
|
+
multiple times to ignore multiple patterns.
|
461
|
+
|
453
462
|
--plugins=...
|
454
463
|
A comma-separated list of plugins to load.
|
455
464
|
|
456
|
-
--print-width
|
465
|
+
--print-width=...
|
457
466
|
The maximum line width to use when formatting.
|
458
467
|
|
459
|
-
-e
|
460
|
-
Parse an inline
|
468
|
+
-e ...
|
469
|
+
Parse an inline string.
|
470
|
+
|
471
|
+
--extension=...
|
472
|
+
A file extension matching the content passed in via STDIN or -e.
|
473
|
+
Defaults to '.rb'.
|
474
|
+
|
475
|
+
--config=...
|
476
|
+
Path to a configuration file. Defaults to .streerc in the current
|
477
|
+
working directory.
|
461
478
|
HELP
|
462
479
|
|
463
480
|
# This represents all of the options that can be passed to the CLI. It is
|
@@ -468,6 +485,7 @@ module SyntaxTree
|
|
468
485
|
:plugins,
|
469
486
|
:print_width,
|
470
487
|
:scripts,
|
488
|
+
:extension,
|
471
489
|
:target_ruby_version
|
472
490
|
|
473
491
|
def initialize
|
@@ -475,6 +493,7 @@ module SyntaxTree
|
|
475
493
|
@plugins = []
|
476
494
|
@print_width = DEFAULT_PRINT_WIDTH
|
477
495
|
@scripts = []
|
496
|
+
@extension = ".rb"
|
478
497
|
@target_ruby_version = DEFAULT_RUBY_VERSION
|
479
498
|
end
|
480
499
|
|
@@ -523,6 +542,13 @@ module SyntaxTree
|
|
523
542
|
# it and add it to the list of scripts to run.
|
524
543
|
opts.on("-e SCRIPT") { |script| @scripts << script }
|
525
544
|
|
545
|
+
# If there is a extension specified, then parse it and use it for
|
546
|
+
# STDIN and scripts.
|
547
|
+
opts.on("--extension=EXTENSION") do |extension|
|
548
|
+
# Both ".rb" and "rb" are going to work
|
549
|
+
@extension = ".#{extension.delete_prefix(".")}"
|
550
|
+
end
|
551
|
+
|
526
552
|
# If there is a target ruby version specified on the command line,
|
527
553
|
# parse that out and use it when formatting.
|
528
554
|
opts.on("--target-ruby-version=VERSION") do |version|
|
@@ -546,8 +572,16 @@ module SyntaxTree
|
|
546
572
|
|
547
573
|
attr_reader :filepath
|
548
574
|
|
549
|
-
def initialize
|
550
|
-
|
575
|
+
def initialize(filepath = nil)
|
576
|
+
if filepath
|
577
|
+
if File.readable?(filepath)
|
578
|
+
@filepath = filepath
|
579
|
+
else
|
580
|
+
raise ArgumentError, "Invalid configuration file: #{filepath}"
|
581
|
+
end
|
582
|
+
else
|
583
|
+
@filepath = File.join(Dir.pwd, FILENAME)
|
584
|
+
end
|
551
585
|
end
|
552
586
|
|
553
587
|
def exists?
|
@@ -565,8 +599,24 @@ module SyntaxTree
|
|
565
599
|
def run(argv)
|
566
600
|
name, *arguments = argv
|
567
601
|
|
568
|
-
|
569
|
-
|
602
|
+
# First, we need to check if there's a --config option specified
|
603
|
+
# so we can use the custom config file path.
|
604
|
+
config_filepath = nil
|
605
|
+
arguments.each_with_index do |arg, index|
|
606
|
+
if arg.start_with?("--config=")
|
607
|
+
config_filepath = arg.split("=", 2)[1]
|
608
|
+
arguments.delete_at(index)
|
609
|
+
break
|
610
|
+
elsif arg == "--config" && arguments[index + 1]
|
611
|
+
config_filepath = arguments[index + 1]
|
612
|
+
arguments.delete_at(index + 1)
|
613
|
+
arguments.delete_at(index)
|
614
|
+
break
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
config_file = ConfigFile.new(config_filepath)
|
619
|
+
arguments = config_file.arguments.concat(arguments)
|
570
620
|
|
571
621
|
options = Options.new
|
572
622
|
options.parse(arguments)
|
@@ -593,7 +643,10 @@ module SyntaxTree
|
|
593
643
|
when "j", "json"
|
594
644
|
Json.new(options)
|
595
645
|
when "lsp"
|
596
|
-
LanguageServer.new(
|
646
|
+
LanguageServer.new(
|
647
|
+
print_width: options.print_width,
|
648
|
+
ignore_files: options.ignore_files
|
649
|
+
).run
|
597
650
|
return 0
|
598
651
|
when "m", "match"
|
599
652
|
Match.new(options)
|
@@ -630,9 +683,11 @@ module SyntaxTree
|
|
630
683
|
end
|
631
684
|
end
|
632
685
|
|
633
|
-
options.scripts.each
|
686
|
+
options.scripts.each do |script|
|
687
|
+
queue << ScriptItem.new(script, options.extension)
|
688
|
+
end
|
634
689
|
else
|
635
|
-
queue << STDINItem.new
|
690
|
+
queue << STDINItem.new(options.extension)
|
636
691
|
end
|
637
692
|
|
638
693
|
# At the end, we're going to return whether or not this worker ever
|
@@ -217,11 +217,13 @@ module SyntaxTree
|
|
217
217
|
def initialize(
|
218
218
|
input: $stdin,
|
219
219
|
output: $stdout,
|
220
|
-
print_width: DEFAULT_PRINT_WIDTH
|
220
|
+
print_width: DEFAULT_PRINT_WIDTH,
|
221
|
+
ignore_files: []
|
221
222
|
)
|
222
223
|
@input = input.binmode
|
223
224
|
@output = output.binmode
|
224
225
|
@print_width = print_width
|
226
|
+
@ignore_files = ignore_files
|
225
227
|
end
|
226
228
|
|
227
229
|
# rubocop:disable Layout/LineLength
|
@@ -255,8 +257,12 @@ module SyntaxTree
|
|
255
257
|
store.delete(request.dig(:params, :textDocument, :uri))
|
256
258
|
when Request[method: "textDocument/formatting", id: :any, params: { textDocument: { uri: :any } }]
|
257
259
|
uri = request.dig(:params, :textDocument, :uri)
|
260
|
+
filepath = uri.split("///").last
|
261
|
+
ignore = @ignore_files.any? do |glob|
|
262
|
+
File.fnmatch(glob, filepath)
|
263
|
+
end
|
258
264
|
contents = store[uri]
|
259
|
-
write(id: request[:id], result: contents ? format(contents, uri.split(".").last) : nil)
|
265
|
+
write(id: request[:id], result: contents && !ignore ? format(contents, uri.split(".").last) : nil)
|
260
266
|
when Request[method: "textDocument/inlayHint", id: :any, params: { textDocument: { uri: :any } }]
|
261
267
|
uri = request.dig(:params, :textDocument, :uri)
|
262
268
|
contents = store[uri]
|
data/lib/syntax_tree/node.rb
CHANGED
@@ -288,7 +288,7 @@ module SyntaxTree
|
|
288
288
|
q.text(value)
|
289
289
|
else
|
290
290
|
q.text(q.quote)
|
291
|
-
q.text(value[1] ==
|
291
|
+
q.text(value[1] == q.quote ? "\\#{q.quote}" : value[1])
|
292
292
|
q.text(q.quote)
|
293
293
|
end
|
294
294
|
end
|
@@ -1783,45 +1783,60 @@ module SyntaxTree
|
|
1783
1783
|
end
|
1784
1784
|
end
|
1785
1785
|
|
1786
|
-
|
1787
|
-
container
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
# Otherwise, we need to check the type of the key. If it's a label or
|
1800
|
-
# dynamic symbol, we can use labels. If it's a symbol literal then it
|
1801
|
-
# needs to match a certain pattern to be used as a label. If it's
|
1802
|
-
# anything else, then we need to use hash rockets.
|
1803
|
-
case assoc.key
|
1804
|
-
when Label, DynaSymbol
|
1805
|
-
# Here labels can be used.
|
1806
|
-
when SymbolLiteral
|
1807
|
-
# When attempting to convert a hash rocket into a hash label,
|
1808
|
-
# you need to take care because only certain patterns are
|
1809
|
-
# allowed. Ruby source says that they have to match keyword
|
1810
|
-
# arguments to methods, but don't specify what that is. After
|
1811
|
-
# some experimentation, it looks like it's:
|
1812
|
-
value = assoc.key.value.value
|
1813
|
-
|
1814
|
-
if !value.match?(/^[_A-Za-z]/) || value.end_with?("=")
|
1815
|
-
return Rockets.new
|
1816
|
-
end
|
1786
|
+
class << self
|
1787
|
+
def for(container)
|
1788
|
+
(assocs = container.assocs).each_with_index do |assoc, index|
|
1789
|
+
if assoc.is_a?(AssocSplat)
|
1790
|
+
# Splat nodes do not impact the formatting choice.
|
1791
|
+
elsif assoc.value.nil?
|
1792
|
+
# If the value is nil, then it has been omitted. In this case we
|
1793
|
+
# have to match the existing formatting because standardizing would
|
1794
|
+
# potentially break the code. For example:
|
1795
|
+
#
|
1796
|
+
# { first:, "second" => "value" }
|
1797
|
+
#
|
1798
|
+
return Identity.new
|
1817
1799
|
else
|
1818
|
-
#
|
1819
|
-
|
1800
|
+
# Otherwise, we need to check the type of the key. If it's a label
|
1801
|
+
# or dynamic symbol, we can use labels. If it's a symbol literal
|
1802
|
+
# then it needs to match a certain pattern to be used as a label. If
|
1803
|
+
# it's anything else, then we need to use hash rockets.
|
1804
|
+
case assoc.key
|
1805
|
+
when Label, DynaSymbol
|
1806
|
+
# Here labels can be used.
|
1807
|
+
when SymbolLiteral
|
1808
|
+
# When attempting to convert a hash rocket into a hash label,
|
1809
|
+
# you need to take care because only certain patterns are
|
1810
|
+
# allowed. Ruby source says that they have to match keyword
|
1811
|
+
# arguments to methods, but don't specify what that is. After
|
1812
|
+
# some experimentation, it looks like it's:
|
1813
|
+
value = assoc.key.value.value
|
1814
|
+
|
1815
|
+
if !value.match?(/^[_A-Za-z]/) || value.end_with?("=")
|
1816
|
+
if omitted_value?(assocs[(index + 1)..])
|
1817
|
+
return Identity.new
|
1818
|
+
else
|
1819
|
+
return Rockets.new
|
1820
|
+
end
|
1821
|
+
end
|
1822
|
+
else
|
1823
|
+
if omitted_value?(assocs[(index + 1)..])
|
1824
|
+
return Identity.new
|
1825
|
+
else
|
1826
|
+
return Rockets.new
|
1827
|
+
end
|
1828
|
+
end
|
1820
1829
|
end
|
1821
1830
|
end
|
1831
|
+
|
1832
|
+
Labels.new
|
1822
1833
|
end
|
1823
1834
|
|
1824
|
-
|
1835
|
+
private
|
1836
|
+
|
1837
|
+
def omitted_value?(assocs)
|
1838
|
+
assocs.any? { |assoc| !assoc.is_a?(AssocSplat) && assoc.value.nil? }
|
1839
|
+
end
|
1825
1840
|
end
|
1826
1841
|
end
|
1827
1842
|
|
@@ -11644,6 +11659,10 @@ module SyntaxTree
|
|
11644
11659
|
elsif value.is_a?(Array) && (index = value.index(self))
|
11645
11660
|
parent.public_send(key)[index] = replace
|
11646
11661
|
break
|
11662
|
+
elsif value.is_a?(Array) &&
|
11663
|
+
(index = value.index { |(_k, v)| v == self })
|
11664
|
+
parent.public_send(key)[index][1] = replace
|
11665
|
+
break
|
11647
11666
|
end
|
11648
11667
|
end
|
11649
11668
|
end
|
data/lib/syntax_tree/parser.rb
CHANGED
@@ -670,7 +670,11 @@ module SyntaxTree
|
|
670
670
|
|
671
671
|
visit_methods do
|
672
672
|
def visit_var_ref(node)
|
673
|
-
node.
|
673
|
+
if node.start_char > pins.first.start_char
|
674
|
+
node.pin(stack[-2], pins.shift)
|
675
|
+
else
|
676
|
+
super
|
677
|
+
end
|
674
678
|
end
|
675
679
|
end
|
676
680
|
|
@@ -1732,13 +1736,13 @@ module SyntaxTree
|
|
1732
1736
|
# :call-seq:
|
1733
1737
|
# on_field: (
|
1734
1738
|
# untyped parent,
|
1735
|
-
# (:"::" | Op | Period) operator
|
1739
|
+
# (:"::" | Op | Period | 73) operator
|
1736
1740
|
# (Const | Ident) name
|
1737
1741
|
# ) -> Field
|
1738
1742
|
def on_field(parent, operator, name)
|
1739
1743
|
Field.new(
|
1740
1744
|
parent: parent,
|
1741
|
-
operator: operator,
|
1745
|
+
operator: operator == 73 ? :"::" : operator,
|
1742
1746
|
name: name,
|
1743
1747
|
location: parent.location.to(name.location)
|
1744
1748
|
)
|
@@ -2867,6 +2871,7 @@ module SyntaxTree
|
|
2867
2871
|
alias on_assign_error on_parse_error
|
2868
2872
|
alias on_class_name_error on_parse_error
|
2869
2873
|
alias on_param_error on_parse_error
|
2874
|
+
alias compile_error on_parse_error
|
2870
2875
|
|
2871
2876
|
# :call-seq:
|
2872
2877
|
# on_period: (String value) -> Period
|
data/lib/syntax_tree/pattern.rb
CHANGED
data/lib/syntax_tree/version.rb
CHANGED
@@ -408,7 +408,7 @@ module SyntaxTree
|
|
408
408
|
def find_local(iseq, operands)
|
409
409
|
name_string, level_string = operands.split(/,\s*/)
|
410
410
|
name = name_string.to_sym
|
411
|
-
level = level_string
|
411
|
+
level = level_string.to_i
|
412
412
|
|
413
413
|
iseq.local_table.plain(name)
|
414
414
|
iseq.local_table.find(name, level)
|
@@ -455,7 +455,7 @@ module SyntaxTree
|
|
455
455
|
CallData::CALL_ARGS_SIMPLE
|
456
456
|
end
|
457
457
|
|
458
|
-
YARV.calldata(message.to_sym, argc_value
|
458
|
+
YARV.calldata(message.to_sym, argc_value.to_i, flags)
|
459
459
|
end
|
460
460
|
end
|
461
461
|
end
|
@@ -45,7 +45,7 @@ module SyntaxTree
|
|
45
45
|
when Integer
|
46
46
|
Int(value.to_s)
|
47
47
|
when Symbol
|
48
|
-
SymbolLiteral(Ident(value.
|
48
|
+
SymbolLiteral(Ident(value.name))
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -88,10 +88,10 @@ module SyntaxTree
|
|
88
88
|
|
89
89
|
clause << HashLiteral(LBrace("{"), assocs)
|
90
90
|
when GetGlobal
|
91
|
-
clause << VarRef(GVar(insn.name.
|
91
|
+
clause << VarRef(GVar(insn.name.name))
|
92
92
|
when GetLocalWC0
|
93
93
|
local = iseq.local_table.locals[insn.index]
|
94
|
-
clause << VarRef(Ident(local.name.
|
94
|
+
clause << VarRef(Ident(local.name.name))
|
95
95
|
when Jump
|
96
96
|
clause << Assign(block_label.field, node_for(insn.label.name))
|
97
97
|
clause << Next(Args([]))
|
@@ -123,7 +123,7 @@ module SyntaxTree
|
|
123
123
|
left, right = clause.pop(2)
|
124
124
|
clause << Binary(left, :"!=", right)
|
125
125
|
when OptSendWithoutBlock
|
126
|
-
method = insn.calldata.method.
|
126
|
+
method = insn.calldata.method.name
|
127
127
|
argc = insn.calldata.argc
|
128
128
|
|
129
129
|
if insn.calldata.flag?(CallData::CALL_FCALL)
|
@@ -182,7 +182,7 @@ module SyntaxTree
|
|
182
182
|
when PutSelf
|
183
183
|
clause << VarRef(Kw("self"))
|
184
184
|
when SetGlobal
|
185
|
-
target = GVar(insn.name.
|
185
|
+
target = GVar(insn.name.name)
|
186
186
|
value = clause.pop
|
187
187
|
|
188
188
|
clause << if value.is_a?(Binary) && VarRef(target) === value.left
|
@@ -256,7 +256,7 @@ module SyntaxTree
|
|
256
256
|
def local_name(index, level)
|
257
257
|
current = iseq
|
258
258
|
level.times { current = current.parent_iseq }
|
259
|
-
current.local_table.locals[index].name.
|
259
|
+
current.local_table.locals[index].name.name
|
260
260
|
end
|
261
261
|
end
|
262
262
|
end
|
@@ -252,19 +252,23 @@ module SyntaxTree
|
|
252
252
|
dumped_options = argument_options.dup
|
253
253
|
dumped_options[:opt].map!(&:name) if dumped_options[:opt]
|
254
254
|
|
255
|
+
metadata = {
|
256
|
+
arg_size: argument_size,
|
257
|
+
local_size: local_table.size,
|
258
|
+
stack_max: stack.maximum_size,
|
259
|
+
node_id: -1,
|
260
|
+
node_ids: [-1] * insns.length
|
261
|
+
}
|
262
|
+
|
263
|
+
metadata[:parser] = :prism if RUBY_VERSION >= "3.3"
|
264
|
+
|
255
265
|
# Next, return the instruction sequence as an array.
|
256
266
|
[
|
257
267
|
MAGIC,
|
258
268
|
versions[0],
|
259
269
|
versions[1],
|
260
270
|
1,
|
261
|
-
|
262
|
-
arg_size: argument_size,
|
263
|
-
local_size: local_table.size,
|
264
|
-
stack_max: stack.maximum_size,
|
265
|
-
node_id: -1,
|
266
|
-
node_ids: [-1] * insns.length
|
267
|
-
},
|
271
|
+
metadata,
|
268
272
|
name,
|
269
273
|
file,
|
270
274
|
"<compiled>",
|
@@ -689,6 +693,10 @@ module SyntaxTree
|
|
689
693
|
push(ConcatStrings.new(number))
|
690
694
|
end
|
691
695
|
|
696
|
+
def concattoarray(object)
|
697
|
+
push(ConcatToArray.new(object))
|
698
|
+
end
|
699
|
+
|
692
700
|
def defineclass(name, class_iseq, flags)
|
693
701
|
push(DefineClass.new(name, class_iseq, flags))
|
694
702
|
end
|
@@ -897,6 +905,14 @@ module SyntaxTree
|
|
897
905
|
push(Pop.new)
|
898
906
|
end
|
899
907
|
|
908
|
+
def pushtoarraykwsplat
|
909
|
+
push(PushToArrayKwSplat.new)
|
910
|
+
end
|
911
|
+
|
912
|
+
def putchilledstring(object)
|
913
|
+
push(PutChilledString.new(object))
|
914
|
+
end
|
915
|
+
|
900
916
|
def putnil
|
901
917
|
push(PutNil.new)
|
902
918
|
end
|
@@ -1079,6 +1095,8 @@ module SyntaxTree
|
|
1079
1095
|
iseq.concatarray
|
1080
1096
|
when :concatstrings
|
1081
1097
|
iseq.concatstrings(opnds[0])
|
1098
|
+
when :concattoarray
|
1099
|
+
iseq.concattoarray(opnds[0])
|
1082
1100
|
when :defineclass
|
1083
1101
|
iseq.defineclass(opnds[0], from(opnds[1], options, iseq), opnds[2])
|
1084
1102
|
when :defined
|
@@ -1191,8 +1209,13 @@ module SyntaxTree
|
|
1191
1209
|
iseq.newarray(opnds[0])
|
1192
1210
|
iseq.send(YARV.calldata(:min))
|
1193
1211
|
when :opt_newarray_send
|
1212
|
+
mid = opnds[1]
|
1213
|
+
if RUBY_VERSION >= "3.4"
|
1214
|
+
mid = %i[max min hash pack pack_buffer include?][mid - 1]
|
1215
|
+
end
|
1216
|
+
|
1194
1217
|
iseq.newarray(opnds[0])
|
1195
|
-
iseq.send(CallData.new(
|
1218
|
+
iseq.send(CallData.new(mid))
|
1196
1219
|
when :opt_neq
|
1197
1220
|
iseq.push(
|
1198
1221
|
OptNEq.new(CallData.from(opnds[0]), CallData.from(opnds[1]))
|
@@ -1207,6 +1230,10 @@ module SyntaxTree
|
|
1207
1230
|
iseq.send(YARV.calldata(:-@))
|
1208
1231
|
when :pop
|
1209
1232
|
iseq.pop
|
1233
|
+
when :pushtoarraykwsplat
|
1234
|
+
iseq.pushtoarraykwsplat
|
1235
|
+
when :putchilledstring
|
1236
|
+
iseq.putchilledstring(opnds[0])
|
1210
1237
|
when :putnil
|
1211
1238
|
iseq.putnil
|
1212
1239
|
when :putobject
|
@@ -757,6 +757,59 @@ module SyntaxTree
|
|
757
757
|
end
|
758
758
|
end
|
759
759
|
|
760
|
+
# ### Summary
|
761
|
+
#
|
762
|
+
# `concattoarray` pops a single value off the stack and attempts to concat
|
763
|
+
# it to the Array on top of the stack. If the value is not an Array, it
|
764
|
+
# will be coerced into one.
|
765
|
+
#
|
766
|
+
# ### Usage
|
767
|
+
#
|
768
|
+
# ~~~ruby
|
769
|
+
# [1, *2]
|
770
|
+
# ~~~
|
771
|
+
#
|
772
|
+
class ConcatToArray < Instruction
|
773
|
+
attr_reader :object
|
774
|
+
|
775
|
+
def initialize(object)
|
776
|
+
@object = object
|
777
|
+
end
|
778
|
+
|
779
|
+
def disasm(fmt)
|
780
|
+
fmt.instruction("concattoarray", [fmt.object(object)])
|
781
|
+
end
|
782
|
+
|
783
|
+
def to_a(_iseq)
|
784
|
+
[:concattoarray, object]
|
785
|
+
end
|
786
|
+
|
787
|
+
def deconstruct_keys(_keys)
|
788
|
+
{ object: object }
|
789
|
+
end
|
790
|
+
|
791
|
+
def ==(other)
|
792
|
+
other.is_a?(ConcatToArray) && other.object == object
|
793
|
+
end
|
794
|
+
|
795
|
+
def length
|
796
|
+
2
|
797
|
+
end
|
798
|
+
|
799
|
+
def pops
|
800
|
+
1
|
801
|
+
end
|
802
|
+
|
803
|
+
def pushes
|
804
|
+
1
|
805
|
+
end
|
806
|
+
|
807
|
+
def call(vm)
|
808
|
+
array, value = vm.pop(2)
|
809
|
+
vm.push(array.concat(Array(value)))
|
810
|
+
end
|
811
|
+
end
|
812
|
+
|
760
813
|
# ### Summary
|
761
814
|
#
|
762
815
|
# `defineclass` defines a class. First it pops the superclass off the
|
@@ -4472,6 +4525,52 @@ module SyntaxTree
|
|
4472
4525
|
end
|
4473
4526
|
end
|
4474
4527
|
|
4528
|
+
# ### Summary
|
4529
|
+
#
|
4530
|
+
# `pushtoarraykwsplat` is used to append a hash literal that is being
|
4531
|
+
# splatted onto an array.
|
4532
|
+
#
|
4533
|
+
# ### Usage
|
4534
|
+
#
|
4535
|
+
# ~~~ruby
|
4536
|
+
# ["string", **{ foo: "bar" }]
|
4537
|
+
# ~~~
|
4538
|
+
#
|
4539
|
+
class PushToArrayKwSplat < Instruction
|
4540
|
+
def disasm(fmt)
|
4541
|
+
fmt.instruction("pushtoarraykwsplat")
|
4542
|
+
end
|
4543
|
+
|
4544
|
+
def to_a(_iseq)
|
4545
|
+
[:pushtoarraykwsplat]
|
4546
|
+
end
|
4547
|
+
|
4548
|
+
def deconstruct_keys(_keys)
|
4549
|
+
{}
|
4550
|
+
end
|
4551
|
+
|
4552
|
+
def ==(other)
|
4553
|
+
other.is_a?(PushToArrayKwSplat)
|
4554
|
+
end
|
4555
|
+
|
4556
|
+
def length
|
4557
|
+
2
|
4558
|
+
end
|
4559
|
+
|
4560
|
+
def pops
|
4561
|
+
2
|
4562
|
+
end
|
4563
|
+
|
4564
|
+
def pushes
|
4565
|
+
1
|
4566
|
+
end
|
4567
|
+
|
4568
|
+
def call(vm)
|
4569
|
+
array, hash = vm.pop(2)
|
4570
|
+
vm.push(array << hash)
|
4571
|
+
end
|
4572
|
+
end
|
4573
|
+
|
4475
4574
|
# ### Summary
|
4476
4575
|
#
|
4477
4576
|
# `putnil` pushes a global nil object onto the stack.
|
@@ -4759,6 +4858,54 @@ module SyntaxTree
|
|
4759
4858
|
end
|
4760
4859
|
end
|
4761
4860
|
|
4861
|
+
# ### Summary
|
4862
|
+
#
|
4863
|
+
# `putchilledstring` pushes an unfrozen string literal onto the stack that
|
4864
|
+
# acts like a frozen string. This is a migration path to frozen string
|
4865
|
+
# literals as the default in the future.
|
4866
|
+
#
|
4867
|
+
# ### Usage
|
4868
|
+
#
|
4869
|
+
# ~~~ruby
|
4870
|
+
# "foo"
|
4871
|
+
# ~~~
|
4872
|
+
#
|
4873
|
+
class PutChilledString < Instruction
|
4874
|
+
attr_reader :object
|
4875
|
+
|
4876
|
+
def initialize(object)
|
4877
|
+
@object = object
|
4878
|
+
end
|
4879
|
+
|
4880
|
+
def disasm(fmt)
|
4881
|
+
fmt.instruction("putchilledstring", [fmt.object(object)])
|
4882
|
+
end
|
4883
|
+
|
4884
|
+
def to_a(_iseq)
|
4885
|
+
[:putchilledstring, object]
|
4886
|
+
end
|
4887
|
+
|
4888
|
+
def deconstruct_keys(_keys)
|
4889
|
+
{ object: object }
|
4890
|
+
end
|
4891
|
+
|
4892
|
+
def ==(other)
|
4893
|
+
other.is_a?(PutChilledString) && other.object == object
|
4894
|
+
end
|
4895
|
+
|
4896
|
+
def length
|
4897
|
+
2
|
4898
|
+
end
|
4899
|
+
|
4900
|
+
def pushes
|
4901
|
+
1
|
4902
|
+
end
|
4903
|
+
|
4904
|
+
def call(vm)
|
4905
|
+
vm.push(object.dup)
|
4906
|
+
end
|
4907
|
+
end
|
4908
|
+
|
4762
4909
|
# ### Summary
|
4763
4910
|
#
|
4764
4911
|
# `putstring` pushes an unfrozen string literal onto the stack.
|
data/tasks/whitequark.rake
CHANGED
@@ -43,8 +43,13 @@ module ParseHelper
|
|
43
43
|
# that we do not support.
|
44
44
|
return if (versions & %w[3.1 3.2]).empty?
|
45
45
|
|
46
|
-
entry =
|
47
|
-
|
46
|
+
entry =
|
47
|
+
caller.find do |call|
|
48
|
+
call.include?("test_parser.rb") && call.match?(%r{(?<!/)test_})
|
49
|
+
end
|
50
|
+
|
51
|
+
_, lineno, name =
|
52
|
+
*entry.match(/(\d+):in [`'](?:block in )?(?:TestParser#)?(.+)'/)
|
48
53
|
|
49
54
|
COLLECTED["#{name}:#{lineno}"] << code
|
50
55
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: syntax_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Newton
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-07-17 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: prettier_print
|
@@ -94,7 +93,6 @@ dependencies:
|
|
94
93
|
- - ">="
|
95
94
|
- !ruby/object:Gem::Version
|
96
95
|
version: '0'
|
97
|
-
description:
|
98
96
|
email:
|
99
97
|
- kddnewton@gmail.com
|
100
98
|
executables:
|
@@ -110,7 +108,6 @@ files:
|
|
110
108
|
- ".github/workflows/main.yml"
|
111
109
|
- ".gitignore"
|
112
110
|
- ".rubocop.yml"
|
113
|
-
- ".ruby-version"
|
114
111
|
- CHANGELOG.md
|
115
112
|
- CODE_OF_CONDUCT.md
|
116
113
|
- Gemfile
|
@@ -184,7 +181,6 @@ licenses:
|
|
184
181
|
- MIT
|
185
182
|
metadata:
|
186
183
|
rubygems_mfa_required: 'true'
|
187
|
-
post_install_message:
|
188
184
|
rdoc_options: []
|
189
185
|
require_paths:
|
190
186
|
- lib
|
@@ -199,8 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
199
195
|
- !ruby/object:Gem::Version
|
200
196
|
version: '0'
|
201
197
|
requirements: []
|
202
|
-
rubygems_version: 3.
|
203
|
-
signing_key:
|
198
|
+
rubygems_version: 3.6.2
|
204
199
|
specification_version: 4
|
205
200
|
summary: A parser based on ripper
|
206
201
|
test_files: []
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
3.2.0
|