1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use crate::priv_prelude::*;

#[derive(Clone, Debug)]
pub struct AsmBlock {
    pub asm_token: AsmToken,
    pub registers: Parens<Punctuated<AsmRegisterDeclaration, CommaToken>>,
    pub contents: Braces<AsmBlockContents>,
}

#[derive(Clone, Debug)]
pub struct AsmRegisterDeclaration {
    pub register: Ident,
    pub value_opt: Option<(ColonToken, Box<Expr>)>,
}

#[derive(Clone, Debug)]
pub struct AsmBlockContents {
    pub instructions: Vec<(Instruction, SemicolonToken)>,
    pub final_expr_opt: Option<AsmFinalExpr>,
}

#[derive(Clone, Debug)]
pub struct AsmFinalExpr {
    pub register: Ident,
    pub ty_opt: Option<(ColonToken, Ty)>,
}

#[derive(Clone, Debug)]
pub struct AsmImmediate {
    pub span: Span,
    pub parsed: BigUint,
}

impl Spanned for AsmImmediate {
    fn span(&self) -> Span {
        self.span.clone()
    }
}

impl Spanned for AsmBlock {
    fn span(&self) -> Span {
        Span::join(self.asm_token.span(), self.contents.span())
    }
}

impl Parse for AsmBlock {
    fn parse(parser: &mut Parser) -> ParseResult<AsmBlock> {
        let asm_token = parser.parse()?;
        let registers = parser.parse()?;
        let contents = parser.parse()?;
        Ok(AsmBlock {
            asm_token,
            registers,
            contents,
        })
    }
}

impl Parse for AsmRegisterDeclaration {
    fn parse(parser: &mut Parser) -> ParseResult<AsmRegisterDeclaration> {
        let register = parser.parse()?;
        let value_opt = match parser.take() {
            Some(colon_token) => {
                let value = parser.parse()?;
                Some((colon_token, value))
            }
            None => None,
        };
        Ok(AsmRegisterDeclaration {
            register,
            value_opt,
        })
    }
}

impl ParseToEnd for AsmBlockContents {
    fn parse_to_end<'a, 'e>(
        mut parser: Parser<'a, 'e>,
    ) -> ParseResult<(AsmBlockContents, ParserConsumed<'a>)> {
        let mut instructions = Vec::new();
        let (final_expr_opt, consumed) = loop {
            if let Some(consumed) = parser.check_empty() {
                break (None, consumed);
            }
            let ident = parser.parse()?;
            if let Some(consumed) = parser.check_empty() {
                let final_expr = AsmFinalExpr {
                    register: ident,
                    ty_opt: None,
                };
                break (Some(final_expr), consumed);
            }
            if let Some(colon_token) = parser.take() {
                let ty = parser.parse()?;
                let consumed = match parser.check_empty() {
                    Some(consumed) => consumed,
                    None => {
                        return Err(
                            parser.emit_error(ParseErrorKind::UnexpectedTokenAfterAsmReturnType)
                        );
                    }
                };
                let final_expr = AsmFinalExpr {
                    register: ident,
                    ty_opt: Some((colon_token, ty)),
                };
                break (Some(final_expr), consumed);
            }
            let instruction = parse_instruction(ident, &mut parser)?;
            let semicolon_token = parser.parse()?;
            instructions.push((instruction, semicolon_token));
        };
        let contents = AsmBlockContents {
            instructions,
            final_expr_opt,
        };
        Ok((contents, consumed))
    }
}

impl Parse for AsmImmediate {
    fn parse(parser: &mut Parser) -> ParseResult<AsmImmediate> {
        let ident = parser.parse::<Ident>()?;
        let digits = match ident.as_str().strip_prefix('i') {
            Some(digits) => digits,
            None => return Err(parser.emit_error(ParseErrorKind::MalformedAsmImmediate)),
        };
        let parsed = match BigUint::from_str(digits).ok() {
            Some(parsed) => parsed,
            None => return Err(parser.emit_error(ParseErrorKind::MalformedAsmImmediate)),
        };
        Ok(AsmImmediate {
            span: ident.span(),
            parsed,
        })
    }
}