Skip to content

Commit 8cc4eda

Browse files
authored
Merge pull request #3978 from ruby/continuable
Refine continuable? with algorithm in C
2 parents c8fd89e + c28810f commit 8cc4eda

19 files changed

Lines changed: 365 additions & 140 deletions

File tree

docs/serialization.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ The header is structured like the following table:
106106
| error* | errors |
107107
| varuint | number of warnings |
108108
| warning* | warnings |
109+
| `1` | `1` if the source is continuable (incomplete but could become valid with more input), `0` otherwise |
109110
| `4` | content pool offset |
110111
| varuint | content pool size |
111112

ext/prism/extension.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,10 +641,11 @@ parse_result_create(VALUE class, const pm_parser_t *parser, VALUE value, rb_enco
641641
parser_data_loc(parser, source, freeze),
642642
parser_errors(parser, encoding, source, freeze),
643643
parser_warnings(parser, encoding, source, freeze),
644+
parser->continuable ? Qtrue : Qfalse,
644645
source
645646
};
646647

647-
return rb_class_new_instance_freeze(7, result_argv, class, freeze);
648+
return rb_class_new_instance_freeze(8, result_argv, class, freeze);
648649
}
649650

650651
/******************************************************************************/

include/prism/parser.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,14 @@ struct pm_parser {
895895
/** Whether or not we're currently recovering from a syntax error. */
896896
bool recovering;
897897

898+
/**
899+
* Whether or not the source being parsed could become valid if more input
900+
* were appended. This is set to false when the parser encounters a token
901+
* that is definitively wrong (e.g., a stray `end` or `]`) as opposed to
902+
* merely incomplete.
903+
*/
904+
bool continuable;
905+
898906
/**
899907
* This is very specialized behavior for when you want to parse in a context
900908
* that does not respect encoding comments. Its main use case is translating

java/org/ruby_lang/prism/ParseResult.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,16 @@ public Warning(Nodes.WarningType type, String message, Nodes.Location location,
6969
public final Nodes.Location dataLocation;
7070
public final Error[] errors;
7171
public final Warning[] warnings;
72+
public final boolean continuable;
7273
public final Nodes.Source source;
7374

74-
public ParseResult(Nodes.Node value, MagicComment[] magicComments, Nodes.Location dataLocation, Error[] errors, Warning[] warnings, Nodes.Source source) {
75+
public ParseResult(Nodes.Node value, MagicComment[] magicComments, Nodes.Location dataLocation, Error[] errors, Warning[] warnings, boolean continuable, Nodes.Source source) {
7576
this.value = value;
7677
this.magicComments = magicComments;
7778
this.dataLocation = dataLocation;
7879
this.errors = errors;
7980
this.warnings = warnings;
81+
this.continuable = continuable;
8082
this.source = source;
8183
}
8284
}

lib/prism/lex_compat.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ class Result < Prism::Result
4343

4444
# Create a new lex compat result object with the given values.
4545
#--
46-
#: (Array[lex_compat_token] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, Source source) -> void
47-
def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
46+
#: (Array[lex_compat_token] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
47+
def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
4848
@value = value
49-
super(comments, magic_comments, data_loc, errors, warnings, source)
49+
super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
5050
end
5151

5252
# Implement the hash pattern matching interface for Result.
@@ -825,7 +825,7 @@ def result
825825

826826
tokens = post_process_tokens(tokens, source, result.data_loc, bom, eof_token)
827827

828-
Result.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, source)
828+
Result.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, result.continuable?, source)
829829
end
830830

831831
private

lib/prism/parse_result.rb

Lines changed: 14 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -898,13 +898,14 @@ class Result
898898

899899
# Create a new result object with the given values.
900900
#--
901-
#: (Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, Source source) -> void
902-
def initialize(comments, magic_comments, data_loc, errors, warnings, source)
901+
#: (Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
902+
def initialize(comments, magic_comments, data_loc, errors, warnings, continuable, source)
903903
@comments = comments
904904
@magic_comments = magic_comments
905905
@data_loc = data_loc
906906
@errors = errors
907907
@warnings = warnings
908+
@continuable = continuable
908909
@source = source
909910
end
910911

@@ -961,54 +962,8 @@ def failure?
961962
#--
962963
#: () -> bool
963964
def continuable?
964-
return false if errors.empty?
965-
966-
offset = source.source.bytesize
967-
errors.all? { |error| CONTINUABLE.include?(error.type) || error.location.start_offset == offset }
968-
end
969-
970-
# The set of error types whose location the parser places at the opening
971-
# token of an unclosed construct rather than at the end of the source. These
972-
# errors always indicate incomplete input regardless of their byte position,
973-
# so they are checked by type rather than by location.
974-
#--
975-
#: Array[Symbol]
976-
CONTINUABLE = %i[
977-
begin_term
978-
begin_upcase_term
979-
block_param_pipe_term
980-
block_term_brace
981-
block_term_end
982-
case_missing_conditions
983-
case_term
984-
class_term
985-
conditional_term
986-
conditional_term_else
987-
def_term
988-
embdoc_term
989-
end_upcase_term
990-
for_term
991-
hash_term
992-
heredoc_term
993-
lambda_term_brace
994-
lambda_term_end
995-
list_i_lower_term
996-
list_i_upper_term
997-
list_w_lower_term
998-
list_w_upper_term
999-
module_term
1000-
regexp_term
1001-
rescue_term
1002-
string_interpolated_term
1003-
string_literal_eof
1004-
symbol_term_dynamic
1005-
symbol_term_interpolated
1006-
until_term
1007-
while_term
1008-
xstring_term
1009-
].freeze
1010-
1011-
private_constant :CONTINUABLE
965+
@continuable
966+
end
1012967

1013968
# Create a code units cache for the given encoding.
1014969
#--
@@ -1033,10 +988,10 @@ class ParseResult < Result
1033988

1034989
# Create a new parse result object with the given values.
1035990
#--
1036-
#: (ProgramNode value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, Source source) -> void
1037-
def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
991+
#: (ProgramNode value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
992+
def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
1038993
@value = value
1039-
super(comments, magic_comments, data_loc, errors, warnings, source)
994+
super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
1040995
end
1041996

1042997
# Implement the hash pattern matching interface for ParseResult.
@@ -1077,10 +1032,10 @@ class LexResult < Result
10771032

10781033
# Create a new lex result object with the given values.
10791034
#--
1080-
#: (Array[[Token, Integer]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, Source source) -> void
1081-
def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
1035+
#: (Array[[Token, Integer]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
1036+
def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
10821037
@value = value
1083-
super(comments, magic_comments, data_loc, errors, warnings, source)
1038+
super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
10841039
end
10851040

10861041
# Implement the hash pattern matching interface for LexResult.
@@ -1099,10 +1054,10 @@ class ParseLexResult < Result
10991054

11001055
# Create a new parse lex result object with the given values.
11011056
#--
1102-
#: ([ProgramNode, Array[[Token, Integer]]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, Source source) -> void
1103-
def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
1057+
#: ([ProgramNode, Array[[Token, Integer]]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
1058+
def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source)
11041059
@value = value
1105-
super(comments, magic_comments, data_loc, errors, warnings, source)
1060+
super(comments, magic_comments, data_loc, errors, warnings, continuable, source)
11061061
end
11071062

11081063
# Implement the hash pattern matching interface for ParseLexResult.

rbi/generated/prism/lex_compat.rbi

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rbi/generated/prism/parse_result.rbi

Lines changed: 8 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rbi/generated/prism/serialize.rbi

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sig/generated/prism/lex_compat.rbs

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)