mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 05:38:46 +00:00
Parse builtin#asm expressions
This commit is contained in:
parent
50882fbfa2
commit
86658c66b4
21 changed files with 865 additions and 31 deletions
|
@ -15,6 +15,7 @@ extend-ignore-re = [
|
||||||
'"flate2"',
|
'"flate2"',
|
||||||
"raison d'être",
|
"raison d'être",
|
||||||
"inout",
|
"inout",
|
||||||
|
"INOUT",
|
||||||
"optin"
|
"optin"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2624,6 +2624,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"directories",
|
"directories",
|
||||||
|
"either",
|
||||||
"flate2",
|
"flate2",
|
||||||
"itertools",
|
"itertools",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
|
@ -185,6 +185,7 @@ style = { level = "warn", priority = -1 }
|
||||||
suspicious = { level = "warn", priority = -1 }
|
suspicious = { level = "warn", priority = -1 }
|
||||||
|
|
||||||
## allow following lints
|
## allow following lints
|
||||||
|
too_long_first_doc_paragraph = "allow"
|
||||||
# subjective
|
# subjective
|
||||||
single_match = "allow"
|
single_match = "allow"
|
||||||
# () makes a fine error in most cases
|
# () makes a fine error in most cases
|
||||||
|
|
|
@ -694,8 +694,11 @@ impl ExprCollector<'_> {
|
||||||
}
|
}
|
||||||
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
|
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
|
||||||
ast::Expr::AsmExpr(e) => {
|
ast::Expr::AsmExpr(e) => {
|
||||||
let e = self.collect_expr_opt(e.expr());
|
let template = e.template().map(|it| self.collect_expr(it)).collect();
|
||||||
self.alloc_expr(Expr::InlineAsm(InlineAsm { e }), syntax_ptr)
|
self.alloc_expr(
|
||||||
|
Expr::InlineAsm(InlineAsm { template, operands: Box::default() }),
|
||||||
|
syntax_ptr,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ast::Expr::OffsetOfExpr(e) => {
|
ast::Expr::OffsetOfExpr(e) => {
|
||||||
let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
|
let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
|
||||||
|
|
|
@ -307,7 +307,8 @@ pub struct OffsetOf {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct InlineAsm {
|
pub struct InlineAsm {
|
||||||
pub e: ExprId,
|
pub template: Box<[ExprId]>,
|
||||||
|
pub operands: Box<[()]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -372,7 +373,7 @@ impl Expr {
|
||||||
match self {
|
match self {
|
||||||
Expr::Missing => {}
|
Expr::Missing => {}
|
||||||
Expr::Path(_) | Expr::OffsetOf(_) => {}
|
Expr::Path(_) | Expr::OffsetOf(_) => {}
|
||||||
Expr::InlineAsm(it) => f(it.e),
|
Expr::InlineAsm(it) => it.template.iter().copied().for_each(f),
|
||||||
Expr::If { condition, then_branch, else_branch } => {
|
Expr::If { condition, then_branch, else_branch } => {
|
||||||
f(*condition);
|
f(*condition);
|
||||||
f(*then_branch);
|
f(*then_branch);
|
||||||
|
|
|
@ -666,7 +666,9 @@ impl InferenceContext<'_> {
|
||||||
fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
|
fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
|
||||||
match &self.body[tgt_expr] {
|
match &self.body[tgt_expr] {
|
||||||
Expr::OffsetOf(_) => (),
|
Expr::OffsetOf(_) => (),
|
||||||
Expr::InlineAsm(e) => self.walk_expr_without_adjust(e.e),
|
Expr::InlineAsm(e) => {
|
||||||
|
e.template.iter().for_each(|it| self.walk_expr_without_adjust(*it))
|
||||||
|
}
|
||||||
Expr::If { condition, then_branch, else_branch } => {
|
Expr::If { condition, then_branch, else_branch } => {
|
||||||
self.consume_expr(*condition);
|
self.consume_expr(*condition);
|
||||||
self.consume_expr(*then_branch);
|
self.consume_expr(*then_branch);
|
||||||
|
|
|
@ -925,7 +925,7 @@ impl InferenceContext<'_> {
|
||||||
}
|
}
|
||||||
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
|
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
|
||||||
Expr::InlineAsm(it) => {
|
Expr::InlineAsm(it) => {
|
||||||
self.infer_expr_no_expect(it.e);
|
it.template.iter().for_each(|&expr| _ = self.infer_expr_no_expect(expr));
|
||||||
self.result.standard_types.unit.clone()
|
self.result.standard_types.unit.clone()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,7 +39,10 @@ impl InferenceContext<'_> {
|
||||||
fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
|
fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
|
||||||
match &self.body[tgt_expr] {
|
match &self.body[tgt_expr] {
|
||||||
Expr::Missing => (),
|
Expr::Missing => (),
|
||||||
Expr::InlineAsm(e) => self.infer_mut_expr_without_adjust(e.e, Mutability::Not),
|
Expr::InlineAsm(e) => e
|
||||||
|
.template
|
||||||
|
.iter()
|
||||||
|
.for_each(|&expr| self.infer_mut_expr_without_adjust(expr, Mutability::Not)),
|
||||||
Expr::OffsetOf(_) => (),
|
Expr::OffsetOf(_) => (),
|
||||||
&Expr::If { condition, then_branch, else_branch } => {
|
&Expr::If { condition, then_branch, else_branch } => {
|
||||||
self.infer_mut_expr(condition, Mutability::Not);
|
self.infer_mut_expr(condition, Mutability::Not);
|
||||||
|
@ -129,7 +132,7 @@ impl InferenceContext<'_> {
|
||||||
target,
|
target,
|
||||||
}) = base_adjustments
|
}) = base_adjustments
|
||||||
{
|
{
|
||||||
// For assignee exprs `IndexMut` obiligations are already applied
|
// For assignee exprs `IndexMut` obligations are already applied
|
||||||
if !is_assignee_expr {
|
if !is_assignee_expr {
|
||||||
if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
|
if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
|
||||||
base_ty = Some(ty.clone());
|
base_ty = Some(ty.clone());
|
||||||
|
|
|
@ -245,7 +245,7 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
|
||||||
|
|
||||||
// test builtin_expr
|
// test builtin_expr
|
||||||
// fn foo() {
|
// fn foo() {
|
||||||
// builtin#asm(0);
|
// builtin#asm("");
|
||||||
// builtin#format_args("", 0, 1, a = 2 + 3, a + b);
|
// builtin#format_args("", 0, 1, a = 2 + 3, a + b);
|
||||||
// builtin#offset_of(Foo, bar.baz.0);
|
// builtin#offset_of(Foo, bar.baz.0);
|
||||||
// }
|
// }
|
||||||
|
@ -297,18 +297,175 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
|
||||||
p.expect(T![')']);
|
p.expect(T![')']);
|
||||||
Some(m.complete(p, FORMAT_ARGS_EXPR))
|
Some(m.complete(p, FORMAT_ARGS_EXPR))
|
||||||
} else if p.at_contextual_kw(T![asm]) {
|
} else if p.at_contextual_kw(T![asm]) {
|
||||||
p.bump_remap(T![asm]);
|
parse_asm_expr(p, m)
|
||||||
p.expect(T!['(']);
|
|
||||||
// FIXME: We just put expression here so highlighting kind of keeps working
|
|
||||||
expr(p);
|
|
||||||
p.expect(T![')']);
|
|
||||||
Some(m.complete(p, ASM_EXPR))
|
|
||||||
} else {
|
} else {
|
||||||
m.abandon(p);
|
m.abandon(p);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test asm_expr
|
||||||
|
// fn foo() {
|
||||||
|
// builtin#asm(
|
||||||
|
// "mov {tmp}, {x}",
|
||||||
|
// "shl {tmp}, 1",
|
||||||
|
// "shl {x}, 2",
|
||||||
|
// "add {x}, {tmp}",
|
||||||
|
// x = inout(reg) x,
|
||||||
|
// tmp = out(reg) _,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
|
||||||
|
p.bump_remap(T![asm]);
|
||||||
|
p.expect(T!['(']);
|
||||||
|
if expr(p).is_none() {
|
||||||
|
p.err_and_bump("expected asm template");
|
||||||
|
}
|
||||||
|
let mut allow_templates = true;
|
||||||
|
while !p.at(EOF) && !p.at(T![')']) {
|
||||||
|
p.expect(T![,]);
|
||||||
|
// accept trailing commas
|
||||||
|
if p.at(T![')']) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse clobber_abi
|
||||||
|
if p.eat_contextual_kw(T![clobber_abi]) {
|
||||||
|
parse_clobber_abi(p);
|
||||||
|
allow_templates = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse options
|
||||||
|
if p.eat_contextual_kw(T![options]) {
|
||||||
|
parse_options(p);
|
||||||
|
allow_templates = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse operand names
|
||||||
|
if p.at(T![ident]) && p.nth_at(1, T![=]) {
|
||||||
|
name(p);
|
||||||
|
p.bump(T![=]);
|
||||||
|
allow_templates = false;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let op = p.start();
|
||||||
|
if p.eat(T![in]) {
|
||||||
|
parse_reg(p);
|
||||||
|
expr(p);
|
||||||
|
op.complete(p, ASM_REG_OPERAND);
|
||||||
|
} else if p.eat_contextual_kw(T![out]) {
|
||||||
|
parse_reg(p);
|
||||||
|
expr(p);
|
||||||
|
op.complete(p, ASM_REG_OPERAND);
|
||||||
|
} else if p.eat_contextual_kw(T![lateout]) {
|
||||||
|
parse_reg(p);
|
||||||
|
expr(p);
|
||||||
|
op.complete(p, ASM_REG_OPERAND);
|
||||||
|
} else if p.eat_contextual_kw(T![inout]) {
|
||||||
|
parse_reg(p);
|
||||||
|
expr(p);
|
||||||
|
if p.eat(T![=>]) {
|
||||||
|
expr(p);
|
||||||
|
}
|
||||||
|
op.complete(p, ASM_REG_OPERAND);
|
||||||
|
} else if p.eat_contextual_kw(T![inlateout]) {
|
||||||
|
parse_reg(p);
|
||||||
|
expr(p);
|
||||||
|
if p.eat(T![=>]) {
|
||||||
|
expr(p);
|
||||||
|
}
|
||||||
|
op.complete(p, ASM_REG_OPERAND);
|
||||||
|
} else if p.eat_contextual_kw(T![label]) {
|
||||||
|
block_expr(p);
|
||||||
|
op.complete(p, ASM_LABEL);
|
||||||
|
} else if p.eat(T![const]) {
|
||||||
|
expr(p);
|
||||||
|
op.complete(p, ASM_CONST);
|
||||||
|
} else if p.eat_contextual_kw(T![sym]) {
|
||||||
|
expr(p);
|
||||||
|
op.complete(p, ASM_SYM);
|
||||||
|
} else if allow_templates {
|
||||||
|
op.abandon(p);
|
||||||
|
if expr(p).is_none() {
|
||||||
|
p.err_and_bump("expected asm template");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
op.abandon(p);
|
||||||
|
p.err_and_bump("expected asm operand");
|
||||||
|
if p.at(T!['}']) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
allow_templates = false;
|
||||||
|
}
|
||||||
|
p.expect(T![')']);
|
||||||
|
Some(m.complete(p, ASM_EXPR))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_options(p: &mut Parser<'_>) {
|
||||||
|
p.expect(T!['(']);
|
||||||
|
|
||||||
|
while !p.eat(T![')']) && !p.at(EOF) {
|
||||||
|
const OPTIONS: &[SyntaxKind] = &[
|
||||||
|
T![pure],
|
||||||
|
T![nomem],
|
||||||
|
T![readonly],
|
||||||
|
T![preserves_flags],
|
||||||
|
T![noreturn],
|
||||||
|
T![nostack],
|
||||||
|
T![may_unwind],
|
||||||
|
T![att_syntax],
|
||||||
|
T![raw],
|
||||||
|
];
|
||||||
|
|
||||||
|
if !OPTIONS.iter().any(|&syntax| p.eat(syntax)) {
|
||||||
|
p.err_and_bump("expected asm option");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow trailing commas
|
||||||
|
if p.eat(T![')']) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p.expect(T![,]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_clobber_abi(p: &mut Parser<'_>) {
|
||||||
|
p.expect(T!['(']);
|
||||||
|
|
||||||
|
while !p.eat(T![')']) && !p.at(EOF) {
|
||||||
|
if !p.expect(T![string]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow trailing commas
|
||||||
|
if p.eat(T![')']) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p.expect(T![,]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_reg(p: &mut Parser<'_>) {
|
||||||
|
p.expect(T!['(']);
|
||||||
|
if p.at(T![ident]) {
|
||||||
|
name_ref(p)
|
||||||
|
} else if p.at(T![string]) {
|
||||||
|
p.bump_any()
|
||||||
|
} else {
|
||||||
|
p.err_and_bump("expected register name");
|
||||||
|
}
|
||||||
|
p.expect(T![')']);
|
||||||
|
}
|
||||||
|
|
||||||
// test array_expr
|
// test array_expr
|
||||||
// fn foo() {
|
// fn foo() {
|
||||||
// [];
|
// [];
|
||||||
|
|
|
@ -131,6 +131,14 @@ impl<'t> Parser<'t> {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn eat_contextual_kw(&mut self, kind: SyntaxKind) -> bool {
|
||||||
|
if !self.at_contextual_kw(kind) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.bump_remap(kind);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool {
|
fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool {
|
||||||
self.inp.kind(self.pos + n) == k1
|
self.inp.kind(self.pos + n) == k1
|
||||||
&& self.inp.kind(self.pos + n + 1) == k2
|
&& self.inp.kind(self.pos + n + 1) == k2
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -19,6 +19,8 @@ mod ok {
|
||||||
#[test]
|
#[test]
|
||||||
fn as_precedence() { run_and_expect_no_errors("test_data/parser/inline/ok/as_precedence.rs"); }
|
fn as_precedence() { run_and_expect_no_errors("test_data/parser/inline/ok/as_precedence.rs"); }
|
||||||
#[test]
|
#[test]
|
||||||
|
fn asm_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_expr.rs"); }
|
||||||
|
#[test]
|
||||||
fn assoc_const_eq() {
|
fn assoc_const_eq() {
|
||||||
run_and_expect_no_errors("test_data/parser/inline/ok/assoc_const_eq.rs");
|
run_and_expect_no_errors("test_data/parser/inline/ok/assoc_const_eq.rs");
|
||||||
}
|
}
|
||||||
|
|
77
crates/parser/test_data/parser/inline/ok/asm_expr.rast
Normal file
77
crates/parser/test_data/parser/inline/ok/asm_expr.rast
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
SOURCE_FILE
|
||||||
|
FN
|
||||||
|
FN_KW "fn"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "foo"
|
||||||
|
PARAM_LIST
|
||||||
|
L_PAREN "("
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
BLOCK_EXPR
|
||||||
|
STMT_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
EXPR_STMT
|
||||||
|
ASM_EXPR
|
||||||
|
BUILTIN_KW "builtin"
|
||||||
|
POUND "#"
|
||||||
|
ASM_KW "asm"
|
||||||
|
L_PAREN "("
|
||||||
|
WHITESPACE "\n "
|
||||||
|
LITERAL
|
||||||
|
STRING "\"mov {tmp}, {x}\""
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE "\n "
|
||||||
|
LITERAL
|
||||||
|
STRING "\"shl {tmp}, 1\""
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE "\n "
|
||||||
|
LITERAL
|
||||||
|
STRING "\"shl {x}, 2\""
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE "\n "
|
||||||
|
LITERAL
|
||||||
|
STRING "\"add {x}, {tmp}\""
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE "\n "
|
||||||
|
NAME
|
||||||
|
IDENT "x"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ "="
|
||||||
|
WHITESPACE " "
|
||||||
|
ASM_REG_OPERAND
|
||||||
|
INOUT_KW "inout"
|
||||||
|
L_PAREN "("
|
||||||
|
NAME_REF
|
||||||
|
IDENT "reg"
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_EXPR
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "x"
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE "\n "
|
||||||
|
NAME
|
||||||
|
IDENT "tmp"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ "="
|
||||||
|
WHITESPACE " "
|
||||||
|
ASM_REG_OPERAND
|
||||||
|
OUT_KW "out"
|
||||||
|
L_PAREN "("
|
||||||
|
NAME_REF
|
||||||
|
IDENT "reg"
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
UNDERSCORE_EXPR
|
||||||
|
UNDERSCORE "_"
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE "\n "
|
||||||
|
R_PAREN ")"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n"
|
10
crates/parser/test_data/parser/inline/ok/asm_expr.rs
Normal file
10
crates/parser/test_data/parser/inline/ok/asm_expr.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fn foo() {
|
||||||
|
builtin#asm(
|
||||||
|
"mov {tmp}, {x}",
|
||||||
|
"shl {tmp}, 1",
|
||||||
|
"shl {x}, 2",
|
||||||
|
"add {x}, {tmp}",
|
||||||
|
x = inout(reg) x,
|
||||||
|
tmp = out(reg) _,
|
||||||
|
);
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ SOURCE_FILE
|
||||||
ASM_KW "asm"
|
ASM_KW "asm"
|
||||||
L_PAREN "("
|
L_PAREN "("
|
||||||
LITERAL
|
LITERAL
|
||||||
INT_NUMBER "0"
|
STRING "\"\""
|
||||||
R_PAREN ")"
|
R_PAREN ")"
|
||||||
SEMICOLON ";"
|
SEMICOLON ";"
|
||||||
WHITESPACE "\n "
|
WHITESPACE "\n "
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
fn foo() {
|
fn foo() {
|
||||||
builtin#asm(0);
|
builtin#asm("");
|
||||||
builtin#format_args("", 0, 1, a = 2 + 3, a + b);
|
builtin#format_args("", 0, 1, a = 2 + 3, a + b);
|
||||||
builtin#offset_of(Foo, bar.baz.0);
|
builtin#offset_of(Foo, bar.baz.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,8 +391,33 @@ Expr =
|
||||||
OffsetOfExpr =
|
OffsetOfExpr =
|
||||||
Attr* 'builtin' '#' 'offset_of' '(' Type ',' fields:(NameRef ('.' NameRef)* ) ')'
|
Attr* 'builtin' '#' 'offset_of' '(' Type ',' fields:(NameRef ('.' NameRef)* ) ')'
|
||||||
|
|
||||||
|
// asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")"
|
||||||
|
// global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")"
|
||||||
|
// format_string := STRING_LITERAL / RAW_STRING_LITERAL
|
||||||
AsmExpr =
|
AsmExpr =
|
||||||
Attr* 'builtin' '#' 'asm' '(' Expr ')'
|
Attr* 'builtin' '#' 'asm' '(' template:(Expr (',' Expr)*) (AsmOperand (',' AsmOperand)*)? ','? ')'
|
||||||
|
|
||||||
|
// operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
|
||||||
|
AsmOperandExpr = in_expr:Expr ('=>' out_expr:Expr)?
|
||||||
|
// dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout"
|
||||||
|
AsmDirSpec = 'in' | 'out' | 'lateout' | 'inout' | 'inlateout'
|
||||||
|
// reg_spec := <register class> / "\"" <explicit register> "\""
|
||||||
|
AsmRegSpec = '@string' | NameRef
|
||||||
|
// reg_operand := [ident "="] dir_spec "(" reg_spec ")" operand_expr
|
||||||
|
AsmRegOperand = (Name '=')? AsmDirSpec '(' AsmRegSpec ')' AsmOperandExpr
|
||||||
|
// clobber_abi := "clobber_abi(" <abi> *("," <abi>) [","] ")"
|
||||||
|
AsmClobberAbi = 'clobber_abi' '(' ('@string' (',' '@string')* ','?) ')'
|
||||||
|
// option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
|
||||||
|
AsmOption = 'pure' | 'nomem' | 'readonly' | 'preserves_flags' | 'noreturn' | 'nostack' | 'att_syntax' | 'raw' | 'may_unwind'
|
||||||
|
// options := "options(" option *("," option) [","] ")"
|
||||||
|
AsmOptions = 'options' '(' AsmOption *(',' AsmOption) ','? ')'
|
||||||
|
// operand := reg_operand / clobber_abi / options
|
||||||
|
AsmOperand = AsmRegOperand | AsmClobberAbi | AsmOptions | AsmLabel
|
||||||
|
AsmLabel = 'label' BlockExpr
|
||||||
|
AsmSym = 'sym' Expr
|
||||||
|
AsmConst = 'const' Expr
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FormatArgsExpr =
|
FormatArgsExpr =
|
||||||
Attr* 'builtin' '#' 'format_args' '('
|
Attr* 'builtin' '#' 'format_args' '('
|
||||||
|
|
|
@ -64,6 +64,53 @@ impl ArrayType {
|
||||||
pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
|
pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmClobberAbi {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmClobberAbi {
|
||||||
|
#[inline]
|
||||||
|
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
|
||||||
|
#[inline]
|
||||||
|
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
||||||
|
#[inline]
|
||||||
|
pub fn clobber_abi_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![clobber_abi])
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn string_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![string]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmConst {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmConst {
|
||||||
|
#[inline]
|
||||||
|
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmDirSpec {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmDirSpec {
|
||||||
|
#[inline]
|
||||||
|
pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn inlateout_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![inlateout])
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn inout_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![inout]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn lateout_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![lateout]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn out_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![out]) }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct AsmExpr {
|
pub struct AsmExpr {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
@ -71,7 +118,9 @@ pub struct AsmExpr {
|
||||||
impl ast::HasAttrs for AsmExpr {}
|
impl ast::HasAttrs for AsmExpr {}
|
||||||
impl AsmExpr {
|
impl AsmExpr {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
pub fn asm_operands(&self) -> AstChildren<AsmOperand> { support::children(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn template(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
|
pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -79,11 +128,133 @@ impl AsmExpr {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
|
||||||
|
#[inline]
|
||||||
pub fn asm_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![asm]) }
|
pub fn asm_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![asm]) }
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
|
pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmLabel {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmLabel {
|
||||||
|
#[inline]
|
||||||
|
pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn label_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![label]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmOperandExpr {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmOperandExpr {
|
||||||
|
#[inline]
|
||||||
|
pub fn in_expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn out_expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn fat_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=>]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmOption {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmOption {
|
||||||
|
#[inline]
|
||||||
|
pub fn att_syntax_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![att_syntax])
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn may_unwind_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![may_unwind])
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn nomem_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![nomem]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn noreturn_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![noreturn])
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn nostack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![nostack]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn preserves_flags_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![preserves_flags])
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn pure_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pure]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn raw_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![raw]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn readonly_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![readonly])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmOptions {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmOptions {
|
||||||
|
#[inline]
|
||||||
|
pub fn asm_option(&self) -> Option<AsmOption> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn asm_options(&self) -> AstChildren<AsmOption> { support::children(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
|
||||||
|
#[inline]
|
||||||
|
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
||||||
|
#[inline]
|
||||||
|
pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn options_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![options]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmRegOperand {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl ast::HasName for AsmRegOperand {}
|
||||||
|
impl AsmRegOperand {
|
||||||
|
#[inline]
|
||||||
|
pub fn asm_dir_spec(&self) -> Option<AsmDirSpec> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn asm_operand_expr(&self) -> Option<AsmOperandExpr> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn asm_reg_spec(&self) -> Option<AsmRegSpec> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
|
||||||
|
#[inline]
|
||||||
|
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
||||||
|
#[inline]
|
||||||
|
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmRegSpec {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmRegSpec {
|
||||||
|
#[inline]
|
||||||
|
pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn string_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![string]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AsmSym {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl AsmSym {
|
||||||
|
#[inline]
|
||||||
|
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
|
#[inline]
|
||||||
|
pub fn sym_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![sym]) }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct AssocItemList {
|
pub struct AssocItemList {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
@ -2051,6 +2222,14 @@ impl ast::HasGenericParams for Adt {}
|
||||||
impl ast::HasName for Adt {}
|
impl ast::HasName for Adt {}
|
||||||
impl ast::HasVisibility for Adt {}
|
impl ast::HasVisibility for Adt {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum AsmOperand {
|
||||||
|
AsmClobberAbi(AsmClobberAbi),
|
||||||
|
AsmLabel(AsmLabel),
|
||||||
|
AsmOptions(AsmOptions),
|
||||||
|
AsmRegOperand(AsmRegOperand),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum AssocItem {
|
pub enum AssocItem {
|
||||||
Const(Const),
|
Const(Const),
|
||||||
|
@ -2316,6 +2495,48 @@ impl AstNode for ArrayType {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl AstNode for AsmClobberAbi {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CLOBBER_ABI }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmConst {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CONST }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmDirSpec {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_DIR_SPEC }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
impl AstNode for AsmExpr {
|
impl AstNode for AsmExpr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
|
||||||
|
@ -2330,6 +2551,104 @@ impl AstNode for AsmExpr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl AstNode for AsmLabel {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_LABEL }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmOperandExpr {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_EXPR }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmOption {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTION }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmOptions {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTIONS }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmRegOperand {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_OPERAND }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmRegSpec {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_SPEC }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmSym {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_SYM }
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
impl AstNode for AssocItemList {
|
impl AstNode for AssocItemList {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
|
||||||
|
@ -4268,6 +4587,48 @@ impl AstNode for Adt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl From<AsmClobberAbi> for AsmOperand {
|
||||||
|
#[inline]
|
||||||
|
fn from(node: AsmClobberAbi) -> AsmOperand { AsmOperand::AsmClobberAbi(node) }
|
||||||
|
}
|
||||||
|
impl From<AsmLabel> for AsmOperand {
|
||||||
|
#[inline]
|
||||||
|
fn from(node: AsmLabel) -> AsmOperand { AsmOperand::AsmLabel(node) }
|
||||||
|
}
|
||||||
|
impl From<AsmOptions> for AsmOperand {
|
||||||
|
#[inline]
|
||||||
|
fn from(node: AsmOptions) -> AsmOperand { AsmOperand::AsmOptions(node) }
|
||||||
|
}
|
||||||
|
impl From<AsmRegOperand> for AsmOperand {
|
||||||
|
#[inline]
|
||||||
|
fn from(node: AsmRegOperand) -> AsmOperand { AsmOperand::AsmRegOperand(node) }
|
||||||
|
}
|
||||||
|
impl AstNode for AsmOperand {
|
||||||
|
#[inline]
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
|
matches!(kind, ASM_CLOBBER_ABI | ASM_LABEL | ASM_OPTIONS | ASM_REG_OPERAND)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
let res = match syntax.kind() {
|
||||||
|
ASM_CLOBBER_ABI => AsmOperand::AsmClobberAbi(AsmClobberAbi { syntax }),
|
||||||
|
ASM_LABEL => AsmOperand::AsmLabel(AsmLabel { syntax }),
|
||||||
|
ASM_OPTIONS => AsmOperand::AsmOptions(AsmOptions { syntax }),
|
||||||
|
ASM_REG_OPERAND => AsmOperand::AsmRegOperand(AsmRegOperand { syntax }),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn syntax(&self) -> &SyntaxNode {
|
||||||
|
match self {
|
||||||
|
AsmOperand::AsmClobberAbi(it) => &it.syntax,
|
||||||
|
AsmOperand::AsmLabel(it) => &it.syntax,
|
||||||
|
AsmOperand::AsmOptions(it) => &it.syntax,
|
||||||
|
AsmOperand::AsmRegOperand(it) => &it.syntax,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl From<Const> for AssocItem {
|
impl From<Const> for AssocItem {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(node: Const) -> AssocItem { AssocItem::Const(node) }
|
fn from(node: Const) -> AssocItem { AssocItem::Const(node) }
|
||||||
|
@ -5803,7 +6164,8 @@ impl AstNode for AnyHasName {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool {
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
kind,
|
kind,
|
||||||
CONST
|
ASM_REG_OPERAND
|
||||||
|
| CONST
|
||||||
| CONST_PARAM
|
| CONST_PARAM
|
||||||
| ENUM
|
| ENUM
|
||||||
| FN
|
| FN
|
||||||
|
@ -5832,6 +6194,10 @@ impl AstNode for AnyHasName {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl From<AsmRegOperand> for AnyHasName {
|
||||||
|
#[inline]
|
||||||
|
fn from(node: AsmRegOperand) -> AnyHasName { AnyHasName { syntax: node.syntax } }
|
||||||
|
}
|
||||||
impl From<Const> for AnyHasName {
|
impl From<Const> for AnyHasName {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(node: Const) -> AnyHasName { AnyHasName { syntax: node.syntax } }
|
fn from(node: Const) -> AnyHasName { AnyHasName { syntax: node.syntax } }
|
||||||
|
@ -6072,6 +6438,11 @@ impl std::fmt::Display for Adt {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for AsmOperand {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for AssocItem {
|
impl std::fmt::Display for AssocItem {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
@ -6142,11 +6513,61 @@ impl std::fmt::Display for ArrayType {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for AsmClobberAbi {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for AsmConst {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for AsmDirSpec {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for AsmExpr {
|
impl std::fmt::Display for AsmExpr {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for AsmLabel {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for AsmOperandExpr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for AsmOption {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for AsmOptions {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for AsmRegOperand {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for AsmRegSpec {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for AsmSym {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for AssocItemList {
|
impl std::fmt::Display for AssocItemList {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
|
|
@ -19,6 +19,7 @@ stdx.workspace = true
|
||||||
proc-macro2 = "1.0.47"
|
proc-macro2 = "1.0.47"
|
||||||
quote = "1.0.20"
|
quote = "1.0.20"
|
||||||
ungrammar = "1.16.1"
|
ungrammar = "1.16.1"
|
||||||
|
either.workspace = true
|
||||||
itertools.workspace = true
|
itertools.workspace = true
|
||||||
# Avoid adding more dependencies to this crate
|
# Avoid adding more dependencies to this crate
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,11 @@ use std::{
|
||||||
fs,
|
fs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use proc_macro2::{Punct, Spacing};
|
use proc_macro2::{Punct, Spacing};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
|
use stdx::panic_context;
|
||||||
use ungrammar::{Grammar, Rule};
|
use ungrammar::{Grammar, Rule};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -462,6 +464,7 @@ fn generate_syntax_kinds(grammar: KindsSrc) -> String {
|
||||||
|
|
||||||
let tokens = grammar.tokens.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
|
let tokens = grammar.tokens.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// FIXME: This generates enum kinds?
|
||||||
let nodes = grammar.nodes.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
|
let nodes = grammar.nodes.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
|
||||||
|
|
||||||
let ast = quote! {
|
let ast = quote! {
|
||||||
|
@ -711,6 +714,7 @@ fn lower(grammar: &Grammar) -> AstSrc {
|
||||||
for &node in &nodes {
|
for &node in &nodes {
|
||||||
let name = grammar[node].name.clone();
|
let name = grammar[node].name.clone();
|
||||||
let rule = &grammar[node].rule;
|
let rule = &grammar[node].rule;
|
||||||
|
let _g = panic_context::enter(name.clone());
|
||||||
match lower_enum(grammar, rule) {
|
match lower_enum(grammar, rule) {
|
||||||
Some(variants) => {
|
Some(variants) => {
|
||||||
let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants };
|
let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants };
|
||||||
|
@ -838,11 +842,16 @@ fn lower_separated_list(
|
||||||
Rule::Seq(it) => it,
|
Rule::Seq(it) => it,
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
let (node, repeat, trailing_sep) = match rule.as_slice() {
|
|
||||||
|
let (nt, repeat, trailing_sep) = match rule.as_slice() {
|
||||||
[Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
|
[Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
|
||||||
(node, repeat, Some(trailing_sep))
|
(Either::Left(node), repeat, Some(trailing_sep))
|
||||||
}
|
}
|
||||||
[Rule::Node(node), Rule::Rep(repeat)] => (node, repeat, None),
|
[Rule::Node(node), Rule::Rep(repeat)] => (Either::Left(node), repeat, None),
|
||||||
|
[Rule::Token(token), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
|
||||||
|
(Either::Right(token), repeat, Some(trailing_sep))
|
||||||
|
}
|
||||||
|
[Rule::Token(token), Rule::Rep(repeat)] => (Either::Right(token), repeat, None),
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
let repeat = match &**repeat {
|
let repeat = match &**repeat {
|
||||||
|
@ -851,15 +860,28 @@ fn lower_separated_list(
|
||||||
};
|
};
|
||||||
if !matches!(
|
if !matches!(
|
||||||
repeat.as_slice(),
|
repeat.as_slice(),
|
||||||
[comma, Rule::Node(n)]
|
[comma, nt_]
|
||||||
if trailing_sep.map_or(true, |it| comma == &**it) && n == node
|
if trailing_sep.map_or(true, |it| comma == &**it) && match (nt, nt_) {
|
||||||
|
(Either::Left(node), Rule::Node(nt_)) => node == nt_,
|
||||||
|
(Either::Right(token), Rule::Token(nt_)) => token == nt_,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let ty = grammar[*node].name.clone();
|
match nt {
|
||||||
let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
|
Either::Right(token) => {
|
||||||
let field = Field::Node { name, ty, cardinality: Cardinality::Many };
|
let name = clean_token_name(&grammar[*token].name);
|
||||||
acc.push(field);
|
let field = Field::Token(name);
|
||||||
|
acc.push(field);
|
||||||
|
}
|
||||||
|
Either::Left(node) => {
|
||||||
|
let ty = grammar[*node].name.clone();
|
||||||
|
let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
|
||||||
|
let field = Field::Node { name, ty, cardinality: Cardinality::Many };
|
||||||
|
acc.push(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,31 @@ const RESERVED: &[&str] = &[
|
||||||
const CONTEXTUAL_KEYWORDS: &[&str] =
|
const CONTEXTUAL_KEYWORDS: &[&str] =
|
||||||
&["macro_rules", "union", "default", "raw", "dyn", "auto", "yeet"];
|
&["macro_rules", "union", "default", "raw", "dyn", "auto", "yeet"];
|
||||||
// keywords we use for special macro expansions
|
// keywords we use for special macro expansions
|
||||||
const CONTEXTUAL_BUILTIN_KEYWORDS: &[&str] = &["builtin", "offset_of", "format_args", "asm"];
|
const CONTEXTUAL_BUILTIN_KEYWORDS: &[&str] = &[
|
||||||
|
"asm",
|
||||||
|
"att_syntax",
|
||||||
|
"builtin",
|
||||||
|
"clobber_abi",
|
||||||
|
"format_args",
|
||||||
|
// "in",
|
||||||
|
"inlateout",
|
||||||
|
"inout",
|
||||||
|
"label",
|
||||||
|
"lateout",
|
||||||
|
"may_unwind",
|
||||||
|
"nomem",
|
||||||
|
"noreturn",
|
||||||
|
"nostack",
|
||||||
|
"offset_of",
|
||||||
|
"options",
|
||||||
|
"out",
|
||||||
|
"preserves_flags",
|
||||||
|
"pure",
|
||||||
|
// "raw",
|
||||||
|
"readonly",
|
||||||
|
"sym",
|
||||||
|
];
|
||||||
|
|
||||||
// keywords that are keywords depending on the edition
|
// keywords that are keywords depending on the edition
|
||||||
const EDITION_DEPENDENT_KEYWORDS: &[(&str, Edition)] = &[
|
const EDITION_DEPENDENT_KEYWORDS: &[(&str, Edition)] = &[
|
||||||
("try", Edition::Edition2018),
|
("try", Edition::Edition2018),
|
||||||
|
|
Loading…
Reference in a new issue