this repo has no description
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
15package export
16
17import (
18 "crypto/md5"
19 "fmt"
20 "io"
21 "strconv"
22
23 "cuelang.org/go/cue/ast"
24 "cuelang.org/go/cue/token"
25 "cuelang.org/go/internal/core/adt"
26)
27
28func (e *exporter) stringLabel(f adt.Feature) ast.Label {
29 x := f.Index()
30 switch f.Typ() {
31 case adt.IntLabel:
32 return ast.NewLit(token.INT, strconv.Itoa(x))
33
34 case adt.DefinitionLabel, adt.HiddenLabel, adt.HiddenDefinitionLabel:
35 s := e.identString(f)
36 return ast.NewIdent(s)
37
38 default:
39 return ast.NewStringLabel(e.ctx.IndexToString(int64(x)))
40 }
41}
42
43// identString converts the given Feature f to an identifier string.
44//
45// Hidden field mangling:
46//
47// If f is a hidden field that comes from an expanded package, it will mangle
48// the name by expending it with the MD5 hash of the package name. This is to
49// avoid collisions of the hidden identifiers when namespaces are merged.
50// It uses the MD5 hash to allow hidden fields from the same package to
51// still match across inlining and unifications.
52//
53// TODO: Alternatives approaches to consider:
54// 1. Rewrite to unique hidden field names. This means, though, that hidden
55// fields may not match across unifications. That may be okay.
56// 2. Force inline hidden fields from such packages, or translate them to let
57// expressions when necessary. This should generally preserve semantics
58// quite well.
59// 3. Allow addressing hidden fields across packages, for instance by allowing
60// `_(hiddenField, pkg: "import/path")`. This kind of defeats the purpose
61// of hidden fields, though.
62//
63// Option 2 seems the best long-term solution. It should be possible to
64// piggyback on the self containment algorithm for this: basically, whenever
65// we see a hidden reference of an inlined package, we treat it as an
66// external reference itself.
67//
68// For now, as this only can occur when the InlineImports feature is used,
69// we use this simpler approach.
70func (e *exporter) identString(f adt.Feature) string {
71 s := f.IdentString(e.ctx)
72
73 if !f.IsHidden() || !e.cfg.InlineImports {
74 return s
75 }
76
77 pkg := f.PkgID(e.ctx)
78 if pkg == "" || pkg == "_" || pkg == e.pkgID {
79 return s
80 }
81
82 if e.pkgHash == nil {
83 e.pkgHash = map[string]string{}
84 }
85 id, ok := e.pkgHash[pkg]
86 if !ok {
87 h := md5.New()
88 io.WriteString(h, pkg)
89 b := h.Sum(nil)
90 id = fmt.Sprintf("_%8X", b[:4])
91 e.pkgHash[pkg] = id
92 }
93 s += id
94
95 return s
96}