prism 0.30.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -1
  3. data/README.md +3 -1
  4. data/config.yml +185 -126
  5. data/docs/serialization.md +3 -0
  6. data/ext/prism/api_node.c +2843 -2085
  7. data/ext/prism/extconf.rb +1 -1
  8. data/ext/prism/extension.c +35 -25
  9. data/ext/prism/extension.h +2 -2
  10. data/include/prism/ast.h +1048 -69
  11. data/include/prism/defines.h +9 -0
  12. data/include/prism/diagnostic.h +11 -3
  13. data/include/prism/options.h +55 -1
  14. data/include/prism/parser.h +27 -3
  15. data/include/prism/regexp.h +2 -1
  16. data/include/prism/util/pm_integer.h +6 -6
  17. data/include/prism/util/pm_newline_list.h +11 -0
  18. data/include/prism/util/pm_string.h +1 -0
  19. data/include/prism/version.h +3 -3
  20. data/lib/prism/desugar_compiler.rb +111 -74
  21. data/lib/prism/dispatcher.rb +2 -1
  22. data/lib/prism/dot_visitor.rb +21 -31
  23. data/lib/prism/dsl.rb +656 -471
  24. data/lib/prism/ffi.rb +3 -0
  25. data/lib/prism/inspect_visitor.rb +285 -57
  26. data/lib/prism/mutation_compiler.rb +5 -5
  27. data/lib/prism/node.rb +2282 -4754
  28. data/lib/prism/node_ext.rb +72 -11
  29. data/lib/prism/parse_result/errors.rb +65 -0
  30. data/lib/prism/parse_result/newlines.rb +28 -28
  31. data/lib/prism/parse_result.rb +25 -2
  32. data/lib/prism/reflection.rb +7 -7
  33. data/lib/prism/serialize.rb +468 -610
  34. data/lib/prism/translation/parser/compiler.rb +18 -18
  35. data/lib/prism/translation/parser/lexer.rb +1 -1
  36. data/lib/prism/translation/parser.rb +3 -3
  37. data/lib/prism/translation/ripper.rb +14 -14
  38. data/lib/prism/translation/ruby_parser.rb +43 -7
  39. data/prism.gemspec +3 -1
  40. data/rbi/prism/dsl.rbi +521 -0
  41. data/rbi/prism/node.rbi +1456 -5616
  42. data/rbi/prism.rbi +16 -16
  43. data/sig/prism/dsl.rbs +189 -305
  44. data/sig/prism/node.rbs +702 -603
  45. data/sig/prism/parse_result.rbs +2 -0
  46. data/src/diagnostic.c +22 -6
  47. data/src/node.c +277 -284
  48. data/src/options.c +18 -0
  49. data/src/prettyprint.c +99 -108
  50. data/src/prism.c +1282 -760
  51. data/src/regexp.c +72 -4
  52. data/src/serialize.c +165 -50
  53. data/src/token_type.c +2 -2
  54. data/src/util/pm_integer.c +14 -14
  55. data/src/util/pm_newline_list.c +29 -0
  56. data/src/util/pm_string.c +9 -5
  57. metadata +4 -2
@@ -21,7 +21,10 @@ module Prism
21
21
  # Returns a numeric value that represents the flags that were used to create
22
22
  # the regular expression.
23
23
  def options
24
- o = flags & (RegularExpressionFlags::IGNORE_CASE | RegularExpressionFlags::EXTENDED | RegularExpressionFlags::MULTI_LINE)
24
+ o = 0
25
+ o |= Regexp::IGNORECASE if flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
26
+ o |= Regexp::EXTENDED if flags.anybits?(RegularExpressionFlags::EXTENDED)
27
+ o |= Regexp::MULTILINE if flags.anybits?(RegularExpressionFlags::MULTI_LINE)
25
28
  o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
26
29
  o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
27
30
  o
@@ -69,11 +72,12 @@ module Prism
69
72
  def to_interpolated
70
73
  InterpolatedStringNode.new(
71
74
  source,
75
+ -1,
76
+ location,
72
77
  frozen? ? InterpolatedStringNodeFlags::FROZEN : 0,
73
78
  opening_loc,
74
- [copy(opening_loc: nil, closing_loc: nil, location: content_loc)],
75
- closing_loc,
76
- location
79
+ [copy(location: content_loc, opening_loc: nil, closing_loc: nil)],
80
+ closing_loc
77
81
  )
78
82
  end
79
83
  end
@@ -86,10 +90,12 @@ module Prism
86
90
  def to_interpolated
