Skip to content

Commit

Permalink
Parse builtin#asm expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Sep 4, 2024
1 parent 50882fb commit 86658c6
Show file tree
Hide file tree
Showing 21 changed files with 865 additions and 31 deletions.
1 change: 1 addition & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extend-ignore-re = [
'"flate2"',
"raison d'être",
"inout",
"INOUT",
"optin"
]

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ style = { level = "warn", priority = -1 }
suspicious = { level = "warn", priority = -1 }

## allow following lints
too_long_first_doc_paragraph = "allow"
# subjective
single_match = "allow"
# () makes a fine error in most cases
Expand Down
7 changes: 5 additions & 2 deletions crates/hir-def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,8 +694,11 @@ impl ExprCollector<'_> {
}
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
ast::Expr::AsmExpr(e) => {
let e = self.collect_expr_opt(e.expr());
self.alloc_expr(Expr::InlineAsm(InlineAsm { e }), syntax_ptr)
let template = e.template().map(|it| self.collect_expr(it)).collect();
self.alloc_expr(
Expr::InlineAsm(InlineAsm { template, operands: Box::default() }),
syntax_ptr,
)
}
ast::Expr::OffsetOfExpr(e) => {
let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
Expand Down
5 changes: 3 additions & 2 deletions crates/hir-def/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,8 @@ pub struct OffsetOf {

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InlineAsm {
pub e: ExprId,
pub template: Box<[ExprId]>,
pub operands: Box<[()]>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -372,7 +373,7 @@ impl Expr {
match self {
Expr::Missing => {}
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 } => {
f(*condition);
f(*then_branch);
Expand Down
4 changes: 3 additions & 1 deletion crates/hir-ty/src/infer/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,9 @@ impl InferenceContext<'_> {
fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
match &self.body[tgt_expr] {
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 } => {
self.consume_expr(*condition);
self.consume_expr(*then_branch);
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-ty/src/infer/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ impl InferenceContext<'_> {
}
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
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()
}
};
Expand Down
7 changes: 5 additions & 2 deletions crates/hir-ty/src/infer/mutability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ impl InferenceContext<'_> {
fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
match &self.body[tgt_expr] {
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::If { condition, then_branch, else_branch } => {
self.infer_mut_expr(condition, Mutability::Not);
Expand Down Expand Up @@ -129,7 +132,7 @@ impl InferenceContext<'_> {
target,
}) = base_adjustments
{
// For assignee exprs `IndexMut` obiligations are already applied
// For assignee exprs `IndexMut` obligations are already applied
if !is_assignee_expr {
if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
base_ty = Some(ty.clone());
Expand Down
171 changes: 164 additions & 7 deletions crates/parser/src/grammar/expressions/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {

// test builtin_expr
// fn foo() {
// builtin#asm(0);
// builtin#asm("");
// builtin#format_args("", 0, 1, a = 2 + 3, a + b);
// builtin#offset_of(Foo, bar.baz.0);
// }
Expand Down Expand Up @@ -297,18 +297,175 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
p.expect(T![')']);
Some(m.complete(p, FORMAT_ARGS_EXPR))
} else if p.at_contextual_kw(T![asm]) {
p.bump_remap(T![asm]);
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))
parse_asm_expr(p, m)
} else {
m.abandon(p);
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
// fn foo() {
// [];
Expand Down
8 changes: 8 additions & 0 deletions crates/parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ impl<'t> Parser<'t> {
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 {
self.inp.kind(self.pos + n) == k1
&& self.inp.kind(self.pos + n + 1) == k2
Expand Down
Loading

0 comments on commit 86658c6

Please sign in to comment.