Skip to content

Commit 0dfd88e

Browse files
author
Grant Wuerker
committed
unsafe expr parsing
1 parent 7252aaf commit 0dfd88e

File tree

11 files changed

+218
-5
lines changed

11 files changed

+218
-5
lines changed

crates/hir/src/hir_def/expr.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ pub enum Expr {
3939
/// The first `ExprId` is the scrutinee, the second is the arms.
4040
Match(ExprId, Partial<Vec<MatchArm>>),
4141

42+
Unsafe(ExprId),
43+
4244
/// The `Assign` Expression. The first `ExprId` is the destination of the
4345
/// assignment, and the second `ExprId` is the rhs value of the binding.
4446
Assign(ExprId, ExprId),

crates/hir/src/lower/expr.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ impl Expr {
171171
Self::Match(scrutinee, arm)
172172
}
173173

174+
ast::ExprKind::Unsafe(unsafe_expr) => {
175+
let inner = Self::push_to_body_opt(ctxt, unsafe_expr.inner_expr());
176+
Self::Unsafe(inner)
177+
}
178+
174179
ast::ExprKind::Paren(paren) => {
175180
return Self::push_to_body_opt(ctxt, paren.expr());
176181
}

crates/hir/src/span/expr.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ define_lazy_span_node!(
201201

202202
define_lazy_span_node!(LazyMatchArmSpan);
203203

204+
define_lazy_span_node!(
205+
LazyUnsafeExprSpan,
206+
ast::UnsafeExpr,
207+
@token {
208+
(unsafe_kw, unsafe_kw),
209+
}
210+
);
211+
204212
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
205213
pub(crate) struct ExprRoot {
206214
expr: ExprId,

crates/hir/src/visitor.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,10 @@ where
10861086
}
10871087
}
10881088

1089+
Expr::Unsafe(expr_id) => {
1090+
visit_node_in_body!(visitor, ctxt, expr_id, expr);
1091+
}
1092+
10891093
Expr::Assign(left_expr_id, right_expr_id) => {
10901094
visit_node_in_body!(visitor, ctxt, left_expr_id, expr);
10911095
visit_node_in_body!(visitor, ctxt, right_expr_id, expr);

crates/parser2/src/ast/expr.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ ast_node! {
2222
| SK::LitExpr
2323
| SK::IfExpr
2424
| SK::MatchExpr
25+
| SK::UnsafeExpr
2526
| SK::ParenExpr
2627
| SK::AssignExpr
2728
| SK::AugAssignExpr,
@@ -50,6 +51,7 @@ impl Expr {
5051
SK::LitExpr => ExprKind::Lit(AstNode::cast(self.syntax().clone()).unwrap()),
5152
SK::IfExpr => ExprKind::If(AstNode::cast(self.syntax().clone()).unwrap()),
5253
SK::MatchExpr => ExprKind::Match(AstNode::cast(self.syntax().clone()).unwrap()),
54+
SK::UnsafeExpr => ExprKind::Unsafe(AstNode::cast(self.syntax().clone()).unwrap()),
5355
SK::ParenExpr => ExprKind::Paren(AstNode::cast(self.syntax().clone()).unwrap()),
5456
SK::AssignExpr => ExprKind::Assign(AstNode::cast(self.syntax().clone()).unwrap()),
5557
SK::AugAssignExpr => ExprKind::AugAssign(AstNode::cast(self.syntax().clone()).unwrap()),
@@ -326,6 +328,21 @@ impl MatchExpr {
326328
}
327329
}
328330

331+
ast_node! {
332+
/// `unsafe expr`
333+
pub struct UnsafeExpr,
334+
SK::UnsafeExpr
335+
}
336+
impl UnsafeExpr {
337+
pub fn unsafe_kw(&self) -> Option<SyntaxToken> {
338+
support::token(self.syntax(), SK::UnsafeKw)
339+
}
340+
341+
pub fn inner_expr(&self) -> Option<Expr> {
342+
support::child(self.syntax())
343+
}
344+
}
345+
329346
ast_node! {
330347
/// `(expr)`
331348
pub struct ParenExpr,
@@ -398,6 +415,7 @@ pub enum ExprKind {
398415
ArrayRep(ArrayRepExpr),
399416
If(IfExpr),
400417
Match(MatchExpr),
418+
Unsafe(UnsafeExpr),
401419
Paren(ParenExpr),
402420
Assign(AssignExpr),
403421
AugAssign(AugAssignExpr),

crates/parser2/src/parser/expr_atom.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
pub(super) fn is_expr_atom_head(kind: SyntaxKind) -> bool {
2222
use SyntaxKind::*;
2323
match kind {
24-
IfKw | MatchKw | LBrace | LParen | LBracket => true,
24+
IfKw | MatchKw | LBrace | LParen | LBracket | UnsafeKw => true,
2525
kind if lit::is_lit(kind) => true,
2626
kind if path::is_path_segment(kind) => true,
2727
_ => false,
@@ -37,6 +37,7 @@ pub(super) fn parse_expr_atom<S: TokenStream>(
3737
match parser.current_kind() {
3838
Some(IfKw) => parser.parse_cp(IfExprScope::default(), None),
3939
Some(MatchKw) => parser.parse_cp(MatchExprScope::default(), None),
40+
Some(UnsafeKw) => parser.parse_cp(UnsafeExprScope::default(), None),
4041
Some(LBrace) => parser.parse_cp(BlockExprScope::default(), None),
4142
Some(LParen) => parser.parse_cp(ParenScope::default(), None),
4243
Some(LBracket) => parser.parse_cp(ArrayScope::default(), None),
@@ -82,8 +83,22 @@ impl super::Parse for BlockExprScope {
8283
.map(SyntaxKind::is_item_head)
8384
.unwrap_or_default()
8485
{
85-
parser.parse(ItemScope::default())?;
86-
continue;
86+
let is_item = if parser.current_kind() == Some(SyntaxKind::UnsafeKw) {
87+
parser.dry_run(|parser| {
88+
parser.bump();
89+
parser
90+
.current_kind()
91+
.map(SyntaxKind::is_item_head)
92+
.unwrap_or_default()
93+
})
94+
} else {
95+
true
96+
};
97+
98+
if is_item {
99+
parser.parse(ItemScope::default())?;
100+
continue;
101+
}
87102
}
88103

89104
parse_stmt(parser)?;
@@ -130,6 +145,17 @@ impl super::Parse for IfExprScope {
130145
}
131146
}
132147

148+
define_scope! { UnsafeExprScope, UnsafeExpr }
149+
impl super::Parse for UnsafeExprScope {
150+
type Error = Recovery<ErrProof>;
151+
152+
fn parse<S: TokenStream>(&mut self, parser: &mut Parser<S>) -> Result<(), Self::Error> {
153+
parser.bump_expected(SyntaxKind::UnsafeKw);
154+
155+
parse_expr(parser)
156+
}
157+
}
158+
133159
define_scope! { MatchExprScope, MatchExpr }
134160
impl super::Parse for MatchExprScope {
135161
type Error = Recovery<ErrProof>;

crates/parser2/src/syntax_kind.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ pub enum SyntaxKind {
282282
LitExpr,
283283
/// `if x { 1 } else { 2 }`
284284
IfExpr,
285+
/// `unsafe foo(x)`
286+
UnsafeExpr,
285287
/// `match x { pat => { .. } }`
286288
MatchExpr,
287289
/// `(1 + 2)`
@@ -634,6 +636,7 @@ impl SyntaxKind {
634636
SyntaxKind::ArrayRepExpr => "array expression",
635637
SyntaxKind::LitExpr => "literal expression",
636638
SyntaxKind::IfExpr => "`if` expression",
639+
SyntaxKind::UnsafeExpr => "`unsafe` expression",
637640
SyntaxKind::MatchExpr => "`match` expression",
638641
SyntaxKind::ParenExpr => "parenthesized expression",
639642
SyntaxKind::AssignExpr => "assignment expression",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
unsafe { foo() }
2+
3+
unsafe {
4+
let a = 42
5+
std::evm::mstore(offset: 0, value: a)
6+
return
7+
}
8+
9+
unsafe 1 + 1
10+
11+
unsafe bar()
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
source: crates/parser2/tests/syntax_node.rs
3+
expression: node
4+
input_file: crates/parser2/test_files/syntax_node/exprs/unsafe.fe
5+
---
6+
Root@0..125
7+
UnsafeExpr@0..16
8+
UnsafeKw@0..6 "unsafe"
9+
WhiteSpace@6..7 " "
10+
BlockExpr@7..16
11+
LBrace@7..8 "{"
12+
WhiteSpace@8..9 " "
13+
ExprStmt@9..14
14+
CallExpr@9..14
15+
PathExpr@9..12
16+
Path@9..12
17+
PathSegment@9..12
18+
Ident@9..12 "foo"
19+
CallArgList@12..14
20+
LParen@12..13 "("
21+
RParen@13..14 ")"
22+
WhiteSpace@14..15 " "
23+
RBrace@15..16 "}"
24+
Newline@16..18 "\n\n"
25+
UnsafeExpr@18..96
26+
UnsafeKw@18..24 "unsafe"
27+
WhiteSpace@24..25 " "
28+
BlockExpr@25..96
29+
LBrace@25..26 "{"
30+
Newline@26..27 "\n"
31+
WhiteSpace@27..31 " "
32+
LetStmt@31..41
33+
LetKw@31..34 "let"
34+
WhiteSpace@34..35 " "
35+
PathPat@35..36
36+
Path@35..36
37+
PathSegment@35..36
38+
Ident@35..36 "a"
39+
WhiteSpace@36..37 " "
40+
Eq@37..38 "="
41+
WhiteSpace@38..39 " "
42+
LitExpr@39..41
43+
Lit@39..41
44+
Int@39..41 "42"
45+
Newline@41..42 "\n"
46+
WhiteSpace@42..46 " "
47+
ExprStmt@46..83
48+
CallExpr@46..83
49+
PathExpr@46..62
50+
Path@46..62
51+
PathSegment@46..49
52+
Ident@46..49 "std"
53+
Colon2@49..51 "::"
54+
PathSegment@51..54
55+
Ident@51..54 "evm"
56+
Colon2@54..56 "::"
57+
PathSegment@56..62
58+
Ident@56..62 "mstore"
59+
CallArgList@62..83
60+
LParen@62..63 "("
61+
CallArg@63..72
62+
Ident@63..69 "offset"
63+
Colon@69..70 ":"
64+
WhiteSpace@70..71 " "
65+
LitExpr@71..72
66+
Lit@71..72
67+
Int@71..72 "0"
68+
Comma@72..73 ","
69+
WhiteSpace@73..74 " "
70+
CallArg@74..82
71+
Ident@74..79 "value"
72+
Colon@79..80 ":"
73+
WhiteSpace@80..81 " "
74+
PathExpr@81..82
75+
Path@81..82
76+
PathSegment@81..82
77+
Ident@81..82 "a"
78+
RParen@82..83 ")"
79+
Newline@83..84 "\n"
80+
WhiteSpace@84..88 " "
81+
ReturnStmt@88..94
82+
ReturnKw@88..94 "return"
83+
Newline@94..95 "\n"
84+
RBrace@95..96 "}"
85+
Newline@96..98 "\n\n"
86+
UnsafeExpr@98..110
87+
UnsafeKw@98..104 "unsafe"
88+
WhiteSpace@104..105 " "
89+
BinExpr@105..110
90+
LitExpr@105..106
91+
Lit@105..106
92+
Int@105..106 "1"
93+
WhiteSpace@106..107 " "
94+
Plus@107..108 "+"
95+
WhiteSpace@108..109 " "
96+
LitExpr@109..110
97+
Lit@109..110
98+
Int@109..110 "1"
99+
Newline@110..112 "\n\n"
100+
UnsafeExpr@112..124
101+
UnsafeKw@112..118 "unsafe"
102+
WhiteSpace@118..119 " "
103+
CallExpr@119..124
104+
PathExpr@119..122
105+
Path@119..122
106+
PathSegment@119..122
107+
Ident@119..122 "bar"
108+
CallArgList@122..124
109+
LParen@122..123 "("
110+
RParen@123..124 ")"
111+
Newline@124..125 "\n"
112+

crates/parser2/test_files/syntax_node/stmts/let.fe

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ let x = if b {
2020
let x = match b {
2121
MyEnum::A(x) | MyEnum::B(x) => x
2222
_ => 0
23-
}
23+
}
24+
25+
let x = unsafe bar()

crates/parser2/test_files/syntax_node/stmts/let.snap

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ source: crates/parser2/tests/syntax_node.rs
33
expression: node
44
input_file: crates/parser2/test_files/syntax_node/stmts/let.fe
55
---
6-
Root@0..231
6+
Root@0..253
77
LetStmt@0..5
88
LetKw@0..3 "let"
99
WhiteSpace@3..4 " "
@@ -298,4 +298,26 @@ Root@0..231
298298
Int@228..229 "0"
299299
Newline@229..230 "\n"
300300
RBrace@230..231 "}"
301+
Newline@231..233 "\n\n"
302+
LetStmt@233..253
303+
LetKw@233..236 "let"
304+
WhiteSpace@236..237 " "
305+
PathPat@237..238
306+
Path@237..238
307+
PathSegment@237..238
308+
Ident@237..238 "x"
309+
WhiteSpace@238..239 " "
310+
Eq@239..240 "="
311+
WhiteSpace@240..241 " "
312+
UnsafeExpr@241..253
313+
UnsafeKw@241..247 "unsafe"
314+
WhiteSpace@247..248 " "
315+
CallExpr@248..253
316+
PathExpr@248..251
317+
Path@248..251
318+
PathSegment@248..251
319+
Ident@248..251 "bar"
320+
CallArgList@251..253
321+
LParen@251..252 "("
322+
RParen@252..253 ")"
301323

0 commit comments

Comments
 (0)