feat(azure-policy): add compiler skeleton with core types and stubs#674
feat(azure-policy): add compiler skeleton with core types and stubs#674anakrish wants to merge 1 commit intomicrosoft:mainfrom
Conversation
Add the compiler module structure with: - core.rs: Compiler struct, CountBinding, new(), compile() pipeline, register allocation, span/emit helpers - mod.rs: module declarations, public entry points (compile_policy_rule, compile_policy_definition, etc.) - utils.rs: pure helper functions (path splitting, JSON conversion) - Stub files for conditions, expressions, fields, template dispatch, count, effects, and metadata — real implementations follow in subsequent commits.
There was a problem hiding this comment.
Pull request overview
Adds an initial Azure Policy AST → RVM compiler module scaffold under languages::azure_policy, establishing public compile entry points, core compiler state/register plumbing, and a set of stub submodules to be implemented in follow-up commits.
Changes:
- Exposes a new
azure_policy::compilermodule and public compile entry points for rules/definitions (with alias-resolution variants). - Introduces
Compilercore infrastructure (program construction, register allocation, span/source mapping, emit helpers). - Adds utility helpers for path splitting and AST JSON → runtime
Valueconversion; other compiler submodules are currently stubs.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/languages/azure_policy/mod.rs | Exposes the new compiler module from the Azure Policy language surface. |
| src/languages/azure_policy/compiler/mod.rs | Defines compiler module layout and public compilation entry points + parameter-default extraction. |
| src/languages/azure_policy/compiler/core.rs | Core Compiler struct, program pipeline skeleton, register/span/emit helpers. |
| src/languages/azure_policy/compiler/utils.rs | Helper functions for literal extraction, path splitting, and JSON value conversion to runtime Value. |
| src/languages/azure_policy/compiler/conditions.rs | Stub for constraint/condition compilation. |
| src/languages/azure_policy/compiler/conditions_wildcard.rs | Stub for wildcard condition handling. |
| src/languages/azure_policy/compiler/count.rs | Stub for count loop compilation (+ placeholder optimization hook). |
| src/languages/azure_policy/compiler/count_any.rs | Stub for count→Any optimization. |
| src/languages/azure_policy/compiler/count_bindings.rs | Stub for count-binding resolution and current() references. |
| src/languages/azure_policy/compiler/effects.rs | Stub for effect compilation and wrapping result. |
| src/languages/azure_policy/compiler/effects_modify_append.rs | Stub for Modify/Append effect detail compilation. |
| src/languages/azure_policy/compiler/expressions.rs | Stub for template/call expression compilation. |
| src/languages/azure_policy/compiler/fields.rs | Stub for field-kind/path/resource path compilation. |
| src/languages/azure_policy/compiler/metadata.rs | Stub for metadata/annotation accumulation and population. |
| src/languages/azure_policy/compiler/template_dispatch.rs | Stub for ARM template function dispatch. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -6,6 +6,7 @@ | |||
| #[allow(clippy::pattern_type_mismatch)] | |||
| pub mod aliases; | |||
| pub mod ast; | |||
There was a problem hiding this comment.
azure_policy can be built without the rvm feature (see Cargo features), but the new compiler module unconditionally depends on crate::rvm. This will fail to compile for --no-default-features --features azure_policy. Consider gating this module behind #[cfg(feature = "rvm")] (or adding rvm as a dependency of the azure_policy feature).
| pub mod ast; | |
| pub mod ast; | |
| #[cfg(feature = "rvm")] |
| let wildcard_index = path | ||
| .find("[*]") | ||
| .ok_or_else(|| anyhow!("count.field must contain [*]: {}", path))?; | ||
|
|
||
| let prefix = path[..wildcard_index].to_string(); | ||
| let suffix = if wildcard_index + 3 < path.len() { | ||
| let rest = &path[wildcard_index + 3..]; | ||
| Some(rest.trim_start_matches('.').to_string()) | ||
| } else { | ||
| None | ||
| }; |
There was a problem hiding this comment.
This function uses direct string slicing (path[..wildcard_index], &path[wildcard_index + 3..]). The crate has #![deny(clippy::indexing_slicing)], and this file does not allow that lint, so CI will fail. Use non-panicking accessors like get(..idx) / get(idx..), or restructure with split_at + checked arithmetic, to satisfy the lint and avoid potential panics.
| '[' => { | ||
| in_bracket = true; | ||
| let t = token.trim(); | ||
| if !t.is_empty() { | ||
| parts.push(t.to_string()); | ||
| } | ||
| token.clear(); | ||
| } | ||
| ']' => { | ||
| in_bracket = false; | ||
| let cleaned = bracket.trim_matches('"').trim_matches('\'').to_string(); | ||
| if !cleaned.is_empty() { | ||
| parts.push(cleaned); | ||
| } | ||
| bracket.clear(); | ||
| } | ||
| _ => { | ||
| if in_bracket { | ||
| bracket.push(ch); | ||
| } else { | ||
| token.push(ch); | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
split_path_without_wildcards does not validate bracket balance. If the input has an unmatched [ (or stray ]), the parser silently drops the bracket content and still returns Ok(parts), which can yield incorrect compilation results. Since the function returns Result, consider bailing on unclosed brackets / unexpected ] to make failures explicit.
| /// Compile a parsed Azure Policy rule with alias resolution. | ||
| /// | ||
| /// The `alias_map` maps lowercase fully-qualified alias names to their short | ||
| /// names. Obtain it from [`AliasRegistry::alias_map()`]. | ||
| pub fn compile_policy_rule_with_aliases( | ||
| rule: &PolicyRule, | ||
| alias_map: BTreeMap<String, String>, | ||
| alias_modifiable: BTreeMap<String, bool>, |
There was a problem hiding this comment.
The intra-doc link [AliasRegistry::alias_map()] likely won’t resolve from this module (no AliasRegistry in scope), which can produce broken rustdoc links. Use the fully-qualified path (e.g., crate::languages::azure_policy::aliases::AliasRegistry) or add an appropriate use so the link resolves.
| /// Compile a parsed Azure Policy definition into an RVM program. | ||
| /// | ||
| /// This extracts the `policyRule` from the definition and compiles it. | ||
| /// Parameter `defaultValue`s are stored so the `azure.policy.get_parameter` | ||
| /// builtin can fall back to them at runtime. | ||
| pub fn compile_policy_definition(defn: &PolicyDefinition) -> Result<Rc<Program>> { | ||
| let mut compiler = Compiler::new(); | ||
| compiler.program.metadata.language = "azure_policy".to_string(); | ||
| compiler.parameter_defaults = Some(build_parameter_defaults(&defn.parameters)?); | ||
| compiler.populate_definition_metadata(defn); | ||
| let effect = compiler.resolve_effect_annotation(&defn.policy_rule); |
There was a problem hiding this comment.
This doc comment claims parameter defaultValues are stored for the azure.policy.get_parameter builtin, but the current skeleton doesn’t persist parameter_defaults into the resulting Program (and populate_compiled_annotations() is a stub). Either adjust the docs to reflect the current behavior or wire the defaults into program metadata/annotations as part of this PR.
Add the compiler module structure with: