diff --git a/src/lexical_analysis/mod.rs b/src/lexical_analysis/mod.rs index d954ad84..11b80e4a 100644 --- a/src/lexical_analysis/mod.rs +++ b/src/lexical_analysis/mod.rs @@ -22,16 +22,24 @@ impl LexicalAnalysis<'_> { fn parse_source_code(&mut self) -> anyhow::Result> { fn parse_context(context: &str) -> anyhow::Result { - match ( - parse_integer(context), - parse_keyword(context), - parse_identifier(context), - ) { - (Some(integer), None, None) => Ok(integer), - // When it is a valid keyword and identifier, then it is a keyword. - (None, Some(keyword), _) => Ok(keyword), - (None, None, Some(identifier)) => Ok(identifier), - (_, _, _) => { + match (parse_integer(context), parse_identifier(context)) { + (IntegerParseOutcome::Valid(integer), IdentifierParseOutcome::NotAnIdentifier) => { + Ok(integer) + } + (IntegerParseOutcome::OutOfRange, IdentifierParseOutcome::NotAnIdentifier) => { + anyhow::bail!( + "The integer literal {:?} does not fit into a signed 64 bit integer.", + context + ) + } + (IntegerParseOutcome::NotAnInteger, IdentifierParseOutcome::Keyword(keyword)) => { + Ok(keyword) + } + ( + IntegerParseOutcome::NotAnInteger, + IdentifierParseOutcome::Identifier(identifier), + ) => Ok(identifier), + (_, _) => { anyhow::bail!("Unparsable context for lexical analysis {:?}.", context) } } @@ -156,33 +164,46 @@ impl LexicalAnalysis<'_> { } } -fn parse_keyword(parsing: &str) -> Option { - match parsing.to_lowercase().as_str() { - "fn" => Some(Token::Function), - "let" => Some(Token::Let), - "true" => Some(Token::True), - "false" => Some(Token::False), - "if" => Some(Token::If), - "else" => Some(Token::Else), - "return" => Some(Token::Return), - _ => None, - } +enum IntegerParseOutcome { + Valid(Token), + OutOfRange, + NotAnInteger, } -fn parse_integer(parsing: &str) -> Option { +fn parse_integer(parsing: &str) -> IntegerParseOutcome { match parsing.parse() { - Ok(integer) => Some(Token::Integer { literal: integer }), - Err(_) => None, + Ok(literal) => IntegerParseOutcome::Valid(Token::Integer { literal }), + Err(error) => match error.kind() { + std::num::IntErrorKind::PosOverflow | std::num::IntErrorKind::NegOverflow => { + IntegerParseOutcome::OutOfRange + } + _ => IntegerParseOutcome::NotAnInteger, + }, } } -fn parse_identifier(parsing: &str) -> Option { - if is_valid_identifier(parsing) { - Some(Token::Identifier { +enum IdentifierParseOutcome { + Keyword(Token), + Identifier(Token), + NotAnIdentifier, +} + +fn parse_identifier(parsing: &str) -> IdentifierParseOutcome { + if !is_valid_identifier(parsing) { + return IdentifierParseOutcome::NotAnIdentifier; + } + + match parsing.to_lowercase().as_str() { + "fn" => IdentifierParseOutcome::Keyword(Token::Function), + "let" => IdentifierParseOutcome::Keyword(Token::Let), + "true" => IdentifierParseOutcome::Keyword(Token::True), + "false" => IdentifierParseOutcome::Keyword(Token::False), + "if" => IdentifierParseOutcome::Keyword(Token::If), + "else" => IdentifierParseOutcome::Keyword(Token::Else), + "return" => IdentifierParseOutcome::Keyword(Token::Return), + _ => IdentifierParseOutcome::Identifier(Token::Identifier { literal: parsing.to_string(), - }) - } else { - None + }), } } diff --git a/src/tests/lexical_analysis_error/invalid_integer_expression/mod.rs b/src/tests/lexical_analysis_error/invalid_integer_expression/mod.rs index b72874fd..a2a40e3d 100644 --- a/src/tests/lexical_analysis_error/invalid_integer_expression/mod.rs +++ b/src/tests/lexical_analysis_error/invalid_integer_expression/mod.rs @@ -6,7 +6,8 @@ use super::*; snapshot_name, case("51a23", "invalid_integer_expression_case_1"), case(" 123.0", "invalid_integer_expression_case_2"), - case("\t0xFF", "invalid_integer_expression_case_3") + case("\t0xFF", "invalid_integer_expression_case_3"), + case("99999999999999999999", "invalid_integer_expression_case_4") )] fn invalid_integer_expression_cases(code: &str, snapshot_name: &str) {} diff --git a/src/tests/lexical_analysis_error/invalid_integer_expression/snapshots/monkey_interpreter__tests__lexical_analysis_error__invalid_integer_expression__test_invalid_integer_expression_case_4_lexical_analysis_error.snap b/src/tests/lexical_analysis_error/invalid_integer_expression/snapshots/monkey_interpreter__tests__lexical_analysis_error__invalid_integer_expression__test_invalid_integer_expression_case_4_lexical_analysis_error.snap new file mode 100644 index 00000000..7f9e674f --- /dev/null +++ b/src/tests/lexical_analysis_error/invalid_integer_expression/snapshots/monkey_interpreter__tests__lexical_analysis_error__invalid_integer_expression__test_invalid_integer_expression_case_4_lexical_analysis_error.snap @@ -0,0 +1,8 @@ +--- +source: src/tests/lexical_analysis_error/invalid_integer_expression/mod.rs +assertion_line: 19 +expression: error +--- +Err( + "The integer literal \"99999999999999999999\" does not fit into a signed 64 bit integer.", +)