Skip to content

Commit 618224a

Browse files
committed
[Feature #20925] Support leading logical operators
1 parent 10f7484 commit 618224a

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

parse.y

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6985,6 +6985,16 @@ is_identchar(struct parser_params *p, const char *ptr, const char *MAYBE_UNUSED(
69856985
return rb_enc_isalnum((unsigned char)*ptr, enc) || *ptr == '_' || !ISASCII(*ptr);
69866986
}
69876987

6988+
static inline bool
6989+
peek_word_at(struct parser_params *p, const char *str, size_t len, int at)
6990+
{
6991+
const char *ptr = p->lex.pcur + at;
6992+
if (lex_eol_ptr_n_p(p, ptr, len-1)) return false;
6993+
if (memcmp(ptr, str, len)) return false;
6994+
if (lex_eol_ptr_n_p(p, ptr, len)) return true;
6995+
return !is_identchar(p, ptr+len, p->lex.pend, p->enc);
6996+
}
6997+
69886998
static inline int
69896999
parser_is_identchar(struct parser_params *p)
69907000
{
@@ -10556,7 +10566,24 @@ parser_yylex(struct parser_params *p)
1055610566
token_flush(p);
1055710567
}
1055810568
goto retry;
10569+
case 'a':
10570+
if (peek_word_at(p, "nd", 2, 0)) goto leading_logical;
10571+
goto bol;
10572+
case 'o':
10573+
if (peek_word_at(p, "r", 1, 0)) goto leading_logical;
10574+
goto bol;
10575+
case '|':
10576+
if (peek(p, '|')) goto leading_logical;
10577+
goto bol;
1055910578
case '&':
10579+
if (peek(p, '&')) {
10580+
leading_logical:
10581+
pushback(p, c);
10582+
dispatch_delayed_token(p, tIGNORED_NL);
10583+
cmd_state = FALSE;
10584+
goto retry;
10585+
}
10586+
/* fall through */
1056010587
case '.': {
1056110588
dispatch_delayed_token(p, tIGNORED_NL);
1056210589
if (peek(p, '.') == (c == '&')) {
@@ -10565,6 +10592,7 @@ parser_yylex(struct parser_params *p)
1056510592
goto retry;
1056610593
}
1056710594
}
10595+
bol:
1056810596
default:
1056910597
p->ruby_sourceline--;
1057010598
p->lex.nextline = p->lex.lastline;

test/ruby/test_syntax.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,56 @@ def test_fluent_dot
12591259
assert_valid_syntax("a #\n#\n&.foo\n")
12601260
end
12611261

1262+
def test_fluent_and
1263+
omit if /\+PRISM\b/ =~ RUBY_DESCRIPTION
1264+
1265+
assert_valid_syntax("a\n" "&& foo")
1266+
assert_valid_syntax("a\n" "and foo")
1267+
1268+
assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
1269+
begin;
1270+
a = true
1271+
if a
1272+
&& (a = :ok; true)
1273+
a
1274+
end
1275+
end;
1276+
1277+
assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
1278+
begin;
1279+
a = true
1280+
if a
1281+
and (a = :ok; true)
1282+
a
1283+
end
1284+
end;
1285+
end
1286+
1287+
def test_fluent_or
1288+
omit if /\+PRISM\b/ =~ RUBY_DESCRIPTION
1289+
1290+
assert_valid_syntax("a\n" "|| foo")
1291+
assert_valid_syntax("a\n" "or foo")
1292+
1293+
assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
1294+
begin;
1295+
a = false
1296+
if a
1297+
|| (a = :ok; true)
1298+
a
1299+
end
1300+
end;
1301+
1302+
assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
1303+
begin;
1304+
a = false
1305+
if a
1306+
or (a = :ok; true)
1307+
a
1308+
end
1309+
end;
1310+
end
1311+
12621312
def test_safe_call_in_massign_lhs
12631313
assert_syntax_error("*a&.x=0", /multiple assignment destination/)
12641314
assert_syntax_error("a&.x,=0", /multiple assignment destination/)

0 commit comments

Comments
 (0)