Skip to content
This repository has been archived by the owner on Oct 20, 2024. It is now read-only.

add checks for evm types as arg names #204

Merged
merged 4 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions huff_lexer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ impl<'a> Iterator for Lexer<'a> {
}
}

// Check for macro keyword
// Check for free storage pointer builtin
let fsp = "FREE_STORAGE_POINTER";
let token_length = fsp.len() - 1;
let peeked = self.peek_n_chars(token_length);
Expand Down Expand Up @@ -503,8 +503,15 @@ impl<'a> Iterator for Lexer<'a> {
self.dyn_consume(|c| c.is_alphanumeric() || *c == '[' || *c == ']');
// got a type at this point, we have to know which
let raw_type: String = self.slice();
// check for arrays first
if EVM_TYPE_ARRAY_REGEX.is_match(&raw_type) {

// Check if calldata, memory, or storage
if raw_type == TokenKind::Calldata.to_string() {
found_kind = Some(TokenKind::Calldata);
} else if raw_type == TokenKind::Memory.to_string() {
found_kind = Some(TokenKind::Memory);
} else if raw_type == TokenKind::Storage.to_string() {
found_kind = Some(TokenKind::Storage);
} else if EVM_TYPE_ARRAY_REGEX.is_match(&raw_type) {
// split to get array size and type
// TODO: support multi-dimensional arrays
let words: Vec<String> = Regex::new(r"\[")
Expand Down
71 changes: 67 additions & 4 deletions huff_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ impl Parser {
) -> Result<Vec<Argument>, ParserError> {
let mut args: Vec<Argument> = Vec::new();
self.match_kind(TokenKind::OpenParen)?;
let mut on_type = true;
tracing::debug!(target: "parser", "PARSING ARGs: {:?}", self.current_token.kind);
while !self.check(TokenKind::CloseParen) {
if is_builtin {
Expand All @@ -801,6 +802,7 @@ impl Parser {
arg_type: None,
indexed: false,
span: AstSpan(vec![self.current_token.span.clone()]),
arg_location: None,
});

self.consume();
Expand All @@ -812,8 +814,9 @@ impl Parser {
// present.
if let TokenKind::Literal(l) = &self.current_token.kind {
args.push(Argument {
name: Some(bytes32_to_string(l, false)), /* Place the literal in the
* "name" field */
// Place literal in the "name" field
name: Some(bytes32_to_string(l, false)),
arg_location: None,
arg_type: None,
indexed: false,
span: AstSpan(vec![self.current_token.span.clone()]),
Expand All @@ -837,17 +840,73 @@ impl Parser {
arg_spans.push(self.current_token.span.clone());
self.consume(); // consume "indexed" keyword
}
on_type = false;
}

// It can also be a data location
match &self.current_token.kind {
TokenKind::Calldata => {
arg.arg_location = Some(ArgumentLocation::Calldata);
arg_spans.push(self.current_token.span.clone());
self.consume();
}
TokenKind::Memory => {
arg.arg_location = Some(ArgumentLocation::Memory);
arg_spans.push(self.current_token.span.clone());
self.consume();
}
TokenKind::Storage => {
arg.arg_location = Some(ArgumentLocation::Storage);
arg_spans.push(self.current_token.span.clone());
self.consume();
}
_ => {}
}

// name comes second (is optional)
if select_name && self.check(TokenKind::Ident("x".to_string())) {
if select_name &&
(self.check(TokenKind::Ident("x".to_string())) ||
self.check(TokenKind::PrimitiveType(PrimitiveEVMType::Address)))
{
// We need to check if the name is a keyword - not the type
if !on_type {
// Check for reserved primitive type keyword use and throw an error if so
match self.current_token.kind.clone() {
TokenKind::Ident(arg_str) => {
if PrimitiveEVMType::try_from(arg_str.clone()).is_ok() {
return Err(ParserError {
kind: ParserErrorKind::InvalidTypeAsArgumentName(
self.current_token.kind.clone(),
),
hint: Some(format!(
"Argument names cannot be EVM types: {}",
arg_str
)),
spans: AstSpan(vec![self.current_token.span.clone()]),
})
}
}
TokenKind::PrimitiveType(ty) => {
return Err(ParserError {
kind: ParserErrorKind::InvalidTypeAsArgumentName(
self.current_token.kind.clone(),
),
hint: Some(format!("Argument names cannot be EVM types: {}", ty)),
spans: AstSpan(vec![self.current_token.span.clone()]),
})
}
_ => { /* continue, valid string */ }
}
}
arg_spans.push(self.current_token.span.clone());
arg.name = Some(self.match_kind(TokenKind::Ident("x".to_string()))?.to_string())
arg.name = Some(self.match_kind(TokenKind::Ident("x".to_string()))?.to_string());
on_type = !on_type;
}

// multiple args possible
if self.check(TokenKind::Comma) {
self.consume();
on_type = true;
}

// If both arg type and arg name are none, we didn't consume anything
Expand Down Expand Up @@ -907,6 +966,10 @@ impl Parser {
args.push(MacroArg::Ident(ident));
self.consume();
}
TokenKind::Calldata => {
args.push(MacroArg::Ident("calldata".to_string()));
self.consume();
}
TokenKind::LeftAngle => {
// Passed into the Macro Call like:
// GET_SLOT_FROM_KEY(<mem_ptr>) // [slot]
Expand Down
3 changes: 2 additions & 1 deletion huff_parser/tests/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ fn test_parses_custom_error() {
arg_type: Some(String::from("uint256")),
name: None,
indexed: false,
span: AstSpan(vec![Span { start: 24, end: 31, file: None }])
span: AstSpan(vec![Span { start: 24, end: 31, file: None }]),
arg_location: None,
}],
span: AstSpan(vec![
Span { start: 0, end: 7, file: None },
Expand Down
74 changes: 74 additions & 0 deletions huff_parser/tests/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,74 @@ use huff_lexer::*;
use huff_parser::*;
use huff_utils::{ast::Event, prelude::*};

#[test]
fn test_prefix_event_arg_names_with_reserved_keywords() {
let source: &str = "#define event TestEvent(bytes4 indexed interfaceId, uint256 uintTest, bool stringMe, string boolean)";
let flattened_source = FullFileSource { source, file: None, spans: vec![] };
let lexer = Lexer::new(flattened_source);
let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
let expected_tokens: Vec<Token> = vec![
Token { kind: TokenKind::Define, span: Span { start: 0, end: 7, file: None } },
Token { kind: TokenKind::Whitespace, span: Span { start: 7, end: 8, file: None } },
Token { kind: TokenKind::Event, span: Span { start: 8, end: 13, file: None } },
Token { kind: TokenKind::Whitespace, span: Span { start: 13, end: 14, file: None } },
Token {
kind: TokenKind::Ident("TestEvent".to_string()),
span: Span { start: 14, end: 23, file: None },
},
Token { kind: TokenKind::OpenParen, span: Span { start: 23, end: 24, file: None } },
Token {
kind: TokenKind::PrimitiveType(PrimitiveEVMType::Bytes(4)),
span: Span { start: 24, end: 30, file: None },
},
Token { kind: TokenKind::Whitespace, span: Span { start: 30, end: 31, file: None } },
Token { kind: TokenKind::Indexed, span: Span { start: 31, end: 38, file: None } },
Token { kind: TokenKind::Whitespace, span: Span { start: 38, end: 39, file: None } },
Token {
kind: TokenKind::Ident("interfaceId".to_string()),
span: Span { start: 39, end: 50, file: None },
},
Token { kind: TokenKind::Comma, span: Span { start: 50, end: 51, file: None } },
Token { kind: TokenKind::Whitespace, span: Span { start: 51, end: 52, file: None } },
Token {
kind: TokenKind::PrimitiveType(PrimitiveEVMType::Uint(256)),
span: Span { start: 52, end: 59, file: None },
},
Token { kind: TokenKind::Whitespace, span: Span { start: 59, end: 60, file: None } },
Token {
kind: TokenKind::Ident("uintTest".to_string()),
span: Span { start: 60, end: 68, file: None },
},
Token { kind: TokenKind::Comma, span: Span { start: 68, end: 69, file: None } },
Token { kind: TokenKind::Whitespace, span: Span { start: 69, end: 70, file: None } },
Token {
kind: TokenKind::PrimitiveType(PrimitiveEVMType::Bool),
span: Span { start: 70, end: 74, file: None },
},
Token { kind: TokenKind::Whitespace, span: Span { start: 74, end: 75, file: None } },
Token {
kind: TokenKind::Ident("stringMe".to_string()),
span: Span { start: 75, end: 83, file: None },
},
Token { kind: TokenKind::Comma, span: Span { start: 83, end: 84, file: None } },
Token { kind: TokenKind::Whitespace, span: Span { start: 84, end: 85, file: None } },
Token {
kind: TokenKind::PrimitiveType(PrimitiveEVMType::String),
span: Span { start: 85, end: 91, file: None },
},
Token { kind: TokenKind::Whitespace, span: Span { start: 91, end: 92, file: None } },
Token {
kind: TokenKind::Ident("boolean".to_string()),
span: Span { start: 92, end: 99, file: None },
},
Token { kind: TokenKind::CloseParen, span: Span { start: 99, end: 100, file: None } },
Token { kind: TokenKind::Eof, span: Span { start: 100, end: 100, file: None } },
];
assert_eq!(expected_tokens, tokens);
let mut parser = Parser::new(tokens, None);
parser.parse().unwrap();
}

#[test]
fn test_parse_event() {
let sources = [
Expand All @@ -14,6 +82,7 @@ fn test_parse_event() {
arg_type: Some(String::from("uint256")),
name: Some(String::from("a")),
indexed: true,
arg_location: None,
span: AstSpan(vec![
// "uint256"
Span { start: 24, end: 31, file: None },
Expand All @@ -27,6 +96,7 @@ fn test_parse_event() {
arg_type: Some(String::from("uint8")),
name: None,
indexed: true,
arg_location: None,
span: AstSpan(vec![
// "uint8"
Span { start: 42, end: 47, file: None },
Expand Down Expand Up @@ -74,6 +144,7 @@ fn test_parse_event() {
arg_type: Some(String::from("uint256")),
name: None,
indexed: false,
arg_location: None,
span: AstSpan(vec![
// "uint256"
Span { start: 24, end: 31, file: None },
Expand All @@ -83,6 +154,7 @@ fn test_parse_event() {
arg_type: Some(String::from("uint8")),
name: Some(String::from("b")),
indexed: false,
arg_location: None,
span: AstSpan(vec![
// "uint8"
Span { start: 32, end: 37, file: None },
Expand Down Expand Up @@ -126,6 +198,7 @@ fn test_parse_event() {
arg_type: Some(String::from("uint256")),
name: None,
indexed: true,
arg_location: None,
span: AstSpan(vec![
// "uint256"
Span { start: 24, end: 31, file: None },
Expand All @@ -137,6 +210,7 @@ fn test_parse_event() {
arg_type: Some(String::from("uint8")),
name: None,
indexed: false,
arg_location: None,
span: AstSpan(vec![
// "uint8"
Span { start: 40, end: 45, file: None },
Expand Down
Loading