1*fae6e9adSlinfeng // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2*fae6e9adSlinfeng // Copyright 2017 Rich Lane <lanerl@gmail.com>
3*fae6e9adSlinfeng
4*fae6e9adSlinfeng // Rust-doc comments were left in the module, but it is no longer publicly exposed from the root
5*fae6e9adSlinfeng // file of the crate. Do not expect to find those comments in the documentation of the crate.
6*fae6e9adSlinfeng
7*fae6e9adSlinfeng //! This module parses eBPF assembly language source code.
8*fae6e9adSlinfeng
9*fae6e9adSlinfeng use alloc::{
10*fae6e9adSlinfeng string::{String, ToString},
11*fae6e9adSlinfeng vec::Vec,
12*fae6e9adSlinfeng };
13*fae6e9adSlinfeng
14*fae6e9adSlinfeng #[cfg(feature = "std")]
15*fae6e9adSlinfeng use combine::EasyParser;
16*fae6e9adSlinfeng use combine::{
17*fae6e9adSlinfeng attempt, between, eof, many, many1, one_of, optional,
18*fae6e9adSlinfeng parser::char::{alpha_num, char, digit, hex_digit, spaces, string},
19*fae6e9adSlinfeng sep_by,
20*fae6e9adSlinfeng stream::position::{self},
21*fae6e9adSlinfeng ParseError, Parser, Stream,
22*fae6e9adSlinfeng };
23*fae6e9adSlinfeng
24*fae6e9adSlinfeng /// Operand of an instruction.
25*fae6e9adSlinfeng #[derive(Clone, Copy, Debug, PartialEq, Eq)]
26*fae6e9adSlinfeng pub enum Operand {
27*fae6e9adSlinfeng /// Register number.
28*fae6e9adSlinfeng Register(i64),
29*fae6e9adSlinfeng /// Jump offset or immediate.
30*fae6e9adSlinfeng Integer(i64),
31*fae6e9adSlinfeng /// Register number and offset.
32*fae6e9adSlinfeng Memory(i64, i64),
33*fae6e9adSlinfeng /// Used for pattern matching.
34*fae6e9adSlinfeng Nil,
35*fae6e9adSlinfeng }
36*fae6e9adSlinfeng
37*fae6e9adSlinfeng /// Parsed instruction.
38*fae6e9adSlinfeng #[derive(Debug, PartialEq, Eq)]
39*fae6e9adSlinfeng pub struct Instruction {
40*fae6e9adSlinfeng /// Instruction name.
41*fae6e9adSlinfeng pub name: String,
42*fae6e9adSlinfeng /// Operands.
43*fae6e9adSlinfeng pub operands: Vec<Operand>,
44*fae6e9adSlinfeng }
45*fae6e9adSlinfeng
ident<I>() -> impl Parser<I, Output = String> where I: Stream<Token = char>, I::Error: ParseError<I::Token, I::Range, I::Position>,46*fae6e9adSlinfeng fn ident<I>() -> impl Parser<I, Output = String>
47*fae6e9adSlinfeng where
48*fae6e9adSlinfeng I: Stream<Token = char>,
49*fae6e9adSlinfeng I::Error: ParseError<I::Token, I::Range, I::Position>,
50*fae6e9adSlinfeng {
51*fae6e9adSlinfeng many1(alpha_num())
52*fae6e9adSlinfeng }
53*fae6e9adSlinfeng
integer<I>() -> impl Parser<I, Output = i64> where I: Stream<Token = char>, I::Error: ParseError<I::Token, I::Range, I::Position>,54*fae6e9adSlinfeng fn integer<I>() -> impl Parser<I, Output = i64>
55*fae6e9adSlinfeng where
56*fae6e9adSlinfeng I: Stream<Token = char>,
57*fae6e9adSlinfeng I::Error: ParseError<I::Token, I::Range, I::Position>,
58*fae6e9adSlinfeng {
59*fae6e9adSlinfeng let sign = optional(one_of("-+".chars())).map(|x| match x {
60*fae6e9adSlinfeng Some('-') => -1,
61*fae6e9adSlinfeng _ => 1,
62*fae6e9adSlinfeng });
63*fae6e9adSlinfeng let hex = string("0x")
64*fae6e9adSlinfeng .with(many1(hex_digit()))
65*fae6e9adSlinfeng .map(|x: String| u64::from_str_radix(&x, 16).unwrap() as i64);
66*fae6e9adSlinfeng let dec = many1(digit()).map(|x: String| x.parse::<i64>().unwrap());
67*fae6e9adSlinfeng (sign, attempt(hex).or(dec)).map(|(s, x)| s * x)
68*fae6e9adSlinfeng }
69*fae6e9adSlinfeng
register<I>() -> impl Parser<I, Output = i64> where I: Stream<Token = char>, I::Error: ParseError<I::Token, I::Range, I::Position>,70*fae6e9adSlinfeng fn register<I>() -> impl Parser<I, Output = i64>
71*fae6e9adSlinfeng where
72*fae6e9adSlinfeng I: Stream<Token = char>,
73*fae6e9adSlinfeng I::Error: ParseError<I::Token, I::Range, I::Position>,
74*fae6e9adSlinfeng {
75*fae6e9adSlinfeng char('r')
76*fae6e9adSlinfeng .with(many1(digit()))
77*fae6e9adSlinfeng .map(|x: String| x.parse::<i64>().unwrap())
78*fae6e9adSlinfeng }
79*fae6e9adSlinfeng
operand<I>() -> impl Parser<I, Output = Operand> where I: Stream<Token = char>, I::Error: ParseError<I::Token, I::Range, I::Position>,80*fae6e9adSlinfeng fn operand<I>() -> impl Parser<I, Output = Operand>
81*fae6e9adSlinfeng where
82*fae6e9adSlinfeng I: Stream<Token = char>,
83*fae6e9adSlinfeng I::Error: ParseError<I::Token, I::Range, I::Position>,
84*fae6e9adSlinfeng {
85*fae6e9adSlinfeng let register_operand = register().map(Operand::Register);
86*fae6e9adSlinfeng let immediate = integer().map(Operand::Integer);
87*fae6e9adSlinfeng let memory = between(char('['), char(']'), (register(), optional(integer())))
88*fae6e9adSlinfeng .map(|t| Operand::Memory(t.0, t.1.unwrap_or(0)));
89*fae6e9adSlinfeng register_operand.or(immediate).or(memory)
90*fae6e9adSlinfeng }
91*fae6e9adSlinfeng
instruction<I>() -> impl Parser<I, Output = Instruction> where I: Stream<Token = char>, I::Error: ParseError<I::Token, I::Range, I::Position>,92*fae6e9adSlinfeng fn instruction<I>() -> impl Parser<I, Output = Instruction>
93*fae6e9adSlinfeng where
94*fae6e9adSlinfeng I: Stream<Token = char>,
95*fae6e9adSlinfeng I::Error: ParseError<I::Token, I::Range, I::Position>,
96*fae6e9adSlinfeng {
97*fae6e9adSlinfeng let operands = sep_by(operand(), char(',').skip(spaces()));
98*fae6e9adSlinfeng (ident().skip(spaces()), operands, spaces()).map(|t| Instruction {
99*fae6e9adSlinfeng name: t.0,
100*fae6e9adSlinfeng operands: t.1,
101*fae6e9adSlinfeng })
102*fae6e9adSlinfeng }
103*fae6e9adSlinfeng
104*fae6e9adSlinfeng /// Parse a string into a list of instructions.
105*fae6e9adSlinfeng ///
106*fae6e9adSlinfeng /// The instructions are not validated and may have invalid names and operand types.
parse(input: &str) -> Result<Vec<Instruction>, String>107*fae6e9adSlinfeng pub fn parse(input: &str) -> Result<Vec<Instruction>, String> {
108*fae6e9adSlinfeng let mut with = spaces().with(many(instruction()).skip(eof()));
109*fae6e9adSlinfeng
110*fae6e9adSlinfeng #[cfg(feature = "std")]
111*fae6e9adSlinfeng {
112*fae6e9adSlinfeng match with.easy_parse(position::Stream::new(input)) {
113*fae6e9adSlinfeng Ok((insts, _)) => Ok(insts),
114*fae6e9adSlinfeng Err(err) => Err(err.to_string()),
115*fae6e9adSlinfeng }
116*fae6e9adSlinfeng }
117*fae6e9adSlinfeng #[cfg(not(feature = "std"))]
118*fae6e9adSlinfeng {
119*fae6e9adSlinfeng match with.parse(position::Stream::new(input)) {
120*fae6e9adSlinfeng Ok((insts, _)) => Ok(insts),
121*fae6e9adSlinfeng Err(err) => Err(err.to_string()),
122*fae6e9adSlinfeng }
123*fae6e9adSlinfeng }
124*fae6e9adSlinfeng }
125*fae6e9adSlinfeng
126*fae6e9adSlinfeng #[cfg(test)]
127*fae6e9adSlinfeng mod tests {
128*fae6e9adSlinfeng use alloc::{string::ToString, vec};
129*fae6e9adSlinfeng
130*fae6e9adSlinfeng use combine::Parser;
131*fae6e9adSlinfeng
132*fae6e9adSlinfeng use super::{ident, instruction, integer, operand, parse, register, Instruction, Operand};
133*fae6e9adSlinfeng
134*fae6e9adSlinfeng // Unit tests for the different kinds of parsers.
135*fae6e9adSlinfeng
136*fae6e9adSlinfeng #[test]
test_ident()137*fae6e9adSlinfeng fn test_ident() {
138*fae6e9adSlinfeng assert_eq!(ident().parse("nop"), Ok(("nop".to_string(), "")));
139*fae6e9adSlinfeng assert_eq!(ident().parse("add32"), Ok(("add32".to_string(), "")));
140*fae6e9adSlinfeng assert_eq!(ident().parse("add32*"), Ok(("add32".to_string(), "*")));
141*fae6e9adSlinfeng }
142*fae6e9adSlinfeng
143*fae6e9adSlinfeng #[test]
test_integer()144*fae6e9adSlinfeng fn test_integer() {
145*fae6e9adSlinfeng assert_eq!(integer().parse("0"), Ok((0, "")));
146*fae6e9adSlinfeng assert_eq!(integer().parse("42"), Ok((42, "")));
147*fae6e9adSlinfeng assert_eq!(integer().parse("+42"), Ok((42, "")));
148*fae6e9adSlinfeng assert_eq!(integer().parse("-42"), Ok((-42, "")));
149*fae6e9adSlinfeng assert_eq!(integer().parse("0x0"), Ok((0, "")));
150*fae6e9adSlinfeng assert_eq!(
151*fae6e9adSlinfeng integer().parse("0x123456789abcdef0"),
152*fae6e9adSlinfeng Ok((0x123456789abcdef0, ""))
153*fae6e9adSlinfeng );
154*fae6e9adSlinfeng assert_eq!(integer().parse("-0x1f"), Ok((-31, "")));
155*fae6e9adSlinfeng }
156*fae6e9adSlinfeng
157*fae6e9adSlinfeng #[test]
test_register()158*fae6e9adSlinfeng fn test_register() {
159*fae6e9adSlinfeng assert_eq!(register().parse("r0"), Ok((0, "")));
160*fae6e9adSlinfeng assert_eq!(register().parse("r15"), Ok((15, "")));
161*fae6e9adSlinfeng }
162*fae6e9adSlinfeng
163*fae6e9adSlinfeng #[test]
test_operand()164*fae6e9adSlinfeng fn test_operand() {
165*fae6e9adSlinfeng assert_eq!(operand().parse("r0"), Ok((Operand::Register(0), "")));
166*fae6e9adSlinfeng assert_eq!(operand().parse("r15"), Ok((Operand::Register(15), "")));
167*fae6e9adSlinfeng assert_eq!(operand().parse("0"), Ok((Operand::Integer(0), "")));
168*fae6e9adSlinfeng assert_eq!(operand().parse("42"), Ok((Operand::Integer(42), "")));
169*fae6e9adSlinfeng assert_eq!(operand().parse("[r1]"), Ok((Operand::Memory(1, 0), "")));
170*fae6e9adSlinfeng assert_eq!(operand().parse("[r3+5]"), Ok((Operand::Memory(3, 5), "")));
171*fae6e9adSlinfeng assert_eq!(
172*fae6e9adSlinfeng operand().parse("[r3+0x1f]"),
173*fae6e9adSlinfeng Ok((Operand::Memory(3, 31), ""))
174*fae6e9adSlinfeng );
175*fae6e9adSlinfeng assert_eq!(
176*fae6e9adSlinfeng operand().parse("[r3-0x1f]"),
177*fae6e9adSlinfeng Ok((Operand::Memory(3, -31), ""))
178*fae6e9adSlinfeng );
179*fae6e9adSlinfeng }
180*fae6e9adSlinfeng
181*fae6e9adSlinfeng #[test]
test_instruction()182*fae6e9adSlinfeng fn test_instruction() {
183*fae6e9adSlinfeng assert_eq!(
184*fae6e9adSlinfeng instruction().parse("exit"),
185*fae6e9adSlinfeng Ok((
186*fae6e9adSlinfeng Instruction {
187*fae6e9adSlinfeng name: "exit".to_string(),
188*fae6e9adSlinfeng operands: vec![],
189*fae6e9adSlinfeng },
190*fae6e9adSlinfeng ""
191*fae6e9adSlinfeng ))
192*fae6e9adSlinfeng );
193*fae6e9adSlinfeng
194*fae6e9adSlinfeng assert_eq!(
195*fae6e9adSlinfeng instruction().parse("call 2"),
196*fae6e9adSlinfeng Ok((
197*fae6e9adSlinfeng Instruction {
198*fae6e9adSlinfeng name: "call".to_string(),
199*fae6e9adSlinfeng operands: vec![Operand::Integer(2)],
200*fae6e9adSlinfeng },
201*fae6e9adSlinfeng ""
202*fae6e9adSlinfeng ))
203*fae6e9adSlinfeng );
204*fae6e9adSlinfeng
205*fae6e9adSlinfeng assert_eq!(
206*fae6e9adSlinfeng instruction().parse("addi r1, 2"),
207*fae6e9adSlinfeng Ok((
208*fae6e9adSlinfeng Instruction {
209*fae6e9adSlinfeng name: "addi".to_string(),
210*fae6e9adSlinfeng operands: vec![Operand::Register(1), Operand::Integer(2)],
211*fae6e9adSlinfeng },
212*fae6e9adSlinfeng ""
213*fae6e9adSlinfeng ))
214*fae6e9adSlinfeng );
215*fae6e9adSlinfeng
216*fae6e9adSlinfeng assert_eq!(
217*fae6e9adSlinfeng instruction().parse("ldxb r2, [r1+12]"),
218*fae6e9adSlinfeng Ok((
219*fae6e9adSlinfeng Instruction {
220*fae6e9adSlinfeng name: "ldxb".to_string(),
221*fae6e9adSlinfeng operands: vec![Operand::Register(2), Operand::Memory(1, 12)],
222*fae6e9adSlinfeng },
223*fae6e9adSlinfeng ""
224*fae6e9adSlinfeng ))
225*fae6e9adSlinfeng );
226*fae6e9adSlinfeng
227*fae6e9adSlinfeng assert_eq!(
228*fae6e9adSlinfeng instruction().parse("lsh r3, 0x8"),
229*fae6e9adSlinfeng Ok((
230*fae6e9adSlinfeng Instruction {
231*fae6e9adSlinfeng name: "lsh".to_string(),
232*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Integer(8)],
233*fae6e9adSlinfeng },
234*fae6e9adSlinfeng ""
235*fae6e9adSlinfeng ))
236*fae6e9adSlinfeng );
237*fae6e9adSlinfeng
238*fae6e9adSlinfeng assert_eq!(
239*fae6e9adSlinfeng instruction().parse("jne r3, 0x8, +37"),
240*fae6e9adSlinfeng Ok((
241*fae6e9adSlinfeng Instruction {
242*fae6e9adSlinfeng name: "jne".to_string(),
243*fae6e9adSlinfeng operands: vec![
244*fae6e9adSlinfeng Operand::Register(3),
245*fae6e9adSlinfeng Operand::Integer(8),
246*fae6e9adSlinfeng Operand::Integer(37)
247*fae6e9adSlinfeng ],
248*fae6e9adSlinfeng },
249*fae6e9adSlinfeng ""
250*fae6e9adSlinfeng ))
251*fae6e9adSlinfeng );
252*fae6e9adSlinfeng
253*fae6e9adSlinfeng // Whitespace between operands is optional.
254*fae6e9adSlinfeng assert_eq!(
255*fae6e9adSlinfeng instruction().parse("jne r3,0x8,+37"),
256*fae6e9adSlinfeng Ok((
257*fae6e9adSlinfeng Instruction {
258*fae6e9adSlinfeng name: "jne".to_string(),
259*fae6e9adSlinfeng operands: vec![
260*fae6e9adSlinfeng Operand::Register(3),
261*fae6e9adSlinfeng Operand::Integer(8),
262*fae6e9adSlinfeng Operand::Integer(37)
263*fae6e9adSlinfeng ],
264*fae6e9adSlinfeng },
265*fae6e9adSlinfeng ""
266*fae6e9adSlinfeng ))
267*fae6e9adSlinfeng );
268*fae6e9adSlinfeng }
269*fae6e9adSlinfeng
270*fae6e9adSlinfeng // Other unit tests: try to parse various set of instructions.
271*fae6e9adSlinfeng
272*fae6e9adSlinfeng #[test]
test_empty()273*fae6e9adSlinfeng fn test_empty() {
274*fae6e9adSlinfeng assert_eq!(parse(""), Ok(vec![]));
275*fae6e9adSlinfeng }
276*fae6e9adSlinfeng
277*fae6e9adSlinfeng #[test]
test_exit()278*fae6e9adSlinfeng fn test_exit() {
279*fae6e9adSlinfeng // No operands.
280*fae6e9adSlinfeng assert_eq!(
281*fae6e9adSlinfeng parse("exit"),
282*fae6e9adSlinfeng Ok(vec![Instruction {
283*fae6e9adSlinfeng name: "exit".to_string(),
284*fae6e9adSlinfeng operands: vec![],
285*fae6e9adSlinfeng }])
286*fae6e9adSlinfeng );
287*fae6e9adSlinfeng }
288*fae6e9adSlinfeng
289*fae6e9adSlinfeng #[test]
test_lsh()290*fae6e9adSlinfeng fn test_lsh() {
291*fae6e9adSlinfeng // Register and immediate operands.
292*fae6e9adSlinfeng assert_eq!(
293*fae6e9adSlinfeng parse("lsh r3, 0x20"),
294*fae6e9adSlinfeng Ok(vec![Instruction {
295*fae6e9adSlinfeng name: "lsh".to_string(),
296*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Integer(0x20)],
297*fae6e9adSlinfeng }])
298*fae6e9adSlinfeng );
299*fae6e9adSlinfeng }
300*fae6e9adSlinfeng
301*fae6e9adSlinfeng #[test]
test_ja()302*fae6e9adSlinfeng fn test_ja() {
303*fae6e9adSlinfeng // Jump offset operand.
304*fae6e9adSlinfeng assert_eq!(
305*fae6e9adSlinfeng parse("ja +1"),
306*fae6e9adSlinfeng Ok(vec![Instruction {
307*fae6e9adSlinfeng name: "ja".to_string(),
308*fae6e9adSlinfeng operands: vec![Operand::Integer(1)],
309*fae6e9adSlinfeng }])
310*fae6e9adSlinfeng );
311*fae6e9adSlinfeng }
312*fae6e9adSlinfeng
313*fae6e9adSlinfeng #[test]
test_ldxh()314*fae6e9adSlinfeng fn test_ldxh() {
315*fae6e9adSlinfeng // Register and memory operands.
316*fae6e9adSlinfeng assert_eq!(
317*fae6e9adSlinfeng parse("ldxh r4, [r1+12]"),
318*fae6e9adSlinfeng Ok(vec![Instruction {
319*fae6e9adSlinfeng name: "ldxh".to_string(),
320*fae6e9adSlinfeng operands: vec![Operand::Register(4), Operand::Memory(1, 12)],
321*fae6e9adSlinfeng }])
322*fae6e9adSlinfeng );
323*fae6e9adSlinfeng }
324*fae6e9adSlinfeng
325*fae6e9adSlinfeng #[test]
test_tcp_sack()326*fae6e9adSlinfeng fn test_tcp_sack() {
327*fae6e9adSlinfeng // Sample program from ubpf.
328*fae6e9adSlinfeng // We could technically indent the instructions since the parser support white spaces at
329*fae6e9adSlinfeng // the beginning, but there is another test for that.
330*fae6e9adSlinfeng let src = "\
331*fae6e9adSlinfeng ldxb r2, [r1+12]
332*fae6e9adSlinfeng ldxb r3, [r1+13]
333*fae6e9adSlinfeng lsh r3, 0x8
334*fae6e9adSlinfeng or r3, r2
335*fae6e9adSlinfeng mov r0, 0x0
336*fae6e9adSlinfeng jne r3, 0x8, +37
337*fae6e9adSlinfeng ldxb r2, [r1+23]
338*fae6e9adSlinfeng jne r2, 0x6, +35
339*fae6e9adSlinfeng ldxb r2, [r1+14]
340*fae6e9adSlinfeng add r1, 0xe
341*fae6e9adSlinfeng and r2, 0xf
342*fae6e9adSlinfeng lsh r2, 0x2
343*fae6e9adSlinfeng add r1, r2
344*fae6e9adSlinfeng mov r0, 0x0
345*fae6e9adSlinfeng ldxh r4, [r1+12]
346*fae6e9adSlinfeng add r1, 0x14
347*fae6e9adSlinfeng rsh r4, 0x2
348*fae6e9adSlinfeng and r4, 0x3c
349*fae6e9adSlinfeng mov r2, r4
350*fae6e9adSlinfeng add r2, 0xffffffec
351*fae6e9adSlinfeng mov r5, 0x15
352*fae6e9adSlinfeng mov r3, 0x0
353*fae6e9adSlinfeng jgt r5, r4, +20
354*fae6e9adSlinfeng mov r5, r3
355*fae6e9adSlinfeng lsh r5, 0x20
356*fae6e9adSlinfeng arsh r5, 0x20
357*fae6e9adSlinfeng mov r4, r1
358*fae6e9adSlinfeng add r4, r5
359*fae6e9adSlinfeng ldxb r5, [r4]
360*fae6e9adSlinfeng jeq r5, 0x1, +4
361*fae6e9adSlinfeng jeq r5, 0x0, +12
362*fae6e9adSlinfeng mov r6, r3
363*fae6e9adSlinfeng jeq r5, 0x5, +9
364*fae6e9adSlinfeng ja +2
365*fae6e9adSlinfeng add r3, 0x1
366*fae6e9adSlinfeng mov r6, r3
367*fae6e9adSlinfeng ldxb r3, [r4+1]
368*fae6e9adSlinfeng add r3, r6
369*fae6e9adSlinfeng lsh r3, 0x20
370*fae6e9adSlinfeng arsh r3, 0x20
371*fae6e9adSlinfeng jsgt r2, r3, -18
372*fae6e9adSlinfeng ja +1
373*fae6e9adSlinfeng mov r0, 0x1
374*fae6e9adSlinfeng exit
375*fae6e9adSlinfeng ";
376*fae6e9adSlinfeng
377*fae6e9adSlinfeng assert_eq!(
378*fae6e9adSlinfeng parse(src),
379*fae6e9adSlinfeng Ok(vec![
380*fae6e9adSlinfeng Instruction {
381*fae6e9adSlinfeng name: "ldxb".to_string(),
382*fae6e9adSlinfeng operands: vec![Operand::Register(2), Operand::Memory(1, 12)],
383*fae6e9adSlinfeng },
384*fae6e9adSlinfeng Instruction {
385*fae6e9adSlinfeng name: "ldxb".to_string(),
386*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Memory(1, 13)],
387*fae6e9adSlinfeng },
388*fae6e9adSlinfeng Instruction {
389*fae6e9adSlinfeng name: "lsh".to_string(),
390*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Integer(8)],
391*fae6e9adSlinfeng },
392*fae6e9adSlinfeng Instruction {
393*fae6e9adSlinfeng name: "or".to_string(),
394*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Register(2)],
395*fae6e9adSlinfeng },
396*fae6e9adSlinfeng Instruction {
397*fae6e9adSlinfeng name: "mov".to_string(),
398*fae6e9adSlinfeng operands: vec![Operand::Register(0), Operand::Integer(0)],
399*fae6e9adSlinfeng },
400*fae6e9adSlinfeng Instruction {
401*fae6e9adSlinfeng name: "jne".to_string(),
402*fae6e9adSlinfeng operands: vec![
403*fae6e9adSlinfeng Operand::Register(3),
404*fae6e9adSlinfeng Operand::Integer(8),
405*fae6e9adSlinfeng Operand::Integer(37)
406*fae6e9adSlinfeng ],
407*fae6e9adSlinfeng },
408*fae6e9adSlinfeng Instruction {
409*fae6e9adSlinfeng name: "ldxb".to_string(),
410*fae6e9adSlinfeng operands: vec![Operand::Register(2), Operand::Memory(1, 23)],
411*fae6e9adSlinfeng },
412*fae6e9adSlinfeng Instruction {
413*fae6e9adSlinfeng name: "jne".to_string(),
414*fae6e9adSlinfeng operands: vec![
415*fae6e9adSlinfeng Operand::Register(2),
416*fae6e9adSlinfeng Operand::Integer(6),
417*fae6e9adSlinfeng Operand::Integer(35)
418*fae6e9adSlinfeng ],
419*fae6e9adSlinfeng },
420*fae6e9adSlinfeng Instruction {
421*fae6e9adSlinfeng name: "ldxb".to_string(),
422*fae6e9adSlinfeng operands: vec![Operand::Register(2), Operand::Memory(1, 14)],
423*fae6e9adSlinfeng },
424*fae6e9adSlinfeng Instruction {
425*fae6e9adSlinfeng name: "add".to_string(),
426*fae6e9adSlinfeng operands: vec![Operand::Register(1), Operand::Integer(14)],
427*fae6e9adSlinfeng },
428*fae6e9adSlinfeng Instruction {
429*fae6e9adSlinfeng name: "and".to_string(),
430*fae6e9adSlinfeng operands: vec![Operand::Register(2), Operand::Integer(15)],
431*fae6e9adSlinfeng },
432*fae6e9adSlinfeng Instruction {
433*fae6e9adSlinfeng name: "lsh".to_string(),
434*fae6e9adSlinfeng operands: vec![Operand::Register(2), Operand::Integer(2)],
435*fae6e9adSlinfeng },
436*fae6e9adSlinfeng Instruction {
437*fae6e9adSlinfeng name: "add".to_string(),
438*fae6e9adSlinfeng operands: vec![Operand::Register(1), Operand::Register(2)],
439*fae6e9adSlinfeng },
440*fae6e9adSlinfeng Instruction {
441*fae6e9adSlinfeng name: "mov".to_string(),
442*fae6e9adSlinfeng operands: vec![Operand::Register(0), Operand::Integer(0)],
443*fae6e9adSlinfeng },
444*fae6e9adSlinfeng Instruction {
445*fae6e9adSlinfeng name: "ldxh".to_string(),
446*fae6e9adSlinfeng operands: vec![Operand::Register(4), Operand::Memory(1, 12)],
447*fae6e9adSlinfeng },
448*fae6e9adSlinfeng Instruction {
449*fae6e9adSlinfeng name: "add".to_string(),
450*fae6e9adSlinfeng operands: vec![Operand::Register(1), Operand::Integer(20)],
451*fae6e9adSlinfeng },
452*fae6e9adSlinfeng Instruction {
453*fae6e9adSlinfeng name: "rsh".to_string(),
454*fae6e9adSlinfeng operands: vec![Operand::Register(4), Operand::Integer(2)],
455*fae6e9adSlinfeng },
456*fae6e9adSlinfeng Instruction {
457*fae6e9adSlinfeng name: "and".to_string(),
458*fae6e9adSlinfeng operands: vec![Operand::Register(4), Operand::Integer(60)],
459*fae6e9adSlinfeng },
460*fae6e9adSlinfeng Instruction {
461*fae6e9adSlinfeng name: "mov".to_string(),
462*fae6e9adSlinfeng operands: vec![Operand::Register(2), Operand::Register(4)],
463*fae6e9adSlinfeng },
464*fae6e9adSlinfeng Instruction {
465*fae6e9adSlinfeng name: "add".to_string(),
466*fae6e9adSlinfeng operands: vec![Operand::Register(2), Operand::Integer(4294967276)],
467*fae6e9adSlinfeng },
468*fae6e9adSlinfeng Instruction {
469*fae6e9adSlinfeng name: "mov".to_string(),
470*fae6e9adSlinfeng operands: vec![Operand::Register(5), Operand::Integer(21)],
471*fae6e9adSlinfeng },
472*fae6e9adSlinfeng Instruction {
473*fae6e9adSlinfeng name: "mov".to_string(),
474*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Integer(0)],
475*fae6e9adSlinfeng },
476*fae6e9adSlinfeng Instruction {
477*fae6e9adSlinfeng name: "jgt".to_string(),
478*fae6e9adSlinfeng operands: vec![
479*fae6e9adSlinfeng Operand::Register(5),
480*fae6e9adSlinfeng Operand::Register(4),
481*fae6e9adSlinfeng Operand::Integer(20)
482*fae6e9adSlinfeng ],
483*fae6e9adSlinfeng },
484*fae6e9adSlinfeng Instruction {
485*fae6e9adSlinfeng name: "mov".to_string(),
486*fae6e9adSlinfeng operands: vec![Operand::Register(5), Operand::Register(3)],
487*fae6e9adSlinfeng },
488*fae6e9adSlinfeng Instruction {
489*fae6e9adSlinfeng name: "lsh".to_string(),
490*fae6e9adSlinfeng operands: vec![Operand::Register(5), Operand::Integer(32)],
491*fae6e9adSlinfeng },
492*fae6e9adSlinfeng Instruction {
493*fae6e9adSlinfeng name: "arsh".to_string(),
494*fae6e9adSlinfeng operands: vec![Operand::Register(5), Operand::Integer(32)],
495*fae6e9adSlinfeng },
496*fae6e9adSlinfeng Instruction {
497*fae6e9adSlinfeng name: "mov".to_string(),
498*fae6e9adSlinfeng operands: vec![Operand::Register(4), Operand::Register(1)],
499*fae6e9adSlinfeng },
500*fae6e9adSlinfeng Instruction {
501*fae6e9adSlinfeng name: "add".to_string(),
502*fae6e9adSlinfeng operands: vec![Operand::Register(4), Operand::Register(5)],
503*fae6e9adSlinfeng },
504*fae6e9adSlinfeng Instruction {
505*fae6e9adSlinfeng name: "ldxb".to_string(),
506*fae6e9adSlinfeng operands: vec![Operand::Register(5), Operand::Memory(4, 0)],
507*fae6e9adSlinfeng },
508*fae6e9adSlinfeng Instruction {
509*fae6e9adSlinfeng name: "jeq".to_string(),
510*fae6e9adSlinfeng operands: vec![
511*fae6e9adSlinfeng Operand::Register(5),
512*fae6e9adSlinfeng Operand::Integer(1),
513*fae6e9adSlinfeng Operand::Integer(4)
514*fae6e9adSlinfeng ],
515*fae6e9adSlinfeng },
516*fae6e9adSlinfeng Instruction {
517*fae6e9adSlinfeng name: "jeq".to_string(),
518*fae6e9adSlinfeng operands: vec![
519*fae6e9adSlinfeng Operand::Register(5),
520*fae6e9adSlinfeng Operand::Integer(0),
521*fae6e9adSlinfeng Operand::Integer(12)
522*fae6e9adSlinfeng ],
523*fae6e9adSlinfeng },
524*fae6e9adSlinfeng Instruction {
525*fae6e9adSlinfeng name: "mov".to_string(),
526*fae6e9adSlinfeng operands: vec![Operand::Register(6), Operand::Register(3)],
527*fae6e9adSlinfeng },
528*fae6e9adSlinfeng Instruction {
529*fae6e9adSlinfeng name: "jeq".to_string(),
530*fae6e9adSlinfeng operands: vec![
531*fae6e9adSlinfeng Operand::Register(5),
532*fae6e9adSlinfeng Operand::Integer(5),
533*fae6e9adSlinfeng Operand::Integer(9)
534*fae6e9adSlinfeng ],
535*fae6e9adSlinfeng },
536*fae6e9adSlinfeng Instruction {
537*fae6e9adSlinfeng name: "ja".to_string(),
538*fae6e9adSlinfeng operands: vec![Operand::Integer(2)],
539*fae6e9adSlinfeng },
540*fae6e9adSlinfeng Instruction {
541*fae6e9adSlinfeng name: "add".to_string(),
542*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Integer(1)],
543*fae6e9adSlinfeng },
544*fae6e9adSlinfeng Instruction {
545*fae6e9adSlinfeng name: "mov".to_string(),
546*fae6e9adSlinfeng operands: vec![Operand::Register(6), Operand::Register(3)],
547*fae6e9adSlinfeng },
548*fae6e9adSlinfeng Instruction {
549*fae6e9adSlinfeng name: "ldxb".to_string(),
550*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Memory(4, 1)],
551*fae6e9adSlinfeng },
552*fae6e9adSlinfeng Instruction {
553*fae6e9adSlinfeng name: "add".to_string(),
554*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Register(6)],
555*fae6e9adSlinfeng },
556*fae6e9adSlinfeng Instruction {
557*fae6e9adSlinfeng name: "lsh".to_string(),
558*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Integer(32)],
559*fae6e9adSlinfeng },
560*fae6e9adSlinfeng Instruction {
561*fae6e9adSlinfeng name: "arsh".to_string(),
562*fae6e9adSlinfeng operands: vec![Operand::Register(3), Operand::Integer(32)],
563*fae6e9adSlinfeng },
564*fae6e9adSlinfeng Instruction {
565*fae6e9adSlinfeng name: "jsgt".to_string(),
566*fae6e9adSlinfeng operands: vec![
567*fae6e9adSlinfeng Operand::Register(2),
568*fae6e9adSlinfeng Operand::Register(3),
569*fae6e9adSlinfeng Operand::Integer(-18)
570*fae6e9adSlinfeng ],
571*fae6e9adSlinfeng },
572*fae6e9adSlinfeng Instruction {
573*fae6e9adSlinfeng name: "ja".to_string(),
574*fae6e9adSlinfeng operands: vec![Operand::Integer(1)],
575*fae6e9adSlinfeng },
576*fae6e9adSlinfeng Instruction {
577*fae6e9adSlinfeng name: "mov".to_string(),
578*fae6e9adSlinfeng operands: vec![Operand::Register(0), Operand::Integer(1)],
579*fae6e9adSlinfeng },
580*fae6e9adSlinfeng Instruction {
581*fae6e9adSlinfeng name: "exit".to_string(),
582*fae6e9adSlinfeng operands: vec![],
583*fae6e9adSlinfeng }
584*fae6e9adSlinfeng ])
585*fae6e9adSlinfeng );
586*fae6e9adSlinfeng }
587*fae6e9adSlinfeng
588*fae6e9adSlinfeng /// When running without `std` the `EasyParser` provided by `combine`
589*fae6e9adSlinfeng /// cannot be used. Because of this we need to use the `Parser` and the
590*fae6e9adSlinfeng /// error messages are different.
591*fae6e9adSlinfeng #[test]
test_error_eof()592*fae6e9adSlinfeng fn test_error_eof() {
593*fae6e9adSlinfeng let expected_error;
594*fae6e9adSlinfeng #[cfg(feature = "std")]
595*fae6e9adSlinfeng {
596*fae6e9adSlinfeng expected_error = Err(
597*fae6e9adSlinfeng "Parse error at line: 1, column: 6\nUnexpected end of input\nExpected digit\n"
598*fae6e9adSlinfeng .to_string(),
599*fae6e9adSlinfeng );
600*fae6e9adSlinfeng }
601*fae6e9adSlinfeng #[cfg(not(feature = "std"))]
602*fae6e9adSlinfeng {
603*fae6e9adSlinfeng expected_error = Err("unexpected parse".to_string());
604*fae6e9adSlinfeng }
605*fae6e9adSlinfeng // Unexpected end of input in a register name.
606*fae6e9adSlinfeng assert_eq!(parse("lsh r"), expected_error);
607*fae6e9adSlinfeng }
608*fae6e9adSlinfeng
609*fae6e9adSlinfeng /// When running without `std` the `EasyParser` provided by `combine`
610*fae6e9adSlinfeng /// cannot be used. Because of this we need to use the `Parser` and the
611*fae6e9adSlinfeng /// error messages are different.
612*fae6e9adSlinfeng #[test]
test_error_unexpected_character()613*fae6e9adSlinfeng fn test_error_unexpected_character() {
614*fae6e9adSlinfeng let expected_error;
615*fae6e9adSlinfeng #[cfg(feature = "std")]
616*fae6e9adSlinfeng {
617*fae6e9adSlinfeng expected_error = Err(
618*fae6e9adSlinfeng "Parse error at line: 2, column: 1\nUnexpected `^`\nExpected letter or digit, whitespaces, `r`, `-`, `+`, `[` or end of input\n".to_string()
619*fae6e9adSlinfeng );
620*fae6e9adSlinfeng }
621*fae6e9adSlinfeng #[cfg(not(feature = "std"))]
622*fae6e9adSlinfeng {
623*fae6e9adSlinfeng expected_error = Err("unexpected parse".to_string());
624*fae6e9adSlinfeng }
625*fae6e9adSlinfeng // Unexpected character at end of input.
626*fae6e9adSlinfeng assert_eq!(parse("exit\n^"), expected_error);
627*fae6e9adSlinfeng }
628*fae6e9adSlinfeng
629*fae6e9adSlinfeng #[test]
test_initial_whitespace()630*fae6e9adSlinfeng fn test_initial_whitespace() {
631*fae6e9adSlinfeng assert_eq!(
632*fae6e9adSlinfeng parse(
633*fae6e9adSlinfeng "
634*fae6e9adSlinfeng exit"
635*fae6e9adSlinfeng ),
636*fae6e9adSlinfeng Ok(vec![Instruction {
637*fae6e9adSlinfeng name: "exit".to_string(),
638*fae6e9adSlinfeng operands: vec![],
639*fae6e9adSlinfeng }])
640*fae6e9adSlinfeng );
641*fae6e9adSlinfeng }
642*fae6e9adSlinfeng }
643