use super::super::{Argument, Token, TokenArgument, TryFromArgument, TryFromArgumentGroup};
use super::TokenDeserialize;
use df_ls_diagnostics::{hash_map, DMExtraInfo, DiagnosticsInfo};
macro_rules! token_de_integer {
( $x:ty ) => {
crate::token_deserialize_unary_token!($x);
};
}
token_de_integer!(i64);
token_de_integer!(i32);
token_de_integer!(i16);
token_de_integer!(i8);
token_de_integer!(u32);
token_de_integer!(u16);
token_de_integer!(u8);
macro_rules! try_from_argument_group {
( $x:ty ) => {
impl TryFromArgumentGroup for $x {
fn try_from_argument_group(
token: &mut Token,
source: &str,
diagnostics: &mut DiagnosticsInfo,
add_diagnostics_on_err: bool,
) -> Result<Self, ()> {
token.check_as_required_argument(source, diagnostics, add_diagnostics_on_err)?;
let arg = token.get_current_arg_opt();
let result =
Self::try_from_argument(arg, source, diagnostics, add_diagnostics_on_err);
token.consume_argument();
result
}
}
};
}
try_from_argument_group!(i64);
try_from_argument_group!(i32);
try_from_argument_group!(i16);
try_from_argument_group!(i8);
try_from_argument_group!(u32);
try_from_argument_group!(u16);
try_from_argument_group!(u8);
macro_rules! token_argument_into_integer {
( $x:ty, $t:literal ) => {
impl TryFromArgument for $x {
fn try_from_argument(
arg_opt: Option<&Argument>,
_source: &str,
diagnostics: &mut DiagnosticsInfo,
add_diagnostics_on_err: bool,
) -> Result<Self, ()> {
if let Some(arg) = arg_opt {
match arg.value {
TokenArgument::TVInteger(i64_value) => {
if i64_value > (<$x>::MAX as i64) {
if add_diagnostics_on_err {
diagnostics.add_message(
DMExtraInfo {
range: arg.node.get_range(),
message_template_data: hash_map! {
"max_value" => <$x>::MAX.to_string(),
},
},
"too_large_int",
);
}
return Err(());
}
if i64_value < (<$x>::MIN as i64) {
if add_diagnostics_on_err {
diagnostics.add_message(
DMExtraInfo {
range: arg.node.get_range(),
message_template_data: hash_map! {
"min_value" => <$x>::MIN.to_string(),
},
},
"too_small_int",
);
}
return Err(());
}
Ok(i64_value as $x)
}
_ => {
if add_diagnostics_on_err {
diagnostics.add_message(
DMExtraInfo {
range: arg.node.get_range(),
message_template_data: hash_map! {
"expected_parameters" => Self::expected_argument_types(),
"found_parameters" => arg.value.argument_to_token_type_name(),
},
},
"wrong_arg_type",
);
}
Err(())
}
}
} else {
Err(())
}
}
fn expected_argument_types() -> String {
format!("Integer ({})", $t)
}
}
};
}
token_argument_into_integer!(i64, "i64");
token_argument_into_integer!(i32, "i32");
token_argument_into_integer!(i16, "i16");
token_argument_into_integer!(i8, "i8");
token_argument_into_integer!(u32, "u32");
token_argument_into_integer!(u16, "u16");
token_argument_into_integer!(u8, "u8");
macro_rules! token_argument_from_integer {
( $x:ty ) => {
impl From<$x> for TokenArgument {
fn from(item: $x) -> TokenArgument {
TokenArgument::TVInteger(item as i64)
}
}
impl From<Option<$x>> for TokenArgument {
fn from(item: Option<$x>) -> TokenArgument {
match item {
Some(v) => TokenArgument::TVInteger(v as i64),
None => TokenArgument::TVEmpty,
}
}
}
};
}
token_argument_from_integer!(i64);
token_argument_from_integer!(i32);
token_argument_from_integer!(i16);
token_argument_from_integer!(i8);
token_argument_from_integer!(u32);
token_argument_from_integer!(u16);
token_argument_from_integer!(u8);
#[cfg(test)]
mod tests {
use super::*;
use crate::test_tree_structure;
use crate::test_utils::SyntaxTestBuilder;
use df_ls_diagnostics::{Position, Range};
use df_ls_lexical_analysis::test_utils::LexerTestBuilder;
#[test]
fn test_integer_correct() {
let test_builder = SyntaxTestBuilder::from_lexer_test_builder(
LexerTestBuilder::test_source(
"header
[REF:127]
[REF:-127]
[REF:-20]
[REF:1555]
[REF:4294967295]",
)
.add_test_lexer_diagnostics_codes(vec![])
.add_test_lexer_diagnostics_ranges(vec![]),
)
.add_test_syntax_diagnostics_codes(vec![])
.add_test_syntax_diagnostics_ranges(vec![]);
test_tree_structure!(
test_builder,
[
i8 => 127i8,
(i8,) => (-127i8,),
i16 => -20i16,
u16 => 1555u16,
u32 => 4294967295u32,
]
);
}
#[test]
fn test_integer_overflow() {
let test_builder = SyntaxTestBuilder::from_lexer_test_builder(
LexerTestBuilder::test_source(
"header
[REF:130]
[REF:-130]
[REF:-32769]
[REF:-1]
[REF:4294967296]",
)
.add_test_lexer_diagnostics_codes(vec![])
.add_test_lexer_diagnostics_ranges(vec![]),
)
.add_test_syntax_diagnostics_codes(vec![
"too_large_int",
"too_small_int",
"too_small_int",
"too_small_int",
"too_large_int",
])
.add_test_syntax_diagnostics_ranges(vec![
Range {
start: Position {
line: 1,
character: 21,
},
end: Position {
line: 1,
character: 24,
},
},
Range {
start: Position {
line: 2,
character: 21,
},
end: Position {
line: 2,
character: 25,
},
},
Range {
start: Position {
line: 3,
character: 21,
},
end: Position {
line: 3,
character: 27,
},
},
Range {
start: Position {
line: 4,
character: 21,
},
end: Position {
line: 4,
character: 23,
},
},
Range {
start: Position {
line: 5,
character: 21,
},
end: Position {
line: 5,
character: 31,
},
},
]);
test_tree_structure!(
test_builder,
[
i8 =!,
(i8,) =!,
i16 =!,
u16 =!,
u32 =!,
]
);
}
}