github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/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/joomcode/cue/cue/ast"
    23  	"github.com/joomcode/cue/cue/ast/astutil"
    24  	"github.com/joomcode/cue/cue/literal"
    25  	"github.com/joomcode/cue/cue/token"
    26  	"github.com/joomcode/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.Elem, 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  		return e.resolveLet(x)
   183  
   184  	case *adt.SelectorExpr:
   185  		return &ast.SelectorExpr{
   186  			X:   e.expr(x.X),
   187  			Sel: e.stringLabel(x.Sel),
   188  		}
   189  
   190  	case *adt.IndexExpr:
   191  		return &ast.IndexExpr{
   192  			X:     e.expr(x.X),
   193  			Index: e.expr(x.Index),
   194  		}
   195  
   196  	case *adt.SliceExpr:
   197  		var lo, hi ast.Expr
   198  		if x.Lo != nil {
   199  			lo = e.expr(x.Lo)
   200  		}
   201  		if x.Hi != nil {
   202  			hi = e.expr(x.Hi)
   203  		}
   204  		// TODO: Stride not yet? implemented.
   205  		// if x.Stride != nil {
   206  		// 	stride = e.expr(x.Stride)
   207  		// }
   208  		return &ast.SliceExpr{X: e.expr(x.X), Low: lo, High: hi}
   209  
   210  	case *adt.Interpolation:
   211  		var (
   212  			tripple    = `"""`
   213  			openQuote  = `"`
   214  			closeQuote = `"`
   215  			f          = literal.String
   216  		)
   217  		if x.K&adt.BytesKind != 0 {
   218  			tripple = `'''`
   219  			openQuote = `'`
   220  			closeQuote = `'`
   221  			f = literal.Bytes
   222  		}
   223  		toString := func(v adt.Expr) string {
   224  			str := ""
   225  			switch x := v.(type) {
   226  			case *adt.String:
   227  				str = x.Str
   228  			case *adt.Bytes:
   229  				str = string(x.B)
   230  			}
   231  			return str
   232  		}
   233  		t := &ast.Interpolation{}
   234  		f = f.WithGraphicOnly()
   235  		indent := ""
   236  		// TODO: mark formatting in interpolation itself.
   237  		for i := 0; i < len(x.Parts); i += 2 {
   238  			if strings.IndexByte(toString(x.Parts[i]), '\n') >= 0 {
   239  				f = f.WithTabIndent(len(e.stack))
   240  				indent = strings.Repeat("\t", len(e.stack))
   241  				openQuote = tripple + "\n" + indent
   242  				closeQuote = tripple
   243  				break
   244  			}
   245  		}
   246  		prefix := openQuote
   247  		suffix := `\(`
   248  		for i, elem := range x.Parts {
   249  			if i%2 == 1 {
   250  				t.Elts = append(t.Elts, e.expr(elem))
   251  			} else {
   252  				// b := strings.Builder{}
   253  				buf := []byte(prefix)
   254  				str := toString(elem)
   255  				buf = f.AppendEscaped(buf, str)
   256  				if i == len(x.Parts)-1 {
   257  					if len(closeQuote) > 1 {
   258  						buf = append(buf, '\n')
   259  						buf = append(buf, indent...)
   260  					}
   261  					buf = append(buf, closeQuote...)
   262  				} else {
   263  					if bytes.HasSuffix(buf, []byte("\n")) {
   264  						buf = append(buf, indent...)
   265  					}
   266  					buf = append(buf, suffix...)
   267  				}
   268  				t.Elts = append(t.Elts, &ast.BasicLit{
   269  					Kind:  token.STRING,
   270  					Value: string(buf),
   271  				})
   272  			}
   273  			prefix = ")"
   274  		}
   275  		return t
   276  
   277  	case *adt.BoundExpr:
   278  		return &ast.UnaryExpr{
   279  			Op: x.Op.Token(),
   280  			X:  e.expr(x.Expr),
   281  		}
   282  
   283  	case *adt.UnaryExpr:
   284  		return &ast.UnaryExpr{
   285  			Op: x.Op.Token(),
   286  			X:  e.expr(x.X),
   287  		}
   288  
   289  	case *adt.BinaryExpr:
   290  		return &ast.BinaryExpr{
   291  			Op: x.Op.Token(),
   292  			X:  e.expr(x.X),
   293  			Y:  e.expr(x.Y),
   294  		}
   295  
   296  	case *adt.CallExpr:
   297  		a := []ast.Expr{}
   298  		for _, arg := range x.Args {
   299  			v := e.expr(arg)
   300  			if v == nil {
   301  				e.expr(arg)
   302  				panic("")
   303  			}
   304  			a = append(a, v)
   305  		}
   306  		fun := e.expr(x.Fun)
   307  		return &ast.CallExpr{Fun: fun, Args: a}
   308  
   309  	case *adt.DisjunctionExpr:
   310  		a := []ast.Expr{}
   311  		for _, d := range x.Values {
   312  			v := e.expr(d.Val)
   313  			if d.Default {
   314  				v = &ast.UnaryExpr{Op: token.MUL, X: v}
   315  			}
   316  			a = append(a, v)
   317  		}
   318  		return ast.NewBinExpr(token.OR, a...)
   319  
   320  	default:
   321  		panic(fmt.Sprintf("unknown field %T", x))
   322  	}
   323  }
   324  
   325  func (e *exporter) decl(d adt.Decl) ast.Decl {
   326  	switch x := d.(type) {
   327  	case adt.Elem:
   328  		return e.elem(x)
   329  
   330  	case *adt.Field:
   331  		e.setDocs(x)
   332  		f := &ast.Field{
   333  			Label: e.stringLabel(x.Label),
   334  		}
   335  
   336  		frame := e.frame(0)
   337  		entry := frame.fields[x.Label]
   338  		entry.field = f
   339  		entry.node = f.Value
   340  		frame.fields[x.Label] = entry
   341  
   342  		f.Value = e.expr(x.Value)
   343  
   344  		// extractDocs(nil)
   345  		return f
   346  
   347  	case *adt.OptionalField:
   348  		e.setDocs(x)
   349  		f := &ast.Field{
   350  			Label:    e.stringLabel(x.Label),
   351  			Optional: token.NoSpace.Pos(),
   352  		}
   353  
   354  		frame := e.frame(0)
   355  		entry := frame.fields[x.Label]
   356  		entry.field = f
   357  		entry.node = f.Value
   358  		frame.fields[x.Label] = entry
   359  
   360  		f.Value = e.expr(x.Value)
   361  
   362  		// extractDocs(nil)
   363  		return f
   364  
   365  	case *adt.BulkOptionalField:
   366  		e.setDocs(x)
   367  		// set bulk in frame.
   368  		frame := e.frame(0)
   369  
   370  		expr := e.expr(x.Filter)
   371  		frame.labelExpr = expr // see astutil.Resolve.
   372  
   373  		if x.Label != 0 {
   374  			expr = &ast.Alias{Ident: e.ident(x.Label), Expr: expr}
   375  		}
   376  		f := &ast.Field{
   377  			Label: ast.NewList(expr),
   378  		}
   379  
   380  		frame.field = f
   381  
   382  		f.Value = e.expr(x.Value)
   383  
   384  		return f
   385  
   386  	case *adt.DynamicField:
   387  		e.setDocs(x)
   388  		key := e.expr(x.Key)
   389  		if _, ok := key.(*ast.Interpolation); !ok {
   390  			key = &ast.ParenExpr{X: key}
   391  		}
   392  		f := &ast.Field{
   393  			Label: key.(ast.Label),
   394  		}
   395  
   396  		frame := e.frame(0)
   397  		frame.field = f
   398  		frame.labelExpr = key
   399  		// extractDocs(nil)
   400  
   401  		f.Value = e.expr(x.Value)
   402  
   403  		return f
   404  
   405  	default:
   406  		panic(fmt.Sprintf("unknown field %T", x))
   407  	}
   408  }
   409  
   410  func (e *exporter) elem(d adt.Elem) ast.Expr {
   411  
   412  	switch x := d.(type) {
   413  	case adt.Expr:
   414  		return e.expr(x)
   415  
   416  	case *adt.Ellipsis:
   417  		t := &ast.Ellipsis{}
   418  		if x.Value != nil {
   419  			t.Type = e.expr(x.Value)
   420  		}
   421  		return t
   422  
   423  	case *adt.Comprehension:
   424  		return e.comprehension(x)
   425  
   426  	default:
   427  		panic(fmt.Sprintf("unknown field %T", x))
   428  	}
   429  }
   430  
   431  func (e *exporter) comprehension(comp *adt.Comprehension) *ast.Comprehension {
   432  	c := &ast.Comprehension{}
   433  
   434  	y := comp.Clauses
   435  
   436  loop:
   437  	for {
   438  		switch x := y.(type) {
   439  		case *adt.ForClause:
   440  			value := e.ident(x.Value)
   441  			clause := &ast.ForClause{
   442  				Value:  value,
   443  				Source: e.expr(x.Src),
   444  			}
   445  			c.Clauses = append(c.Clauses, clause)
   446  
   447  			_, saved := e.pushFrame(nil)
   448  			defer e.popFrame(saved)
   449  
   450  			if x.Key != adt.InvalidLabel ||
   451  				(x.Syntax != nil && x.Syntax.Key != nil) {
   452  				key := e.ident(x.Key)
   453  				clause.Key = key
   454  				e.addField(x.Key, nil, clause)
   455  			}
   456  			e.addField(x.Value, nil, clause)
   457  
   458  			y = x.Dst
   459  
   460  		case *adt.IfClause:
   461  			clause := &ast.IfClause{Condition: e.expr(x.Condition)}
   462  			c.Clauses = append(c.Clauses, clause)
   463  			y = x.Dst
   464  
   465  		case *adt.LetClause:
   466  			clause := &ast.LetClause{
   467  				Ident: e.ident(x.Label),
   468  				Expr:  e.expr(x.Expr),
   469  			}
   470  			c.Clauses = append(c.Clauses, clause)
   471  
   472  			_, saved := e.pushFrame(nil)
   473  			defer e.popFrame(saved)
   474  
   475  			e.addField(x.Label, nil, clause)
   476  
   477  			y = x.Dst
   478  
   479  		case *adt.ValueClause:
   480  			break loop
   481  
   482  		default:
   483  			panic(fmt.Sprintf("unknown field %T", x))
   484  		}
   485  	}
   486  
   487  	v := e.expr(comp.Value)
   488  	if _, ok := v.(*ast.StructLit); !ok {
   489  		v = ast.NewStruct(ast.Embed(v))
   490  	}
   491  	c.Value = v
   492  	return c
   493  }