Coverage Report

Created: 2026-03-26 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/wast-245.0.1/src/component/wast.rs
Line
Count
Source
1
use crate::kw;
2
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
3
use crate::token::{F32, F64};
4
5
/// Expression that can be used inside of `invoke` expressions for core wasm
6
/// functions.
7
#[derive(Debug)]
8
#[allow(missing_docs)]
9
pub enum WastVal<'a> {
10
    Bool(bool),
11
    U8(u8),
12
    S8(i8),
13
    U16(u16),
14
    S16(i16),
15
    U32(u32),
16
    S32(i32),
17
    U64(u64),
18
    S64(i64),
19
    F32(F32),
20
    F64(F64),
21
    Char(char),
22
    String(&'a str),
23
    List(Vec<WastVal<'a>>),
24
    Record(Vec<(&'a str, WastVal<'a>)>),
25
    Tuple(Vec<WastVal<'a>>),
26
    Variant(&'a str, Option<Box<WastVal<'a>>>),
27
    Enum(&'a str),
28
    Option(Option<Box<WastVal<'a>>>),
29
    Result(Result<Option<Box<WastVal<'a>>>, Option<Box<WastVal<'a>>>>),
30
    Flags(Vec<&'a str>),
31
}
32
33
static CASES: &[(&str, fn(Parser<'_>) -> Result<WastVal<'_>>)] = {
34
    use WastVal::*;
35
    &[
36
0
        ("bool.const", |p| {
37
0
            let mut l = p.lookahead1();
38
0
            if l.peek::<kw::true_>()? {
39
0
                p.parse::<kw::true_>()?;
40
0
                Ok(Bool(true))
41
0
            } else if l.peek::<kw::false_>()? {
42
0
                p.parse::<kw::false_>()?;
43
0
                Ok(Bool(false))
44
            } else {
45
0
                Err(l.error())
46
            }
47
0
        }),
48
0
        ("u8.const", |p| Ok(U8(p.parse()?))),
49
0
        ("s8.const", |p| Ok(S8(p.parse()?))),
50
0
        ("u16.const", |p| Ok(U16(p.parse()?))),
51
0
        ("s16.const", |p| Ok(S16(p.parse()?))),
52
0
        ("u32.const", |p| Ok(U32(p.parse()?))),
53
0
        ("s32.const", |p| Ok(S32(p.parse()?))),
54
0
        ("u64.const", |p| Ok(U64(p.parse()?))),
55
0
        ("s64.const", |p| Ok(S64(p.parse()?))),
56
0
        ("f32.const", |p| Ok(F32(p.parse()?))),
57
0
        ("f64.const", |p| Ok(F64(p.parse()?))),
58
0
        ("char.const", |p| {
59
0
            let s = p.parse::<&str>()?;
60
0
            let mut ch = s.chars();
61
0
            let ret = match ch.next() {
62
0
                Some(c) => c,
63
0
                None => return Err(p.error("empty string")),
64
            };
65
0
            if ch.next().is_some() {
66
0
                return Err(p.error("more than one character"));
67
0
            }
68
0
            Ok(Char(ret))
69
0
        }),
70
0
        ("str.const", |p| Ok(String(p.parse()?))),
71
0
        ("list.const", |p| {
72
0
            let mut ret = Vec::new();
73
0
            while !p.is_empty() {
74
0
                ret.push(p.parens(|p| p.parse())?);
75
            }
76
0
            Ok(List(ret))
77
0
        }),
78
0
        ("record.const", |p| {
79
0
            let mut ret = Vec::new();
80
0
            while !p.is_empty() {
81
0
                ret.push(p.parens(|p| {
82
0
                    p.parse::<kw::field>()?;
83
0
                    Ok((p.parse()?, p.parse()?))
84
0
                })?);
85
            }
86
0
            Ok(Record(ret))
87
0
        }),
88
0
        ("tuple.const", |p| {
89
0
            let mut ret = Vec::new();
90
0
            while !p.is_empty() {
91
0
                ret.push(p.parens(|p| p.parse())?);
92
            }
93
0
            Ok(Tuple(ret))
94
0
        }),
95
0
        ("variant.const", |p| {
96
0
            let name = p.parse()?;
97
0
            let payload = if p.is_empty() {
98
0
                None
99
            } else {
100
0
                Some(Box::new(p.parens(|p| p.parse())?))
101
            };
102
0
            Ok(Variant(name, payload))
103
0
        }),
104
0
        ("enum.const", |p| Ok(Enum(p.parse()?))),
105
0
        ("option.none", |_| Ok(Option(None))),
106
0
        ("option.some", |p| {
107
0
            Ok(Option(Some(Box::new(p.parens(|p| p.parse())?))))
108
0
        }),
109
0
        ("result.ok", |p| {
110
0
            Ok(Result(Ok(if p.is_empty() {
111
0
                None
112
            } else {
113
0
                Some(Box::new(p.parens(|p| p.parse())?))
114
            })))
115
0
        }),
116
0
        ("result.err", |p| {
117
0
            Ok(Result(Err(if p.is_empty() {
118
0
                None
119
            } else {
120
0
                Some(Box::new(p.parens(|p| p.parse())?))
121
            })))
122
0
        }),
123
0
        ("flags.const", |p| {
124
0
            let mut ret = Vec::new();
125
0
            while !p.is_empty() {
126
0
                ret.push(p.parse()?);
127
            }
128
0
            Ok(Flags(ret))
129
0
        }),
130
    ]
131
};
132
133
impl<'a> Parse<'a> for WastVal<'a> {
134
0
    fn parse(parser: Parser<'a>) -> Result<Self> {
135
0
        parser.depth_check()?;
136
0
        let parse = parser.step(|c| {
137
0
            if let Some((kw, rest)) = c.keyword()? {
138
0
                if let Some(i) = CASES.iter().position(|(name, _)| *name == kw) {
139
0
                    return Ok((CASES[i].1, rest));
140
0
                }
141
0
            }
142
0
            Err(c.error("expected a [type].const expression"))
143
0
        })?;
144
0
        parse(parser)
145
0
    }
146
}
147
148
impl Peek for WastVal<'_> {
149
0
    fn peek(cursor: Cursor<'_>) -> Result<bool> {
150
0
        let kw = match cursor.keyword()? {
151
0
            Some((kw, _)) => kw,
152
0
            None => return Ok(false),
153
        };
154
0
        Ok(CASES.iter().any(|(name, _)| *name == kw))
155
0
    }
156
157
0
    fn display() -> &'static str {
158
0
        "core wasm argument"
159
0
    }
160
}