Merge pull request #22233 from github/tausbn/swift-syntax-rs-sequenced

unified: Switch over to using `swift-syntax` for parsing
This commit is contained in:
Taus
2026-07-28 16:06:15 +02:00
committed by GitHub
135 changed files with 7773 additions and 4002 deletions

BIN
ql/Cargo.lock generated

Binary file not shown.

View File

@@ -29,28 +29,24 @@ pub fn run(options: Options) -> std::io::Result<()> {
prefix: "ql",
ts_language: tree_sitter_ql::LANGUAGE.into(),
node_types: tree_sitter_ql::NODE_TYPES,
desugar: None,
file_globs: vec!["*.ql".into(), "*.qll".into()],
},
simple::LanguageSpec {
prefix: "dbscheme",
ts_language: tree_sitter_ql_dbscheme::LANGUAGE.into(),
node_types: tree_sitter_ql_dbscheme::NODE_TYPES,
desugar: None,
file_globs: vec!["*.dbscheme".into()],
},
simple::LanguageSpec {
prefix: "json",
ts_language: tree_sitter_json::LANGUAGE.into(),
node_types: tree_sitter_json::NODE_TYPES,
desugar: None,
file_globs: vec!["*.json".into(), "*.jsonl".into(), "*.jsonc".into()],
},
simple::LanguageSpec {
prefix: "blame",
ts_language: tree_sitter_blame::LANGUAGE.into(),
node_types: tree_sitter_blame::NODE_TYPES,
desugar: None,
file_globs: vec!["*.blame".into()],
},
],

View File

