prism 0.24.0 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/BSDmakefile +58 -0
  3. data/CHANGELOG.md +50 -1
  4. data/Makefile +5 -2
  5. data/README.md +45 -6
  6. data/config.yml +499 -4
  7. data/docs/build_system.md +31 -0
  8. data/docs/configuration.md +2 -0
  9. data/docs/cruby_compilation.md +1 -1
  10. data/docs/parser_translation.md +14 -9
  11. data/docs/releasing.md +2 -2
  12. data/docs/ripper_translation.md +50 -0
  13. data/docs/ruby_api.md +1 -0
  14. data/docs/serialization.md +26 -5
  15. data/ext/prism/api_node.c +911 -815
  16. data/ext/prism/api_pack.c +9 -0
  17. data/ext/prism/extconf.rb +27 -11
  18. data/ext/prism/extension.c +313 -66
  19. data/ext/prism/extension.h +5 -4
  20. data/include/prism/ast.h +213 -64
  21. data/include/prism/defines.h +106 -2
  22. data/include/prism/diagnostic.h +134 -71
  23. data/include/prism/encoding.h +22 -4
  24. data/include/prism/node.h +93 -0
  25. data/include/prism/options.h +82 -7
  26. data/include/prism/pack.h +11 -0
  27. data/include/prism/parser.h +198 -53
  28. data/include/prism/prettyprint.h +8 -0
  29. data/include/prism/static_literals.h +118 -0
  30. data/include/prism/util/pm_buffer.h +65 -2
  31. data/include/prism/util/pm_constant_pool.h +18 -1
  32. data/include/prism/util/pm_integer.h +119 -0
  33. data/include/prism/util/pm_list.h +1 -1
  34. data/include/prism/util/pm_newline_list.h +8 -0
  35. data/include/prism/util/pm_string.h +26 -2
  36. data/include/prism/version.h +2 -2
  37. data/include/prism.h +59 -1
  38. data/lib/prism/compiler.rb +8 -1
  39. data/lib/prism/debug.rb +46 -3
  40. data/lib/prism/desugar_compiler.rb +1 -1
  41. data/lib/prism/dispatcher.rb +29 -0
  42. data/lib/prism/dot_visitor.rb +87 -16
  43. data/lib/prism/dsl.rb +24 -12
  44. data/lib/prism/ffi.rb +67 -12
  45. data/lib/prism/lex_compat.rb +17 -15
  46. data/lib/prism/mutation_compiler.rb +11 -0
  47. data/lib/prism/node.rb +2096 -2499
  48. data/lib/prism/node_ext.rb +77 -29
  49. data/lib/prism/pack.rb +4 -0
  50. data/lib/prism/parse_result/comments.rb +34 -17
  51. data/lib/prism/parse_result/newlines.rb +3 -1
  52. data/lib/prism/parse_result.rb +78 -32
  53. data/lib/prism/pattern.rb +16 -4
  54. data/lib/prism/polyfill/string.rb +12 -0
  55. data/lib/prism/serialize.rb +439 -102
  56. data/lib/prism/translation/parser/compiler.rb +152 -50
  57. data/lib/prism/translation/parser/lexer.rb +103 -22
  58. data/lib/prism/translation/parser/rubocop.rb +41 -13
  59. data/lib/prism/translation/parser.rb +119 -7
  60. data/lib/prism/translation/parser33.rb +1 -1
  61. data/lib/prism/translation/parser34.rb +1 -1
  62. data/lib/prism/translation/ripper/sexp.rb +125 -0
  63. data/lib/prism/translation/ripper/shim.rb +5 -0
  64. data/lib/prism/translation/ripper.rb +3212 -462
  65. data/lib/prism/translation/ruby_parser.rb +35 -18
  66. data/lib/prism/translation.rb +3 -1
  67. data/lib/prism/visitor.rb +10 -0
  68. data/lib/prism.rb +8 -2
  69. data/prism.gemspec +33 -4
  70. data/rbi/prism/compiler.rbi +14 -0
  71. data/rbi/prism/desugar_compiler.rbi +5 -0
  72. data/rbi/prism/mutation_compiler.rbi +5 -0
  73. data/rbi/prism/node.rbi +8221 -0
  74. data/rbi/prism/node_ext.rbi +102 -0
  75. data/rbi/prism/parse_result.rbi +304 -0
  76. data/rbi/prism/translation/parser/compiler.rbi +13 -0
  77. data/rbi/prism/translation/ripper/ripper_compiler.rbi +5 -0
  78. data/rbi/prism/translation/ripper.rbi +25 -0
  79. data/rbi/prism/translation/ruby_parser.rbi +11 -0
  80. data/rbi/prism/visitor.rbi +470 -0
  81. data/rbi/prism.rbi +39 -7749
  82. data/sig/prism/compiler.rbs +9 -0
  83. data/sig/prism/dispatcher.rbs +16 -0
  84. data/sig/prism/dot_visitor.rbs +6 -0
  85. data/sig/prism/dsl.rbs +462 -0
  86. data/sig/prism/mutation_compiler.rbs +158 -0
  87. data/sig/prism/node.rbs +3529 -0
  88. data/sig/prism/node_ext.rbs +78 -0
  89. data/sig/prism/pack.rbs +43 -0
  90. data/sig/prism/parse_result.rbs +127 -0
  91. data/sig/prism/pattern.rbs +13 -0
  92. data/sig/prism/serialize.rbs +7 -0
  93. data/sig/prism/visitor.rbs +168 -0
  94. data/sig/prism.rbs +188 -4767
  95. data/src/diagnostic.c +575 -230
  96. data/src/encoding.c +211 -108
  97. data/src/node.c +7526 -447
  98. data/src/options.c +36 -12
  99. data/src/pack.c +33 -17
  100. data/src/prettyprint.c +1294 -1385
  101. data/src/prism.c +3628 -1099
  102. data/src/regexp.c +17 -2
  103. data/src/serialize.c +47 -28
  104. data/src/static_literals.c +552 -0
  105. data/src/token_type.c +1 -0
  106. data/src/util/pm_buffer.c +147 -20
  107. data/src/util/pm_char.c +4 -4
  108. data/src/util/pm_constant_pool.c +35 -11
  109. data/src/util/pm_integer.c +629 -0
  110. data/src/util/pm_list.c +1 -1
  111. data/src/util/pm_newline_list.c +14 -5
  112. data/src/util/pm_string.c +134 -5
  113. data/src/util/pm_string_list.c +2 -2
  114. metadata +35 -6
  115. data/docs/ripper.md +0 -36
  116. data/rbi/prism_static.rbi +0 -207
  117. data/sig/prism_static.rbs +0 -201
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  =begin
3
4
  This file is generated by the templates/template.rb script and should not be
