azure-policy parser: allow overriding the column-width limit (#673)

Some Azure Policy JSON documents contain very long lines — ARM template
expressions with deeply nested if()/concat() calls can easily exceed
the default 1024-column lexer limit.

Add Parser::new_with_max_col() and corresponding parse_policy_rule_with_max_col()
/ parse_policy_definition_with_max_col() entry points so callers can raise
the limit when needed.  Also bump ExprParser's own default to 65536 since
template expressions are routinely thousands of characters wide.
This commit is contained in:
Anand Krishnamoorthi
2026-04-10 18:23:02 -05:00
committed by GitHub
parent 35521ce900
commit 3d34021dea
3 changed files with 40 additions and 2 deletions

View File

@@ -70,6 +70,13 @@ impl<'source> ExprParser<'source> {
fn new(source: &'source Source) -> Self {
let mut lexer = Lexer::new(source);
lexer.set_unknown_char_is_symbol(true);
// ARM template expressions inside Azure Policy JSON values can be
// very long (e.g. deeply nested `if(...)` / `concat(...)` spanning
// thousands of characters on a single line). Use a generous column
// limit so these expressions parse successfully.
if let Some(limit) = core::num::NonZeroU32::new(65536) {
lexer.set_max_col(limit);
}
let tok = Token(
TokenKind::Eof,
Span {

View File

@@ -148,8 +148,21 @@ pub(super) struct Parser<'source> {
impl<'source> Parser<'source> {
/// Create a new parser for the given source.
pub fn new(source: &'source Source) -> Result<Self, ParseError> {
Self::new_with_max_col(source, None)
}
/// Create a new parser with an optional column-width override.
///
/// When `max_col` is `None`, the lexer's default limit applies.
pub fn new_with_max_col(
source: &'source Source,
max_col: Option<core::num::NonZeroU32>,
) -> Result<Self, ParseError> {
let mut lexer = Lexer::new(source);
lexer.set_unknown_char_is_symbol(true);
if let Some(mc) = max_col {
lexer.set_max_col(mc);
}
let tok = lexer
.next_token()

View File

@@ -34,6 +34,8 @@ pub use error::ParseError;
use alloc::string::ToString as _;
use ::core::num::NonZeroU32;
use crate::lexer::{Source, TokenKind};
use super::ast::{Constraint, FieldKind, OperatorKind, PolicyDefinition, PolicyRule};
@@ -57,7 +59,15 @@ use self::core::Parser;
///
/// Returns a span-annotated [`PolicyRule`] AST.
pub fn parse_policy_rule(source: &Source) -> Result<PolicyRule, ParseError> {
let mut parser = Parser::new(source)?;
parse_policy_rule_with_max_col(source, None)
}
/// Like [`parse_policy_rule`] but with an optional column-width override.
pub fn parse_policy_rule_with_max_col(
source: &Source,
max_col: Option<NonZeroU32>,
) -> Result<PolicyRule, ParseError> {
let mut parser = Parser::new_with_max_col(source, max_col)?;
let rule = parser.parse_policy_rule()?;
if parser.tok.0 != TokenKind::Eof {
@@ -79,7 +89,15 @@ pub fn parse_policy_rule(source: &Source) -> Result<PolicyRule, ParseError> {
/// Returns a [`PolicyDefinition`] with typed fields for known properties
/// and a catch-all list of `extra` entries for everything else.
pub fn parse_policy_definition(source: &Source) -> Result<PolicyDefinition, ParseError> {
let mut parser = Parser::new(source)?;
parse_policy_definition_with_max_col(source, None)
}
/// Like [`parse_policy_definition`] but with an optional column-width override.
pub fn parse_policy_definition_with_max_col(
source: &Source,
max_col: Option<NonZeroU32>,
) -> Result<PolicyDefinition, ParseError> {
let mut parser = Parser::new_with_max_col(source, max_col)?;
let defn = parser.parse_policy_definition()?;
if parser.tok.0 != TokenKind::Eof {