// Copyright 2016-2020, Pulumi Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package model import ( "fmt" "io" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/pulumi/pulumi/pkg/v3/codegen/hcl2/syntax" ) type printable interface { print(w io.Writer, p *printer) // HasLeadingTrivia returns true if the value has associated leading trivia. HasLeadingTrivia() bool // HasTrailingTrivia returns true if the value has associated trailing trivia. HasTrailingTrivia() bool // GetLeadingTrivia returns the leading trivia for this value, if any. GetLeadingTrivia() syntax.TriviaList // GetTrailingTrivia returns the trailing trivia for this value, if any. GetTrailingTrivia() syntax.TriviaList } type printer struct { indent string } type formatter func(f fmt.State, c rune) func (fn formatter) Format(f fmt.State, c rune) { fn(f, c) } func (p *printer) indented(f func()) { p.indent += " " f() p.indent = p.indent[:len(p.indent)-4] } func (p *printer) format(f fmt.State, c rune, pp printable) { if f.Flag(' ') && !pp.HasLeadingTrivia() { switch pp.(type) { case BodyItem: p.fprintf(f, "%s", p.indent) case Expression: p.fprintf(f, " ") } } parentPrecedence, hasPrecedence := f.Precision() if !hasPrecedence { pp.print(f, p) return } var operator *hclsyntax.Operation switch pp := pp.(type) { case *BinaryOpExpression: operator = pp.Operation case *UnaryOpExpression: operator = pp.Operation } precedence := operatorPrecedence(operator) switch { case precedence < parentPrecedence || (precedence == parentPrecedence && c == 'o'): p.fprintf(f, "(") pp.print(f, p) p.fprintf(f, ")") default: pp.print(f, p) } } func (p *printer) fprintf(w io.Writer, f string, v ...interface{}) { for i, e := range v { if printable, ok := e.(printable); ok { v[i] = formatter(func(f fmt.State, c rune) { p.format(f, c, printable) }) } } if _, err := fmt.Fprintf(w, f, v...); err != nil { panic(err) } }