4
5
  modified manually. See templates/lib/prism/dot_visitor.rb.erb
@@ -24,7 +25,7 @@ module Prism
24
25
  if port
25
26
  "<tr><td align=\"left\" colspan=\"2\" port=\"#{name}\">#{name}</td></tr>"
26
27
  else
27
- "<tr><td align=\"left\">#{name}</td><td>#{CGI.escapeHTML(value)}</td></tr>"
28
+ "<tr><td align=\"left\">#{name}</td><td>#{CGI.escapeHTML(value || raise)}</td></tr>"
28
29
  end
29
30
  end
30
31
  end
@@ -1155,9 +1156,7 @@ module Prism
1155
1156
  digraph.edge("#{id}:value -> #{node_id(node.value)};")
1156
1157
 
1157
1158
  # operator_loc
1158
- unless (operator_loc = node.operator_loc).nil?
1159
- table.field("operator_loc", location_inspect(operator_loc))
1160
- end
1159
+ table.field("operator_loc", location_inspect(node.operator_loc))
1161
1160
 
1162
1161
  digraph.nodes << <<~DOT
1163
1162
  #{id} [
@@ -1773,6 +1772,9 @@ module Prism
1773
1772
  table = Table.new("FloatNode")
1774
1773
  id = node_id(node)
1775
1774
 
1775
+ # value
1776
+ table.field("value", node.value.inspect)
1777
+
1776
1778
  digraph.nodes << <<~DOT
1777
1779
  #{id} [
1778
1780
  label=<#{table.to_dot.gsub(/\n/, "\n ")}>
@@ -2580,6 +2582,9 @@ module Prism
2580
2582
  # flags
2581
2583
  table.field("flags", integer_base_flags_inspect(node))
2582
2584
 
2585
+ # value
2586
+ table.field("value", node.value.inspect)
2587
+
2583
2588
  digraph.nodes << <<~DOT
2584
2589
  #{id} [
2585
2590
  label=<#{table.to_dot.gsub(/\n/, "\n ")}>
@@ -2666,6 +2671,9 @@ module Prism
2666
2671
  table = Table.new("InterpolatedStringNode")
2667
2672
  id = node_id(node)
2668
2673
 
2674
+ # flags
2675
+ table.field("flags", interpolated_string_node_flags_inspect(node))
2676
+
2669
2677
  # opening_loc
