diff --git a/huff_core/tests/parser_errors.rs b/huff_core/tests/parser_errors.rs index a41a7c2e..21feb713 100644 --- a/huff_core/tests/parser_errors.rs +++ b/huff_core/tests/parser_errors.rs @@ -42,6 +42,7 @@ fn test_invalid_macro_statement() { kind: ParserErrorKind::InvalidTokenInMacroBody(TokenKind::FreeStoragePointer), hint: None, spans: AstSpan(vec![Span { start: const_start, end: const_end, file: None }]), + cursor: 36, } ) } @@ -72,6 +73,7 @@ fn test_unexpected_type() { end: source.find("internal").unwrap_or(0) + "internal".len() - 1, file: None }]), + cursor: 5, } ) } @@ -103,6 +105,7 @@ fn test_invalid_definition() { end: source.find("invalid").unwrap_or(0) + "invalid".len() - 1, file: None }]), + cursor: 1, } ) } @@ -147,6 +150,7 @@ fn test_invalid_constant_value() { end: source.find(value).unwrap_or(0) + value.len() - 1, file: None }]), + cursor: 4 } ) } @@ -191,6 +195,7 @@ fn test_invalid_token_in_macro_body() { end: source.rfind(value).unwrap_or(0) + value.len() - 1, file: None }]), + cursor: 15, } ) } @@ -236,6 +241,7 @@ fn test_invalid_token_in_label_definition() { end: source.rfind(value).unwrap_or(0) + value.len() - 1, file: None }]), + cursor: 17, } ) } @@ -279,6 +285,7 @@ fn test_invalid_single_arg() { ))), hint: Some("Expected number representing stack item count.".to_string()), spans: AstSpan(vec![Span { start: 34, end: 34, file: None }]), + cursor: 8, } ) } diff --git a/huff_parser/src/lib.rs b/huff_parser/src/lib.rs index 7d1c0d42..fc7589b7 100644 --- a/huff_parser/src/lib.rs +++ b/huff_parser/src/lib.rs @@ -120,6 +120,7 @@ impl Parser { kind: ParserErrorKind::InvalidDefinition(self.current_token.kind.clone()), hint: Some("Definition must be one of: `function`, `event`, `constant`, `error`, `macro`, `fn`, or `test`.".to_string()), spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }); } }; @@ -133,6 +134,7 @@ impl Parser { TokenKind::Include )), spans: AstSpan(self.spans.clone()), + cursor: self.cursor, }); } } @@ -158,6 +160,7 @@ impl Parser { kind: ParserErrorKind::InvalidName(tok.clone()), hint: Some(format!("Expected import string. Got: \"{tok}\"")), spans: AstSpan(new_spans), + cursor: self.cursor, }); } }; @@ -177,6 +180,7 @@ impl Parser { kind: ParserErrorKind::UnexpectedType(self.current_token.kind.clone()), hint: Some(format!("Expected: \"{kind}\"")), spans: AstSpan(self.spans.clone()), + cursor: self.cursor, }) } } @@ -198,6 +202,7 @@ impl Parser { kind: ParserErrorKind::DuplicateMacro(m.name.to_owned()), hint: Some("MACRO names should be unique".to_string()), spans: AstSpan(vec![m.span[2].clone()]), + cursor: self.cursor, }) } else { Ok(()) @@ -257,6 +262,7 @@ impl Parser { kind: ParserErrorKind::InvalidName(tok.clone()), hint: Some(format!("Expected function name, found: \"{tok}\"")), spans: AstSpan(self.spans.clone()), + cursor: self.cursor, }); } }; @@ -276,6 +282,7 @@ impl Parser { "Expected one of: `view`, `pure`, `payable`, `nonpayable`.".to_string(), ), spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }) } }; @@ -319,6 +326,7 @@ impl Parser { kind: ParserErrorKind::InvalidName(tok.clone()), hint: Some(format!("Expected event name, found: \"{tok}\"")), spans: AstSpan(self.spans.clone()), + cursor: self.cursor, }); } }; @@ -350,6 +358,7 @@ impl Parser { kind: ParserErrorKind::UnexpectedType(tok), hint: Some("Expected constant name.".to_string()), spans: AstSpan(self.spans.clone()), + cursor: self.cursor, }); } }; @@ -375,6 +384,7 @@ impl Parser { .to_string(), ), spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }); } }; @@ -403,6 +413,7 @@ impl Parser { kind: ParserErrorKind::UnexpectedType(tok), hint: Some("Expected error name.".to_string()), spans: AstSpan(self.spans.clone()), + cursor: self.cursor, }); } }; @@ -450,6 +461,7 @@ impl Parser { ), hint: Some(format!("Expected string for decorator flag: {s}")), spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }); } } @@ -466,6 +478,7 @@ impl Parser { ), hint: Some(format!("Expected literal for decorator flag: {s}")), spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }); } } @@ -475,6 +488,7 @@ impl Parser { kind: ParserErrorKind::InvalidDecoratorFlag(s.clone()), hint: Some(format!("Unknown decorator flag: {s}")), spans: AstSpan(self.spans.clone()), + cursor: self.cursor, }); } } @@ -493,6 +507,7 @@ impl Parser { )), hint: Some(String::from("Unknown decorator flag")), spans: AstSpan(self.spans.clone()), + cursor: self.cursor, }); } } @@ -597,6 +612,7 @@ impl Parser { "Literal {hex_literal:?} contains too many bytes for opcode \"{o:?}\"" )), spans: AstSpan(curr_spans), + cursor: self.cursor, }); } @@ -614,6 +630,7 @@ impl Parser { o, self.current_token.kind )), spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }) } } @@ -704,6 +721,7 @@ impl Parser { kind: ParserErrorKind::InvalidTokenInMacroBody(kind), hint: None, spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }); } }; @@ -817,6 +835,7 @@ impl Parser { kind: ParserErrorKind::InvalidTokenInLabelDefinition(kind), hint: None, spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }); } }; @@ -948,6 +967,7 @@ impl Parser { "Argument names cannot be EVM types: {arg_str}" )), spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }); } } @@ -958,6 +978,7 @@ impl Parser { ), hint: Some(format!("Argument names cannot be EVM types: {ty}")), spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }) } _ => { /* continue, valid string */ } @@ -981,6 +1002,7 @@ impl Parser { kind: ParserErrorKind::InvalidArgs(self.current_token.kind.clone()), hint: None, spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }); } @@ -1004,6 +1026,7 @@ impl Parser { kind: ParserErrorKind::InvalidSingleArg(self.current_token.kind.clone()), hint: Some("Expected number representing stack item count.".to_string()), spans: AstSpan(single_arg_span), + cursor: self.cursor, }) } }; @@ -1059,6 +1082,7 @@ impl Parser { .to_string(), ), spans: AstSpan(new_spans), + cursor: self.cursor, }); } } @@ -1147,7 +1171,8 @@ impl Parser { ), hint: Some("Expected valid hex bytecode.".to_string()), spans: AstSpan(new_spans), - }); + cursor: self.cursor, + }) } } else { StatementType::LabelCall(ident_str.to_string()) @@ -1162,7 +1187,8 @@ impl Parser { kind: ParserErrorKind::InvalidTableBodyToken(kind.clone()), hint: Some("Expected an identifier string.".to_string()), spans: AstSpan(new_spans), - }); + cursor: self.cursor, + }) } }; } @@ -1189,6 +1215,7 @@ impl Parser { kind: ParserErrorKind::InvalidConstant(kind), hint: None, spans: AstSpan(new_spans), + cursor: self.cursor, }) } } @@ -1221,6 +1248,7 @@ impl Parser { kind: ParserErrorKind::InvalidArgCallIdent(kind), hint: None, spans: AstSpan(new_spans), + cursor: self.cursor, }) } } @@ -1250,6 +1278,7 @@ impl Parser { kind: ParserErrorKind::InvalidArgs(kind), hint: None, spans: AstSpan(vec![self.current_token.span.clone()]), + cursor: self.cursor, }), } } @@ -1267,7 +1296,8 @@ impl Parser { kind: ParserErrorKind::InvalidUint256(size), hint: None, spans: AstSpan(vec![self.current_token.span.clone()]), - }); + cursor: self.cursor, + }) } Ok(self.match_kind(self.current_token.kind.clone())?) } @@ -1277,7 +1307,8 @@ impl Parser { kind: ParserErrorKind::InvalidBytes(size), hint: None, spans: AstSpan(vec![self.current_token.span.clone()]), - }); + cursor: self.cursor, + }) } Ok(self.match_kind(self.current_token.kind.clone())?) } @@ -1291,7 +1322,8 @@ impl Parser { kind: ParserErrorKind::InvalidInt(size), hint: None, spans: AstSpan(vec![self.current_token.span.clone()]), - }); + cursor: self.cursor, + }) } let curr_token_kind = self.current_token.kind.clone(); self.consume(); diff --git a/huff_parser/tests/macro.rs b/huff_parser/tests/macro.rs index a2017997..f8ed7a8a 100644 --- a/huff_parser/tests/macro.rs +++ b/huff_parser/tests/macro.rs @@ -1291,6 +1291,7 @@ fn test_duplicate_macro_error() { end: occurrences[1].1, file: None }]), + cursor: 58, } ) } diff --git a/huff_utils/src/error.rs b/huff_utils/src/error.rs index d0e90a1b..f942fc75 100644 --- a/huff_utils/src/error.rs +++ b/huff_utils/src/error.rs @@ -16,6 +16,8 @@ pub struct ParserError { pub hint: Option, /// A collection of spans the Parser Error crosses pub spans: AstSpan, + /// Line number where the error was seen + pub cursor: usize, } /// A Type of Parser Error @@ -326,7 +328,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidPush(op) => { write!( f, - "\nError: Invalid use of \"{:?}\" \n{}\n", + "\nError at token {}: Invalid use of \"{:?}\" \n{}\n", + pe.cursor, op, pe.spans.error(pe.hint.as_ref()) ) @@ -334,7 +337,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::UnexpectedType(ut) => { write!( f, - "\nError: Unexpected Type: \"{}\" \n{}\n", + "\nError at token {}: Unexpected Type: \"{}\" \n{}\n", + pe.cursor, ut, pe.spans.error(pe.hint.as_ref()) ) @@ -342,7 +346,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidTypeAsArgumentName(ut) => { write!( f, - "\nError: Unexpected Argument Name is an EVM Type: \"{}\" \n{}\n", + "\nError at token {}: Unexpected Argument Name is an EVM Type: \"{}\" \n{}\n", + pe.cursor, ut, pe.spans.error(pe.hint.as_ref()) ) @@ -350,7 +355,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidDefinition(k) => { write!( f, - "\nError: Invalid Defintion \"{}\"\n{}\n", + "\nError at token {}: Invalid Defintion \"{}\"\n{}\n", + pe.cursor, k, pe.spans.error(pe.hint.as_ref()) ) @@ -358,7 +364,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidConstantValue(cv) => { write!( f, - "\nError: Invalid Constant Value: \"{}\" \n{}\n", + "\nError at token {}: Invalid Constant Value: \"{}\" \n{}\n", + pe.cursor, cv, pe.spans.error(pe.hint.as_ref()) ) @@ -366,7 +373,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidTokenInMacroBody(tmb) => { write!( f, - "\nError: Invalid Token In Macro Body: \"{}\" \n{}\n", + "\nError at token {}: Invalid Token In Macro Body: \"{}\" \n{}\n", + pe.cursor, tmb, pe.spans.error(pe.hint.as_ref()) ) @@ -374,7 +382,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidTokenInLabelDefinition(tlb) => { write!( f, - "\nError: Invalid Token In Label Defintiion: \"{}\" \n{}\n", + "\nError at token {}: Invalid Token In Label Defintiion: \"{}\" \n{}\n", + pe.cursor, tlb, pe.spans.error(pe.hint.as_ref()) ) @@ -382,7 +391,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidSingleArg(sa) => { write!( f, - "\nError: Invalid Argument: \"{}\" \n{}\n", + "\nError at token {}: Invalid Argument: \"{}\" \n{}\n", + pe.cursor, sa, pe.spans.error(pe.hint.as_ref()) ) @@ -390,7 +400,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidTableBodyToken(tbt) => { write!( f, - "\nError: Invalid Token In Table Body: \"{}\" \n{}\n", + "\nError at token {}: Invalid Token In Table Body: \"{}\" \n{}\n", + pe.cursor, tbt, pe.spans.error(pe.hint.as_ref()) ) @@ -398,7 +409,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidConstant(constant) => { write!( f, - "\nError: Invalid Constant: \"{}\" \n{}\n", + "\nError at token {}: Invalid Constant: \"{}\" \n{}\n", + pe.cursor, constant, pe.spans.error(pe.hint.as_ref()) ) @@ -406,7 +418,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidArgCallIdent(aci) => { write!( f, - "\nError: Invalid Argument Call Identifier: \"{}\" \n{}\n", + "\nError at token {}: Invalid Argument Call Identifier: \"{}\" \n{}\n", + pe.cursor, aci, pe.spans.error(pe.hint.as_ref()) ) @@ -414,7 +427,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidName(name) => { write!( f, - "\nError: Invalid Name: \"{}\" \n{}\n", + "\nError at token {}: Invalid Name: \"{}\" \n{}\n", + pe.cursor, name, pe.spans.error(pe.hint.as_ref()) ) @@ -422,7 +436,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidArgs(args) => { write!( f, - "\nError: Invalid Argument Type: \"{}\" \n{}\n", + "\nError at token {}: Invalid Argument Type: \"{}\" \n{}\n", + pe.cursor, args, pe.spans.error(pe.hint.as_ref()) ) @@ -430,7 +445,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidUint256(v) => { write!( f, - "\nError: Invalid Uint256 Value: \"{}\" \n{}\n", + "\nError at token {}: Invalid Uint256 Value: \"{}\" \n{}\n", + pe.cursor, v, pe.spans.error(pe.hint.as_ref()) ) @@ -438,7 +454,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidBytes(b) => { write!( f, - "\nError: Invalid Bytes Value: \"{}\" \n{}\n", + "\nError at token {}: Invalid Bytes Value: \"{}\" \n{}\n", + pe.cursor, b, pe.spans.error(pe.hint.as_ref()) ) @@ -446,7 +463,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidInt(i) => { write!( f, - "\nError: Invalid Int Value: \"{}\" \n{}\n", + "\nError at token {}: Invalid Int Value: \"{}\" \n{}\n", + pe.cursor, i, pe.spans.error(pe.hint.as_ref()) ) @@ -454,7 +472,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidMacroArgs(ma) => { write!( f, - "\nError: Invalid Macro Arguments: \"{}\" \n{}\n", + "\nError at token {}: Invalid Macro Arguments: \"{}\" \n{}\n", + pe.cursor, ma, pe.spans.error(pe.hint.as_ref()) ) @@ -462,14 +481,16 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidReturnArgs => { write!( f, - "\nError: Invalid Return Arguments\n{}\n", + "\nError at token {}: Invalid Return Arguments\n{}\n", + pe.cursor, pe.spans.error(pe.hint.as_ref()) ) } ParserErrorKind::InvalidImportPath(ip) => { write!( f, - "\nError: Invalid Import Path: \"{}\" \n{}\n", + "\nError at token {}: Invalid Import Path: \"{}\" \n{}\n", + pe.cursor, ip, pe.spans.error(pe.hint.as_ref()) ) @@ -477,7 +498,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidDecoratorFlag(df) => { write!( f, - "\nError: Invalid Decorator Flag: \"{}\" \n{}\n", + "\nError at token {}: Invalid Decorator Flag: \"{}\" \n{}\n", + pe.cursor, df, pe.spans.error(pe.hint.as_ref()) ) @@ -485,7 +507,8 @@ impl fmt::Display for CompilerError { ParserErrorKind::InvalidDecoratorFlagArg(dfa) => { write!( f, - "\nError: Invalid Decorator Flag Argument: \"{}\" \n{}\n", + "\nError at token {}: Invalid Decorator Flag Argument: \"{}\" \n{}\n", + pe.cursor, dfa, pe.spans.error(pe.hint.as_ref()) )