87
91
  InterpolatedXStringNode.new(
88
92
  source,
93
+ -1,
94
+ location,
95
+ flags,
89
96
  opening_loc,
90
- [StringNode.new(source, 0, nil, content_loc, nil, unescaped, content_loc)],
91
- closing_loc,
92
- location
97
+ [StringNode.new(source, node_id, content_loc, 0, nil, content_loc, nil, unescaped)],
98
+ closing_loc
93
99
  )
94
100
  end
95
101
  end
@@ -115,9 +121,9 @@ module Prism
115
121
  deprecated("value", "numerator", "denominator")
116
122
 
117
123
  if denominator == 1
118
- IntegerNode.new(source, flags, numerator, location.chop)
124
+ IntegerNode.new(source, -1, location.chop, flags, numerator)
119
125
  else
120
- FloatNode.new(source, numerator.to_f / denominator, location.chop)
126
+ FloatNode.new(source, -1, location.chop, 0, numerator.to_f / denominator)
121
127
  end
122
128
  end
123
129
  end
@@ -195,7 +201,12 @@ module Prism
195
201
  # continue to supply that API.
196
202
  def child
197
203
  deprecated("name", "name_loc")
198
- name ? ConstantReadNode.new(source, name, name_loc) : MissingNode.new(source, location)
204
+
205
+ if name
206
+ ConstantReadNode.new(source, -1, name_loc, 0, name)
207
+ else
208
+ MissingNode.new(source, -1, location, 0)
209
+ end
199
210
  end
200
211
  end
201
212
 
@@ -231,7 +242,12 @@ module Prism
231
242
  # continue to supply that API.
232
243
  def child
233
244
  deprecated("name", "name_loc")
234
- name ? ConstantReadNode.new(source, name, name_loc) : MissingNode.new(source, location)
245
+
246
+ if name
247
+ ConstantReadNode.new(source, -1, name_loc, 0, name)
248
+ else
249
+ MissingNode.new(source, -1, location, 0)
250
+ end
235
251
  end
236
252
  end
237
253
 
@@ -444,4 +460,49 @@ module Prism
444
460
  binary_operator_loc
445
461
  end
446
462
  end
463
+
464
+ class CaseMatchNode < Node
465
+ # Returns the else clause of the case match node. This method is deprecated
466
+ # in favor of #else_clause.
467
+ def consequent
468
+ deprecated("else_clause")
469
+ else_clause
470
+ end
471
+ end
472
+
473
+ class CaseNode < Node
474
+ # Returns the else clause of the case node. This method is deprecated in
475
+ # favor of #else_clause.
476
+ def consequent
477
+ deprecated("else_clause")
478
+ else_clause
479
+ end
480
+ end
481
+
482
+ class IfNode < Node
483
+ # Returns the subsequent if/elsif/else clause of the if node. This method is
484
+ # deprecated in favor of #subsequent.
485
+ def consequent
486
+ deprecated("subsequent")
487
+ subsequent
488
+ end
489
+ end
490
+
491
+ class RescueNode < Node
492
+ # Returns the subsequent rescue clause of the rescue node. This method is
493
+ # deprecated in favor of #subsequent.
494
+ def consequent
495
+ deprecated("subsequent")
496
+ subsequent
497
+ end
498
+ end
499
+
500
+ class UnlessNode < Node
501
+ # Returns the else clause of the unless node. This method is deprecated in
502
+ # favor of #else_clause.
503
+ def consequent
504
+ deprecated("else_clause")
505
+ else_clause
506
+ end
507
+ end
447
508
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Prism
6
+ class ParseResult < Result
7
+ # An object to represent the set of errors on a parse result. This object
8
+ # can be used to format the errors in a human-readable way.
9
+ class Errors
10
+ # The parse result that contains the errors.
11
+ attr_reader :parse_result
12
+
13
+ # Initialize a new set of errors from the given parse result.
14
+ def initialize(parse_result)
15
+ @parse_result = parse_result
16
+ end
17
+
18
+ # Formats the errors in a human-readable way and return them as a string.
19
+ def format
20
+ error_lines = {}
21
+ parse_result.errors.each do |error|
22
+ location = error.location
23
+ (location.start_line..location.end_line).each do |line|
24
+ error_lines[line] ||= []
25
+ error_lines[line] << error
26
+ end
27
+ end
28
+
29
+ source_lines = parse_result.source.source.lines
30
+ source_lines << "" if error_lines.key?(source_lines.size + 1)
31
+
32
+ io = StringIO.new
33
+ source_lines.each.with_index(1) do |line, line_number|
34
+ io.puts(line)
35
+
36
+ (error_lines.delete(line_number) || []).each do |error|
37
+ location = error.location
38
+
39
+ case line_number
40
+ when location.start_line
41
+ io.print(" " * location.start_column + "^")
42
+
43
+ if location.start_line == location.end_line
44
+ if location.start_column != location.end_column
45
+ io.print("~" * (location.end_column - location.start_column - 1))
46
+ end
47
+
48
+ io.puts(" " + error.message)
49
+ else
50
+ io.puts("~" * (line.bytesize - location.start_column))
51
+ end
52
+ when location.end_line
53
+ io.puts("~" * location.end_column + " " + error.message)
54
+ else
55
+ io.puts("~" * line.bytesize)
56
+ end
57
+ end
58
+ end
59
+
60
+ io.puts
61
+ io.string
62
+ end
63
+ end
64
+ end
65
+ end
@@ -45,7 +45,7 @@ module Prism
45
45
 
