-
Notifications
You must be signed in to change notification settings - Fork 55
Add lambda expression and map() function with ARM syntax
#1238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add lambda expression and map() function with ARM syntax
#1238
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements lambda expressions and the map() function for DSC configuration documents, using ARM-compatible syntax (lambda('param', body) and lambdaVariables('param')). The implementation stores lambdas in the context with unique UUID-based identifiers and evaluates them by binding lambda parameters to array elements.
Key changes:
- Added
Lambdastruct and lambda-specific handling in the function evaluation pipeline - Implemented
map(),lambda(), andlambdaVariables()functions for array transformations - Extended
Contextwith lambda storage (lambdas) and lambda parameter bindings (lambda_variables)
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/dsc-lib/src/parser/functions.rs | Added Lambda struct and FunctionArg::Lambda variant; special handling for lambda() function to bypass normal evaluation |
| lib/dsc-lib/src/functions/mod.rs | Implemented invoke_lambda() to create and store lambda objects with UUID-based IDs; registered new lambda-related functions |
| lib/dsc-lib/src/functions/map.rs | Implemented array transformation function that evaluates lambdas for each element with optional index parameter |
| lib/dsc-lib/src/functions/lambda_variables.rs | Implemented parameter lookup function for accessing lambda-bound variables during evaluation |
| lib/dsc-lib/src/functions/lambda.rs | Created lambda function stub that returns error if invoked directly (handled specially elsewhere) |
| lib/dsc-lib/src/configure/context.rs | Added lambda_variables HashMap and lambdas RefCell for lambda storage and parameter binding |
| lib/dsc-lib/locales/en-us.toml | Added localized error messages and descriptions for lambda-related functions |
| dsc/tests/dsc_lambda.tests.ps1 | Added integration tests for map() with various lambda scenarios (multiplication, index usage, range, empty array) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
97cf256 to
b180986
Compare
…//github.com/Gijsreyn/operation-methods into PowerShellgh-57/main/add-map-lambda-function
|
|
||
| if args.len() != 1 { | ||
| return Err(DscError::Parser(t!("functions.invalidArgCount", name = "lambdaVariables", count = 1).to_string())); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't needed as function validation ensures min_args and max_args is correct
| let Some(var_name) = args[0].as_str() else { | ||
| return Err(DscError::Parser(t!("functions.lambdaVariables.paramNameMustBeString").to_string())); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, just unwrap.
| if args.len() != 2 { | ||
| return Err(DscError::Parser(t!("functions.invalidArgCount", name = "map", count = 2).to_string())); | ||
| } | ||
|
|
||
| let Some(array) = args[0].as_array() else { | ||
| return Err(DscError::Parser(t!("functions.map.firstArgMustBeArray").to_string())); | ||
| }; | ||
|
|
||
| let Some(lambda_id) = args[1].as_str() else { | ||
| return Err(DscError::Parser(t!("functions.map.secondArgMustBeLambda").to_string())); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, this is all validated already so these strings won't be used
| pub fn invoke_lambda(&self, args: &Option<Vec<crate::parser::functions::FunctionArg>>, context: &Context) -> Result<Value, DscError> { | ||
| use crate::parser::functions::{FunctionArg, Lambda}; | ||
| use uuid::Uuid; | ||
|
|
||
| let Some(args) = args else { | ||
| return Err(DscError::Parser(t!("functions.lambda.requiresArgs").to_string())); | ||
| }; | ||
|
|
||
| if args.len() < 2 { | ||
| return Err(DscError::Parser(t!("functions.lambda.requiresParamAndBody").to_string())); | ||
| } | ||
|
|
||
| // All arguments except the last must be string values (parameter names) | ||
| let mut parameters = Vec::new(); | ||
| for arg in args.iter().take(args.len() - 1) { | ||
| match arg { | ||
| FunctionArg::Value(Value::String(s)) => { | ||
| parameters.push(s.clone()); | ||
| }, | ||
| _ => { | ||
| return Err(DscError::Parser(t!("functions.lambda.paramsMustBeStrings").to_string())); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Last argument is the body expression | ||
| let body_expr = match &args[args.len() - 1] { | ||
| FunctionArg::Expression(expr) => expr.clone(), | ||
| _ => { | ||
| return Err(DscError::Parser(t!("functions.lambda.bodyMustBeExpression").to_string())); | ||
| } | ||
| }; | ||
|
|
||
| // Create Lambda and store in Context with unique ID | ||
| let lambda = Lambda { | ||
| parameters, | ||
| body: body_expr, | ||
| }; | ||
|
|
||
| let lambda_id = format!("__lambda_{}", Uuid::new_v4()); | ||
| context.lambdas.borrow_mut().insert(lambda_id.clone(), lambda); | ||
|
|
||
| // Return the ID as a string value | ||
| Ok(Value::String(lambda_id)) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of special handling it this way, you should have a new ProcessMode::Lambda and just have the lambda() function do this only when process mode is correct other return an error. This keeps it consistent with modes.
PR Summary
This PR implements lambda expressions and the
map()function for DSC configuration documents, enabling array transformations. The implementation uses ARM compatible syntax e.g., (lambda('param', body)andlambdaVariables('param'))Example usage:
Seperated tests in a different file.
PR Context
Partially addresses #57.