Skip to content

Commit 7c14910

Browse files
committed
cranelift: Deduplicate match_imm functions
Transforming this into a generic function is proving to be a challenge since most of the necessary methods are not in a trait. We also need to cast between the signed and unsigned types, which is difficult to do in a generic function. This can be solved for example by adding the num crate as a dependency. But adding a dependency just to solve this issue seems a bit much.
1 parent eae1b2d commit 7c14910

File tree

1 file changed

+49
-156
lines changed

1 file changed

+49
-156
lines changed

cranelift/reader/src/parser.rs

Lines changed: 49 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,51 @@ use std::str::FromStr;
3131
use std::{u16, u32};
3232
use target_lexicon::Triple;
3333

34+
macro_rules! match_imm {
35+
($signed:ty, $unsigned:ty, $parser:expr, $err_msg:expr) => {{
36+
if let Some(Token::Integer(text)) = $parser.token() {
37+
$parser.consume();
38+
let negative = text.starts_with('-');
39+
let positive = text.starts_with('+');
40+
let text = if negative || positive {
41+
// Strip sign prefix.
42+
&text[1..]
43+
} else {
44+
text
45+
};
46+
47+
// Parse the text value; the lexer gives us raw text that looks like an integer.
48+
let value = if text.starts_with("0x") {
49+
// Skip underscores.
50+
let text = text.replace("_", "");
51+
// Parse it in hexadecimal form.
52+
<$unsigned>::from_str_radix(&text[2..], 16).map_err(|_| {
53+
$parser.error("unable to parse value as a hexadecimal immediate")
54+
})?
55+
} else {
56+
// Parse it as a signed type to check for overflow and other issues.
57+
text.parse()
58+
.map_err(|_| $parser.error("expected decimal immediate"))?
59+
};
60+
61+
// Apply sign if necessary.
62+
let signed = if negative {
63+
let value = value.wrapping_neg() as $signed;
64+
if value > 0 {
65+
return Err($parser.error("negative number too small"));
66+
}
67+
value
68+
} else {
69+
value as $signed
70+
};
71+
72+
Ok(signed)
73+
} else {
74+
err!($parser.loc, $err_msg)
75+
}
76+
}};
77+
}
78+
3479
/// After some quick benchmarks a program should never have more than 100,000 blocks.
3580
const MAX_BLOCKS_IN_A_FUNCTION: u32 = 100_000;
3681