2670
2678
  unless (opening_loc = node.opening_loc).nil?
2671
2679
  table.field("opening_loc", location_inspect(opening_loc))
@@ -2768,6 +2776,20 @@ module Prism
2768
2776
  super
2769
2777
  end
2770
2778
 
2779
+ # Visit a ItParametersNode node.
2780
+ def visit_it_parameters_node(node)
2781
+ table = Table.new("ItParametersNode")
2782
+ id = node_id(node)
2783
+
2784
+ digraph.nodes << <<~DOT
2785
+ #{id} [
2786
+ label=<#{table.to_dot.gsub(/\n/, "\n ")}>
2787
+ ];
2788
+ DOT
2789
+
2790
+ super
2791
+ end
2792
+
2771
2793
  # Visit a KeywordHashNode node.
2772
2794
  def visit_keyword_hash_node(node)
2773
2795
  table = Table.new("KeywordHashNode")
@@ -4009,6 +4031,27 @@ module Prism
4009
4031
  super
4010
4032
  end
4011
4033
 
4034
+ # Visit a ShareableConstantNode node.
4035
+ def visit_shareable_constant_node(node)
4036
+ table = Table.new("ShareableConstantNode")
4037
+ id = node_id(node)
4038
+
4039
+ # flags
4040
+ table.field("flags", shareable_constant_node_flags_inspect(node))
4041
+
4042
+ # write
4043
+ table.field("write", port: true)
4044
+ digraph.edge("#{id}:write -> #{node_id(node.write)};")
4045
+
4046
+ digraph.nodes << <<~DOT
4047
+ #{id} [
4048
+ label=<#{table.to_dot.gsub(/\n/, "\n ")}>
4049
+ ];
4050
+ DOT
4051
+
4052
+ super
4053
+ end
4054
+
4012
4055
  # Visit a SingletonClassNode node.
4013
4056
  def visit_singleton_class_node(node)
4014
4057
  table = Table.new("SingletonClassNode")
@@ -4064,6 +4107,9 @@ module Prism
4064
4107
  table = Table.new("SourceFileNode")
4065
4108
  id = node_id(node)
4066
4109
 
4110
+ # flags
4111
+ table.field("flags", string_flags_inspect(node))
4112
+
4067
4113
  # filepath
4068
4114
  table.field("filepath", node.filepath.inspect)
4069
4115
 
@@ -4390,6 +4436,11 @@ module Prism
4390
4436
  table.field("conditions", "[]")
4391
4437
  end
4392
4438
 
4439
+ # then_keyword_loc
4440
+ unless (then_keyword_loc = node.then_keyword_loc).nil?
4441
+ table.field("then_keyword_loc", location_inspect(then_keyword_loc))
4442
+ end
4443
+
4393
4444
  # statements
4394
4445
  unless (statements = node.statements).nil?
4395
4446
  table.field("statements", port: true)
@@ -4517,7 +4568,7 @@ module Prism
4517
4568
  # Inspect a node that has arguments_node_flags flags to display the flags as a
4518
4569
  # comma-separated list.
4519
4570
  def arguments_node_flags_inspect(node)
4520
- flags = []
4571
+ flags = [] #: Array[String]
4521
4572
  flags << "contains_keyword_splat" if node.contains_keyword_splat?
4522
4573
  flags.join(", ")
4523
4574
  end
@@ -4525,7 +4576,7 @@ module Prism
4525
4576
  # Inspect a node that has array_node_flags flags to display the flags as a
4526
4577
  # comma-separated list.
4527
4578
  def array_node_flags_inspect(node)
4528
- flags = []
4579
+ flags = [] #: Array[String]
4529
4580
  flags << "contains_splat" if node.contains_splat?
4530
4581
  flags.join(", ")
4531
4582
  end
@@ -4533,7 +4584,7 @@ module Prism
4533
4584
  # Inspect a node that has call_node_flags flags to display the flags as a
4534
4585
  # comma-separated list.
4535
4586
  def call_node_flags_inspect(node)
4536
- flags = []
4587
+ flags = [] #: Array[String]
4537
4588
  flags << "safe_navigation" if node.safe_navigation?
4538
4589
  flags << "variable_call" if node.variable_call?
4539
4590
  flags << "attribute_write" if node.attribute_write?
@@ -4544,7 +4595,7 @@ module Prism
4544
4595
  # Inspect a node that has encoding_flags flags to display the flags as a
4545
4596
  # comma-separated list.
4546
4597
  def encoding_flags_inspect(node)
4547
- flags = []
4598
+ flags = [] #: Array[String]
4548
4599
  flags << "forced_utf8_encoding" if node.forced_utf8_encoding?