46
46
  # Mark if/unless nodes as newlines.
47
47
  def visit_if_node(node)
48
- node.newline!(@lines)
48
+ node.newline_flag!(@lines)
49
49
  super(node)
50
50
  end
51
51
 
@@ -54,7 +54,7 @@ module Prism
54
54
  # Permit statements lists to mark newlines within themselves.
55
55
  def visit_statements_node(node)
56
56
  node.body.each do |child|
57
- child.newline!(@lines)
57
+ child.newline_flag!(@lines)
58
58
  end
59
59
  super(node)
60
60
  end
@@ -62,93 +62,93 @@ module Prism
62
62
  end
63
63
 
64
64
  class Node
65
- def newline? # :nodoc:
66
- @newline ? true : false
65
+ def newline_flag? # :nodoc:
66
+ @newline_flag ? true : false
67
67
  end
68
68
 
69
- def newline!(lines) # :nodoc:
69
+ def newline_flag!(lines) # :nodoc:
70
70
  line = location.start_line
71
71
  unless lines[line]
72
72
  lines[line] = true
73
- @newline = true
73
+ @newline_flag = true
74
74
  end
75
75
  end
76
76
  end
77
77
 
78
78
  class BeginNode < Node
79
- def newline!(lines) # :nodoc:
79
+ def newline_flag!(lines) # :nodoc:
80
80
  # Never mark BeginNode with a newline flag, mark children instead.
81
81
  end
82
82
  end
83
83
 
84
84
  class ParenthesesNode < Node
85
- def newline!(lines) # :nodoc:
85
+ def newline_flag!(lines) # :nodoc:
86
86
  # Never mark ParenthesesNode with a newline flag, mark children instead.
87
87
  end
88
88
  end
89
89
 
90
90
  class IfNode < Node
91
- def newline!(lines) # :nodoc:
92
- predicate.newline!(lines)
91
+ def newline_flag!(lines) # :nodoc:
92
+ predicate.newline_flag!(lines)
93
93
  end
94
94
  end
95
95
 
96
96
  class UnlessNode < Node
97
- def newline!(lines) # :nodoc:
98
- predicate.newline!(lines)
97
+ def newline_flag!(lines) # :nodoc:
98
+ predicate.newline_flag!(lines)
99
99
  end
100
100
  end
101
101
 
102
102
  class UntilNode < Node
103
- def newline!(lines) # :nodoc:
104
- predicate.newline!(lines)
103
+ def newline_flag!(lines) # :nodoc:
104
+ predicate.newline_flag!(lines)
105
105
  end
106
106
  end
107
107
 
108
108
  class WhileNode < Node
109
- def newline!(lines) # :nodoc:
110
- predicate.newline!(lines)
109
+ def newline_flag!(lines) # :nodoc:
110
+ predicate.newline_flag!(lines)
111
111
  end
112
112
  end
113
113
 
114
114
  class RescueModifierNode < Node
115
- def newline!(lines) # :nodoc:
116
- expression.newline!(lines)
115
+ def newline_flag!(lines) # :nodoc:
116
+ expression.newline_flag!(lines)
117
117
  end
118
118
  end
119
119
 
120
120
  class InterpolatedMatchLastLineNode < Node
121
- def newline!(lines) # :nodoc:
121
+ def newline_flag!(lines) # :nodoc:
122
122
  first = parts.first
123
- first.newline!(lines) if first
123
+ first.newline_flag!(lines) if first
124
124
  end
125
125
  end
126
126
 
127
127
  class InterpolatedRegularExpressionNode < Node
128
- def newline!(lines) # :nodoc:
128
+ def newline_flag!(lines) # :nodoc:
129
129
  first = parts.first
130
- first.newline!(lines) if first
130
+ first.newline_flag!(lines) if first
131
131
  end
