1use std::iter::{self, Peekable};
2use std::str::CharIndices;
3use std::cmp::Ordering;
4use rug::{Integer, Float};
5
6use super::*;
7use super::expr::{ExprData, OP, Value, FLOAT_PRECISION};
8use super::caseless::Caseless;
9
10#[cfg(test)]
11use super::expr::ValueCow;
12
13fn advance_cursor(cursor: &mut Peekable<CharIndices>, to: usize, end_pos: usize) {
16 loop {
17 match cursor.peek().copied() {
18 None => return assert_eq!(to, end_pos),
19 Some((p, _)) => {
20 if p < to { cursor.next(); }
21 else if p == to { return }
22 else { panic!() }
23 }
24 }
25 }
26}
27#[test]
28fn test_advance_cursor() {
29 let mut cursor = "hello world".char_indices().peekable();
30 assert_eq!(cursor.peek().unwrap().0, 0);
31 advance_cursor(&mut cursor, 5, 11);
32 assert_eq!(cursor.peek().unwrap().0, 5);
33 advance_cursor(&mut cursor, 5, 11);
34 assert_eq!(cursor.peek().unwrap().0, 5);
35 advance_cursor(&mut cursor, 10, 11);
36 assert_eq!(cursor.peek().unwrap().0, 10);
37 advance_cursor(&mut cursor, 11, 11);
38 assert_eq!(cursor.peek(), None);
39 advance_cursor(&mut cursor, 11, 11);
40 assert_eq!(cursor.peek(), None);
41}
42
43fn next_nonwhite_pos(s: &str, pos: usize) -> Option<usize> {
44 s[pos..].find(|c: char| !c.is_whitespace()).map(|p| p + pos)
45}
46#[test]
47fn test_next_nonwhite_pos() {
48 assert_eq!(next_nonwhite_pos("hello world", 0), Some(0));
49 assert_eq!(next_nonwhite_pos("hello world", 2), Some(2));
50 assert_eq!(next_nonwhite_pos("hello world", 4), Some(4));
51 assert_eq!(next_nonwhite_pos("hello world", 5), Some(9));
52 assert_eq!(next_nonwhite_pos("hello world", 8), Some(9));
53 assert_eq!(next_nonwhite_pos("hello world", 9), Some(9));
54 assert_eq!(next_nonwhite_pos("hello world", 10), Some(10));
55 assert_eq!(next_nonwhite_pos("hello world", 13), Some(13));
56 assert_eq!(next_nonwhite_pos("hello world", 14), None);
57 assert_eq!(next_nonwhite_pos("hello world ", 14), None);
58 assert_eq!(next_nonwhite_pos("hello world ", 16), None);
59}
60
61fn parse_size_str(val: &str, success: usize, failure: usize) -> (Option<Size>, usize) {
62 match SIZE_KEYWORDS.get(&Caseless(val)) {
63 Some(size) => (Some(*size), success),
64 None => (None, failure),
65 }
66}
67
68#[derive(Clone, Copy, PartialEq, Eq, Debug)]
69pub(super) struct TimesInfo {
70 pub(super) total_count: u64,
71 pub(super) current: u64,
72}
73
74#[derive(Clone, Copy, PartialEq, Eq, Debug)]
75pub(super) enum Locality {
76 Local,
77 Nonlocal,
78}
79
80pub(super) struct AssembleArgs<'a> {
81 pub(super) file_name: &'a str,
82 pub(super) file: ObjectFile,
83
84 pub(super) current_seg: Option<AsmSegment>,
85 pub(super) done_segs: Vec<AsmSegment>,
86
87 pub(super) line_num: usize,
88 pub(super) line_pos_in_seg: usize,
89
90 pub(super) last_nonlocal_label: Option<String>,
91 pub(super) label_def: Option<(String, Locality)>,
92
93 pub(super) times: Option<TimesInfo>,
94}
95impl AssembleArgs<'_> {
96 pub(super) fn update_line_pos_in_seg(&mut self) {
99 match self.current_seg {
100 None => (),
101 Some(AsmSegment::Text) => self.line_pos_in_seg = self.file.text.len(),
102 Some(AsmSegment::Rodata) => self.line_pos_in_seg = self.file.rodata.len(),
103 Some(AsmSegment::Data) => self.line_pos_in_seg = self.file.data.len(),
104 Some(AsmSegment::Bss) => self.line_pos_in_seg = self.file.bss_len,
105 }
106 }
107
108 fn mutate_name(&self, name: &str, err_pos: usize) -> Result<(String, Locality), AsmError> {
110 if name.starts_with('.') {
111 if name.len() <= 1 || name.chars().nth(1).unwrap().is_digit(10) { return Err(AsmError { kind: AsmErrorKind::InvalidSymbolName, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
113 match &self.last_nonlocal_label {
114 None => return Err(AsmError { kind: AsmErrorKind::LocalSymbolBeforeNonlocal, line_num: self.line_num, pos: Some(err_pos), inner_err: None }),
115 Some(nonlocal) => {
116 let mutated = format!("{}{}", nonlocal, name);
117 if !is_valid_symbol_name(&mutated) { return Err(AsmError { kind: AsmErrorKind::InvalidSymbolName, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
118 Ok((mutated, Locality::Local))
119 }
120 }
121 }
122 else {
123 if !is_valid_symbol_name(name) { return Err(AsmError { kind: AsmErrorKind::InvalidSymbolName, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
124 Ok((name.into(), Locality::Nonlocal))
125 }
126 }
127
128 fn extract_binary_op(&self, raw_line: &str, raw_start: usize, raw_stop: usize) -> Option<(OP, usize)> {
131 let mut pos = raw_line[raw_start..raw_stop].char_indices();
132
133 loop {
134 match pos.next() {
135 None => return None,
136 Some((p, c)) => {
137 if c.is_whitespace() { continue; }
138
139 let val = &raw_line[raw_start + p..];
140 for (repr, op) in BINARY_OP_STR.iter() {
141 if val.starts_with(repr) {
142 return Some((*op, raw_start + p + repr.len()));
143 }
144 }
145 return None;
146 }
147 }
148 }
149 }
150
151 fn extract_string(&self, raw_line: &str, raw_start: usize, raw_stop: usize) -> Result<(Vec<u8>, usize), AsmError> {
154 let mut pos = raw_line[raw_start..raw_stop].char_indices();
156 let (quote_pos, quote_char) = loop {
157 match pos.next() {
158 None => return Err(AsmError { kind: AsmErrorKind::ExpectedString, line_num: self.line_num, pos: Some(raw_stop), inner_err: None }),
159 Some((p, ch)) => {
160 if ['\'', '"'].contains(&ch) {
161 break (p, ch);
162 }
163 else if !ch.is_whitespace() {
164 return Err(AsmError { kind: AsmErrorKind::ExpectedString, line_num: self.line_num, pos: Some(raw_start + p), inner_err: None });
165 }
166 }
167 }
168 };
169
170 let mut res = vec![];
171 let mut buf = [0u8; 4];
172
173 loop {
175 match pos.next() {
176 None => return Err(AsmError { kind: AsmErrorKind::IncompleteString, line_num: self.line_num, pos: Some(raw_start + quote_pos), inner_err: None }),
177 Some((p, ch)) => {
178 if ch == quote_char {
179 return Ok((res, raw_start + p + 1));
180 }
181 else if ch == '\\' {
182 match pos.next() {
183 None => return Err(AsmError { kind: AsmErrorKind::IncompleteEscape, line_num: self.line_num, pos: Some(raw_start + p), inner_err: None }),
184 Some((_, esc)) => {
185 let mapped = match esc {
186 '\\' => Some('\\'),
187 '\'' => Some('\''),
188 '"' => Some('"'),
189 'n' => Some('\n'),
190 't' => Some('\t'),
191 'r' => Some('\r'),
192 '0' => Some('\0'),
193 'x' => {
194 let mut vals = [0; 2];
195 for val in vals.iter_mut() {
196 *val = match pos.next().map(|(_, x)| x.to_digit(16)).flatten() {
197 None => return Err(AsmError { kind: AsmErrorKind::IncompleteEscape, line_num: self.line_num, pos: Some(raw_start + p), inner_err: None }),
198 Some(v) => v,
199 };
200 }
201 let val = vals[0] * 16 + vals[1];
202 res.push(val as u8);
203 None
204 }
205 _ => return Err(AsmError { kind: AsmErrorKind::InvalidEscape, line_num: self.line_num, pos: Some(raw_start + p), inner_err: None }),
206 };
207 if let Some(mapped) = mapped {
208 res.extend(mapped.encode_utf8(&mut buf).as_bytes());
209 }
210 }
211 }
212 }
213 else {
214 res.extend(ch.encode_utf8(&mut buf).as_bytes());
215 }
216 }
217 }
218 }
219 }
220
221 fn parse_comma_sep_exprs(&mut self, raw_line: &str, raw_start: usize, raw_stop: usize) -> Result<Vec<Expr>, AsmError> {
223 let mut args = vec![];
224
225 let mut pos = raw_start;
226 loop {
227 let (expr, aft) = self.extract_expr(raw_line, pos, raw_stop)?;
229 args.push(expr);
230
231 let mut tail = raw_line[aft..raw_stop].char_indices();
233 loop {
234 match tail.next() {
235 None => return Ok(args), Some((p, c)) => {
237 if c.is_whitespace() { continue; } else if c == ',' { pos = aft + p + 1; break; } else { return Err(AsmError { kind: AsmErrorKind::ExpectedCommaBeforeToken, line_num: self.line_num, pos: Some(aft + p, ), inner_err: None }); }
240 }
241 }
242 }
243 }
244 }
245
246 fn extract_expr(&mut self, raw_line: &str, raw_start: usize, raw_stop: usize) -> Result<(Expr, usize), AsmError> {
249 let mut parsing_pos = raw_start;
250
251 let mut unary_stack: Vec<OP> = Vec::with_capacity(8);
252 let mut binary_stack: Vec<OP> = Vec::with_capacity(8);
253
254 let mut output_stack: Vec<Expr> = Vec::with_capacity(8);
255
256 loop {
257 let mut chars = raw_line[parsing_pos..raw_stop].char_indices().peekable();
258
259 debug_assert!(unary_stack.is_empty());
261 let (term_start, numeric) = loop {
262 match chars.peek().copied() {
263 None => return Err(AsmError { kind: AsmErrorKind::ExpectedExpr, line_num: self.line_num, pos: Some(raw_stop), inner_err: None }),
264 Some((_, x)) if x.is_whitespace() || x == '+' => (), Some((_, '-')) => unary_stack.push(OP::Neg), Some((_, '!')) => unary_stack.push(OP::Not),
267 Some((p, '~')) => return Err(AsmError { kind: AsmErrorKind::UseOfTildeNot, line_num: self.line_num, pos: Some(parsing_pos + p), inner_err: None }),
268 Some((p, c)) => break (parsing_pos + p, c.is_digit(10)), }
270 chars.next(); };
272
273 let mut paren_positions = vec![]; let (term_stop, bin_op) = loop {
277 let end_content = chars.peek().cloned();
278 match end_content {
279 None => {
281 if paren_positions.is_empty() { break (raw_stop, None); }
282 else { return Err(AsmError { kind: AsmErrorKind::UnclosedParen, line_num: self.line_num, pos: Some(paren_positions.last().copied().unwrap()), inner_err: None }); }
283 }
284 Some((p, ch)) => match ch {
286 '(' => {
287 if numeric { break (parsing_pos + p, None)
289 }
290 paren_positions.push(parsing_pos + p);
291 }
292 ')' => match paren_positions.len() {
293 0 => break (parsing_pos + p, None), 1 => match self.extract_binary_op(raw_line, parsing_pos + p + 1, raw_stop) { Some((op, aft)) => break (parsing_pos + p + 1, Some((op, aft))),
296 None => break (parsing_pos + p + 1, None),
297 }
298 _ => { paren_positions.pop(); }
299 }
300 '"' | '\'' => {
301 if numeric { break (parsing_pos + p, None)
303 }
304 let (_, aft) = self.extract_string(raw_line, parsing_pos + p, raw_stop)?; advance_cursor(&mut chars, aft - 1 - parsing_pos, raw_stop); debug_assert_ne!(chars.peek().unwrap().0, p);
307 debug_assert_eq!(chars.peek().unwrap().1, ch); }
309 'e' | 'E' if numeric => {
310 if let Some((_, x)) = chars.clone().nth(1) { if x == '+' || x == '-' { chars.next(); } }
313 }
314 _ => {
315 if paren_positions.is_empty() {
316 if let Some((op, aft)) = self.extract_binary_op(raw_line, parsing_pos + p, raw_stop) {
317 break (parsing_pos + p, Some((op, aft))); }
319 else if ch.is_whitespace() || ch == ',' || ch == ']' || ch == '}' || ch == COMMENT_CHAR {
320 break (parsing_pos + p, None); }
322 }
323 }
324 }
325 }
326 chars.next(); };
328 drop(chars); let term = &raw_line[term_start..term_stop];
332 debug_assert_eq!(term, term.trim());
333 if term.is_empty() { return Err(AsmError { kind: AsmErrorKind::ExpectedExpr, line_num: self.line_num, pos: Some(term_start), inner_err: None }); }
334
335 let term_expr = match term.chars().next().unwrap() {
336 '(' => { debug_assert_eq!(term.chars().rev().next().unwrap(), ')'); let (expr, aft) = self.extract_expr(raw_line, term_start + 1, term_stop - 1)?; match raw_line[aft..term_stop-1].trim_start().chars().next() {
340 None => (),
341 Some(x) if x == COMMENT_CHAR => return Err(AsmError { kind: AsmErrorKind::UnclosedParen, line_num: self.line_num, pos: Some(term_start), inner_err: None }),
342 Some(_) => return Err(AsmError { kind: AsmErrorKind::ParenInteriorNotExpr, line_num: self.line_num, pos: Some(term_start), inner_err: None }), }
344 expr
345 }
346 '$' => match term { "$" => match self.current_seg { None => return Err(AsmError { kind: AsmErrorKind::AddressOutsideOfSegment, line_num: self.line_num, pos: Some(term_start), inner_err: None }),
349 Some(seg) => (OP::Add, ExprData::Ident(get_seg_offset_str(seg).into()), self.line_pos_in_seg as i64).into(),
350 }
351 "$$" => match self.current_seg { None => return Err(AsmError { kind: AsmErrorKind::AddressOutsideOfSegment, line_num: self.line_num, pos: Some(term_start), inner_err: None }),
353 Some(seg) => ExprData::Ident(get_seg_origin_str(seg).into()).into(),
354 }
355 "$file" => Value::Binary(self.file_name.as_bytes().into()).into(),
356 "$i" => match &self.times { None => return Err(AsmError { kind: AsmErrorKind::TimesIterOutisideOfTimes, line_num: self.line_num, pos: Some(term_start), inner_err: None }),
358 Some(info) => (info.current as u64).into(),
359 }
360 _ => { let paren_pos = match term.find('(') {
362 None => return Err(AsmError { kind: AsmErrorKind::UnrecognizedMacroInvocation, line_num: self.line_num, pos: Some(term_start), inner_err: None }),
363 Some(p) => p,
364 };
365 if term.chars().rev().next() != Some(')') {
366 return Err(AsmError { kind: AsmErrorKind::UnrecognizedMacroInvocation, line_num: self.line_num, pos: Some(term_start), inner_err: None });
367 }
368 let func = &term[..paren_pos];
369 let args = self.parse_comma_sep_exprs(raw_line, term_start + paren_pos + 1, term_stop - 1)?;
370
371 fn chain_encode(args: Vec<Expr>, encoder: OP, line_num: usize, term_start: usize) -> Result<Expr, AsmError> {
372 if args.len() == 0 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCountAtLeast(1), line_num, pos: Some(term_start), inner_err: None }); }
373 Ok(Expr::chain_add(args.into_iter().map(|x| Expr::from((encoder, x))).collect()).unwrap())
374 }
375 match func {
376 "$if" => {
377 if args.len() != 3 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[3]), line_num: self.line_num, pos: Some(term_start), inner_err: None }); }
378 let mut args = args.into_iter();
379 let cond = args.next().unwrap();
380 let left = args.next().unwrap();
381 let right = args.next().unwrap();
382 (OP::Condition, cond, Expr::from((OP::Pair, left, right))).into()
383 }
384
385 "$eb" => chain_encode(args, OP::EncodeBin8, self.line_num, term_start)?,
386 "$ew" => chain_encode(args, OP::EncodeBin16, self.line_num, term_start)?,
387 "$ed" => chain_encode(args, OP::EncodeBin32, self.line_num, term_start)?,
388 "$eq" => chain_encode(args, OP::EncodeBin64, self.line_num, term_start)?,
389 "$et" => chain_encode(args, OP::EncodeBin80, self.line_num, term_start)?,
390
391 "$db" => Expr::from((OP::Intern, chain_encode(args, OP::EncodeBin8, self.line_num, term_start)?)),
392 "$dw" => Expr::from((OP::Intern, chain_encode(args, OP::EncodeBin16, self.line_num, term_start)?)),
393 "$dd" => Expr::from((OP::Intern, chain_encode(args, OP::EncodeBin32, self.line_num, term_start)?)),
394 "$dq" => Expr::from((OP::Intern, chain_encode(args, OP::EncodeBin64, self.line_num, term_start)?)),
395 "$dt" => Expr::from((OP::Intern, chain_encode(args, OP::EncodeBin80, self.line_num, term_start)?)),
396
397 _ => match UNARY_FUNCTION_OPERATOR_TO_OP.get(func).copied() {
398 Some(op) => {
399 if args.len() != 1 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[1]), line_num: self.line_num, pos: Some(term_start), inner_err: None }); }
400 (op, args.into_iter().next().unwrap()).into()
401 }
402 None => return Err(AsmError { kind: AsmErrorKind::UnrecognizedMacroInvocation, line_num: self.line_num, pos: Some(term_start), inner_err: None }),
403 }
404 }
405 }
406 }
407 str_char @ '\'' | str_char @ '"' => {
408 debug_assert_eq!(term.chars().rev().next().unwrap(), term.chars().next().unwrap()); let (content, _) = self.extract_string(raw_line, term_start, term_stop)?;
410 match str_char {
411 '"' => ExprData::Value(Value::Binary(content)).into(),
412 '\'' => match String::from_utf8(content) {
413 Err(_) => return Err(AsmError { kind: AsmErrorKind::CharacterLiteralNotUnicode, line_num: self.line_num, pos: Some(term_start), inner_err: None }),
414 Ok(string) => {
415 let mut chars = string.chars();
416 let res = chars.next();
417 if res.is_none() || chars.next().is_some() {
418 return Err(AsmError { kind: AsmErrorKind::CharacterLiteralNotSingleChar, line_num: self.line_num, pos: Some(term_start), inner_err: None });
419 }
420 ExprData::Value(Value::Character(res.unwrap())).into()
421 }
422 }
423 _ => unreachable!(),
424 }
425
426 }
427 '0'..='9' => { let (term_fix, radix) = match term { x if x.starts_with("0x") => (&x[2..], 16),
430 x if x.starts_with("0o") => (&x[2..], 8),
431 x if x.starts_with("0b") => (&x[2..], 2),
432 x => (x, 10),
433 };
434 let term_fix = { let start = term_fix.find(|c: char| c != '_').unwrap_or(term_fix.len());
436 let term_fix = &term_fix[start..];
437 let stop = term_fix.rfind(|c: char| c != '_').map(|p| p + 1).unwrap_or(0);
438 &term_fix[..stop]
439 };
440 debug_assert!(!term_fix.starts_with('+') && !term_fix.starts_with('-'));
442
443 match Integer::from_str_radix(&term_fix, radix) {
445 Ok(v) => {
446 if radix == 10 && term_fix.len() > 1 && term_fix.starts_with('0') { return Err(AsmError { kind: AsmErrorKind::NumericLiteralWithZeroPrefix, line_num: self.line_num, pos: Some(term_start), inner_err: None });
448 }
449 v.into()
450 }
451 Err(_) => {
452 if radix != 10 { return Err(AsmError { kind: AsmErrorKind::IllFormedNumericLiteral, line_num: self.line_num, pos: Some(term_start), inner_err: None }); }
454
455 match Float::parse(term_fix) { Err(_) => return Err(AsmError { kind: AsmErrorKind::IllFormedNumericLiteral, line_num: self.line_num, pos: Some(term_start), inner_err: None }),
458 Ok(v) => Float::with_val(FLOAT_PRECISION, v).into(),
459 }
460 }
461 }
462 }
463 _ => { if Caseless(term) == Caseless("TRUE") { true.into() }
465 else if Caseless(term) == Caseless("FALSE") { false.into() }
466 else if Caseless(term) == Caseless("NULL") { Value::Integer(Integer::new()).into() }
467 else if Caseless(term) == Caseless("EOF") { Value::Integer((-1).into()).into() }
468 else { let (mutated, _) = self.mutate_name(term, term_start)?;
470 ExprData::Ident(mutated).into()
471 }
472 }
473 };
474
475 parsing_pos = match bin_op {
477 None => term_stop,
478 Some((_, aft)) => aft,
479 };
480
481 output_stack.push(term_expr);
483
484 while let Some(op) = unary_stack.pop() {
486 let last = output_stack.pop().unwrap();
487 output_stack.push((op, last).into());
488 }
489
490 match bin_op {
492 Some((op, _)) => { let op_prec = *PRECEDENCE.get(&op).unwrap();
495 loop {
496 let top = match binary_stack.last() {
497 None => break,
498 Some(op) => *op,
499 };
500 let top_prec = *PRECEDENCE.get(&top).unwrap();
501 if top_prec.0 >= op_prec.0 && (top_prec.0 != op_prec.0 || op_prec.1 != Associativity::Left) {
502 break;
503 }
504
505 binary_stack.pop();
507 let right = output_stack.pop().unwrap();
508 let left = output_stack.pop().unwrap();
509 output_stack.push((top, left, right).into()); }
511
512 binary_stack.push(op);
514 }
515 None => {
516 break; }
518 }
519 }
520
521 while let Some(op) = binary_stack.pop() {
523 let right = output_stack.pop().unwrap();
524 let left = output_stack.pop().unwrap();
525 output_stack.push((op, left, right).into()); }
527
528 debug_assert_eq!(output_stack.len(), 1);
530 let res = self.apply_ptrdiff(output_stack.into_iter().next().unwrap());
531
532 Ok((res, parsing_pos))
533 }
534
535 fn get_ptr_offset<'a>(&'a self, expr: &'a Expr, base: &str) -> Option<Expr> {
536 let target = match &*expr.data.borrow() {
537 ExprData::Value(_) => return None,
538 ExprData::Ident(ident) => {
539 if ident == base { return Some(0.into()); } match self.file.symbols.get(ident) {
541 None => return None,
542 Some((symbol, _)) => symbol,
543 }
544 }
545 ExprData::Uneval { .. } => expr,
546 };
547 match &*target.data.borrow() {
548 ExprData::Uneval { op: OP::Add, left, right } => match &*left.as_ref().unwrap().data.borrow() { ExprData::Ident(ident) if ident == base => match &*right.as_ref().unwrap().data.borrow() {
550 ExprData::Value(Value::Integer(v)) => Some(v.clone().into()), _ => panic!("address improperly constructed"),
552 }
553 _ => None,
554 }
555 _ => None,
556 }
557 }
558 fn apply_ptrdiff(&self, expr: Expr) -> Expr {
562 let (mut add, mut sub) = expr.break_add_sub();
563 for base in PTRDIFF_IDS { let a = add.iter_mut().filter_map(|x| self.get_ptr_offset(x, base).map(|r| (x, r)));
565 let b = sub.iter_mut().filter_map(|x| self.get_ptr_offset(x, base).map(|r| (x, r)));
566 for (a, b) in a.zip(b) {
567 *a.0 = a.1; *b.0 = b.1;
569 }
570 }
571
572 let recurse = |x: Expr| match x.data.into_inner() {
574 x @ ExprData::Value(_) => Expr::from(x),
575 x @ ExprData::Ident(_) => Expr::from(x),
576 ExprData::Uneval { op, left, right } => {
577 let left = left.map(|x| Box::new(self.apply_ptrdiff(*x)));
578 let right = right.map(|x| Box::new(self.apply_ptrdiff(*x)));
579 ExprData::Uneval { op, left, right }.into()
580 }
581 };
582 let add = add.into_iter().map(recurse).collect();
583 let sub = sub.into_iter().map(recurse).collect();
584
585 Expr::chain_add_sub(add, sub).unwrap() }
587
588 fn extract_imm(&mut self, raw_line: &str, raw_start: usize, raw_stop: usize) -> Result<(Imm, usize), AsmError> {
589 let (token, token_stop) = grab_alnum_token(raw_line, raw_start, raw_stop);
591 let (size, expr_start) = parse_size_str(token, token_stop, raw_start);
592
593 let (expr, aft) = self.extract_expr(raw_line, expr_start, raw_stop)?;
595 Ok((Imm { expr, size }, aft))
596 }
597 fn extract_address(&mut self, raw_line: &str, raw_start: usize, raw_stop: usize) -> Result<(Address, usize), AsmError> {
598 let (token, token_stop) = grab_whitespace_sep_token(raw_line, raw_start, raw_stop);
600 let addr_start = token_stop - token.len();
601 if token.is_empty() {
602 return Err(AsmError { kind: AsmErrorKind::ExpectedAddress, line_num: self.line_num, pos: Some(raw_stop), inner_err: None });
603 }
604 if let Some(p) = token.find('[') {
605 let token_fix = &token[..p];
606 if Caseless(token_fix) == Caseless("PTR") {
607 return Err(AsmError { kind: BadAddress::PtrSpecWithoutSize.into(), line_num: self.line_num, pos: Some(addr_start), inner_err: None });
608 }
609 if p != 0 && token_fix.chars().all(|c| c.is_ascii_alphanumeric()) { if parse_size_str(token_fix, 0, 0).0.is_some() { return Err(AsmError { kind: BadAddress::SizeMissingPtr.into(), line_num: self.line_num, pos: Some(addr_start + p), inner_err: None });
612 }
613 else { return Err(AsmError { kind: BadAddress::SizeNotRecognized.into(), line_num: self.line_num, pos: Some(addr_start), inner_err: None });
615 }
616 }
617 }
618 if Caseless(token) == Caseless("PTR") {
619 return Err(AsmError { kind: BadAddress::PtrSpecWithoutSize.into(), line_num: self.line_num, pos: Some(addr_start), inner_err: None });
620 }
621 let (pointed_size, mut next_start) = parse_size_str(token, token_stop, raw_start);
622 match pointed_size {
623 Some(_) => { let (mut token, mut token_stop) = grab_whitespace_sep_token(raw_line, next_start, raw_stop);
625 let bracket_pos = token.find('[');
626 if let Some(p) = bracket_pos {
627 token_stop -= token.len() - p; token = &token[..p];
629 }
630
631 if Caseless(token) == Caseless("PTR") { next_start = token_stop; }
632 else {
633 let should_be_addr = match bracket_pos {
635 Some(_) => token.chars().all(|c| c.is_ascii_alphanumeric()),
636 None => {
637 let (next_tok, _) = grab_whitespace_sep_token(raw_line, token_stop, raw_stop);
638 next_tok.starts_with('[')
639 }
640 };
641 if should_be_addr {
642 return Err(AsmError { kind: BadAddress::SizeMissingPtr.into(), line_num: self.line_num, pos: Some(token_stop - token.len()), inner_err: None });
643 } else {
644 return Err(AsmError { kind: AsmErrorKind::ExpectedAddress, line_num: self.line_num, pos: Some(token_stop - token.len()), inner_err: None });
645 }
646 }
647 }
648 None => { if token.chars().next() != Some('[') {
650 let should_be_addr = { let (next_tok, _) = grab_whitespace_sep_token(raw_line, token_stop, raw_stop);
652 match next_tok.find('[') {
653 Some(p) => p == 0 || Caseless(&next_tok[..p]) == Caseless("PTR"),
654 None => Caseless(next_tok) == Caseless("PTR")
655 }
656 };
657 if should_be_addr {
658 return Err(AsmError { kind: BadAddress::SizeNotRecognized.into(), line_num: self.line_num, pos: Some(addr_start), inner_err: None });
659 } else {
660 return Err(AsmError { kind: AsmErrorKind::ExpectedAddress, line_num: self.line_num, pos: Some(addr_start), inner_err: None });
661 }
662 }
663 }
664 }
665
666 let address_start = match raw_line[next_start..raw_stop].find(|c: char| !c.is_whitespace()) {
668 None => return Err(AsmError { kind: AsmErrorKind::ExpectedAddress, line_num: self.line_num, pos: Some(raw_stop), inner_err: None }),
669 Some(p) => next_start + p,
670 };
671 if raw_line[address_start..].chars().next().unwrap() != '[' {
672 return Err(AsmError { kind: AsmErrorKind::ExpectedAddress, line_num: self.line_num, pos: Some(address_start), inner_err: None });
673 }
674 let (mut imm, imm_aft) = match self.extract_imm(raw_line, address_start + 1, raw_stop) {
675 Err(e) => return Err(AsmError { kind: BadAddress::BadBase.into(), line_num: self.line_num, pos: Some(address_start), inner_err: Some(Box::new(e)) }),
676 Ok(x) => x,
677 };
678 let (tail, tail_start) = trim_start_with_pos(raw_line, imm_aft, raw_stop);
679 match tail.chars().next() {
680 Some(']') => (),
681 None => return Err(AsmError { kind: BadAddress::Unterminated.into(), line_num: self.line_num, pos: Some(tail_start), inner_err: None }),
682 Some(_) => return Err(AsmError { kind: BadAddress::InteriorNotSingleExpr.into(), line_num: self.line_num, pos: Some(tail_start), inner_err: None }),
683 }
684 if let Some(size) = imm.size {
685 match size {
686 Size::Word | Size::Dword | Size::Qword => (),
687 _ => return Err(AsmError { kind: BadAddress::SizeUnsupported.into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }),
688 }
689 }
690
691 let mut r1: Option<(u8, u8)> = None; let mut r2: Option<u8> = None; for reg in CPU_REGISTER_INFO.iter() {
695 if let Some(mult) = self.get_reg_mult(*reg.0, &imm.expr, raw_line, address_start)? { match imm.size {
697 None => {
698 match reg.1.size {
699 Size::Word | Size::Dword | Size::Qword => (),
700 _ => return Err(AsmError { kind: BadAddress::SizeUnsupported.into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }),
701 }
702 imm.size = Some(reg.1.size); }
704 Some(size) => if size != reg.1.size { return Err(AsmError { kind: BadAddress::ConflictingSizes.into(), line_num: self.line_num, pos: Some(address_start), inner_err: None });
706 }
707 }
708
709 let mut mult = match mult.eval(&self.file.symbols) { Err(e) => return Err(AsmError { kind: BadAddress::RegMultNotCriticalExpr(e).into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }),
711 Ok(val) => match &*val {
712 Value::Integer(v) => match v.to_u64() {
713 None => return Err(AsmError { kind: BadAddress::InvalidRegMults.into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }),
714 Some(v) => v,
715 }
716 _ => unreachable!(), },
718 };
719 if mult == 0 { continue; } if mult & 1 != 0 {
723 mult &= !1; if r2.is_none() { r2 = Some(reg.1.id); } else if r1.is_none() { r1 = Some((reg.1.id, 0)); } else { return Err(AsmError { kind: BadAddress::InvalidRegMults.into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }); } }
728 if mult != 0 {
730 let multcode = match mult { 1 => 0,
732 2 => 1,
733 4 => 2,
734 8 => 3,
735 _ => return Err(AsmError { kind: BadAddress::InvalidRegMults.into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }),
736 };
737
738 if r1.is_none() { r1 = Some((reg.1.id, multcode)); }
739 else { return Err(AsmError { kind: BadAddress::InvalidRegMults.into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }); }
740 }
741 }
742 }
743
744 let address_size = imm.size.unwrap_or(Size::Qword); let base = {
746 let present = match imm.expr.eval(&self.file.symbols) {
747 Err(e) => match e {
748 EvalError::Illegal(reason) => return Err(AsmError { kind: BadAddress::IllegalExpr(reason).into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }),
749 EvalError::UndefinedSymbol(_) => true, }
751 Ok(v) => match &*v {
752 Value::Integer(v) => *v != 0, t => return Err(AsmError { kind: BadAddress::TypeUnsupported(t.get_type()).into(), line_num: self.line_num, pos: Some(address_start), inner_err: None }), }
755 };
756 if present { Some(imm.expr) } else { None }
757 };
758
759 Ok((Address { address_size, r1, r2, base, pointed_size }, tail_start + 1))
760 }
761 fn get_reg_mult(&self, reg: Caseless, expr: &Expr, raw_line: &str, err_pos: usize) -> Result<Option<Expr>, AsmError> {
762 let handle = &mut *expr.data.borrow_mut();
763 match handle {
764 ExprData::Value(_) => Ok(None),
765 ExprData::Ident(ident) => {
766 if Caseless(ident) == reg {
767 *handle = 0.into(); Ok(Some(1.into())) }
770 else {
771 Ok(None)
772 }
773 }
774 ExprData::Uneval { op, left, right } => {
775 let a = self.get_reg_mult(reg, left.as_ref().unwrap(), raw_line, err_pos)?;
776 match op {
777 OP::Neg => {
778 if let Some(_) = right.as_ref() { panic!(); }
779 Ok(a.map(|t| (OP::Neg, t).into())) }
781 OP::Add | OP::Sub => {
782 let b = self.get_reg_mult(reg, right.as_ref().unwrap(), raw_line, err_pos)?;
783
784 if a.is_none() && b.is_none() { Ok(None) }
786 else { Ok(Some((*op, a.unwrap_or(0.into()), b.unwrap_or(0.into())).into())) }
787 }
788 OP::Mul => match a { Some(a) => Ok(Some((OP::Mul, a, (**right.as_ref().unwrap()).clone()).into())), None => match self.get_reg_mult(reg, right.as_ref().unwrap(), raw_line, err_pos)? {
791 Some(b) => Ok(Some((OP::Mul, (**left.as_ref().unwrap()).clone(), b).into())), None => Ok(None), }
794 }
795 _ => { if let Some(_) = a {
797 return Err(AsmError { kind: BadAddress::RegIllegalOp.into(), line_num: self.line_num, pos: Some(err_pos), inner_err: None });
798 }
799 if let Some(v) = right.as_ref() {
800 if let Some(_) = self.get_reg_mult(reg, v, raw_line, err_pos)? {
801 return Err(AsmError { kind: BadAddress::RegIllegalOp.into(), line_num: self.line_num, pos: Some(err_pos), inner_err: None });
802 }
803 }
804 Ok(None)
805 }
806 }
807 }
808 }
809 }
810
811 fn extract_vpu_bracket_arg(&mut self, raw_line: &str, raw_start: usize, raw_stop: usize) -> Result<(Option<Argument>, usize), AsmError> {
812 match raw_line[raw_start..raw_stop].find(|c: char| !c.is_whitespace()).map(|v| v + raw_start) {
813 Some(open_pos) if raw_line[open_pos..].chars().next().unwrap() == '{' => {
814 let (arg, aft) = match self.extract_arg(raw_line, open_pos + 1, raw_stop) {
815 Ok(v) => v,
816 Err(e) => return Err(AsmError { kind: AsmErrorKind::VPUFailedToParseMaskArg, line_num: self.line_num, pos: Some(open_pos), inner_err: Some(Box::new(e)) }),
817 };
818 match raw_line[aft..raw_stop].find(|c: char| !c.is_whitespace()).map(|v| v + aft) {
819 Some(close_pos) if raw_line[close_pos..].chars().next().unwrap() == '}' => Ok((Some(arg), close_pos + 1)),
820 _ => Err(AsmError { kind: AsmErrorKind::VPUMaskUnclosedBracket, line_num: self.line_num, pos: Some(open_pos), inner_err: None }),
821 }
822 }
823 _ => Ok((None, raw_start)),
824 }
825 }
826 fn extract_vpu_mask(&mut self, soft_err_pos: usize, raw_line: &str, raw_start: usize, raw_stop: usize) -> Result<(Option<VPUMaskType>, usize), AsmError> {
827 match self.extract_vpu_bracket_arg(raw_line, raw_start, raw_stop)? {
828 (Some(mask), mask_aft) => {
829 match mask {
830 Argument::Imm(imm) => { if imm.size.is_some() { return Err(AsmError { kind: AsmErrorKind::SizeSpecNotAllowed { index: None }, line_num: self.line_num, pos: Some(raw_start), inner_err: None }); }
832 match imm.expr.to_ident() {
833 Some(ident) if ident == "z" || ident == "Z" => return Err(AsmError { kind: AsmErrorKind::VPUZeroingWithoutOpmask, line_num: self.line_num, pos: Some(soft_err_pos), inner_err: None }),
834 _ => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: ArgumentType::Imm, expected: &[ArgumentType::VPUMaskRegister] }, line_num: self.line_num, pos: Some(raw_start), inner_err: None }),
835 }
836 }
837 Argument::VPUMaskRegister(reg) => {
838 if reg.id == 0 { return Err(AsmError { kind: AsmErrorKind::VPUOpmaskWasK0, line_num: self.line_num, pos: Some(soft_err_pos), inner_err: None }); }
840
841 match self.extract_vpu_bracket_arg(raw_line, mask_aft, raw_stop)? {
842 (Some(extra), extra_aft) => match extra {
843 Argument::Imm(imm) => {
844 if imm.size.is_some() { return Err(AsmError { kind: AsmErrorKind::SizeSpecNotAllowed { index: None }, line_num: self.line_num, pos: Some(raw_start), inner_err: None }); }
845 match imm.expr.into_ident() {
846 Some(ident) if ident == "z" || ident == "Z" => Ok((Some(VPUMaskType::Zero(reg)), extra_aft)),
847 _ => return Err(AsmError { kind: AsmErrorKind::VPUMaskUnrecognizedMode, line_num: self.line_num, pos: Some(mask_aft), inner_err: None }),
848 }
849 }
850 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::Ident] }, line_num: self.line_num, pos: Some(mask_aft), inner_err: None }),
851 }
852 (None, extra_aft) => Ok((Some(VPUMaskType::Blend(reg)), extra_aft)),
853 }
854 }
855 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::VPUMaskRegister] }, line_num: self.line_num, pos: Some(raw_start), inner_err: None }),
856 }
857 }
858 (None, _) => Ok((None, raw_start))
859 }
860 }
861
862 fn extract_arg(&mut self, raw_line: &str, raw_start: usize, raw_stop: usize) -> Result<(Argument, usize), AsmError> {
866 let (token, token_aft) = grab_alnum_token(raw_line, raw_start, raw_stop);
868 if let Some(reg) = CPU_REGISTER_INFO.get(&Caseless(token)) { return Ok((Argument::CPURegister(*reg), token_aft)); }
869 if let Some(reg) = FPU_REGISTER_INFO.get(&Caseless(token)) { return Ok((Argument::FPURegister(*reg), token_aft)); }
870 if let Some(reg) = VPU_MASK_REGISTER_INFO.get(&Caseless(token)) { return Ok((Argument::VPUMaskRegister(*reg), token_aft)); }
871 if let Some(seg) = SEGMENTS.get(&Caseless(token)) { return Ok((Argument::Segment(*seg), token_aft)); }
872
873 if let Some(reg) = VPU_REGISTER_INFO.get(&Caseless(token)) {
875 let (mask, mask_aft) = self.extract_vpu_mask(token_aft - token.len(), raw_line, token_aft, raw_stop)?;
876 return Ok((Argument::VPURegister { reg: *reg, mask }, mask_aft));
877 }
878
879 match self.extract_address(raw_line, raw_start, raw_stop) {
881 Ok((addr, aft)) => {
882 let err_pos = next_nonwhite_pos(raw_line, raw_start).unwrap();
883 let (mask, mask_aft) = self.extract_vpu_mask(err_pos, raw_line, aft, raw_stop)?;
884 return Ok((Argument::Address { addr, mask }, mask_aft))
885 }
886 Err(e) => if let AsmErrorKind::BadAddress(_) = e.kind { return Err(e); } }
888
889 let (imm, aft) = self.extract_imm(raw_line, raw_start, raw_stop)?;
891 Ok((Argument::Imm(imm), aft))
892 }
893
894 pub(super) fn extract_header(&mut self, raw_line: &str) -> Result<(Option<(Option<(Prefix, usize)>, (Instruction, usize))>, usize), AsmError> {
898 self.label_def = None;
899 self.times = None;
900
901 let mut token = grab_whitespace_sep_token(raw_line, 0, raw_line.len());
903 if token.0.is_empty() { return Ok((None, 0)); }
904 if token.0.ends_with(LABEL_DEF_CHAR) { let mutated = self.mutate_name(&token.0[..token.0.len()-1], token.1 - token.0.len())?;
906 if is_reserved_symbol_name(&mutated.0) { return Err(AsmError { kind: AsmErrorKind::ReservedSymbolName, line_num: self.line_num, pos: Some(token.1 - token.0.len()), inner_err: None }); }
907 self.label_def = Some(mutated);
908
909 let new_token = grab_whitespace_sep_token(raw_line, token.1, raw_line.len());
910 if new_token.0.is_empty() { return Ok((None, token.1)); }
911 token = new_token;
912 }
913 if Caseless(token.0) == Caseless("TIMES") { let err_pos = token.1 - token.0.len();
915 let (arg, aft) = match self.extract_arg(raw_line, token.1, raw_line.len()) {
916 Err(e) => return Err(AsmError { kind: AsmErrorKind::TimesMissingCount, line_num: self.line_num, pos: e.pos, inner_err: None }),
917 Ok(x) => x,
918 };
919 let count = match arg {
920 Argument::Imm(imm) => {
921 if imm.size.is_some() { return Err(AsmError { kind: AsmErrorKind::SizeSpecNotAllowed { index: None }, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
922 match imm.expr.eval(&self.file.symbols) {
923 Err(e) => return Err(AsmError { kind: AsmErrorKind::FailedCriticalExpression(e), line_num: self.line_num, pos: Some(err_pos), inner_err: None }),
924 Ok(val) => match &*val {
925 Value::Integer(v) => {
926 if v.cmp0() == Ordering::Less { return Err(AsmError { kind: AsmErrorKind::TimesCountWasNegative, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
927 match v.to_u64() {
928 None => return Err(AsmError { kind: AsmErrorKind::TimesCountTooLarge, line_num: self.line_num, pos: Some(err_pos), inner_err: None }),
929 Some(v) => v,
930 }
931 }
932 x => return Err(AsmError { kind: AsmErrorKind::ValueInvalidType { index: None, got: x.get_type(), expected: &[ValueType::Integer] }, line_num: self.line_num, pos: Some(err_pos), inner_err: None }),
933 }
934 }
935 }
936 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::Imm] }, line_num: self.line_num, pos: Some(err_pos), inner_err: None }),
937 };
938 self.times = Some(TimesInfo { total_count: count, current: 0 });
939
940 token = grab_whitespace_sep_token(raw_line, aft, raw_line.len());
941 if token.0.is_empty() { return Err(AsmError { kind: AsmErrorKind::TimesUsedOnEmptyLine, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
942 }
943 else if Caseless(token.0) == Caseless("IF") { let err_pos = token.1 - token.0.len();
945 let (arg, aft) = match self.extract_arg(raw_line, token.1, raw_line.len()) {
946 Err(e) => return Err(AsmError { kind: AsmErrorKind::IfMissingExpr, line_num: self.line_num, pos: e.pos, inner_err: None }),
947 Ok(x) => x,
948 };
949 let cond = match arg {
950 Argument::Imm(imm) => {
951 if imm.size.is_some() { return Err(AsmError { kind: AsmErrorKind::SizeSpecNotAllowed { index: None }, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
952 match imm.expr.eval(&self.file.symbols) {
953 Err(e) => return Err(AsmError { kind: AsmErrorKind::FailedCriticalExpression(e), line_num: self.line_num, pos: Some(err_pos), inner_err: None }),
954 Ok(val) => match &*val {
955 Value::Logical(v) => *v,
956 x => return Err(AsmError { kind: AsmErrorKind::ValueInvalidType { index: None, got: x.get_type(), expected: &[ValueType::Logical] }, line_num: self.line_num, pos: Some(err_pos), inner_err: None }),
957 }
958 }
959 }
960 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::Imm] }, line_num: self.line_num, pos: Some(err_pos), inner_err: None }),
961 };
962 self.times = Some(TimesInfo { total_count: if cond { 1 } else { 0 }, current: 0 });
963
964 token = grab_whitespace_sep_token(raw_line, aft, raw_line.len());
965 if token.0.is_empty() { return Err(AsmError { kind: AsmErrorKind::IfUsedOnEmptyLine, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
966 }
967
968 let prefix = match PREFIXES.get(&Caseless(token.0)) {
970 None => None,
971 Some(prefix) => {
972 let err_pos = token.1 - token.0.len();
973 token = grab_whitespace_sep_token(raw_line, token.1, raw_line.len());
974 if token.0.is_empty() { return Err(AsmError { kind: AsmErrorKind::PrefixWithoutInstruction, line_num: self.line_num, pos: Some(err_pos), inner_err: None }); }
975 Some((*prefix, err_pos))
976 }
977 };
978
979 let ins_pos = token.1 - token.0.len();
981 match INSTRUCTIONS.get(&Caseless(token.0)) {
982 None => return Err(AsmError { kind: AsmErrorKind::UnrecognizedInstruction, line_num: self.line_num, pos: Some(ins_pos), inner_err: None }),
983 Some(ins) => Ok((Some((prefix, (*ins, ins_pos))), token.1)),
984 }
985 }
986 pub(super) fn extract_arguments(&mut self, raw_line: &str, raw_start: usize) -> Result<Vec<Argument>, AsmError> {
987 let mut args = vec![];
988
989 let (tail, mut pos) = trim_start_with_pos(raw_line, raw_start, raw_line.len());
991 if !tail.is_empty() { loop { let (arg, aft) = self.extract_arg(raw_line, pos, raw_line.len())?;
994 args.push(arg);
995
996 let (tail, tail_pos) = trim_start_with_pos(raw_line, aft, raw_line.len());
997 if tail.chars().next() != Some(',') { pos = aft;
999 break;
1000 }
1001 pos = tail_pos + 1;
1002 }
1003
1004 let (tail, tail_pos) = trim_start_with_pos(raw_line, pos, raw_line.len());
1006 if !tail.is_empty() { return Err(AsmError { kind: AsmErrorKind::ExtraContentAfterArgs, line_num: self.line_num, pos: Some(tail_pos), inner_err: None }); }
1007 }
1008
1009 Ok(args)
1010 }
1011
1012 pub(super) fn get_current_segment_for_writing(&mut self) -> Result<(&mut Vec<u8>, &dyn SymbolTableCore, &mut Vec<Hole>), AsmError> {
1015 Ok(match self.current_seg {
1016 None => return Err(AsmError { kind: AsmErrorKind::WriteOutsideOfSegment, line_num: self.line_num, pos: None, inner_err: None }),
1017 Some(seg) => match seg {
1018 AsmSegment::Text => (&mut self.file.text, &self.file.symbols, &mut self.file.text_holes),
1019 AsmSegment::Rodata => (&mut self.file.rodata, &self.file.symbols, &mut self.file.rodata_holes),
1020 AsmSegment::Data => (&mut self.file.data, &self.file.symbols, &mut self.file.data_holes),
1021 AsmSegment::Bss => return Err(AsmError { kind: AsmErrorKind::WriteInBssSegment, line_num: self.line_num, pos: None, inner_err: None }),
1022 }
1023 })
1024 }
1025 pub(super) fn append_byte(&mut self, val: u8) -> Result<(), AsmError> {
1027 let (seg, _, _) = self.get_current_segment_for_writing()?;
1028 seg.push(val);
1029 Ok(())
1030 }
1031 pub(super) fn append_val(&mut self, size: Size, expr: Expr, allowed_type: HoleType) -> Result<(), AsmError> {
1034 let line_num = self.line_num;
1035 let (seg, symbols, holes) = self.get_current_segment_for_writing()?;
1036 let hole = Hole { address: seg.len(),
1038 size, expr, allowed_type, line_num,
1039 };
1040 seg.extend(iter::once(0xffu8).cycle().take(size.size())); match patch_hole(seg, &hole, symbols) {
1042 Ok(_) => (), Err(e) => match e.kind {
1044 PatchErrorKind::Illegal(r) => return Err(AsmError { kind: AsmErrorKind::IllegalPatch(r), line_num: e.line_num, pos: None, inner_err: None }), PatchErrorKind::NotPatched(_) => holes.push(hole), }
1047 }
1048 Ok(())
1049 }
1050 pub(super) fn append_address(&mut self, addr: Address) -> Result<(), AsmError> {
1052 let a = (if addr.base.is_some() { 0x80 } else { 0 }) | (addr.r1.unwrap_or((0, 0)).1 << 4) | (addr.address_size.basic_sizecode().unwrap() << 2) | (if addr.r1.is_some() { 2 } else { 0 }) | (if addr.r2.is_some() { 1 } else { 0 });
1053 let b = (addr.r1.unwrap_or((0, 0)).0 << 4) | addr.r2.unwrap_or(0);
1054
1055 self.append_byte(a)?;
1056 if a & 3 != 0 { self.append_byte(b)?; }
1057 if a & 0x80 != 0 { self.append_val(addr.address_size, addr.base.unwrap(), HoleType::Integer)? }
1058 Ok(())
1059 }
1060
1061 pub(super) fn process_no_arg_op(&mut self, args: Vec<Argument>, op: Option<u8>, ext_op: Option<u8>) -> Result<(), AsmError> {
1064 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1065 if args.len() != 0 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[0]), line_num: self.line_num, pos: None, inner_err: None }); }
1066 if let Some(ext) = op { self.append_byte(ext)? }
1067 if let Some(ext) = ext_op { self.append_byte(ext)? }
1068 Ok(())
1069 }
1070 pub(super) fn process_ternary_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, allowed_type: HoleType, allowed_sizes: &'static [Size], force_b_rm_size: Option<Size>, force_b_imm_size: Option<Size>) -> Result<(), AsmError> {
1071 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1072 if args.len() != 3 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[3]), line_num: self.line_num, pos: None, inner_err: None }); }
1073 let mut args = args.into_iter();
1074 let arg1 = args.next().unwrap();
1075 let mut arg2 = args.next().unwrap();
1076 let arg3 = args.next().unwrap();
1077
1078 self.append_byte(op)?;
1079 if let Some(ext) = ext_op { self.append_byte(ext)?; }
1080
1081 let supported_types = slice_slice!(ArgumentType:
1082 [CPURegister, CPURegister, CPURegister],
1083 [CPURegister, CPURegister, Imm],
1084 [CPURegister, CPURegister, Address],
1085 [CPURegister, Address, CPURegister],
1086 [CPURegister, Address, Imm],
1087 );
1088
1089 let r1 = match arg1 {
1090 Argument::CPURegister(r) => r,
1091 _ => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![arg1.get_type(), arg2.get_type(), arg3.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1092 };
1093 let pseudo_op = (r1.id << 4) | (if r1.high { 1 } else { 0 });
1094
1095 let mismatched_sizes = match (&mut arg2, &arg3) {
1096 (Argument::CPURegister(reg), Argument::CPURegister(_)) | (Argument::CPURegister(reg), Argument::Imm(_)) | (Argument::CPURegister(reg), Argument::Address { .. }) => {
1097 if reg.size != r1.size { Some((reg.size, r1.size)) } else { None }
1098 }
1099 (Argument::Address { addr, .. }, Argument::CPURegister(_)) | (Argument::Address { addr, .. }, Argument::Imm(_)) => match addr.pointed_size {
1100 Some(size) => if size != r1.size { Some((size, r1.size)) } else { None },
1101 None => { addr.pointed_size = Some(r1.size); None }, }
1103 _ => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![arg1.get_type(), arg2.get_type(), arg3.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1104 };
1105 if let Some((s1, s2)) = mismatched_sizes { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(s1, s2), line_num: self.line_num, pos: None, inner_err: None }); }
1106
1107 self.process_binary_op(vec![arg2, arg3], pseudo_op, None, allowed_type, allowed_sizes, force_b_rm_size, force_b_imm_size)
1109 }
1110 pub(super) fn process_binary_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, allowed_type: HoleType, allowed_sizes: &'static [Size], force_b_rm_size: Option<Size>, force_b_imm_size: Option<Size>) -> Result<(), AsmError> {
1113 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1114 if args.len() != 2 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[2]), line_num: self.line_num, pos: None, inner_err: None }); }
1115 let mut args = args.into_iter();
1116 let arg1 = args.next().unwrap();
1117 let arg2 = args.next().unwrap();
1118
1119 self.append_byte(op)?;
1120 if let Some(ext) = ext_op { self.append_byte(ext)?; }
1121
1122 let supported_types = slice_slice!(ArgumentType:
1123 [CPURegister, CPURegister],
1124 [CPURegister, Address],
1125 [CPURegister, Imm],
1126 [Address, CPURegister],
1127 [Address, Imm],
1128 );
1129
1130 match (arg1, arg2) {
1131 (Argument::CPURegister(dest), Argument::CPURegister(src)) => {
1132 match force_b_rm_size {
1133 Some(b_size) => if src.size != b_size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: src.size, expected: vec![b_size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1134 None => if src.size != dest.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(src.size, dest.size), line_num: self.line_num, pos: None, inner_err: None }); }
1135 }
1136 if !allowed_sizes.contains(&dest.size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: dest.size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1137 self.append_byte((dest.id << 4) | (dest.size.basic_sizecode().unwrap() << 2) | (if dest.high { 2 } else { 0 }) | (if src.high { 1 } else { 0 }))?;
1138 self.append_byte(src.id)?;
1139 }
1140 (Argument::CPURegister(dest), Argument::Address { addr: src, mask }) => {
1141 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1142 if let Some(src_size) = src.pointed_size {
1143 match force_b_rm_size {
1144 Some(b_size) => if src_size != b_size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: src_size, expected: vec![b_size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1145 None => if src_size != dest.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(src_size, dest.size), line_num: self.line_num, pos: None, inner_err: None }); }
1146 }
1147 }
1148 if !allowed_sizes.contains(&dest.size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: dest.size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1149 self.append_byte((dest.id << 4) | (dest.size.basic_sizecode().unwrap() << 2) | (if dest.high { 2 } else { 0 }))?;
1150 self.append_byte(2 << 4)?;
1151 self.append_address(src)?;
1152 }
1153 (Argument::CPURegister(dest), Argument::Imm(mut src)) => {
1154 match (force_b_imm_size, src.size) {
1155 (Some(b_size), Some(src_size)) => if src_size != b_size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: src_size, expected: vec![b_size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1156 (Some(b_size), None) => src.size = Some(b_size),
1157 (None, Some(src_size)) => if src_size != dest.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(src_size, dest.size), line_num: self.line_num, pos: None, inner_err: None }); },
1158 (None, None) => src.size = Some(dest.size),
1159 }
1160 if !allowed_sizes.contains(&dest.size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: dest.size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1161 self.append_byte((dest.id << 4) | (dest.size.basic_sizecode().unwrap() << 2) | (if dest.high { 2 } else { 0 }))?;
1162 self.append_byte(1 << 4)?;
1163 self.append_val(src.size.unwrap(), src.expr, allowed_type)?;
1164 }
1165 (Argument::Address { addr: dest, mask }, Argument::CPURegister(src)) => {
1166 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1167 let a_size = match force_b_rm_size {
1168 Some(b_size) => {
1169 if src.size != b_size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: src.size, expected: vec![b_size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1170 match dest.pointed_size {
1171 None => { return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }); }
1172 Some(a_size) => a_size,
1173 }
1174 }
1175 None => {
1176 if let Some(a_size) = dest.pointed_size {
1177 if a_size != src.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(a_size, src.size), line_num: self.line_num, pos: None, inner_err: None }); }
1178 }
1179 src.size
1180 }
1181 };
1182 if !allowed_sizes.contains(&a_size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: a_size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1183 self.append_byte((a_size.basic_sizecode().unwrap() << 2) | (if src.high { 1 } else { 0 }))?;
1184 self.append_byte((3 << 4) | src.id)?;
1185 self.append_address(dest)?;
1186 }
1187 (Argument::Address { addr: dest, mask }, Argument::Imm(mut src)) => {
1188 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1189 let a_size = match force_b_imm_size {
1190 Some(b_size) => {
1191 match src.size {
1192 Some(size) => if size != b_size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: size, expected: vec![b_size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1193 None => src.size = Some(b_size),
1194 }
1195 match dest.pointed_size {
1196 None => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1197 Some(size) => size,
1198 }
1199 }
1200 None => match (dest.pointed_size, src.size) {
1201 (Some(a), Some(b)) => {
1202 if a != b { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(a, b), line_num: self.line_num, pos: None, inner_err: None }); }
1203 a
1204 }
1205 (None, Some(b)) => b,
1206 (Some(a), None) => { src.size = Some(a); a },
1207 (None, None) => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1208 }
1209 };
1210 if !allowed_sizes.contains(&a_size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: a_size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1211 self.append_byte(a_size.basic_sizecode().unwrap() << 2)?;
1212 self.append_byte(4 << 4)?;
1213 self.append_address(dest)?;
1214 self.append_val(src.size.unwrap(), src.expr, allowed_type)?;
1215 }
1216 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![a.get_type(), b.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1217 }
1218
1219 Ok(())
1220 }
1221 pub (super) fn process_mov_ext_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, signed: bool) -> Result<(), AsmError> {
1233 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1234 if args.len() != 2 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[2]), line_num: self.line_num, pos: None, inner_err: None }); }
1235 let mut args = args.into_iter();
1236 let arg1 = args.next().unwrap();
1237 let arg2 = args.next().unwrap();
1238
1239 self.append_byte(op)?;
1240 if let Some(ext) = ext_op { self.append_byte(ext)?; }
1241
1242 let supported_types = slice_slice!(ArgumentType:
1243 [CPURegister, CPURegister],
1244 [CPURegister, Address],
1245 );
1246 let supported_sizes = slice_slice!(Size:
1247 [Word, Byte],
1248 [Dword, Byte],
1249 [Qword, Byte],
1250 [Dword, Word],
1251 [Qword, Word],
1252 [Qword, Dword],
1253 );
1254 let get_mode = |dest_size: Size, src_size: Size, args: &AssembleArgs| -> Result<u8, AsmError> {
1255 Ok(match (dest_size, src_size) {
1256 (Size::Word, Size::Byte) => 0,
1257 (Size::Dword, Size::Byte) => 1,
1258 (Size::Qword, Size::Byte) => 2,
1259 (Size::Dword, Size::Word) => 3,
1260 (Size::Qword, Size::Word) => 4,
1261 (Size::Qword, Size::Dword) => 5,
1262 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidSizes { got: vec![a, b], expected: supported_sizes }, line_num: args.line_num, pos: None, inner_err: None }),
1263 })
1264 };
1265
1266 match (arg1, arg2) {
1267 (Argument::CPURegister(dest), Argument::CPURegister(src)) => {
1268 let mode = get_mode(dest.size, src.size, self)?;
1269
1270 self.append_byte((if signed { 0x80 } else { 0 }) | (if src.high { 0x40 } else { 0 }) | mode)?;
1271 self.append_byte((dest.id << 4) | src.id)?;
1272 }
1273 (Argument::CPURegister(dest), Argument::Address { addr: src, mask }) => {
1274 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1275 let mode = match src.pointed_size {
1276 None => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1277 Some(src_size) => get_mode(dest.size, src_size, self)?,
1278 };
1279
1280 self.append_byte((if signed { 0x80 } else { 0 }) | 0x20 | mode)?;
1281 self.append_byte(dest.id << 4)?;
1282 self.append_address(src)?;
1283 }
1284 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![a.get_type(), b.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1285 }
1286
1287 Ok(())
1288 }
1289 pub(super) fn process_binary_lvalue_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, allowed_sizes: &'static [Size]) -> Result<(), AsmError> {
1290 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1291 if args.len() != 2 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[2]), line_num: self.line_num, pos: None, inner_err: None }); }
1292 let mut args = args.into_iter();
1293 let arg1 = args.next().unwrap();
1294 let arg2 = args.next().unwrap();
1295
1296 self.append_byte(op)?;
1297 if let Some(ext) = ext_op { self.append_byte(ext)?; }
1298
1299 let supported_types = slice_slice!(ArgumentType:
1300 [CPURegister, CPURegister],
1301 [CPURegister, Address],
1302 );
1303
1304 match (arg1, arg2) {
1305 (Argument::CPURegister(dest), Argument::CPURegister(src)) => {
1306 if dest.size != src.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(dest.size, src.size), line_num: self.line_num, pos: None, inner_err: None }); }
1307 if !allowed_sizes.contains(&dest.size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: dest.size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1308 self.append_byte((dest.id << 4) | (dest.size.basic_sizecode().unwrap() << 2) | (if dest.high { 2 } else { 0 }) | 0)?;
1309 self.append_byte((if src.high { 0x80 } else { 0 }) | src.id)?;
1310 }
1311 (Argument::CPURegister(dest), Argument::Address { addr: src, mask }) => {
1312 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1313 if let Some(size) = src.pointed_size {
1314 if dest.size != size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(dest.size, size), line_num: self.line_num, pos: None, inner_err: None }); }
1315 }
1316 if !allowed_sizes.contains(&dest.size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: dest.size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1317 self.append_byte((dest.id << 4) | (dest.size.basic_sizecode().unwrap() << 2) | (if dest.high { 2 } else { 0 }) | 1)?;
1318 self.append_address(src)?;
1319 }
1320 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![a.get_type(), b.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1321 }
1322
1323 Ok(())
1324 }
1325 pub(super) fn process_binary_lvalue_unordered_op(&mut self, mut args: Vec<Argument>, op: u8, ext_op: Option<u8>, allowed_sizes: &'static [Size]) -> Result<(), AsmError> {
1326 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1327 if args.len() != 2 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[2]), line_num: self.line_num, pos: None, inner_err: None }); }
1328
1329 let supported_types = slice_slice!(ArgumentType:
1330 [CPURegister, CPURegister],
1331 [CPURegister, Address],
1332 [Address, CPURegister],
1333 );
1334
1335 match (&args[0], &args[1]) {
1336 (Argument::CPURegister(_), Argument::CPURegister(_)) => (),
1337 (Argument::CPURegister(_), Argument::Address { .. }) => (),
1338 (Argument::Address { .. }, Argument::CPURegister(_)) => args.swap(0, 1),
1339 _ => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![args[0].get_type(), args[1].get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1340 }
1341 self.process_binary_lvalue_op(args, op, ext_op, allowed_sizes)
1342 }
1343 pub(super) fn process_unary_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, allowed_sizes: &'static [Size]) -> Result<(), AsmError> {
1344 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1345 if args.len() != 1 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[1]), line_num: self.line_num, pos: None, inner_err: None }); }
1346
1347 self.append_byte(op)?;
1348 if let Some(ext) = ext_op { self.append_byte(ext)?; }
1349
1350 match args.into_iter().next().unwrap() {
1351 Argument::CPURegister(reg) => {
1352 if !allowed_sizes.contains(®.size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: reg.size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1353 self.append_byte((reg.id << 4) | (reg.size.basic_sizecode().unwrap() << 2) | (if reg.high { 2 } else { 0 }))?;
1354 }
1355 Argument::Address { addr, mask } => {
1356 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1357 let size = match addr.pointed_size {
1358 None => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1359 Some(s) => s,
1360 };
1361 if !allowed_sizes.contains(&size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1362 self.append_byte((size.basic_sizecode().unwrap() << 2) | 1)?;
1363 self.append_address(addr)?;
1364 }
1365 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::CPURegister, ArgumentType::Address] }, line_num: self.line_num, pos: None, inner_err: None }),
1366 }
1367
1368 Ok(())
1369 }
1370 pub(super) fn process_value_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, allowed_type: HoleType, allowed_sizes: &'static [Size], default_size: Option<Size>) -> Result<(), AsmError> {
1371 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1372 if args.len() != 1 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[1]), line_num: self.line_num, pos: None, inner_err: None }); }
1373
1374 self.append_byte(op)?;
1375 if let Some(ext) = ext_op { self.append_byte(ext)?; }
1376
1377 match args.into_iter().next().unwrap() {
1378 Argument::CPURegister(reg) => {
1379 if !allowed_sizes.contains(®.size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: reg.size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1380 self.append_byte((reg.id << 4) | (reg.size.basic_sizecode().unwrap() << 2) | (if reg.high { 1 } else { 0 }))?;
1381 }
1382 Argument::Imm(imm) => {
1383 let size = match imm.size.or(default_size) {
1384 None => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1385 Some(s) => s,
1386 };
1387 if !allowed_sizes.contains(&size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1388 self.append_byte((size.basic_sizecode().unwrap() << 2) | 2)?;
1389 self.append_val(size, imm.expr, allowed_type)?;
1390 }
1391 Argument::Address { addr, mask } => {
1392 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1393 let size = match addr.pointed_size.or(default_size) {
1394 None => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1395 Some(s) => s,
1396 };
1397 if !allowed_sizes.contains(&size) { return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: size, expected: allowed_sizes }, line_num: self.line_num, pos: None, inner_err: None }); }
1398 self.append_byte((size.basic_sizecode().unwrap() << 2) | 3)?;
1399 self.append_address(addr)?;
1400 }
1401 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::CPURegister, ArgumentType::Imm, ArgumentType::Address] }, line_num: self.line_num, pos: None, inner_err: None }),
1402 }
1403
1404 Ok(())
1405 }
1406
1407 pub(super) fn process_fpu_value_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, integral: bool) -> Result<(), AsmError> {
1408 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1409 if args.len() != 1 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[1]), line_num: self.line_num, pos: None, inner_err: None }); }
1410
1411 self.append_byte(op)?;
1412 if let Some(ext) = ext_op { self.append_byte(ext)?; }
1413
1414 match args.into_iter().next().unwrap() {
1415 Argument::FPURegister(src) => self.append_byte((src.id << 4) | 0)?,
1416 Argument::Address { addr, mask } => {
1417 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1418 let size = match addr.pointed_size {
1419 None => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1420 Some(s) => s,
1421 };
1422 let mode = match (integral, size) {
1423 (false, Size::Dword) => 1,
1424 (false, Size::Qword) => 2,
1425 (false, Size::Tword) => 3,
1426 (false, _) => return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: size, expected: &[Size::Dword, Size::Qword, Size::Tword] }, line_num: self.line_num, pos: None, inner_err: None }),
1427 (true, Size::Word) => 4,
1428 (true, Size::Dword) => 5,
1429 (true, Size::Qword) => 6,
1430 (true, _) => return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: size, expected: &[Size::Word, Size::Dword, Size::Qword] }, line_num: self.line_num, pos: None, inner_err: None }),
1431 };
1432 self.append_byte(mode)?;
1433 self.append_address(addr)?;
1434 }
1435 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::FPURegister, ArgumentType::Address] }, line_num: self.line_num, pos: None, inner_err: None }),
1436 }
1437
1438 Ok(())
1439 }
1440 pub(super) fn process_fpu_binary_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, integral: bool, pop: bool) -> Result<(), AsmError> {
1441 if self.current_seg != Some(AsmSegment::Text) { return Err(AsmError { kind: AsmErrorKind::InstructionOutsideOfTextSegment, line_num: self.line_num, pos: None, inner_err: None }); }
1442
1443 self.append_byte(op)?;
1444 if let Some(ext) = ext_op { self.append_byte(ext)?; }
1445
1446 if integral && pop { panic!() }
1447 else if integral {
1448 if args.len() != 1 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[1]), line_num: self.line_num, pos: None, inner_err: None }); }
1449 match args.into_iter().next().unwrap() {
1450 Argument::Address { addr, mask } => {
1451 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1452 let mode = match addr.pointed_size {
1453 None => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1454 Some(size) => match size {
1455 Size::Word => 6,
1456 Size::Dword => 7,
1457 Size::Qword => 8,
1458 _ => return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: size, expected: &[Size::Word, Size::Dword, Size::Qword] }, line_num: self.line_num, pos: None, inner_err: None }),
1459 }
1460 };
1461 self.append_byte(mode)?;
1462 self.append_address(addr)?;
1463 }
1464 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::Address] }, line_num: self.line_num, pos: None, inner_err: None }),
1465 }
1466 }
1467 else if pop {
1468 match args.len() {
1469 0 => self.append_byte((1 << 4) | 2)?,
1470 2 => {
1471 let mut args = args.into_iter();
1472 let a = args.next().unwrap();
1473 let b = args.next().unwrap();
1474
1475 let supported_types = slice_slice!(ArgumentType:
1476 [FPURegister, FPURegister],
1477 );
1478
1479 match (a, b) {
1480 (Argument::FPURegister(a), Argument::FPURegister(b)) => {
1481 if b.id != 0 { return Err(AsmError { kind: AsmErrorKind::FPUBinaryOpPop2SrcNotST0, line_num: self.line_num, pos: None, inner_err: None }); }
1482 self.append_byte((a.id << 4) | 2)?;
1483 }
1484 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![a.get_type(), b.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1485 }
1486 }
1487 _ => return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[0, 2]), line_num: self.line_num, pos: None, inner_err: None }),
1488 }
1489 }
1490 else {
1491 match args.len() {
1492 1 => match args.into_iter().next().unwrap() {
1493 Argument::Address { addr, mask } => {
1494 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1495 let mode = match addr.pointed_size {
1496 None => return Err(AsmError { kind: AsmErrorKind::CouldNotDeduceOperandSize, line_num: self.line_num, pos: None, inner_err: None }),
1497 Some(size) => match size {
1498 Size::Dword => 3,
1499 Size::Qword => 4,
1500 Size::Tword => 5,
1501 _ => return Err(AsmError { kind: AsmErrorKind::UnsupportedOperandSize { got: size, expected: &[Size::Dword, Size::Qword, Size::Tword] }, line_num: self.line_num, pos: None, inner_err: None }),
1502 }
1503 };
1504 self.append_byte(mode)?;
1505 self.append_address(addr)?;
1506 }
1507 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: None, got: x.get_type(), expected: &[ArgumentType::Address] }, line_num: self.line_num, pos: None, inner_err: None }),
1508 },
1509 2 => {
1510 let mut args = args.into_iter();
1511 let a = args.next().unwrap();
1512 let b = args.next().unwrap();
1513
1514 let supported_types = slice_slice!(ArgumentType:
1515 [FPURegister, FPURegister]
1516 );
1517
1518 match (a, b) {
1519 (Argument::FPURegister(a), Argument::FPURegister(b)) => {
1520 if a.id == 0 { self.append_byte((b.id << 4) | 0)?; }
1521 else if b.id == 0 { self.append_byte((a.id << 4) | 1)?; }
1522 else { return Err(AsmError { kind: AsmErrorKind::FPUBinaryOpNeitherST0, line_num: self.line_num, pos: None, inner_err: None }); }
1523 }
1524 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![a.get_type(), b.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1525 }
1526 }
1527 _ => return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[1, 2]), line_num: self.line_num, pos: None, inner_err: None }),
1528 }
1529 }
1530
1531 Ok(())
1532 }
1533
1534 fn decompose_opmask(&self, opmask: Option<VPUMaskType>) -> Result<(u8, bool), AsmError> {
1536 Ok(match opmask {
1537 Some(VPUMaskType::Blend(r)) if r.id != 0 => (r.id, false),
1538 Some(VPUMaskType::Zero(r)) if r.id != 0 => (r.id, true),
1539 Some(_) => return Err(AsmError { kind: AsmErrorKind::VPUOpmaskWasK0, line_num: self.line_num, pos: None, inner_err: None }),
1540 None => (0, false),
1541 })
1542 }
1543
1544 pub(crate) fn process_vpu_move(&mut self, args: Vec<Argument>, elem_size: Option<Size>, packed: bool, aligned: bool, special_transfer: bool) -> Result<(), AsmError> {
1545 debug_assert!(packed || elem_size.is_some()); debug_assert!(packed || !aligned); debug_assert!(!special_transfer || !packed); let ext_op_base = (if !packed { 44 } else if aligned { 20 } else { 32 }) + elem_size.unwrap_or(Size::Qword).basic_sizecode().unwrap();
1549
1550 if args.len() != 2 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[2]), line_num: self.line_num, pos: None, inner_err: None }); }
1551 let mut args = args.into_iter();
1552 let arg1 = args.next().unwrap();
1553 let arg2 = args.next().unwrap();
1554
1555 self.append_byte(OPCode::TRANS as u8)?;
1556
1557 if !special_transfer {
1558 let supported_types = slice_slice!(ArgumentType:
1559 [VPURegister, Address],
1560 [Address, VPURegister],
1561 [VPURegister, VPURegister],
1562 );
1563
1564 match (arg1, arg2) {
1565 (Argument::VPURegister { reg, mask }, Argument::Address { addr, mask: src_mask }) => {
1566 if src_mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNondestArg, line_num: self.line_num, pos: None, inner_err: None }); }
1567 if let Some(size) = addr.pointed_size {
1568 if packed && size != reg.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(reg.size, size), line_num: self.line_num, pos: None, inner_err: None }); }
1569 if !packed && size != elem_size.unwrap() { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: size, expected: vec![elem_size.unwrap()] }, line_num: self.line_num, pos: None, inner_err: None }); }
1570 }
1571 if elem_size.is_none() && mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnInstructionWithoutElemSize, line_num: self.line_num, pos: None, inner_err: None }); }
1572 let (mask_reg, zeroing) = self.decompose_opmask(mask)?;
1573
1574 self.append_byte(ext_op_base + 0)?;
1575 self.append_byte((mask_reg << 5) | reg.id)?;
1576 self.append_byte((if zeroing { 0x80 } else { 0 }) | (reg.size.vector_sizecode().unwrap() << 5))?;
1577 self.append_address(addr)?;
1578 }
1579 (Argument::Address { addr, mask }, Argument::VPURegister { reg, mask: src_mask }) => {
1580 if src_mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNondestArg, line_num: self.line_num, pos: None, inner_err: None }); }
1581 if let Some(size) = addr.pointed_size {
1582 if packed && size != reg.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(size, reg.size), line_num: self.line_num, pos: None, inner_err: None }); }
1583 if !packed && size != elem_size.unwrap() { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: size, expected: vec![elem_size.unwrap()] }, line_num: self.line_num, pos: None, inner_err: None }); }
1584 }
1585 if elem_size.is_none() && mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnInstructionWithoutElemSize, line_num: self.line_num, pos: None, inner_err: None }); }
1586 let (mask_reg, zeroing) = self.decompose_opmask(mask)?;
1587
1588 self.append_byte(ext_op_base + 4)?;
1589 self.append_byte(mask_reg << 5)?;
1590 self.append_byte((if zeroing { 0x80 } else { 0 }) | (reg.size.vector_sizecode().unwrap() << 5) | reg.id)?;
1591 self.append_address(addr)?;
1592 }
1593 (Argument::VPURegister { reg: dest_reg, mask }, Argument::VPURegister { reg: src_reg, mask: src_mask }) => {
1594 if src_mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNondestArg, line_num: self.line_num, pos: None, inner_err: None }); }
1595 if dest_reg.size != src_reg.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(dest_reg.size, src_reg.size), line_num: self.line_num, pos: None, inner_err: None }); }
1596 if elem_size.is_none() && mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnInstructionWithoutElemSize, line_num: self.line_num, pos: None, inner_err: None }); }
1597 let (mask_reg, zeroing) = self.decompose_opmask(mask)?;
1598
1599 self.append_byte(ext_op_base + 8)?;
1600 self.append_byte((mask_reg << 5) | dest_reg.id)?;
1601 self.append_byte((if zeroing { 0x80 } else { 0 }) | (dest_reg.size.vector_sizecode().unwrap() << 5) | src_reg.id)?;
1602 }
1603 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![a.get_type(), b.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1604 }
1605 } else { let supported_types = slice_slice!(ArgumentType:
1607 [CPURegister, VPURegister],
1608 [VPURegister, CPURegister],
1609 [VPURegister, Address],
1610 [Address, VPURegister],
1611 );
1612
1613 let cpu_trans = |args: &mut AssembleArgs, op: u8, vreg_idx: usize, reg_idx: usize, vreg: VPURegisterInfo, reg: CPURegisterInfo, mask: Option<VPUMaskType>| -> Result<(), AsmError> {
1614 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: args.line_num, pos: None, inner_err: None }) }
1615 if reg.size != elem_size.unwrap() { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(reg_idx), got: reg.size, expected: vec![elem_size.unwrap()] }, line_num: args.line_num, pos: None, inner_err: None }) }
1616 if vreg.size != Size::Xword { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(vreg_idx), got: vreg.size, expected: vec![Size::Xword] }, line_num: args.line_num, pos: None, inner_err: None }) }
1617
1618 args.append_byte(op)?;
1619 args.append_byte((reg.size.basic_sizecode().unwrap() << 6) | vreg.id)?;
1620 args.append_byte((if reg.high { 0x80 } else { 0 }) | reg.id)
1621 };
1622 let mem_trans = |args: &mut AssembleArgs, op: u8, vreg_idx: usize, addr_idx: usize, vreg: VPURegisterInfo, addr: Address, masks: &[Option<VPUMaskType>]| -> Result<(), AsmError> {
1623 if masks.iter().any(|s| s.is_some()) { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: args.line_num, pos: None, inner_err: None }) }
1624 if let Some(size) = addr.pointed_size {
1625 if size != elem_size.unwrap() { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(addr_idx), got: size, expected: vec![elem_size.unwrap()] }, line_num: args.line_num, pos: None, inner_err: None }) }
1626 }
1627 if vreg.size != Size::Xword { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(vreg_idx), got: vreg.size, expected: vec![Size::Xword] }, line_num: args.line_num, pos: None, inner_err: None }) }
1628
1629 args.append_byte(op)?;
1630 args.append_byte((elem_size.unwrap().basic_sizecode().unwrap() << 6) | vreg.id)?;
1631 args.append_address(addr)
1632 };
1633
1634 match (arg1, arg2) {
1635 (Argument::VPURegister { reg: vreg, mask }, Argument::CPURegister(reg)) => cpu_trans(self, 56, 0, 1, vreg, reg, mask)?,
1636 (Argument::CPURegister(reg), Argument::VPURegister { reg: vreg, mask }) => cpu_trans(self, 57, 1, 0, vreg, reg, mask)?,
1637 (Argument::VPURegister { reg: vreg, mask: mask1 }, Argument::Address { addr, mask: mask2 }) => mem_trans(self, 58, 0, 1, vreg, addr, &[mask1, mask2])?,
1638 (Argument::Address { addr, mask: mask2 }, Argument::VPURegister { reg: vreg, mask: mask1 }) => mem_trans(self, 59, 1, 0, vreg, addr, &[mask1, mask2])?,
1639 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![a.get_type(), b.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1640 }
1641 }
1642
1643 Ok(())
1644 }
1645
1646 pub(crate) fn process_vpu_binary_op(&mut self, args: Vec<Argument>, op: u8, ext_op: Option<u8>, elem_size: Size, packed: bool) -> Result<(), AsmError> {
1647 if args.len() != 2 && args.len() != 3 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[2, 3]), line_num: self.line_num, pos: None, inner_err: None }); }
1648
1649 let shorthand = args.len() == 2;
1650 let mut args = args.into_iter();
1651 let (dest, mask_reg, zeroing) = match args.next().unwrap() {
1652 Argument::VPURegister { reg, mask } => self.decompose_opmask(mask).map(|r| (reg, r.0, r.1))?,
1653 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: Some(0), got: x.get_type(), expected: &[ArgumentType::VPURegister] }, line_num: self.line_num, pos: None, inner_err: None }),
1654 };
1655 let src1 = if shorthand { dest } else {
1656 match args.next().unwrap() {
1657 Argument::VPURegister { reg, mask } => {
1658 if reg.size != dest.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(dest.size, reg.size), line_num: self.line_num, pos: None, inner_err: None }); }
1659 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNondestArg, line_num: self.line_num, pos: None, inner_err: None }); }
1660 reg
1661 }
1662 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: Some(1), got: x.get_type(), expected: &[ArgumentType::VPURegister] }, line_num: self.line_num, pos: None, inner_err: None }),
1663 }
1664 };
1665 self.append_byte(op)?;
1667 if let Some(ext) = ext_op { self.append_byte(ext)? }
1668
1669 self.append_byte((mask_reg << 5) | dest.id)?;
1670 self.append_byte((if zeroing { 0x80 } else { 0 }) | (if packed { dest.size.vector_sizecode().unwrap() } else { 3 } << 5) | src1.id)?;
1671
1672 let last_index = Some(if shorthand { 1 } else { 2 });
1673 match args.next().unwrap() {
1674 Argument::VPURegister { reg, mask } => {
1675 if reg.size != dest.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(dest.size, reg.size), line_num: self.line_num, pos: None, inner_err: None }); }
1676 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNondestArg, line_num: self.line_num, pos: None, inner_err: None }); }
1677
1678 self.append_byte(reg.id)?;
1679 }
1680 Argument::Address { addr, mask } => {
1681 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNondestArg, line_num: self.line_num, pos: None, inner_err: None }); }
1682 if let Some(size) = addr.pointed_size {
1683 if packed && size != dest.size { return Err(AsmError { kind: AsmErrorKind::OperandsHadDifferentSizes(dest.size, size), line_num: self.line_num, pos: None, inner_err: None }); }
1684 if !packed && size != elem_size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: size, expected: vec![elem_size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1685 }
1686
1687 self.append_byte(0x80)?;
1688 self.append_address(addr)?;
1689 }
1690 x => return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidType { index: last_index, got: x.get_type(), expected: &[ArgumentType::VPURegister, ArgumentType::Address] }, line_num: self.line_num, pos: None, inner_err: None }),
1691 };
1692
1693 Ok(())
1694 }
1695
1696 pub(crate) fn process_kmov(&mut self, args: Vec<Argument>, size: Size) -> Result<(), AsmError> {
1697 let reg_size = match size {
1698 Size::Byte | Size::Word | Size::Dword => Size::Dword,
1699 Size::Qword => Size::Qword,
1700 _ => panic!(),
1701 };
1702
1703 if args.len() != 2 { return Err(AsmError { kind: AsmErrorKind::ArgsExpectedCount(&[2]), line_num: self.line_num, pos: None, inner_err: None }); }
1704 let mut args = args.into_iter();
1705 let arg1 = args.next().unwrap();
1706 let arg2 = args.next().unwrap();
1707
1708 let supported_types = slice_slice!(ArgumentType:
1709 [VPUMaskRegister, CPURegister],
1710 [CPURegister, VPUMaskRegister],
1711 [VPUMaskRegister, VPUMaskRegister],
1712 [VPUMaskRegister, Address],
1713 [Address, VPUMaskRegister],
1714 );
1715
1716 self.append_byte(OPCode::TRANS as u8)?;
1717
1718 match (arg1, arg2) {
1719 (Argument::VPUMaskRegister(dest), Argument::CPURegister(src)) => {
1720 if src.size != reg_size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: src.size, expected: vec![reg_size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1721
1722 debug_assert_ne!(src.size, Size::Byte); self.append_byte(0 + size.basic_sizecode().unwrap())?;
1724 self.append_byte((dest.id << 5) | src.id)?;
1725 }
1726 (Argument::CPURegister(dest), Argument::VPUMaskRegister(src)) => {
1727 if dest.size != reg_size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(0), got: dest.size, expected: vec![reg_size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1728
1729 debug_assert_ne!(dest.size, Size::Byte); self.append_byte(4 + size.basic_sizecode().unwrap())?;
1731 self.append_byte((dest.id << 4) | src.id)?;
1732 }
1733 (Argument::VPUMaskRegister(dest), Argument::VPUMaskRegister(src)) => {
1734 self.append_byte(8 + size.basic_sizecode().unwrap())?;
1735 self.append_byte((dest.id << 5) | src.id)?;
1736 }
1737 (Argument::VPUMaskRegister(dest), Argument::Address { addr, mask }) => {
1738 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1739 if let Some(s) = addr.pointed_size {
1740 if s != size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(1), got: s, expected: vec![size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1741 }
1742
1743 self.append_byte(12 + size.basic_sizecode().unwrap())?;
1744 self.append_byte(dest.id << 5)?;
1745 self.append_address(addr)?;
1746 }
1747 (Argument::Address { addr, mask }, Argument::VPUMaskRegister(src)) => {
1748 if mask.is_some() { return Err(AsmError { kind: AsmErrorKind::VPUMaskOnNonVecInstruction, line_num: self.line_num, pos: None, inner_err: None }); }
1749 if let Some(s) = addr.pointed_size {
1750 if s != size { return Err(AsmError { kind: AsmErrorKind::ArgumentInvalidSize { index: Some(0), got: s, expected: vec![size] }, line_num: self.line_num, pos: None, inner_err: None }); }
1751 }
1752
1753 self.append_byte(16 + size.basic_sizecode().unwrap())?;
1754 self.append_byte(src.id)?;
1755 self.append_address(addr)?;
1756 }
1757 (a, b) => return Err(AsmError { kind: AsmErrorKind::ArgumentsInvalidTypes { got: vec![a.get_type(), b.get_type()], expected: supported_types }, line_num: self.line_num, pos: None, inner_err: None }),
1758 }
1759
1760 Ok(())
1761 }
1762
1763 fn verify_legal_expr(&self, expr: &Expr, line_num: usize) -> Result<(), AsmError> {
1764 match &*expr.data.borrow() {
1765 ExprData::Value(_) => (),
1766 ExprData::Ident(ident) => if !self.file.symbols.is_defined(ident) && !self.file.extern_symbols.contains_key(ident) && !ident.starts_with('#') {
1767 return Err(AsmError { kind: AsmErrorKind::UnknownSymbol(ident.clone()), line_num, pos: None, inner_err: None });
1768 }
1769 ExprData::Uneval { op: _, left, right } => {
1770 self.verify_legal_expr(left.as_ref().unwrap(), line_num)?;
1771 if let Some(right) = right { self.verify_legal_expr(right, line_num)?; }
1772 }
1773 }
1774 Ok(())
1775 }
1776 pub(super) fn finalize(self) -> Result<ObjectFile, AsmError> {
1777 for (global, &line_num) in self.file.global_symbols.iter() {
1779 if !self.file.symbols.is_defined(global) {
1780 return Err(AsmError { kind: AsmErrorKind::GlobalSymbolWasNotDefined(global.clone()), line_num, pos: None, inner_err: None });
1781 }
1782 }
1783
1784 for (_, (expr, line_num)) in self.file.symbols.iter() { self.verify_legal_expr(expr, *line_num)?; }
1785
1786 for hole in self.file.text_holes.iter() { self.verify_legal_expr(&hole.expr, hole.line_num)?; }
1787 for hole in self.file.rodata_holes.iter() { self.verify_legal_expr(&hole.expr, hole.line_num)?; }
1788 for hole in self.file.data_holes.iter() { self.verify_legal_expr(&hole.expr, hole.line_num)?; }
1789
1790 Ok(self.file) }
1792}
1793
1794#[cfg(test)]
1795fn create_context() -> AssembleArgs<'static> {
1796 AssembleArgs {
1797 file_name: "test.asm",
1798 file: ObjectFile {
1799 global_symbols: Default::default(),
1800 extern_symbols: Default::default(),
1801
1802 symbols: Default::default(),
1803
1804 text_align: Default::default(),
1805 rodata_align: Default::default(),
1806 data_align: Default::default(),
1807 bss_align: Default::default(),
1808
1809 text_holes: Default::default(),
1810 rodata_holes: Default::default(),
1811 data_holes: Default::default(),
1812
1813 text: Default::default(),
1814 rodata: Default::default(),
1815 data: Default::default(),
1816 bss_len: Default::default(),
1817 },
1818
1819 current_seg: Some(AsmSegment::Text),
1820 done_segs: Default::default(),
1821
1822 line_num: Default::default(),
1823 line_pos_in_seg: Default::default(),
1824
1825 last_nonlocal_label: Default::default(),
1826 label_def: Default::default(),
1827
1828 times: Default::default(),
1829 }
1830}
1831
1832#[test]
1833fn test_extr_bin_op() {
1834 let c = create_context();
1835
1836 match c.extract_binary_op("+", 0, 1) {
1837 Some((op ,aft)) => {
1838 assert_eq!(op, OP::Add);
1839 assert_eq!(aft, 1);
1840 }
1841 None => panic!(),
1842 }
1843 match c.extract_binary_op(" + ", 2, 7) {
1844 Some((op, aft)) => {
1845 assert_eq!(op, OP::Add);
1846 assert_eq!(aft, 5);
1847 }
1848 None => panic!(),
1849 }
1850 match c.extract_binary_op(" a ", 2, 7) {
1851 Some(_) => panic!(),
1852 None => (),
1853 }
1854}
1855
1856#[test]
1857fn test_extr_string() {
1858 let c = create_context();
1859
1860 match c.extract_string("'hello world'", 0, 13) {
1861 Ok((res, aft)) => {
1862 assert_eq!(res, "hello world".as_bytes());
1863 assert_eq!(aft, 13);
1864 }
1865 Err(_) => panic!(),
1866 }
1867 match c.extract_string("hello ' wo rld' ", 5, 22) {
1868 Ok((res, aft)) => {
1869 assert_eq!(res, " wo rld".as_bytes());
1870 assert_eq!(aft, 20);
1871 }
1872 Err(_) => panic!(),
1873 }
1874 match c.extract_string("hello ' wo rld' b ", 12, 22) {
1875 Ok(_) => panic!(),
1876 Err(e) => {
1877 assert!(matches!(e.kind, AsmErrorKind::ExpectedString));
1878 assert_eq!(e.pos, Some(13));
1879 }
1880 }
1881 match c.extract_string("hello ' wo rld'y ", 5, 19) {
1882 Ok(_) => panic!(),
1883 Err(e) => {
1884 assert!(matches!(e.kind, AsmErrorKind::IncompleteString));
1885 assert_eq!(e.pos, Some(11));
1886 }
1887 }
1888 match c.extract_string("hello ' wo rld' ", 5, 11) {
1889 Ok(_) => panic!(),
1890 Err(e) => {
1891 assert!(matches!(e.kind, AsmErrorKind::ExpectedString));
1892 assert_eq!(e.pos, Some(11));
1893 }
1894 }
1895 match c.extract_string("hello ' wo rld' ", 5, 12) {
1896 Ok(_) => panic!(),
1897 Err(e) => {
1898 assert!(matches!(e.kind, AsmErrorKind::IncompleteString));
1899 assert_eq!(e.pos, Some(11));
1900 }
1901 }
1902 match c.extract_string("\"\\\\\\'\\\"'\\n\\t\\r\\0\\x12\\xfe\"\t ", 0, 25) {
1903 Ok((res, aft)) => {
1904 assert_eq!(res, &[92, 39, 34, 39, 10, 9, 13, 0, 0x12, 0xfe]);
1905 assert_eq!(aft, 25);
1906 }
1907 Err(_) => panic!(),
1908 }
1909 match c.extract_string("'\\\\\\'\\\"\"\\n\\t\\r\\0\\x12\\xfe'\t ", 0, 25) {
1910 Ok((res, aft)) => {
1911 assert_eq!(res, &[92, 39, 34, 34, 10, 9, 13, 0, 0x12, 0xfe]);
1912 assert_eq!(aft, 25);
1913 }
1914 Err(_) => panic!(),
1915 }
1916 match c.extract_string(" 'hello;world' 'another string' ", 1, 33) {
1917 Ok((res, aft)) => {
1918 assert_eq!(res, "hello;world".as_bytes());
1919 assert_eq!(aft, 15);
1920 }
1921 Err(_) => panic!(),
1922 }
1923 match c.extract_string(" 'hello world' 'another string' ", 14, 33) {
1924 Ok((res, aft)) => {
1925 assert_eq!(res, " ".as_bytes());
1926 assert_eq!(aft, 17);
1927 }
1928 Err(_) => panic!(),
1929 }
1930 match c.extract_string(" '\\y'y", 2, 7) {
1931 Ok(_) => panic!(),
1932 Err(e) => {
1933 assert!(matches!(e.kind, AsmErrorKind::InvalidEscape));
1934 assert_eq!(e.pos, Some(3));
1935 }
1936 }
1937 match c.extract_string(" '\\x'", 1, 6) {
1938 Ok(_) => panic!(),
1939 Err(e) => {
1940 assert!(matches!(e.kind, AsmErrorKind::IncompleteEscape));
1941 assert_eq!(e.pos, Some(3));
1942 }
1943 }
1944 match c.extract_string(" '\\x5'", 1, 7) {
1945 Ok(_) => panic!(),
1946 Err(e) => {
1947 assert!(matches!(e.kind, AsmErrorKind::IncompleteEscape));
1948 assert_eq!(e.pos, Some(3));
1949 }
1950 }
1951 match c.extract_string(" '\\x5g'", 2, 8) {
1952 Ok(_) => panic!(),
1953 Err(e) => {
1954 assert!(matches!(e.kind, AsmErrorKind::IncompleteEscape));
1955 assert_eq!(e.pos, Some(3));
1956 }
1957 }
1958 match c.extract_string(" '\\x", 2, 5) {
1959 Ok(_) => panic!(),
1960 Err(e) => {
1961 assert!(matches!(e.kind, AsmErrorKind::IncompleteEscape));
1962 assert_eq!(e.pos, Some(3));
1963 }
1964 }
1965 match c.extract_string(" '\\x4", 1, 6) {
1966 Ok(_) => panic!(),
1967 Err(e) => {
1968 assert!(matches!(e.kind, AsmErrorKind::IncompleteEscape));
1969 assert_eq!(e.pos, Some(3));
1970 }
1971 }
1972 match c.extract_string(" '\\x4b", 2, 7) {
1973 Ok(_) => panic!(),
1974 Err(e) => {
1975 assert!(matches!(e.kind, AsmErrorKind::IncompleteString));
1976 assert_eq!(e.pos, Some(2));
1977 }
1978 }
1979 match c.extract_string(" '\\", 1, 4) {
1980 Ok(_) => panic!(),
1981 Err(e) => {
1982 assert!(matches!(e.kind, AsmErrorKind::IncompleteEscape));
1983 assert_eq!(e.pos, Some(3));
1984 }
1985 }
1986}
1987
1988#[test]
1989fn test_extr_expr() {
1990 let mut c = create_context();
1991 match c.extract_expr("trUe;", 0, 5) {
1992 Ok((expr, aft)) => {
1993 assert_eq!(aft, 4);
1994 match expr.into_eval(&c.file.symbols).unwrap() {
1995 ValueCow::Owned(Value::Logical(val)) => assert_eq!(val, true),
1996 _ => panic!(),
1997 }
1998 }
1999 Err(e) => panic!("{:?}", e),
2000 }
2001 match c.extract_expr("faLse", 0, 5) {
2002 Ok((expr, aft)) => {
2003 assert_eq!(aft, 5);
2004 match expr.into_eval(&c.file.symbols).unwrap() {
2005 ValueCow::Owned(Value::Logical(val)) => assert_eq!(val, false),
2006 _ => panic!(),
2007 }
2008 }
2009 Err(e) => panic!("{:?}", e),
2010 }
2011 match c.extract_expr("nuLl", 0, 4) {
2012 Ok((expr, aft)) => {
2013 assert_eq!(aft, 4);
2014 match expr.into_eval(&c.file.symbols).unwrap() {
2015 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 0),
2016 _ => panic!(),
2017 }
2018 }
2019 Err(e) => panic!("{:?}", e),
2020 }
2021 match c.extract_expr("5", 0, 1) {
2022 Ok((expr, aft)) => {
2023 assert_eq!(aft, 1);
2024 match expr.into_eval(&c.file.symbols).unwrap() {
2025 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 5),
2026 _ => panic!(),
2027 }
2028 }
2029 Err(e) => panic!("{:?}", e),
2030 }
2031 match c.extract_expr(" 010 ", 1, 7) {
2032 Ok(r) => panic!("{:?}", r),
2033 Err(e) => {
2034 assert_eq!(e.pos, Some(2));
2035 assert!(matches!(e.kind, AsmErrorKind::NumericLiteralWithZeroPrefix));
2036 }
2037 }
2038 match c.extract_expr(" 00 ", 1, 6) {
2039 Ok(r) => panic!("{:?}", r),
2040 Err(e) => {
2041 assert_eq!(e.pos, Some(2));
2042 assert!(matches!(e.kind, AsmErrorKind::NumericLiteralWithZeroPrefix));
2043 }
2044 }
2045 match c.extract_expr(" 00_ ", 1, 7) {
2046 Ok(r) => panic!("{:?}", r),
2047 Err(e) => {
2048 assert_eq!(e.pos, Some(2));
2049 assert!(matches!(e.kind, AsmErrorKind::NumericLiteralWithZeroPrefix));
2050 }
2051 }
2052 match c.extract_expr(" 0_0_ ", 1, 8) {
2053 Ok(r) => panic!("{:?}", r),
2054 Err(e) => {
2055 assert_eq!(e.pos, Some(2));
2056 assert!(matches!(e.kind, AsmErrorKind::NumericLiteralWithZeroPrefix));
2057 }
2058 }
2059 match c.extract_expr("0", 0, 1) {
2060 Ok((expr, aft)) => {
2061 assert_eq!(aft, 1);
2062 match expr.into_eval(&c.file.symbols).unwrap() {
2063 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 0),
2064 _ => panic!(),
2065 }
2066 }
2067 Err(e) => panic!("{:?}", e),
2068 }
2069 match c.extract_expr("3.14", 0, 4) {
2070 Ok((expr, aft)) => {
2071 assert_eq!(aft, 4);
2072 match expr.into_eval(&c.file.symbols).unwrap() {
2073 ValueCow::Owned(Value::Float(val)) => assert!(Float::from(val - 3.14).abs() < 0.00000001),
2074 _ => panic!(),
2075 }
2076 }
2077 Err(e) => panic!("{:?}", e),
2078 }
2079 match c.extract_expr(" .14 ", 1, 7) {
2080 Ok(v) => panic!("{:?}", v),
2081 Err(e) => {
2082 assert_eq!(e.pos, Some(2));
2083 assert!(matches!(e.kind, AsmErrorKind::InvalidSymbolName));
2084 }
2085 }
2086 match c.extract_expr("5+8", 0, 3) {
2087 Ok((expr, aft)) => {
2088 assert_eq!(aft, 3);
2089 match expr.into_eval(&c.file.symbols).unwrap() {
2090 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 13),
2091 _ => panic!(),
2092 }
2093 }
2094 Err(e) => panic!("{:?}", e),
2095 }
2096 match c.extract_expr("5+8*2-1", 0, 7) {
2097 Ok((expr, aft)) => {
2098 assert_eq!(aft, 7);
2099 match expr.into_eval(&c.file.symbols).unwrap() {
2100 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 20),
2101 _ => panic!(),
2102 }
2103 }
2104 Err(e) => panic!("{:?}", e),
2105 }
2106 match c.extract_expr("(5+1)*(5-1) g", 0, 13) {
2107 Ok((expr, aft)) => {
2108 assert_eq!(aft, 11);
2109 match expr.into_eval(&c.file.symbols).unwrap() {
2110 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 24),
2111 _ => panic!(),
2112 }
2113 }
2114 Err(e) => panic!("{:?}", e),
2115 }
2116 match c.extract_expr("(5+1)*;(5-1) g", 0, 13) {
2117 Ok(r) => panic!("{:?}", r),
2118 Err(e) => {
2119 assert_eq!(e.pos, Some(6));
2120 assert!(matches!(e.kind, AsmErrorKind::ExpectedExpr));
2121 }
2122 }
2123 match c.extract_expr("(5+1);*(5-1) g", 0, 13) {
2124 Ok((expr, aft)) => {
2125 assert_eq!(aft, 5);
2126 match expr.into_eval(&c.file.symbols).unwrap() {
2127 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 6),
2128 _ => panic!(),
2129 }
2130 }
2131 Err(e) => panic!("{:?}", e),
2132 }
2133 match c.extract_expr("(5;+1)", 0, 6) {
2134 Ok(r) => panic!("{:?}", r),
2135 Err(e) => {
2136 assert_eq!(e.pos, Some(0));
2137 assert!(matches!(e.kind, AsmErrorKind::UnclosedParen));
2138 }
2139 }
2140 match c.extract_expr(";(5;+1)", 0, 7) {
2141 Ok(r) => panic!("{:?}", r),
2142 Err(e) => {
2143 assert_eq!(e.pos, Some(0));
2144 assert!(matches!(e.kind, AsmErrorKind::ExpectedExpr));
2145 }
2146 }
2147 match c.extract_expr(" ( 5-3 ) *--+ -(5 -1)f ", 1, 30) {
2148 Ok((expr, aft)) => {
2149 assert_eq!(aft, 27);
2150 match expr.into_eval(&c.file.symbols).unwrap() {
2151 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, -8),
2152 _ => panic!(),
2153 }
2154 }
2155 Err(e) => panic!("{:?}", e),
2156 }
2157 match c.extract_expr(" \"hello world\" ", 1, 17) {
2158 Ok((expr, aft)) => {
2159 assert_eq!(aft, 15);
2160 match expr.into_eval(&c.file.symbols).unwrap() {
2161 ValueCow::Owned(Value::Binary(val)) => assert_eq!(val, "hello world".as_bytes()),
2162 _ => panic!(),
2163 }
2164 }
2165 Err(e) => panic!("{:?}", e),
2166 }
2167 match c.extract_expr(" \"hello;world\" ", 1, 17) {
2168 Ok((expr, aft)) => {
2169 assert_eq!(aft, 15);
2170 match expr.into_eval(&c.file.symbols).unwrap() {
2171 ValueCow::Owned(Value::Binary(val)) => assert_eq!(val, "hello;world".as_bytes()),
2172 _ => panic!(),
2173 }
2174 }
2175 Err(e) => panic!("{:?}", e),
2176 }
2177 match c.extract_expr(" 'hello;world\" ", 1, 17) {
2178 Ok(r) => panic!("{:?}", r),
2179 Err(e) => {
2180 assert_eq!(e.pos, Some(2));
2181 assert!(matches!(e.kind, AsmErrorKind::IncompleteString));
2182 }
2183 }
2184 match c.extract_expr("$if(TrUe,6 / -2,3 << 2)", 0, 23) {
2185 Ok((expr, aft)) => {
2186 assert_eq!(aft, 23);
2187 match expr.into_eval(&c.file.symbols).unwrap() {
2188 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, -3),
2189 _ => panic!(),
2190 }
2191 }
2192 Err(e) => panic!("{:?}", e),
2193 }
2194 match c.extract_expr(" $if( False == true , 6 / - 2 , 3 << 2 ) ", 1, 53) {
2195 Ok((expr, aft)) => {
2196 assert_eq!(aft, 51);
2197 match expr.into_eval(&c.file.symbols).unwrap() {
2198 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 12),
2199 _ => panic!(),
2200 }
2201 }
2202 Err(e) => panic!("{:?}", e),
2203 }
2204}
2205#[test]
2206fn test_float_lexer() {
2207 let mut c = create_context();
2208 match c.extract_expr(" 1.234 - 1.0 ", 1, 20) {
2209 Err(e) => panic!("{:?}", e),
2210 Ok((expr, aft)) => {
2211 assert_eq!(aft, 16);
2212 match expr.into_eval(&c.file.symbols).unwrap() {
2213 ValueCow::Owned(v) => match v {
2214 Value::Float(v) => assert!(v - 0.234 < 0.00000000001),
2215 x => panic!("{:?}", x),
2216 }
2217 _ => panic!(),
2218 }
2219 }
2220 }
2221 match c.extract_expr(" 1.234 -1.0 ", 1, 19) {
2222 Err(e) => panic!("{:?}", e),
2223 Ok((expr, aft)) => {
2224 assert_eq!(aft, 15);
2225 match expr.into_eval(&c.file.symbols).unwrap() {
2226 ValueCow::Owned(v) => match v {
2227 Value::Float(v) => assert!(v - 0.234 < 0.00000000001),
2228 x => panic!("{:?}", x),
2229 }
2230 _ => panic!(),
2231 }
2232 }
2233 }
2234 match c.extract_expr(" 1.234- 1.0 ", 1, 19) {
2235 Err(e) => panic!("{:?}", e),
2236 Ok((expr, aft)) => {
2237 assert_eq!(aft, 15);
2238 match expr.into_eval(&c.file.symbols).unwrap() {
2239 ValueCow::Owned(v) => match v {
2240 Value::Float(v) => assert!(v - 0.234 < 0.00000000001),
2241 x => panic!("{:?}", x),
2242 }
2243 _ => panic!(),
2244 }
2245 }
2246 }
2247 match c.extract_expr(" 1.234-1.0 ", 1, 18) {
2248 Err(e) => panic!("{:?}", e),
2249 Ok((expr, aft)) => {
2250 assert_eq!(aft, 14);
2251 match expr.into_eval(&c.file.symbols).unwrap() {
2252 ValueCow::Owned(v) => match v {
2253 Value::Float(v) => assert!(v - 0.234 < 0.00000000001),
2254 x => panic!("{:?}", x),
2255 }
2256 _ => panic!(),
2257 }
2258 }
2259 }
2260 match c.extract_expr(" 574.35849590905674857649 - 8576485769847659845769845769845646534457546756867867823344356 ", 1, 97) {
2261 Err(e) => panic!("{:?}", e),
2262 Ok((expr, aft)) => {
2263 assert_eq!(aft, 93);
2264 match expr.into_eval(&c.file.symbols) {
2265 Ok(v) => panic!("{:?}", v),
2266 Err(e) => match e {
2267 EvalError::Illegal(e) => match e {
2268 IllegalReason::IncompatibleTypes(OP::Sub, ValueType::Float, ValueType::Integer) => (),
2269 r => panic!("{:?}", r),
2270 }
2271 e => panic!("{:?}", e),
2272 }
2273 }
2274 }
2275 }
2276 match c.extract_expr(" 574.35849590905674857649-8576485769847659845769845769845646534457546756867867823344356 ", 1, 95) {
2277 Err(e) => panic!("{:?}", e),
2278 Ok((expr, aft)) => {
2279 assert_eq!(aft, 91);
2280 match expr.into_eval(&c.file.symbols) {
2281 Ok(v) => panic!("{:?}", v),
2282 Err(e) => match e {
2283 EvalError::Illegal(e) => match e {
2284 IllegalReason::IncompatibleTypes(OP::Sub, ValueType::Float, ValueType::Integer) => (),
2285 r => panic!("{:?}", r),
2286 }
2287 e => panic!("{:?}", e),
2288 }
2289 }
2290 }
2291 }
2292}
2293#[test]
2294fn test_ptriff() {
2295 let mut c = create_context();
2296 c.file.symbols.define("foo".into(), (OP::Add, Expr::from(ExprData::Ident("#t".into())), 10i64).into(), 0).unwrap();
2297 c.file.symbols.define("bar".into(), (OP::Add, Expr::from(ExprData::Ident("#t".into())), 14i64).into(), 0).unwrap();
2298 match c.extract_expr("$-$", 0, 3) {
2299 Ok((expr, aft)) => {
2300 assert_eq!(aft, 3);
2301 match expr.into_eval(&c.file.symbols).unwrap() {
2302 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 0),
2303 _ => panic!(),
2304 }
2305 }
2306 Err(e) => panic!("{:?}", e),
2307 }
2308 match c.extract_expr(" $ + 3 + 3 - 1 - 2 - -- $ - 2 + 1 ", 2, 40) {
2309 Ok((expr, aft)) => {
2310 assert_eq!(aft, 38);
2311 match expr.into_eval(&c.file.symbols).unwrap() {
2312 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 2),
2313 _ => panic!(),
2314 }
2315 }
2316 Err(e) => panic!("{:?}", e),
2317 }
2318 match c.extract_expr("5*(($ + 8)-($ - 3))", 0, 19) {
2319 Ok((expr, aft)) => {
2320 assert_eq!(aft, 19);
2321 match expr.into_eval(&c.file.symbols).unwrap() {
2322 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 55),
2323 _ => panic!(),
2324 }
2325 }
2326 Err(e) => panic!("{:?}", e),
2327 }
2328 match c.extract_expr("foo-foo", 0, 7) {
2329 Ok((expr, aft)) => {
2330 assert_eq!(aft, 7);
2331 match expr.into_eval(&c.file.symbols).unwrap() {
2332 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 0),
2333 _ => panic!(),
2334 }
2335 }
2336 Err(e) => panic!("{:?}", e),
2337 }
2338 match c.extract_expr("foo-$;comment", 0, 5) {
2339 Ok((expr, aft)) => {
2340 assert_eq!(aft, 5);
2341 match expr.into_eval(&c.file.symbols).unwrap() {
2342 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 10),
2343 _ => panic!(),
2344 }
2345 }
2346 Err(e) => panic!("{:?}", e),
2347 }
2348 match c.extract_expr("$-foo", 0, 5) {
2349 Ok((expr, aft)) => {
2350 assert_eq!(aft, 5);
2351 match expr.into_eval(&c.file.symbols).unwrap() {
2352 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, -10),
2353 _ => panic!(),
2354 }
2355 }
2356 Err(e) => panic!("{:?}", e),
2357 }
2358 match c.extract_expr("bar-foo", 0, 7) {
2359 Ok((expr, aft)) => {
2360 assert_eq!(aft, 7);
2361 match expr.into_eval(&c.file.symbols).unwrap() {
2362 ValueCow::Owned(Value::Integer(val)) => assert_eq!(val, 4),
2363 _ => panic!(),
2364 }
2365 }
2366 Err(e) => panic!("{:?}", e),
2367 }
2368}
2369#[test]
2370fn test_numeric_formats() {
2371 let mut c = create_context();
2372 match c.extract_expr("0x2Ff4;comment", 0, 6) {
2373 Ok((expr, aft)) => {
2374 assert_eq!(aft, 6);
2375 match expr.eval(&c.file.symbols) {
2376 Ok(v) => match &*v {
2377 Value::Integer(v) => assert_eq!(*v, 0x2Ff4),
2378 x => panic!("unexpected type: {:?}", x),
2379 }
2380 Err(e) => panic!("{:?}", e),
2381 }
2382 }
2383 Err(e) => panic!("{:?}", e),
2384 }
2385 match c.extract_expr("0x02Ff4", 0, 7) {
2386 Ok((expr, aft)) => {
2387 assert_eq!(aft, 7);
2388 match expr.eval(&c.file.symbols) {
2389 Ok(v) => match &*v {
2390 Value::Integer(v) => assert_eq!(*v, 0x2Ff4),
2391 x => panic!("unexpected type: {:?}", x),
2392 }
2393 Err(e) => panic!("{:?}", e),
2394 }
2395 }
2396 Err(e) => panic!("{:?}", e),
2397 }
2398 match c.extract_expr("0o23_34", 0, 7) {
2399 Ok((expr, aft)) => {
2400 assert_eq!(aft, 7);
2401 match expr.eval(&c.file.symbols) {
2402 Ok(v) => match &*v {
2403 Value::Integer(v) => assert_eq!(*v, 0o23_34),
2404 x => panic!("unexpected type: {:?}", x),
2405 }
2406 Err(e) => panic!("{:?}", e),
2407 }
2408 }
2409 Err(e) => panic!("{:?}", e),
2410 }
2411 match c.extract_expr("0o23_34_", 0, 8) {
2412 Ok((expr, aft)) => {
2413 assert_eq!(aft, 8);
2414 match expr.eval(&c.file.symbols) {
2415 Ok(v) => match &*v {
2416 Value::Integer(v) => assert_eq!(*v, 0o23_34_),
2417 x => panic!("unexpected type: {:?}", x),
2418 }
2419 Err(e) => panic!("{:?}", e),
2420 }
2421 }
2422 Err(e) => panic!("{:?}", e),
2423 }
2424 match c.extract_expr("0b1011_0010", 0, 11) {
2425 Ok((expr, aft)) => {
2426 assert_eq!(aft, 11);
2427 match expr.eval(&c.file.symbols) {
2428 Ok(v) => match &*v {
2429 Value::Integer(v) => assert_eq!(*v, 0b1011_0010),
2430 x => panic!("unexpected type: {:?}", x),
2431 }
2432 Err(e) => panic!("{:?}", e),
2433 }
2434 }
2435 Err(e) => panic!("{:?}", e),
2436 }
2437 match c.extract_expr("0b1011_0010", 0, 11) {
2438 Ok((expr, aft)) => {
2439 assert_eq!(aft, 11);
2440 match expr.eval(&c.file.symbols) {
2441 Ok(v) => match &*v {
2442 Value::Integer(v) => assert_eq!(*v, 0b1011_0010),
2443 x => panic!("unexpected type: {:?}", x),
2444 }
2445 Err(e) => panic!("{:?}", e),
2446 }
2447 }
2448 Err(e) => panic!("{:?}", e),
2449 }
2450}
2451#[test]
2452fn test_imm_parser() {
2453 let mut c = create_context();
2454 match c.extract_imm(" dword] ", 1, 11) {
2455 Ok(x) => panic!("{:?}", x),
2456 Err(e) => {
2457 match e.kind {
2458 AsmErrorKind::ExpectedExpr => (),
2459 x => panic!("{:?}", x),
2460 }
2461 assert_eq!(e.pos, Some(8));
2462 assert!(e.inner_err.is_none());
2463 }
2464 }
2465}
2466#[test]
2467fn test_address_parser() {
2468 let mut c = create_context();
2469 match c.extract_address(" dword ptr [0x2334] ", 2, 28) {
2470 Ok((addr, aft)) => {
2471 assert_eq!(aft, 26);
2472 assert_eq!(addr.address_size, Size::Qword);
2473 assert_eq!(addr.r1, None);
2474 assert_eq!(addr.r2, None);
2475 assert_eq!(addr.pointed_size, Some(Size::Dword));
2476 match addr.base.as_ref().unwrap().eval(&c.file.symbols) {
2477 Ok(v) => match &*v {
2478 Value::Integer(v) => assert_eq!(*v, 0x2334),
2479 x => panic!("unexpected type {:?}", x),
2480 }
2481 Err(e) => panic!("{:?}", e),
2482 }
2483 }
2484 Err(e) => panic!("{:?}", e),
2485 }
2486 match c.extract_address(" dword ptr [ 0x2334 ] ", 2, 34) {
2487 Ok((addr, aft)) => {
2488 assert_eq!(aft, 32);
2489 assert_eq!(addr.address_size, Size::Qword);
2490 assert_eq!(addr.r1, None);
2491 assert_eq!(addr.r2, None);
2492 assert_eq!(addr.pointed_size, Some(Size::Dword));
2493 match addr.base.as_ref().unwrap().eval(&c.file.symbols) {
2494 Ok(v) => match &*v {
2495 Value::Integer(v) => assert_eq!(*v, 0x2334),
2496 x => panic!("unexpected type {:?}", x),
2497 }
2498 Err(e) => panic!("{:?}", e),
2499 }
2500 }
2501 Err(e) => panic!("{:?}", e),
2502 }
2503 match c.extract_address(". tword ptr [4*eax] _", 2, 27) {
2504 Ok((addr, aft)) => {
2505 assert_eq!(aft, 25);
2506 assert_eq!(addr.address_size, Size::Dword);
2507 assert_eq!(addr.r1, Some((0, 2)));
2508 assert_eq!(addr.r2, None);
2509 assert_eq!(addr.pointed_size, Some(Size::Tword));
2510 assert!(addr.base.is_none());
2511 }
2512 Err(e) => panic!("{:?}", e),
2513 }
2514 match c.extract_address(". tword ptr [3*eax + EaX] _", 2, 33) {
2515 Ok((addr, aft)) => {
2516 assert_eq!(aft, 31);
2517 assert_eq!(addr.address_size, Size::Dword);
2518 assert_eq!(addr.r1, Some((0, 2)));
2519 assert_eq!(addr.r2, None);
2520 assert_eq!(addr.pointed_size, Some(Size::Tword));
2521 assert!(addr.base.is_none());
2522 }
2523 Err(e) => panic!("{:?}", e),
2524 }
2525 match c.extract_address(" tword ptr [ax+bx] ", 2, 27) {
2526 Ok((addr, aft)) => {
2527 assert_eq!(aft, 25);
2528 assert_eq!(addr.address_size, Size::Word);
2529 assert_eq!(addr.r1.unwrap().1, 0);
2530 assert_eq!(addr.r1.unwrap().0 + addr.r2.unwrap(), 1);
2531 assert_eq!(addr.pointed_size, Some(Size::Tword));
2532 assert!(addr.base.is_none());
2533 }
2534 Err(e) => panic!("{:?}", e),
2535 }
2536 match c.extract_address(" zWord ptr [4*(r8d + 7)] ", 2, 34) {
2537 Ok((addr, aft)) => {
2538 assert_eq!(aft, 31);
2539 assert_eq!(addr.address_size, Size::Dword);
2540 assert_eq!(addr.r1, Some((8, 2)));
2541 assert_eq!(addr.r2, None);
2542 assert_eq!(addr.pointed_size, Some(Size::Zword));
2543 match addr.base.as_ref().unwrap().eval(&c.file.symbols) {
2544 Ok(v) => match &*v {
2545 Value::Integer(v) => assert_eq!(*v, 28),
2546 x => panic!("unexpected type {:?}", x),
2547 }
2548 Err(e) => panic!("{:?}", e),
2549 }
2550 }
2551 Err(e) => panic!("{:?}", e),
2552 }
2553 match c.extract_address(" [4*(4 * (2 + r8) + (7 + -r8 * (1 + 1 * 1))) + R8] g ", 2, 54) {
2554 Ok((addr, aft)) => {
2555 assert_eq!(aft, 51);
2556 assert_eq!(addr.address_size, Size::Qword);
2557 assert_eq!(addr.r1, Some((8, 3)));
2558 assert_eq!(addr.r2, Some(8));
2559 assert_eq!(addr.pointed_size, None);
2560 match addr.base.as_ref().unwrap().eval(&c.file.symbols) {
2561 Ok(v) => match &*v {
2562 Value::Integer(v) => assert_eq!(*v, 60),
2563 x => panic!("unexpected type {:?}", x),
2564 }
2565 Err(e) => panic!("{:?}", e),
2566 }
2567 }
2568 Err(e) => panic!("{:?}", e),
2569 }
2570 match c.extract_address("[5*ax] extra stuff after", 0, 24) {
2571 Ok((addr, aft)) => {
2572 assert_eq!(aft, 6);
2573 assert_eq!(addr.address_size, Size::Word);
2574 assert_eq!(addr.r1, Some((0, 2)));
2575 assert_eq!(addr.r2, Some(0));
2576 assert_eq!(addr.pointed_size, None);
2577 assert!(addr.base.is_none());
2578 }
2579 Err(e) => panic!("{:?}", e),
2580 }
2581 match c.extract_address(" 5 * ax] ", 2, 12) {
2582 Ok(_) => panic!(),
2583 Err(e) => {
2584 assert_eq!(e.pos, Some(3));
2585 assert!(matches!(e.kind, AsmErrorKind::ExpectedAddress));
2586 }
2587 }
2588 match c.extract_address(" [5 * ax ", 2, 12) {
2589 Ok(_) => panic!(),
2590 Err(e) => {
2591 assert_eq!(e.pos, Some(12));
2592 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::Unterminated)));
2593 }
2594 }
2595 match c.extract_address(" word [5 * ax ", 2, 17) {
2596 Ok(_) => panic!(),
2597 Err(e) => {
2598 assert_eq!(e.pos, Some(8));
2599 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeMissingPtr)));
2600 }
2601 }
2602 match c.extract_address(" wOrd[5 * ax ", 2, 16) {
2603 Ok(_) => panic!(),
2604 Err(e) => {
2605 assert_eq!(e.pos, Some(7));
2606 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeMissingPtr)));
2607 }
2608 }
2609 match c.extract_address(" WORD ptr[5 * ax ", 2, 20) {
2610 Ok(_) => panic!(),
2611 Err(e) => {
2612 assert_eq!(e.pos, Some(20));
2613 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::Unterminated)));
2614 }
2615 }
2616 match c.extract_address(" word ptr[9 * ax] ", 2, 21) {
2617 Ok((addr, aft)) => {
2618 assert_eq!(aft, 19);
2619 assert_eq!(addr.address_size, Size::Word);
2620 assert_eq!(addr.r1, Some((0, 3)));
2621 assert_eq!(addr.r2, Some(0));
2622 assert_eq!(addr.pointed_size, Some(Size::Word));
2623 assert!(addr.base.is_none());
2624 }
2625 Err(e) => panic!("{:?}", e),
2626 }
2627 match c.extract_address(" word pTr[ ] ", 1, 17) {
2628 Ok(_) => panic!(),
2629 Err(e) => {
2630 match e.kind {
2631 AsmErrorKind::BadAddress(BadAddress::BadBase) => (),
2632 _ => panic!("{:?}", e.kind),
2633 }
2634 assert_eq!(e.pos, Some(10));
2635 let inner = *e.inner_err.unwrap();
2636 match inner.kind {
2637 AsmErrorKind::ExpectedExpr => (),
2638 _ => panic!("{:?}", inner.kind),
2639 }
2640 assert_eq!(inner.pos, Some(14));
2641 assert!(inner.inner_err.is_none());
2642 }
2643 }
2644 match c.extract_address(" word ptr[] ", 1, 14) {
2645 Ok(_) => panic!(),
2646 Err(e) => {
2647 match e.kind {
2648 AsmErrorKind::BadAddress(BadAddress::BadBase) => (),
2649 _ => panic!("{:?}", e.kind),
2650 }
2651 assert_eq!(e.pos, Some(10));
2652 let inner = *e.inner_err.unwrap();
2653 match inner.kind {
2654 AsmErrorKind::ExpectedExpr => (),
2655 _ => panic!("{:?}", inner.kind),
2656 }
2657 assert_eq!(inner.pos, Some(11));
2658 assert!(inner.inner_err.is_none());
2659 }
2660 }
2661 match c.extract_address(" word ptr[a b] ", 1, 17) {
2662 Ok(_) => panic!(),
2663 Err(e) => {
2664 assert_eq!(e.pos, Some(13));
2665 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::InteriorNotSingleExpr)));
2666 }
2667 }
2668 match c.extract_address(" ptr[45] ", 1, 11) {
2669 Ok(_) => panic!(),
2670 Err(e) => {
2671 assert_eq!(e.pos, Some(2));
2672 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::PtrSpecWithoutSize)));
2673 }
2674 }
2675 match c.extract_address(" ptr [45] ", 1, 12) {
2676 Ok(_) => panic!(),
2677 Err(e) => {
2678 assert_eq!(e.pos, Some(2));
2679 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::PtrSpecWithoutSize)));
2680 }
2681 }
2682 match c.extract_address(" sefsfsd[45] ", 1, 15) {
2683 Ok(_) => panic!(),
2684 Err(e) => {
2685 assert_eq!(e.pos, Some(2));
2686 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeNotRecognized)));
2687 }
2688 }
2689 match c.extract_address(" sefsfsd [45] ", 1, 16) {
2690 Ok(_) => panic!(),
2691 Err(e) => {
2692 assert_eq!(e.pos, Some(2));
2693 match e.kind {
2694 AsmErrorKind::BadAddress(BadAddress::SizeNotRecognized) => (),
2695 k => panic!("{:?}", k),
2696 }
2697 }
2698 }
2699 match c.extract_address(" sefsfsd ptr [45] ", 1, 20) {
2700 Ok(_) => panic!(),
2701 Err(e) => {
2702 assert_eq!(e.pos, Some(2));
2703 match e.kind {
2704 AsmErrorKind::BadAddress(BadAddress::SizeNotRecognized) => (),
2705 k => panic!("{:?}", k),
2706 }
2707 }
2708 }
2709 match c.extract_address(" sefsfsd ptr[45] ", 1, 19) {
2710 Ok(_) => panic!(),
2711 Err(e) => {
2712 assert_eq!(e.pos, Some(2));
2713 match e.kind {
2714 AsmErrorKind::BadAddress(BadAddress::SizeNotRecognized) => (),
2715 k => panic!("{:?}", k),
2716 }
2717 }
2718 }
2719 match c.extract_address(" ", 1, 10) {
2720 Ok(_) => panic!(),
2721 Err(e) => {
2722 assert_eq!(e.pos, Some(10));
2723 assert!(matches!(e.kind, AsmErrorKind::ExpectedAddress));
2724 }
2725 }
2726 match c.extract_address(" [ byte 45] ", 1, 16) {
2727 Ok(_) => panic!(),
2728 Err(e) => {
2729 assert_eq!(e.pos, Some(2));
2730 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeUnsupported)));
2731 }
2732 }
2733 match c.extract_address(" [tword 45] ", 1, 15) {
2734 Ok(_) => panic!(),
2735 Err(e) => {
2736 assert_eq!(e.pos, Some(2));
2737 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeUnsupported)));
2738 }
2739 }
2740 match c.extract_address(" [ xwoRd 45] ", 1, 16) {
2741 Ok(_) => panic!(),
2742 Err(e) => {
2743 assert_eq!(e.pos, Some(2));
2744 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeUnsupported)));
2745 }
2746 }
2747 match c.extract_address(" [ yword 45] ", 1, 16) {
2748 Ok(_) => panic!(),
2749 Err(e) => {
2750 assert_eq!(e.pos, Some(2));
2751 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeUnsupported)));
2752 }
2753 }
2754 match c.extract_address(" [ ZWORD 45] ", 1, 16) {
2755 Ok(_) => panic!(),
2756 Err(e) => {
2757 assert_eq!(e.pos, Some(2));
2758 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeUnsupported)));
2759 }
2760 }
2761 match c.extract_address(" word ptr [al] ", 1, 18) {
2762 Ok(_) => panic!(),
2763 Err(e) => {
2764 assert_eq!(e.pos, Some(11));
2765 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeUnsupported)));
2766 }
2767 }
2768 match c.extract_address(" [ah] ", 1, 9) {
2769 Ok(_) => panic!(),
2770 Err(e) => {
2771 assert_eq!(e.pos, Some(2));
2772 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::SizeUnsupported)));
2773 }
2774 }
2775 match c.extract_address(" [ax*bx] ", 1, 12) {
2776 Ok(_) => panic!(),
2777 Err(e) => {
2778 assert_eq!(e.pos, Some(2));
2779 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::RegMultNotCriticalExpr(_))));
2780 }
2781 }
2782 match c.extract_address(" [ax*ax] ", 1, 12) {
2783 Ok(_) => panic!(),
2784 Err(e) => {
2785 assert_eq!(e.pos, Some(2));
2786 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::RegMultNotCriticalExpr(_))));
2787 }
2788 }
2789 match c.extract_address(" [ax;*ax] ", 1, 12) {
2790 Ok(_) => panic!(),
2791 Err(e) => {
2792 assert!(matches!(e.kind, AsmErrorKind::BadAddress(BadAddress::Unterminated)));
2793 assert_eq!(e.pos, Some(5));
2794 }
2795 }
2796}
2797#[test]
2798fn test_parse_arg() {
2799 let mut c = create_context();
2800 match c.extract_arg("g RaX g", 1, 7).unwrap() {
2801 (Argument::CPURegister(CPURegisterInfo { id: 0, size: Size::Qword, high: false }), 5) => (),
2802 e => panic!("wrong value: {:?}", e),
2803 }
2804 match c.extract_arg("g sT0 g", 1, 7).unwrap() {
2805 (Argument::FPURegister(FPURegisterInfo { id: 0 }), 5) => (),
2806 e => panic!("wrong value: {:?}", e),
2807 }
2808 match c.extract_arg("g XmM0 g", 1, 8).unwrap() {
2809 (Argument::VPURegister { reg: VPURegisterInfo { id: 0, size: Size::Xword }, mask: None }, 6) => (),
2810 e => panic!("wrong value: {:?}", e),
2811 }
2812 match c.extract_arg("g XmM0{k1} g", 1, 12).unwrap() {
2813 (Argument::VPURegister { reg: VPURegisterInfo { id: 0, size: Size::Xword }, mask: Some(VPUMaskType::Blend(VPUMaskRegisterInfo { id: 1 })) }, 10) => (),
2814 e => panic!("wrong value: {:?}", e),
2815 }
2816 match c.extract_arg("g XmM0{k3}{z} g", 1, 15).unwrap() {
2817 (Argument::VPURegister { reg: VPURegisterInfo { id: 0, size: Size::Xword }, mask: Some(VPUMaskType::Zero(VPUMaskRegisterInfo { id: 3 })) }, 13) => (),
2818 e => panic!("wrong value: {:?}", e),
2819 }
2820 match c.extract_arg("g XmM0 { k3 } { z } g", 1, 29).unwrap() {
2821 (Argument::VPURegister { reg: VPURegisterInfo { id: 0, size: Size::Xword }, mask: Some(VPUMaskType::Zero(VPUMaskRegisterInfo { id: 3 })) }, 26) => (),
2822 e => panic!("wrong value: {:?}", e),
2823 }
2824 match c.extract_arg("g [0]{k1} g", 1, 11).unwrap() {
2825 (Argument::Address { addr: Address { address_size: Size::Qword, r1: None, r2: None, pointed_size: None, base: None }, mask: Some(VPUMaskType::Blend(VPUMaskRegisterInfo { id: 1 })) }, 9) => (),
2826 e => panic!("wrong value: {:?}", e),
2827 }
2828 match c.extract_arg("g byte ptr [eax + edi]{k3}{z} g", 1, 31).unwrap() {
2829 (Argument::Address { addr: Address { address_size: Size::Dword, r1: Some(_), r2: Some(_), pointed_size: Some(Size::Byte), base: None }, mask: Some(VPUMaskType::Zero(VPUMaskRegisterInfo { id: 3 })) }, 29) => (),
2830 e => panic!("wrong value: {:?}", e),
2831 }
2832 match c.extract_arg("g dword ptr [qword rdi + 0x6] { k3 } { z } g", 1, 56).unwrap() {
2833 (Argument::Address { addr: Address { address_size: Size::Qword, r1: _, r2: _, pointed_size: Some(Size::Dword), base: Some(_) }, mask: Some(VPUMaskType::Zero(VPUMaskRegisterInfo { id: 3 })) }, 53) => (),
2834 e => panic!("wrong value: {:?}", e),
2835 }
2836 match c.extract_arg("g XmM0{z} g", 1, 13) {
2837 Ok(v) => panic!("{:?}", v),
2838 Err(e) => {
2839 match e.kind {
2840 AsmErrorKind::VPUZeroingWithoutOpmask => (),
2841 k => panic!("{:?}", k),
2842 }
2843 assert_eq!(e.pos, Some(3));
2844 }
2845 }
2846 match c.extract_arg("g XmM0{k0} g", 1, 14) {
2847 Ok(v) => panic!("{:?}", v),
2848 Err(e) => {
2849 match e.kind {
2850 AsmErrorKind::VPUOpmaskWasK0 => (),
2851 k => panic!("{:?}", k),
2852 }
2853 assert_eq!(e.pos, Some(3));
2854 }
2855 }
2856 match c.extract_arg("g XmM0{eax} g", 1, 15) {
2857 Ok(v) => panic!("{:?}", v),
2858 Err(e) => {
2859 match e.kind {
2860 AsmErrorKind::ArgumentInvalidType { index: None, got: ArgumentType::CPURegister, expected: &[ArgumentType::VPUMaskRegister] } => (),
2861 k => panic!("{:?}", k),
2862 }
2863 assert_eq!(e.pos, Some(7));
2864 }
2865 }
2866 match c.extract_arg("g XmM0 { eax g", 1, 18) {
2867 Ok(v) => panic!("{:?}", v),
2868 Err(e) => {
2869 match e.kind {
2870 AsmErrorKind::VPUMaskUnclosedBracket => (),
2871 k => panic!("{:?}", k),
2872 }
2873 assert_eq!(e.pos, Some(9));
2874 }
2875 }
2876 match c.extract_arg("g bYte PtR [20+rax] g", 1, 21).unwrap() {
2877 (Argument::Address { .. }, 19) => (),
2878 e => panic!("wrong value: {:?}", e),
2879 }
2880 match c.extract_arg("g foo + bar g", 1, 13).unwrap() {
2881 (Argument::Imm(Imm { .. }), 11) => (),
2882 e => panic!("wrong value: {:?}", e),
2883 }
2884 match c.extract_arg(" ", 1, 7) {
2885 Ok(x) => panic!("{:?}", x),
2886 Err(e) => {
2887 assert_eq!(e.pos, Some(7));
2888 assert!(matches!(e.kind, AsmErrorKind::ExpectedExpr));
2889 }
2890 }
2891 match c.extract_arg(" \"[]\" ", 1, 8) {
2892 Ok((x, aft)) => {
2893 assert_eq!(aft, 6);
2894 match x {
2895 Argument::Imm(imm) => {
2896 assert_eq!(imm.size, None);
2897 match &*imm.expr.eval(&c.file.symbols).unwrap() {
2898 Value::Binary(bin) => assert_eq!(bin, "[]".as_bytes()),
2899 x => panic!("{:?}", x),
2900 }
2901 }
2902 _ => panic!("{:?}", x),
2903 }
2904 }
2905 Err(e) => panic!("{:?}", e),
2906 }
2907 match c.extract_arg(" dword \"[]\" ", 1, 14) {
2908 Ok((x, aft)) => {
2909 assert_eq!(aft, 12);
2910 match x {
2911 Argument::Imm(imm) => {
2912 assert_eq!(imm.size, Some(Size::Dword));
2913 match &*imm.expr.eval(&c.file.symbols).unwrap() {
2914 Value::Binary(bin) => assert_eq!(bin, "[]".as_bytes()),
2915 x => panic!("{:?}", x),
2916 }
2917 }
2918 _ => panic!("{:?}", x),
2919 }
2920 }
2921 Err(e) => panic!("{:?}", e),
2922 }
2923}
2924#[test]
2925fn test_tilde_parse() {
2926 let mut c = create_context();
2927 match c.extract_arg(" !32 ", 1, 7) {
2928 Ok((x, aft)) => {
2929 assert_eq!(aft, 5);
2930 match x {
2931 Argument::Imm(imm) => {
2932 assert_eq!(imm.size, None);
2933 match &*imm.expr.eval(&c.file.symbols).unwrap() {
2934 Value::Integer(v) => assert_eq!(*v, !32),
2935 x => panic!("{:?}", x),
2936 }
2937 }
2938 _ => panic!("{:?}", x),
2939 }
2940 }
2941 Err(e) => panic!("{:?}", e),
2942 }
2943 match c.extract_arg(" ~32 ", 1, 7) {
2944 Ok(_) => panic!(),
2945 Err(e) => {
2946 assert_eq!(e.pos, Some(2));
2947 assert!(e.inner_err.is_none());
2948 match e.kind {
2949 AsmErrorKind::UseOfTildeNot => (),
2950 x => panic!("{:?}", x),
2951 }
2952 }
2953 }
2954 match c.extract_arg(" + --~-32 ", 3, 17) {
2955 Ok(_) => panic!(),
2956 Err(e) => {
2957 assert_eq!(e.pos, Some(11));
2958 assert!(e.inner_err.is_none());
2959 match e.kind {
2960 AsmErrorKind::UseOfTildeNot => (),
2961 x => panic!("{:?}", x),
2962 }
2963 }
2964 }
2965}
2966#[test]
2967fn test_extract_header() {
2968 let mut c = create_context();
2969
2970 assert_eq!(c.extract_header("").unwrap(), (None, 0));
2971 assert_eq!(c.label_def, None);
2972 assert_eq!(c.times, None);
2973
2974 assert_eq!(c.extract_header(" \t ").unwrap(), (None, 0));
2975 assert_eq!(c.label_def, None);
2976 assert_eq!(c.times, None);
2977
2978 assert_eq!(c.extract_header(" \t ; this is a comment ").unwrap(), (None, 0));
2979 assert_eq!(c.label_def, None);
2980 assert_eq!(c.times, None);
2981
2982 assert_eq!(c.extract_header(" label: ; this is a comment ").unwrap(), (None, 8));
2983 assert_eq!(c.label_def.as_ref().unwrap().0, "label");
2984 assert_eq!(c.label_def.as_ref().unwrap().1, Locality::Nonlocal);
2985 assert_eq!(c.times, None);
2986
2987 match c.extract_header(" label%^: ; this is a comment ") {
2988 Ok(_) => panic!(),
2989 Err(e) => {
2990 assert_eq!(e.pos, Some(2));
2991 assert!(matches!(e.kind, AsmErrorKind::InvalidSymbolName));
2992 }
2993 }
2994
2995 match c.extract_header(" .top: ; this is a comment ") {
2996 Ok(_) => panic!(),
2997 Err(e) => {
2998 assert_eq!(e.pos, Some(2));
2999 assert!(matches!(e.kind, AsmErrorKind::LocalSymbolBeforeNonlocal));
3000 }
3001 }
3002 c.last_nonlocal_label = Some("thingy".into());
3003 assert_eq!(c.extract_header(" .top: ; this is a comment ").unwrap(), (None, 7));
3004 assert_eq!(c.label_def.as_ref().unwrap().0, "thingy.top");
3005 assert_eq!(c.label_def.as_ref().unwrap().1, Locality::Local);
3006 assert_eq!(c.times, None);
3007
3008 assert_eq!(c.extract_header(" times 45 nop ; this is a comment ").unwrap(), (Some((None, (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 11))), 14));
3009 assert_eq!(c.label_def, None);
3010 assert_eq!(c.times, Some(TimesInfo { total_count: 45, current: 0 }));
3011
3012 match c.extract_header(" times 45 ; this is a comment ") {
3013 Ok(_) => panic!(),
3014 Err(e) => {
3015 assert_eq!(e.pos, Some(2));
3016 assert!(matches!(e.kind, AsmErrorKind::TimesUsedOnEmptyLine));
3017 }
3018 }
3019 match c.extract_header(" times abc ; this is a comment ") {
3020 Ok(_) => panic!(),
3021 Err(e) => {
3022 assert_eq!(e.pos, Some(2));
3023 assert!(matches!(e.kind, AsmErrorKind::FailedCriticalExpression(_)));
3024 }
3025 }
3026 match c.extract_header(" times -45 ; this is a comment ") {
3027 Ok(_) => panic!(),
3028 Err(e) => {
3029 assert_eq!(e.pos, Some(2));
3030 assert!(matches!(e.kind, AsmErrorKind::TimesCountWasNegative));
3031 }
3032 }
3033
3034 match c.extract_header(" times 5 UNKNOWN_COMMAND ; this is a comment ") {
3035 Ok(_) => panic!(),
3036 Err(e) => {
3037 assert_eq!(e.pos, Some(10));
3038 assert!(matches!(e.kind, AsmErrorKind::UnrecognizedInstruction));
3039 }
3040 }
3041 match c.extract_header(" UNKNOWN_COMMAND ; this is a comment ") {
3042 Ok(_) => panic!(),
3043 Err(e) => {
3044 assert_eq!(e.pos, Some(3));
3045 assert!(matches!(e.kind, AsmErrorKind::UnrecognizedInstruction));
3046 }
3047 }
3048
3049 assert_eq!(c.extract_header(" label: tiMEs 5 NoP ; this is a comment ").unwrap(), (Some((None, (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 17))), 20));
3050 assert_eq!(c.label_def.as_ref().unwrap().0, "label");
3051 assert_eq!(c.label_def.as_ref().unwrap().1, Locality::Nonlocal);
3052 assert_eq!(c.times, Some(TimesInfo { total_count: 5, current: 0 }));
3053
3054 assert_eq!(c.extract_header(" label: tiMEs 0 NoP ; this is a comment ").unwrap(), (Some((None, (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 17))), 20));
3055 assert_eq!(c.label_def.as_ref().unwrap().0, "label");
3056 assert_eq!(c.label_def.as_ref().unwrap().1, Locality::Nonlocal);
3057 assert_eq!(c.times, Some(TimesInfo { total_count: 0, current: 0 }));
3058
3059 assert_eq!(c.extract_header(" merp: NoP ; this is a comment ").unwrap(), (Some((None, (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 8))), 11));
3060 assert_eq!(c.label_def.as_ref().unwrap().0, "merp");
3061 assert_eq!(c.label_def.as_ref().unwrap().1, Locality::Nonlocal);
3062 assert_eq!(c.times, None);
3063
3064 assert_eq!(c.extract_header(" NoP ; this is a comment ").unwrap(), (Some((None, (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 2))), 5));
3065 assert_eq!(c.label_def, None);
3066 assert_eq!(c.times, None);
3067
3068 assert_eq!(c.extract_header(" NoP; this is a comment ").unwrap(), (Some((None, (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 2))), 5));
3069 assert_eq!(c.label_def, None);
3070 assert_eq!(c.times, None);
3071
3072 assert_eq!(c.extract_header(" lab: if true nop ' ; this is a comment ").unwrap(), (Some((None, (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 14))), 17));
3073 assert_eq!(c.label_def.as_ref().unwrap().0, "lab");
3074 assert_eq!(c.label_def.as_ref().unwrap().1, Locality::Nonlocal);
3075 assert_eq!(c.times, Some(TimesInfo { total_count: 1, current: 0 }));
3076
3077 assert_eq!(c.extract_header(" .lab2: if false nop ' ; this is a comment ").unwrap(), (Some((None, (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 17))), 20));
3078 assert_eq!(c.label_def.as_ref().unwrap().0, "thingy.lab2");
3079 assert_eq!(c.label_def.as_ref().unwrap().1, Locality::Local);
3080 assert_eq!(c.times, Some(TimesInfo { total_count: 0, current: 0 }));
3081
3082 match c.extract_header(" rax: ; this is a comment ") {
3083 Ok(_) => panic!(),
3084 Err(e) => {
3085 assert_eq!(e.pos, Some(3));
3086 assert!(matches!(e.kind, AsmErrorKind::ReservedSymbolName));
3087 }
3088 }
3089
3090 assert_eq!(c.extract_header(" reP NoP ").unwrap(), (Some((Some((Prefix::REP, 2)), (Instruction::NoArg { op: Some(OPCode::NOP as u8), ext_op: None }, 6))), 9));
3091 assert_eq!(c.label_def, None);
3092 assert_eq!(c.times, None);
3093
3094 match c.extract_header(" reP ") {
3095 Ok(_) => panic!(),
3096 Err(e) => {
3097 assert_eq!(e.pos, Some(2));
3098 assert!(matches!(e.kind, AsmErrorKind::PrefixWithoutInstruction));
3099 }
3100 }
3101}
3102#[test]
3103fn test_unexpected_string() {
3104 let mut c = create_context();
3105 match c.extract_arg(" 37'hello' ", 1, 13) {
3106 Ok((x, aft)) => {
3107 assert_eq!(aft, 4);
3108 match x {
3109 Argument::Imm(imm) => {
3110 assert_eq!(imm.size, None);
3111 match &*imm.expr.eval(&c.file.symbols).unwrap() {
3112 Value::Integer(v) => assert_eq!(*v, 37),
3113 x => panic!("{:?}", x),
3114 }
3115 }
3116 _ => panic!("{:?}", x),
3117 }
3118 }
3119 Err(e) => panic!("{:?}", e),
3120 }
3121 match c.extract_arg(" (37'hello') ", 1, 15) {
3122 Ok((x, _)) => panic!("{:?}", x),
3123 Err(e) => {
3124 match e.kind {
3125 AsmErrorKind::ParenInteriorNotExpr => (),
3126 k => panic!("{:?}", k),
3127 }
3128 assert_eq!(e.pos, Some(2));
3129 assert!(e.inner_err.is_none());
3130 }
3131 }
3132 match c.extract_arg(" (37'hello' ", 1, 14) {
3133 Ok((x, _)) => panic!("{:?}", x),
3134 Err(e) => {
3135 match e.kind {
3136 AsmErrorKind::UnclosedParen => (),
3137 k => panic!("{:?}", k),
3138 }
3139 assert_eq!(e.pos, Some(2));
3140 assert!(e.inner_err.is_none());
3141 }
3142 }
3143 match c.extract_arg(" (37'hello) ", 1, 14) {
3144 Ok((x, _)) => panic!("{:?}", x),
3145 Err(e) => {
3146 match e.kind {
3147 AsmErrorKind::IncompleteString => (),
3148 k => panic!("{:?}", k),
3149 }
3150 assert_eq!(e.pos, Some(5));
3151 assert!(e.inner_err.is_none());
3152 }
3153 }
3154 match c.extract_arg(" (37'hello ", 1, 13) {
3155 Ok((x, _)) => panic!("{:?}", x),
3156 Err(e) => {
3157 match e.kind {
3158 AsmErrorKind::IncompleteString => (),
3159 k => panic!("{:?}", k),
3160 }
3161 assert_eq!(e.pos, Some(5));
3162 assert!(e.inner_err.is_none());
3163 }
3164 }
3165}
3166#[test]
3167fn test_unexpected_open_paren() {
3168 let mut c = create_context();
3169 match c.extract_arg(" 37(hello' ", 1, 13) {
3170 Ok((x, aft)) => {
3171 assert_eq!(aft, 4);
3172 match x {
3173 Argument::Imm(imm) => {
3174 assert_eq!(imm.size, None);
3175 match &*imm.expr.eval(&c.file.symbols).unwrap() {
3176 Value::Integer(v) => assert_eq!(*v, 37),
3177 x => panic!("{:?}", x),
3178 }
3179 }
3180 _ => panic!("{:?}", x),
3181 }
3182 }
3183 Err(e) => panic!("{:?}", e),
3184 }
3185 match c.extract_arg(" (37(hello)) ", 1, 15) {
3186 Ok((x, _)) => panic!("{:?}", x),
3187 Err(e) => {
3188 match e.kind {
3189 AsmErrorKind::ParenInteriorNotExpr => (),
3190 k => panic!("{:?}", k),
3191 }
3192 assert_eq!(e.pos, Some(2));
3193 assert!(e.inner_err.is_none());
3194 }
3195 }
3196 match c.extract_arg(" (37(hello) ", 1, 14) {
3197 Ok((x, _)) => panic!("{:?}", x),
3198 Err(e) => {
3199 match e.kind {
3200 AsmErrorKind::UnclosedParen => (),
3201 k => panic!("{:?}", k),
3202 }
3203 assert_eq!(e.pos, Some(2));
3204 assert!(e.inner_err.is_none());
3205 }
3206 }
3207}