4549
4600
  flags << "forced_binary_encoding" if node.forced_binary_encoding?
4550
4601
  flags.join(", ")
@@ -4553,7 +4604,7 @@ module Prism
4553
4604
  # Inspect a node that has integer_base_flags flags to display the flags as a
4554
4605
  # comma-separated list.
4555
4606
  def integer_base_flags_inspect(node)
4556
- flags = []
4607
+ flags = [] #: Array[String]
4557
4608
  flags << "binary" if node.binary?
4558
4609
  flags << "decimal" if node.decimal?
4559
4610
  flags << "octal" if node.octal?
@@ -4561,10 +4612,19 @@ module Prism
4561
4612
  flags.join(", ")
4562
4613
  end
4563
4614
 
4615
+ # Inspect a node that has interpolated_string_node_flags flags to display the flags as a
4616
+ # comma-separated list.
4617
+ def interpolated_string_node_flags_inspect(node)
4618
+ flags = [] #: Array[String]
4619
+ flags << "frozen" if node.frozen?
4620
+ flags << "mutable" if node.mutable?
4621
+ flags.join(", ")
4622
+ end
4623
+
4564
4624
  # Inspect a node that has keyword_hash_node_flags flags to display the flags as a
4565
4625
  # comma-separated list.
4566
4626
  def keyword_hash_node_flags_inspect(node)
4567
- flags = []
4627
+ flags = [] #: Array[String]
4568
4628
  flags << "symbol_keys" if node.symbol_keys?
4569
4629
  flags.join(", ")
4570
4630
  end
@@ -4572,7 +4632,7 @@ module Prism
4572
4632
  # Inspect a node that has loop_flags flags to display the flags as a
4573
4633
  # comma-separated list.
4574
4634
  def loop_flags_inspect(node)
4575
- flags = []
4635
+ flags = [] #: Array[String]
4576
4636
  flags << "begin_modifier" if node.begin_modifier?
4577
4637
  flags.join(", ")
4578
4638
  end
@@ -4580,7 +4640,7 @@ module Prism
4580
4640
  # Inspect a node that has parameter_flags flags to display the flags as a
4581
4641
  # comma-separated list.
4582
4642
  def parameter_flags_inspect(node)
4583
- flags = []
4643
+ flags = [] #: Array[String]
4584
4644
  flags << "repeated_parameter" if node.repeated_parameter?
4585
4645
  flags.join(", ")
4586
4646
  end
@@ -4588,7 +4648,7 @@ module Prism
4588
4648
  # Inspect a node that has range_flags flags to display the flags as a
4589
4649
  # comma-separated list.
4590
4650
  def range_flags_inspect(node)
4591
- flags = []
4651
+ flags = [] #: Array[String]
4592
4652
  flags << "exclude_end" if node.exclude_end?
4593
4653
  flags.join(", ")
4594
4654
  end
@@ -4596,7 +4656,7 @@ module Prism
4596
4656
  # Inspect a node that has regular_expression_flags flags to display the flags as a
4597
4657
  # comma-separated list.
4598
4658
  def regular_expression_flags_inspect(node)
4599
- flags = []
4659
+ flags = [] #: Array[String]
4600
4660
  flags << "ignore_case" if node.ignore_case?
4601
4661
  flags << "extended" if node.extended?
4602
4662
  flags << "multi_line" if node.multi_line?
@@ -4611,20 +4671,31 @@ module Prism
4611
4671
  flags.join(", ")
4612
4672
  end
4613
4673
 
4674
+ # Inspect a node that has shareable_constant_node_flags flags to display the flags as a
4675
+ # comma-separated list.
4676
+ def shareable_constant_node_flags_inspect(node)
4677
+ flags = [] #: Array[String]
4678
+ flags << "literal" if node.literal?
4679
+ flags << "experimental_everything" if node.experimental_everything?
4680
+ flags << "experimental_copy" if node.experimental_copy?
4681
+ flags.join(", ")
4682
+ end
4683
+
4614
4684
  # Inspect a node that has string_flags flags to display the flags as a
4615
4685
  # comma-separated list.
4616
4686
  def string_flags_inspect(node)
4617
- flags = []
4687
+ flags = [] #: Array[String]
4618
4688
  flags << "forced_utf8_encoding" if node.forced_utf8_encoding?
4619
4689
  flags << "forced_binary_encoding" if node.forced_binary_encoding?
4620
4690
  flags << "frozen" if node.frozen?
4691
+ flags << "mutable" if node.mutable?
4621
4692
  flags.join(", ")