132
132
  end
133
133
 
134
134
  class InterpolatedStringNode < Node
135
- def newline!(lines) # :nodoc:
135
+ def newline_flag!(lines) # :nodoc:
136
136
  first = parts.first
137
- first.newline!(lines) if first
137
+ first.newline_flag!(lines) if first
138
138
  end
139
139
  end
140
140
 
141
141
  class InterpolatedSymbolNode < Node
142
- def newline!(lines) # :nodoc:
142
+ def newline_flag!(lines) # :nodoc:
143
143
  first = parts.first
144
- first.newline!(lines) if first
144
+ first.newline_flag!(lines) if first
145
145
  end
146
146
  end
147
147
 
148
148
  class InterpolatedXStringNode < Node
149
- def newline!(lines) # :nodoc:
149
+ def newline_flag!(lines) # :nodoc:
150
150
  first = parts.first
151
- first.newline!(lines) if first
151
+ first.newline_flag!(lines) if first
152
152
  end
153
153
  end
154
154
  end
@@ -10,7 +10,11 @@ module Prism
10
10
  # specialized and more performant `ASCIISource` if no multibyte characters
11
11
  # are present in the source code.
12
12
  def self.for(source, start_line = 1, offsets = [])
13
- source.ascii_only? ? ASCIISource.new(source, start_line, offsets): new(source, start_line, offsets)
13
+ if source.ascii_only?
14
+ ASCIISource.new(source, start_line, offsets)
15
+ else
16
+ new(source, start_line, offsets)
17
+ end
14
18
  end
15
19
 
16
20
  # The source code that this source object represents.
@@ -87,7 +91,12 @@ module Prism
87
91
  # encodings, it is not captured here.
88
92
  def code_units_offset(byte_offset, encoding)
89
93
  byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding)
90
- (encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE) ? (byteslice.bytesize / 2) : byteslice.length
94
+
95
+ if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
96
+ byteslice.bytesize / 2
97
+ else
98
+ byteslice.length
99
+ end
91
100
  end
92
101
 
93
102
  # Returns the column number in code units for the given encoding for the
@@ -575,9 +584,11 @@ module Prism
575
584
  # This is a result specific to the `parse` and `parse_file` methods.
576
585
  class ParseResult < Result
577
586
  autoload :Comments, "prism/parse_result/comments"
587
+ autoload :Errors, "prism/parse_result/errors"
578
588
  autoload :Newlines, "prism/parse_result/newlines"
579
589
 
580
590
  private_constant :Comments
591
+ private_constant :Errors
581
592
  private_constant :Newlines
582
593
 
583
594
  # The syntax tree that was parsed from the source code.
@@ -604,6 +615,12 @@ module Prism
604
615
  def mark_newlines!
605
616
  value.accept(Newlines.new(source.offsets.size)) # steep:ignore
606
617
  end
618
+
619
+ # Returns a string representation of the syntax tree with the errors
620
+ # displayed inline.
621
+ def errors_format
622
+ Errors.new(self).format
623
+ end
607
624
  end
608
625
 
609
626
  # This is a result specific to the `lex` and `lex_file` methods.
@@ -694,5 +711,11 @@ module Prism
694
711
  other.type == type &&
695
712
  other.value == value
696
713
  end
714
+
715
+ # Returns a string representation of this token.
716
+ def inspect
717
+ location
718
+ super
719
+ end
697
720
  end
698
721
  end
@@ -112,7 +112,7 @@ module Prism
112
112
  when :and_node
113
113
  [NodeField.new(:left), NodeField.new(:right), LocationField.new(:operator_loc)]
114
114
  when :arguments_node
115
- [FlagsField.new(:flags, [:contains_keywords?, :contains_keyword_splat?]), NodeListField.new(:arguments)]
115
+ [FlagsField.new(:flags, [:contains_keywords?, :contains_keyword_splat?, :contains_splat?]), NodeListField.new(:arguments)]
116
116
  when :array_node
117
117
  [FlagsField.new(:flags, [:contains_splat?]), NodeListField.new(:elements), OptionalLocationField.new(:opening_loc), OptionalLocationField.new(:closing_loc)]
118
118
  when :array_pattern_node
@@ -150,9 +150,9 @@ module Prism
150
150
  when :capture_pattern_node
151
151
  [NodeField.new(:value), NodeField.new(:target), LocationField.new(:operator_loc)]
152
152
  when :case_match_node
