Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow different characters after certain operators #67

Merged
merged 2 commits into from
Nov 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion corpus/expressions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -682,12 +682,16 @@ SignalProducer<(), CarthageError>.empty
Suppressing the syntactic significance of a newline
===

let _ = (1 + 2)
let _ = (1+2)
/ 3

let additionIsSane = (2 + 2)
== 4

let two = 2
+ 2
- 2

---

(source_file
Expand All @@ -710,4 +714,13 @@ let additionIsSane = (2 + 2)
(additive_expression
(integer_literal)
(integer_literal)))
(integer_literal)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(additive_expression
(additive_expression
(integer_literal)
(integer_literal))
(integer_literal))))
14 changes: 11 additions & 3 deletions grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,15 @@ module.exports = grammar({
$._nil_coalescing_operator,
$._equal_sign,
$._eq_eq,
$._plus_then_ws, // + symbol with whitespace after it
$._minus_then_ws, // - symbol with whitespace after it
$._throws_keyword,
$._rethrows_keyword,
$.default_keyword,
$._where_keyword,
$._else,
$._catch,
$._as,
$._as_quest,
$._as_bang,
],
Expand Down Expand Up @@ -834,11 +837,12 @@ module.exports = grammar({

_is_operator: ($) => "is",

_additive_operator: ($) => choice("+", "-"),
_additive_operator: ($) =>
choice($._plus_then_ws, $._minus_then_ws, "+", "-"),

_multiplicative_operator: ($) => choice("*", "/", "%"),

_as_operator: ($) => choice("as", $._as_quest, $._as_bang),
_as_operator: ($) => choice($._as, $._as_quest, $._as_bang),

_prefix_unary_operator: ($) =>
prec.right(
Expand Down Expand Up @@ -1634,7 +1638,11 @@ function generate_case_pattern($, allows_binding, force) {
function generate_type_casting_pattern($, allows_binding) {
return choice(
seq("is", $._type),
seq(generate_pattern_matching_rule($, allows_binding, false), "as", $._type)
seq(
generate_pattern_matching_rule($, allows_binding, false),
$._as,
$._type
)
);
}

Expand Down
2 changes: 0 additions & 2 deletions script-data/known_failures.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@ firefox-ios/Shared/Functions.swift
RxSwift/RxExample/RxExample/Examples/GitHubSearchRepositories/GitHubSearchRepositories.swift
RxSwift/Rx.playground/Pages/Transforming_Operators.xcplaygroundpage/Contents.swift
SwiftLint/Source/SwiftLintFramework/Extensions/String+SwiftLint.swift
SwiftLint/Source/SwiftLintFramework/Rules/Metrics/NestingRuleExamples.swift
SwiftLint/Source/SwiftLintFramework/Rules/Style/StatementPositionRule.swift
16 changes: 11 additions & 5 deletions scripts/top-repos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,16 @@ while read line ; do
cd $tmpdir
checkout $line
cd $parser_dir
validate $line &
pids+=($!)
if [ -z "$1" ]; then
validate $line &
pids+=($!)
else
validate $line
fi
done <<<"$repos"

for pid in "${pids[@]}" ; do
wait $pid
done
if [ -z "$1" ]; then
for pid in "${pids[@]}" ; do
wait $pid
done
fi
63 changes: 58 additions & 5 deletions src/scanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@ enum TokenType {
NIL_COALESCING_OPERATOR,
EQUAL_SIGN,
EQ_EQ,
PLUS_THEN_WS,
MINUS_THEN_WS,
THROWS_KEYWORD,
RETHROWS_KEYWORD,
DEFAULT_KEYWORD,
WHERE_KEYWORD,
ELSE_KEYWORD,
CATCH_KEYWORD,
AS_KEYWORD,
AS_QUEST,
AS_BANG
};

#define CROSS_SEMI_OPERATOR_COUNT 17
#define CROSS_SEMI_OPERATOR_COUNT 20

const char* CROSS_SEMI_OPERATORS[CROSS_SEMI_OPERATOR_COUNT] = {
"->",
Expand All @@ -38,16 +41,49 @@ const char* CROSS_SEMI_OPERATORS[CROSS_SEMI_OPERATOR_COUNT] = {
"??",
"=",
"==",
"+",
"-",
"throws",
"rethrows",
"default",
"where",
"else",
"catch",
"as",
"as?",
"as!"
};

enum IllegalTerminatorGroup {
ALPHANUMERIC,
OPERATOR_SYMBOLS,
OPERATOR_OR_DOT,
NON_WHITESPACE
};

const enum IllegalTerminatorGroup CROSS_SEMI_ILLEGAL_TERMINATORS[CROSS_SEMI_OPERATOR_COUNT] = {
OPERATOR_SYMBOLS, // ->
OPERATOR_OR_DOT, // .
OPERATOR_OR_DOT, // ...
OPERATOR_OR_DOT, // ..<
OPERATOR_SYMBOLS, // &&
OPERATOR_SYMBOLS, // ||
OPERATOR_SYMBOLS, // ??
OPERATOR_SYMBOLS, // =
OPERATOR_SYMBOLS, // ==
NON_WHITESPACE, // +
NON_WHITESPACE, // -
ALPHANUMERIC, // throws
ALPHANUMERIC, // rethrows
ALPHANUMERIC, // default
ALPHANUMERIC, // where
ALPHANUMERIC, // else
ALPHANUMERIC, // catch
ALPHANUMERIC, // as
OPERATOR_SYMBOLS, // as?
OPERATOR_SYMBOLS // as!
};

const enum TokenType CROSS_SEMI_SYMBOLS[CROSS_SEMI_OPERATOR_COUNT] = {
ARROW_OPERATOR,
DOT_OPERATOR,
Expand All @@ -58,18 +94,21 @@ const enum TokenType CROSS_SEMI_SYMBOLS[CROSS_SEMI_OPERATOR_COUNT] = {
NIL_COALESCING_OPERATOR,
EQUAL_SIGN,
EQ_EQ,
PLUS_THEN_WS,
MINUS_THEN_WS,
THROWS_KEYWORD,
RETHROWS_KEYWORD,
DEFAULT_KEYWORD,
WHERE_KEYWORD,
ELSE_KEYWORD,
CATCH_KEYWORD,
AS_KEYWORD,
AS_QUEST,
AS_BANG
};

#define NON_CONSUMING_CROSS_SEMI_CHAR_COUNT 3
const char NON_CONSUMING_CROSS_SEMI_CHARS[CROSS_SEMI_OPERATOR_COUNT] = { '?', ':', '{' };
const char NON_CONSUMING_CROSS_SEMI_CHARS[NON_CONSUMING_CROSS_SEMI_CHAR_COUNT] = { '?', ':', '{' };

/**
* All possible results of having performed some sort of parsing.
Expand Down Expand Up @@ -175,6 +214,8 @@ static bool eat_operators(
}

if (CROSS_SEMI_OPERATORS[op_idx][str_idx] == '\0') {
// Make sure that the operator is allowed to have the next character as its lookahead.
enum IllegalTerminatorGroup illegal_terminators = CROSS_SEMI_ILLEGAL_TERMINATORS[op_idx];
switch (lexer->lookahead) {
// See "Operators":
// https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418
Expand All @@ -192,10 +233,22 @@ static bool eat_operators(
case '^':
case '?':
case '~':
break;
if (illegal_terminators == OPERATOR_SYMBOLS) {
break;
} // Otherwise, intentionally fall through to the OPERATOR_OR_DOT case
case '.':
if (illegal_terminators == OPERATOR_OR_DOT) {
break;
} // Otherwise, fall through to DEFAULT which checks its groups directly
default:
// Only match if this is the _end_ of an operator. If it's possible for a custom
// operator to continue from here, don't treat it as a full match.
if (iswalnum(lexer->lookahead) && illegal_terminators == ALPHANUMERIC) {
break;
}

if (!iswspace(lexer->lookahead) && illegal_terminators == NON_WHITESPACE) {
break;
}

full_match = op_idx;
if (mark_end) {
lexer->mark_end(lexer);
Expand Down