4622
4693
  end
4623
4694
 
4624
4695
  # Inspect a node that has symbol_flags flags to display the flags as a
4625
4696
  # comma-separated list.
4626
4697
  def symbol_flags_inspect(node)
4627
- flags = []
4698
+ flags = [] #: Array[String]
4628
4699
  flags << "forced_utf8_encoding" if node.forced_utf8_encoding?
4629
4700
  flags << "forced_binary_encoding" if node.forced_binary_encoding?
4630
4701
  flags << "forced_us_ascii_encoding" if node.forced_us_ascii_encoding?
data/lib/prism/dsl.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  =begin
3
4
  This file is generated by the templates/template.rb script and should not be
4
5
  modified manually. See templates/lib/prism/dsl.rb.erb
@@ -15,6 +16,7 @@ module Prism
15
16
  # [
16
17
  # Prism::IntegerNode.new(
17
18
  # Prism::IntegerBaseFlags::DECIMAL,
19
+ # 1,
18
20
  # Prism::Location.new(source, 1, 1),
19
21
  # source
20
22
  # )
@@ -29,7 +31,7 @@ module Prism
29
31
  # source = Prism::Source.new("[1]")
30
32
  #
31
33
  # ArrayNode(
32
- # IntegerNode(Prism::IntegerBaseFlags::DECIMAL, Location(source, 1, 1)), source),
34
+ # IntegerNode(Prism::IntegerBaseFlags::DECIMAL, 1, Location(source, 1, 1)), source),
33
35
  # Location(source, 0, 1),
34
36
  # Location(source, 2, 1),
35
37
  # source
@@ -42,7 +44,7 @@ module Prism
42
44
 
43
45
  # Create a new Location object
44
46
  def Location(source = nil, start_offset = 0, length = 0)
45
- Location.new(source, start_offset, length)
47
+ Location.new(source, start_offset, length) # steep:ignore
46
48
  end
47
49
 
48
50
  # Create a new AliasGlobalVariableNode node
@@ -311,8 +313,8 @@ module Prism
311
313
  end
312
314
 
313
315
  # Create a new FloatNode node
314
- def FloatNode(source = nil, location = Location())
315
- FloatNode.new(source, location)
316
+ def FloatNode(value, source = nil, location = Location())
317
+ FloatNode.new(source, value, location)
316
318
  end
317
319
 
318
320
  # Create a new ForNode node
@@ -451,8 +453,8 @@ module Prism
451
453
  end
452
454
 
453
455
  # Create a new IntegerNode node
454
- def IntegerNode(flags, source = nil, location = Location())
455
- IntegerNode.new(source, flags, location)
456
+ def IntegerNode(flags, value, source = nil, location = Location())
457
+ IntegerNode.new(source, flags, value, location)
456
458
  end
457
459
 
458
460
  # Create a new InterpolatedMatchLastLineNode node
@@ -466,8 +468,8 @@ module Prism
466
468
  end
467
469
 
468
470
  # Create a new InterpolatedStringNode node
469
- def InterpolatedStringNode(opening_loc, parts, closing_loc, source = nil, location = Location())
470
- InterpolatedStringNode.new(source, opening_loc, parts, closing_loc, location)
471
+ def InterpolatedStringNode(flags, opening_loc, parts, closing_loc, source = nil, location = Location())
472
+ InterpolatedStringNode.new(source, flags, opening_loc, parts, closing_loc, location)
471
473
  end
472
474
 
473
475
  # Create a new InterpolatedSymbolNode node
@@ -480,6 +482,11 @@ module Prism
480
482
  InterpolatedXStringNode.new(source, opening_loc, parts, closing_loc, location)
481
483
  end
482
484
 
485
+ # Create a new ItParametersNode node
486
+ def ItParametersNode(source = nil, location = Location())
487
+ ItParametersNode.new(source, location)
488
+ end
489
+
483
490
  # Create a new KeywordHashNode node
484
491
  def KeywordHashNode(flags, elements, source = nil, location = Location())
485
492
  KeywordHashNode.new(source, flags, elements, location)
@@ -700,6 +707,11 @@ module Prism
700
707
  SelfNode.new(source, location)
701
708
  end
702
709
 
710
+ # Create a new ShareableConstantNode node
711
+ def ShareableConstantNode(flags, write, source = nil, location = Location())
712
+ ShareableConstantNode.new(source, flags, write, location)
713
+ end
714
+
703
715
  # Create a new SingletonClassNode node
704
716
  def SingletonClassNode(locals, class_keyword_loc, operator_loc, expression, body, end_keyword_loc, source = nil, location = Location())
