diff --git a/cmd/hcldec/spec-format.md b/cmd/hcldec/spec-format.md index d80beda..9f4d7a9 100644 --- a/cmd/hcldec/spec-format.md +++ b/cmd/hcldec/spec-format.md @@ -364,7 +364,7 @@ block type: ``` function "add_one" { - params = ["n"] + params = [n] result = n + 1 } ``` @@ -379,9 +379,15 @@ input file: ``` function "upper" { - params = ["str"] + params = [str] result = upper(str) } + +function "min" { + params = [] + variadic_param = nums + result = min(nums...) +} ``` Custom functions defined in the spec cannot be called from the spec itself. diff --git a/ext/userfunc/README.md b/ext/userfunc/README.md index 033b36c..4f9d343 100644 --- a/ext/userfunc/README.md +++ b/ext/userfunc/README.md @@ -7,9 +7,15 @@ Functions are defined via a specific block type, like this: ```hcl function "add" { - params = ["a", "b"] + params = [a, b] result = a + b } + +function "list" { + params = [] + variadic_param = items + result = items +} ``` The extension is implemented as a pre-processor for `cty.Body` objects. Given diff --git a/ext/userfunc/decode.go b/ext/userfunc/decode.go index 375a1ea..2f3ce64 100644 --- a/ext/userfunc/decode.go +++ b/ext/userfunc/decode.go @@ -1,7 +1,6 @@ package userfunc import ( - "github.com/hashicorp/hcl2/gohcl" "github.com/hashicorp/hcl2/hcl" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" @@ -54,6 +53,7 @@ func decodeUserFunctions(body hcl.Body, blockType string, contextFunc ContextFun } funcs = make(map[string]function.Function) +Blocks: for _, block := range content.Blocks { name := block.Labels[0] funcContent, funcDiags := block.Body.Content(funcBodySchema) @@ -72,15 +72,34 @@ func decodeUserFunctions(body hcl.Body, blockType string, contextFunc ContextFun var params []string var varParam string - paramsDiags := gohcl.DecodeExpression(paramsExpr, nil, ¶ms) + paramExprs, paramsDiags := hcl.ExprList(paramsExpr) diags = append(diags, paramsDiags...) if paramsDiags.HasErrors() { continue } + for _, paramExpr := range paramExprs { + param := hcl.ExprAsKeyword(paramExpr) + if param == "" { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid param element", + Detail: "Each parameter name must be an identifier.", + Subject: paramExpr.Range().Ptr(), + }) + continue Blocks + } + params = append(params, param) + } + if varParamExpr != nil { - paramsDiags := gohcl.DecodeExpression(varParamExpr, nil, &varParam) - diags = append(diags, paramsDiags...) - if paramsDiags.HasErrors() { + varParam = hcl.ExprAsKeyword(varParamExpr) + if varParam == "" { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid variadic_param", + Detail: "The variadic parameter name must be an identifier.", + Subject: varParamExpr.Range().Ptr(), + }) continue } } diff --git a/ext/userfunc/decode_test.go b/ext/userfunc/decode_test.go index 09d1d07..039beba 100644 --- a/ext/userfunc/decode_test.go +++ b/ext/userfunc/decode_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" - "github.com/hashicorp/hcl2/hcl/hclsyntax" "github.com/hashicorp/hcl2/hcl" + "github.com/hashicorp/hcl2/hcl/hclsyntax" "github.com/zclconf/go-cty/cty" ) @@ -20,7 +20,7 @@ func TestDecodeUserFunctions(t *testing.T) { { ` function "greet" { - params = ["name"] + params = [name] result = "Hello, ${name}." } `, @@ -32,7 +32,7 @@ function "greet" { { ` function "greet" { - params = ["name"] + params = [name] result = "Hello, ${name}." } `, @@ -44,7 +44,7 @@ function "greet" { { ` function "greet" { - params = ["name"] + params = [name] result = "Hello, ${name}." } `, @@ -56,7 +56,7 @@ function "greet" { { ` function "add" { - params = ["a", "b"] + params = [a, b] result = a + b } `, @@ -69,7 +69,7 @@ function "add" { ` function "argstuple" { params = [] - variadic_param = "args" + variadic_param = args result = args } `, @@ -109,11 +109,11 @@ function "closure" { { ` function "neg" { - params = ["val"] + params = [val] result = -val } function "add" { - params = ["a", "b"] + params = [a, b] result = a + b } `, @@ -125,7 +125,7 @@ function "add" { { ` function "neg" { - parrams = ["val"] + parrams = [val] result = -val } `,