nff: improve diagnostics and vmap expression handling in parser and formatter

This commit is contained in:
raf 2025-06-02 09:31:44 +03:00
commit e0f93d0307
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
3 changed files with 30 additions and 10 deletions

View file

@ -127,7 +127,7 @@ pub enum Expression {
// Vmap expressions (value maps) // Vmap expressions (value maps)
Vmap { Vmap {
expr: Box<Expression>, expr: Option<Box<Expression>>,
map: Vec<(Expression, Expression)>, map: Vec<(Expression, Expression)>,
}, },

View file

@ -311,9 +311,8 @@ impl Parser {
self.advance(); // consume 'policy' self.advance(); // consume 'policy'
let policy = self.parse_policy()?; let policy = self.parse_policy()?;
chain = chain.with_policy(policy); chain = chain.with_policy(policy);
self.consume(TokenKind::Semicolon, "Expected ';' after policy")?;
} }
self.consume(TokenKind::Semicolon, "Expected ';' after policy")?;
} }
Some(TokenKind::CommentLine(_)) => { Some(TokenKind::CommentLine(_)) => {
self.advance(); self.advance();
@ -511,7 +510,7 @@ impl Parser {
// Return a vmap expression with the previous expression as the mapping target // Return a vmap expression with the previous expression as the mapping target
return Ok(Expression::Vmap { return Ok(Expression::Vmap {
expr: Box::new(expr), expr: Some(Box::new(expr)),
map, map,
}); });
} }
@ -828,8 +827,8 @@ impl Parser {
self.consume(TokenKind::RightBrace, "Expected '}' to close vmap")?; self.consume(TokenKind::RightBrace, "Expected '}' to close vmap")?;
// The expression that came before "vmap" is the expr being mapped // No expression available at parse time, will be filled by post-processing if needed
let expr = Box::new(Expression::Identifier("dummy".to_string())); // This will be replaced in post-processing let expr = None;
Ok(Expression::Vmap { expr, map }) Ok(Expression::Vmap { expr, map })
} }
@ -854,6 +853,23 @@ impl Parser {
self.consume(TokenKind::RightBrace, "Expected '}' to close set")?; self.consume(TokenKind::RightBrace, "Expected '}' to close set")?;
Ok(Expression::Set(elements)) Ok(Expression::Set(elements))
} }
Some(TokenKind::Accept) => {
self.advance();
Ok(Expression::Identifier("accept".to_string()))
}
Some(TokenKind::Drop) => {
self.advance();
Ok(Expression::Identifier("drop".to_string()))
}
Some(TokenKind::Reject) => {
self.advance();
Ok(Expression::Identifier("reject".to_string()))
}
Some(TokenKind::Protocol) => {
self.advance(); // consume 'protocol'
let protocol = self.parse_identifier_or_keyword()?;
Ok(Expression::Protocol(protocol))
}
_ => Err(ParseError::InvalidExpression { _ => Err(ParseError::InvalidExpression {
message: format!( message: format!(
"Unexpected token in expression: {}", "Unexpected token in expression: {}",

View file

@ -175,10 +175,11 @@ impl NftablesFormatter {
// Add policy on the same line if present // Add policy on the same line if present
if let Some(policy) = &chain.policy { if let Some(policy) = &chain.policy {
write!(output, " policy {}", policy).unwrap(); write!(output, " policy {}", policy).unwrap();
output.push_str(";\n");
} else {
output.push_str("\n");
} }
output.push_str(";\n");
if !chain.rules.is_empty() && !self.config.optimize { if !chain.rules.is_empty() && !self.config.optimize {
output.push('\n'); output.push('\n');
} }
@ -294,8 +295,11 @@ impl NftablesFormatter {
} }
Expression::Vmap { expr, map } => { Expression::Vmap { expr, map } => {
self.format_expression(output, expr); if let Some(expr) = expr {
output.push_str(" vmap { "); self.format_expression(output, expr);
output.push(' ');
}
output.push_str("vmap { ");
for (i, (key, value)) in map.iter().enumerate() { for (i, (key, value)) in map.iter().enumerate() {
if i > 0 { if i > 0 {
output.push_str(", "); output.push_str(", ");