@@ -94,7 +94,9 @@ pub fn run(options: Options) -> std::io::Result<()> {
node_types::read_node_types_str("erb", tree_sitter_embedded_template::NODE_TYPES)?;
let lines: std::io::Result<Vec<String>> = std::io::BufReader::new(file_list).lines().collect();
let lines = lines?;
let source_root = std::env::current_dir().ok().and_then(|d| d.canonicalize().ok());
let source_root = std::env::current_dir()
.ok()
.and_then(|d| d.canonicalize().ok());
lines
.par_iter()
.try_for_each(|line| {
@@ -126,7 +128,6 @@ pub fn run(options: Options) -> std::io::Result<()> {
&path,
&source,
&[],
None,
);
let (ranges, line_breaks) = scan_erb(
@@ -215,7 +216,6 @@ pub fn run(options: Options) -> std::io::Result<()> {
&path,
&source,
&code_ranges,
None,
);
std::fs::create_dir_all(src_archive_file.parent().unwrap())?;
if needs_conversion {

View File

@@ -0,0 +1,104 @@
//! Extraction for languages that rewrite their syntax tree before extraction.
//!
//! Unlike [`crate::extractor::simple`] (direct tree-sitter extraction), a
//! desugaring language parses source into a [`ParsedTree`] — a `yeast::Ast`
//! plus side-channel `extra` tokens (comments and similar) — and rewrites the
//! AST through a [`yeast::Desugarer`] before emitting TRAP. The parser is a
//! closure, so both tree-sitter grammars (via
//! [`crate::extractor::tree_sitter_parser`]) and fully custom parsers plug in
//! the same way.
use crate::trap;
use std::path::PathBuf;
use crate::diagnostics;
use crate::extractor::ParsedTree;
use crate::extractor::driver::{self, LanguageExtractor};
use crate::node_types::{self, NodeTypeMap};
/// A parser turns source bytes into a [`ParsedTree`]. Tree-sitter grammars plug
/// in via [`crate::extractor::tree_sitter_parser`]; custom (non-tree-sitter)
/// parsers supply their own closure.
pub type Parser = Box<dyn Fn(&[u8]) -> Result<ParsedTree, String> + Send + Sync>;
pub struct LanguageSpec {
pub prefix: &'static str,
/// The parser: source -> `yeast::Ast` + `extra` tokens (see [`Parser`]).
pub parser: Parser,
/// Fallback TRAP schema, used only when `desugarer` does not supply its own
/// output schema (via [`yeast::Desugarer::output_node_types_yaml`]). May be
/// empty for a custom parser whose desugarer always provides the schema.
pub node_types: &'static str,
/// The desugarer applied to the parsed AST before extraction. Its
/// `output_node_types_yaml()` (when set) provides the TRAP schema.
///
/// `Box<dyn yeast::Desugarer>` so the shared extractor is agnostic to the
/// user-defined context type the desugarer uses internally.
pub desugarer: Box<dyn yeast::Desugarer>,
pub file_globs: Vec<String>,
}
impl LanguageExtractor for LanguageSpec {
fn file_globs(&self) -> &[String] {
&self.file_globs
}
fn build_schema(&self) -> std::io::Result<NodeTypeMap> {
let effective_node_types: String = match self.desugarer.output_node_types_yaml() {
Some(yaml) => yeast::node_types_yaml::convert(yaml).map_err(|e| {
std::io::Error::other(format!(
"Failed to convert YAML node-types to JSON for {}: {e}",
self.prefix
))
})?,
None => self.node_types.to_string(),
};
node_types::read_node_types_str(self.prefix, &effective_node_types)
}
fn extract_file(
&self,
schema: &NodeTypeMap,
diagnostics_writer: &mut diagnostics::LogWriter,
trap_writer: &mut trap::Writer,
path: &std::path::Path,
source: &[u8],
) {
crate::extractor::extract_parsed(
self.parser.as_ref(),
self.prefix,
schema,
diagnostics_writer,
trap_writer,
None,
path,
source,
self.desugarer.as_ref(),
);
}
}
pub struct Extractor {
pub prefix: String,
pub languages: Vec<LanguageSpec>,
pub trap_dir: PathBuf,
pub source_archive_dir: PathBuf,
pub file_lists: Vec<PathBuf>,
// Typically constructed via `trap::Compression::from_env`.
// This allow us to report the error using our diagnostics system
// without exposing it to consumers.
pub trap_compression: Result<trap::Compression, String>,
}
impl Extractor {
pub fn run(&self) -> std::io::Result<()> {
driver::run_extractor(
&self.prefix,
&self.languages,
&self.trap_dir,
&self.source_archive_dir,
&self.file_lists,
&self.trap_compression,
)
}
}

View File

@@ -0,0 +1,210 @@
//! Shared multi-file extraction driver.
//!
//! The `simple` (direct tree-sitter) and `desugaring` (parse + desugar)
//! extractors differ only in how a language's schema is built and how a single
//! file is extracted. Everything else — threading, matching files to languages
//! by glob, writing TRAP, and copying into the source archive — is identical
//! and lives here, parameterised over the [`LanguageExtractor`] trait.
use globset::{GlobBuilder, GlobSetBuilder};
use rayon::prelude::*;
use std::fs::File;
use std::io::BufRead;
use std::path::{Path, PathBuf};
use crate::diagnostics;
use crate::file_paths;
use crate::node_types::NodeTypeMap;
use crate::trap;
/// A language that [`run_extractor`] can process: it knows its file globs, its
/// TRAP schema, and how to extract a single file. Implemented by
/// [`super::simple::LanguageSpec`] (direct tree-sitter extraction) and
/// [`super::desugaring::LanguageSpec`] (parse into an AST and desugar it).
pub(crate) trait LanguageExtractor: Sync {
/// The file-name globs that select files for this language.
fn file_globs(&self) -> &[String];
/// Build the TRAP node-type schema used to validate emitted tuples.
fn build_schema(&self) -> std::io::Result<NodeTypeMap>;
/// Extract a single file's `source` into `trap_writer`.
fn extract_file(
&self,
schema: &NodeTypeMap,
diagnostics_writer: &mut diagnostics::LogWriter,
trap_writer: &mut trap::Writer,
path: &Path,
source: &[u8],
);
}
/// Drive extraction over `languages` for every file listed in `file_lists`.
///
/// Sets up the thread pool, builds a combined glob set, and for each input file
/// dispatches to the matching language's [`LanguageExtractor::extract_file`],
/// writing the resulting TRAP and a source-archive copy.
pub(crate) fn run_extractor<L: LanguageExtractor>(
prefix: &str,
languages: &[L],
trap_dir: &Path,
source_archive_dir: &Path,
file_lists: &[PathBuf],
trap_compression: &Result<trap::Compression, String>,
) -> std::io::Result<()> {
tracing::info!("Extraction started");
let diagnostics = diagnostics::DiagnosticLoggers::new(prefix);
let mut main_thread_logger = diagnostics.logger();
let num_threads = match crate::options::num_threads() {
Ok(num) => num,
Err(e) => {
main_thread_logger.write(
main_thread_logger
.new_entry("configuration-error", "Configuration error")
.message(
"{}; defaulting to 1 thread.",
&[diagnostics::MessageArg::Code(&e)],
)
.severity(diagnostics::Severity::Warning),
);
1
}
};
tracing::info!(
"Using {} {}",
num_threads,
if num_threads == 1 {
"thread"
} else {
"threads"
}
);
let trap_compression = match trap_compression {
Ok(x) => *x,
Err(e) => {
main_thread_logger.write(
main_thread_logger
.new_entry("configuration-error", "Configuration error")
.message("{}; using gzip.", &[diagnostics::MessageArg::Code(e)])
.severity(diagnostics::Severity::Warning),
);
trap::Compression::Gzip
}
};
drop(main_thread_logger);
rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
.build_global()
.unwrap();
let file_lists: Vec<File> = file_lists
.iter()
.map(|file_list| {
File::open(file_list)
.unwrap_or_else(|_| panic!("Unable to open file list at {file_list:?}"))
})
.collect();
let mut schemas = vec![];
for lang in languages {
schemas.push(lang.build_schema()?);
}
// Construct a single globset containing all language globs,
// and a mapping from glob index to language index.
let (globset, glob_language_mapping) = {
let mut builder = GlobSetBuilder::new();
let mut glob_lang_mapping = vec![];
for (i, lang) in languages.iter().enumerate() {
for glob_str in lang.file_globs() {
let glob = GlobBuilder::new(glob_str)
.literal_separator(true)
.build()
.expect("invalid glob");
builder.add(glob);
glob_lang_mapping.push(i);
}
}
(
builder.build().expect("failed to build globset"),
glob_lang_mapping,
)
};
let path_transformer = file_paths::load_path_transformer()?;
let lines: std::io::Result<Vec<String>> = file_lists
.iter()
.flat_map(|file_list| std::io::BufReader::new(file_list).lines())
.collect();
let lines = lines?;
lines
.par_iter()
.try_for_each(|line| {
let mut diagnostics_writer = diagnostics.logger();
let path = PathBuf::from(line).canonicalize()?;
let src_archive_file = crate::file_paths::path_for(
source_archive_dir,
&path,
"",
path_transformer.as_ref(),
);
let source = std::fs::read(&path)?;
let mut trap_writer = trap::Writer::new();
match path.file_name() {
None => {
tracing::error!(?path, "No file name found, skipping file.");
}
Some(filename) => {
let matches = globset.matches(filename);
if matches.is_empty() {
tracing::error!(?path, "No matching language found, skipping file.");
} else {
let mut languages_processed = vec![false; languages.len()];
for m in matches {
let i = glob_language_mapping[m];
if languages_processed[i] {
continue;
}
languages_processed[i] = true;
let lang = &languages[i];
lang.extract_file(
&schemas[i],
&mut diagnostics_writer,
&mut trap_writer,
&path,
&source,
);
std::fs::create_dir_all(src_archive_file.parent().unwrap())?;
std::fs::copy(&path, &src_archive_file)?;
write_trap(trap_dir, &path, &trap_writer, trap_compression)?;
}
}
}
}
Ok(()) as std::io::Result<()>
})
.expect("failed to extract files");
let path = PathBuf::from("extras");
let mut trap_writer = trap::Writer::new();
crate::extractor::populate_empty_location(&mut trap_writer);
let res = write_trap(trap_dir, &path, &trap_writer, trap_compression);
tracing::info!("Extraction complete");
res
}
fn write_trap(
trap_dir: &Path,
path: &Path,
trap_writer: &trap::Writer,
trap_compression: trap::Compression,
) -> std::io::Result<()> {
let trap_file = crate::file_paths::path_for(trap_dir, path, trap_compression.extension(), None);
std::fs::create_dir_all(trap_file.parent().unwrap())?;
trap_writer.write_to_file(&trap_file, trap_compression)
}

View File

@@ -16,6 +16,8 @@ use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tree_sitter::{Language, Node, Parser, Range, Tree};
pub mod desugaring;
mod driver;
pub mod simple;
/// Trait abstracting over tree-sitter and yeast node types for extraction.
@@ -294,6 +296,10 @@ pub fn location_label(writer: &mut trap::Writer, location: trap::Location) -> tr
/// caller's responsibility, allowing it to be done once and shared across
/// files.
#[allow(clippy::too_many_arguments)]
/// Extract a file with a tree-sitter grammar, walking the parse tree directly.
/// Comments and other `extra` nodes are emitted inline as tokens. This is the
/// path for languages that don't desugar their syntax tree (and hence have no
/// `extra` side channel); desugaring languages use [`extract_parsed`] instead.
pub fn extract(
language: &Language,
language_prefix: &str,
@@ -304,7 +310,6 @@ pub fn extract(
path: &Path,
source: &[u8],
ranges: &[Range],
desugarer: Option<&dyn yeast::Desugarer>,
) {
let path_str = file_paths::normalize_and_transform_path(path, transformer);
let source_root = std::env::current_dir()
@@ -337,21 +342,173 @@ pub fn extract(
schema,
);
if let Some(desugarer) = desugarer {
let ast = desugarer
.run_from_tree(&tree, source)
.unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}"));
traverse_yeast(&ast, &mut visitor);
// Comments and other `extra` nodes are not represented in the desugared
// AST, so recover them directly from the original parse tree.
traverse_extras(&tree, &mut visitor);
} else {
traverse(&tree, &mut visitor);
}
traverse(&tree, &mut visitor);
parser.reset();
}
/// A source tree produced by a parser: the raw `yeast::Ast` (pre-desugaring)
/// plus side-channel `extra` tokens (comments and similar) that are not
/// attached to the AST proper.
pub struct ParsedTree {
pub ast: yeast::Ast,
pub extras: Vec<ExtraToken>,
}
/// A piece of side-channel `extra` content (a comment or unexpected text)
/// recovered by a parser. `kind` is a language-defined id written verbatim into
/// the `<lang>_trivia_tokeninfo` table (the tree-sitter parser uses the
/// grammar's node kind id here; a custom parser supplies its own stable
/// enumeration).
pub struct ExtraToken {
pub kind: usize,
pub range: yeast::Range,
pub text: String,
}
/// Build a parser closure that parses `source` with a tree-sitter `language`,
/// producing a [`ParsedTree`]: a `yeast::Ast` (via [`yeast::Ast::from_tree`])
/// plus the `extra` nodes (comments and similar) recovered as side-channel
/// tokens. This lets a tree-sitter language plug into the same
/// `ParsedTree`-producing interface as a custom parser.
pub fn tree_sitter_parser(
language: tree_sitter::Language,
) -> impl Fn(&[u8]) -> Result<ParsedTree, String> + Send + Sync {
move |source: &[u8]| {
let mut parser = Parser::new();
parser
.set_language(&language)
.map_err(|e| format!("failed to set tree-sitter language: {e}"))?;
let tree = parser
.parse(source, None)
.ok_or_else(|| "tree-sitter failed to parse".to_string())?;
let ast = yeast::Ast::from_tree_with_schema_and_source(
yeast::schema::from_language(&language),
&tree,
&language,
source.to_vec(),
);
let mut extras = Vec::new();
collect_extras(tree.root_node(), source, &mut extras);
Ok(ParsedTree { ast, extras })
}
}
/// Collect `extra` nodes (comments and similar) under `node` into `out` as
/// [`ExtraToken`]s, keyed by the grammar's node kind id, for a desugaring
/// language whose rewritten AST won't retain them.
fn collect_extras(node: Node<'_>, source: &[u8], out: &mut Vec<ExtraToken>) {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
if child.is_extra() {
let text = String::from_utf8_lossy(&source[child.byte_range()]).into_owned();
out.push(ExtraToken {
kind: child.kind_id() as usize,
range: child.range().into(),
text,
});
} else {
collect_extras(child, source, out);
}
}
}
/// Extract a file from a [`ParsedTree`]-producing parser that desugars. The
/// parser yields a `yeast::Ast` plus side-channel `extra` tokens; the AST is
/// rewritten through `desugarer` ([`yeast::Desugarer::run_from_ast`]) before
/// TRAP extraction, and the `extra` tokens (comments and similar, which the
/// desugared AST does not carry) are emitted from the side channel. Both
/// tree-sitter grammars (via [`tree_sitter_parser`]) and custom parsers plug in
/// here; languages that don't desugar use [`extract`] instead.
#[allow(clippy::too_many_arguments)]
pub fn extract_parsed(
parse: &(dyn Fn(&[u8]) -> Result<ParsedTree, String> + Send + Sync),
language_prefix: &str,
schema: &NodeTypeMap,
diagnostics_writer: &mut diagnostics::LogWriter,
trap_writer: &mut trap::Writer,
transformer: Option<&file_paths::PathTransformer>,
path: &Path,
source: &[u8],
desugarer: &dyn yeast::Desugarer,
) {
let path_str = file_paths::normalize_and_transform_path(path, transformer);
let source_root = std::env::current_dir()
.ok()
.and_then(|d| d.canonicalize().ok());
let diagnostics_path = file_paths::relativize_for_diagnostic(path, source_root.as_deref());
let span = tracing::span!(tracing::Level::TRACE, "extract", file = %path_str);
let _enter = span.enter();
tracing::debug!("extracting: {}", path_str);
trap_writer.comment(format!("Auto-generated TRAP file for {path_str}"));
let file_label = populate_file(trap_writer, path, transformer);
let mut visitor = Visitor::new(
source,
diagnostics_writer,
trap_writer,
&diagnostics_path,
file_label,
language_prefix,
schema,
);
let parsed = parse(source).unwrap_or_else(|e| panic!("Parsing failed for {path_str}: {e}"));
let ast = desugarer
.run_from_ast(parsed.ast)
.unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}"));
traverse_yeast(&ast, &mut visitor);
// Comments and other `extra` tokens are not part of the desugared AST; emit
// them directly from the parser's side channel.
for extra in &parsed.extras {
visitor.emit_extra(extra);
}
}
/// A lightweight [`AstNode`] over a piece of side-channel `extra` content
/// recovered by a custom parser, so it can reuse the tree-sitter location
/// machinery.
struct ExtraNode {
range: yeast::Range,
text: String,
}
impl AstNode for ExtraNode {
fn kind(&self) -> &str {
"extra"
}
fn is_named(&self) -> bool {
false
}
fn is_missing(&self) -> bool {
false
}
fn is_error(&self) -> bool {
false
}
fn is_extra(&self) -> bool {
true
}
fn start_position(&self) -> tree_sitter::Point {
tree_sitter::Point {
row: self.range.start_point.row,
column: self.range.start_point.column,
}
}
fn end_position(&self) -> tree_sitter::Point {
tree_sitter::Point {
row: self.range.end_point.row,
column: self.range.end_point.column,
}
}
fn byte_range(&self) -> std::ops::Range<usize> {
self.range.start_byte..self.range.end_byte
}
fn opt_string_content(&self) -> Option<String> {
Some(self.text.clone())
}
}
struct ChildNode {
field_name: Option<&'static str>,
label: trap::Label,
@@ -415,10 +572,11 @@ impl<'a> Visitor<'a> {
}
}
/// Emits a `TriviaToken` for the given `extra` node (e.g. a comment) from
/// the original parse tree. Trivia tokens carry a location and their source
/// text, but are not attached to a parent in the (possibly desugared) AST.
fn emit_trivia_token(&mut self, node: &Node) {
/// Emit an `extra` token (a location row plus a `trivia_tokeninfo` row) for
/// any [`AstNode`], with an explicit `kind` id. Shared by the tree-sitter
/// path (kind = the grammar's node kind id) and the custom-parser path
/// (kind = a language-defined `extra` kind id).
fn emit_extra_from<N: AstNode>(&mut self, node: &N, kind: usize) {
let id = self.trap_writer.fresh_id();
let loc = location_for(self, self.file_label, node);
let loc_label = location_label(self.trap_writer, loc);
@@ -430,12 +588,21 @@ impl<'a> Visitor<'a> {
&self.trivia_tokeninfo_table_name,
vec![
trap::Arg::Label(id),
trap::Arg::Int(node.kind_id() as usize),
trap::Arg::Int(kind),
sliced_source_arg(self.source, node),
],
);
}
/// Emit an `extra` token recovered from a parser's side channel.
fn emit_extra(&mut self, extra: &ExtraToken) {
let node = ExtraNode {
range: extra.range,
text: extra.text.clone(),
};
self.emit_extra_from(&node, extra.kind);
}
fn record_parse_error(&mut self, loc: trap::Label, mesg: &diagnostics::DiagnosticMessage) {
self.diagnostics_writer.write(mesg);
let id = self.trap_writer.fresh_id();
@@ -871,24 +1038,6 @@ fn traverse(tree: &Tree, visitor: &mut Visitor) {
}
}
/// Walks the original tree-sitter tree and emits a `TriviaToken` for every
/// `extra` node (e.g. a comment). Used to preserve comments that would
/// otherwise be lost after a desugaring pass rewrites the tree.
fn traverse_extras(tree: &Tree, visitor: &mut Visitor) {
emit_extras_in(visitor, tree.root_node());
}
fn emit_extras_in(visitor: &mut Visitor, node: Node<'_>) {
let mut cursor = node.walk();
for child in node.children(&mut cursor) {
if child.is_extra() {
visitor.emit_trivia_token(&child);
} else {
emit_extras_in(visitor, child);
}
}
}
fn traverse_yeast(tree: &yeast::Ast, visitor: &mut Visitor) {
let mut cursor = tree.walk();
visitor.enter_node(cursor.node());

View File

@@ -1,29 +1,52 @@
use crate::{file_paths, trap};
use globset::{GlobBuilder, GlobSetBuilder};
use rayon::prelude::*;
use std::fs::File;
use std::io::BufRead;
use std::path::{Path, PathBuf};
use crate::trap;
use std::path::PathBuf;
use crate::diagnostics;
use crate::node_types;
use yeast;
use crate::extractor::driver::{self, LanguageExtractor};
use crate::node_types::{self, NodeTypeMap};
/// A tree-sitter language extracted directly from its parse tree, with no
/// desugaring. Comments and other `extra` nodes are emitted inline as tokens.
/// Languages that rewrite their syntax tree use
/// [`crate::extractor::desugaring`] instead.
pub struct LanguageSpec {
pub prefix: &'static str,
pub ts_language: tree_sitter::Language,
pub node_types: &'static str,
/// Optional desugarer. When set, the parsed tree is rewritten through
/// the desugarer before TRAP extraction. The desugarer's
/// `output_node_types_yaml()` (if set) provides the schema used both
/// at runtime (for the rewriter) and for TRAP validation.
///
/// `Box<dyn yeast::Desugarer>` so the shared extractor is agnostic to
/// the user-defined context type the desugarer uses internally.
pub desugar: Option<Box<dyn yeast::Desugarer>>,
pub file_globs: Vec<String>,
}
impl LanguageExtractor for LanguageSpec {
fn file_globs(&self) -> &[String] {
&self.file_globs
}
fn build_schema(&self) -> std::io::Result<NodeTypeMap> {
node_types::read_node_types_str(self.prefix, self.node_types)
}
fn extract_file(
&self,
schema: &NodeTypeMap,
diagnostics_writer: &mut diagnostics::LogWriter,
trap_writer: &mut trap::Writer,
path: &std::path::Path,
source: &[u8],
) {
crate::extractor::extract(
&self.ts_language,
self.prefix,
schema,
diagnostics_writer,
trap_writer,
None,
path,
source,
&[],
);
}
}
pub struct Extractor {
pub prefix: String,
pub languages: Vec<LanguageSpec>,
@@ -38,182 +61,13 @@ pub struct Extractor {
impl Extractor {
pub fn run(&self) -> std::io::Result<()> {
tracing::info!("Extraction started");
let diagnostics = diagnostics::DiagnosticLoggers::new(&self.prefix);
let mut main_thread_logger = diagnostics.logger();
let num_threads = match crate::options::num_threads() {
Ok(num) => num,
Err(e) => {
main_thread_logger.write(
main_thread_logger
.new_entry("configuration-error", "Configuration error")
.message(
"{}; defaulting to 1 thread.",
&[diagnostics::MessageArg::Code(&e)],
)
.severity(diagnostics::Severity::Warning),
);
1
}
};
tracing::info!(
"Using {} {}",
num_threads,
if num_threads == 1 {
"thread"
} else {
"threads"
}
);
let trap_compression = match &self.trap_compression {
Ok(x) => *x,
Err(e) => {
main_thread_logger.write(
main_thread_logger
.new_entry("configuration-error", "Configuration error")
.message("{}; using gzip.", &[diagnostics::MessageArg::Code(e)])
.severity(diagnostics::Severity::Warning),
);
trap::Compression::Gzip
}
};
drop(main_thread_logger);
rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
.build_global()
.unwrap();
let file_lists: Vec<File> = self
.file_lists
.iter()
.map(|file_list| {
File::open(file_list)
.unwrap_or_else(|_| panic!("Unable to open file list at {file_list:?}"))
})
.collect();
let mut schemas = vec![];
for lang in &self.languages {
let effective_node_types: String = match lang
.desugar
.as_ref()
.and_then(|d| d.output_node_types_yaml())
{
Some(yaml) => yeast::node_types_yaml::convert(yaml).map_err(|e| {
std::io::Error::other(format!(
"Failed to convert YAML node-types to JSON for {}: {e}",
lang.prefix
))
})?,
None => lang.node_types.to_string(),
};
let schema = node_types::read_node_types_str(lang.prefix, &effective_node_types)?;
schemas.push(schema);
}
// Construct a single globset containing all language globs,
// and a mapping from glob index to language index.
let (globset, glob_language_mapping) = {
let mut builder = GlobSetBuilder::new();
let mut glob_lang_mapping = vec![];
for (i, lang) in self.languages.iter().enumerate() {
for glob_str in &lang.file_globs {
let glob = GlobBuilder::new(glob_str)
.literal_separator(true)
.build()
.expect("invalid glob");
builder.add(glob);
glob_lang_mapping.push(i);
}
}
(
builder.build().expect("failed to build globset"),
glob_lang_mapping,
)
};
let path_transformer = file_paths::load_path_transformer()?;
let lines: std::io::Result<Vec<String>> = file_lists
.iter()
.flat_map(|file_list| std::io::BufReader::new(file_list).lines())
.collect();
let lines = lines?;
lines
.par_iter()
.try_for_each(|line| {
let mut diagnostics_writer = diagnostics.logger();
let path = PathBuf::from(line).canonicalize()?;
let src_archive_file = crate::file_paths::path_for(
&self.source_archive_dir,
&path,
"",
path_transformer.as_ref(),
);
let source = std::fs::read(&path)?;
let mut trap_writer = trap::Writer::new();
match path.file_name() {
None => {
tracing::error!(?path, "No file name found, skipping file.");
}
Some(filename) => {
let matches = globset.matches(filename);
if matches.is_empty() {
tracing::error!(?path, "No matching language found, skipping file.");
} else {
let mut languages_processed = vec![false; self.languages.len()];
for m in matches {
let i = glob_language_mapping[m];
if languages_processed[i] {
continue;
}
languages_processed[i] = true;
let lang = &self.languages[i];
crate::extractor::extract(
&lang.ts_language,
lang.prefix,
&schemas[i],
&mut diagnostics_writer,
&mut trap_writer,
None,
&path,
&source,
&[],
lang.desugar.as_deref(),
);
std::fs::create_dir_all(src_archive_file.parent().unwrap())?;
std::fs::copy(&path, &src_archive_file)?;
write_trap(&self.trap_dir, &path, &trap_writer, trap_compression)?;
}
}
}
}
Ok(()) as std::io::Result<()>
})
.expect("failed to extract files");
let path = PathBuf::from("extras");
let mut trap_writer = trap::Writer::new();
crate::extractor::populate_empty_location(&mut trap_writer);
let res = write_trap(&self.trap_dir, &path, &trap_writer, trap_compression);
tracing::info!("Extraction complete");
res
driver::run_extractor(
&self.prefix,
&self.languages,
&self.trap_dir,
&self.source_archive_dir,
&self.file_lists,
&self.trap_compression,
)
}
}
fn write_trap(
trap_dir: &Path,
path: &Path,
trap_writer: &trap::Writer,
trap_compression: trap::Compression,
) -> std::io::Result<()> {
let trap_file = crate::file_paths::path_for(trap_dir, path, trap_compression.extension(), None);
std::fs::create_dir_all(trap_file.parent().unwrap())?;
trap_writer.write_to_file(&trap_file, trap_compression)
}

View File

@@ -13,7 +13,6 @@ fn simple_extractor() {
prefix: "ql",
ts_language: tree_sitter_ql::LANGUAGE.into(),
node_types: tree_sitter_ql::NODE_TYPES,
desugar: None,
file_globs: vec!["*.qll".into()],
};

View File

@@ -13,14 +13,12 @@ fn multiple_language_extractor() {
prefix: "ql",
ts_language: tree_sitter_ql::LANGUAGE.into(),
node_types: tree_sitter_ql::NODE_TYPES,
desugar: None,
file_globs: vec!["*.qll".into()],
};
let lang_json = simple::LanguageSpec {
prefix: "json",
ts_language: tree_sitter_json::LANGUAGE.into(),
node_types: tree_sitter_json::NODE_TYPES,
desugar: None,
file_globs: vec!["*.json".into(), "*Jsonfile".into()],
};

View File

@@ -252,6 +252,41 @@ pub fn extend_schema_from_yaml(
let yaml: YamlNodeTypes =
serde_yaml::from_str(yaml_input).map_err(|e| format!("Failed to parse YAML: {e}"))?;
apply_yaml_to_schema(&yaml, schema);
// The typed `YamlNodeTypes` stores each node's fields in a `BTreeMap`
// (alphabetical), losing the authored order. Re-parse as an ordered value to
// record the declared field order for presentation (see the AST dump).
record_field_order(schema, yaml_input)?;
Ok(())
}
/// Record each node kind's declared (named) field order from the source YAML,
/// which `serde`'s `BTreeMap`-based deserialization does not preserve.
/// `serde_yaml::Value` mappings keep insertion (source) order.
fn record_field_order(schema: &mut crate::schema::Schema, yaml_input: &str) -> Result<(), String> {
let value: serde_yaml::Value = serde_yaml::from_str(yaml_input)
.map_err(|e| format!("Failed to parse YAML for field order: {e}"))?;
let Some(named) = value.get("named").and_then(|v| v.as_mapping()) else {
return Ok(());
};
for (node_name, fields) in named {
let Some(node_name) = node_name.as_str() else {
continue;
};
let Some(fields) = fields.as_mapping() else {
continue; // node with no fields (null)
};
let mut order = Vec::new();
for (raw_field_name, _) in fields {
let Some(raw) = raw_field_name.as_str() else {
continue;
};
// Skip the unnamed/`child` slot; the dump handles it separately.
if let Some(name) = parse_field_name(raw).name {
order.push(schema.register_field(&name));
}
}
schema.set_field_order(node_name, order);
}
Ok(())
}

View File

@@ -44,6 +44,11 @@ pub struct Schema {
field_types: BTreeMap<(String, FieldId), Vec<NodeType>>,
field_cardinalities: BTreeMap<(String, FieldId), FieldCardinality>,
supertypes: BTreeMap<String, Vec<NodeType>>,
/// Per-node-kind declared field order (named fields only), as written in
/// the source node-types YAML. Field ids are not a stable ordering key
/// across front-ends, so this preserves the authored order for
/// presentation (see the AST dump).
field_order: BTreeMap<String, Vec<FieldId>>,
}
impl Default for Schema {
@@ -65,6 +70,7 @@ impl Schema {
field_types: BTreeMap::new(),
field_cardinalities: BTreeMap::new(),
supertypes: BTreeMap::new(),
field_order: BTreeMap::new(),
}
}
@@ -269,6 +275,17 @@ impl Schema {
.get(&(parent_kind.to_string(), field_id))
}
/// Record the declared (named) field order for a node kind, as authored in
/// the source node-types YAML.
pub fn set_field_order(&mut self, kind: &str, field_ids: Vec<FieldId>) {
self.field_order.insert(kind.to_string(), field_ids);
}
/// The declared (named) field order for a node kind, if known.
pub fn field_order(&self, kind: &str) -> Option<&Vec<FieldId>> {
self.field_order.get(kind)
}
pub fn set_field_cardinality(
&mut self,
parent_kind: &str,

View File

@@ -108,6 +108,17 @@ impl<'a, C> BuildCtx<'a, C> {
self.captures.get_all(name)
}
/// Read the source text of a captured (or any other) node.
///
/// Convenience for the common `ctx.ast.source_text(id)` reach-through used
/// by Rust-block rules that branch on, or embed, a raw capture's spelling
/// (e.g. an operator or keyword token). Resolves against the stored source
/// bytes, so it works for both parsed nodes and synthesized ones (via their
/// inherited source range).
pub fn source_text(&self, id: Id) -> String {
self.ast.source_text(id)
}
/// Create a named AST node with the given kind and fields.
pub fn node(&mut self, kind: &str, fields: Vec<(&str, Vec<Id>)>) -> Id {
let kind_id = self

View File

@@ -162,8 +162,12 @@ fn type_error_for_node(
fn expected_for_field<'a>(
schema: &'a Schema,
parent_kind: &str,
field_id: u16,
field_name: &str,
) -> Option<&'a [crate::schema::NodeType]> {
// Resolve the field NAME in the validation schema's own id space, so the
// AST being dumped and the validation schema stay completely independent:
// they need not share field ids, only field names.
let field_id = schema.field_id_for_name(field_name)?;
schema
.field_types(parent_kind, field_id)
.map(|v| v.as_slice())
@@ -223,15 +227,49 @@ fn dump_node(
writeln!(out).unwrap();
// Named fields first
for (&field_id, children) in &node.fields {
if field_id == CHILD_FIELD {
continue; // Handle unnamed children last
// Named fields first, in the schema's declared order when available
// (front-end-independent), else in field-id order. Any present fields not
// covered by the declared order are appended in field-id order.
//
// The declared order lives in the validation schema, keyed by *its* field
// ids; the AST being dumped may key the same field names under different
// ids. So map the declared order through field NAMES into this AST's own id
// space, keeping the two schemas independent (they share names, not ids).
let named_field_ids: Vec<u16> = {
let present: Vec<u16> = node
.fields
.keys()
.copied()
.filter(|&f| f != CHILD_FIELD)
.collect();
match type_check.and_then(|(schema, _, _)| {
schema
.field_order(node.kind_name())
.map(|order| (schema, order))
}) {
Some((schema, order)) => {
let mut result: Vec<u16> = order
.iter()
.filter_map(|&f| schema.field_name_for_id(f))
.filter_map(|name| ast.field_id_for_name(name))
.filter(|&f| f != CHILD_FIELD && node.fields.contains_key(&f))
.collect();
for &f in &present {
if !result.contains(&f) {
result.push(f);
}
}
result
}
None => present,
}
};
for field_id in named_field_ids {
let children = &node.fields[&field_id];
let field_name = ast.field_name_for_id(field_id).unwrap_or("?");
let child_type_check = type_check.map(|(schema, _, _)| {
let expected =
expected_for_field(schema, node.kind_name(), field_id).or(Some(EMPTY_NODE_TYPES));
let expected = expected_for_field(schema, node.kind_name(), field_name)
.or(Some(EMPTY_NODE_TYPES));
let parent_field = Some((node.kind_name(), field_name));
(schema, expected, parent_field)
});
@@ -273,8 +311,14 @@ fn dump_node(
// Check for required fields that are absent
if let Some((schema, _, _)) = type_check {
for (field_id, field_name) in schema.required_fields_for_kind(node.kind_name()) {
if !node.fields.contains_key(&field_id) {
for (_field_id, field_name) in schema.required_fields_for_kind(node.kind_name()) {
let present = match field_name {
Some(n) => ast
.field_id_for_name(n)
.is_some_and(|fid| node.fields.contains_key(&fid)),
None => node.fields.contains_key(&CHILD_FIELD),
};
if !present {
let name = field_name.unwrap_or("child");
writeln!(out, "{prefix} <-- ERROR: missing required field '{name}'").unwrap();
}
@@ -284,7 +328,9 @@ fn dump_node(
// Unnamed children — skip unnamed tokens (keywords, punctuation)
if let Some(children) = node.fields.get(&CHILD_FIELD) {
let child_type_check = type_check.map(|(schema, _, _)| {
let expected = expected_for_field(schema, node.kind_name(), CHILD_FIELD)
let expected = schema
.field_types(node.kind_name(), CHILD_FIELD)
.map(|v| v.as_slice())
.or(Some(EMPTY_NODE_TYPES));
let parent_field = Some((node.kind_name(), "children"));
(schema, expected, parent_field)

View File

@@ -1329,10 +1329,27 @@ impl<C> DesugaringConfig<C> {
None => Ok(schema::from_language(language)),
}
}
/// Build the yeast `Schema` from the output YAML alone, with no input
/// tree-sitter grammar. Requires `output_node_types_yaml` to be set (there
/// is no grammar to fall back to). Used by custom (non-tree-sitter)
/// front-ends whose input schema is supplied by their own parser/adapter.
pub fn build_schema_no_language(&self) -> Result<schema::Schema, String> {
match self.output_node_types_yaml {
Some(yaml) => node_types_yaml::schema_from_yaml(yaml),
None => Err(
"a language-free desugarer requires output_node_types_yaml to be set".to_string(),
),
}
}
}
pub struct Runner<'a, C = ()> {
language: tree_sitter::Language,
/// The input tree-sitter language, used only when parsing (`run_from_tree`
/// / `run`). `None` for pipelines that only ever run over an
/// externally-built AST (`run_from_ast`), so no tree-sitter grammar is
/// required.
language: Option<tree_sitter::Language>,
schema: schema::Schema,
phases: &'a [Phase<C>],
}
@@ -1342,7 +1359,7 @@ impl<'a, C> Runner<'a, C> {
pub fn new(language: tree_sitter::Language, phases: &'a [Phase<C>]) -> Self {
let schema = schema::from_language(&language);
Self {
language,
language: Some(language),
schema,
phases,
}
@@ -1355,7 +1372,18 @@ impl<'a, C> Runner<'a, C> {
phases: &'a [Phase<C>],
) -> Self {
Self {
language,
language: Some(language),
schema: schema.clone(),
phases,
}
}
/// Create a runner with no input tree-sitter language, for pipelines that
/// only run over an externally-built AST (`run_from_ast`). The parsing
/// entry points (`run_from_tree` / `run`) will error if called.
pub fn with_schema_no_language(schema: &schema::Schema, phases: &'a [Phase<C>]) -> Self {
Self {
language: None,
schema: schema.clone(),
phases,
}
@@ -1368,7 +1396,7 @@ impl<'a, C> Runner<'a, C> {
) -> Result<Self, String> {
let schema = config.build_schema(&language)?;
Ok(Self {
language,
language: Some(language),
schema,
phases: &config.phases,
})
@@ -1388,7 +1416,9 @@ impl<'a, C: Clone> Runner<'a, C> {
let mut ast = Ast::from_tree_with_schema_and_source(
self.schema.clone(),
tree,
&self.language,
self.language
.as_ref()
.ok_or("run_from_tree requires a tree-sitter language")?,
source.to_vec(),
);
self.run_phases(&mut ast, user_ctx)?;
@@ -1398,9 +1428,13 @@ impl<'a, C: Clone> Runner<'a, C> {
/// Parse `input` and run all phases, threading `user_ctx` through
/// every rule transform. The caller owns the initial context state.
pub fn run_with_ctx(&self, input: &str, user_ctx: &mut C) -> Result<Ast, String> {
let language = self
.language
.as_ref()
.ok_or("run requires a tree-sitter language")?;
let mut parser = tree_sitter::Parser::new();
parser
.set_language(&self.language)
.set_language(language)
.map_err(|e| format!("Failed to set language: {e}"))?;
let tree = parser
.parse(input, None)
@@ -1408,7 +1442,7 @@ impl<'a, C: Clone> Runner<'a, C> {
let mut ast = Ast::from_tree_with_schema_and_source(
self.schema.clone(),
&tree,
&self.language,
language,
input.as_bytes().to_vec(),
);
self.run_phases(&mut ast, user_ctx)?;
@@ -1506,7 +1540,10 @@ pub trait Desugarer: Send + Sync {
/// schema so that per-call cost is bounded to constructing a transient
/// [`Runner`] and cloning the schema (no YAML re-parsing).
pub struct ConcreteDesugarer<C: Default + Clone + Send + Sync + 'static> {
language: tree_sitter::Language,
/// The input tree-sitter language, or `None` for a custom (non-tree-sitter)
/// front-end that only ever desugars an externally-built AST
/// (`run_from_ast`).
language: Option<tree_sitter::Language>,
schema: schema::Schema,
config: DesugaringConfig<C>,
}
@@ -1520,7 +1557,20 @@ impl<C: Default + Clone + Send + Sync + 'static> ConcreteDesugarer<C> {
) -> Result<Self, String> {
let schema = config.build_schema(&language)?;
Ok(Self {
language,
language: Some(language),
schema,
config,
})
}
/// Build a desugarer with no input tree-sitter language, for a custom
/// front-end whose parser supplies the input AST directly. Only
/// [`run_from_ast`](Desugarer::run_from_ast) is supported; the schema comes
/// from the config's `output_node_types_yaml` (which must be set).
pub fn without_language(config: DesugaringConfig<C>) -> Result<Self, String> {
let schema = config.build_schema_no_language()?;
Ok(Self {
language: None,
schema,
config,
})
@@ -1533,7 +1583,11 @@ impl<C: Default + Clone + Send + Sync + 'static> Desugarer for ConcreteDesugarer
}
fn run_from_tree(&self, tree: &tree_sitter::Tree, source: &[u8]) -> Result<Ast, String> {
let runner = Runner::with_schema(self.language.clone(), &self.schema, &self.config.phases);
let language = self
.language
.clone()
.ok_or("run_from_tree requires a tree-sitter language")?;
let runner = Runner::with_schema(language, &self.schema, &self.config.phases);
runner.run_from_tree(tree, source)
}
@@ -1541,7 +1595,8 @@ impl<C: Default + Clone + Send + Sync + 'static> Desugarer for ConcreteDesugarer
// The AST was built against its own (external) schema; make sure the
// output kind/field names the rules build are resolvable in it.
ast.register_names_from_schema(&self.schema);
let runner = Runner::with_schema(self.language.clone(), &self.schema, &self.config.phases);
// `run_from_ast` never parses, so no tree-sitter language is needed.
let runner = Runner::with_schema_no_language(&self.schema, &self.config.phases);
runner.run_from_ast(ast)
}
}

View File

@@ -1,5 +1,6 @@
load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup")
load("//misc/bazel:pkg.bzl", "codeql_pack", "codeql_pkg_files")
load("//misc/bazel:utils.bzl", "select_os")
package(default_visibility = ["//visibility:public"])
@@ -46,12 +47,26 @@ codeql_pkg_files(
prefix = "tools/{CODEQL_PLATFORM}",
)
# The Swift front-end parser (wrapper + real binary + bundled Swift runtime),
# shipped next to the extractor. Only on platforms where swift-syntax builds
# (Linux/macOS); elsewhere the group is empty so the pack still builds (Swift
# extraction is simply unavailable there).
pkg_filegroup(
name = "swift-syntax-parse-arch",
srcs = select_os(
otherwise = [],
posix = ["//unified/swift-syntax-rs:swift-syntax-parse-pkg"],
),
prefix = "tools/{CODEQL_PLATFORM}",
)
codeql_pack(
name = "unified",
srcs = [
":codeql-extractor-yml",
":dbscheme-group",
":extractor-arch",
":swift-syntax-parse-arch",
"//unified/tools",
],
)

View File

@@ -7,7 +7,10 @@ codeql_rust_binary(
name = "extractor",
srcs = glob(["src/**/*.rs"]),
aliases = aliases(),
compile_data = ["ast_types.yml"],
compile_data = [
"ast_types.yml",
"swift_node_types.yml",
],
proc_macro_deps = all_crate_deps(
proc_macro = True,
),

View File

@@ -31,6 +31,7 @@ supertypes:
- throw_expr
- try_expr
- switch_expr
- unresolved_operator_sequence
- unsupported_node
expr_or_pattern:
- expr
@@ -38,6 +39,11 @@ supertypes:
expr_or_type:
- expr
- type_expr
# An element of an `unresolved_operator_sequence`: either an operand (`expr`)
# or one of the infix operators separating the operands.
expr_or_operator:
- expr
- infix_operator
pattern:
- name_pattern
- tuple_pattern
@@ -137,6 +143,19 @@ named:
operand: expr
operator: operator
# A flat, unresolved operator sequence such as `a <+> b <+> c`.
#
# Swift's grammar doesn't encode operator precedence, so an operator chain is
# first parsed as a flat list of operands and operators. The parser front-end
# resolves this into structured `binary_expr` trees when it knows the
# operators' precedence (standard-library operators, and operators declared in
# the same file). When it encounters an operator whose precedence it can't
# determine (e.g. one imported from another module), it leaves that chain
# unresolved and emits it here rather than guessing a (possibly wrong)
# structure. The `element`s alternate operands (`expr`) and infix operators.
unresolved_operator_sequence:
element*: expr_or_operator
# Plain assignment
assign_expr:
target: expr_or_pattern

View File

@@ -2,7 +2,7 @@ use clap::Args;
use std::path::PathBuf;
use crate::languages;
use codeql_extractor::extractor::simple;
use codeql_extractor::extractor::desugaring;
use codeql_extractor::trap;
#[derive(Args)]
@@ -31,7 +31,7 @@ pub fn run(options: Options) -> std::io::Result<()> {
lang.prefix = "unified";
}
let extractor = simple::Extractor {
let extractor = desugaring::Extractor {
prefix: "unified".to_string(),
languages,
trap_dir: options.output_dir,

View File

@@ -1,20 +1,21 @@
use codeql_extractor::extractor::simple;
use codeql_extractor::extractor::desugaring;
#[path = "swift/swift.rs"]
mod swift;
/// swift-syntax JSON -> `yeast::Ast` adapter for the Swift front-end.
///
/// Currently exercised by tests and the forthcoming runtime extraction path;
/// `allow(dead_code)` because this is a binary crate, so its public API isn't
/// counted as used until the binary itself calls it.
#[path = "swift/adapter.rs"]
#[allow(dead_code)]
pub mod swift_adapter;
/// Swift front-end parser: shells out to `swift-syntax-parse` and adapts its
/// JSON output via [`swift_adapter`]. This is the live Swift front-end used by
/// [`all_language_specs`].
#[path = "swift/parse.rs"]
pub mod swift_parse;
/// Shared YEAST output AST schema for all languages.
pub(crate) const OUTPUT_AST_SCHEMA: &str = include_str!("../../ast_types.yml");
pub fn all_language_specs() -> Vec<simple::LanguageSpec> {
pub fn all_language_specs() -> Vec<desugaring::LanguageSpec> {
vec![swift::language_spec(OUTPUT_AST_SCHEMA)]
}

View File

@@ -2,9 +2,8 @@
//! in-memory format the CodeQL desugaring rules operate on.
//!
//! The JSON tree is produced by the `swift-syntax-rs` crate's Swift FFI shim
//! (`parse_to_json`). This module is pure Rust (only `yeast` + `serde_json`),
//! so the extractor consumes swift-syntax output without pulling in the Swift
//! toolchain (the JSON is produced out-of-process).
//! (`parse_to_json`). This module needs no Swift toolchain, so the extractor
//! consumes swift-syntax output out-of-process.
//!
//! The mapping mirrors tree-sitter's node model, which is what yeast (and the
//! extractor's rewrite rules) expect:
@@ -24,31 +23,19 @@
use std::collections::BTreeMap;
use codeql_extractor::extractor::ExtraToken;
use serde_json::Value;
use yeast::schema::Schema;
use yeast::{Ast, Id, NodeContent, Point, Range};
/// A comment (or `unexpectedText`) recovered from the syntax tree's trivia.
///
/// These are collected into a side channel rather than embedded in the
/// [`yeast::Ast`], mirroring how the extractor treats tree-sitter `extra`
/// nodes: they carry a location and text but are not attached to a parent.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TriviaToken {
/// The trivia kind (e.g. `lineComment`, `blockComment`, `docLineComment`,
/// `docBlockComment`, `unexpectedText`).
pub kind: String,
/// The verbatim source text of the piece (e.g. `// comment`).
pub text: String,
/// The source range the piece occupies.
pub range: Range,
}
/// The result of adapting a swift-syntax JSON tree: the [`yeast::Ast`] plus the
/// comment/`unexpectedText` trivia harvested from it (in source order).
/// comment/`unexpectedText` [`ExtraToken`]s harvested from it (in source order).
///
/// The extra tokens are collected into a side channel rather than embedded in
/// the [`yeast::Ast`], mirroring how the extractor treats tree-sitter `extra`
/// nodes: they carry a location and text but are not attached to a parent.
pub struct AdaptedTree {
pub ast: Ast,
pub trivia: Vec<TriviaToken>,
pub extras: Vec<ExtraToken>,
}
/// swift-syntax `TokenKind` cases whose text is *not* determined by the kind
@@ -170,17 +157,18 @@ fn children_of(value: &Value) -> Vec<&Value> {
/// in the schema on the fly, immediately before the node is created. Children
/// are built first so a parent's field lists reference existing ids. Any
/// comment/`unexpectedText` trivia carried by a token is harvested into
/// `trivia` during the same pass rather than embedded in the tree.
fn build(node: &Value, ast: &mut Ast, trivia: &mut Vec<TriviaToken>) -> Result<Id, String> {
/// `extras` (as [`ExtraToken`]s) during the same pass rather than embedded in
/// the tree.
fn build(node: &Value, ast: &mut Ast, extras: &mut Vec<ExtraToken>) -> Result<Id, String> {
let info = classify(node)?;
collect_trivia(node, trivia);
collect_extras(node, extras);
let mut fields: BTreeMap<u16, Vec<Id>> = BTreeMap::new();
for (field, value) in field_entries(node) {
let field_id = ast.register_field(field);
let mut ids = Vec::new();
for child in children_of(value) {
ids.push(build(child, ast, trivia)?);
ids.push(build(child, ast, extras)?);
}
fields.insert(field_id, ids);
}
@@ -201,9 +189,10 @@ fn build(node: &Value, ast: &mut Ast, trivia: &mut Vec<TriviaToken>) -> Result<I
}
/// Harvest a token's `leadingTrivia`/`trailingTrivia` pieces (each already
/// filtered to comments/`unexpectedText` upstream) into `out`. Non-token nodes
/// have no trivia keys, so this is a no-op for them.
fn collect_trivia(node: &Value, out: &mut Vec<TriviaToken>) {
/// filtered to comments/`unexpectedText` upstream) into `out` as
/// [`ExtraToken`]s. Non-token nodes have no trivia keys, so this is a no-op for
/// them.
fn collect_extras(node: &Value, out: &mut Vec<ExtraToken>) {
for key in ["leadingTrivia", "trailingTrivia"] {
let Some(Value::Array(pieces)) = node.get(key) else {
continue;
@@ -220,8 +209,8 @@ fn collect_trivia(node: &Value, out: &mut Vec<TriviaToken>) {
.and_then(Value::as_str)
.unwrap_or("")
.to_string();
out.push(TriviaToken {
kind: kind.to_string(),
out.push(ExtraToken {
kind: trivia_kind_id(kind),
text,
range,
});
@@ -229,6 +218,21 @@ fn collect_trivia(node: &Value, out: &mut Vec<TriviaToken>) {
}
}
/// Map a swift-syntax trivia kind name to the stable integer id stored in an
/// [`ExtraToken`]'s `kind` (and written to the `unified_trivia_tokeninfo`
/// table). The value is opaque to the QL library (which reads only the text),
/// but is kept stable and meaningful.
fn trivia_kind_id(kind: &str) -> usize {
match kind {
"lineComment" => 1,
"blockComment" => 2,
"docLineComment" => 3,
"docBlockComment" => 4,
"unexpectedText" => 5,
_ => 0,
}
}
/// Parse a node's `range` into a [`yeast::Range`].
///
/// The JSON carries, for `start` and `end`, a 0-based UTF-8 file byte `offset`,
@@ -258,21 +262,29 @@ fn parse_range(node: &Value) -> Option<Range> {
})
}
/// The authoritative swift-syntax input node-types schema.
/// [`json_to_ast`] seeds every parse with the schema built from this,
/// pre-registering every input kind and field so rule matching never references
/// a name absent from a given file's tree.
const SWIFT_NODE_TYPES: &str = include_str!("../../../swift_node_types.yml");
/// Convert a swift-syntax JSON tree (as produced by [`crate::parse_to_json`])
/// into a [`yeast::Ast`] plus the comment/`unexpectedText` trivia harvested
/// from it. Both are produced in a single traversal.
/// from it. Both are produced in a single traversal. The AST is seeded with the
/// authoritative swift-syntax schema ([`SWIFT_NODE_TYPES`]); the adapter only
/// ever consumes swift-syntax input, so the schema is not a parameter.
pub fn json_to_ast(json: &str) -> Result<AdaptedTree, String> {
let root: Value = serde_json::from_str(json).map_err(|e| format!("invalid JSON: {e}"))?;
let mut ast = Ast::with_schema(Schema::new());
let mut trivia = Vec::new();
let root_id = build(&root, &mut ast, &mut trivia)?;
let mut ast = Ast::with_schema(yeast::node_types_yaml::schema_from_yaml(SWIFT_NODE_TYPES)?);
let mut extras = Vec::new();
let root_id = build(&root, &mut ast, &mut extras)?;
ast.set_root(root_id);
// Emit trivia in source order (the traversal visits nodes bottom-up).
trivia.sort_by_key(|t| t.range.start_byte);
// Emit extras in source order (the traversal visits nodes bottom-up).
extras.sort_by_key(|t| t.range.start_byte);
Ok(AdaptedTree { ast, trivia })
Ok(AdaptedTree { ast, extras })
}
#[cfg(test)]
@@ -373,7 +385,7 @@ mod tests {
}
#[test]
fn collects_trivia_into_side_channel() {
fn collects_extras_into_side_channel() {
// A token carrying a trailing line comment in its trivia.
let json = r#"{
"kind": "sourceFile",
@@ -395,9 +407,10 @@ mod tests {
let adapted = json_to_ast(json).expect("adapter should succeed");
// The comment is in the side channel, with its text and location.
assert_eq!(adapted.trivia.len(), 1);
let comment = &adapted.trivia[0];
assert_eq!(comment.kind, "lineComment");
assert_eq!(adapted.extras.len(), 1);
let comment = &adapted.extras[0];
// `lineComment` maps to extra kind id 1.
assert_eq!(comment.kind, 1);
assert_eq!(comment.text, "// c");
assert_eq!(comment.range.start_byte, 2);
assert_eq!(comment.range.end_byte, 6);

View File

@@ -0,0 +1,121 @@
//! Swift front-end parser: shells out to the separate `swift-syntax-parse`
//! binary (which links swift-syntax) to obtain a JSON syntax tree, then adapts
//! that JSON into a `yeast::Ast` via the pure-Rust [`swift_adapter`] module.
//!
//! Running the parser in a separate process keeps the Swift toolchain out of
//! the extractor's own build: the extractor never links Swift, so working on
//! other (e.g. tree-sitter based) languages needs no Swift toolchain. Each call
//! spawns the parser afresh; a longer-lived parser process could be swapped in
//! behind this same seam later without touching the extraction pipeline.
use std::io::Write;
use std::process::{Command, Stdio};
use codeql_extractor::extractor::ParsedTree;
use super::swift_adapter;
/// Environment variable naming the `swift-syntax-parse` executable. When unset,
/// the parser is resolved next to the extractor executable, then on `PATH`.
const PARSE_BIN_ENV: &str = "CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE";
/// Base name of the `swift-syntax-parse` executable as shipped / looked up.
const PARSE_BIN_NAME: &str = "swift-syntax-parse";
/// Parse Swift `source` into a [`ParsedTree`] (a raw `yeast::Ast` plus
/// side-channel `extra` tokens), ready to be desugared via `run_from_ast`.
pub fn parse(source: &[u8]) -> Result<ParsedTree, String> {
let source =
std::str::from_utf8(source).map_err(|e| format!("Swift source is not valid UTF-8: {e}"))?;
let json = run_parser(source)?;
let mut adapted = swift_adapter::json_to_ast(&json)?;
adapted.ast.set_source(source.as_bytes().to_vec());
Ok(ParsedTree {
ast: adapted.ast,
extras: adapted.extras,
})
}
/// The `swift-syntax-parse` executable to invoke, resolved in priority order:
///
/// 1. the `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` override, if set;
/// 2. a copy shipped next to the extractor executable — this is how the CodeQL
/// extractor pack lays it out (`tools/<platform>/{extractor,
/// swift-syntax-parse}`), so a packaged extractor is self-contained with no
/// environment setup;
/// 3. a bare `swift-syntax-parse`, looked up on `PATH`.
fn parse_bin() -> String {
if let Ok(bin) = std::env::var(PARSE_BIN_ENV) {
if !bin.is_empty() {
return bin;
}
}
if let Ok(exe) = std::env::current_exe() {
if let Some(sibling) = exe.parent().map(|dir| dir.join(PARSE_BIN_NAME)) {
if sibling.is_file() {
return sibling.to_string_lossy().into_owned();
}
}
}
PARSE_BIN_NAME.to_string()
}
/// Whether the `swift-syntax-parse` executable can be launched at all.
///
/// This reports availability of the *executable*, deliberately not whether
/// parsing succeeds: a binary that launches but then crashes or emits invalid
/// JSON is still "available", so callers run and surface the failure rather
/// than silently skipping. Only a genuinely missing/unlaunchable binary (e.g.
/// no Swift toolchain is installed) reports `false`.
pub fn binary_available() -> bool {
match Command::new(parse_bin())
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
{
Ok(mut child) => {
let _ = child.wait();
true
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => false,
// Any other spawn failure (e.g. a permissions problem) is a genuine
// issue worth surfacing, so treat the parser as available and let the
// caller fail rather than masking it as "unavailable".
Err(_) => true,
}
}
/// Run the external parser, feeding `source` on stdin and returning its JSON
/// stdout.
fn run_parser(source: &str) -> Result<String, String> {
let bin = parse_bin();
let mut child = Command::new(&bin)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(|e| format!("failed to spawn Swift parser `{bin}`: {e}"))?;
// The parser reads all of stdin before writing any stdout, so writing the
// whole source and then closing stdin (by dropping it) cannot deadlock.
child
.stdin
.take()
.expect("child stdin was piped")
.write_all(source.as_bytes())
.map_err(|e| format!("failed to write source to Swift parser `{bin}`: {e}"))?;
let output = child
.wait_with_output()
.map_err(|e| format!("failed to run Swift parser `{bin}`: {e}"))?;
if !output.status.success() {
return Err(format!(
"Swift parser `{bin}` failed ({}): {}",
output.status,
String::from_utf8_lossy(&output.stderr).trim()
));
}
String::from_utf8(output.stdout)
.map_err(|e| format!("Swift parser produced non-UTF-8 output: {e}"))
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,41 +2,61 @@ let f = { [weak self] in self?.doThing() }
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "f"
value:
lambda_literal
captures:
capture_list
item:
capture_list_item
name: simple_identifier "self"
ownership:
ownership_modifier
statement:
call_expression
function:
navigation_expression
suffix:
navigation_suffix
suffix: simple_identifier "doThing"
target:
optional_chain_marker
expr:
self_expression
suffix:
call_suffix
arguments:
value_arguments
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
closureExpr
leftBrace: {
rightBrace: }
signature:
closureSignature
attributes:
capture:
closureCaptureClause
leftSquare: [
rightSquare: ]
items:
closureCapture
name: self
specifier:
closureCaptureSpecifier
specifier: weak
inKeyword: in
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "doThing"
base:
optionalChainingExpr
expression:
declReferenceExpr
baseName: self
questionMark: ?
pattern:
identifierPattern
identifier: identifier "f"
---
@@ -51,6 +71,12 @@ top_level
identifier: identifier "f"
value:
function_expr
capture_declaration:
variable_declaration
modifier: modifier "weak"
pattern:
name_pattern
identifier: identifier "self"
body:
block
stmt:
@@ -61,9 +87,3 @@ top_level
name_expr
identifier: identifier "self"
member: identifier "doThing"
capture_declaration:
variable_declaration
modifier: modifier "weak"
pattern:
name_pattern
identifier: identifier "self"

View File

@@ -2,45 +2,63 @@ let f = { (x: Int) -> Int in x * 2 }
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "f"
value:
lambda_literal
statement:
multiplicative_expression
lhs: simple_identifier "x"
op: *
rhs: integer_literal "2"
type:
lambda_function_type
params:
lambda_function_type_parameters
parameter:
lambda_parameter
name: simple_identifier "x"
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
return_type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
closureExpr
leftBrace: {
rightBrace: }
signature:
closureSignature
attributes:
inKeyword: in
parameterClause:
closureParameterClause
leftParen: (
rightParen: )
parameters:
closureParameter
colon: :
attributes:
modifiers:
type:
identifierType
name: identifier "Int"
firstName: identifier "x"
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "Int"
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "*"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "2"
pattern:
identifierPattern
identifier: identifier "f"
---
@@ -55,23 +73,23 @@ top_level
identifier: identifier "f"
value:
function_expr
parameter:
parameter
type:
named_type_expr
name: identifier "Int"
pattern:
name_pattern
identifier: identifier "x"
return_type:
named_type_expr
name: identifier "Int"
body:
block
stmt:
binary_expr
operator: infix_operator "*"
left:
name_expr
identifier: identifier "x"
operator: infix_operator "*"
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"

View File

@@ -2,24 +2,40 @@ let f = { $0 + $1 }
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "f"
value:
lambda_literal
statement:
additive_expression
lhs: simple_identifier "$0"
op: +
rhs: simple_identifier "$1"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
closureExpr
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
declReferenceExpr
baseName: dollarIdentifier "$0"
rightOperand:
declReferenceExpr
baseName: dollarIdentifier "$1"
pattern:
identifierPattern
identifier: identifier "f"
---
@@ -38,10 +54,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "+"
left:
name_expr
identifier: identifier "$0"
operator: infix_operator "+"
right:
name_expr
identifier: identifier "$1"

View File

@@ -5,62 +5,91 @@ let f = { (x: Int) -> Int in
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "f"
value:
lambda_literal
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "y"
value:
additive_expression
lhs: simple_identifier "x"
op: +
rhs: integer_literal "1"
control_transfer_statement
kind: return
result:
multiplicative_expression
lhs: simple_identifier "y"
op: *
rhs: integer_literal "2"
type:
lambda_function_type
params:
lambda_function_type_parameters
parameter:
lambda_parameter
name: simple_identifier "x"
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
return_type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
closureExpr
leftBrace: {
rightBrace: }
signature:
closureSignature
attributes:
inKeyword: in
parameterClause:
closureParameterClause
leftParen: (
rightParen: )
parameters:
closureParameter
colon: :
attributes:
modifiers:
type:
identifierType
name: identifier "Int"
firstName: identifier "x"
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "Int"
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "1"
pattern:
identifierPattern
identifier: identifier "y"
codeBlockItem
item:
returnStmt
expression:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "*"
leftOperand:
declReferenceExpr
baseName: identifier "y"
rightOperand:
integerLiteralExpr
literal: integerLiteral "2"
returnKeyword: return
pattern:
identifierPattern
identifier: identifier "f"
---
@@ -75,6 +104,17 @@ top_level
identifier: identifier "f"
value:
function_expr
parameter:
parameter
type:
named_type_expr
name: identifier "Int"
pattern:
name_pattern
identifier: identifier "x"
return_type:
named_type_expr
name: identifier "Int"
body:
block
stmt:
@@ -85,27 +125,16 @@ top_level
identifier: identifier "y"
value:
binary_expr
operator: infix_operator "+"
left:
name_expr
identifier: identifier "x"
operator: infix_operator "+"
right: int_literal "1"
return_expr
value:
binary_expr
operator: infix_operator "*"
left:
name_expr
identifier: identifier "y"
operator: infix_operator "*"
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"

View File

@@ -2,24 +2,40 @@ xs.map { $0 * 2 }
---
source_file
statement:
call_expression
function:
navigation_expression
suffix:
navigation_suffix
suffix: simple_identifier "map"
target: simple_identifier "xs"
suffix:
call_suffix
lambda:
lambda_literal
statement:
multiplicative_expression
lhs: simple_identifier "$0"
op: *
rhs: integer_literal "2"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionCallExpr
arguments:
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "map"
base:
declReferenceExpr
baseName: identifier "xs"
trailingClosure:
closureExpr
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "*"
leftOperand:
declReferenceExpr
baseName: dollarIdentifier "$0"
rightOperand:
integerLiteralExpr
literal: integerLiteral "2"
---
@@ -28,6 +44,12 @@ top_level
block
stmt:
call_expr
callee:
member_access_expr
base:
name_expr
identifier: identifier "xs"
member: identifier "map"
argument:
argument
value:
@@ -36,14 +58,8 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "*"
left:
name_expr
identifier: identifier "$0"
operator: infix_operator "*"
right: int_literal "2"
callee:
member_access_expr
base:
name_expr
identifier: identifier "xs"
member: identifier "map"

View File

@@ -2,23 +2,42 @@ let xs = [1, 2, 3]
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "xs"
value:
array_literal
element:
integer_literal "1"
integer_literal "2"
integer_literal "3"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
arrayExpr
elements:
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "1"
trailingComma: ,
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "2"
trailingComma: ,
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "3"
leftSquare: [
rightSquare: ]
pattern:
identifierPattern
identifier: identifier "xs"
---

View File

@@ -2,30 +2,53 @@ let d = ["a": 1, "b": 2]
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "d"
value:
dictionary_literal
element:
dictionary_literal_item
key:
line_string_literal
text: line_str_text "a"
value: integer_literal "1"
dictionary_literal_item
key:
line_string_literal
text: line_str_text "b"
value: integer_literal "2"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
dictionaryExpr
leftSquare: [
rightSquare: ]
content:
dictionaryElement
colon: :
trailingComma: ,
value:
integerLiteralExpr
literal: integerLiteral "1"
key:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "a"
dictionaryElement
colon: :
value:
integerLiteralExpr
literal: integerLiteral "2"
key:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "b"
pattern:
identifierPattern
identifier: identifier "d"
---

View File

@@ -4,31 +4,40 @@ let v = d["key"]
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "v"
value:
call_expression
function: simple_identifier "d"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "key"
comment "// TODO: same parser issue as the array subscript case above —"
comment "// `d[\"key\"]` is parsed as `call_expression(d, (\"key\"))`."
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
subscriptCallExpr
leftSquare: [
rightSquare: ]
arguments:
labeledExpr
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "key"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "d"
pattern:
identifierPattern
identifier: identifier "v"
---
@@ -43,9 +52,9 @@ top_level
identifier: identifier "v"
value:
call_expr
argument:
argument
value: string_literal "\"key\""
callee:
name_expr
identifier: identifier "d"
argument:
argument
value: string_literal "\"key\""

View File

@@ -2,32 +2,38 @@ let xs: [Int] = []
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "xs"
type:
type_annotation
type:
type
name:
array_type
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
arrayExpr
elements:
leftSquare: [
rightSquare: ]
pattern:
identifierPattern
identifier: identifier "xs"
typeAnnotation:
typeAnnotation
colon: :
type:
arrayType
leftSquare: [
rightSquare: ]
element:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
value:
array_literal
identifierType
name: identifier "Int"
---

View File

@@ -2,41 +2,57 @@ let s: Set<Int> = [1, 2, 3]
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "s"
type:
type_annotation
type:
type
name:
user_type
part:
simple_user_type
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
arrayExpr
elements:
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "1"
trailingComma: ,
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "2"
trailingComma: ,
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "3"
leftSquare: [
rightSquare: ]
pattern:
identifierPattern
identifier: identifier "s"
typeAnnotation:
typeAnnotation
colon: :
type:
identifierType
name: identifier "Set"
genericArgumentClause:
genericArgumentClause
arguments:
type_arguments
genericArgument
argument:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
name: type_identifier "Set"
value:
array_literal
element:
integer_literal "1"
integer_literal "2"
integer_literal "3"
identifierType
name: identifier "Int"
leftAngle: <
rightAngle: >
---

View File

@@ -5,30 +5,36 @@ let first = xs[0]
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "first"
value:
call_expression
function: simple_identifier "xs"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: integer_literal "0"
comment "// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape"
comment "// as `xs(0)`), so the mapping currently produces a call_expr. Update the"
comment "// parser / add a separate subscript_expr node and remap when fixed."
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
subscriptCallExpr
leftSquare: [
rightSquare: ]
arguments:
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "0"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "xs"
pattern:
identifierPattern
identifier: identifier "first"
---
@@ -43,9 +49,9 @@ top_level
identifier: identifier "first"
value:
call_expr
argument:
argument
value: int_literal "0"
callee:
name_expr
identifier: identifier "xs"
argument:
argument
value: int_literal "0"

View File

@@ -2,28 +2,46 @@ let t = (1, "two", 3.0)
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "t"
value:
tuple_expression
element:
tuple_expression_item
value: integer_literal "1"
tuple_expression_item
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
line_string_literal
text: line_str_text "two"
tuple_expression_item
value: real_literal "3.0"
tupleExpr
leftParen: (
rightParen: )
elements:
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "1"
trailingComma: ,
labeledExpr
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "two"
trailingComma: ,
labeledExpr
expression:
floatLiteralExpr
literal: floatLiteral "3.0"
pattern:
identifierPattern
identifier: identifier "t"
---

View File

@@ -2,23 +2,32 @@ let n = t.0
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "n"
value:
navigation_expression
suffix:
navigation_suffix
suffix: integer_literal "0"
target: simple_identifier "t"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: integerLiteral "0"
base:
declReferenceExpr
baseName: identifier "t"
pattern:
identifierPattern
identifier: identifier "n"
---

View File

@@ -8,44 +8,79 @@ default:
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "x"
value: integer_literal "1"
switch_statement
entry:
switch_entry
pattern:
switch_pattern
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
integerLiteralExpr
literal: integerLiteral "1"
pattern:
pattern
kind: simple_identifier "someConstant"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "matched"
switch_entry
default: default_keyword "default"
statement:
control_transfer_statement
kind: break
expr: simple_identifier "y"
identifierPattern
identifier: identifier "x"
codeBlockItem
item:
expressionStmt
expression:
switchExpr
leftBrace: {
rightBrace: }
cases:
switchCase
label:
switchCaseLabel
colon: :
caseKeyword: case
caseItems:
switchCaseItem
pattern:
expressionPattern
expression:
declReferenceExpr
baseName: identifier "someConstant"
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "matched"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
switchCase
label:
switchDefaultLabel
colon: :
defaultKeyword: default
statements:
codeBlockItem
item:
breakStmt
breakKeyword: break
subject:
declReferenceExpr
baseName: identifier "y"
switchKeyword: switch
---
@@ -60,27 +95,27 @@ top_level
identifier: identifier "x"
value: int_literal "1"
switch_expr
value:
name_expr
identifier: identifier "y"
case:
switch_case
body:
block
stmt:
call_expr
argument:
argument
value: string_literal "\"matched\""
callee:
name_expr
identifier: identifier "print"
pattern:
expr_equality_pattern
expr:
name_expr
identifier: identifier "someConstant"
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value: string_literal "\"matched\""
switch_case
body:
block
stmt: break_expr "break"
value:
name_expr
identifier: identifier "y"

View File

@@ -2,25 +2,37 @@ guard let value = optional else { return }
---
source_file
statement:
guard_statement
body:
block
statement:
control_transfer_statement
kind: return
condition:
if_condition
kind:
if_let_binding
pattern:
pattern
binding:
value_binding_pattern
mutability: let
bound_identifier: simple_identifier "value"
value: simple_identifier "optional"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
guardStmt
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
returnStmt
returnKeyword: return
conditions:
conditionElement
condition:
optionalBindingCondition
initializer:
initializerClause
equal: =
value:
declReferenceExpr
baseName: identifier "optional"
pattern:
identifierPattern
identifier: identifier "value"
bindingSpecifier: let
elseKeyword: else
guardKeyword: guard
---
@@ -33,17 +45,17 @@ top_level
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"
element:
pattern_element
pattern:
name_pattern
identifier: identifier "value"
value:
name_expr
identifier: identifier "optional"

View File

@@ -4,40 +4,59 @@ if case let x = x + 10 {
---
source_file
statement:
if_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "x"
condition:
if_condition
kind:
if_let_binding
pattern:
pattern
kind:
binding_pattern
binding:
value_binding_pattern
mutability: let
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
expressionStmt
expression:
ifExpr
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "x"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
conditions:
conditionElement
condition:
matchingPatternCondition
initializer:
initializerClause
equal: =
value:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "10"
pattern:
pattern
bound_identifier: simple_identifier "x"
value:
additive_expression
lhs: simple_identifier "x"
op: +
rhs: integer_literal "10"
valueBindingPattern
pattern:
identifierPattern
identifier: identifier "x"
bindingSpecifier: let
caseKeyword: case
ifKeyword: if
---
@@ -53,20 +72,20 @@ top_level
identifier: identifier "x"
value:
binary_expr
operator: infix_operator "+"
left:
name_expr
identifier: identifier "x"
operator: infix_operator "+"
right: int_literal "10"
then:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "x"
callee:
name_expr
identifier: identifier "print"

View File

@@ -8,61 +8,103 @@ if x > 0 {
---
source_file
statement:
if_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: integer_literal "1"
condition:
if_condition
kind:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "0"
else_branch:
if_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: integer_literal "2"
condition:
if_condition
kind:
comparison_expression
lhs: simple_identifier "x"
op: <
rhs: integer_literal "0"
else_branch:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: integer_literal "3"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
expressionStmt
expression:
ifExpr
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "1"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
conditions:
conditionElement
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator ">"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
elseKeyword: else
elseBody:
ifExpr
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "2"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
conditions:
conditionElement
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "<"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
elseKeyword: else
elseBody:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "3"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
ifKeyword: if
ifKeyword: if
---
@@ -73,47 +115,47 @@ top_level
if_expr
condition:
binary_expr
operator: infix_operator ">"
left:
name_expr
identifier: identifier "x"
operator: infix_operator ">"
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"
argument:
argument
value: int_literal "1"
else:
if_expr
condition:
binary_expr
left:
name_expr
identifier: identifier "x"
operator: infix_operator "<"
right: int_literal "0"
then:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value: int_literal "2"
else:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value: int_literal "3"

View File

@@ -6,43 +6,70 @@ if x > 0 {
---
source_file
statement:
if_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "x"
condition:
if_condition
kind:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "0"
else_branch:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
prefix_expression
operation: -
target: simple_identifier "x"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
expressionStmt
expression:
ifExpr
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "x"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
conditions:
conditionElement
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator ">"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
elseKeyword: else
elseBody:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
prefixOperatorExpr
expression:
declReferenceExpr
baseName: identifier "x"
operator: prefixOperator "-"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
ifKeyword: if
---
@@ -53,15 +80,30 @@ top_level
if_expr
condition:
binary_expr
operator: infix_operator ">"
left:
name_expr
identifier: identifier "x"
operator: infix_operator ">"
right: int_literal "0"
then:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "x"
else:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
@@ -70,18 +112,3 @@ top_level
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"

View File

@@ -4,32 +4,48 @@ if let value = optional {
---
source_file
statement:
if_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "value"
condition:
if_condition
kind:
if_let_binding
pattern:
pattern
binding:
value_binding_pattern
mutability: let
bound_identifier: simple_identifier "value"
value: simple_identifier "optional"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
expressionStmt
expression:
ifExpr
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "value"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
conditions:
conditionElement
condition:
optionalBindingCondition
initializer:
initializerClause
equal: =
value:
declReferenceExpr
baseName: identifier "optional"
pattern:
identifierPattern
identifier: identifier "value"
bindingSpecifier: let
ifKeyword: if
---
@@ -42,17 +58,17 @@ top_level
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"
element:
pattern_element
pattern:
name_pattern
identifier: identifier "value"
value:
name_expr
identifier: identifier "optional"
@@ -60,11 +76,11 @@ top_level
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "value"
callee:
name_expr
identifier: identifier "print"

View File

@@ -4,28 +4,47 @@ if x > 0 {
---
source_file
statement:
if_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "x"
condition:
if_condition
kind:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "0"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
expressionStmt
expression:
ifExpr
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "x"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
conditions:
conditionElement
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator ">"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
ifKeyword: if
---
@@ -36,20 +55,20 @@ top_level
if_expr
condition:
binary_expr
operator: infix_operator ">"
left:
name_expr
identifier: identifier "x"
operator: infix_operator ">"
right: int_literal "0"
then:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "x"
callee:
name_expr
identifier: identifier "print"

View File

@@ -9,65 +9,114 @@ default:
---
source_file
statement:
switch_statement
entry:
switch_entry
pattern:
switch_pattern
pattern:
pattern
kind: integer_literal "1"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "one"
switch_entry
pattern:
switch_pattern
pattern:
pattern
kind: integer_literal "2"
switch_pattern
pattern:
pattern
kind: integer_literal "3"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "two or three"
switch_entry
default: default_keyword "default"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "other"
expr: simple_identifier "x"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
expressionStmt
expression:
switchExpr
leftBrace: {
rightBrace: }
cases:
switchCase
label:
switchCaseLabel
colon: :
caseKeyword: case
caseItems:
switchCaseItem
pattern:
expressionPattern
expression:
integerLiteralExpr
literal: integerLiteral "1"
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "one"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
switchCase
label:
switchCaseLabel
colon: :
caseKeyword: case
caseItems:
switchCaseItem
trailingComma: ,
pattern:
expressionPattern
expression:
integerLiteralExpr
literal: integerLiteral "2"
switchCaseItem
pattern:
expressionPattern
expression:
integerLiteralExpr
literal: integerLiteral "3"
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "two or three"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
switchCase
label:
switchDefaultLabel
colon: :
defaultKeyword: default
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "other"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
subject:
declReferenceExpr
baseName: identifier "x"
switchKeyword: switch
---
@@ -76,32 +125,25 @@ top_level
block
stmt:
switch_expr
value:
name_expr
identifier: identifier "x"
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"
argument:
argument
value: string_literal "\"one\""
switch_case
pattern:
or_pattern
pattern:
@@ -109,17 +151,24 @@ top_level
expr: int_literal "2"
expr_equality_pattern
expr: int_literal "3"
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value: string_literal "\"two or three\""
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"
argument:
argument
value: string_literal "\"other\""

View File

@@ -7,77 +7,111 @@ case .square(let s):
---
source_file
statement:
switch_statement
entry:
switch_entry
pattern:
switch_pattern
pattern:
pattern
kind:
case_pattern
arguments:
tuple_pattern
item:
tuple_pattern_item
pattern:
pattern
kind:
binding_pattern
binding:
value_binding_pattern
mutability: let
pattern:
pattern
bound_identifier: simple_identifier "r"
dot: .
name: simple_identifier "circle"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "r"
switch_entry
pattern:
switch_pattern
pattern:
pattern
kind:
case_pattern
arguments:
tuple_pattern
item:
tuple_pattern_item
pattern:
pattern
kind:
binding_pattern
binding:
value_binding_pattern
mutability: let
pattern:
pattern
bound_identifier: simple_identifier "s"
dot: .
name: simple_identifier "square"
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "s"
expr: simple_identifier "shape"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
expressionStmt
expression:
switchExpr
leftBrace: {
rightBrace: }
cases:
switchCase
label:
switchCaseLabel
colon: :
caseKeyword: case
caseItems:
switchCaseItem
pattern:
expressionPattern
expression:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
patternExpr
pattern:
valueBindingPattern
pattern:
identifierPattern
identifier: identifier "r"
bindingSpecifier: let
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "circle"
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "r"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
switchCase
label:
switchCaseLabel
colon: :
caseKeyword: case
caseItems:
switchCaseItem
pattern:
expressionPattern
expression:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
patternExpr
pattern:
valueBindingPattern
pattern:
identifierPattern
identifier: identifier "s"
bindingSpecifier: let
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "square"
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "s"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
subject:
declReferenceExpr
baseName: identifier "shape"
switchKeyword: switch
---
@@ -86,55 +120,55 @@ top_level
block
stmt:
switch_expr
value:
name_expr
identifier: identifier "shape"
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
constructor:
member_access_expr
base: inferred_type_expr "."
member: identifier "circle"
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
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "s"
callee:
name_expr
identifier: identifier "print"
identifier: identifier "r"
switch_case
pattern:
constructor_pattern
constructor:
member_access_expr
base: inferred_type_expr "."
member: identifier "square"
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"
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "s"

View File

@@ -7,79 +7,119 @@ case .thread(threadRowId: _, let 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"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
expressionStmt
expression:
switchExpr
leftBrace: {
rightBrace: }
cases:
switchCase
label:
switchCaseLabel
colon: :
caseKeyword: case
caseItems:
switchCaseItem
pattern:
expressionPattern
expression:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
colon: :
label: identifier "isAcknowledged"
expression:
booleanLiteralExpr
literal: false
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "implicit"
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "yes"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
switchCase
label:
switchCaseLabel
colon: :
caseKeyword: case
caseItems:
switchCaseItem
pattern:
expressionPattern
expression:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
colon: :
label: identifier "threadRowId"
expression:
discardAssignmentExpr
wildcard: _
trailingComma: ,
labeledExpr
expression:
patternExpr
pattern:
valueBindingPattern
pattern:
identifierPattern
identifier: identifier "rowId"
bindingSpecifier: let
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "thread"
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "rowId"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
subject:
declReferenceExpr
baseName: identifier "x"
switchKeyword: switch
---
@@ -88,45 +128,40 @@ top_level
block
stmt:
switch_expr
value:
name_expr
identifier: identifier "x"
case:
switch_case
body:
block
stmt:
call_expr
argument:
argument
value: string_literal "\"yes\""
callee:
name_expr
identifier: identifier "print"
pattern:
constructor_pattern
constructor:
member_access_expr
base: inferred_type_expr "."
member: identifier "implicit"
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"
argument:
argument
value: string_literal "\"yes\""
switch_case
pattern:
constructor_pattern
constructor:
member_access_expr
base: inferred_type_expr "."
member: identifier "thread"
element:
pattern_element
key: identifier "threadRowId"
@@ -135,10 +170,15 @@ top_level
pattern:
name_pattern
identifier: identifier "rowId"
constructor:
member_access_expr
base: inferred_type_expr "."
member: identifier "thread"
value:
name_expr
identifier: identifier "x"
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "rowId"

View File

@@ -2,29 +2,47 @@ let y = x > 0 ? 1 : -1
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "y"
value:
ternary_expression
condition:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "0"
if_false:
prefix_expression
operation: -
target: integer_literal "1"
if_true: integer_literal "1"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
ternaryExpr
colon: :
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator ">"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
questionMark: ?
elseExpression:
prefixOperatorExpr
expression:
integerLiteralExpr
literal: integerLiteral "1"
operator: prefixOperator "-"
thenExpression:
integerLiteralExpr
literal: integerLiteral "1"
pattern:
identifierPattern
identifier: identifier "y"
---
@@ -41,13 +59,13 @@ top_level
if_expr
condition:
binary_expr
operator: infix_operator ">"
left:
name_expr
identifier: identifier "x"
operator: infix_operator ">"
right: int_literal "0"
then: int_literal "1"
else:
unary_expr
operand: int_literal "1"
operator: prefix_operator "-"
then: int_literal "1"

View File

@@ -2,12 +2,21 @@
---
source_file
statement:
additive_expression
lhs: integer_literal "1"
op: +
rhs: integer_literal "2"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
integerLiteralExpr
literal: integerLiteral "1"
rightOperand:
integerLiteralExpr
literal: integerLiteral "2"
---
@@ -16,6 +25,6 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "+"
left: int_literal "1"
operator: infix_operator "+"
right: int_literal "2"

View File

@@ -2,12 +2,21 @@ foo + bar
---
source_file
statement:
additive_expression
lhs: simple_identifier "foo"
op: +
rhs: simple_identifier "bar"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
declReferenceExpr
baseName: identifier "foo"
rightOperand:
declReferenceExpr
baseName: identifier "bar"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "+"
left:
name_expr
identifier: identifier "foo"
operator: infix_operator "+"
right:
name_expr
identifier: identifier "bar"

View File

@@ -2,15 +2,24 @@ import Foundation.Networking.URLSession
---
source_file
statement:
import_declaration
name:
identifier
part:
simple_identifier "Foundation"
simple_identifier "Networking"
simple_identifier "URLSession"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
importDecl
attributes:
modifiers:
importKeyword: import
path:
importPathComponent
name: identifier "Foundation"
trailingPeriod: .
importPathComponent
name: identifier "Networking"
trailingPeriod: .
importPathComponent
name: identifier "URLSession"
---
@@ -19,7 +28,6 @@ top_level
block
stmt:
import_declaration
pattern: bulk_importing_pattern "import Foundation.Networking.URLSession"
imported_expr:
member_access_expr
base:
@@ -29,3 +37,4 @@ top_level
identifier: identifier "Foundation"
member: identifier "Networking"
member: identifier "URLSession"
pattern: bulk_importing_pattern "import Foundation.Networking.URLSession"

View File

@@ -2,14 +2,21 @@ import Foundation.Networking
---
source_file
statement:
import_declaration
name:
identifier
part:
simple_identifier "Foundation"
simple_identifier "Networking"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
importDecl
attributes:
modifiers:
importKeyword: import
path:
importPathComponent
name: identifier "Foundation"
trailingPeriod: .
importPathComponent
name: identifier "Networking"
---
@@ -18,10 +25,10 @@ top_level
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"
pattern: bulk_importing_pattern "import Foundation.Networking"

View File

@@ -2,15 +2,22 @@ import struct Foundation.Date
---
source_file
statement:
import_declaration
name:
identifier
part:
simple_identifier "Foundation"
simple_identifier "Date"
scoped_import_kind: struct
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
importDecl
attributes:
modifiers:
importKeyword: import
importKindSpecifier: struct
path:
importPathComponent
name: identifier "Foundation"
trailingPeriod: .
importPathComponent
name: identifier "Date"
---
@@ -20,12 +27,12 @@ top_level
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"
pattern:
name_pattern
identifier: identifier "Date"

View File

@@ -2,12 +2,18 @@ import Foundation
---
source_file
statement:
import_declaration
name:
identifier
part: simple_identifier "Foundation"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
importDecl
attributes:
modifiers:
importKeyword: import
path:
importPathComponent
name: identifier "Foundation"
---
@@ -16,7 +22,7 @@ top_level
block
stmt:
import_declaration
pattern: bulk_importing_pattern "import Foundation"
imported_expr:
name_expr
identifier: identifier "Foundation"
pattern: bulk_importing_pattern "import Foundation"

View File

@@ -2,22 +2,29 @@ greet(person: "Bob")
---
source_file
statement:
call_expression
function: simple_identifier "greet"
suffix:
call_suffix
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
value_arguments
argument:
value_argument
name:
value_argument_label
name: simple_identifier "person"
value:
line_string_literal
text: line_str_text "Bob"
labeledExpr
colon: :
label: identifier "person"
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "Bob"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "greet"
---
@@ -26,10 +33,10 @@ top_level
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "greet"
argument:
argument
name: identifier "person"
value: string_literal "\"Bob\""
callee:
name_expr
identifier: identifier "greet"

View File

@@ -2,19 +2,28 @@ foo(1, 2)
---
source_file
statement:
call_expression
function: simple_identifier "foo"
suffix:
call_suffix
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
value_arguments
argument:
value_argument
value: integer_literal "1"
value_argument
value: integer_literal "2"
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "1"
trailingComma: ,
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "2"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "foo"
---
@@ -23,11 +32,11 @@ top_level
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "foo"
argument:
argument
value: int_literal "1"
argument
value: int_literal "2"
callee:
name_expr
identifier: identifier "foo"

View File

@@ -4,37 +4,60 @@ func greet(name: String = "world") {
---
source_file
statement:
function_declaration
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "name"
name: simple_identifier "greet"
parameter:
function_parameter
default_value:
line_string_literal
text: line_str_text "world"
parameter:
parameter
name: simple_identifier "name"
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "String"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionDecl
attributes:
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "name"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
name: identifier "greet"
modifiers:
signature:
functionSignature
parameterClause:
functionParameterClause
leftParen: (
rightParen: )
parameters:
functionParameter
colon: :
attributes:
modifiers:
type:
identifierType
name: identifier "String"
firstName: identifier "name"
defaultValue:
initializerClause
equal: =
value:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "world"
funcKeyword: func
---
@@ -43,22 +66,22 @@ top_level
block
stmt:
function_declaration
name: identifier "greet"
parameter:
parameter
pattern:
name_pattern
identifier: identifier "name"
default: string_literal "\"world\""
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
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"

View File

@@ -4,35 +4,51 @@ func greet(person name: String) {
---
source_file
statement:
function_declaration
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "name"
name: simple_identifier "greet"
parameter:
function_parameter
parameter:
parameter
external_name: simple_identifier "person"
name: simple_identifier "name"
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "String"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionDecl
attributes:
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "name"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
name: identifier "greet"
modifiers:
signature:
functionSignature
parameterClause:
functionParameterClause
leftParen: (
rightParen: )
parameters:
functionParameter
colon: :
attributes:
modifiers:
type:
identifierType
name: identifier "String"
firstName: identifier "person"
secondName: identifier "name"
funcKeyword: func
---
@@ -41,18 +57,6 @@ top_level
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
@@ -60,3 +64,15 @@ top_level
pattern:
name_pattern
identifier: identifier "name"
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "name"

View File

@@ -4,24 +4,46 @@ func greet() {
---
source_file
statement:
function_declaration
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value:
line_string_literal
text: line_str_text "hello"
name: simple_identifier "greet"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionDecl
attributes:
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "hello"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
name: identifier "greet"
modifiers:
signature:
functionSignature
parameterClause:
functionParameterClause
leftParen: (
rightParen: )
parameters:
funcKeyword: func
---
@@ -30,14 +52,14 @@ top_level
block
stmt:
function_declaration
name: identifier "greet"
body:
block
stmt:
call_expr
argument:
argument
value: string_literal "\"hello\""
callee:
name_expr
identifier: identifier "print"
name: identifier "greet"
argument:
argument
value: string_literal "\"hello\""

View File

@@ -4,52 +4,68 @@ func add(_ a: Int, _ b: Int) -> Int {
---
source_file
statement:
function_declaration
body:
block
statement:
control_transfer_statement
kind: return
result:
additive_expression
lhs: simple_identifier "a"
op: +
rhs: simple_identifier "b"
name: simple_identifier "add"
parameter:
function_parameter
parameter:
parameter
external_name: simple_identifier "_"
name: simple_identifier "a"
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
function_parameter
parameter:
parameter
external_name: simple_identifier "_"
name: simple_identifier "b"
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
return_type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionDecl
attributes:
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
returnStmt
expression:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
returnKeyword: return
name: identifier "add"
modifiers:
signature:
functionSignature
parameterClause:
functionParameterClause
leftParen: (
rightParen: )
parameters:
functionParameter
colon: :
attributes:
modifiers:
trailingComma: ,
type:
identifierType
name: identifier "Int"
firstName: _
secondName: identifier "a"
functionParameter
colon: :
attributes:
modifiers:
type:
identifierType
name: identifier "Int"
firstName: _
secondName: identifier "b"
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "Int"
funcKeyword: func
---
@@ -58,19 +74,6 @@ top_level
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
@@ -86,3 +89,16 @@ top_level
return_type:
named_type_expr
name: identifier "Int"
body:
block
stmt:
return_expr
value:
binary_expr
left:
name_expr
identifier: identifier "a"
operator: infix_operator "+"
right:
name_expr
identifier: identifier "b"

View File

@@ -4,41 +4,58 @@ func identity<T>(_ x: T) -> T {
---
source_file
statement:
function_declaration
body:
block
statement:
control_transfer_statement
kind: return
result: simple_identifier "x"
name: simple_identifier "identity"
parameter:
function_parameter
parameter:
parameter
external_name: simple_identifier "_"
name: simple_identifier "x"
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "T"
return_type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "T"
type_parameters:
type_parameters
parameter:
type_parameter
name: type_identifier "T"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionDecl
attributes:
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
returnStmt
expression:
declReferenceExpr
baseName: identifier "x"
returnKeyword: return
name: identifier "identity"
genericParameterClause:
genericParameterClause
parameters:
genericParameter
attributes:
name: identifier "T"
leftAngle: <
rightAngle: >
modifiers:
signature:
functionSignature
parameterClause:
functionParameterClause
leftParen: (
rightParen: )
parameters:
functionParameter
colon: :
attributes:
modifiers:
type:
identifierType
name: identifier "T"
firstName: _
secondName: identifier "x"
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "T"
funcKeyword: func
---
@@ -47,13 +64,6 @@ top_level
block
stmt:
function_declaration
body:
block
stmt:
return_expr
value:
name_expr
identifier: identifier "x"
name: identifier "identity"
parameter:
parameter
@@ -64,3 +74,10 @@ top_level
return_type:
named_type_expr
name: identifier "T"
body:
block
stmt:
return_expr
value:
name_expr
identifier: identifier "x"

View File

@@ -2,30 +2,39 @@ 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"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "1"
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "some"
pattern:
identifierPattern
identifier: identifier "y"
---
@@ -40,10 +49,10 @@ top_level
identifier: identifier "y"
value:
call_expr
argument:
argument
value: int_literal "1"
callee:
member_access_expr
base: inferred_type_expr ".some"
member: identifier "some"
argument:
argument
value: int_literal "1"

View File

@@ -2,21 +2,29 @@ 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"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "foo"
pattern:
identifierPattern
identifier: identifier "x"
---

View File

@@ -2,22 +2,29 @@ list.append(1)
---
source_file
statement:
call_expression
function:
navigation_expression
suffix:
navigation_suffix
suffix: simple_identifier "append"
target: simple_identifier "list"
suffix:
call_suffix
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
value_arguments
argument:
value_argument
value: integer_literal "1"
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "1"
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "append"
base:
declReferenceExpr
baseName: identifier "list"
---
@@ -26,12 +33,12 @@ top_level
block
stmt:
call_expr
argument:
argument
value: int_literal "1"
callee:
member_access_expr
base:
name_expr
identifier: identifier "list"
member: identifier "append"
argument:
argument
value: int_literal "1"

View File

@@ -0,0 +1,156 @@
typealias NestedFunction = ((Int) -> Bool) -> Bool
typealias MixedParametersAndTuples = ((Int) -> Bool, String) -> (Bool, Int)
---
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
typeAliasDecl
attributes:
name: identifier "NestedFunction"
modifiers:
initializer:
typeInitializerClause
equal: =
value:
functionType
leftParen: (
rightParen: )
parameters:
tupleTypeElement
type:
functionType
leftParen: (
rightParen: )
parameters:
tupleTypeElement
type:
identifierType
name: identifier "Int"
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "Bool"
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "Bool"
typealiasKeyword: typealias
codeBlockItem
item:
typeAliasDecl
attributes:
name: identifier "MixedParametersAndTuples"
modifiers:
initializer:
typeInitializerClause
equal: =
value:
functionType
leftParen: (
rightParen: )
parameters:
tupleTypeElement
trailingComma: ,
type:
functionType
leftParen: (
rightParen: )
parameters:
tupleTypeElement
type:
identifierType
name: identifier "Int"
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "Bool"
tupleTypeElement
type:
identifierType
name: identifier "String"
returnClause:
returnClause
arrow: ->
type:
tupleType
leftParen: (
rightParen: )
elements:
tupleTypeElement
trailingComma: ,
type:
identifierType
name: identifier "Bool"
tupleTypeElement
type:
identifierType
name: identifier "Int"
typealiasKeyword: typealias
---
top_level
body:
block
stmt:
type_alias_declaration
name: identifier "NestedFunction"
type:
function_type_expr
parameter:
parameter
type:
function_type_expr
parameter:
parameter
type:
named_type_expr
name: identifier "Int"
return_type:
named_type_expr
name: identifier "Bool"
return_type:
named_type_expr
name: identifier "Bool"
type_alias_declaration
name: identifier "MixedParametersAndTuples"
type:
function_type_expr
parameter:
parameter
type:
function_type_expr
parameter:
parameter
type:
named_type_expr
name: identifier "Int"
return_type:
named_type_expr
name: identifier "Bool"
parameter
type:
named_type_expr
name: identifier "String"
return_type:
tuple_type_expr
element:
tuple_type_element
type:
named_type_expr
name: identifier "Bool"
tuple_type_element
type:
named_type_expr
name: identifier "Int"

View File

@@ -0,0 +1,3 @@
typealias NestedFunction = ((Int) -> Bool) -> Bool
typealias MixedParametersAndTuples = ((Int) -> Bool, String) -> (Bool, Int)

View File

@@ -4,54 +4,72 @@ func sum(_ values: Int...) -> Int {
---
source_file
statement:
function_declaration
body:
block
statement:
control_transfer_statement
kind: return
result:
call_expression
function:
navigation_expression
suffix:
navigation_suffix
suffix: simple_identifier "reduce"
target: simple_identifier "values"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: integer_literal "0"
value_argument
value:
referenceable_operator
operator: +
name: simple_identifier "sum"
parameter:
function_parameter
parameter:
parameter
external_name: simple_identifier "_"
name: simple_identifier "values"
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
return_type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionDecl
attributes:
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
returnStmt
expression:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
integerLiteralExpr
literal: integerLiteral "0"
trailingComma: ,
labeledExpr
expression:
declReferenceExpr
baseName: binaryOperator "+"
additionalTrailingClosures:
calledExpression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "reduce"
base:
declReferenceExpr
baseName: identifier "values"
returnKeyword: return
name: identifier "sum"
modifiers:
signature:
functionSignature
parameterClause:
functionParameterClause
leftParen: (
rightParen: )
parameters:
functionParameter
colon: :
attributes:
modifiers:
type:
identifierType
name: identifier "Int"
ellipsis: ...
firstName: _
secondName: identifier "values"
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "Int"
funcKeyword: func
---
@@ -60,25 +78,6 @@ top_level
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
@@ -89,3 +88,22 @@ top_level
return_type:
named_type_expr
name: identifier "Int"
body:
block
stmt:
return_expr
value:
call_expr
callee:
member_access_expr
base:
name_expr
identifier: identifier "values"
member: identifier "reduce"
argument:
argument
value: int_literal "0"
argument
value:
name_expr
identifier: identifier "+"

View File

@@ -3,10 +3,17 @@ false
---
source_file
statement:
boolean_literal
boolean_literal
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
booleanLiteralExpr
literal: true
codeBlockItem
item:
booleanLiteralExpr
literal: false
---

View File

@@ -2,8 +2,13 @@
---
source_file
statement: real_literal "3.14"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
floatLiteralExpr
literal: floatLiteral "3.14"
---

View File

@@ -2,8 +2,13 @@
---
source_file
statement: integer_literal "42"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
integerLiteralExpr
literal: integerLiteral "42"
---

View File

@@ -2,11 +2,16 @@
---
source_file
statement:
prefix_expression
operation: -
target: integer_literal "7"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
prefixOperatorExpr
expression:
integerLiteralExpr
literal: integerLiteral "7"
operator: prefixOperator "-"
---

View File

@@ -2,8 +2,13 @@ nil
---
source_file
statement: nil
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
nilLiteralExpr
nilKeyword: nil
---

View File

@@ -2,10 +2,17 @@
---
source_file
statement:
line_string_literal
text: line_str_text "hello"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "hello"
---

View File

@@ -2,13 +2,28 @@
---
source_file
statement:
line_string_literal
interpolation:
interpolated_expression
value: simple_identifier "name"
text: line_str_text "hello "
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment "hello "
expressionSegment
leftParen: (
rightParen: )
backslash: \
expressions:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "name"
stringSegment
content: stringSegment
---

View File

@@ -6,51 +6,95 @@ for x in xs {
---
source_file
statement:
for_statement
body:
block
statement:
if_statement
body:
block
statement:
control_transfer_statement
kind: continue
condition:
if_condition
kind:
comparison_expression
lhs: simple_identifier "x"
op: <
rhs: integer_literal "0"
if_statement
body:
block
statement:
control_transfer_statement
kind: break
condition:
if_condition
kind:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "100"
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "x"
collection: simple_identifier "xs"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
pattern
bound_identifier: simple_identifier "x"
forStmt
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
expressionStmt
expression:
ifExpr
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
continueStmt
continueKeyword: continue
conditions:
conditionElement
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "<"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
ifKeyword: if
codeBlockItem
item:
expressionStmt
expression:
ifExpr
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
breakStmt
breakKeyword: break
conditions:
conditionElement
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator ">"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "100"
ifKeyword: if
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "x"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
pattern:
identifierPattern
identifier: identifier "x"
inKeyword: in
forKeyword: for
sequence:
declReferenceExpr
baseName: identifier "xs"
---
@@ -59,16 +103,22 @@ top_level
block
stmt:
for_each_stmt
pattern:
name_pattern
identifier: identifier "x"
iterable:
name_expr
identifier: identifier "xs"
body:
block
stmt:
if_expr
condition:
binary_expr
operator: infix_operator "<"
left:
name_expr
identifier: identifier "x"
operator: infix_operator "<"
right: int_literal "0"
then:
block
@@ -76,26 +126,20 @@ top_level
if_expr
condition:
binary_expr
operator: infix_operator ">"
left:
name_expr
identifier: identifier "x"
operator: infix_operator ">"
right: int_literal "100"
then:
block
stmt: break_expr "break"
call_expr
callee:
name_expr
identifier: identifier "print"
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"

View File

@@ -4,30 +4,55 @@ for x in [1, 2, 3] {
---
source_file
statement:
for_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "x"
collection:
array_literal
element:
integer_literal "1"
integer_literal "2"
integer_literal "3"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
pattern
bound_identifier: simple_identifier "x"
forStmt
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "x"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
pattern:
identifierPattern
identifier: identifier "x"
inKeyword: in
forKeyword: for
sequence:
arrayExpr
elements:
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "1"
trailingComma: ,
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "2"
trailingComma: ,
arrayElement
expression:
integerLiteralExpr
literal: integerLiteral "3"
leftSquare: [
rightSquare: ]
---
@@ -36,18 +61,6 @@ top_level
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"
@@ -57,3 +70,15 @@ top_level
int_literal "1"
int_literal "2"
int_literal "3"
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "x"

View File

@@ -4,29 +4,47 @@ for i in 0..<10 {
---
source_file
statement:
for_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "i"
collection:
range_expression
end: integer_literal "10"
op: ..<
start: integer_literal "0"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
pattern
bound_identifier: simple_identifier "i"
forStmt
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "i"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
pattern:
identifierPattern
identifier: identifier "i"
inKeyword: in
forKeyword: for
sequence:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "..<"
leftOperand:
integerLiteralExpr
literal: integerLiteral "0"
rightOperand:
integerLiteralExpr
literal: integerLiteral "10"
---
@@ -35,23 +53,23 @@ top_level
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"
operator: infix_operator "..<"
right: int_literal "10"
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "i"

View File

@@ -4,33 +4,53 @@ for x in xs where x > 0 {
---
source_file
statement:
for_statement
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "x"
collection: simple_identifier "xs"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
pattern
bound_identifier: simple_identifier "x"
where:
where_clause
expr:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "0"
keyword: where_keyword "where"
forStmt
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "x"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
pattern:
identifierPattern
identifier: identifier "x"
whereClause:
whereClause
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator ">"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
whereKeyword: where
inKeyword: in
forKeyword: for
sequence:
declReferenceExpr
baseName: identifier "xs"
---
@@ -39,28 +59,28 @@ top_level
block
stmt:
for_each_stmt
pattern:
name_pattern
identifier: identifier "x"
iterable:
name_expr
identifier: identifier "xs"
guard:
binary_expr
left:
name_expr
identifier: identifier "x"
operator: infix_operator ">"
right: int_literal "0"
body:
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
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"

View File

@@ -4,25 +4,42 @@ repeat {
---
source_file
statement:
repeat_while_statement
body:
block
statement:
assignment
operator: -=
result: integer_literal "1"
target:
directly_assignable_expression
expr: simple_identifier "x"
condition:
if_condition
kind:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "0"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
repeatStmt
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "-="
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "1"
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator ">"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
repeatKeyword: repeat
whileKeyword: while
---
@@ -35,15 +52,15 @@ top_level
block
stmt:
compound_assign_expr
operator: infix_operator "-="
target:
name_expr
identifier: identifier "x"
operator: infix_operator "-="
value: int_literal "1"
condition:
binary_expr
operator: infix_operator ">"
left:
name_expr
identifier: identifier "x"
operator: infix_operator ">"
right: int_literal "0"

View File

@@ -4,25 +4,43 @@ while x > 0 {
---
source_file
statement:
while_statement
body:
block
statement:
assignment
operator: -=
result: integer_literal "1"
target:
directly_assignable_expression
expr: simple_identifier "x"
condition:
if_condition
kind:
comparison_expression
lhs: simple_identifier "x"
op: >
rhs: integer_literal "0"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
whileStmt
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "-="
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "1"
conditions:
conditionElement
condition:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator ">"
leftOperand:
declReferenceExpr
baseName: identifier "x"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
whileKeyword: while
---
@@ -31,19 +49,19 @@ top_level
block
stmt:
while_stmt
condition:
binary_expr
left:
name_expr
identifier: identifier "x"
operator: infix_operator ">"
right: int_literal "0"
body:
block
stmt:
compound_assign_expr
operator: infix_operator "-="
target:
name_expr
identifier: identifier "x"
operator: infix_operator "-="
value: int_literal "1"
condition:
binary_expr
operator: infix_operator ">"
left:
name_expr
identifier: identifier "x"
right: int_literal "0"

View File

@@ -2,12 +2,21 @@ a + b
---
source_file
statement:
additive_expression
lhs: simple_identifier "a"
op: +
rhs: simple_identifier "b"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "+"
left:
name_expr
identifier: identifier "a"
operator: infix_operator "+"
right:
name_expr
identifier: identifier "b"

View File

@@ -2,12 +2,21 @@ a < b
---
source_file
statement:
comparison_expression
lhs: simple_identifier "a"
op: <
rhs: simple_identifier "b"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "<"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "<"
left:
name_expr
identifier: identifier "a"
operator: infix_operator "<"
right:
name_expr
identifier: identifier "b"

View File

@@ -2,12 +2,21 @@ a / b
---
source_file
statement:
multiplicative_expression
lhs: simple_identifier "a"
op: /
rhs: simple_identifier "b"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "/"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "/"
left:
name_expr
identifier: identifier "a"
operator: infix_operator "/"
right:
name_expr
identifier: identifier "b"

View File

@@ -2,12 +2,21 @@ a == b
---
source_file
statement:
equality_expression
lhs: simple_identifier "a"
op: ==
rhs: simple_identifier "b"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "=="
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "=="
left:
name_expr
identifier: identifier "a"
operator: infix_operator "=="
right:
name_expr
identifier: identifier "b"

View File

@@ -2,12 +2,21 @@ a && b
---
source_file
statement:
conjunction_expression
lhs: simple_identifier "a"
op: &&
rhs: simple_identifier "b"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "&&"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "&&"
left:
name_expr
identifier: identifier "a"
operator: infix_operator "&&"
right:
name_expr
identifier: identifier "b"

View File

@@ -2,11 +2,16 @@
---
source_file
statement:
prefix_expression
operation: bang "!"
target: simple_identifier "a"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
prefixOperatorExpr
expression:
declReferenceExpr
baseName: identifier "a"
operator: prefixOperator "!"
---

View File

@@ -2,12 +2,21 @@ a || b
---
source_file
statement:
disjunction_expression
lhs: simple_identifier "a"
op: ||
rhs: simple_identifier "b"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "||"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "||"
left:
name_expr
identifier: identifier "a"
operator: infix_operator "||"
right:
name_expr
identifier: identifier "b"

View File

@@ -2,12 +2,21 @@ a * b
---
source_file
statement:
multiplicative_expression
lhs: simple_identifier "a"
op: *
rhs: simple_identifier "b"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "*"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "*"
left:
name_expr
identifier: identifier "a"
operator: infix_operator "*"
right:
name_expr
identifier: identifier "b"

View File

@@ -2,16 +2,29 @@ a + b * c
---
source_file
statement:
additive_expression
lhs: simple_identifier "a"
op: +
rhs:
multiplicative_expression
lhs: simple_identifier "b"
op: *
rhs: simple_identifier "c"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "*"
leftOperand:
declReferenceExpr
baseName: identifier "b"
rightOperand:
declReferenceExpr
baseName: identifier "c"
---
@@ -20,16 +33,16 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "+"
left:
name_expr
identifier: identifier "a"
operator: infix_operator "+"
right:
binary_expr
operator: infix_operator "*"
left:
name_expr
identifier: identifier "b"
operator: infix_operator "*"
right:
name_expr
identifier: identifier "c"

View File

@@ -2,20 +2,35 @@
---
source_file
statement:
multiplicative_expression
lhs:
tuple_expression
element:
tuple_expression_item
value:
additive_expression
lhs: simple_identifier "a"
op: +
rhs: simple_identifier "b"
op: *
rhs: simple_identifier "c"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "*"
leftOperand:
tupleExpr
leftParen: (
rightParen: )
elements:
labeledExpr
expression:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "+"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
rightOperand:
declReferenceExpr
baseName: identifier "c"
---
@@ -24,8 +39,8 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "*"
left: tuple_expr "(a + b)"
operator: infix_operator "*"
right:
name_expr
identifier: identifier "c"

View File

@@ -2,12 +2,21 @@
---
source_file
statement:
range_expression
end: integer_literal "10"
op: ...
start: integer_literal "1"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "..."
leftOperand:
integerLiteralExpr
literal: integerLiteral "1"
rightOperand:
integerLiteralExpr
literal: integerLiteral "10"
---
@@ -16,6 +25,6 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "..."
left: int_literal "1"
operator: infix_operator "..."
right: int_literal "10"

View File

@@ -2,12 +2,21 @@ a - b
---
source_file
statement:
additive_expression
lhs: simple_identifier "a"
op: -
rhs: simple_identifier "b"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "-"
leftOperand:
declReferenceExpr
baseName: identifier "a"
rightOperand:
declReferenceExpr
baseName: identifier "b"
---
@@ -16,10 +25,10 @@ top_level
block
stmt:
binary_expr
operator: infix_operator "-"
left:
name_expr
identifier: identifier "a"
operator: infix_operator "-"
right:
name_expr
identifier: identifier "b"

View File

@@ -6,37 +6,54 @@ do {
---
source_file
statement:
do_statement
body:
block
statement:
try_expression
expr:
call_expression
function: simple_identifier "foo"
suffix:
call_suffix
arguments:
value_arguments
operator:
try_operator
catch:
catch_block
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
doStmt
body:
block
statement:
call_expression
function: simple_identifier "print"
suffix:
call_suffix
arguments:
value_arguments
argument:
value_argument
value: simple_identifier "error"
keyword: catch_keyword "catch"
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
tryExpr
expression:
functionCallExpr
leftParen: (
rightParen: )
arguments:
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "foo"
tryKeyword: try
catchClauses:
catchClause
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
functionCallExpr
leftParen: (
rightParen: )
arguments:
labeledExpr
expression:
declReferenceExpr
baseName: identifier "error"
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "print"
catchItems:
catchKeyword: catch
doKeyword: do
---
@@ -61,11 +78,11 @@ top_level
block
stmt:
call_expr
callee:
name_expr
identifier: identifier "print"
argument:
argument
value:
name_expr
identifier: identifier "error"
callee:
name_expr
identifier: identifier "print"

View File

@@ -2,21 +2,29 @@ let n = opt!
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "n"
value:
postfix_expression
operation: bang "!"
target: simple_identifier "opt"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
forceUnwrapExpr
expression:
declReferenceExpr
baseName: identifier "opt"
exclamationMark: !
pattern:
identifierPattern
identifier: identifier "n"
---

View File

@@ -2,21 +2,34 @@ let n = opt ?? 0
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "n"
value:
nil_coalescing_expression
if_nil: integer_literal "0"
value: simple_identifier "opt"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
infixOperatorExpr
operator:
binaryOperatorExpr
operator: binaryOperator "??"
leftOperand:
declReferenceExpr
baseName: identifier "opt"
rightOperand:
integerLiteralExpr
literal: integerLiteral "0"
pattern:
identifierPattern
identifier: identifier "n"
---
@@ -31,8 +44,8 @@ top_level
identifier: identifier "n"
value:
binary_expr
operator: infix_operator "??"
left:
name_expr
identifier: identifier "opt"
operator: infix_operator "??"
right: int_literal "0"

View File

@@ -2,32 +2,44 @@ let n = obj?.foo?.bar
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "n"
value:
navigation_expression
suffix:
navigation_suffix
suffix: simple_identifier "bar"
target:
optional_chain_marker
expr:
navigation_expression
suffix:
navigation_suffix
suffix: simple_identifier "foo"
target:
optional_chain_marker
expr: simple_identifier "obj"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "bar"
base:
optionalChainingExpr
expression:
memberAccessExpr
period: .
declName:
declReferenceExpr
baseName: identifier "foo"
base:
optionalChainingExpr
expression:
declReferenceExpr
baseName: identifier "obj"
questionMark: ?
questionMark: ?
pattern:
identifierPattern
identifier: identifier "n"
---

View File

@@ -2,29 +2,35 @@ let x: Int? = nil
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "x"
type:
type_annotation
type:
type
name:
optional_type
wrapped:
user_type
part:
simple_user_type
name: type_identifier "Int"
value: nil
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
nilLiteralExpr
nilKeyword: nil
pattern:
identifierPattern
identifier: identifier "x"
typeAnnotation:
typeAnnotation
colon: :
type:
optionalType
wrappedType:
identifierType
name: identifier "Int"
questionMark: ?
---

View File

@@ -4,25 +4,50 @@ func read() throws -> String {
---
source_file
statement:
function_declaration
body:
block
statement:
control_transfer_statement
kind: return
result:
line_string_literal
name: simple_identifier "read"
return_type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "String"
throws: throws "throws"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
functionDecl
attributes:
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
returnStmt
expression:
stringLiteralExpr
closingQuote: "
openingQuote: "
segments:
stringSegment
content: stringSegment
returnKeyword: return
name: identifier "read"
modifiers:
signature:
functionSignature
effectSpecifiers:
functionEffectSpecifiers
throwsClause:
throwsClause
throwsSpecifier: throws
parameterClause:
functionParameterClause
leftParen: (
rightParen: )
parameters:
returnClause:
returnClause
arrow: ->
type:
identifierType
name: identifier "String"
funcKeyword: func
---
@@ -31,12 +56,12 @@ top_level
block
stmt:
function_declaration
name: identifier "read"
return_type:
named_type_expr
name: identifier "String"
body:
block
stmt:
return_expr
value: string_literal "\"\""
name: identifier "read"
return_type:
named_type_expr
name: identifier "String"

View File

@@ -2,28 +2,36 @@ let result = try! foo()
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "result"
value:
try_expression
expr:
call_expression
function: simple_identifier "foo"
suffix:
call_suffix
arguments:
value_arguments
operator:
try_operator
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
tryExpr
expression:
functionCallExpr
leftParen: (
rightParen: )
arguments:
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "foo"
questionOrExclamationMark: !
tryKeyword: try
pattern:
identifierPattern
identifier: identifier "result"
---

View File

@@ -2,28 +2,36 @@ let result = try? foo()
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: let
declarator:
property_binding
name:
pattern
bound_identifier: simple_identifier "result"
value:
try_expression
expr:
call_expression
function: simple_identifier "foo"
suffix:
call_suffix
arguments:
value_arguments
operator:
try_operator
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
initializer:
initializerClause
equal: =
value:
tryExpr
expression:
functionCallExpr
leftParen: (
rightParen: )
arguments:
additionalTrailingClosures:
calledExpression:
declReferenceExpr
baseName: identifier "foo"
questionOrExclamationMark: ?
tryKeyword: try
pattern:
identifierPattern
identifier: identifier "result"
---

View File

@@ -11,54 +11,84 @@ var p: Int {
---
source_file
statement:
property_declaration
binding:
value_binding_pattern
mutability: var
declarator:
property_binding
computed_value:
computed_property
accessor:
computed_getter
body:
block
statement:
switch_statement
entry:
switch_entry
pattern:
switch_pattern
pattern:
pattern
kind: simple_identifier "someConstant"
statement:
control_transfer_statement
kind: return
result: integer_literal "1"
switch_entry
default: default_keyword "default"
statement:
control_transfer_statement
kind: return
result: integer_literal "2"
expr: simple_identifier "y"
specifier:
getter_specifier
name:
pattern
bound_identifier: simple_identifier "p"
type:
type_annotation
type:
type
name:
user_type
part:
simple_user_type
name: type_identifier "Int"
sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: var
bindings:
patternBinding
pattern:
identifierPattern
identifier: identifier "p"
typeAnnotation:
typeAnnotation
colon: :
type:
identifierType
name: identifier "Int"
accessorBlock:
accessorBlock
accessors:
accessorDecl
accessorSpecifier: get
attributes:
body:
codeBlock
leftBrace: {
rightBrace: }
statements:
codeBlockItem
item:
expressionStmt
expression:
switchExpr
leftBrace: {
rightBrace: }
cases:
switchCase
label:
switchCaseLabel
colon: :
caseKeyword: case
caseItems:
switchCaseItem
pattern:
expressionPattern
expression:
declReferenceExpr
baseName: identifier "someConstant"
statements:
codeBlockItem
item:
returnStmt
expression:
integerLiteralExpr
literal: integerLiteral "1"
returnKeyword: return
switchCase
label:
switchDefaultLabel
colon: :
defaultKeyword: default
statements:
codeBlockItem
item:
returnStmt
expression:
integerLiteralExpr
literal: integerLiteral "2"
returnKeyword: return
subject:
declReferenceExpr
baseName: identifier "y"
switchKeyword: switch
leftBrace: {
rightBrace: }
---
@@ -67,34 +97,34 @@ top_level
block
stmt:
accessor_declaration
modifier: modifier "var"
name: identifier "p"
accessor_kind: accessor_kind "get"
type:
named_type_expr
name: identifier "Int"
body:
block
stmt:
switch_expr
value:
name_expr
identifier: identifier "y"
case:
switch_case
body:
block
stmt:
return_expr
value: int_literal "1"
pattern:
expr_equality_pattern
expr:
name_expr
identifier: identifier "someConstant"
body:
block
stmt:
return_expr
value: int_literal "1"
switch_case
body:
block
stmt:
return_expr
value: int_literal "2"
value:
name_expr
identifier: identifier "y"
modifier: modifier "var"
name: identifier "p"
type:
named_type_expr
name: identifier "Int"
accessor_kind: accessor_kind "get"

Some files were not shown because too many files have changed in this diff Show More