Skip to content

Commit e15833a

Browse files
authored
Merge pull request #184 from AaronC81/parser-errors-in-constants
Don't crash Sord if a constant value doesn't parse
2 parents 200e7f1 + df968ff commit e15833a

File tree

3 files changed

+49
-16
lines changed

3 files changed

+49
-16
lines changed

.github/workflows/examples.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ jobs:
1919
- name: Run examples (RBI)
2020
run: bundle exec rake examples:seed[rbi]
2121
- name: Run examples (RBS)
22-
run: bundle exec rake examples:seed[rbs]
22+
run: bundle exec rake examples:reseed[rbs]

lib/sord/generator.rb

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -143,22 +143,29 @@ def add_constants(item)
143143
when :rbi
144144
# Parse so we can set up constant with correct heredoc syntax
145145
kwargs = {}
146-
value_node = Parser::CurrentRuby.parse(constant.value)
147-
loc = value_node.loc
148-
if loc.instance_of? Parser::Source::Map::Heredoc
149-
#
150-
# heredocs in Ruby come after the full expression is complete. e.g.,
151-
# puts(>>FOO)
152-
# bar
153-
# FOO
154-
#
155-
# so if we want to wrap them in a T.let, we need to parse out the expression vs the rest
156-
kwargs[:heredocs] = constant.value[loc.heredoc_body.begin_pos...loc.heredoc_end.end_pos]
157-
expression = loc.expression
158-
value = constant.value[expression.begin_pos...expression.end_pos]
159-
else
160-
value = constant.value
146+
147+
value = constant.value
148+
begin
149+
value_node = Parser::CurrentRuby.parse(constant.value)
150+
loc = value_node.loc
151+
if loc.instance_of? Parser::Source::Map::Heredoc
152+
#
153+
# heredocs in Ruby come after the full expression is complete. e.g.,
154+
# puts(>>FOO)
155+
# bar
156+
# FOO
157+
#
158+
# so if we want to wrap them in a T.let, we need to parse out the expression vs the rest
159+
kwargs[:heredocs] = constant.value[loc.heredoc_body.begin_pos...loc.heredoc_end.end_pos]
160+
expression = loc.expression
161+
value = constant.value[expression.begin_pos...expression.end_pos]
162+
end
163+
164+
rescue Parser::SyntaxError => e
165+
# Emit a warning, since this may cause a syntax error when parsing the RBI
166+
Logging.warn("syntax error on constant value: #{e}", constant)
161167
end
168+
162169
@current_object.create_constant(constant_name, value: "T.let(#{value}, T.untyped)", **kwargs) do |c|
163170
c.add_comments(constant.docstring.all.split("\n"))
164171
end

spec/generator_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,32 @@ class A
11511151
RUBY
11521152
end
11531153

1154+
it 'gracefully handles malformed expressions as constants' do
1155+
# This isn't something we expect to happen very often, but we at least want to know Sord itself
1156+
# doesn't blow up.
1157+
1158+
# This string is valid Ruby syntax, but `parser` rejects it intentionally
1159+
# See https://github.com/whitequark/parser/issues/283
1160+
YARD.parse_string(<<-RUBY)
1161+
class A
1162+
MALFORMED = "\\xFF"
1163+
end
1164+
RUBY
1165+
1166+
expect(rbi_gen.generate.strip).to eq fix_heredoc(<<-RUBY)
1167+
# typed: strong
1168+
class A
1169+
MALFORMED = T.let("\\xFF", T.untyped)
1170+
end
1171+
RUBY
1172+
1173+
expect(rbs_gen.generate.strip).to eq fix_heredoc(<<-RUBY)
1174+
class A
1175+
MALFORMED: untyped
1176+
end
1177+
RUBY
1178+
end
1179+
11541180
it 'does not generate constants from included classes' do
11551181
YARD.parse_string(<<-RUBY)
11561182
class A

0 commit comments

Comments
 (0)