705
717
  SingletonClassNode.new(source, locals, class_keyword_loc, operator_loc, expression, body, end_keyword_loc, location)
@@ -711,8 +723,8 @@ module Prism
711
723
  end
712
724
 
713
725
  # Create a new SourceFileNode node
714
- def SourceFileNode(filepath, source = nil, location = Location())
715
- SourceFileNode.new(source, filepath, location)
726
+ def SourceFileNode(flags, filepath, source = nil, location = Location())
727
+ SourceFileNode.new(source, flags, filepath, location)
716
728
  end
717
729
 
718
730
  # Create a new SourceLineNode node
@@ -766,8 +778,8 @@ module Prism
766
778
  end
767
779
 
768
780
  # Create a new WhenNode node
769
- def WhenNode(keyword_loc, conditions, statements, source = nil, location = Location())
770
- WhenNode.new(source, keyword_loc, conditions, statements, location)
781
+ def WhenNode(keyword_loc, conditions, then_keyword_loc, statements, source = nil, location = Location())
782
+ WhenNode.new(source, keyword_loc, conditions, then_keyword_loc, statements, location)
771
783
  end
772
784
 
773
785
  # Create a new WhileNode node
data/lib/prism/ffi.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: ignore
2
3
 
3
4
  # This file is responsible for mirroring the API provided by the C extension by
4
5
  # using FFI to call into the shared library.
@@ -7,8 +8,6 @@ require "rbconfig"
7
8
  require "ffi"
8
9
 
9
10
  module Prism
10
- BACKEND = :FFI
11
-
12
11
  module LibRubyParser # :nodoc:
13
12
  extend FFI::Library
14
13
 
@@ -24,15 +23,21 @@ module Prism
24
23
  # size_t -> :size_t
25
24
  # void -> :void
26
25
  #
27
- def self.resolve_type(type)
26
+ def self.resolve_type(type, callbacks)
28
27
  type = type.strip
29
- type.end_with?("*") ? :pointer : type.delete_prefix("const ").to_sym
28
+
29
+ if !type.end_with?("*")
30
+ type.delete_prefix("const ").to_sym
31
+ else
32
+ type = type.delete_suffix("*").rstrip
33
+ callbacks.include?(type.to_sym) ? type.to_sym : :pointer
34
+ end
30
35
  end
31
36
 
32
37
  # Read through the given header file and find the declaration of each of the
33
38
  # given functions. For each one, define a function with the same name and
34
39
  # signature as the C function.
35
- def self.load_exported_functions_from(header, *functions)
40
+ def self.load_exported_functions_from(header, *functions, callbacks)
36
41
  File.foreach(File.expand_path("../../include/#{header}", __dir__)) do |line|
37
42
  # We only want to attempt to load exported functions.
38
43
  next unless line.start_with?("PRISM_EXPORTED_FUNCTION ")
@@ -56,24 +61,28 @@ module Prism
56
61
 
57
62
  # Resolve the type of the argument by dropping the name of the argument
58
63
  # first if it is present.
59
- arg_types.map! { |type| resolve_type(type.sub(/\w+$/, "")) }
64
+ arg_types.map! { |type| resolve_type(type.sub(/\w+$/, ""), callbacks) }
60
65
 
61
66
  # Attach the function using the FFI library.
62
- attach_function name, arg_types, resolve_type(return_type)
67
+ attach_function name, arg_types, resolve_type(return_type, [])
63
68
  end
64
69
 
65
70
  # If we didn't find all of the functions, raise an error.
66
71
  raise "Could not find functions #{functions.inspect}" unless functions.empty?
67
72
  end
68
73
 
74
+ callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
75
+
69
76
  load_exported_functions_from(
70
77
  "prism.h",
71
78
  "pm_version",
72
79
  "pm_serialize_parse",
80
+ "pm_serialize_parse_stream",
73
81
  "pm_serialize_parse_comments",
74
82
  "pm_serialize_lex",
75
83
  "pm_serialize_parse_lex",
76
- "pm_parse_success_p"
84
+ "pm_parse_success_p",
85
+ [:pm_parse_stream_fgets_t]
77
86
  )
78
87
 
79
88
  load_exported_functions_from(
@@ -82,7 +91,8 @@ module Prism
82
91
  "pm_buffer_init",
83
92
  "pm_buffer_value",
84
93
  "pm_buffer_length",
85
- "pm_buffer_free"
94
+ "pm_buffer_free",
95
+ []
86
96
  )
87
97
 
