|
1 |
| -use libeir_ir::{ Block, MatchKind, BasicType, BinaryEntrySpecifier, Endianness }; |
| 1 | +use std::convert::TryInto; |
| 2 | +use std::sync::Arc; |
2 | 3 |
|
3 |
| -use libeir_util::binary::{ BitCarrier }; |
4 |
| -use libeir_util::binary::{ BitVec, BitSlice, carrier_to_integer, Endian }; |
| 4 | +use libeir_ir::{ Block, MatchKind, PrimOpKind, BasicType, |
| 5 | + BinaryEntrySpecifier, Endianness }; |
5 | 6 |
|
6 |
| -use crate::{ Term }; |
7 |
| -use crate::module::ErlangFunction; |
8 |
| -use crate::term::ErlExactEq; |
| 7 | +use lumen_runtime::otp::erlang; |
| 8 | +use liblumen_alloc::erts::term::{ Term, TypedTerm, Tuple, Atom, Integer, Closure, |
| 9 | + AsTerm, atom_unchecked }; |
| 10 | +use liblumen_alloc::erts::process::ProcessControlBlock; |
| 11 | +use liblumen_alloc::erts::exception::system; |
9 | 12 |
|
10 |
| -use super::{ CallExecutor, TermCall }; |
| 13 | +use crate::module::ErlangFunction; |
| 14 | +use super::{ CallExecutor, OpResult }; |
11 | 15 |
|
12 | 16 | pub fn match_op(
|
13 | 17 | exec: &mut CallExecutor,
|
| 18 | + proc: &Arc<ProcessControlBlock>, |
14 | 19 | fun: &ErlangFunction,
|
15 | 20 | branches: &[MatchKind],
|
16 | 21 | block: Block
|
17 |
| -) -> TermCall |
| 22 | +) -> std::result::Result<OpResult, system::Exception> |
18 | 23 | {
|
19 | 24 | let reads = fun.fun.block_reads(block);
|
20 | 25 |
|
21 |
| - let branches_elems = Term::as_value_list( |
22 |
| - &exec.make_term(fun, reads[0])); |
| 26 | + let branches_prim = fun.fun.value_primop(reads[0]).unwrap(); |
| 27 | + assert!(fun.fun.primop_kind(branches_prim) == &PrimOpKind::ValueList); |
| 28 | + let branches_dests = fun.fun.primop_reads(branches_prim); |
| 29 | + |
| 30 | + let unpack_term = exec.make_term(proc, fun, reads[1]).unwrap(); |
23 | 31 |
|
24 |
| - let unpack_term = exec.make_term(fun, reads[1]); |
| 32 | + for (idx, (kind, branch)) in branches.iter() |
| 33 | + .zip(branches_dests.iter()).enumerate() |
| 34 | + { |
| 35 | + let branch_arg_prim = fun.fun.value_primop(reads[idx + 2]).unwrap(); |
| 36 | + assert!(fun.fun.primop_kind(branch_arg_prim) == &PrimOpKind::ValueList); |
| 37 | + let branch_args = fun.fun.primop_reads(branch_arg_prim); |
25 | 38 |
|
26 |
| - //println!("MATCH START {:?}", unpack_term); |
27 |
| - for (idx, kind) in branches.iter().enumerate() { |
28 |
| - let branch_args = Term::as_value_list( |
29 |
| - &exec.make_term(fun, reads[idx + 2])); |
30 |
| - //println!("MATCH KIND {:?} {:?}", kind, branch_args); |
31 | 39 | match kind {
|
32 | 40 | MatchKind::Value => {
|
33 | 41 | assert!(branch_args.len() == 1);
|
34 |
| - if unpack_term.erl_exact_eq(&*branch_args[0]) { |
35 |
| - return TermCall { |
36 |
| - fun: branches_elems[idx].clone(), |
37 |
| - args: vec![], |
38 |
| - }; |
39 |
| - } |
40 |
| - } |
41 |
| - MatchKind::ListCell => { |
42 |
| - assert!(branch_args.len() == 0); |
43 |
| - match &*unpack_term { |
44 |
| - Term::ListCell(head, tail) => { |
45 |
| - return TermCall { |
46 |
| - fun: branches_elems[idx].clone(), |
47 |
| - args: vec![head.clone(), tail.clone()], |
48 |
| - }; |
49 |
| - } |
50 |
| - _ => (), |
51 |
| - } |
52 |
| - } |
53 |
| - MatchKind::Tuple(len) => { |
54 |
| - assert!(branch_args.len() == 0); |
55 |
| - match &*unpack_term { |
56 |
| - Term::Tuple(elems) if elems.len() == *len => { |
57 |
| - return TermCall { |
58 |
| - fun: branches_elems[idx].clone(), |
59 |
| - args: elems.clone(), |
60 |
| - }; |
61 |
| - } |
62 |
| - _ => (), |
63 |
| - } |
64 |
| - } |
65 |
| - MatchKind::Type(BasicType::Map) => { |
66 |
| - assert!(branch_args.len() == 0); |
67 |
| - match &*unpack_term { |
68 |
| - Term::Map(_) => { |
69 |
| - return TermCall { |
70 |
| - fun: branches_elems[idx].clone(), |
71 |
| - args: vec![], |
72 |
| - }; |
73 |
| - } |
74 |
| - _ => (), |
75 |
| - } |
76 |
| - } |
77 |
| - MatchKind::MapItem => { |
78 |
| - assert!(branch_args.len() == 1); |
79 |
| - match &*unpack_term { |
80 |
| - Term::Map(map) => { |
81 |
| - if let Some(v) = map.get(&branch_args[0]) { |
82 |
| - return TermCall { |
83 |
| - fun: branches_elems[idx].clone(), |
84 |
| - args: vec![v.clone()], |
85 |
| - }; |
86 |
| - } |
87 |
| - } |
88 |
| - _ => unreachable!(), |
89 |
| - } |
90 |
| - } |
91 |
| - MatchKind::Binary(BinaryEntrySpecifier::Integer { |
92 |
| - unit, endianness, signed |
93 |
| - }) => { |
94 |
| - let size = branch_args[0].as_usize().unwrap(); |
95 |
| - let bit_len = (*unit as usize) * size; |
96 |
| - |
97 |
| - let ret = match &*unpack_term { |
98 |
| - Term::Binary(bin) => { |
99 |
| - if (bin.len() * 8) < bit_len { continue; } |
100 |
| - |
101 |
| - let int_slice = BitSlice::with_offset_length( |
102 |
| - &**bin, 0, bit_len); |
103 |
| - let endian = match *endianness { |
104 |
| - Endianness::Big => Endian::Big, |
105 |
| - Endianness::Little => Endian::Little, |
106 |
| - Endianness::Native => Endian::Big, |
107 |
| - }; |
108 |
| - let int = carrier_to_integer(int_slice, *signed, endian); |
109 |
| - |
110 |
| - TermCall { |
111 |
| - fun: branches_elems[idx].clone(), |
112 |
| - args: vec![ |
113 |
| - Term::Integer(int).into(), |
114 |
| - Term::BinarySlice { |
115 |
| - buf: bin.clone(), |
116 |
| - bit_offset: bit_len, |
117 |
| - bit_length: bin.bit_len() - bit_len, |
118 |
| - }.into(), |
119 |
| - ], |
120 |
| - } |
121 |
| - }, |
122 |
| - Term::BinarySlice { buf, bit_offset, bit_length } => { |
123 |
| - if *bit_length < bit_len { continue; } |
124 |
| - |
125 |
| - let int_slice = BitSlice::with_offset_length( |
126 |
| - &**buf, *bit_offset, bit_len); |
127 |
| - let endian = match *endianness { |
128 |
| - Endianness::Big => Endian::Big, |
129 |
| - Endianness::Little => Endian::Little, |
130 |
| - Endianness::Native => Endian::Big, |
131 |
| - }; |
132 |
| - let int = carrier_to_integer(int_slice, *signed, endian); |
133 |
| - |
134 |
| - TermCall { |
135 |
| - fun: branches_elems[idx].clone(), |
136 |
| - args: vec![ |
137 |
| - Term::Integer(int).into(), |
138 |
| - Term::BinarySlice { |
139 |
| - buf: buf.clone(), |
140 |
| - bit_offset: *bit_offset + bit_len, |
141 |
| - bit_length: *bit_length - bit_len, |
142 |
| - }.into(), |
143 |
| - ], |
144 |
| - } |
145 |
| - }, |
146 |
| - _ => continue, |
147 |
| - }; |
148 |
| - return ret; |
149 |
| - } |
150 |
| - MatchKind::Binary(BinaryEntrySpecifier::Bytes { unit: 8 }) => { |
151 |
| - match &*unpack_term { |
152 |
| - Term::Binary(bin) => { |
153 |
| - if bin.bit_len() % 8 != 0 { continue; } |
154 |
| - |
155 |
| - return TermCall { |
156 |
| - fun: branches_elems[idx].clone(), |
157 |
| - args: vec![ |
158 |
| - unpack_term.clone(), |
159 |
| - Term::Binary(BitVec::new().into()).into(), |
160 |
| - ], |
161 |
| - }; |
162 |
| - } |
163 |
| - Term::BinarySlice { bit_length, .. } => { |
164 |
| - if *bit_length % 8 != 0 { continue; } |
| 42 | + let rhs = exec.make_term(proc, fun, branch_args[0]).unwrap(); |
165 | 43 |
|
166 |
| - return TermCall { |
167 |
| - fun: branches_elems[idx].clone(), |
168 |
| - args: vec![ |
169 |
| - unpack_term.clone(), |
170 |
| - Term::Binary(BitVec::new().into()).into(), |
171 |
| - ], |
172 |
| - }; |
173 |
| - } |
174 |
| - _ => (), |
| 44 | + if unpack_term.exactly_eq(&rhs) { |
| 45 | + return exec.val_call(proc, fun, *branch); |
175 | 46 | }
|
176 | 47 | }
|
177 | 48 | MatchKind::Wildcard => {
|
178 | 49 | assert!(branch_args.len() == 0);
|
179 |
| - return TermCall { |
180 |
| - fun: branches_elems[idx].clone(), |
181 |
| - args: vec![], |
182 |
| - }; |
| 50 | + return exec.val_call(proc, fun, *branch); |
183 | 51 | }
|
184 | 52 | kind => unimplemented!("{:?}", kind),
|
185 | 53 | }
|
|
0 commit comments