blob: 432025260b7392ebaf678319e88d9f4b94e86bb3 [file] [log] [blame]
// Copyright 2020 CUE Authors
//
// 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 compile
import (
"strings"
"github.com/cockroachdb/apd/v2"
"golang.org/x/text/unicode/norm"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/literal"
"cuelang.org/go/cue/token"
"cuelang.org/go/internal/core/adt"
)
// LabelFromNode converts an ADT node to a feature.
func (c *compiler) label(n ast.Node) adt.Feature {
index := c.index
switch x := n.(type) {
case *ast.Ident:
s := x.Name
i := index.StringToIndex(x.Name)
t := adt.StringLabel
switch {
case strings.HasPrefix(s, "#_"):
t = adt.HiddenDefinitionLabel
case strings.HasPrefix(s, "#"):
t = adt.DefinitionLabel
case strings.HasPrefix(s, "_"):
t = adt.HiddenLabel
}
f, err := adt.MakeLabel(n, i, t)
if err != nil {
c.errf(n, "invalid identifier label: %v", err)
return adt.InvalidLabel
}
return f
case *ast.BasicLit:
switch x.Kind {
case token.STRING:
const msg = "invalid string label: %v"
s, err := literal.Unquote(x.Value)
if err != nil {
c.errf(n, msg, err)
return adt.InvalidLabel
}
i := int64(index.StringToIndex(norm.NFC.String(s)))
f, err := adt.MakeLabel(n, i, adt.StringLabel)
if err != nil {
c.errf(n, msg, err)
}
return f
case token.INT:
const msg = "invalid int label: %v"
if err := literal.ParseNum(x.Value, &c.num); err != nil {
c.errf(n, msg, err)
return adt.InvalidLabel
}
var d apd.Decimal
if err := c.num.Decimal(&d); err != nil {
c.errf(n, msg, err)
return adt.InvalidLabel
}
i, err := d.Int64()
if err != nil {
c.errf(n, msg, err)
return adt.InvalidLabel
}
f, err := adt.MakeLabel(n, i, adt.IntLabel)
if err != nil {
c.errf(n, msg, err)
return adt.InvalidLabel
}
return f
case token.FLOAT:
_ = c.errf(n, "float %s cannot be used as label", x.Value)
return adt.InvalidLabel
default: // keywords (null, true, false, for, in, if, let)
i := index.StringToIndex(x.Kind.String())
f, err := adt.MakeLabel(n, i, adt.StringLabel)
if err != nil {
c.errf(n, "invalid string label: %v", err)
}
return f
}
default:
c.errf(n, "unsupported label node type %T", n)
return adt.InvalidLabel
}
}
// A labeler converts an AST node to a string representation.
type labeler interface {
labelString() string
}
type fieldLabel ast.Field
func (l *fieldLabel) labelString() string {
lab := l.Label
if a, ok := lab.(*ast.Alias); ok {
if x, _ := a.Expr.(ast.Label); x != nil {
lab = x
}
}
switch x := lab.(type) {
case *ast.Ident:
return x.Name
case *ast.BasicLit:
if x.Kind == token.STRING {
s, err := literal.Unquote(x.Value)
if err == nil && ast.IsValidIdent(s) {
return s
}
}
return x.Value
case *ast.ListLit:
return "[]" // TODO: more detail
case *ast.Interpolation:
return "?"
// case *ast.ParenExpr:
}
return "<unknown>"
}
type forScope ast.ForClause
func (l *forScope) labelString() string {
// TODO: include more info in square brackets.
return "for[]"
}
type letScope ast.LetClause
func (l *letScope) labelString() string {
// TODO: include more info in square brackets.
return "let[]"
}
// TODO(legacy): remove
type deprecatedAliasScope ast.Alias
func (l *deprecatedAliasScope) labelString() string {
// TODO: include more info in square brackets.
return "let[]"
}