github.com/solo-io/cue@v0.4.7/internal/core/export/adt.go (about)

     1  // Copyright 2020 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package export
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/solo-io/cue/cue/ast"
    23  	"github.com/solo-io/cue/cue/ast/astutil"
    24  	"github.com/solo-io/cue/cue/literal"
    25  	"github.com/solo-io/cue/cue/token"
    26  	"github.com/solo-io/cue/internal/core/adt"
    27  )
    28  
    29  func (e *exporter) ident(x adt.Feature) *ast.Ident {
    30  	s := x.IdentString(e.ctx)
    31  	if !ast.IsValidIdent(s) {
    32  		panic(s + " is not a valid identifier")
    33  	}
    34  	return ast.NewIdent(s)
    35  }
    36  
    37  func (e *exporter) adt(expr adt.Expr, conjuncts []adt.Conjunct) ast.Expr {
    38  	switch x := expr.(type) {
    39  	case adt.Value:
    40  		return e.expr(x)
    41  
    42  	case *adt.ListLit:
    43  		a := []ast.Expr{}
    44  		for _, x := range x.Elems {
    45  			a = append(a, e.elem(x))
    46  		}
    47  		return ast.NewList(a...)
    48  
    49  	case *adt.StructLit:
    50  		// TODO: should we use pushFrame here?
    51  		// _, saved := e.pushFrame([]adt.Conjunct{adt.MakeConjunct(nil, x)})
    52  		// defer e.popFrame(saved)
    53  		// s := e.frame(0).scope
    54  
    55  		s := &ast.StructLit{}
    56  
    57  		for _, d := range x.Decls {
    58  			var a *ast.Alias
    59  			if orig, ok := d.Source().(*ast.Field); ok {
    60  				if alias, ok := orig.Value.(*ast.Alias); ok {
    61  					if e.valueAlias == nil {
    62  						e.valueAlias = map[*ast.Alias]*ast.Alias{}
    63  					}
    64  					a = &ast.Alias{Ident: ast.NewIdent(alias.Ident.Name)}
    65  					e.valueAlias[alias] = a
    66  				}
    67  			}
    68  			decl := e.decl(d)
    69  
    70  			if a != nil {
    71  				if f, ok := decl.(*ast.Field); ok {
    72  					a.Expr = f.Value
    73  					f.Value = a
    74  				}
    75  			}
    76  
    77  			s.Elts = append(s.Elts, decl)
    78  		}
    79  
    80  		return s
    81  
    82  	case *adt.FieldReference:
    83  		f := e.frame(x.UpCount)
    84  		entry := f.fields[x.Label]
    85  
    86  		name := x.Label.IdentString(e.ctx)
    87  		switch {
    88  		case entry.alias != "":
    89  			name = entry.alias
    90  
    91  		case !ast.IsValidIdent(name):
    92  			name = "X"
    93  			if x.Src != nil {
    94  				name = x.Src.Name
    95  			}
    96  			name = e.uniqueAlias(name)
    97  			entry.alias = name
    98  		}
    99  
   100  		ident := ast.NewIdent(name)
   101  		entry.references = append(entry.references, ident)
   102  
   103  		if f.fields != nil {
   104  			f.fields[x.Label] = entry
   105  		}
   106  
   107  		return ident
   108  
   109  	case *adt.ValueReference:
   110  		name := x.Label.IdentString(e.ctx)
   111  		if a, ok := x.Src.Node.(*ast.Alias); ok { // Should always pass
   112  			if b, ok := e.valueAlias[a]; ok {
   113  				name = b.Ident.Name
   114  			}
   115  		}
   116  		ident := ast.NewIdent(name)
   117  		return ident
   118  
   119  	case *adt.LabelReference:
   120  		// get potential label from Source. Otherwise use X.
   121  		f := e.frame(x.UpCount)
   122  		if f.field == nil {
   123  			// This can happen when the LabelReference is evaluated outside of
   124  			// normal evaluation, that is, if a pattern constraint or
   125  			// additional constraint is evaluated by itself.
   126  			return ast.NewIdent("string")
   127  		}
   128  		list, ok := f.field.Label.(*ast.ListLit)
   129  		if !ok || len(list.Elts) != 1 {
   130  			panic("label reference to non-pattern constraint field or invalid list")
   131  		}
   132  		name := ""
   133  		if a, ok := list.Elts[0].(*ast.Alias); ok {
   134  			name = a.Ident.Name
   135  		} else {
   136  			if x.Src != nil {
   137  				name = x.Src.Name
   138  			}
   139  			name = e.uniqueAlias(name)
   140  			list.Elts[0] = &ast.Alias{
   141  				Ident: ast.NewIdent(name),
   142  				Expr:  list.Elts[0],
   143  			}
   144  		}
   145  		ident := ast.NewIdent(name)
   146  		ident.Scope = f.field
   147  		ident.Node = f.labelExpr
   148  		return ident
   149  
   150  	case *adt.DynamicReference:
   151  		// get potential label from Source. Otherwise use X.
   152  		name := "X"
   153  		f := e.frame(x.UpCount)
   154  		if d := f.field; d != nil {
   155  			if x.Src != nil {
   156  				name = x.Src.Name
   157  			}
   158  			name = e.getFieldAlias(d, name)
   159  		}
   160  		ident := ast.NewIdent(name)
   161  		ident.Scope = f.field
   162  		ident.Node = f.field
   163  		return ident
   164  
   165  	case *adt.ImportReference:
   166  		importPath := x.ImportPath.StringValue(e.index)
   167  		spec := ast.NewImport(nil, importPath)
   168  
   169  		info, _ := astutil.ParseImportSpec(spec)
   170  		name := info.PkgName
   171  		if x.Label != 0 {
   172  			name = x.Label.StringValue(e.index)
   173  			if name != info.PkgName {
   174  				spec.Name = ast.NewIdent(name)
   175  			}
   176  		}
   177  		ident := ast.NewIdent(name)
   178  		ident.Node = spec
   179  		return ident
   180  
   181  	case *adt.LetReference:
   182  		// TODO: Handle references that went out of scope. In case of aliases
   183  		// this means they may need to be reproduced locally. Most of these
   184  		// issues can be avoided by either fully expanding a configuration
   185  		// (export) or not at all (def).
   186  		//
   187  		i := len(e.stack) - 1 - int(x.UpCount) - 1
   188  		if i < 0 {
   189  			i = 0
   190  		}
   191  		f := &(e.stack[i])
   192  		let := f.let[x.X]
   193  		if let == nil {
   194  			if f.let == nil {
   195  				f.let = map[adt.Expr]*ast.LetClause{}
   196  			}
   197  			label := e.uniqueLetIdent(x.Label, x.X)
   198  
   199  			name := label.IdentString(e.ctx)
   200  
   201  			// A let may be added multiple times to the same scope as a result
   202  			// of how merging works. If that happens here it must be one
   203  			// originating from the same expression, and it is safe to drop.
   204  			for _, elt := range f.scope.Elts {
   205  				if a, ok := elt.(*ast.LetClause); ok {
   206  					if a.Ident.Name == name {
   207  						let = a
   208  						break
   209  					}
   210  				}
   211  			}
   212  
   213  			if let == nil {
   214  				let = &ast.LetClause{
   215  					Ident: e.ident(label),
   216  					Expr:  e.expr(x.X),
   217  				}
   218  				f.scope.Elts = append(f.scope.Elts, let)
   219  			}
   220  
   221  			f.let[x.X] = let
   222  		}
   223  		ident := ast.NewIdent(let.Ident.Name)
   224  		ident.Node = let
   225  		ident.Scope = f.scope
   226  		return ident
   227  
   228  	case *adt.SelectorExpr:
   229  		return &ast.SelectorExpr{
   230  			X:   e.expr(x.X),
   231  			Sel: e.stringLabel(x.Sel),
   232  		}
   233  
   234  	case *adt.IndexExpr:
   235  		return &ast.IndexExpr{
   236  			X:     e.expr(x.X),
   237  			Index: e.expr(x.Index),
   238  		}
   239  
   240  	case *adt.SliceExpr:
   241  		var lo, hi ast.Expr
   242  		if x.Lo != nil {
   243  			lo = e.expr(x.Lo)
   244  		}
   245  		if x.Hi != nil {
   246  			hi = e.expr(x.Hi)
   247  		}
   248  		// TODO: Stride not yet? implemented.
   249  		// if x.Stride != nil {
   250  		// 	stride = e.expr(x.Stride)
   251  		// }
   252  		return &ast.SliceExpr{X: e.expr(x.X), Low: lo, High: hi}
   253  
   254  	case *adt.Interpolation:
   255  		var (
   256  			tripple    = `"""`
   257  			openQuote  = `"`
   258  			closeQuote = `"`
   259  			f          = literal.String
   260  		)
   261  		if x.K&adt.BytesKind != 0 {
   262  			tripple = `'''`
   263  			openQuote = `'`
   264  			closeQuote = `'`
   265  			f = literal.Bytes
   266  		}
   267  		toString := func(v adt.Expr) string {
   268  			str := ""
   269  			switch x := v.(type) {
   270  			case *adt.String:
   271  				str = x.Str
   272  			case *adt.Bytes:
   273  				str = string(x.B)
   274  			}
   275  			return str
   276  		}
   277  		t := &ast.Interpolation{}
   278  		f = f.WithGraphicOnly()
   279  		indent := ""
   280  		// TODO: mark formatting in interpolation itself.
   281  		for i := 0; i < len(x.Parts); i += 2 {
   282  			if strings.IndexByte(toString(x.Parts[i]), '\n') >= 0 {
   283  				f = f.WithTabIndent(len(e.stack))
   284  				indent = strings.Repeat("\t", len(e.stack))
   285  				openQuote = tripple + "\n" + indent
   286  				closeQuote = tripple
   287  				break
   288  			}
   289  		}
   290  		prefix := openQuote
   291  		suffix := `\(`
   292  		for i, elem := range x.Parts {
   293  			if i%2 == 1 {
   294  				t.Elts = append(t.Elts, e.expr(elem))
   295  			} else {
   296  				// b := strings.Builder{}
   297  				buf := []byte(prefix)
   298  				str := toString(elem)
   299  				buf = f.AppendEscaped(buf, str)
   300  				if i == len(x.Parts)-1 {
   301  					if len(closeQuote) > 1 {
   302  						buf = append(buf, '\n')
   303  						buf = append(buf, indent...)
   304  					}
   305  					buf = append(buf, closeQuote...)
   306  				} else {
   307  					if bytes.HasSuffix(buf, []byte("\n")) {
   308  						buf = append(buf, indent...)
   309  					}
   310  					buf = append(buf, suffix...)
   311  				}
   312  				t.Elts = append(t.Elts, &ast.BasicLit{
   313  					Kind:  token.STRING,
   314  					Value: string(buf),
   315  				})
   316  			}
   317  			prefix = ")"
   318  		}
   319  		return t
   320  
   321  	case *adt.BoundExpr:
   322  		return &ast.UnaryExpr{
   323  			Op: x.Op.Token(),
   324  			X:  e.expr(x.Expr),
   325  		}
   326  
   327  	case *adt.UnaryExpr:
   328  		return &ast.UnaryExpr{
   329  			Op: x.Op.Token(),
   330  			X:  e.expr(x.X),
   331  		}
   332  
   333  	case *adt.BinaryExpr:
   334  		return &ast.BinaryExpr{
   335  			Op: x.Op.Token(),
   336  			X:  e.expr(x.X),
   337  			Y:  e.expr(x.Y),
   338  		}
   339  
   340  	case *adt.CallExpr:
   341  		a := []ast.Expr{}
   342  		for _, arg := range x.Args {
   343  			v := e.expr(arg)
   344  			if v == nil {
   345  				e.expr(arg)
   346  				panic("")
   347  			}
   348  			a = append(a, v)
   349  		}
   350  		fun := e.expr(x.Fun)
   351  		return &ast.CallExpr{Fun: fun, Args: a}
   352  
   353  	case *adt.DisjunctionExpr:
   354  		a := []ast.Expr{}
   355  		for _, d := range x.Values {
   356  			v := e.expr(d.Val)
   357  			if d.Default {
   358  				v = &ast.UnaryExpr{Op: token.MUL, X: v}
   359  			}
   360  			a = append(a, v)
   361  		}
   362  		return ast.NewBinExpr(token.OR, a...)
   363  
   364  	default:
   365  		panic(fmt.Sprintf("unknown field %T", x))
   366  	}
   367  }
   368  
   369  func (e *exporter) decl(d adt.Decl) ast.Decl {
   370  	switch x := d.(type) {
   371  	case adt.Elem:
   372  		return e.elem(x)
   373  
   374  	case *adt.Field:
   375  		e.setDocs(x)
   376  		f := &ast.Field{
   377  			Label: e.stringLabel(x.Label),
   378  		}
   379  
   380  		frame := e.frame(0)
   381  		entry := frame.fields[x.Label]
   382  		entry.field = f
   383  		entry.node = f.Value
   384  		frame.fields[x.Label] = entry
   385  
   386  		f.Value = e.expr(x.Value)
   387  
   388  		// extractDocs(nil)
   389  		return f
   390  
   391  	case *adt.OptionalField:
   392  		e.setDocs(x)
   393  		f := &ast.Field{
   394  			Label:    e.stringLabel(x.Label),
   395  			Optional: token.NoSpace.Pos(),
   396  		}
   397  
   398  		frame := e.frame(0)
   399  		entry := frame.fields[x.Label]
   400  		entry.field = f
   401  		entry.node = f.Value
   402  		frame.fields[x.Label] = entry
   403  
   404  		f.Value = e.expr(x.Value)
   405  
   406  		// extractDocs(nil)
   407  		return f
   408  
   409  	case *adt.BulkOptionalField:
   410  		e.setDocs(x)
   411  		// set bulk in frame.
   412  		frame := e.frame(0)
   413  
   414  		expr := e.expr(x.Filter)
   415  		frame.labelExpr = expr // see astutil.Resolve.
   416  
   417  		if x.Label != 0 {
   418  			expr = &ast.Alias{Ident: e.ident(x.Label), Expr: expr}
   419  		}
   420  		f := &ast.Field{
   421  			Label: ast.NewList(expr),
   422  		}
   423  
   424  		frame.field = f
   425  
   426  		f.Value = e.expr(x.Value)
   427  
   428  		return f
   429  
   430  	case *adt.DynamicField:
   431  		e.setDocs(x)
   432  		key := e.expr(x.Key)
   433  		if _, ok := key.(*ast.Interpolation); !ok {
   434  			key = &ast.ParenExpr{X: key}
   435  		}
   436  		f := &ast.Field{
   437  			Label: key.(ast.Label),
   438  		}
   439  
   440  		frame := e.frame(0)
   441  		frame.field = f
   442  		frame.labelExpr = key
   443  		// extractDocs(nil)
   444  
   445  		f.Value = e.expr(x.Value)
   446  
   447  		return f
   448  
   449  	default:
   450  		panic(fmt.Sprintf("unknown field %T", x))
   451  	}
   452  }
   453  
   454  func (e *exporter) elem(d adt.Elem) ast.Expr {
   455  
   456  	switch x := d.(type) {
   457  	case adt.Expr:
   458  		return e.expr(x)
   459  
   460  	case *adt.Ellipsis:
   461  		t := &ast.Ellipsis{}
   462  		if x.Value != nil {
   463  			t.Type = e.expr(x.Value)
   464  		}
   465  		return t
   466  
   467  	case adt.Yielder:
   468  		return e.comprehension(x)
   469  
   470  	default:
   471  		panic(fmt.Sprintf("unknown field %T", x))
   472  	}
   473  }
   474  
   475  func (e *exporter) comprehension(y adt.Yielder) ast.Expr {
   476  	c := &ast.Comprehension{}
   477  
   478  	for {
   479  		switch x := y.(type) {
   480  		case *adt.ForClause:
   481  			value := e.ident(x.Value)
   482  			clause := &ast.ForClause{
   483  				Value:  value,
   484  				Source: e.expr(x.Src),
   485  			}
   486  			c.Clauses = append(c.Clauses, clause)
   487  
   488  			_, saved := e.pushFrame(nil)
   489  			defer e.popFrame(saved)
   490  
   491  			if x.Key != 0 {
   492  				key := e.ident(x.Key)
   493  				clause.Key = key
   494  				e.addField(x.Key, nil, clause)
   495  			}
   496  			e.addField(x.Value, nil, clause)
   497  
   498  			y = x.Dst
   499  
   500  		case *adt.IfClause:
   501  			clause := &ast.IfClause{Condition: e.expr(x.Condition)}
   502  			c.Clauses = append(c.Clauses, clause)
   503  			y = x.Dst
   504  
   505  		case *adt.LetClause:
   506  			clause := &ast.LetClause{
   507  				Ident: e.ident(x.Label),
   508  				Expr:  e.expr(x.Expr),
   509  			}
   510  			c.Clauses = append(c.Clauses, clause)
   511  
   512  			_, saved := e.pushFrame(nil)
   513  			defer e.popFrame(saved)
   514  
   515  			e.addField(x.Label, nil, clause)
   516  
   517  			y = x.Dst
   518  
   519  		case *adt.ValueClause:
   520  			v := e.expr(x.StructLit)
   521  			if _, ok := v.(*ast.StructLit); !ok {
   522  				v = ast.NewStruct(ast.Embed(v))
   523  			}
   524  			c.Value = v
   525  			return c
   526  
   527  		default:
   528  			panic(fmt.Sprintf("unknown field %T", x))
   529  		}
   530  	}
   531  
   532  }