/
enums.go
122 lines (110 loc) · 4.33 KB
/
enums.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright 2023 The Blocky 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
//
// https://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 filtering
import (
"fmt"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/blockysource/blocky-aip/expr"
"github.com/blockysource/blocky-aip/filtering/ast"
"github.com/blockysource/blocky-aip/token"
)
// TryParseEnumField tries to parse an enum field.
// It can be a single enum value or a repeated enum value.
func (b *Interpreter) TryParseEnumField(ctx *ParseContext, in TryParseValueInput) (TryParseValueResult, error) {
if len(in.Args) > 0 {
// A non-repeated enum field cannot have nested fields.
if ctx.ErrHandler != nil {
return TryParseValueResult{ErrPos: in.Value.Position(), ErrMsg: fmt.Sprintf("field is of %q type, but provided value is not a valid %q value: '%s'", in.Field.Kind(), in.Field.Kind(), joinedName(in.Value, in.Args...))}, ErrInvalidValue
}
return TryParseValueResult{}, ErrInvalidValue
}
if in.Field.Enum() == nil {
if ctx.ErrHandler != nil {
return TryParseValueResult{ErrPos: in.Value.Position(), ErrMsg: "field is not an enum field"}, ErrInvalidValue
}
return TryParseValueResult{}, ErrInvalidValue
}
var sl *ast.StringLiteral
switch ft := in.Value.(type) {
case *ast.StringLiteral:
sl = ft
case *ast.TextLiteral:
if in.IsOptional && ft.Token == token.NULL {
ve := expr.AcquireValueExpr()
ve.Value = nil
return TryParseValueResult{Expr: ve}, nil
}
if ctx.ErrHandler != nil {
return TryParseValueResult{ErrPos: ft.Pos, ErrMsg: fmt.Sprintf("field is of %q type, but provided value is not a valid value: '%s'. String literal required", in.Field.Enum().FullName(), ft.Value)}, ErrInvalidValue
}
return TryParseValueResult{}, ErrInvalidValue
case *ast.ArrayExpr:
// An array can be parsed as a repeated field value.
ve := expr.AcquireArrayExpr()
for _, elem := range ft.Elements {
// Try parsing each element as a enum value.
res, err := b.TryParseValue(ctx, TryParseValueInput{
Field: in.Field,
AllowIndirect: in.AllowIndirect,
IsOptional: in.IsOptional,
Value: elem,
Complexity: in.Complexity,
})
if err != nil {
return res, err
}
if res.Expr == nil {
// This is internal error, return an error.
if ctx.ErrHandler != nil {
return TryParseValueResult{ErrPos: elem.Position(), ErrMsg: "internal error: parsed expression is nil"}, ErrInternal
}
return TryParseValueResult{}, ErrInternal
}
if !in.AllowIndirect {
switch res.Expr.(type) {
case *expr.FunctionCallExpr, *expr.FieldSelectorExpr:
ve.Free()
res.Expr.Free()
if ctx.ErrHandler != nil {
return TryParseValueResult{ErrPos: elem.Position(), ErrMsg: "field cannot accept function call or field selector expression as a value"}, ErrInvalidValue
}
return TryParseValueResult{}, ErrInternal
}
}
ve.Elements = append(ve.Elements, res.Expr)
}
return TryParseValueResult{Expr: ve}, nil
case *ast.StructExpr:
// A struct is not a valid enum.
if ctx.ErrHandler != nil {
return TryParseValueResult{ErrPos: ft.Position(), ErrMsg: "field cannot accept struct expression as a value"}, ErrInvalidValue
}
return TryParseValueResult{}, ErrInvalidValue
default:
if ctx.ErrHandler != nil {
return TryParseValueResult{ErrPos: in.Value.Position(), ErrMsg: "invalid AST node"}, ErrInvalidAST
}
return TryParseValueResult{}, ErrInvalidAST
}
enumValue := in.Field.Enum().Values().ByName(protoreflect.Name(sl.Value))
if enumValue == nil {
if ctx.ErrHandler != nil {
return TryParseValueResult{ErrPos: sl.Pos, ErrMsg: fmt.Sprintf("field is of %q type, but provided value is not valid: '%s'", in.Field.Enum().FullName(), sl.Value)}, ErrInvalidValue
}
return TryParseValueResult{}, ErrInvalidValue
}
ve := expr.AcquireValueExpr()
ve.Value = enumValue.Number()
return TryParseValueResult{Expr: ve}, nil
}