mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Owned AST IR
This commit is contained in:
parent
04d2b7b256
commit
627eddbc7e
2 changed files with 1990 additions and 1981 deletions
|
@ -223,35 +223,35 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct AstSrc<'a> {
|
pub(crate) struct AstSrc {
|
||||||
pub(crate) tokens: &'a [&'a str],
|
pub(crate) tokens: Vec<String>,
|
||||||
pub(crate) nodes: &'a [AstNodeSrc<'a>],
|
pub(crate) nodes: Vec<AstNodeSrc>,
|
||||||
pub(crate) enums: &'a [AstEnumSrc<'a>],
|
pub(crate) enums: Vec<AstEnumSrc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct AstNodeSrc<'a> {
|
pub(crate) struct AstNodeSrc {
|
||||||
pub(crate) doc: &'a [&'a str],
|
pub(crate) doc: Vec<String>,
|
||||||
pub(crate) name: &'a str,
|
pub(crate) name: String,
|
||||||
pub(crate) traits: &'a [&'a str],
|
pub(crate) traits: Vec<String>,
|
||||||
pub(crate) fields: &'a [Field<'a>],
|
pub(crate) fields: Vec<Field>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum Field<'a> {
|
pub(crate) enum Field {
|
||||||
Token(&'a str),
|
Token(String),
|
||||||
Node { name: &'a str, src: FieldSrc<'a> },
|
Node { name: String, src: FieldSrc },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum FieldSrc<'a> {
|
pub(crate) enum FieldSrc {
|
||||||
Shorthand,
|
Shorthand,
|
||||||
Optional(&'a str),
|
Optional(String),
|
||||||
Many(&'a str),
|
Many(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct AstEnumSrc<'a> {
|
pub(crate) struct AstEnumSrc {
|
||||||
pub(crate) doc: &'a [&'a str],
|
pub(crate) doc: Vec<String>,
|
||||||
pub(crate) name: &'a str,
|
pub(crate) name: String,
|
||||||
pub(crate) traits: &'a [&'a str],
|
pub(crate) traits: Vec<String>,
|
||||||
pub(crate) variants: &'a [&'a str],
|
pub(crate) variants: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! ast_nodes {
|
macro_rules! ast_nodes {
|
||||||
|
@ -261,12 +261,12 @@ macro_rules! ast_nodes {
|
||||||
$($field_name:ident $(![$token:tt])? $(: $ty:tt)?),*$(,)?
|
$($field_name:ident $(![$token:tt])? $(: $ty:tt)?),*$(,)?
|
||||||
}
|
}
|
||||||
)*) => {
|
)*) => {
|
||||||
[$(
|
vec![$(
|
||||||
AstNodeSrc {
|
AstNodeSrc {
|
||||||
doc: &[$($doc),*],
|
doc: vec![$($doc.to_string()),*],
|
||||||
name: stringify!($name),
|
name: stringify!($name).to_string(),
|
||||||
traits: &[$($(stringify!($trait)),*)?],
|
traits: vec![$($(stringify!($trait).to_string()),*)?],
|
||||||
fields: &[
|
fields: vec![
|
||||||
$(field!($(T![$token])? $field_name $($ty)?)),*
|
$(field!($(T![$token])? $field_name $($ty)?)),*
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -277,16 +277,22 @@ macro_rules! ast_nodes {
|
||||||
|
|
||||||
macro_rules! field {
|
macro_rules! field {
|
||||||
(T![$token:tt] T) => {
|
(T![$token:tt] T) => {
|
||||||
Field::Token(stringify!($token))
|
Field::Token(stringify!($token).to_string())
|
||||||
};
|
};
|
||||||
($field_name:ident) => {
|
($field_name:ident) => {
|
||||||
Field::Node { name: stringify!($field_name), src: FieldSrc::Shorthand }
|
Field::Node { name: stringify!($field_name).to_string(), src: FieldSrc::Shorthand }
|
||||||
};
|
};
|
||||||
($field_name:ident [$ty:ident]) => {
|
($field_name:ident [$ty:ident]) => {
|
||||||
Field::Node { name: stringify!($field_name), src: FieldSrc::Many(stringify!($ty)) }
|
Field::Node {
|
||||||
|
name: stringify!($field_name).to_string(),
|
||||||
|
src: FieldSrc::Many(stringify!($ty).to_string()),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
($field_name:ident $ty:ident) => {
|
($field_name:ident $ty:ident) => {
|
||||||
Field::Node { name: stringify!($field_name), src: FieldSrc::Optional(stringify!($ty)) }
|
Field::Node {
|
||||||
|
name: stringify!($field_name).to_string(),
|
||||||
|
src: FieldSrc::Optional(stringify!($ty).to_string()),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,20 +303,21 @@ macro_rules! ast_enums {
|
||||||
$($variant:ident),*$(,)?
|
$($variant:ident),*$(,)?
|
||||||
}
|
}
|
||||||
)*) => {
|
)*) => {
|
||||||
[$(
|
vec![$(
|
||||||
AstEnumSrc {
|
AstEnumSrc {
|
||||||
doc: &[$($doc),*],
|
doc: vec![$($doc.to_string()),*],
|
||||||
name: stringify!($name),
|
name: stringify!($name).to_string(),
|
||||||
traits: &[$($(stringify!($trait)),*)?],
|
traits: vec![$($(stringify!($trait).to_string()),*)?],
|
||||||
variants: &[$(stringify!($variant)),*],
|
variants: vec![$(stringify!($variant).to_string()),*],
|
||||||
}
|
}
|
||||||
),*]
|
),*]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const AST_SRC: AstSrc = AstSrc {
|
pub(crate) fn rust_ast() -> AstSrc {
|
||||||
tokens: &["Whitespace", "Comment", "String", "RawString"],
|
AstSrc {
|
||||||
nodes: &ast_nodes! {
|
tokens: vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()],
|
||||||
|
nodes: ast_nodes! {
|
||||||
/// The entire Rust source file. Includes all top-level inner attributes and module items.
|
/// The entire Rust source file. Includes all top-level inner attributes and module items.
|
||||||
///
|
///
|
||||||
/// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html)
|
/// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html)
|
||||||
|
@ -2089,7 +2096,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
|
||||||
Name, TokenTree
|
Name, TokenTree
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enums: &ast_enums! {
|
enums: ast_enums! {
|
||||||
/// Any kind of nominal type definition.
|
/// Any kind of nominal type definition.
|
||||||
enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner {
|
enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner {
|
||||||
StructDef, EnumDef, UnionDef,
|
StructDef, EnumDef, UnionDef,
|
||||||
|
@ -2240,4 +2247,5 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
|
||||||
TupleFieldDefList,
|
TupleFieldDefList,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,28 +9,29 @@ use proc_macro2::{Punct, Spacing};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast_src::{AstSrc, Field, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC},
|
ast_src::{rust_ast, AstSrc, Field, FieldSrc, KindsSrc, KINDS_SRC},
|
||||||
codegen::{self, update, Mode},
|
codegen::{self, update, Mode},
|
||||||
project_root, Result,
|
project_root, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn generate_syntax(mode: Mode) -> Result<()> {
|
pub fn generate_syntax(mode: Mode) -> Result<()> {
|
||||||
|
let ast = rust_ast();
|
||||||
let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS);
|
let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS);
|
||||||
let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
|
let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
|
||||||
update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
|
update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
|
||||||
|
|
||||||
let ast_tokens_file = project_root().join(codegen::AST_TOKENS);
|
let ast_tokens_file = project_root().join(codegen::AST_TOKENS);
|
||||||
let contents = generate_tokens(AST_SRC)?;
|
let contents = generate_tokens(&ast)?;
|
||||||
update(ast_tokens_file.as_path(), &contents, mode)?;
|
update(ast_tokens_file.as_path(), &contents, mode)?;
|
||||||
|
|
||||||
let ast_nodes_file = project_root().join(codegen::AST_NODES);
|
let ast_nodes_file = project_root().join(codegen::AST_NODES);
|
||||||
let contents = generate_nodes(KINDS_SRC, AST_SRC)?;
|
let contents = generate_nodes(KINDS_SRC, &ast)?;
|
||||||
update(ast_nodes_file.as_path(), &contents, mode)?;
|
update(ast_nodes_file.as_path(), &contents, mode)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> {
|
fn generate_tokens(grammar: &AstSrc) -> Result<String> {
|
||||||
let tokens = grammar.tokens.iter().map(|token| {
|
let tokens = grammar.tokens.iter().map(|token| {
|
||||||
let name = format_ident!("{}", token);
|
let name = format_ident!("{}", token);
|
||||||
let kind = format_ident!("{}", to_upper_snake_case(token));
|
let kind = format_ident!("{}", to_upper_snake_case(token));
|
||||||
|
@ -62,13 +63,13 @@ fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> {
|
||||||
Ok(pretty)
|
Ok(pretty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
|
fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> {
|
||||||
let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
|
let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
|
||||||
.nodes
|
.nodes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|node| {
|
.map(|node| {
|
||||||
let name = format_ident!("{}", node.name);
|
let name = format_ident!("{}", node.name);
|
||||||
let kind = format_ident!("{}", to_upper_snake_case(node.name));
|
let kind = format_ident!("{}", to_upper_snake_case(&node.name));
|
||||||
let traits = node.traits.iter().map(|trait_name| {
|
let traits = node.traits.iter().map(|trait_name| {
|
||||||
let trait_name = format_ident!("{}", trait_name);
|
let trait_name = format_ident!("{}", trait_name);
|
||||||
quote!(impl ast::#trait_name for #name {})
|
quote!(impl ast::#trait_name for #name {})
|
||||||
|
@ -192,8 +193,8 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
|
||||||
})
|
})
|
||||||
.unzip();
|
.unzip();
|
||||||
|
|
||||||
let enum_names = grammar.enums.iter().map(|it| it.name);
|
let enum_names = grammar.enums.iter().map(|it| &it.name);
|
||||||
let node_names = grammar.nodes.iter().map(|it| it.name);
|
let node_names = grammar.nodes.iter().map(|it| &it.name);
|
||||||
|
|
||||||
let display_impls =
|
let display_impls =
|
||||||
enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| {
|
enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| {
|
||||||
|
@ -212,7 +213,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
|
||||||
.nodes
|
.nodes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|kind| to_pascal_case(kind))
|
.map(|kind| to_pascal_case(kind))
|
||||||
.filter(|name| !defined_nodes.contains(name.as_str()))
|
.filter(|name| !defined_nodes.iter().any(|&it| it == name))
|
||||||
{
|
{
|
||||||
eprintln!("Warning: node {} not defined in ast source", node);
|
eprintln!("Warning: node {} not defined in ast source", node);
|
||||||
}
|
}
|
||||||
|
@ -236,12 +237,12 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
|
||||||
let mut res = String::with_capacity(ast.len() * 2);
|
let mut res = String::with_capacity(ast.len() * 2);
|
||||||
|
|
||||||
let mut docs =
|
let mut docs =
|
||||||
grammar.nodes.iter().map(|it| it.doc).chain(grammar.enums.iter().map(|it| it.doc));
|
grammar.nodes.iter().map(|it| &it.doc).chain(grammar.enums.iter().map(|it| &it.doc));
|
||||||
|
|
||||||
for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") {
|
for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") {
|
||||||
res.push_str(chunk);
|
res.push_str(chunk);
|
||||||
if let Some(doc) = docs.next() {
|
if let Some(doc) = docs.next() {
|
||||||
write_doc_comment(doc, &mut res);
|
write_doc_comment(&doc, &mut res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +250,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
|
||||||
Ok(pretty)
|
Ok(pretty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_doc_comment(contents: &[&str], dest: &mut String) {
|
fn write_doc_comment(contents: &[String], dest: &mut String) {
|
||||||
for line in contents {
|
for line in contents {
|
||||||
writeln!(dest, "///{}", line).unwrap();
|
writeln!(dest, "///{}", line).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -413,7 +414,7 @@ fn to_pascal_case(s: &str) -> String {
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Field<'_> {
|
impl Field {
|
||||||
fn is_many(&self) -> bool {
|
fn is_many(&self) -> bool {
|
||||||
matches!(self, Field::Node { src: FieldSrc::Many(_), .. })
|
matches!(self, Field::Node { src: FieldSrc::Many(_), .. })
|
||||||
}
|
}
|
||||||
|
@ -429,7 +430,7 @@ impl Field<'_> {
|
||||||
fn method_name(&self) -> proc_macro2::Ident {
|
fn method_name(&self) -> proc_macro2::Ident {
|
||||||
match self {
|
match self {
|
||||||
Field::Token(name) => {
|
Field::Token(name) => {
|
||||||
let name = match *name {
|
let name = match name.as_str() {
|
||||||
";" => "semicolon",
|
";" => "semicolon",
|
||||||
"->" => "thin_arrow",
|
"->" => "thin_arrow",
|
||||||
"'{'" => "l_curly",
|
"'{'" => "l_curly",
|
||||||
|
|
Loading…
Reference in a new issue