Skip to content

Commit c362d7d

Browse files
author
Grant Wuerker
committed
unsafe expr parsing
1 parent 57335f1 commit c362d7d

File tree

11 files changed

+219
-6
lines changed

11 files changed

+219
-6
lines changed

crates/hir/src/hir_def/expr.rs

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

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

crates/hir/src/lower/expr.rs

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

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

crates/hir/src/span/expr.rs

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

200200
define_lazy_span_node!(LazyMatchArmSpan);
201201

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

crates/hir/src/visitor.rs

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

1090+
Expr::Unsafe(expr_id) => {
1091+
visit_node_in_body!(visitor, ctxt, expr_id, expr);
1092+
}
1093+
10901094
Expr::Assign(left_expr_id, right_expr_id) => {
10911095
visit_node_in_body!(visitor, ctxt, left_expr_id, expr);
10921096
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
@@ -22,7 +22,7 @@ use super::{
2222
pub(super) fn is_expr_atom_head(kind: SyntaxKind) -> bool {
2323
use SyntaxKind::*;
2424
match kind {
25-
IfKw | MatchKw | LBrace | LParen | LBracket => true,
25+
IfKw | MatchKw | LBrace | LParen | LBracket | UnsafeKw => true,
2626
kind if lit::is_lit(kind) => true,
2727
kind if path::is_path_segment(kind) => true,
2828
_ => false,
@@ -38,6 +38,7 @@ pub(super) fn parse_expr_atom<S: TokenStream>(
3838
match parser.current_kind() {
3939
Some(IfKw) => parser.parse_cp(IfExprScope::default(), None),
4040
Some(MatchKw) => parser.parse_cp(MatchExprScope::default(), None),
41+
Some(UnsafeKw) => parser.parse_cp(UnsafeExprScope::default(), None),
4142
Some(LBrace) => parser.parse_cp(BlockExprScope::default(), None),
4243
Some(LParen) => parser.parse_cp(ParenScope::default(), None),
4344
Some(LBracket) => parser.parse_cp(ArrayScope::default(), None),
@@ -83,8 +84,22 @@ impl super::Parse for BlockExprScope {
8384
.map(SyntaxKind::is_item_head)
8485
.unwrap_or_default()
8586
{
86-
parser.parse(ItemScope::default())?;
87-
continue;
87+
let is_item = parser.dry_run(|parser| {
88+
if parser.bump_if(SyntaxKind::UnsafeKw) {
89+
parser
90+
.current_kind()
91+
.map(SyntaxKind::is_item_head)
92+
.unwrap_or_default()
93+
&& !parser.bump_if(SyntaxKind::UnsafeKw)
94+
} else {
95+
true
96+
}
97+
});
98+
99+
if is_item {
100+
parser.parse(ItemScope::default())?;
101+
continue;
102+
}
88103
}
89104

90105
parse_stmt(parser)?;
@@ -131,6 +146,17 @@ impl super::Parse for IfExprScope {
131146
}
132147
}
133148

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

crates/parser2/src/syntax_kind.rs

Lines changed: 4 additions & 1 deletion
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)`
@@ -571,6 +573,7 @@ impl SyntaxKind {
571573
SyntaxKind::ConstKw => "`const`",
572574
SyntaxKind::IfKw => "`if`",
573575
SyntaxKind::ElseKw => "`else`",
576+
SyntaxKind::UnsafeKw => "`unsafe`",
574577
SyntaxKind::MatchKw => "`match`",
575578
SyntaxKind::ForKw => "`for`",
576579
SyntaxKind::InKw => "`in`",
@@ -589,7 +592,6 @@ impl SyntaxKind {
589592
SyntaxKind::MutKw => "`mut`",
590593
SyntaxKind::UseKw => "`use`",
591594
SyntaxKind::ExternKw => "`extern`",
592-
SyntaxKind::UnsafeKw => "`unsafe`",
593595
SyntaxKind::IngotKw => "`ingot`",
594596
SyntaxKind::SuperKw => "`super`",
595597
SyntaxKind::LShift => "`<<`",
@@ -632,6 +634,7 @@ impl SyntaxKind {
632634
SyntaxKind::ArrayRepExpr => "array expression",
633635
SyntaxKind::LitExpr => "literal expression",
634636
SyntaxKind::IfExpr => "`if` expression",
637+
SyntaxKind::UnsafeExpr => "`unsafe` expression",
635638
SyntaxKind::MatchExpr => "`match` expression",
636639
SyntaxKind::ParenExpr => "parenthesized expression",
637640
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)