88
98
  load_exported_functions_from(
@@ -91,7 +101,8 @@ module Prism
91
101
  "pm_string_free",
92
102
  "pm_string_source",
93
103
  "pm_string_length",
94
- "pm_string_sizeof"
104
+ "pm_string_sizeof",
105
+ []
95
106
  )
96
107
 
97
108
  # This object represents a pm_buffer_t. We only use it as an opaque pointer,
@@ -216,13 +227,36 @@ module Prism
216
227
  end
217
228
 
218
229
  # Mirror the Prism.parse_file API by using the serialization API. This uses
219
- # native strings instead of Ruby strings because it allows us to use mmap when
220
- # it is available.
230
+ # native strings instead of Ruby strings because it allows us to use mmap
231
+ # when it is available.
221
232
  def parse_file(filepath, **options)
222
233
  options[:filepath] = filepath
223
234
  LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) }
224
235
  end
225
236
 
237
+ # Mirror the Prism.parse_stream API by using the serialization API.
238
+ def parse_stream(stream, **options)
239
+ LibRubyParser::PrismBuffer.with do |buffer|
240
+ source = +""
241
+ callback = -> (string, size, _) {
242
+ raise "Expected size to be >= 0, got: #{size}" if size <= 0
243
+
244
+ if !(line = stream.gets(size - 1)).nil?
245
+ source << line
246
+ string.write_string("#{line}\x00", line.bytesize + 1)
247
+ end
248
+ }
249
+
250
+ # In the pm_serialize_parse_stream function it accepts a pointer to the
251
+ # IO object as a void* and then passes it through to the callback as the
252
+ # third argument, but it never touches it itself. As such, since we have
253
+ # access to the IO object already through the closure of the lambda, we
254
+ # can pass a null pointer here and not worry.
255
+ LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, dump_options(options))
256
+ Prism.load(source, buffer.read)
257
+ end
258
+ end
259
+
226
260
  # Mirror the Prism.parse_comments API by using the serialization API.
227
261
  def parse_comments(code, **options)
228
262
  LibRubyParser::PrismString.with_string(code) { |string| parse_comments_common(string, code, options) }
@@ -314,6 +348,24 @@ module Prism
314
348
  LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options))
315
349
  end
316
350
 
351
+ # Return the value that should be dumped for the command_line option.
352
+ def dump_options_command_line(options)
353
+ command_line = options.fetch(:command_line, "")
354
+ raise ArgumentError, "command_line must be a string" unless command_line.is_a?(String)
355
+
356
+ command_line.each_char.inject(0) do |value, char|
357
+ case char
358
+ when "a" then value | 0b000001
359
+ when "e" then value | 0b000010
360
+ when "l" then value | 0b000100
361
+ when "n" then value | 0b001000
362
+ when "p" then value | 0b010000
363
+ when "x" then value | 0b100000
364
+ else raise ArgumentError, "invalid command_line option: #{char}"
365
+ end
366
+ end
367
+ end
368
+
317
369
  # Convert the given options into a serialized options string.
318
370
  def dump_options(options)
319
371
  template = +""
@@ -342,6 +394,9 @@ module Prism
342
394
  template << "C"
343
395
  values << (options.fetch(:frozen_string_literal, false) ? 1 : 0)
344
396
 
397
+ template << "C"
398
+ values << dump_options_command_line(options)
399
+
345
400
  template << "C"
346
401
  values << { nil => 0, "3.3.0" => 1, "3.4.0" => 0, "latest" => 0 }.fetch(options[:version])
347
402
 
@@ -185,6 +185,8 @@ module Prism
185
185
  # However, we add a couple of convenience methods onto them to make them a
186
186
  # little easier to work with. We delegate all other methods to the array.
187
187
  class Token < SimpleDelegator
188
+ # @dynamic initialize, each, []
189
+
188
190
  # The location of the token in the source.
189
191
  def location
190
192
  self[0]
@@ -241,10 +243,10 @@ module Prism
241
243
  def ==(other) # :nodoc:
242
244
  return false unless self[0...-1] == other[0...-1]
243
245
 
244
- if self[4] == Ripper::EXPR_ARG | Ripper::EXPR_LABELED
245
- other[4] & Ripper::EXPR_ARG | Ripper::EXPR_LABELED > 0
246
+ if self[3] == Ripper::EXPR_ARG | Ripper::EXPR_LABELED
247
+ other[3] & Ripper::EXPR_ARG | Ripper::EXPR_LABELED != 0
246
248
  else
247
- self[4] == other[4]
249
+ self[3] == other[3]
248
250
  end
249
251
  end
250
252
  end
