Skip to content

Commit a9277bc

Browse files
committed
Unified: Only translate conditional compilation blocks to if expressions in statement context
1 parent 142184d commit a9277bc

26 files changed

Lines changed: 191 additions & 257 deletions

‎unified/extractor/ast_types.yml‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ supertypes:
6868
- do_while_stmt
6969
- defer_stmt
7070
- labeled_stmt
71-
- associated_type_declaration
72-
- initializer_declaration
7371
callable:
7472
subtypes:
7573
- top_level
@@ -95,7 +93,6 @@ supertypes:
9593
- class_like_declaration
9694
- type_alias_declaration
9795
- associated_type_declaration
98-
- if_expr # For conditional compilation
9996
- unsupported_node
10097
- unhandled_node
10198
fields:

‎unified/extractor/src/languages/swift/swift.rs‎

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ struct SwiftContext {
3838
/// True while translating a pattern. Optional chaining in this context is
3939
/// represented as an `Optional.some` call rather than being unwrapped.
4040
in_pattern: bool,
41+
/// True when a conditional compilation block should be translated into an
42+
/// if expression.
43+
conditional_compilation_as_expr: bool,
4144
/// When iterating over the clauses of a conditional compilation block, this
4245
/// holds the tail of the clauses that have already been translated.
4346
conditional_compilation_tail: Option<yeast::OutputId>,
@@ -67,29 +70,11 @@ fn implicit_parameterless_initializer(
6770
ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>,
6871
members: &[yeast::OutputId],
6972
) -> Option<yeast::OutputId> {
70-
// Search for an initializer while recursing into nodes for conditional
71-
// compilation blocks.
72-
fn find_initializer(ast: &yeast::OutputAst, id: yeast::OutputId) -> Option<yeast::OutputId> {
73-
let node = ast.get_node(id)?;
74-
match node.kind_name() {
75-
"constructor_declaration" => Some(id),
76-
name => {
77-
let fields: &[&str] = match name {
78-
"if_expr" => &["then", "else"], // look into conditional compilation
79-
"block" => &["stmt"], // look into blocks in branches
80-
_ => &[],
81-
};
82-
fields.iter().find_map(|field| {
83-
node.field_children(ast.field_id_for_name(field)?)
84-
.iter()
85-
.find_map(|child| find_initializer(ast, *child))
86-
})
87-
}
88-
}
89-
}
90-
let has_explicit_initializer = members
91-
.iter()
92-
.any(|member| find_initializer(ctx.output, *member).is_some());
73+
let has_explicit_initializer = members.iter().any(|member| {
74+
ctx.output
75+
.get_node(*member)
76+
.is_some_and(|node| node.kind_name() == "constructor_declaration")
77+
});
9378
(!has_explicit_initializer).then(|| {
9479
tree!((constructor_declaration
9580
modifier: (modifier "generated")
@@ -174,6 +159,14 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
174159
// but a single wrapped `variableDecl` can translate to *several*
175160
// declarations (`let x = 1, y = 2`), so the wrapped node is captured with
176161
// `_*` and the result annotated `stmt*` to splice all of them.
162+
rule!(
163+
(codeBlockItem item: (ifConfigDecl) @@item)
164+
=>
165+
stmt* {
166+
ctx.conditional_compilation_as_expr = true;
167+
ctx.translate(item)?
168+
}
169+
),
177170
rule!((codeBlockItem item: _* @item) => stmt* { item }),
178171
// ---- Literals ----
179172
// swift-syntax does not distinguish the lexical integer/string forms
@@ -897,25 +890,33 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
897890
=>
898891
(parameter pattern: (identifier #{name}))
899892
),
900-
// ---- Conditioal compilation blocks ----
893+
// ---- Conditional compilation blocks ----
901894
// Conditional compilation blocks (`#if … #elseif … #else … #endif`) are
902895
// represented with a `ifConfigDecl` node for the entire block and an
903-
// `ifConfigClause` for each branch. We translate them into nested
904-
// `if_expr` nodes.
896+
// `ifConfigClause` for each branch.
905897

906-
// When a conditional compilation block contains a switch case it
907-
// appears within a `switch` -- we do not support this yet.
898+
// When a conditional compilation block is not in a context where it
899+
// should be translated into an if expression we simply extract the
900+
// first branch (for now).
908901
rule!(
909-
(ifConfigDecl clauses: (ifConfigClause elements: (switchCase)))
902+
(ifConfigDecl
903+
clauses: (ifConfigClause elements: _* @items)
904+
clauses: _* @@rest)
905+
where !ctx.conditional_compilation_as_expr
910906
=>
911-
(unsupported_node)
907+
_* { items }
912908
),
913909
// A conditional compilation block is translated into `if_expr` nodes
914910
// with branches occurring nested within the else branch.
915911
rule!(
916912
(ifConfigDecl clauses: _* @@clauses) @@declaration
917913
=>
918914
expr {
915+
// Revert `conditional_compilation_as_expr` before processing
916+
// clauses. Note that if a clause contains a nested conditional
917+
// compilation block, then that block will be wrapped in another
918+
// `codeBlockItem` which will flip this back to `true`.
919+
ctx.conditional_compilation_as_expr = false;
919920
ctx.conditional_compilation_tail = None;
920921
for clause in clauses.into_iter().rev() {
921922
ctx.conditional_compilation_tail = ctx.translate(clause)?.into_iter().next();

‎unified/extractor/tests/corpus/swift/conditional-compilation/conditional-compilation-in-attributes.output‎

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,14 @@ sourceFile
9898

9999
top_level source="⟨body⟩"
100100
body:
101-
block source="⟨stmt⟩\n\n⟨stmt⟩"
101+
block source="⟨stmt⟩\n\n#if DEBUG\n ⟨stmt⟩"
102102
stmt:
103103
function_declaration source="#if DEBUG\n @available(*, deprecated)\n#endif\nfunc ⟨name_node⟩() ⟨body⟩"
104104
name_node: identifier "f" source="f"
105105
body: block "{}" source="{}"
106-
variable_declaration source="⟨modifier⟩\n⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩"
106+
variable_declaration source="⟨modifier⟩\n#endif\n⟨modifier⟩ ⟨pattern⟩ = ⟨value⟩"
107107
modifier:
108108
modifier "let" source="let"
109-
if_expr source="#if ⟨condition⟩\n ⟨then⟩\n#endif" <-- ERROR: The field variable_declaration.modifier should contain modifier, but got if_expr
110-
modifier: modifier "conditional_compilation" source=""
111-
condition: identifier "DEBUG" source="DEBUG"
112-
then:
113-
block source="⟨stmt⟩"
114-
stmt: modifier "@available(*, deprecated)" source="@available(*, deprecated)" <-- ERROR: The field block.stmt should contain stmt, but got modifier
109+
modifier "@available(*, deprecated)" source="@available(*, deprecated)"
115110
pattern: identifier "x" source="x"
116111
value: int_literal "1" source="1"

‎unified/extractor/tests/corpus/swift/conditional-compilation/conditional-compilation-in-class-body.output‎

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,17 @@ top_level source="⟨body⟩"
7878
body:
7979
block source="⟨stmt⟩"
8080
stmt:
81-
class_like_declaration source="⟨modifier⟩ ⟨name_node⟩ {\n ⟨member⟩\n}"
81+
class_like_declaration source="⟨modifier⟩ ⟨name_node⟩ {\n #if DEBUG\n ⟨member⟩\n ⟨member⟩\n #endif\n}"
8282
modifier: modifier "class" source="class"
8383
name_node: identifier "C" source="C"
8484
member:
85-
if_expr source="#if ⟨condition⟩\n ⟨then⟩\n #endif"
86-
modifier: modifier "conditional_compilation" source=""
87-
condition: identifier "DEBUG" source="DEBUG"
88-
then:
89-
block source="⟨stmt⟩\n ⟨stmt⟩"
90-
stmt:
91-
constructor_declaration source="⟨name_node⟩(⟨parameter⟩) ⟨body⟩"
92-
name_node: identifier "init" source="init"
93-
parameter:
94-
parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩"
95-
external_name_node: identifier "x" source="x"
96-
type: identifier "Int" source="Int"
97-
pattern: identifier "x" source="x"
98-
body: block "{}" source="{}"
99-
destructor_declaration source="deinit ⟨body⟩"
100-
body: block "{}" source="{}"
85+
constructor_declaration source="⟨name_node⟩(⟨parameter⟩) ⟨body⟩"
86+
name_node: identifier "init" source="init"
87+
parameter:
88+
parameter source="⟨external_name_node⟩⟨pattern⟩: ⟨type⟩"
89+
external_name_node: identifier "x" source="x"
90+
type: identifier "Int" source="Int"
91+
pattern: identifier "x" source="x"
92+
body: block "{}" source="{}"
93+
destructor_declaration source="deinit ⟨body⟩"
94+
body: block "{}" source="{}"

‎unified/extractor/tests/corpus/swift/conditional-compilation/conditional-compilation-in-switch-cases.output‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,19 @@ top_level source="⟨body⟩"
123123
body:
124124
block source="{\n ⟨stmt⟩\n}"
125125
stmt:
126-
switch_expr source="switch ⟨value⟩ {\n ⟨case⟩\n ⟨case⟩\n }"
126+
switch_expr source="switch ⟨value⟩ {\n #if DEBUG\n ⟨case⟩\n ⟨case⟩\n #endif\n ⟨case⟩\n }"
127127
value: identifier "x" source="x"
128128
case:
129-
unsupported_node "#if DEBUG\n case 0: break\n case 1: break\n #endif" source="#if DEBUG\n case 0: break\n case 1: break\n #endif" <-- ERROR: The field switch_expr.case should contain switch_case, but got unsupported_node
129+
switch_case source="case ⟨pattern⟩: ⟨body⟩"
130+
pattern: int_literal "0" source="0"
131+
body:
132+
block source="⟨stmt⟩"
133+
stmt: break_expr "break" source="break"
134+
switch_case source="case ⟨pattern⟩: ⟨body⟩"
135+
pattern: int_literal "1" source="1"
136+
body:
137+
block source="⟨stmt⟩"
138+
stmt: break_expr "break" source="break"
130139
switch_case source="default: ⟨body⟩"
131140
body:
132141
block source="⟨stmt⟩"

0 commit comments

Comments
 (0)