@@ -793,175 +838,23 @@ impl<'a> Parser<'a> {
793838

794839
// Match and consume an i8 immediate.
795840
fn match_imm8(&mut self, err_msg: &str) -> ParseResult<i8> {
796-
if let Some(Token::Integer(text)) = self.token() {
797-
self.consume();
798-
let negative = text.starts_with('-');
799-
let positive = text.starts_with('+');
800-
let text = if negative || positive {
801-
// Strip sign prefix.
802-
&text[1..]
803-
} else {
804-
text
805-
};
806-
807-
// Parse the text value; the lexer gives us raw text that looks like an integer.
808-
let value = if text.starts_with("0x") {
809-
// Skip underscores.
810-
let text = text.replace("_", "");
811-
// Parse it as a i8 in hexadecimal form.
812-
u8::from_str_radix(&text[2..], 16)
813-
.map_err(|_| self.error("unable to parse i8 as a hexadecimal immediate"))?
814-
} else {
815-
// Parse it as a i8 to check for overflow and other issues.
816-
text.parse()
817-
.map_err(|_| self.error("expected i8 decimal immediate"))?
818-
};
819-
820-
// Apply sign if necessary.
821-
let signed = if negative {
822-
let value = value.wrapping_neg() as i8;
823-
if value > 0 {
824-
return Err(self.error("negative number too small"));
825-
}
826-
value
827-
} else {
828-
value as i8
829-
};
830-
831-
Ok(signed)
832-
} else {
833-
err!(self.loc, err_msg)
834-
}
841+
match_imm!(i8, u8, self, err_msg)
835842
}
836843

837844
// Match and consume a signed 16-bit immediate.
838845
fn match_imm16(&mut self, err_msg: &str) -> ParseResult<i16> {
839-
if let Some(Token::Integer(text)) = self.token() {
840-
self.consume();
841-
let negative = text.starts_with('-');
842-
let positive = text.starts_with('+');
843-
let text = if negative || positive {
844-
// Strip sign prefix.
845-
&text[1..]
846-
} else {
847-
text
848-
};
849-
850-
// Parse the text value; the lexer gives us raw text that looks like an integer.
851-
let value = if text.starts_with("0x") {
852-
// Skip underscores.
853-
let text = text.replace("_", "");
854-
// Parse it as a i16 in hexadecimal form.
855-
u16::from_str_radix(&text[2..], 16)
856-
.map_err(|_| self.error("unable to parse i16 as a hexadecimal immediate"))?
857-
} else {
858-
// Parse it as a i16 to check for overflow and other issues.
859-
text.parse()
860-
.map_err(|_| self.error("expected i16 decimal immediate"))?
861-
};
862-
863-
// Apply sign if necessary.
864-
let signed = if negative {
865-
let value = value.wrapping_neg() as i16;
866-
if value > 0 {
867-
return Err(self.error("negative number too small"));
868-
}
869-
value
870-
} else {
871-
value as i16
872-
};
873-
874-
Ok(signed)
875-
} else {
876-
err!(self.loc, err_msg)
877-
}
846+
match_imm!(i16, u16, self, err_msg)
878847
}
879848

880849
// Match and consume an i32 immediate.
881850
// This is used for stack argument byte offsets.
882851
fn match_imm32(&mut self, err_msg: &str) -> ParseResult<i32> {
883-
if let Some(Token::Integer(text)) = self.token() {
884-
self.consume();
885-
let negative = text.starts_with('-');
886-
let positive = text.starts_with('+');
887-
let text = if negative || positive {
888-
// Strip sign prefix.
889-
&text[1..]
890-
} else {
891-
text
892-
};
893-
894-
// Parse the text value; the lexer gives us raw text that looks like an integer.
895-
let value = if text.starts_with("0x") {
896-
// Skip underscores.
897-
let text = text.replace("_", "");
898-
// Parse it as a i32 in hexadecimal form.
899-
u32::from_str_radix(&text[2..], 16)
900-
.map_err(|_| self.error("unable to parse i32 as a hexadecimal immediate"))?
901-
} else {
902-
// Parse it as a i32 to check for overflow and other issues.
903-
text.parse()
904-
.map_err(|_| self.error("expected i32 decimal immediate"))?
905-
};
906-
907-
// Apply sign if necessary.
908-
let signed = if negative {
909-
let value = value.wrapping_neg() as i32;
910-
if value > 0 {
911-
return Err(self.error("negative number too small"));
912-
}
913-
value
914-
} else {
915-
value as i32
916-
};
917-
918-
Ok(signed)
919-
} else {
920-
err!(self.loc, err_msg)
921-
}
852+
match_imm!(i32, u32, self, err_msg)
922853
}
923854

924855
// Match and consume an i128 immediate.
925856
fn match_imm128(&mut self, err_msg: &str) -> ParseResult<i128> {
926-
if let Some(Token::Integer(text)) = self.token() {
927-
self.consume();
928-
let negative = text.starts_with('-');
929-
let positive = text.starts_with('+');
930-
let text = if negative || positive {
931-
// Strip sign prefix.
932-
&text[1..]
933-
} else {
934-
text
935-
};
936-
937-
// Parse the text value; the lexer gives us raw text that looks like an integer.
938-
let value = if text.starts_with("0x") {
939-
// Skip underscores.
940-
let text = text.replace("_", "");
941-
// Parse it as a i128 in hexadecimal form.
942-
u128::from_str_radix(&text[2..], 16)
943-
.map_err(|_| self.error("unable to parse i128 as a hexadecimal immediate"))?
944-
} else {
945-
// Parse it as a i128 to check for overflow and other issues.
946-
text.parse()
947-
.map_err(|_| self.error("expected i128 decimal immediate"))?
948-
};
949-
950-
// Apply sign if necessary.
951-
let signed = if negative {
952-
let value = value.wrapping_neg() as i128;
953-
if value > 0 {
954-
return Err(self.error("negative number too small"));
955-
}
956-
value
957-
} else {
958-
value as i128
959-
};
960-
961-
Ok(signed)
962-
} else {
963-
err!(self.loc, err_msg)
964-
}
857+
match_imm!(i128, u128, self, err_msg)
965858
}
966859

967860
// Match and consume an optional offset32 immediate.

0 commit comments

Comments
 (0)