@@ -308,7 +310,7 @@ module Prism
308
310
  def to_a
309
311
  embexpr_balance = 0
310
312
 
311
- tokens.each_with_object([]) do |token, results|
313
+ tokens.each_with_object([]) do |token, results| #$ Array[Token]
312
314
  case token.event
313
315
  when :on_embexpr_beg
314
316
  embexpr_balance += 1
@@ -409,7 +411,7 @@ module Prism
409
411
  # If every line in the heredoc is blank, we still need to split up the
410
412
  # string content token into multiple tokens.
411
413
  if dedent.nil?
412
- results = []
414
+ results = [] #: Array[Token]
413
415
  embexpr_balance = 0
414
416
 
415
417
  tokens.each do |token|
@@ -444,7 +446,7 @@ module Prism
444
446
  # If the minimum common whitespace is 0, then we need to concatenate
445
447
  # string nodes together that are immediately adjacent.
446
448
  if dedent == 0
447
- results = []
449
+ results = [] #: Array[Token]
448
450
  embexpr_balance = 0
449
451
 
450
452
  index = 0
@@ -477,7 +479,7 @@ module Prism
477
479
  # insert on_ignored_sp tokens for the amount of dedent that we need to
478
480
  # perform. We also need to remove the dedent from the beginning of
479
481
  # each line of plain string content tokens.
480
- results = []
482
+ results = [] #: Array[Token]
481
483
  dedent_next = true
482
484
  embexpr_balance = 0
483
485
 
@@ -526,7 +528,7 @@ module Prism
526
528
  # dedent from the beginning of the line.
527
529
  if (dedent > 0) && (dedent_next || index > 0)
528
530
  deleting = 0
529
- deleted_chars = []
531
+ deleted_chars = [] #: Array[String]
530
532
 
531
533
  # Gather up all of the characters that we're going to
532
534
  # delete, stopping when you hit a character that would put
@@ -603,15 +605,15 @@ module Prism
603
605
  end
604
606
 
605
607
  def result
606
- tokens = []
608
+ tokens = [] #: Array[LexCompat::Token]
607
609
 
608
610
  state = :default
609
- heredoc_stack = [[]]
611
+ heredoc_stack = [[]] #: Array[Array[Heredoc::PlainHeredoc | Heredoc::DashHeredoc | Heredoc::DedentingHeredoc]]
610
612
 
611
613
  result = Prism.lex(source, **options)
612
614
  result_value = result.value
613
- previous_state = nil
614
- last_heredoc_end = nil
615
+ previous_state = nil #: Ripper::Lexer::State?
616
+ last_heredoc_end = nil #: Integer?
615
617
 
616
618
  # In previous versions of Ruby, Ripper wouldn't flush the bom before the
617
619
  # first token, so we had to have a hack in place to account for that. This
@@ -842,7 +844,7 @@ module Prism
842
844
  # We sort by location to compare against Ripper's output
843
845
  tokens.sort_by!(&:location)
844
846
 
845
- ParseResult.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, [])
847
+ ParseResult.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, Source.new(source))
846
848
  end
847
849
  end
848
850
 
@@ -858,8 +860,8 @@ module Prism
858
860
  end
859
861
 
860
862
  def result
861
- previous = []
862
- results = []
863
+ previous = [] #: [[Integer, Integer], Symbol, String, untyped] | []
864
+ results = [] #: Array[[[Integer, Integer], Symbol, String, untyped]]
863
865
 
864
866
  lex(source).each do |token|
865
867
  case token[1]
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  =begin
3
4
  This file is generated by the templates/template.rb script and should not be
4
5
  modified manually. See templates/lib/prism/mutation_compiler.rb.erb
@@ -445,6 +446,11 @@ module Prism
445
446
  node.copy(parts: visit_all(node.parts))
446
447
  end
447
448
 
449
+ # Copy a ItParametersNode node
450
+ def visit_it_parameters_node(node)
451
+ node.copy
452
+ end
453
+
448
454
  # Copy a KeywordHashNode node
449
455
  def visit_keyword_hash_node(node)
450
456
  node.copy(elements: visit_all(node.elements))
@@ -665,6 +671,11 @@ module Prism
665
671
  node.copy
666
672
  end
667
673
 
674
+ # Copy a ShareableConstantNode node
675
+ def visit_shareable_constant_node(node)
676
+ node.copy(write: visit(node.write))
677
+ end
678
+
668
679
  # Copy a SingletonClassNode node
669
680
  def visit_singleton_class_node(node)
670
681
  node.copy(expression: visit(node.expression), body: visit(node.body))