doc error: gohcl.EvalContext not implemented, but mentioned in the doc
Hi,
I stumbled over this promising gohcl.EvalContext() description. It would be really useful for gohcl but, not implemented (yet?) and the user of the high-level gohcl must go into the low level rabbit hole of cty.
Please correct the documentation or ... wait, much better, please implement gohcl.EvalContext() as described below ;)
Variables and Functions
By default, arguments given in the configuration may use only literal values and the built in expression language operators, such as arithmetic.
The second argument to gohcl.DecodeBody, shown as nil in the previous example, allows the calling application to additionally offer variables and functions for use in expressions. Its value is a pointer to an hcl.EvalContext, which will be covered in more detail in the later section Expression Evaluation. For now, a simple example of making the id of the current process available as a single variable called pid:
type Context struct {
Pid string
}
ctx := gohcl.EvalContext(&Context{
Pid: os.Getpid()
})
var c Config
moreDiags := gohcl.DecodeBody(f.Body, ctx, &c)
diags = append(diags, moreDiags...)
gohcl.EvalContext constructs an expression evaluation context from a Go struct value, making the fields available as variables and the methods available as functions, after transforming the field and method names such that each word (starting with an uppercase letter) is all lowercase and separated by underscores.
name = "example-program (${pid})"
btw, thanks for HCL!
Hey @gaissmai, I noticed this problem and working on it. In my github project on branch implement/gohcl-eval_context, I made a implementation of this function and added simple test case. Could you please think of more test cases? It would be helpful to ensure if it's robust.
Hey @incubator4, thanks for implementing this. maybe I just don't understand it, but I don't see that the described function is implemented: "gohcl.EvalContext constructs an expression evaluation context from a Go struct value, making the fields available as variables and the methods available as functions"
I see just the variable part und no functions/methods. Am I missing something?
Hey @incubator4, thanks for implementing this.
maybe I just don't understand it, but I don't see that the described function is implemented:
"gohcl.EvalContext constructs an expression evaluation context from a Go struct value, making the fields available as variables and the methods available as functions"
I see just the variable part und no functions/methods. Am I missing something?
Actually you're right ,I'm working on it,so I just finished variable part before.
Cause of without demo in doc,I'm still considering about how to implement function part.
In my opinion, the struct contains variable pid with certain value should be render into final string , it should be like
name = "example-program a-pid-value"
How to implement function part is a problem, or may I understand some mistakes.
If you have any idea about that, we can communicate in this issue.
Hello @incubator4, i think this is only possible with method values
Hello @incubator4, i think this is only possible with method values
Well, I've checked code abount function DecodeBody, most of then are used by nil EvalContext. Fortunately, I saw this in file hcl/cmd/hcldec/spec.go with line 485 to 499
func decodeLiteralSpec(body hcl.Body) (hcldec.Spec, hcl.Diagnostics) {
type content struct {
Value cty.Value `hcl:"value"`
}
var args content
diags := gohcl.DecodeBody(body, specCtx, &args)
if diags.HasErrors() {
return errSpec, diags
}
return &hcldec.LiteralSpec{
Value: args.Value,
}, diags
}
This specCtx use a specFunc var which in hcl/cmd/hcldec/spec_funcs.go
var specFuncs = map[string]function.Function{
"abs": stdlib.AbsoluteFunc,
"coalesce": stdlib.CoalesceFunc,
"concat": stdlib.ConcatFunc,
"hasindex": stdlib.HasIndexFunc,
"int": stdlib.IntFunc,
"jsondecode": stdlib.JSONDecodeFunc,
"jsonencode": stdlib.JSONEncodeFunc,
"length": stdlib.LengthFunc,
"lower": stdlib.LowerFunc,
"max": stdlib.MaxFunc,
"min": stdlib.MinFunc,
"reverse": stdlib.ReverseFunc,
"strlen": stdlib.StrlenFunc,
"substr": stdlib.SubstrFunc,
"upper": stdlib.UpperFunc,
}
In my opinion, suppose that Functions might not be implement, or it could not be generate by golang Function variable.
Hey @incubator4 , sorry for the delay. Maybe I don't understand what you want to show me. Anyway, do you know this blogpost: build your own DSL with go and e.g. the implementation of the random() function and more examples.
Hey @incubator4 , sorry for the delay. Maybe I don't understand what you want to show me. Anyway, do you know this blogpost: build your own DSL with go and e.g. the implementation of the
random()function and more examples.
I've already finished this post. The key info I thought , which was
golang function -> cty.Function
variable -> cty.Type
I could try to finish function part, it should be implement as same as the variables with reflect.
Hey @gaissmai . During reading abount go-cty source code. I found out one problem could be improved.
In short, this library provides a conversion method from interface{} to cty.Value. But struct must have the structTag with cty: "name", which will confuse users (why I must add cty tag, I just using hcl go lib).
There are two solutions that can be thought of at present,
- Rewrite the conversion method at present, which I've already did
- Find out how to modify golang
structTagat runtime, then use cty lib.
Do you or any others have idea ?