|
1 | 1 | use codeql_extractor::extractor::simple; |
2 | 2 | use yeast::{manual_rule, rule, tree, ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule}; |
3 | 3 |
|
4 | | -/// User context propagated from outer `property_binding` rules down to the |
5 | | -/// inner accessor-translation rules so that every `accessor_declaration` |
6 | | -/// emitted by an inner rule is born with the property's `name` (and |
7 | | -/// optionally its `type`) already set — no schema-invalid intermediate |
8 | | -/// state requiring post-hoc mutation. |
| 4 | +/// User context propagated from outer rules down to the inner rules that |
| 5 | +/// emit the corresponding output declarations, so that each emitted node |
| 6 | +/// is born with the outer information (name, type, modifiers, etc.) |
| 7 | +/// already set — no schema-invalid intermediate state requiring |
| 8 | +/// post-hoc mutation. |
9 | 9 | #[derive(Clone, Default)] |
10 | | -struct PropertyContext { |
11 | | - /// Identifier node for the property name, to be used as the |
12 | | - /// `accessor_declaration.name`. Set by the outer property_binding rule |
13 | | - /// before translating accessor children. |
| 10 | +struct SwiftContext { |
| 11 | + /// Identifier node for the property name. Set by the outer |
| 12 | + /// `property_binding` (computed accessors / willSet-didSet) rule |
| 13 | + /// before translating accessor children; read by |
| 14 | + /// `computed_getter`/`computed_setter`/`computed_modify`/ |
| 15 | + /// `willset_clause`/`didset_clause`. |
14 | 16 | property_name: Option<yeast::Id>, |
15 | | - /// Translated type node for the property type, to be used as the |
16 | | - /// `accessor_declaration.type`. Set by the outer property_binding rule |
17 | | - /// when present. |
| 17 | + /// Translated type node for the property type. Set by the outer |
| 18 | + /// `property_binding` rule (computed accessors variant) when |
| 19 | + /// present; read by `computed_*` rules. |
18 | 20 | property_type: Option<yeast::Id>, |
| 21 | + /// Default-value expression for the next translated `parameter`. Set |
| 22 | + /// by the outer `function_parameter` rule; read by the `parameter` |
| 23 | + /// rules. |
| 24 | + default_value: Option<yeast::Id>, |
19 | 25 | } |
20 | 26 |
|
21 | | -fn translation_rules() -> Vec<Rule<PropertyContext>> { |
| 27 | +fn translation_rules() -> Vec<Rule<SwiftContext>> { |
22 | 28 | vec![ |
23 | 29 | // ---- Top-level ---- |
24 | 30 | // Capture all top-level statements, including unnamed tokens like `nil`. |
@@ -358,47 +364,49 @@ fn translation_rules() -> Vec<Rule<PropertyContext>> { |
358 | 364 | body: (block stmt: {..body_stmts})) |
359 | 365 | ), |
360 | 366 | // Parameters are wrapped in function_parameter, which also carries |
361 | | - // optional default values. |
362 | | - rule!( |
| 367 | + // optional default values. Publishes the default value into `ctx` |
| 368 | + // before translating the inner `parameter` so the `parameter` |
| 369 | + // rules can include it as a `default:` field directly. |
| 370 | + manual_rule!( |
363 | 371 | (function_parameter parameter: @p default_value: _? @def) |
364 | | - => |
365 | | - {..{ |
366 | | - let p_id: usize = p.into(); |
367 | | - for &d in def.iter().rev() { |
368 | | - ctx.prepend_field(p_id, "default", d.into()); |
369 | | - } |
370 | | - vec![p_id] |
371 | | - }} |
| 372 | + { |
| 373 | + ctx.default_value = ctx.translate_opt(def)?; |
| 374 | + ctx.translate(p) |
| 375 | + } |
372 | 376 | ), |
373 | 377 | // Parameter with external name and type |
374 | 378 | rule!( |
375 | 379 | (parameter external_name: @ext name: @name) |
376 | 380 | => |
377 | 381 | (parameter |
378 | 382 | external_name: (identifier #{ext}) |
379 | | - pattern: (name_pattern identifier: (identifier #{name}))) |
| 383 | + pattern: (name_pattern identifier: (identifier #{name})) |
| 384 | + default: {..ctx.default_value}) |
380 | 385 | ), |
381 | 386 | rule!( |
382 | 387 | (parameter external_name: @ext name: @name type: @ty) |
383 | 388 | => |
384 | 389 | (parameter |
385 | 390 | external_name: (identifier #{ext}) |
386 | 391 | pattern: (name_pattern identifier: (identifier #{name})) |
387 | | - type: {ty}) |
| 392 | + type: {ty} |
| 393 | + default: {..ctx.default_value}) |
388 | 394 | ), |
389 | 395 | // Parameter with just name and type (no external name) |
390 | 396 | rule!( |
391 | 397 | (parameter name: @name) |
392 | 398 | => |
393 | 399 | (parameter |
394 | | - pattern: (name_pattern identifier: (identifier #{name}))) |
| 400 | + pattern: (name_pattern identifier: (identifier #{name})) |
| 401 | + default: {..ctx.default_value}) |
395 | 402 | ), |
396 | 403 | rule!( |
397 | 404 | (parameter name: @name type: @ty) |
398 | 405 | => |
399 | 406 | (parameter |
400 | 407 | pattern: (name_pattern identifier: (identifier #{name})) |
401 | | - type: {ty}) |
| 408 | + type: {ty} |
| 409 | + default: {..ctx.default_value}) |
402 | 410 | ), |
403 | 411 | // Reference to a function, f(x:y:z:). This is parsed as a call with a single argument with multiple reference_specifier labels. |
404 | 412 | // We don't want downstream QL to try to handle this as a call_expr with a weird argument, so explicitly mark it as unsupported for now. |
@@ -1017,7 +1025,7 @@ fn translation_rules() -> Vec<Rule<PropertyContext>> { |
1017 | 1025 |
|
1018 | 1026 | pub fn language_spec(desugared_ast_schema: &'static str) -> simple::LanguageSpec { |
1019 | 1027 | let ts_language: tree_sitter::Language = tree_sitter_swift::LANGUAGE.into(); |
1020 | | - let config = DesugaringConfig::<PropertyContext>::new() |
| 1028 | + let config = DesugaringConfig::<SwiftContext>::new() |
1021 | 1029 | .add_phase("translate", PhaseKind::OneShot, translation_rules()) |
1022 | 1030 | .with_output_node_types_yaml(desugared_ast_schema); |
1023 | 1031 | let desugarer = ConcreteDesugarer::new(ts_language.clone(), config) |
|
0 commit comments