Skip to content

Commit

Permalink
Warn if an interpolated identifier is followed by -. (#1375)
Browse files Browse the repository at this point in the history
  • Loading branch information
floitsch authored Jan 24, 2023
1 parent 3cc98c1 commit 2e2d9dc
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 3 deletions.
24 changes: 22 additions & 2 deletions src/compiler/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2272,12 +2272,25 @@ Expression* Parser::parse_string_interpolate() {
ListBuilder<Expression*> expressions;

bool is_multiline = current_token() == Token::STRING_PART_MULTI_LINE;
bool last_interpolated_was_identifier = false;
auto last_identifier_range = Source::Range::invalid();
auto check_minus_after_identifier = [&](Symbol current_data) {
if (last_interpolated_was_identifier &&
current_data.c_str()[0] == '-' &&
is_identifier_part(current_data.c_str()[1])) {
diagnostics()->report_warning(last_identifier_range,
"Interpolated identifiers followed by '-' must be parenthesized");
}
};
Token::Kind end_token = is_multiline ? Token::STRING_END_MULTI_LINE : Token::STRING_END;
Token::Kind kind;
auto range = start;
do {
parts.add(NEW_NODE(LiteralString(current_token_data(), is_multiline), range));
Symbol current_data = current_token_data();
check_minus_after_identifier(current_data);
parts.add(NEW_NODE(LiteralString(current_data, is_multiline), range));
consume();
last_interpolated_was_identifier = false;
scan_interpolated_part();
// We just passed $.
LiteralString* format = null;
Expand All @@ -2300,6 +2313,8 @@ Expression* Parser::parse_string_interpolate() {
if (encountered_error) discard_buffered_scanner_states();
} else if (current_token() == Token::IDENTIFIER) {
expression = parse_identifier();
last_interpolated_was_identifier = true;
last_identifier_range = expression->range();
} else {
if (current_token() == Token::EOS || current_token() == Token::DEDENT) {
report_error("Incomplete string interpolation");
Expand All @@ -2316,6 +2331,7 @@ Expression* Parser::parse_string_interpolate() {
if (!was_parenthesized) {
while (true) {
if (scanner_peek() == '[') {
last_interpolated_was_identifier = false;
bool encountered_error;
expression = parse_postfix_index(expression, &encountered_error);
if (encountered_error) {
Expand All @@ -2333,6 +2349,8 @@ Expression* Parser::parse_string_interpolate() {
if (current_token() == Token::IDENTIFIER && is_current_token_attached()) {
Identifier* name = parse_identifier();
expression = NEW_NODE(Dot(expression, name), range);
last_interpolated_was_identifier = true;
last_identifier_range = range;
continue; // Try for another postfix.
} else {
report_error("Non-identifier member name");
Expand All @@ -2349,7 +2367,9 @@ Expression* Parser::parse_string_interpolate() {
range = current_range();
} while (kind != end_token);

parts.add(NEW_NODE(LiteralString(current_token_data(), is_multiline), range));
Symbol current_data = current_token_data();
check_minus_after_identifier(current_data);
parts.add(NEW_NODE(LiteralString(current_data, is_multiline), range));
consume();
return NEW_NODE(LiteralStringInterpolation(parts.build(), formats.build(), expressions.build()), start);
}
Expand Down
10 changes: 10 additions & 0 deletions tests/negative/gold/minus_interpolated_test.gold
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
tests/negative/minus_interpolated_test.toit:9:11: warning: Interpolated identifiers followed by '-' must be parenthesized
print "$foo-b" // Warning, since that would become a single identifier.
^~~
tests/negative/minus_interpolated_test.toit:10:11: warning: Interpolated identifiers followed by '-' must be parenthesized
print "$foo-3" // Same warning.
^~~
tests/negative/minus_interpolated_test.toit:12:3: error: Unresolved identifier: 'unresolved'
unresolved
^~~~~~~~~~
Compilation failed.
12 changes: 12 additions & 0 deletions tests/negative/minus_interpolated_test.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (C) 2023 Toitware ApS.
// Use of this source code is governed by a Zero-Clause BSD license that can
// be found in the tests/LICENSE file.
main:
foo := 499
bar := 42
print "$foo-" // OK because not followed by identifier character.
print "$foo-b" // Warning, since that would become a single identifier.
print "$foo-3" // Same warning.
print "$foo-$bar" // OK.
unresolved
2 changes: 1 addition & 1 deletion tools/make_crc.toit
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ main args:
Computes the $name checksum of the given \$data.
The \$data must be a string or byte array.
Returns the checksum as a$(width == 8 ? "n" : "") $width-bit integer.
Returns the checksum as a$(width == 8 ? "n" : "") $(width)-bit integer.
*/
$name_snake data -> int:
crc := Crc.$(endian)_endian $width --$polynomial_argument=$fields[2]$initial_string$xor_string
Expand Down

0 comments on commit 2e2d9dc

Please sign in to comment.