sway_parse/expr/
asm.rs

1use crate::expr::op_code::parse_instruction;
2use crate::{Parse, ParseResult, ParseToEnd, Parser, ParserConsumed};
3
4use core::str::FromStr;
5use num_bigint::BigUint;
6
7use sway_ast::expr::asm::{
8    AsmBlock, AsmBlockContents, AsmFinalExpr, AsmImmediate, AsmRegisterDeclaration,
9};
10use sway_error::parser_error::ParseErrorKind;
11use sway_types::{Ident, Spanned};
12
13impl Parse for AsmBlock {
14    fn parse(parser: &mut Parser) -> ParseResult<AsmBlock> {
15        let asm_token = parser.parse()?;
16        let registers = parser.parse()?;
17        let contents = parser.parse()?;
18        Ok(AsmBlock {
19            asm_token,
20            registers,
21            contents,
22        })
23    }
24}
25
26impl Parse for AsmRegisterDeclaration {
27    fn parse(parser: &mut Parser) -> ParseResult<AsmRegisterDeclaration> {
28        let register = parser.parse()?;
29        let value_opt = match parser.take() {
30            Some(colon_token) => {
31                let value = parser.parse()?;
32                Some((colon_token, value))
33            }
34            None => None,
35        };
36        Ok(AsmRegisterDeclaration {
37            register,
38            value_opt,
39        })
40    }
41}
42
43impl ParseToEnd for AsmBlockContents {
44    fn parse_to_end<'a, 'e>(
45        mut parser: Parser<'a, '_>,
46    ) -> ParseResult<(AsmBlockContents, ParserConsumed<'a>)> {
47        let mut instructions = Vec::new();
48        let (final_expr_opt, consumed) = loop {
49            if let Some(consumed) = parser.check_empty() {
50                break (None, consumed);
51            }
52
53            // Parse the opcode directly instead of calling `parser.parse()` to avoid checking for
54            // illegal identifiers such as keywords. opcode names should not be subject to those
55            // checks because some opcodes, such as `mod`, are also Sway keywords.
56            let ident = match parser.take::<Ident>() {
57                Some(ident) => ident,
58                None => return Err(parser.emit_error(ParseErrorKind::ExpectedIdent)),
59            };
60
61            if let Some(consumed) = parser.check_empty() {
62                let final_expr = AsmFinalExpr {
63                    register: ident,
64                    ty_opt: None,
65                };
66                break (Some(final_expr), consumed);
67            }
68            if let Some(colon_token) = parser.take() {
69                let ty = parser.parse()?;
70                let consumed = match parser.check_empty() {
71                    Some(consumed) => consumed,
72                    None => {
73                        return Err(
74                            parser.emit_error(ParseErrorKind::UnexpectedTokenAfterAsmReturnType)
75                        );
76                    }
77                };
78                let final_expr = AsmFinalExpr {
79                    register: ident,
80                    ty_opt: Some((colon_token, ty)),
81                };
82                break (Some(final_expr), consumed);
83            }
84            let instruction = parse_instruction(ident, &mut parser)?;
85            let semicolon_token = parser.parse()?;
86            instructions.push((instruction, semicolon_token));
87        };
88        let contents = AsmBlockContents {
89            instructions,
90            final_expr_opt,
91        };
92        Ok((contents, consumed))
93    }
94}
95
96impl Parse for AsmImmediate {
97    fn parse(parser: &mut Parser) -> ParseResult<AsmImmediate> {
98        let ident = parser.parse::<Ident>()?;
99        let digits = ident
100            .as_str()
101            .strip_prefix('i')
102            .ok_or_else(|| parser.emit_error(ParseErrorKind::MalformedAsmImmediate))?;
103        let parsed = BigUint::from_str(digits)
104            .ok()
105            .ok_or_else(|| parser.emit_error(ParseErrorKind::MalformedAsmImmediate))?;
106        Ok(AsmImmediate {
107            span: ident.span(),
108            parsed,
109        })
110    }
111}