treewide: fmt

This commit is contained in:
raf 2025-05-24 23:41:06 +03:00
commit 10a525b2e7
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
5 changed files with 326 additions and 206 deletions

View file

@ -1,12 +1,14 @@
use crate::ast::*;
use crate::lexer::{LexError, Token, TokenKind};
use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use thiserror::Error;
/// Parse errors for nftables configuration
#[derive(Error, Debug)]
pub enum ParseError {
#[error("Unexpected token at line {line}, column {column}: expected {expected}, found '{found}'")]
#[error(
"Unexpected token at line {line}, column {column}: expected {expected}, found '{found}'"
)]
UnexpectedToken {
line: usize,
column: usize,
@ -123,7 +125,10 @@ impl Parser {
line: 1,
column: 1,
expected: "include, define, table, or comment".to_string(),
found: self.peek().map(|t| t.text.clone()).unwrap_or("EOF".to_string()),
found: self
.peek()
.map(|t| t.text.clone())
.unwrap_or("EOF".to_string()),
});
}
}
@ -154,21 +159,23 @@ impl Parser {
self.consume(TokenKind::Include, "Expected 'include'")?;
let path = match self.advance() {
Some(token) if matches!(token.kind, TokenKind::StringLiteral(_)) => {
match &token.kind {
TokenKind::StringLiteral(s) => s.clone(),
_ => unreachable!(),
}
Some(token) if matches!(token.kind, TokenKind::StringLiteral(_)) => match &token.kind {
TokenKind::StringLiteral(s) => s.clone(),
_ => unreachable!(),
},
None => {
return Err(ParseError::MissingToken {
expected: "string literal after 'include'".to_string(),
});
}
Some(token) => {
return Err(ParseError::UnexpectedToken {
line: 1,
column: 1,
expected: "string literal".to_string(),
found: token.text.clone(),
});
}
None => return Err(ParseError::MissingToken {
expected: "string literal after 'include'".to_string()
}),
Some(token) => return Err(ParseError::UnexpectedToken {
line: 1,
column: 1,
expected: "string literal".to_string(),
found: token.text.clone(),
}),
};
Ok(Include { path })
@ -179,21 +186,23 @@ impl Parser {
self.consume(TokenKind::Define, "Expected 'define'")?;
let name = match self.advance() {
Some(token) if matches!(token.kind, TokenKind::Identifier(_)) => {
match &token.kind {
TokenKind::Identifier(s) => s.clone(),
_ => unreachable!(),
}
Some(token) if matches!(token.kind, TokenKind::Identifier(_)) => match &token.kind {
TokenKind::Identifier(s) => s.clone(),
_ => unreachable!(),
},
None => {
return Err(ParseError::MissingToken {
expected: "identifier after 'define'".to_string(),
});
}
Some(token) => {
return Err(ParseError::UnexpectedToken {
line: 1,
column: 1,
expected: "identifier".to_string(),
found: token.text.clone(),
});
}
None => return Err(ParseError::MissingToken {
expected: "identifier after 'define'".to_string()
}),
Some(token) => return Err(ParseError::UnexpectedToken {
line: 1,
column: 1,
expected: "identifier".to_string(),
found: token.text.clone(),
}),
};
self.consume(TokenKind::Assign, "Expected '=' after define name")?;
@ -232,10 +241,14 @@ impl Parser {
Some(TokenKind::Newline) => {
self.advance();
}
_ => { return Err(ParseError::SemanticError {
message: format!("Unexpected token in table: {}",
self.peek().map(|t| t.text.as_str()).unwrap_or("EOF")),
}.into());
_ => {
return Err(ParseError::SemanticError {
message: format!(
"Unexpected token in table: {}",
self.peek().map(|t| t.text.as_str()).unwrap_or("EOF")
),
}
.into());
}
}
self.skip_whitespace();
@ -337,8 +350,8 @@ impl Parser {
// Parse expressions and action
while !self.current_token_is(&TokenKind::Newline)
&& !self.current_token_is(&TokenKind::RightBrace)
&& !self.is_at_end() {
&& !self.is_at_end()
{
// Check for actions first
match self.peek().map(|t| &t.kind) {
Some(TokenKind::Accept) => {
@ -415,7 +428,8 @@ impl Parser {
} else {
return Err(ParseError::InvalidStatement {
message: "Expected string literal after 'comment'".to_string(),
}.into());
}
.into());
}
}
_ => {
@ -451,16 +465,16 @@ impl Parser {
fn parse_comparison_expression(&mut self) -> Result<Expression> {
let mut expr = self.parse_range_expression()?;
while let Some(token) = self.peek() {
let operator = match &token.kind {
TokenKind::Eq => BinaryOperator::Eq,
TokenKind::Ne => BinaryOperator::Ne,
TokenKind::Lt => BinaryOperator::Lt,
TokenKind::Le => BinaryOperator::Le,
TokenKind::Gt => BinaryOperator::Gt,
TokenKind::Ge => BinaryOperator::Ge,
_ => break,
};
while let Some(token) = self.peek() {
let operator = match &token.kind {
TokenKind::Eq => BinaryOperator::Eq,
TokenKind::Ne => BinaryOperator::Ne,
TokenKind::Lt => BinaryOperator::Lt,
TokenKind::Le => BinaryOperator::Le,
TokenKind::Gt => BinaryOperator::Gt,
TokenKind::Ge => BinaryOperator::Ge,
_ => break,
};
self.advance(); // consume operator
let right = self.parse_range_expression()?;
@ -664,19 +678,22 @@ impl Parser {
// Check for rate expression (e.g., 10/minute)
if self.current_token_is(&TokenKind::Slash) {
self.advance(); // consume '/'
if let Some(token) = self.peek() {
if matches!(token.kind, TokenKind::Identifier(_)) {
let unit = self.advance().unwrap().text.clone();
Ok(Expression::String(format!("{}/{}", num, unit)))
} else {
Err(ParseError::InvalidExpression {
message: "Expected identifier after '/' in rate expression".to_string(),
}.into())
}
if let Some(token) = self.peek() {
if matches!(token.kind, TokenKind::Identifier(_)) {
let unit = self.advance().unwrap().text.clone();
Ok(Expression::String(format!("{}/{}", num, unit)))
} else {
Err(ParseError::InvalidExpression {
message: "Expected identifier after '/' in rate expression"
.to_string(),
}
.into())
}
} else {
Err(ParseError::InvalidExpression {
message: "Expected identifier after '/' in rate expression".to_string(),
}.into())
}
.into())
}
} else {
Ok(Expression::Number(num))
@ -694,12 +711,14 @@ impl Parser {
} else {
Err(ParseError::InvalidExpression {
message: "Expected number after '/' in CIDR notation".to_string(),
}.into())
}
.into())
}
} else {
Err(ParseError::InvalidExpression {
message: "Expected number after '/' in CIDR notation".to_string(),
}.into())
}
.into())
}
// Check for port specification (e.g., 192.168.1.100:80)
} else if self.current_token_is(&TokenKind::Colon) {
@ -710,13 +729,17 @@ impl Parser {
Ok(Expression::String(format!("{}:{}", addr, port)))
} else {
Err(ParseError::InvalidExpression {
message: "Expected number after ':' in address:port specification".to_string(),
}.into())
message: "Expected number after ':' in address:port specification"
.to_string(),
}
.into())
}
} else {
Err(ParseError::InvalidExpression {
message: "Expected number after ':' in address:port specification".to_string(),
}.into())
message: "Expected number after ':' in address:port specification"
.to_string(),
}
.into())
}
} else {
Ok(Expression::IpAddress(addr))
@ -751,12 +774,13 @@ impl Parser {
self.consume(TokenKind::RightBrace, "Expected '}' to close set")?;
Ok(Expression::Set(elements))
}
_ => {
Err(ParseError::InvalidExpression {
message: format!("Unexpected token in expression: {}",
self.peek().map(|t| t.text.as_str()).unwrap_or("EOF")),
}.into())
_ => Err(ParseError::InvalidExpression {
message: format!(
"Unexpected token in expression: {}",
self.peek().map(|t| t.text.as_str()).unwrap_or("EOF")
),
}
.into()),
}
}
@ -822,12 +846,12 @@ impl Parser {
let token_clone = token.clone();
Err(self.unexpected_token_error_with_token(
"family (ip, ip6, inet, arp, bridge, netdev)".to_string(),
&token_clone
&token_clone,
))
}
},
None => Err(ParseError::MissingToken {
expected: "family".to_string()
expected: "family".to_string(),
}),
}
}
@ -842,12 +866,12 @@ impl Parser {
let token_clone = token.clone();
Err(self.unexpected_token_error_with_token(
"chain type (filter, nat, route)".to_string(),
&token_clone
&token_clone,
))
}
},
None => Err(ParseError::MissingToken {
expected: "chain type".to_string()
expected: "chain type".to_string(),
}),
}
}
@ -864,12 +888,12 @@ impl Parser {
let token_clone = token.clone();
Err(self.unexpected_token_error_with_token(
"hook (input, output, forward, prerouting, postrouting)".to_string(),
&token_clone
&token_clone,
))
}
},
None => Err(ParseError::MissingToken {
expected: "hook".to_string()
expected: "hook".to_string(),
}),
}
}
@ -879,7 +903,10 @@ impl Parser {
Some(token) => match token.kind {
TokenKind::Accept => Ok(Policy::Accept),
TokenKind::Drop => Ok(Policy::Drop),
_ => Err(anyhow!("Expected policy (accept, drop), got: {}", token.text)),
_ => Err(anyhow!(
"Expected policy (accept, drop), got: {}",
token.text
)),
},
None => Err(anyhow!("Expected policy")),
}
@ -887,12 +914,10 @@ impl Parser {
fn parse_identifier(&mut self) -> Result<String> {
match self.advance() {
Some(token) if matches!(token.kind, TokenKind::Identifier(_)) => {
match &token.kind {
TokenKind::Identifier(s) => Ok(s.clone()),
_ => unreachable!(),
}
}
Some(token) if matches!(token.kind, TokenKind::Identifier(_)) => match &token.kind {
TokenKind::Identifier(s) => Ok(s.clone()),
_ => unreachable!(),
},
Some(token) => Err(anyhow!("Expected identifier, got: {}", token.text)),
None => Err(anyhow!("Expected identifier")),
}
@ -905,17 +930,33 @@ impl Parser {
match &token.kind {
TokenKind::Identifier(s) => Ok(s.clone()),
// Allow keywords to be used as identifiers in certain contexts
TokenKind::Filter | TokenKind::Nat | TokenKind::Route |
TokenKind::Input | TokenKind::Output | TokenKind::Forward |
TokenKind::Prerouting | TokenKind::Postrouting |
TokenKind::Accept | TokenKind::Drop | TokenKind::Reject |
TokenKind::State | TokenKind::Ct | TokenKind::Type | TokenKind::Hook |
TokenKind::Priority | TokenKind::Policy |
TokenKind::Tcp | TokenKind::Udp | TokenKind::Icmp | TokenKind::Icmpv6 |
TokenKind::Ip | TokenKind::Ip6 => {
Ok(token.text.clone())
}
_ => Err(anyhow!("Expected identifier or keyword, got: {}", token.text)),
TokenKind::Filter
| TokenKind::Nat
| TokenKind::Route
| TokenKind::Input
| TokenKind::Output
| TokenKind::Forward
| TokenKind::Prerouting
| TokenKind::Postrouting
| TokenKind::Accept
| TokenKind::Drop
| TokenKind::Reject
| TokenKind::State
| TokenKind::Ct
| TokenKind::Type
| TokenKind::Hook
| TokenKind::Priority
| TokenKind::Policy
| TokenKind::Tcp
| TokenKind::Udp
| TokenKind::Icmp
| TokenKind::Icmpv6
| TokenKind::Ip
| TokenKind::Ip6 => Ok(token.text.clone()),
_ => Err(anyhow!(
"Expected identifier or keyword, got: {}",
token.text
)),
}
}
None => Err(anyhow!("Expected identifier or keyword")),
@ -924,26 +965,32 @@ impl Parser {
fn parse_string_or_identifier(&mut self) -> Result<String> {
match self.advance() {
Some(token) if matches!(token.kind, TokenKind::Identifier(_) | TokenKind::StringLiteral(_)) => {
Some(token)
if matches!(
token.kind,
TokenKind::Identifier(_) | TokenKind::StringLiteral(_)
) =>
{
match &token.kind {
TokenKind::Identifier(s) => Ok(s.clone()),
TokenKind::StringLiteral(s) => Ok(s.clone()),
_ => unreachable!(),
}
}
Some(token) => Err(anyhow!("Expected string or identifier, got: {}", token.text)),
Some(token) => Err(anyhow!(
"Expected string or identifier, got: {}",
token.text
)),
None => Err(anyhow!("Expected string or identifier")),
}
}
fn parse_number(&mut self) -> Result<u64> {
match self.advance() {
Some(token) if matches!(token.kind, TokenKind::NumberLiteral(_)) => {
match &token.kind {
TokenKind::NumberLiteral(n) => Ok(*n),
_ => unreachable!(),
}
}
Some(token) if matches!(token.kind, TokenKind::NumberLiteral(_)) => match &token.kind {
TokenKind::NumberLiteral(n) => Ok(*n),
_ => unreachable!(),
},
Some(token) => Err(anyhow!("Expected number, got: {}", token.text)),
None => Err(anyhow!("Expected number")),
}
@ -1029,11 +1076,7 @@ impl Parser {
}
}
fn unexpected_token_error_with_token(
&self,
expected: String,
token: &Token,
) -> ParseError {
fn unexpected_token_error_with_token(&self, expected: String, token: &Token) -> ParseError {
ParseError::UnexpectedToken {
line: 1, // TODO: Calculate line from range
column: token.range.start().into(),