]> Witch of Git - jade-rose/blob - toolchain/src/inst/parse.rs
Add parser and encoder tests, fix a parser bug
[jade-rose] / toolchain / src / inst / parse.rs
1 use super::{AddImm, AluI, Data, Inst, Op1, OpI3, OpR, Reg, Special, U3};
2 use nom::{
3 branch::alt,
4 bytes::complete::tag_no_case,
5 character::complete::{char, digit1, one_of, space1},
6 combinator::{complete, map, map_opt, map_res, opt, recognize, value},
7 sequence::{pair, preceded},
8 IResult,
9 };
10 use std::convert::TryFrom;
11
12 pub fn parse_inst(s: &str) -> Option<Inst> {
13 complete(inst())(s).ok().map(|x| x.1)
14 }
15
16 pub fn box_alt<
17 'a,
18 I: Clone + 'a,
19 O: 'a,
20 E: nom::error::ParseError<I> + 'a,
21 List: nom::branch::Alt<I, O, E> + 'a,
22 >(
23 l: List,
24 ) -> Box<dyn Fn(I) -> IResult<I, O, E> + 'a> {
25 Box::new(alt(l))
26 }
27
28 fn inst<'s>() -> impl Fn(&'s str) -> IResult<&'s str, Inst> {
29 alt((
30 box_alt((
31 fixed("trap", Inst::Trap),
32 fixed("JABS", Inst::JAbs),
33 fixed("CABS", Inst::CAbs),
34 fixed("JOFF", Inst::JOff),
35 fixed("COFF", Inst::COff),
36 )),
37 box_alt((
38 with_reg("SWAP", |r| Inst::Swap(r)),
39 with_reg("GETR", |r| Inst::GetR(r)),
40 with_reg("SETR", |r| Inst::SetR(r)),
41 )),
42 box_alt((
43 fixed("GET1", Inst::Get(Special::Data(Data::D1))),
44 fixed("GET2", Inst::Get(Special::Data(Data::D2))),
45 fixed("GETC", Inst::Get(Special::Code)),
46 fixed("SET1", Inst::Set(Special::Data(Data::D1))),
47 fixed("SET2", Inst::Set(Special::Data(Data::D2))),
48 fixed("SETC", Inst::Set(Special::Code)),
49 fixed("ZERO", Inst::Alu1(Op1::Zero)),
50 fixed("LSL1", Inst::Alu1(Op1::Lsl1)),
51 fixed("LSR1", Inst::Alu1(Op1::Lsr1)),
52 fixed("ASR1", Inst::Alu1(Op1::Asr1)),
53 fixed("INCR", Inst::Alu1(Op1::Incr)),
54 fixed("DECR", Inst::Alu1(Op1::Decr)),
55 fixed("COMP", Inst::Alu1(Op1::Comp)),
56 fixed("NEGT", Inst::Alu1(Op1::Negt)),
57 )),
58 box_alt((
59 with_reg("ISLT", |r| Inst::IsLt(r)),
60 with_reg("ADDR", |r| Inst::AluR(OpR::Add, r)),
61 with_reg("SUBR", |r| Inst::AluR(OpR::Sub, r)),
62 with_reg("ANDR", |r| Inst::AluR(OpR::And, r)),
63 with_reg("IORR", |r| Inst::AluR(OpR::Ior, r)),
64 with_reg("XORR", |r| Inst::AluR(OpR::Xor, r)),
65 with_reg("LSLR", |r| Inst::AluR(OpR::Lsl, r)),
66 with_reg("LSRR", |r| Inst::AluR(OpR::Lsr, r)),
67 with_reg("ASRR", |r| Inst::AluR(OpR::Asr, r)),
68 )),
69 box_alt((
70 with_reg_bang("LD1U", |r, b| Inst::LdD(Data::D1, r, b)),
71 with_reg_bang("ST1U", |r, b| Inst::StD(Data::D1, r, b)),
72 with_reg_bang("LD2U", |r, b| Inst::LdD(Data::D2, r, b)),
73 with_reg_bang("ST2U", |r, b| Inst::StD(Data::D2, r, b)),
74 )),
75 box_alt((
76 with_imm8("ANDI", |imm| Inst::AluI(AluI::And(imm))),
77 with_imm8("IORI", |imm| Inst::AluI(AluI::Ior(imm))),
78 with_imm8("XORI", |imm| Inst::AluI(AluI::Xor(imm))),
79 )),
80 with_add_imm("ADDI", |imm| Inst::AluI(AluI::Add(imm))),
81 box_alt((
82 with_imm3("ROLI", |imm| Inst::AluI(AluI::Compact(OpI3::Rol, imm))),
83 with_imm3("LSLI", |imm| Inst::AluI(AluI::Compact(OpI3::Lsl, imm))),
84 with_imm3("LSRI", |imm| Inst::AluI(AluI::Compact(OpI3::Lsr, imm))),
85 with_imm3("ASRI", |imm| Inst::AluI(AluI::Compact(OpI3::Asr, imm))),
86 with_imm3("CLRI", |imm| Inst::AluI(AluI::Compact(OpI3::Clr, imm))),
87 with_imm3("SETI", |imm| Inst::AluI(AluI::Compact(OpI3::Set, imm))),
88 with_imm3("TOGI", |imm| Inst::AluI(AluI::Compact(OpI3::Tog, imm))),
89 with_imm3("EXTI", |imm| Inst::AluI(AluI::Compact(OpI3::Ext, imm))),
90 )),
91 box_alt((
92 with_off("BEZI", |off| Inst::BEzI(off)),
93 with_off("JOFI", |off| Inst::JOfI(off)),
94 with_off("COFI", |off| Inst::COfI(off)),
95 )),
96 ))
97 }
98
99 fn fixed<'s>(tag: &'s str, inst: Inst) -> impl Fn(&'s str) -> IResult<&'s str, Inst> {
100 value(inst, tag_no_case(tag))
101 }
102
103 fn reg<'s>() -> impl Fn(&'s str) -> IResult<&'s str, Reg> {
104 let raw = preceded(tag_no_case("r"), digit1);
105 let num = map_res(raw, |x: &str| x.parse());
106 map_opt(num, Reg::new)
107 }
108
109 fn imm<'s>() -> impl Fn(&'s str) -> IResult<&'s str, i16> {
110 let text = recognize(pair(opt(one_of("+-")), digit1));
111 map_res(preceded(char('#'), text), |x: &str| x.parse())
112 }
113
114 fn imm8<'s>() -> impl Fn(&'s str) -> IResult<&'s str, u8> {
115 map_res(imm(), TryFrom::try_from)
116 }
117
118 fn add_imm<'s>() -> impl Fn(&'s str) -> IResult<&'s str, AddImm> {
119 map_opt(map_res(imm(), TryFrom::try_from), AddImm::new)
120 }
121
122 fn imm3<'s>() -> impl Fn(&'s str) -> IResult<&'s str, U3> {
123 map_opt(map_res(imm(), TryFrom::try_from), U3::new)
124 }
125
126 fn imm_off<'s>() -> impl Fn(&'s str) -> IResult<&'s str, i8> {
127 map_res(imm(), TryFrom::try_from)
128 }
129
130 fn with_reg<'s>(
131 tag: &'s str,
132 make_inst: impl Fn(Reg) -> Inst,
133 ) -> impl Fn(&'s str) -> IResult<&'s str, Inst> {
134 let reg = preceded(pair(tag_no_case(tag), space1), reg());
135 map(reg, make_inst)
136 }
137
138 fn with_reg_bang<'s>(
139 tag: &'s str,
140 make_inst: impl Fn(Reg, bool) -> Inst,
141 ) -> impl Fn(&'s str) -> IResult<&'s str, Inst> {
142 let reg_bang = pair(
143 preceded(pair(tag_no_case(tag), space1), reg()),
144 map(opt(char('!')), |x| x.is_some()),
145 );
146 map(reg_bang, move |(r, b)| make_inst(r, b))
147 }
148
149 fn with_imm8<'s>(
150 tag: &'s str,
151 make_inst: impl Fn(u8) -> Inst,
152 ) -> impl Fn(&'s str) -> IResult<&'s str, Inst> {
153 let imm = preceded(pair(tag_no_case(tag), space1), imm8());
154 map(imm, make_inst)
155 }
156
157 fn with_add_imm<'s>(
158 tag: &'s str,
159 make_inst: impl Fn(AddImm) -> Inst,
160 ) -> impl Fn(&'s str) -> IResult<&'s str, Inst> {
161 let imm = preceded(pair(tag_no_case(tag), space1), add_imm());
162 map(imm, make_inst)
163 }
164
165 fn with_imm3<'s>(
166 tag: &'s str,
167 make_inst: impl Fn(U3) -> Inst,
168 ) -> impl Fn(&'s str) -> IResult<&'s str, Inst> {
169 let imm = preceded(pair(tag_no_case(tag), space1), imm3());
170 map(imm, make_inst)
171 }
172
173 fn with_off<'s>(
174 tag: &'s str,
175 make_inst: impl Fn(i8) -> Inst,
176 ) -> impl Fn(&'s str) -> IResult<&'s str, Inst> {
177 let imm = preceded(pair(tag_no_case(tag), space1), imm_off());
178 map(imm, make_inst)
179 }