Skip to content
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

doc error: gohcl.EvalContext not implemented, but mentioned in the doc #565

Open
gaissmai opened this issue Nov 1, 2022 · 8 comments
Open

Comments

@gaissmai
Copy link

gaissmai commented Nov 1, 2022

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 ;)

go_decoding_gohcl.html

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!

@incubator4
Copy link
Contributor

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.

@gaissmai
Copy link
Author

gaissmai commented Nov 7, 2022

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?

@incubator4
Copy link
Contributor

incubator4 commented Nov 7, 2022

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.

@gaissmai
Copy link
Author

gaissmai commented Nov 7, 2022

Hello @incubator4, i think this is only possible with method values

@incubator4
Copy link
Contributor

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.

@gaissmai
Copy link
Author

gaissmai commented Nov 12, 2022

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.

@incubator4
Copy link
Contributor

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.

@incubator4
Copy link
Contributor

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,

  1. Rewrite the conversion method at present, which I've already did
  2. Find out how to modify golang structTag at runtime, then use cty lib.

Do you or any others have idea ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants