mirror of
https://github.com/github/codeql.git
synced 2026-06-25 22:57:01 +02:00
Merge pull request #22016 from asgerf/commonast-rebased5
Unified/swift: new AST spec and Swift mappings
This commit is contained in:
@@ -44,8 +44,19 @@ pub fn query(input: TokenStream) -> TokenStream {
|
||||
/// {expr} - embed a Rust expression returning Id
|
||||
/// {..expr} - splice an iterable of Id (in child/field position)
|
||||
/// field: {..expr} - splice into a named field
|
||||
/// {expr}.map(p -> tpl) - apply tpl to each element; splice result
|
||||
/// {expr}.reduce_left(f -> init, acc, e -> fold)
|
||||
/// - fold with per-element init; splice 0 or 1 result
|
||||
/// ```
|
||||
///
|
||||
/// Chain syntax after `{expr}` or `{..expr}`:
|
||||
/// - `.map(param -> template)` — one output node per input element.
|
||||
/// - `.reduce_left(first -> init, acc, elem -> fold)` — fold left; the first
|
||||
/// element is converted by `init`, subsequent elements are folded by `fold`
|
||||
/// with the accumulator bound to `acc`. An empty iterable yields nothing.
|
||||
/// - Chains always splice (the result is iterable).
|
||||
/// - Multiple chains can be chained, e.g. `.map(...).reduce_left(...)`.
|
||||
///
|
||||
/// Can be called with an explicit context or using the implicit context
|
||||
/// from an enclosing `rule!`:
|
||||
///
|
||||
|
||||
@@ -141,7 +141,12 @@ fn parse_query_fields(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
|
||||
// Parse the field's pattern. To support repetition like
|
||||
// `field: (kind)* @cap`, parse the atom first, then check for
|
||||
// a quantifier, and lastly handle a trailing `@capture`.
|
||||
let atom = parse_query_atom(tokens)?;
|
||||
// `field: @cap` is sugar for `field: _ @cap`.
|
||||
let atom = if peek_is_at(tokens) {
|
||||
quote! { yeast::query::QueryNode::Any { match_unnamed: true } }
|
||||
} else {
|
||||
parse_query_atom(tokens)?
|
||||
};
|
||||
if peek_is_repetition(tokens) {
|
||||
let rep = expect_repetition(tokens)?;
|
||||
let elem = quote! {
|
||||
@@ -259,6 +264,7 @@ fn parse_query_list(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
|
||||
yeast::query::QueryListElem::SingleNode(#node)
|
||||
},
|
||||
)?;
|
||||
let elem = maybe_wrap_list_capture(tokens, elem)?;
|
||||
elems.push(elem);
|
||||
continue;
|
||||
}
|
||||
@@ -276,6 +282,7 @@ fn parse_query_list(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
|
||||
yeast::query::QueryListElem::SingleNode(#node)
|
||||
},
|
||||
)?;
|
||||
let elem = maybe_wrap_list_capture(tokens, elem)?;
|
||||
elems.push(elem);
|
||||
continue;
|
||||
}
|
||||
@@ -389,8 +396,10 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result<TokenStre
|
||||
let expr = group.stream();
|
||||
return Ok(quote! {
|
||||
{
|
||||
let __value = yeast::YeastDisplay::yeast_to_string(&(#expr), &*#ctx.ast);
|
||||
#ctx.literal(#kind_str, &__value)
|
||||
let __expr = (#expr);
|
||||
let __value = yeast::YeastDisplay::yeast_to_string(&__expr, &*#ctx.ast);
|
||||
let __source_range = yeast::YeastSourceRange::yeast_source_range(&__expr, &*#ctx.ast);
|
||||
#ctx.literal_with_source_range(#kind_str, &__value, __source_range)
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -419,23 +428,35 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result<TokenStre
|
||||
);
|
||||
field_counter += 1;
|
||||
|
||||
// Check for field: {..expr} — splice a Vec<Id> into the field
|
||||
// Check for field: {..expr}.chain or field: {expr}.chain — splice a Vec<Id> into the field
|
||||
if peek_is_group(tokens, Delimiter::Brace) {
|
||||
let group_clone = tokens.clone().next().unwrap();
|
||||
if let TokenTree::Group(g) = &group_clone {
|
||||
let mut inner_check = g.stream().into_iter();
|
||||
let is_splice = matches!(inner_check.next(), Some(TokenTree::Punct(p)) if p.as_char() == '.')
|
||||
&& matches!(inner_check.next(), Some(TokenTree::Punct(p)) if p.as_char() == '.');
|
||||
if is_splice {
|
||||
// Determine if a chain (.map(..)) follows the `{}` group.
|
||||
let mut after = tokens.clone();
|
||||
after.next(); // skip the brace group
|
||||
let has_chain = matches!(after.peek(), Some(TokenTree::Punct(p)) if p.as_char() == '.');
|
||||
|
||||
if is_splice || has_chain {
|
||||
let group = expect_group(tokens, Delimiter::Brace)?;
|
||||
let mut inner = group.stream().into_iter().peekable();
|
||||
inner.next(); // consume first .
|
||||
inner.next(); // consume second .
|
||||
let expr: proc_macro2::TokenStream = inner.collect();
|
||||
let base: TokenStream = if is_splice {
|
||||
let mut inner = group.stream().into_iter().peekable();
|
||||
inner.next(); // consume first .
|
||||
inner.next(); // consume second .
|
||||
let expr: TokenStream = inner.collect();
|
||||
quote! {
|
||||
(#expr).into_iter().map(::std::convert::Into::<usize>::into)
|
||||
}
|
||||
} else {
|
||||
let expr = group.stream();
|
||||
quote! { (#expr).into_iter() }
|
||||
};
|
||||
let chained = parse_chain_suffix(tokens, ctx, base)?;
|
||||
stmts.push(quote! {
|
||||
let #temp: Vec<usize> = (#expr).into_iter()
|
||||
.map(::std::convert::Into::<usize>::into)
|
||||
.collect();
|
||||
let #temp: Vec<usize> = #chained.collect();
|
||||
});
|
||||
// An empty splice means the field is absent — skip it
|
||||
// entirely rather than emitting an empty named field.
|
||||
@@ -472,6 +493,98 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result<TokenStre
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a chain of `.method(args)` suffixes after a `{expr}` or `{..expr}`
|
||||
/// placeholder in tree templates. Currently supports:
|
||||
///
|
||||
/// ```text
|
||||
/// .map(param -> template) -- iterator map: produces Vec<usize>
|
||||
/// ```
|
||||
///
|
||||
/// The chain may be empty (returns `base` unchanged). Multiple chained calls
|
||||
/// are supported, e.g. `.map(p -> ...).map(q -> ...)`.
|
||||
///
|
||||
/// Each call expects the receiver to be an iterator. The `base` argument
|
||||
/// should therefore already be an iterator (use `.into_iter()` on it before
|
||||
/// calling this function).
|
||||
fn parse_chain_suffix(
|
||||
tokens: &mut Tokens,
|
||||
ctx: &Ident,
|
||||
base: TokenStream,
|
||||
) -> Result<TokenStream> {
|
||||
let mut current = base;
|
||||
while matches!(tokens.peek(), Some(TokenTree::Punct(p)) if p.as_char() == '.') {
|
||||
tokens.next(); // consume .
|
||||
let method = expect_ident(tokens, "expected method name after `.`")?;
|
||||
let method_str = method.to_string();
|
||||
let args_group = expect_group(tokens, Delimiter::Parenthesis)?;
|
||||
match method_str.as_str() {
|
||||
"map" => {
|
||||
let mut inner = args_group.stream().into_iter().peekable();
|
||||
let param = expect_ident(&mut inner, "expected lambda parameter name")?;
|
||||
expect_punct(&mut inner, '-', "expected `->` after lambda parameter")?;
|
||||
expect_punct(&mut inner, '>', "expected `->` after lambda parameter")?;
|
||||
let body = parse_direct_node(&mut inner, ctx)?;
|
||||
if let Some(tok) = inner.next() {
|
||||
return Err(syn::Error::new_spanned(
|
||||
tok,
|
||||
"unexpected token after lambda body",
|
||||
));
|
||||
}
|
||||
current = quote! {
|
||||
#current.map(|#param| #body)
|
||||
};
|
||||
}
|
||||
"reduce_left" => {
|
||||
// Syntax: reduce_left(first -> init_tpl, acc, elem -> fold_tpl)
|
||||
// - first -> init_tpl : converts the first element to the initial accumulator
|
||||
// - acc, elem -> fold_tpl : fold step (acc = current accumulator, elem = next element)
|
||||
// Empty iterator produces an empty iterator; non-empty produces a single-element iterator.
|
||||
let mut inner = args_group.stream().into_iter().peekable();
|
||||
let init_param = expect_ident(&mut inner, "expected initial lambda parameter")?;
|
||||
expect_punct(&mut inner, '-', "expected `->` after init parameter")?;
|
||||
expect_punct(&mut inner, '>', "expected `->` after init parameter")?;
|
||||
let init_body = parse_direct_node(&mut inner, ctx)?;
|
||||
expect_punct(&mut inner, ',', "expected `,` after init template")?;
|
||||
let acc_param = expect_ident(&mut inner, "expected accumulator parameter")?;
|
||||
expect_punct(&mut inner, ',', "expected `,` after accumulator parameter")?;
|
||||
let elem_param = expect_ident(&mut inner, "expected element parameter")?;
|
||||
expect_punct(&mut inner, '-', "expected `->` after element parameter")?;
|
||||
expect_punct(&mut inner, '>', "expected `->` after element parameter")?;
|
||||
let fold_body = parse_direct_node(&mut inner, ctx)?;
|
||||
if let Some(tok) = inner.next() {
|
||||
return Err(syn::Error::new_spanned(
|
||||
tok,
|
||||
"unexpected token after fold template",
|
||||
));
|
||||
}
|
||||
current = quote! {
|
||||
{
|
||||
let mut __iter = #current;
|
||||
let __result: Option<usize> = if let Some(#init_param) = __iter.next() {
|
||||
let mut __acc: usize = #init_body;
|
||||
for #elem_param in __iter {
|
||||
let #acc_param: usize = __acc;
|
||||
__acc = #fold_body;
|
||||
}
|
||||
Some(__acc)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
__result.into_iter()
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
return Err(syn::Error::new_spanned(
|
||||
method,
|
||||
format!("unknown builtin method `.{method_str}()`"),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(current)
|
||||
}
|
||||
|
||||
/// Parse the top-level list of a `trees!` template.
|
||||
/// Each item is a node template or `{expr}` splice.
|
||||
fn parse_direct_list(tokens: &mut Tokens, ctx: &Ident) -> Result<Vec<TokenStream>> {
|
||||
@@ -492,18 +605,27 @@ fn parse_direct_list(tokens: &mut Tokens, ctx: &Ident) -> Result<Vec<TokenStream
|
||||
continue;
|
||||
}
|
||||
|
||||
// {expr} or {..expr} — single node or splice
|
||||
// {expr} or {..expr} (with optional .chain) — single node or splice
|
||||
if peek_is_group(tokens, Delimiter::Brace) {
|
||||
let group = expect_group(tokens, Delimiter::Brace)?;
|
||||
let has_chain = matches!(tokens.peek(), Some(TokenTree::Punct(p)) if p.as_char() == '.');
|
||||
let mut inner = group.stream().into_iter().peekable();
|
||||
if peek_is_dotdot(&inner) {
|
||||
inner.next(); // consume first .
|
||||
inner.next(); // consume second .
|
||||
let expr: TokenStream = inner.collect();
|
||||
items.push(quote! {
|
||||
__nodes.extend(
|
||||
let is_splice = peek_is_dotdot(&inner);
|
||||
if is_splice || has_chain {
|
||||
let base: TokenStream = if is_splice {
|
||||
inner.next(); // consume first .
|
||||
inner.next(); // consume second .
|
||||
let expr: TokenStream = inner.collect();
|
||||
quote! {
|
||||
(#expr).into_iter().map(::std::convert::Into::<usize>::into)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let expr = group.stream();
|
||||
quote! { (#expr).into_iter() }
|
||||
};
|
||||
let chained = parse_chain_suffix(tokens, ctx, base)?;
|
||||
items.push(quote! {
|
||||
__nodes.extend(#chained);
|
||||
});
|
||||
} else {
|
||||
let expr = group.stream();
|
||||
@@ -604,8 +726,11 @@ fn extract_captures_inner(
|
||||
}
|
||||
last_mult = CaptureMultiplicity::Single;
|
||||
}
|
||||
TokenTree::Punct(p) if matches!(p.as_char(), '*' | '+' | '?') => {
|
||||
// Keep last_mult — the @capture follows
|
||||
TokenTree::Punct(p) if p.as_char() == '*' || p.as_char() == '+' => {
|
||||
last_mult = CaptureMultiplicity::Repeated;
|
||||
}
|
||||
TokenTree::Punct(p) if p.as_char() == '?' => {
|
||||
last_mult = CaptureMultiplicity::Optional;
|
||||
}
|
||||
_ => {
|
||||
last_mult = CaptureMultiplicity::Single;
|
||||
|
||||
@@ -82,10 +82,34 @@ impl<'a> BuildCtx<'a> {
|
||||
.create_named_token_with_range(kind, value.to_string(), self.source_range)
|
||||
}
|
||||
|
||||
/// Create a leaf node with fixed content and an optional preferred source range.
|
||||
/// If `source_range` is `None`, falls back to this context's inherited range.
|
||||
pub fn literal_with_source_range(
|
||||
&mut self,
|
||||
kind: &'static str,
|
||||
value: &str,
|
||||
source_range: Option<tree_sitter::Range>,
|
||||
) -> Id {
|
||||
self.ast.create_named_token_with_range(
|
||||
kind,
|
||||
value.to_string(),
|
||||
source_range.or(self.source_range),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a leaf node with an auto-generated unique name.
|
||||
pub fn fresh(&mut self, kind: &'static str, name: &str) -> Id {
|
||||
let generated = self.fresh.resolve(name);
|
||||
self.ast
|
||||
.create_named_token_with_range(kind, generated, self.source_range)
|
||||
}
|
||||
|
||||
/// Prepend a value to a field of an existing node.
|
||||
pub fn prepend_field(&mut self, node_id: Id, field_name: &str, value_id: Id) {
|
||||
let field_id = self
|
||||
.ast
|
||||
.field_id_for_name(field_name)
|
||||
.unwrap_or_else(|| panic!("build: field '{field_name}' not found"));
|
||||
self.ast.prepend_field_child(node_id, field_id, value_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,12 +58,30 @@ pub trait YeastDisplay {
|
||||
fn yeast_to_string(&self, ast: &Ast) -> String;
|
||||
}
|
||||
|
||||
/// Optional source range for values used in `#{expr}` interpolations.
|
||||
///
|
||||
/// By default this returns `None`, so synthesized leaves inherit the matched
|
||||
/// rule's source range. `NodeRef` returns the referenced node's range, letting
|
||||
/// `(kind #{capture})` carry the captured node's location.
|
||||
pub trait YeastSourceRange {
|
||||
fn yeast_source_range(&self, ast: &Ast) -> Option<tree_sitter::Range>;
|
||||
}
|
||||
|
||||
impl YeastDisplay for NodeRef {
|
||||
fn yeast_to_string(&self, ast: &Ast) -> String {
|
||||
ast.source_text(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl YeastSourceRange for NodeRef {
|
||||
fn yeast_source_range(&self, ast: &Ast) -> Option<tree_sitter::Range> {
|
||||
ast.get_node(self.0).and_then(|n| match &n.content {
|
||||
NodeContent::Range(r) => Some(r.clone()),
|
||||
_ => n.source_range,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_yeast_display_via_display {
|
||||
($($t:ty),* $(,)?) => {
|
||||
$(
|
||||
@@ -72,6 +90,12 @@ macro_rules! impl_yeast_display_via_display {
|
||||
::std::string::ToString::to_string(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl YeastSourceRange for $t {
|
||||
fn yeast_source_range(&self, _ast: &Ast) -> Option<tree_sitter::Range> {
|
||||
None
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
@@ -90,6 +114,12 @@ impl<T: YeastDisplay + ?Sized> YeastDisplay for &T {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: YeastSourceRange + ?Sized> YeastSourceRange for &T {
|
||||
fn yeast_source_range(&self, ast: &Ast) -> Option<tree_sitter::Range> {
|
||||
(**self).yeast_source_range(ast)
|
||||
}
|
||||
}
|
||||
|
||||
pub const CHILD_FIELD: u16 = u16::MAX;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -368,6 +398,15 @@ impl Ast {
|
||||
is_named: bool,
|
||||
source_range: Option<tree_sitter::Range>,
|
||||
) -> Id {
|
||||
let source_range = match &content {
|
||||
// Parsed nodes already carry an exact source range in their content.
|
||||
NodeContent::Range(_) => source_range,
|
||||
// Synthesized nodes derive location from children when possible,
|
||||
// and fall back to the inherited rule-match range otherwise.
|
||||
_ => self
|
||||
.union_source_range_of_children(&fields)
|
||||
.or(source_range),
|
||||
};
|
||||
let id = self.nodes.len();
|
||||
self.nodes.push(Node {
|
||||
kind,
|
||||
@@ -383,10 +422,76 @@ impl Ast {
|
||||
id
|
||||
}
|
||||
|
||||
fn union_source_range_of_children(
|
||||
&self,
|
||||
fields: &BTreeMap<FieldId, Vec<Id>>,
|
||||
) -> Option<tree_sitter::Range> {
|
||||
let mut start_byte: Option<usize> = None;
|
||||
let mut end_byte: Option<usize> = None;
|
||||
let mut start_point = tree_sitter::Point { row: 0, column: 0 };
|
||||
let mut end_point = tree_sitter::Point { row: 0, column: 0 };
|
||||
|
||||
for child_ids in fields.values() {
|
||||
for &child_id in child_ids {
|
||||
let Some(child) = self.get_node(child_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let child_start_byte = child.start_byte();
|
||||
let child_end_byte = child.end_byte();
|
||||
|
||||
// Skip children that carry no usable location.
|
||||
if child_start_byte == 0 && child_end_byte == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
match start_byte {
|
||||
None => {
|
||||
start_byte = Some(child_start_byte);
|
||||
start_point = child.start_position();
|
||||
}
|
||||
Some(current_start) if child_start_byte < current_start => {
|
||||
start_byte = Some(child_start_byte);
|
||||
start_point = child.start_position();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match end_byte {
|
||||
None => {
|
||||
end_byte = Some(child_end_byte);
|
||||
end_point = child.end_position();
|
||||
}
|
||||
Some(current_end) if child_end_byte > current_end => {
|
||||
end_byte = Some(child_end_byte);
|
||||
end_point = child.end_position();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match (start_byte, end_byte) {
|
||||
(Some(start_byte), Some(end_byte)) => Some(tree_sitter::Range {
|
||||
start_byte,
|
||||
end_byte,
|
||||
start_point,
|
||||
end_point,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_named_token(&mut self, kind: &'static str, content: String) -> Id {
|
||||
self.create_named_token_with_range(kind, content, None)
|
||||
}
|
||||
|
||||
/// Prepend a child id to the given field of the given node.
|
||||
pub fn prepend_field_child(&mut self, node_id: Id, field_id: FieldId, value_id: Id) {
|
||||
let node = self.nodes.get_mut(node_id).expect("prepend_field_child: invalid node id");
|
||||
node.fields.entry(field_id).or_default().insert(0, value_id);
|
||||
}
|
||||
|
||||
pub fn create_named_token_with_range(
|
||||
&mut self,
|
||||
kind: &'static str,
|
||||
@@ -825,14 +930,6 @@ fn apply_one_shot_rules_inner(
|
||||
|
||||
let node_kind = ast.get_node(id).map(|n| n.kind()).unwrap_or("");
|
||||
|
||||
// Don't rewrite unnamed nodes (punctuation, keywords, etc.); leave them
|
||||
// as-is. Rules target named nodes only.
|
||||
if let Some(node) = ast.get_node(id) {
|
||||
if !node.is_named() {
|
||||
return Ok(vec![id]);
|
||||
}
|
||||
}
|
||||
|
||||
for rule in index.rules_for_kind(node_kind) {
|
||||
if let Some(mut captures) = rule.try_match(ast, id)? {
|
||||
// Recursively translate every captured node before invoking the
|
||||
|
||||
@@ -18,6 +18,16 @@ fn run_and_dump(input: &str, rules: Vec<Rule>) -> String {
|
||||
run_phased_and_dump(input, vec![Phase::new("test", PhaseKind::Repeating, rules)])
|
||||
}
|
||||
|
||||
/// Helper: parse Ruby source with custom rules and return the transformed AST.
|
||||
fn run_and_ast(input: &str, rules: Vec<Rule>) -> Ast {
|
||||
let lang: tree_sitter::Language = tree_sitter_ruby::LANGUAGE.into();
|
||||
let schema =
|
||||
yeast::node_types_yaml::schema_from_yaml_with_language(OUTPUT_SCHEMA_YAML, &lang).unwrap();
|
||||
let phases = vec![Phase::new("test", PhaseKind::Repeating, rules)];
|
||||
let runner = Runner::with_schema(lang, &schema, &phases);
|
||||
runner.run(input).unwrap()
|
||||
}
|
||||
|
||||
/// Helper: parse Ruby source with a custom output schema and multiple
|
||||
/// rule phases, return dump.
|
||||
fn run_phased_and_dump(input: &str, phases: Vec<Phase>) -> String {
|
||||
@@ -389,6 +399,29 @@ fn test_capture_unnamed_node_parenthesized() {
|
||||
assert!(!op_node.is_named());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_capture_bare_underscore_repeated() {
|
||||
// `_` matches named and unnamed nodes in bare-child position. On this
|
||||
// assignment shape, bare children correspond to unnamed tokens (the `=`).
|
||||
let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]);
|
||||
let ast = runner.run("x = 1").unwrap();
|
||||
|
||||
let query = yeast::query!((assignment _* @all));
|
||||
|
||||
let mut cursor = AstCursor::new(&ast);
|
||||
cursor.goto_first_child();
|
||||
let assignment_id = cursor.node_id();
|
||||
|
||||
let mut captures = yeast::captures::Captures::new();
|
||||
let matched = query.do_match(&ast, assignment_id, &mut captures).unwrap();
|
||||
assert!(matched);
|
||||
|
||||
let all = captures.get_all("all");
|
||||
assert_eq!(all.len(), 1);
|
||||
assert_eq!(ast.get_node(all[0]).unwrap().kind(), "=");
|
||||
assert!(!ast.get_node(all[0]).unwrap().is_named());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_capture_unnamed_node_bare_literal() {
|
||||
// `"=" @op` (without surrounding parens) is the same as `("=") @op`.
|
||||
@@ -1149,3 +1182,37 @@ fn test_hash_brace_renders_integer_expression() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
/// Regression test: `(kind #{capture})` should inherit the captured node's
|
||||
/// source location, not the full source range of the matched rule root.
|
||||
#[test]
|
||||
fn test_hash_brace_uses_capture_location_for_leaf() {
|
||||
let rule = rule!(
|
||||
(call
|
||||
method: (identifier) @name
|
||||
receiver: (identifier) @recv
|
||||
)
|
||||
=>
|
||||
(call
|
||||
method: (identifier #{name})
|
||||
receiver: (identifier #{recv})
|
||||
arguments: (argument_list)
|
||||
)
|
||||
);
|
||||
|
||||
let ast = run_and_ast("foo.bar()", vec![rule]);
|
||||
|
||||
let mut bar_ids: Vec<usize> = Vec::new();
|
||||
for id in ast.reachable_node_ids() {
|
||||
let Some(node) = ast.get_node(id) else { continue; };
|
||||
if node.kind() == "identifier" && ast.source_text(id) == "bar" {
|
||||
bar_ids.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(bar_ids.len(), 1, "expected exactly one identifier 'bar'");
|
||||
let bar = ast.get_node(bar_ids[0]).unwrap();
|
||||
|
||||
assert_eq!(bar.start_byte(), 4);
|
||||
assert_eq!(bar.end_byte(), 7);
|
||||
}
|
||||
|
||||
@@ -3,25 +3,21 @@
|
||||
This is a CodeQL extractor based on tree-sitter.
|
||||
|
||||
## Building
|
||||
To build the extractor, run `scripts/create-extractor-pack.sh`
|
||||
- To build the extractor, run `scripts/create-extractor-pack.sh`
|
||||
|
||||
## Editing the Swift grammar
|
||||
The vendored tree-sitter-swift grammar lives at
|
||||
`extractor/tree-sitter-swift/`. After editing `grammar.js` (or any other
|
||||
grammar source), run `scripts/regenerate-grammar.sh` to:
|
||||
- regenerate `extractor/tree-sitter-swift/src/{parser.c, grammar.json,
|
||||
node-types.json}` (and the `src/tree_sitter/*.h` headers) via
|
||||
`tree-sitter generate`; and
|
||||
- refresh `extractor/tree-sitter-swift/node-types.yml`, the
|
||||
human-readable companion to `src/node-types.json` produced by yeast's
|
||||
`node_types_yaml` binary.
|
||||
## Swift Parser
|
||||
- The Swift parser is defined by `extractor/tree-sitter-swift/grammar.js` and can be edited if needed.
|
||||
|
||||
`node-types.yml` is the recommended review surface for grammar changes —
|
||||
it shows the impact of a grammar tweak on the named node kinds, fields,
|
||||
and child types in a form much easier to read than the raw JSON.
|
||||
- After editing the grammar, always run `scripts/regenerate-grammar.sh`.
|
||||
|
||||
## Extractor Testing
|
||||
- To run extractor tests, run `cargo test` in the `extractor` directory.
|
||||
- The raw parse tree is described by `extractor/tree-sitter-swift/node-types.yml` and should be reviewed after grammar changes.
|
||||
|
||||
## AST Mapping
|
||||
- The target AST shape is described by `extractor/ast_types.yml`.
|
||||
|
||||
- The mapping from the parse tree to the target AST is found in `extractor/src/languages/swift/swift.rs`
|
||||
|
||||
- To run tests for the parser and mapping, run `cargo test` in the `extractor` directory.
|
||||
|
||||
- Do not edit the printed ASTs in `extractor/test/corpus` directly. To regenerate the ASTs, run `scripts/update-corpus.sh`.
|
||||
|
||||
|
||||
@@ -2,36 +2,103 @@ supertypes:
|
||||
expr:
|
||||
- name_expr
|
||||
- int_literal
|
||||
- float_literal
|
||||
- boolean_literal
|
||||
- string_literal
|
||||
- regex_literal
|
||||
- builtin_expr
|
||||
- binary_expr
|
||||
- unary_expr
|
||||
- call_expr
|
||||
- member_access_expr
|
||||
- lambda_expr
|
||||
- unsupported_node
|
||||
stmt:
|
||||
- empty_stmt
|
||||
- block_stmt
|
||||
- expr_stmt
|
||||
- if_stmt
|
||||
- variable_declaration_stmt
|
||||
- guard_if_stmt
|
||||
- unsupported_node
|
||||
condition:
|
||||
- expr_condition
|
||||
- let_pattern_condition
|
||||
- sequence_condition
|
||||
- super_expr
|
||||
- function_expr
|
||||
- array_literal
|
||||
- map_literal
|
||||
- key_value_pair
|
||||
- tuple_expr
|
||||
- type_cast_expr
|
||||
- type_test_expr
|
||||
- if_expr
|
||||
- assign_expr
|
||||
- compound_assign_expr
|
||||
- pattern_guard_expr
|
||||
- empty_expr
|
||||
- block
|
||||
- break_expr
|
||||
- continue_expr
|
||||
- return_expr
|
||||
- throw_expr
|
||||
- try_expr
|
||||
- switch_expr
|
||||
- unsupported_node
|
||||
expr_or_pattern:
|
||||
- expr
|
||||
- pattern
|
||||
expr_or_type:
|
||||
- expr
|
||||
- type_expr
|
||||
pattern:
|
||||
- var_pattern
|
||||
- apply_pattern
|
||||
- name_pattern
|
||||
- tuple_pattern
|
||||
- constructor_pattern
|
||||
- ignore_pattern
|
||||
- expr_equality_pattern
|
||||
- bulk_importing_pattern
|
||||
- unsupported_node
|
||||
# A statement is anything that can appear in a block.
|
||||
# This type contains all of 'expr' and has partial overlap with 'member'.
|
||||
# For example, type_alias_declaration can appear either as a stmt or member.
|
||||
# constructor_declaration and destructor_declaration appear here because
|
||||
# tree-sitter-swift's error recovery for #if/#endif in class bodies can place
|
||||
# init/deinit declarations at the wrong (statement) level.
|
||||
stmt:
|
||||
- expr
|
||||
- variable_declaration
|
||||
- type_alias_declaration
|
||||
- function_declaration
|
||||
- import_declaration
|
||||
- operator_syntax_declaration
|
||||
- class_like_declaration
|
||||
- accessor_declaration
|
||||
- constructor_declaration
|
||||
- destructor_declaration
|
||||
- guard_if_stmt
|
||||
- for_each_stmt
|
||||
- while_stmt
|
||||
- do_while_stmt
|
||||
- labeled_stmt
|
||||
# A member is anything that can appear in the body of a class-like declaration
|
||||
member:
|
||||
- constructor_declaration
|
||||
- destructor_declaration
|
||||
- function_declaration
|
||||
- variable_declaration
|
||||
- accessor_declaration
|
||||
- initializer_declaration
|
||||
- class_like_declaration
|
||||
- type_alias_declaration
|
||||
- associated_type_declaration
|
||||
- unsupported_node
|
||||
type_expr:
|
||||
- named_type_expr
|
||||
- generic_type_expr
|
||||
- tuple_type_expr
|
||||
- function_type_expr
|
||||
- inferred_type_expr
|
||||
- unsupported_node
|
||||
type_constraint:
|
||||
- equality_type_constraint
|
||||
- bound_type_constraint
|
||||
operator:
|
||||
- infix_operator
|
||||
- prefix_operator
|
||||
- postfix_operator
|
||||
named:
|
||||
# Top-level is the root node, currently containing a list of expressions
|
||||
# Top-level is the root node, containing a single block of statements
|
||||
# (which are themselves expressions or declarations).
|
||||
top_level:
|
||||
body*: [expr, stmt]
|
||||
body: block
|
||||
|
||||
# An identifier used in the context of an expression
|
||||
name_expr:
|
||||
@@ -40,13 +107,28 @@ named:
|
||||
# An integer literal
|
||||
int_literal:
|
||||
|
||||
# A floating-point literal
|
||||
float_literal:
|
||||
|
||||
# A boolean literal
|
||||
boolean_literal:
|
||||
|
||||
# A literal backed by a keyword such as `nil`, `null`, or `nullptr`.
|
||||
#
|
||||
# Although nil/null are keyword literals in many languages there should be
|
||||
# no attempt to normalize "null-like" named entities, like Python's `None`.
|
||||
builtin_expr:
|
||||
|
||||
# A string literal
|
||||
string_literal:
|
||||
|
||||
# A regex literal
|
||||
regex_literal:
|
||||
|
||||
# Application of a binary operator, such as `a + b`
|
||||
binary_expr:
|
||||
left: expr
|
||||
operator: operator
|
||||
operator: infix_operator
|
||||
right: expr
|
||||
|
||||
# Application of a unary operator, such as `!x`
|
||||
@@ -54,86 +136,310 @@ named:
|
||||
operand: expr
|
||||
operator: operator
|
||||
|
||||
# A function or method call, such as `f(x)` or `obj.m(x)`. Method calls
|
||||
# are represented as a call whose `function` is a `member_access_expr`.
|
||||
# Plain assignment
|
||||
assign_expr:
|
||||
target: expr_or_pattern
|
||||
value: expr
|
||||
|
||||
# Compound assignment
|
||||
compound_assign_expr:
|
||||
target: expr
|
||||
operator: infix_operator
|
||||
value: expr
|
||||
|
||||
# A function or method call, such as `f(x)` or `obj.m(x)`.
|
||||
#
|
||||
# Method calls are represented as a call whose `function` is a `member_access_expr`.
|
||||
#
|
||||
# Constructor calls are marked by a language-specific modifier, and the target may be
|
||||
# a `type_expr` if the parser can deduce that the target is a type.
|
||||
call_expr:
|
||||
function: expr
|
||||
argument*: expr
|
||||
modifier*: modifier
|
||||
callee: expr_or_type
|
||||
argument*: argument
|
||||
|
||||
argument:
|
||||
modifier*: modifier
|
||||
name?: identifier
|
||||
value: expr
|
||||
|
||||
# Member access, such as `obj.member`.
|
||||
#
|
||||
# The base may be a type expression when it is a static member access like `Array<Int>.method`.
|
||||
# In ambiguous cases where the parser cannot distinguish static and instance member access, the base
|
||||
# will be typically be an expression.
|
||||
#
|
||||
# For `super.x` the base will be an instance of `super_expr`.
|
||||
member_access_expr:
|
||||
target: expr
|
||||
base: expr_or_type
|
||||
member: identifier
|
||||
|
||||
lambda_expr:
|
||||
# A type expression that refers to a type inferred from the contextual type.
|
||||
# This is used to translate Swift's leading-dot syntax, `.foo`, which means `T.foo` where
|
||||
# `T` is the contextual type of some enclosing expression. This is translated to a member_access
|
||||
# with an inferred_type_expr as the base.
|
||||
inferred_type_expr:
|
||||
|
||||
# A `super` token, which can usually only appear as the base of member access.
|
||||
super_expr:
|
||||
|
||||
function_expr:
|
||||
modifier*: modifier
|
||||
capture_declaration*: variable_declaration
|
||||
parameter*: parameter
|
||||
body: [expr, stmt]
|
||||
return_type?: type_expr
|
||||
body: block
|
||||
|
||||
# A parameter
|
||||
array_literal:
|
||||
element*: expr
|
||||
|
||||
map_literal:
|
||||
element*: expr
|
||||
|
||||
# A key-value pair, usually appearing as a named argument or as part of a map literal.
|
||||
#
|
||||
# For some languages, the key-value pair is a first class value and this type of expression
|
||||
# may thus appear anywhere in the general case.
|
||||
key_value_pair:
|
||||
key: expr
|
||||
value: expr
|
||||
|
||||
# A tuple expression, such as `(a, b, c)`.
|
||||
tuple_expr:
|
||||
element*: expr
|
||||
|
||||
# A parameter.
|
||||
#
|
||||
# `type` is its declared type annotation (if any)
|
||||
#
|
||||
# `pattern` binds the parameter's internal name(s). For a simple parameter this is a
|
||||
# `name_pattern`, but may be an arbitrary pattern for languages where patterns may appear
|
||||
# in the parameter list.
|
||||
#
|
||||
# `external_name` is the name by which to call sites refer to the parameter, if the parameter
|
||||
# can be passed as a named parameter. For example, the Swift function `func greet(person id: String)`
|
||||
# would have `person` as the external name and a `name_pattern` wrapping `id` is the parameter's pattern.
|
||||
parameter:
|
||||
modifier*: modifier
|
||||
external_name?: identifier
|
||||
type?: type_expr
|
||||
pattern?: pattern
|
||||
default?: expr
|
||||
|
||||
# An expression that does nothing. Used where the grammar permits an
|
||||
# empty statement (e.g. a stray `;`).
|
||||
empty_expr:
|
||||
|
||||
# A brace-delimited sequence of statements (`{ ... }`). Blocks are the
|
||||
# only nodes that can directly contain statements; every other body-like
|
||||
# field holds a single `block`.
|
||||
block:
|
||||
stmt*: stmt
|
||||
|
||||
if_expr:
|
||||
condition: expr
|
||||
then?: expr
|
||||
else?: expr
|
||||
|
||||
# A variable declaration or destructuring assignment that introduces new variables.
|
||||
#
|
||||
# Any occurrence of `var_patterns` in 'pattern' result in fresh bindings that are
|
||||
# in scope for the rest of the enclosing block.
|
||||
#
|
||||
# The initializer is optional (but typically cannot be omitted if combined with a non-trivial pattern).
|
||||
#
|
||||
# Modifiers should include 'var', 'let', 'const', etc, if they are significant.
|
||||
# A grouped declaration like `let x = 1, y = 2` is emitted as a sequence of
|
||||
# `variable_declaration`s directly into the enclosing stmt/member slot; every
|
||||
# declaration after the first in such a group is tagged with a synthetic
|
||||
# `chained_declaration` modifier so the grouping can be recovered downstream.
|
||||
variable_declaration:
|
||||
modifier*: modifier
|
||||
pattern: pattern
|
||||
|
||||
empty_stmt:
|
||||
|
||||
block_stmt:
|
||||
body*: stmt
|
||||
|
||||
expr_stmt:
|
||||
expr: expr
|
||||
|
||||
if_stmt:
|
||||
condition: condition
|
||||
then?: stmt
|
||||
else?: stmt
|
||||
|
||||
variable_declaration_stmt:
|
||||
variable_declarator+: variable_declarator
|
||||
|
||||
# A variable declaration, or assignment to a pattern.
|
||||
# The initializer is optional (but typically only possible in combination with a simple variable pattern).
|
||||
variable_declarator:
|
||||
pattern: pattern
|
||||
type?: type_expr
|
||||
value?: expr
|
||||
|
||||
# Evaluate 'condition', and if false, execute 'else' which must break from the enclosing block scope (return, break, etc).
|
||||
# Any variables bound by 'condition' will be in scope for the remainder of the enclosing block scope
|
||||
# (which differs from how if_stmt works).
|
||||
# (which differs from how if_expr works).
|
||||
guard_if_stmt:
|
||||
condition: condition
|
||||
else: stmt
|
||||
condition: expr
|
||||
else: block
|
||||
|
||||
# Evaluates the given condition and interprets it as a boolean (by language conventions)
|
||||
expr_condition:
|
||||
expr: expr
|
||||
# `break` (with optional label)
|
||||
break_expr:
|
||||
label?: identifier
|
||||
|
||||
# A series of statements that are executed before evaluating the trailing condition.
|
||||
# Useful for languages where a conditional clause may be preceded by side-effecting
|
||||
# syntactic elements (e.g. binding clauses) that don't themselves form a condition.
|
||||
sequence_condition:
|
||||
stmt*: stmt
|
||||
condition: condition
|
||||
# `continue` (with optional label)
|
||||
continue_expr:
|
||||
label?: identifier
|
||||
|
||||
# A labeled statement, such as `outer: for ... { ... }`. The labeled
|
||||
# statement appears as the `stmt` field; `break`/`continue` may target
|
||||
# the label.
|
||||
labeled_stmt:
|
||||
label: identifier
|
||||
stmt: stmt
|
||||
|
||||
# `return value` or bare `return`
|
||||
return_expr:
|
||||
value?: expr
|
||||
|
||||
# `throw value`
|
||||
throw_expr:
|
||||
value?: expr
|
||||
|
||||
# An import declaration.
|
||||
#
|
||||
# The semantics of an import are generally:
|
||||
# - Evaluate the 'imported_expr' to a value (possibly a compile-time value, such as namespace)
|
||||
# - Filter away possible values based on modifiers (e.g. type-only imports only accept types)
|
||||
# - Assign the value to the pattern, binding variables and/or type names in scope
|
||||
#
|
||||
import_declaration:
|
||||
modifier*: modifier
|
||||
imported_expr: expr # Qualified names are encoded as a chain of member_access_expr ending with a name_expr
|
||||
pattern?: pattern # Binds local names in scope (possibly via bulk_importing_pattern)
|
||||
|
||||
# `typealias Name = Type`
|
||||
type_alias_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
type_parameter*: type_parameter
|
||||
type_constraint*: type_constraint
|
||||
type: type_expr
|
||||
|
||||
# A top-level function declaration.
|
||||
function_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
type_parameter*: type_parameter
|
||||
type_constraint*: type_constraint
|
||||
parameter*: parameter
|
||||
return_type?: type_expr
|
||||
body?: block
|
||||
|
||||
# `for pattern in iterable [where guard] { body }`.
|
||||
for_each_stmt:
|
||||
modifier*: modifier
|
||||
pattern: pattern
|
||||
iterable: expr
|
||||
guard?: expr
|
||||
body?: block
|
||||
|
||||
# `while condition { body }`.
|
||||
while_stmt:
|
||||
modifier*: modifier
|
||||
condition: expr
|
||||
body?: block
|
||||
|
||||
# `repeat { body } while condition`.
|
||||
do_while_stmt:
|
||||
modifier*: modifier
|
||||
body?: block
|
||||
condition: expr
|
||||
|
||||
# `do { body } catch pattern { ... } catch ...`. Swift uses `do`/`catch`
|
||||
# for error handling; for languages with `try`/`catch`, this is the same shape.
|
||||
try_expr:
|
||||
modifier*: modifier
|
||||
body: block
|
||||
catch_clause*: catch_clause
|
||||
|
||||
catch_clause:
|
||||
modifier*: modifier
|
||||
pattern?: pattern
|
||||
guard?: expr
|
||||
body: block
|
||||
|
||||
# `switch value { case pattern: body case ...: default: body }`
|
||||
switch_expr:
|
||||
modifier*: modifier
|
||||
value: expr
|
||||
case*: switch_case
|
||||
|
||||
# A single `case ...:` (or `default:`) entry in a switch.
|
||||
# An entry with multiple `case p1, p2:` patterns has multiple `pattern`s.
|
||||
# A `default:` entry has no patterns.
|
||||
# An optional `guard` corresponds to a `where`-clause on the case.
|
||||
switch_case:
|
||||
modifier*: modifier
|
||||
pattern*: pattern
|
||||
guard?: expr
|
||||
body: block
|
||||
|
||||
# Evaluate 'expr' and match its result against 'pattern', and return true if it matches.
|
||||
# Variables bound by the pattern will be in scope within the 'true' branch controlled by this condition.
|
||||
let_pattern_condition:
|
||||
# Variables bound by the pattern will be in scope within the 'true' branch controlled by this expression.
|
||||
#
|
||||
# In Swift, `if case let PATTERN = EXPR` maps to this node
|
||||
#
|
||||
# Java: 'if (x instanceof Foo y && w ...) { ... }'
|
||||
pattern_guard_expr:
|
||||
pattern: pattern
|
||||
value: expr
|
||||
|
||||
# A pattern matching anything, binding its value to the given variable
|
||||
var_pattern:
|
||||
# A type cast expression, such as `x as T`, `x as? T`, or `x as! T`. The
|
||||
# operator distinguishes between the variants.
|
||||
type_cast_expr:
|
||||
expr: expr
|
||||
operator: infix_operator
|
||||
type: type_expr
|
||||
|
||||
# A type-test expression, such as `x is T`. Yields a boolean indicating
|
||||
# whether `expr` is an instance of `type`.
|
||||
type_test_expr:
|
||||
expr: expr
|
||||
operator: infix_operator
|
||||
type: type_expr
|
||||
|
||||
# An identifier that introduces a variable.
|
||||
#
|
||||
# When used as a pattern, the pattern matches anything and binds its incoming value to the variable
|
||||
name_pattern:
|
||||
modifier*: modifier
|
||||
identifier: identifier
|
||||
|
||||
# A pattern matching anything, binding no variables, usually using the syntax "_"
|
||||
ignore_pattern:
|
||||
|
||||
# A pattern such as `Some(x)` where `Some` is the constructor and `x` is an argument
|
||||
apply_pattern:
|
||||
constructor: expr
|
||||
argument*: pattern
|
||||
# A pattern that matches if the incoming value is equal to the value of the given expression.
|
||||
# Used for literal patterns in switch (e.g. `case 1:`).
|
||||
expr_equality_pattern:
|
||||
expr: expr
|
||||
|
||||
# A tuple pattern such as `(a, b)` in `let (a, b) = pair`.
|
||||
#
|
||||
# Elements of the tuple pattern can have names, such as Swift's `let (foo: x, bar: y) = tuple`.
|
||||
tuple_pattern:
|
||||
element*: pattern
|
||||
modifier*: modifier
|
||||
element*: pattern_element
|
||||
|
||||
# A pattern such as `Some(x)` where `Some` is the constructor and `x` is an element.
|
||||
# The element names are interpreted as argument labels and/or field names.
|
||||
constructor_pattern:
|
||||
modifier*: modifier
|
||||
constructor: expr_or_type
|
||||
element*: pattern_element
|
||||
|
||||
# A pattern with an optional associated name.
|
||||
pattern_element:
|
||||
modifier*: modifier
|
||||
key?: identifier
|
||||
pattern: pattern
|
||||
|
||||
# A pattern that checks if the incoming value has the given type, and if so, the
|
||||
# value is matched against the given nested pattern (and succeeds iff the nested match succeeds).
|
||||
#
|
||||
# In Swift: `if let y = x as? Foo` is a pattern_guard_expr containing a type_test_pattern
|
||||
# In Java: `x instanceof Foo y` is a type_test_pattern wrapping a name_pattern
|
||||
type_test_pattern:
|
||||
pattern: pattern
|
||||
type: type_expr
|
||||
|
||||
# A '*' pattern that imports all members of the incoming value into the local scope
|
||||
# Currently this can only appear in import declarations.
|
||||
bulk_importing_pattern:
|
||||
modifier*: modifier
|
||||
|
||||
# An simple unqualified identifier token
|
||||
identifier:
|
||||
@@ -141,4 +447,129 @@ named:
|
||||
# A node that we don't yet translate
|
||||
unsupported_node:
|
||||
|
||||
operator:
|
||||
infix_operator:
|
||||
|
||||
prefix_operator:
|
||||
|
||||
postfix_operator:
|
||||
|
||||
# The fixity of a custom operator declaration (e.g. "prefix", "infix",
|
||||
# "postfix"). The value is the keyword string.
|
||||
fixity:
|
||||
|
||||
type_parameter:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
bound?: type_expr
|
||||
|
||||
# A generic constraint of the form `T == U`, requiring two types to be
|
||||
# equal. Appears in `where` clauses on generic declarations
|
||||
# (e.g. Swift `func foo<T, U>() where T == U`).
|
||||
equality_type_constraint:
|
||||
left: type_expr
|
||||
right: type_expr
|
||||
|
||||
# A generic constraint of the form `T: Bound`, requiring a type parameter
|
||||
# to conform to (or inherit from) some other type. Appears in `where`
|
||||
# clauses on generic declarations (e.g. Swift `where T: Equatable`).
|
||||
bound_type_constraint:
|
||||
type: type_expr
|
||||
bound: type_expr
|
||||
|
||||
# `infix operator +++` (and the like) — a declaration of a custom operator.
|
||||
operator_syntax_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
# The fixity specifier (`prefix`, `infix`, `postfix`), when applicable.
|
||||
fixity?: fixity
|
||||
# The declared precedence level, when present (e.g. Swift's
|
||||
# `infix operator +++ : AdditionPrecedence`).
|
||||
precedence?: expr
|
||||
|
||||
# A class-like declaration: class, struct, interface (protocol), enum (or actor).
|
||||
# The syntactic kind is carried as a `modifier` (e.g. "class", "struct",
|
||||
# "interface", "enum", "extension"). The `"enum_case"` modifier additionally
|
||||
# marks a declaration as an enum case with associated values. Extensions are
|
||||
# represented as a class-like declaration with the `"extension"` modifier and
|
||||
# no `name`; the extended type appears as a `base_type`.
|
||||
class_like_declaration:
|
||||
modifier*: modifier
|
||||
name?: identifier
|
||||
type_parameter*: type_parameter
|
||||
type_constraint*: type_constraint
|
||||
base_type*: base_type
|
||||
member*: member
|
||||
|
||||
# One of the base types of a class declaration.
|
||||
#
|
||||
# If the language has multiple kinds of base classes (e.g. extends/implements) the
|
||||
# kind should be included as a modifier on this node.
|
||||
base_type:
|
||||
modifier*: modifier
|
||||
type: type_expr
|
||||
|
||||
constructor_declaration:
|
||||
modifier*: modifier
|
||||
name?: identifier
|
||||
parameter*: parameter
|
||||
body: block
|
||||
|
||||
# A destructor / finalizer (Swift `deinit`, C++ `~T()`, etc.).
|
||||
destructor_declaration:
|
||||
modifier*: modifier
|
||||
body: block
|
||||
|
||||
# Declaration of a single accessor for a property (such as a getter, setter,
|
||||
# or observer like Swift's `willSet`/`didSet`).
|
||||
#
|
||||
# Multiple accessors for the same property are emitted as a sequence of
|
||||
# accessor_declaration nodes; every accessor after the first is tagged with
|
||||
# a synthetic `chained_declaration` modifier so the grouping can be recovered
|
||||
# downstream. Stored properties with observers are emitted as a
|
||||
# variable_declaration followed by one accessor_declaration per observer
|
||||
# (each observer also tagged with `chained_declaration`).
|
||||
accessor_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
accessor_kind: accessor_kind
|
||||
parameter*: parameter
|
||||
type?: type_expr
|
||||
body?: block
|
||||
|
||||
# "get", "set", or a language-specific kind like "didSet"
|
||||
accessor_kind:
|
||||
|
||||
# Static or instance initializer block. That is, code that runs at initialization time of either the class or an instance.
|
||||
initializer_declaration:
|
||||
modifier*: modifier
|
||||
body: block
|
||||
|
||||
associated_type_declaration:
|
||||
modifier*: modifier
|
||||
name: identifier
|
||||
bound?: type_expr
|
||||
|
||||
named_type_expr:
|
||||
qualifier?: type_expr
|
||||
name: identifier
|
||||
|
||||
generic_type_expr:
|
||||
base: type_expr
|
||||
type_argument*: type_expr
|
||||
|
||||
# A tuple type such as `(Int, String)` or `(a: A, b: B)`.
|
||||
tuple_type_expr:
|
||||
element*: tuple_type_element
|
||||
|
||||
# An element of a `tuple_type_expr`, optionally carrying a label.
|
||||
tuple_type_element:
|
||||
name?: identifier
|
||||
type: type_expr
|
||||
|
||||
# A function type such as `(Int, String) -> Bool` or `(x: Int) -> Bool`.
|
||||
function_type_expr:
|
||||
parameter*: parameter
|
||||
return_type: type_expr
|
||||
|
||||
# A modifier such as 'static', 'public', or 'async'. For now this is just a leaf node with a string value.
|
||||
modifier:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,35 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "f"
|
||||
value:
|
||||
function_expr
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "*"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "2"
|
||||
parameter:
|
||||
parameter
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
return_type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
|
||||
===
|
||||
Closure with shorthand parameters
|
||||
@@ -82,6 +111,26 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "f"
|
||||
value:
|
||||
function_expr
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "+"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "$0"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "$1"
|
||||
|
||||
===
|
||||
Trailing closure
|
||||
@@ -114,6 +163,28 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
function_expr
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "*"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "$0"
|
||||
right: int_literal "2"
|
||||
callee:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "xs"
|
||||
member: identifier "map"
|
||||
|
||||
===
|
||||
Closure with capture list
|
||||
@@ -163,6 +234,31 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "f"
|
||||
value:
|
||||
function_expr
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
callee:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "self"
|
||||
member: identifier "doThing"
|
||||
capture_declaration:
|
||||
variable_declaration
|
||||
modifier: modifier "weak"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "self"
|
||||
|
||||
===
|
||||
Multi-statement closure
|
||||
@@ -236,3 +332,46 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "f"
|
||||
value:
|
||||
function_expr
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "y"
|
||||
value:
|
||||
binary_expr
|
||||
operator: infix_operator "+"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "1"
|
||||
return_expr
|
||||
value:
|
||||
binary_expr
|
||||
operator: infix_operator "*"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "y"
|
||||
right: int_literal "2"
|
||||
parameter:
|
||||
parameter
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
return_type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
|
||||
@@ -28,6 +28,19 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "xs"
|
||||
value:
|
||||
array_literal
|
||||
element:
|
||||
int_literal "1"
|
||||
int_literal "2"
|
||||
int_literal "3"
|
||||
|
||||
===
|
||||
Empty array literal with type
|
||||
@@ -68,6 +81,22 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "xs"
|
||||
type:
|
||||
generic_type_expr
|
||||
base:
|
||||
named_type_expr
|
||||
name: identifier "Array"
|
||||
type_argument:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
value: array_literal "[]"
|
||||
|
||||
===
|
||||
Dictionary literal
|
||||
@@ -106,6 +135,14 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "d"
|
||||
value: map_literal "[\"a\": 1, \"b\": 2]"
|
||||
|
||||
===
|
||||
Set literal
|
||||
@@ -155,6 +192,22 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "s"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Set<Int>"
|
||||
value:
|
||||
array_literal
|
||||
element:
|
||||
int_literal "1"
|
||||
int_literal "2"
|
||||
int_literal "3"
|
||||
|
||||
===
|
||||
Tuple literal
|
||||
@@ -191,6 +244,14 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "t"
|
||||
value: tuple_expr "(1, \"two\", 3.0)"
|
||||
|
||||
===
|
||||
Subscript access
|
||||
@@ -232,9 +293,21 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
unsupported_node "// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape"
|
||||
unsupported_node "// as `xs(0)`), so the mapping currently produces a call_expr. Update the"
|
||||
unsupported_node "// parser / add a separate subscript_expr node and remap when fixed."
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "first"
|
||||
value:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: int_literal "0"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "xs"
|
||||
|
||||
===
|
||||
Dictionary subscript
|
||||
@@ -276,8 +349,21 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
unsupported_node "// TODO: same parser issue as the array subscript case above —"
|
||||
unsupported_node "// `d[\"key\"]` is parsed as `call_expression(d, (\"key\"))`."
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "v"
|
||||
value:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: string_literal "\"key\""
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "d"
|
||||
|
||||
===
|
||||
Tuple member access
|
||||
@@ -309,3 +395,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "n"
|
||||
value:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "t"
|
||||
member: identifier "0"
|
||||
|
||||
@@ -35,6 +35,28 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
if_expr
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator ">"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
then:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
|
||||
===
|
||||
If-else
|
||||
@@ -90,6 +112,43 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
if_expr
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator ">"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
else:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
unary_expr
|
||||
operand:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
operator: prefix_operator "-"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
then:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
|
||||
===
|
||||
If-else-if chain
|
||||
@@ -165,6 +224,55 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
if_expr
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator ">"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
else:
|
||||
if_expr
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator "<"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
else:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: int_literal "3"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
then:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: int_literal "2"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
then:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: int_literal "1"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
|
||||
===
|
||||
If-let optional binding
|
||||
@@ -207,6 +315,39 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
if_expr
|
||||
condition:
|
||||
pattern_guard_expr
|
||||
pattern:
|
||||
constructor_pattern
|
||||
element:
|
||||
pattern_element
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "value"
|
||||
constructor:
|
||||
member_access_expr
|
||||
base:
|
||||
named_type_expr
|
||||
name: identifier "Optional"
|
||||
member: identifier "some"
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "optional"
|
||||
then:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "value"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
|
||||
===
|
||||
Guard let
|
||||
@@ -240,6 +381,30 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
guard_if_stmt
|
||||
condition:
|
||||
pattern_guard_expr
|
||||
pattern:
|
||||
constructor_pattern
|
||||
element:
|
||||
pattern_element
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "value"
|
||||
constructor:
|
||||
member_access_expr
|
||||
base:
|
||||
named_type_expr
|
||||
name: identifier "Optional"
|
||||
member: identifier "some"
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "optional"
|
||||
else:
|
||||
block
|
||||
stmt: return_expr "return"
|
||||
|
||||
===
|
||||
Ternary expression
|
||||
@@ -277,6 +442,27 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "y"
|
||||
value:
|
||||
if_expr
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator ">"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
else:
|
||||
unary_expr
|
||||
operand: int_literal "1"
|
||||
operator: prefix_operator "-"
|
||||
then: int_literal "1"
|
||||
|
||||
===
|
||||
Switch statement
|
||||
@@ -357,6 +543,54 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
switch_expr
|
||||
case:
|
||||
switch_case
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: string_literal "\"one\""
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
expr_equality_pattern
|
||||
expr: int_literal "1"
|
||||
switch_case
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: string_literal "\"two or three\""
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
expr_equality_pattern
|
||||
expr: int_literal "2"
|
||||
expr_equality_pattern
|
||||
expr: int_literal "3"
|
||||
switch_case
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: string_literal "\"other\""
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
|
||||
===
|
||||
Switch with binding pattern
|
||||
@@ -396,6 +630,7 @@ source_file
|
||||
pattern:
|
||||
pattern
|
||||
bound_identifier: simple_identifier "r"
|
||||
dot: .
|
||||
name: simple_identifier "circle"
|
||||
statement:
|
||||
call_expression
|
||||
@@ -428,6 +663,7 @@ source_file
|
||||
pattern:
|
||||
pattern
|
||||
bound_identifier: simple_identifier "s"
|
||||
dot: .
|
||||
name: simple_identifier "square"
|
||||
statement:
|
||||
call_expression
|
||||
@@ -445,3 +681,207 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
switch_expr
|
||||
case:
|
||||
switch_case
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "r"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
constructor_pattern
|
||||
element:
|
||||
pattern_element
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "r"
|
||||
constructor:
|
||||
member_access_expr
|
||||
base: inferred_type_expr "."
|
||||
member: identifier "circle"
|
||||
switch_case
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "s"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
constructor_pattern
|
||||
element:
|
||||
pattern_element
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "s"
|
||||
constructor:
|
||||
member_access_expr
|
||||
base: inferred_type_expr "."
|
||||
member: identifier "square"
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "shape"
|
||||
|
||||
===
|
||||
Switch with labeled case pattern arguments
|
||||
===
|
||||
|
||||
switch x {
|
||||
case .implicit(isAcknowledged: false):
|
||||
print("yes")
|
||||
case .thread(threadRowId: _, let rowId):
|
||||
print(rowId)
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
source_file
|
||||
statement:
|
||||
switch_statement
|
||||
entry:
|
||||
switch_entry
|
||||
pattern:
|
||||
switch_pattern
|
||||
pattern:
|
||||
pattern
|
||||
kind:
|
||||
case_pattern
|
||||
arguments:
|
||||
tuple_pattern
|
||||
item:
|
||||
tuple_pattern_item
|
||||
name: simple_identifier "isAcknowledged"
|
||||
pattern:
|
||||
pattern
|
||||
kind:
|
||||
boolean_literal
|
||||
dot: .
|
||||
name: simple_identifier "implicit"
|
||||
statement:
|
||||
call_expression
|
||||
function: simple_identifier "print"
|
||||
suffix:
|
||||
call_suffix
|
||||
arguments:
|
||||
value_arguments
|
||||
argument:
|
||||
value_argument
|
||||
value:
|
||||
line_string_literal
|
||||
text: line_str_text "yes"
|
||||
switch_entry
|
||||
pattern:
|
||||
switch_pattern
|
||||
pattern:
|
||||
pattern
|
||||
kind:
|
||||
case_pattern
|
||||
arguments:
|
||||
tuple_pattern
|
||||
item:
|
||||
tuple_pattern_item
|
||||
name: simple_identifier "threadRowId"
|
||||
pattern:
|
||||
pattern
|
||||
kind: wildcard_pattern "_"
|
||||
tuple_pattern_item
|
||||
pattern:
|
||||
pattern
|
||||
kind:
|
||||
binding_pattern
|
||||
binding:
|
||||
value_binding_pattern
|
||||
mutability: let
|
||||
pattern:
|
||||
pattern
|
||||
bound_identifier: simple_identifier "rowId"
|
||||
dot: .
|
||||
name: simple_identifier "thread"
|
||||
statement:
|
||||
call_expression
|
||||
function: simple_identifier "print"
|
||||
suffix:
|
||||
call_suffix
|
||||
arguments:
|
||||
value_arguments
|
||||
argument:
|
||||
value_argument
|
||||
value: simple_identifier "rowId"
|
||||
expr: simple_identifier "x"
|
||||
|
||||
---
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
switch_expr
|
||||
case:
|
||||
switch_case
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: string_literal "\"yes\""
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
constructor_pattern
|
||||
element:
|
||||
pattern_element
|
||||
key: identifier "isAcknowledged"
|
||||
pattern:
|
||||
expr_equality_pattern
|
||||
expr: boolean_literal "false"
|
||||
constructor:
|
||||
member_access_expr
|
||||
base: inferred_type_expr "."
|
||||
member: identifier "implicit"
|
||||
switch_case
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "rowId"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
constructor_pattern
|
||||
element:
|
||||
pattern_element
|
||||
key: identifier "threadRowId"
|
||||
pattern: ignore_pattern "_"
|
||||
pattern_element
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "rowId"
|
||||
constructor:
|
||||
member_access_expr
|
||||
base: inferred_type_expr "."
|
||||
member: identifier "thread"
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
|
||||
@@ -17,6 +17,12 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "+"
|
||||
left: int_literal "1"
|
||||
right: int_literal "2"
|
||||
|
||||
===
|
||||
Another additive expression is desugared
|
||||
@@ -37,3 +43,144 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "+"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "foo"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "bar"
|
||||
|
||||
===
|
||||
Simple import with single name
|
||||
===
|
||||
|
||||
import Foundation
|
||||
|
||||
---
|
||||
|
||||
source_file
|
||||
statement:
|
||||
import_declaration
|
||||
name:
|
||||
identifier
|
||||
part: simple_identifier "Foundation"
|
||||
|
||||
---
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
import_declaration
|
||||
pattern: bulk_importing_pattern "import Foundation"
|
||||
imported_expr:
|
||||
name_expr
|
||||
identifier: identifier "Foundation"
|
||||
|
||||
===
|
||||
Import with dotted path (two parts)
|
||||
===
|
||||
|
||||
import Foundation.Networking
|
||||
|
||||
---
|
||||
|
||||
source_file
|
||||
statement:
|
||||
import_declaration
|
||||
name:
|
||||
identifier
|
||||
part:
|
||||
simple_identifier "Foundation"
|
||||
simple_identifier "Networking"
|
||||
|
||||
---
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
import_declaration
|
||||
pattern: bulk_importing_pattern "import Foundation.Networking"
|
||||
imported_expr:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "Foundation"
|
||||
member: identifier "Networking"
|
||||
|
||||
===
|
||||
Import with deeply nested path (three parts)
|
||||
===
|
||||
|
||||
import Foundation.Networking.URLSession
|
||||
|
||||
---
|
||||
|
||||
source_file
|
||||
statement:
|
||||
import_declaration
|
||||
name:
|
||||
identifier
|
||||
part:
|
||||
simple_identifier "Foundation"
|
||||
simple_identifier "Networking"
|
||||
simple_identifier "URLSession"
|
||||
|
||||
---
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
import_declaration
|
||||
pattern: bulk_importing_pattern "import Foundation.Networking.URLSession"
|
||||
imported_expr:
|
||||
member_access_expr
|
||||
base:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "Foundation"
|
||||
member: identifier "Networking"
|
||||
member: identifier "URLSession"
|
||||
|
||||
===
|
||||
Scoped import uses name_pattern
|
||||
===
|
||||
|
||||
import struct Foundation.Date
|
||||
|
||||
---
|
||||
|
||||
source_file
|
||||
statement:
|
||||
import_declaration
|
||||
name:
|
||||
identifier
|
||||
part:
|
||||
simple_identifier "Foundation"
|
||||
simple_identifier "Date"
|
||||
scoped_import_kind: struct
|
||||
|
||||
---
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
import_declaration
|
||||
modifier: modifier "struct"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "Date"
|
||||
imported_expr:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "Foundation"
|
||||
member: identifier "Date"
|
||||
|
||||
@@ -31,6 +31,20 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: string_literal "\"hello\""
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
name: identifier "greet"
|
||||
|
||||
===
|
||||
Function with parameters and return type
|
||||
@@ -93,6 +107,37 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
return_expr
|
||||
value:
|
||||
binary_expr
|
||||
operator: infix_operator "+"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
name: identifier "add"
|
||||
parameter:
|
||||
parameter
|
||||
external_name: identifier "_"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "a"
|
||||
parameter
|
||||
external_name: identifier "_"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "b"
|
||||
return_type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
|
||||
===
|
||||
Function with named parameters
|
||||
@@ -138,6 +183,28 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "name"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
name: identifier "greet"
|
||||
parameter:
|
||||
parameter
|
||||
external_name: identifier "person"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "name"
|
||||
|
||||
===
|
||||
Function with default parameter value
|
||||
@@ -185,6 +252,28 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "name"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
name: identifier "greet"
|
||||
parameter:
|
||||
parameter
|
||||
default: string_literal "\"world\""
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "name"
|
||||
|
||||
===
|
||||
Variadic function
|
||||
@@ -249,6 +338,38 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
return_expr
|
||||
value:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: int_literal "0"
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "+"
|
||||
callee:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "values"
|
||||
member: identifier "reduce"
|
||||
name: identifier "sum"
|
||||
parameter:
|
||||
parameter
|
||||
external_name: identifier "_"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "values"
|
||||
return_type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
|
||||
===
|
||||
Function call
|
||||
@@ -276,6 +397,17 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: int_literal "1"
|
||||
argument
|
||||
value: int_literal "2"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "foo"
|
||||
|
||||
===
|
||||
Function call with labelled arguments
|
||||
@@ -306,6 +438,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
name: identifier "person"
|
||||
value: string_literal "\"Bob\""
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "greet"
|
||||
|
||||
===
|
||||
Method call
|
||||
@@ -336,6 +478,18 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: int_literal "1"
|
||||
callee:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "list"
|
||||
member: identifier "append"
|
||||
|
||||
===
|
||||
Generic function
|
||||
@@ -387,3 +541,117 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
return_expr
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
name: identifier "identity"
|
||||
parameter:
|
||||
parameter
|
||||
external_name: identifier "_"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
return_type:
|
||||
named_type_expr
|
||||
name: identifier "T"
|
||||
|
||||
===
|
||||
Leading-dot expression value
|
||||
===
|
||||
|
||||
let x = .foo
|
||||
|
||||
---
|
||||
|
||||
source_file
|
||||
statement:
|
||||
property_declaration
|
||||
binding:
|
||||
value_binding_pattern
|
||||
mutability: let
|
||||
declarator:
|
||||
property_binding
|
||||
name:
|
||||
pattern
|
||||
bound_identifier: simple_identifier "x"
|
||||
value:
|
||||
prefix_expression
|
||||
operation: .
|
||||
target: simple_identifier "foo"
|
||||
|
||||
---
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
value:
|
||||
member_access_expr
|
||||
base: inferred_type_expr ".foo"
|
||||
member: identifier "foo"
|
||||
|
||||
===
|
||||
Leading-dot expression call
|
||||
===
|
||||
|
||||
let y = .some(1)
|
||||
|
||||
---
|
||||
|
||||
source_file
|
||||
statement:
|
||||
property_declaration
|
||||
binding:
|
||||
value_binding_pattern
|
||||
mutability: let
|
||||
declarator:
|
||||
property_binding
|
||||
name:
|
||||
pattern
|
||||
bound_identifier: simple_identifier "y"
|
||||
value:
|
||||
call_expression
|
||||
function:
|
||||
prefix_expression
|
||||
operation: .
|
||||
target: simple_identifier "some"
|
||||
suffix:
|
||||
call_suffix
|
||||
arguments:
|
||||
value_arguments
|
||||
argument:
|
||||
value_argument
|
||||
value: integer_literal "1"
|
||||
|
||||
---
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "y"
|
||||
value:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value: int_literal "1"
|
||||
callee:
|
||||
member_access_expr
|
||||
base: inferred_type_expr ".some"
|
||||
member: identifier "some"
|
||||
|
||||
@@ -13,6 +13,8 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt: int_literal "42"
|
||||
|
||||
===
|
||||
Negative integer literal
|
||||
@@ -32,6 +34,11 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
unary_expr
|
||||
operand: int_literal "7"
|
||||
operator: prefix_operator "-"
|
||||
|
||||
===
|
||||
Floating-point literal
|
||||
@@ -48,6 +55,8 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt: float_literal "3.14"
|
||||
|
||||
===
|
||||
Boolean literals
|
||||
@@ -67,6 +76,10 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
boolean_literal "true"
|
||||
boolean_literal "false"
|
||||
|
||||
===
|
||||
Nil literal
|
||||
@@ -83,6 +96,8 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt: builtin_expr "nil"
|
||||
|
||||
===
|
||||
String literal
|
||||
@@ -101,6 +116,8 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt: string_literal "\"hello\""
|
||||
|
||||
===
|
||||
String with interpolation
|
||||
@@ -122,3 +139,5 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt: string_literal "\"hello \\(name)\""
|
||||
|
||||
@@ -37,6 +37,30 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
for_each_stmt
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
iterable:
|
||||
array_literal
|
||||
element:
|
||||
int_literal "1"
|
||||
int_literal "2"
|
||||
int_literal "3"
|
||||
|
||||
===
|
||||
For-in over range
|
||||
@@ -76,6 +100,29 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
for_each_stmt
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "i"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "i"
|
||||
iterable:
|
||||
binary_expr
|
||||
operator: infix_operator "..<"
|
||||
left: int_literal "0"
|
||||
right: int_literal "10"
|
||||
|
||||
===
|
||||
For-in with where clause
|
||||
@@ -119,6 +166,34 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
for_each_stmt
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
guard:
|
||||
binary_expr
|
||||
operator: infix_operator ">"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
iterable:
|
||||
name_expr
|
||||
identifier: identifier "xs"
|
||||
|
||||
===
|
||||
While loop
|
||||
@@ -154,6 +229,25 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
while_stmt
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
compound_assign_expr
|
||||
operator: infix_operator "-="
|
||||
target:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
value: int_literal "1"
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator ">"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
|
||||
===
|
||||
Repeat-while loop
|
||||
@@ -189,6 +283,25 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
do_while_stmt
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
compound_assign_expr
|
||||
operator: infix_operator "-="
|
||||
target:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
value: int_literal "1"
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator ">"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
|
||||
===
|
||||
Break and continue
|
||||
@@ -252,3 +365,46 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
for_each_stmt
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
if_expr
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator "<"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "0"
|
||||
then:
|
||||
block
|
||||
stmt: continue_expr "continue"
|
||||
if_expr
|
||||
condition:
|
||||
binary_expr
|
||||
operator: infix_operator ">"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
right: int_literal "100"
|
||||
then:
|
||||
block
|
||||
stmt: break_expr "break"
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
iterable:
|
||||
name_expr
|
||||
identifier: identifier "xs"
|
||||
|
||||
@@ -17,6 +17,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "+"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
|
||||
===
|
||||
Subtraction
|
||||
@@ -37,6 +47,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "-"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
|
||||
===
|
||||
Multiplication
|
||||
@@ -57,6 +77,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "*"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
|
||||
===
|
||||
Division
|
||||
@@ -77,6 +107,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "/"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
|
||||
===
|
||||
Operator precedence: addition and multiplication
|
||||
@@ -101,6 +141,22 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "+"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
binary_expr
|
||||
operator: infix_operator "*"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "c"
|
||||
|
||||
===
|
||||
Parenthesised expression
|
||||
@@ -129,6 +185,14 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "*"
|
||||
left: tuple_expr "(a + b)"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "c"
|
||||
|
||||
===
|
||||
Comparison
|
||||
@@ -149,6 +213,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "<"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
|
||||
===
|
||||
Equality
|
||||
@@ -169,6 +243,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "=="
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
|
||||
===
|
||||
Logical and
|
||||
@@ -189,6 +273,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "&&"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
|
||||
===
|
||||
Logical or
|
||||
@@ -209,6 +303,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "||"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
|
||||
===
|
||||
Logical not
|
||||
@@ -228,6 +332,13 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
unary_expr
|
||||
operand:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
operator: prefix_operator "!"
|
||||
|
||||
===
|
||||
Range operator
|
||||
@@ -248,3 +359,9 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
binary_expr
|
||||
operator: infix_operator "..."
|
||||
left: int_literal "1"
|
||||
right: int_literal "10"
|
||||
|
||||
@@ -34,6 +34,22 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
type:
|
||||
generic_type_expr
|
||||
base:
|
||||
named_type_expr
|
||||
name: identifier "Optional"
|
||||
type_argument:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
value: builtin_expr "nil"
|
||||
|
||||
===
|
||||
Optional chaining
|
||||
@@ -74,6 +90,22 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "n"
|
||||
value:
|
||||
member_access_expr
|
||||
base:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "obj"
|
||||
member: identifier "foo"
|
||||
member: identifier "bar"
|
||||
|
||||
===
|
||||
Force unwrap
|
||||
@@ -103,6 +135,19 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "n"
|
||||
value:
|
||||
unary_expr
|
||||
operand:
|
||||
name_expr
|
||||
identifier: identifier "opt"
|
||||
operator: postfix_operator "!"
|
||||
|
||||
===
|
||||
Nil-coalescing
|
||||
@@ -132,6 +177,20 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "n"
|
||||
value:
|
||||
binary_expr
|
||||
operator: infix_operator "??"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "opt"
|
||||
right: int_literal "0"
|
||||
|
||||
===
|
||||
Throwing function
|
||||
@@ -167,6 +226,18 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
return_expr
|
||||
value: string_literal "\"\""
|
||||
name: identifier "read"
|
||||
return_type:
|
||||
named_type_expr
|
||||
name: identifier "String"
|
||||
|
||||
===
|
||||
Do-catch
|
||||
@@ -216,6 +287,33 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
try_expr
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
unary_expr
|
||||
operand:
|
||||
call_expr
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "foo"
|
||||
operator: prefix_operator "try"
|
||||
catch_clause:
|
||||
catch_clause
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
call_expr
|
||||
argument:
|
||||
argument
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "error"
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "print"
|
||||
|
||||
===
|
||||
Try? expression
|
||||
@@ -252,6 +350,21 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "result"
|
||||
value:
|
||||
unary_expr
|
||||
operand:
|
||||
call_expr
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "foo"
|
||||
operator: prefix_operator "try?"
|
||||
|
||||
===
|
||||
Try! expression
|
||||
@@ -288,3 +401,18 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "result"
|
||||
value:
|
||||
unary_expr
|
||||
operand:
|
||||
call_expr
|
||||
callee:
|
||||
name_expr
|
||||
identifier: identifier "foo"
|
||||
operator: prefix_operator "try!"
|
||||
|
||||
@@ -18,6 +18,11 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
modifier: modifier "class"
|
||||
name: identifier "Foo"
|
||||
|
||||
===
|
||||
Class with stored properties
|
||||
@@ -79,6 +84,28 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "y"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
modifier: modifier "class"
|
||||
name: identifier "Point"
|
||||
|
||||
===
|
||||
Class with initializer
|
||||
@@ -152,6 +179,34 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
constructor_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
assign_expr
|
||||
target:
|
||||
member_access_expr
|
||||
base:
|
||||
name_expr
|
||||
identifier: identifier "self"
|
||||
member: identifier "x"
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
modifier: modifier "class"
|
||||
name: identifier "Point"
|
||||
|
||||
===
|
||||
Class with method
|
||||
@@ -200,6 +255,29 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "n"
|
||||
value: int_literal "0"
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
compound_assign_expr
|
||||
operator: infix_operator "+="
|
||||
target:
|
||||
name_expr
|
||||
identifier: identifier "n"
|
||||
value: int_literal "1"
|
||||
name: identifier "bump"
|
||||
modifier: modifier "class"
|
||||
name: identifier "Counter"
|
||||
|
||||
===
|
||||
Class inheritance
|
||||
@@ -228,6 +306,11 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
modifier: modifier "class"
|
||||
name: identifier "Dog"
|
||||
|
||||
===
|
||||
Struct
|
||||
@@ -289,6 +372,28 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "y"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
modifier: modifier "struct"
|
||||
name: identifier "Point"
|
||||
|
||||
===
|
||||
Enum with cases
|
||||
@@ -332,6 +437,32 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
variable_declaration
|
||||
modifier: modifier "enum_case"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "north"
|
||||
variable_declaration
|
||||
modifier: modifier "enum_case"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "south"
|
||||
variable_declaration
|
||||
modifier: modifier "enum_case"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "east"
|
||||
variable_declaration
|
||||
modifier: modifier "enum_case"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "west"
|
||||
modifier: modifier "enum"
|
||||
name: identifier "Direction"
|
||||
|
||||
===
|
||||
Enum with associated values
|
||||
@@ -389,6 +520,40 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
class_like_declaration
|
||||
member:
|
||||
constructor_declaration
|
||||
body: block "circle(radius: Double)"
|
||||
parameter:
|
||||
parameter
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "radius"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Double"
|
||||
modifier: modifier "enum_case"
|
||||
name: identifier "circle"
|
||||
class_like_declaration
|
||||
member:
|
||||
constructor_declaration
|
||||
body: block "square(side: Double)"
|
||||
parameter:
|
||||
parameter
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "side"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Double"
|
||||
modifier: modifier "enum_case"
|
||||
name: identifier "square"
|
||||
modifier: modifier "enum"
|
||||
name: identifier "Shape"
|
||||
|
||||
===
|
||||
Protocol declaration
|
||||
@@ -414,6 +579,15 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
function_declaration
|
||||
body: block "func draw()"
|
||||
name: identifier "draw"
|
||||
modifier: modifier "protocol"
|
||||
name: identifier "Drawable"
|
||||
|
||||
===
|
||||
Extension
|
||||
@@ -463,6 +637,30 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
function_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
return_expr
|
||||
value:
|
||||
binary_expr
|
||||
operator: infix_operator "*"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "self"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "self"
|
||||
name: identifier "squared"
|
||||
return_type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
modifier: modifier "extension"
|
||||
name: identifier "Int"
|
||||
|
||||
===
|
||||
Computed property
|
||||
@@ -555,6 +753,48 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "w"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Double"
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "h"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Double"
|
||||
accessor_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
return_expr
|
||||
value:
|
||||
binary_expr
|
||||
operator: infix_operator "*"
|
||||
left:
|
||||
name_expr
|
||||
identifier: identifier "w"
|
||||
right:
|
||||
name_expr
|
||||
identifier: identifier "h"
|
||||
modifier: modifier "var"
|
||||
name: identifier "area"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Double"
|
||||
accessor_kind: accessor_kind "get"
|
||||
modifier: modifier "class"
|
||||
name: identifier "Rect"
|
||||
|
||||
===
|
||||
Property with getter and setter
|
||||
@@ -639,3 +879,48 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
class_like_declaration
|
||||
member:
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "_v"
|
||||
value: int_literal "0"
|
||||
accessor_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
return_expr
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "_v"
|
||||
modifier: modifier "var"
|
||||
name: identifier "v"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
accessor_kind: accessor_kind "get"
|
||||
accessor_declaration
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
assign_expr
|
||||
target:
|
||||
name_expr
|
||||
identifier: identifier "_v"
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "newValue"
|
||||
modifier:
|
||||
modifier "var"
|
||||
modifier "chained_declaration"
|
||||
name: identifier "v"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
accessor_kind: accessor_kind "set"
|
||||
modifier: modifier "class"
|
||||
name: identifier "Box"
|
||||
|
||||
@@ -23,6 +23,14 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
value: int_literal "1"
|
||||
|
||||
===
|
||||
Var binding
|
||||
@@ -49,6 +57,14 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
value: int_literal "1"
|
||||
|
||||
===
|
||||
Let with type annotation
|
||||
@@ -84,6 +100,17 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
value: int_literal "1"
|
||||
|
||||
===
|
||||
Var without initialiser
|
||||
@@ -118,6 +145,16 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "var"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
type:
|
||||
named_type_expr
|
||||
name: identifier "Int"
|
||||
|
||||
===
|
||||
Tuple destructuring binding
|
||||
@@ -154,6 +191,28 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
tuple_pattern
|
||||
element:
|
||||
pattern_element
|
||||
pattern:
|
||||
expr_equality_pattern
|
||||
expr:
|
||||
name_expr
|
||||
identifier: identifier "a"
|
||||
pattern_element
|
||||
pattern:
|
||||
expr_equality_pattern
|
||||
expr:
|
||||
name_expr
|
||||
identifier: identifier "b"
|
||||
value:
|
||||
name_expr
|
||||
identifier: identifier "pair"
|
||||
|
||||
===
|
||||
Multiple bindings on one line
|
||||
@@ -185,6 +244,22 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
variable_declaration
|
||||
modifier: modifier "let"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "x"
|
||||
value: int_literal "1"
|
||||
variable_declaration
|
||||
modifier:
|
||||
modifier "let"
|
||||
modifier "chained_declaration"
|
||||
pattern:
|
||||
name_pattern
|
||||
identifier: identifier "y"
|
||||
value: int_literal "2"
|
||||
|
||||
===
|
||||
Assignment
|
||||
@@ -207,6 +282,13 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
assign_expr
|
||||
target:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
value: int_literal "1"
|
||||
|
||||
===
|
||||
Compound assignment
|
||||
@@ -229,3 +311,11 @@ source_file
|
||||
|
||||
top_level
|
||||
body:
|
||||
block
|
||||
stmt:
|
||||
compound_assign_expr
|
||||
operator: infix_operator "+="
|
||||
target:
|
||||
name_expr
|
||||
identifier: identifier "x"
|
||||
value: int_literal "1"
|
||||
|
||||
@@ -1368,7 +1368,7 @@ module.exports = grammar({
|
||||
seq(
|
||||
field("modifiers", optional($.modifiers)),
|
||||
"import",
|
||||
optional($._import_kind),
|
||||
optional(field("scoped_import_kind", $._import_kind)),
|
||||
field("name", $.identifier)
|
||||
),
|
||||
_import_kind: ($) =>
|
||||
@@ -1930,7 +1930,7 @@ module.exports = grammar({
|
||||
seq(
|
||||
optional("case"),
|
||||
optional(field("type", $.user_type)), // XXX this should just be _type but that creates ambiguity
|
||||
$._dot,
|
||||
field("dot", $._dot),
|
||||
field("name", $.simple_identifier),
|
||||
optional(field("arguments", $.tuple_pattern))
|
||||
),
|
||||
|
||||
@@ -173,6 +173,7 @@ named:
|
||||
value?: expression
|
||||
case_pattern:
|
||||
arguments?: tuple_pattern
|
||||
dot: "."
|
||||
name: simple_identifier
|
||||
type?: user_type
|
||||
catch_block:
|
||||
@@ -351,6 +352,7 @@ named:
|
||||
import_declaration:
|
||||
modifiers?: modifiers
|
||||
name: identifier
|
||||
scoped_import_kind?: ["class", "enum", "func", "let", "protocol", "struct", "typealias", "var"]
|
||||
infix_expression:
|
||||
lhs: expression
|
||||
op: custom_operator
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,37 @@
|
||||
nameExpr
|
||||
| name_expr.swift:1:9:1:9 | NameExpr | y |
|
||||
| test.swift:1:8:1:17 | NameExpr | Foundation |
|
||||
| test.swift:8:9:8:13 | NameExpr | items |
|
||||
| test.swift:8:22:8:25 | NameExpr | item |
|
||||
| test.swift:12:16:12:20 | NameExpr | items |
|
||||
| test.swift:12:31:12:34 | NameExpr | item |
|
||||
| test.swift:25:18:25:22 | NameExpr | Array |
|
||||
| test.swift:25:24:25:28 | NameExpr | first |
|
||||
| test.swift:26:17:26:22 | NameExpr | second |
|
||||
| test.swift:27:13:27:18 | NameExpr | result |
|
||||
| test.swift:27:29:27:32 | NameExpr | item |
|
||||
| test.swift:28:13:28:18 | NameExpr | result |
|
||||
| test.swift:28:27:28:30 | NameExpr | item |
|
||||
| test.swift:31:12:31:17 | NameExpr | result |
|
||||
| test.swift:40:16:40:19 | NameExpr | data |
|
||||
| test.swift:44:9:44:12 | NameExpr | data |
|
||||
| test.swift:48:15:48:19 | NameExpr | index |
|
||||
| test.swift:48:29:48:33 | NameExpr | index |
|
||||
| test.swift:48:37:48:40 | NameExpr | data |
|
||||
| test.swift:49:16:49:19 | NameExpr | data |
|
||||
| test.swift:49:21:49:25 | NameExpr | index |
|
||||
| test.swift:53:9:53:12 | NameExpr | data |
|
||||
| test.swift:53:21:53:24 | NameExpr | item |
|
||||
| test.swift:63:16:63:19 | NameExpr | self |
|
||||
| test.swift:65:29:65:37 | NameExpr | transform |
|
||||
| test.swift:65:39:65:43 | NameExpr | value |
|
||||
| test.swift:67:29:67:33 | NameExpr | error |
|
||||
| test.swift:76:16:76:19 | NameExpr | self |
|
||||
| test.swift:76:21:76:21 | NameExpr | i |
|
||||
| test.swift:76:26:76:29 | NameExpr | self |
|
||||
| test.swift:76:31:76:31 | NameExpr | i |
|
||||
| test.swift:86:12:86:17 | NameExpr | values |
|
||||
| test.swift:87:12:87:17 | NameExpr | values |
|
||||
| test.swift:87:38:87:43 | NameExpr | values |
|
||||
| test.swift:87:49:87:57 | NameExpr | transform |
|
||||
unsupported
|
||||
| test.swift:3:1:3:38 | | |
|
||||
| test.swift:16:1:16:32 | | |
|
||||
| test.swift:23:1:23:37 | | |
|
||||
| test.swift:34:1:34:49 | | |
|
||||
| test.swift:57:1:57:30 | | |
|
||||
| test.swift:72:1:72:37 | | |
|
||||
| test.swift:84:1:84:24 | | |
|
||||
|
||||
Reference in New Issue
Block a user