153
- [OptionalNodeField.new(:predicate), NodeListField.new(:conditions), OptionalNodeField.new(:consequent), LocationField.new(:case_keyword_loc), LocationField.new(:end_keyword_loc)]
153
+ [OptionalNodeField.new(:predicate), NodeListField.new(:conditions), OptionalNodeField.new(:else_clause), LocationField.new(:case_keyword_loc), LocationField.new(:end_keyword_loc)]
154
154
  when :case_node
155
- [OptionalNodeField.new(:predicate), NodeListField.new(:conditions), OptionalNodeField.new(:consequent), LocationField.new(:case_keyword_loc), LocationField.new(:end_keyword_loc)]
155
+ [OptionalNodeField.new(:predicate), NodeListField.new(:conditions), OptionalNodeField.new(:else_clause), LocationField.new(:case_keyword_loc), LocationField.new(:end_keyword_loc)]
156
156
  when :class_node
157
157
  [ConstantListField.new(:locals), LocationField.new(:class_keyword_loc), NodeField.new(:constant_path), OptionalLocationField.new(:inheritance_operator_loc), OptionalNodeField.new(:superclass), OptionalNodeField.new(:body), LocationField.new(:end_keyword_loc), ConstantField.new(:name)]
158
158
  when :class_variable_and_write_node
@@ -236,7 +236,7 @@ module Prism
236
236
  when :hash_pattern_node
237
237
  [OptionalNodeField.new(:constant), NodeListField.new(:elements), OptionalNodeField.new(:rest), OptionalLocationField.new(:opening_loc), OptionalLocationField.new(:closing_loc)]
238
238
  when :if_node
239
- [OptionalLocationField.new(:if_keyword_loc), NodeField.new(:predicate), OptionalLocationField.new(:then_keyword_loc), OptionalNodeField.new(:statements), OptionalNodeField.new(:consequent), OptionalLocationField.new(:end_keyword_loc)]
239
+ [OptionalLocationField.new(:if_keyword_loc), NodeField.new(:predicate), OptionalLocationField.new(:then_keyword_loc), OptionalNodeField.new(:statements), OptionalNodeField.new(:subsequent), OptionalLocationField.new(:end_keyword_loc)]
240
240
  when :imaginary_node
241
241
  [NodeField.new(:numeric)]
242
242
  when :implicit_node
@@ -360,13 +360,13 @@ module Prism
360
360
  when :rescue_modifier_node
361
361
  [NodeField.new(:expression), LocationField.new(:keyword_loc), NodeField.new(:rescue_expression)]
362
362
  when :rescue_node
363
- [LocationField.new(:keyword_loc), NodeListField.new(:exceptions), OptionalLocationField.new(:operator_loc), OptionalNodeField.new(:reference), OptionalNodeField.new(:statements), OptionalNodeField.new(:consequent)]
363
+ [LocationField.new(:keyword_loc), NodeListField.new(:exceptions), OptionalLocationField.new(:operator_loc), OptionalNodeField.new(:reference), OptionalNodeField.new(:statements), OptionalNodeField.new(:subsequent)]
364
364
  when :rest_parameter_node
365
365
  [FlagsField.new(:flags, [:repeated_parameter?]), OptionalConstantField.new(:name), OptionalLocationField.new(:name_loc), LocationField.new(:operator_loc)]
366
366
  when :retry_node
367
367
  []
368
368
  when :return_node
369
- [FlagsField.new(:flags, [:redundant?]), LocationField.new(:keyword_loc), OptionalNodeField.new(:arguments)]
369
+ [LocationField.new(:keyword_loc), OptionalNodeField.new(:arguments)]
370
370
  when :self_node
371
371
  []
372
372
  when :shareable_constant_node
@@ -394,7 +394,7 @@ module Prism
394
394
  when :undef_node
395
395
  [NodeListField.new(:names), LocationField.new(:keyword_loc)]
396
396
  when :unless_node
397
- [LocationField.new(:keyword_loc), NodeField.new(:predicate), OptionalLocationField.new(:then_keyword_loc), OptionalNodeField.new(:statements), OptionalNodeField.new(:consequent), OptionalLocationField.new(:end_keyword_loc)]
397
+ [LocationField.new(:keyword_loc), NodeField.new(:predicate), OptionalLocationField.new(:then_keyword_loc), OptionalNodeField.new(:statements), OptionalNodeField.new(:else_clause), OptionalLocationField.new(:end_keyword_loc)]
398
398
  when :until_node
399
399
  [FlagsField.new(:flags, [:begin_modifier?]), LocationField.new(:keyword_loc), OptionalLocationField.new(:closing_loc), NodeField.new(:predicate), OptionalNodeField.new(:statements)]
400
400
  when :when_node