-
Notifications
You must be signed in to change notification settings - Fork 15
/
expr_bytes.go
86 lines (78 loc) · 2.11 KB
/
expr_bytes.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
package rel
import (
"strings"
"github.com/arr-ai/wbnf/parser"
"github.com/go-errors/errors"
)
// BytesExpr is an expression that evaluates to a Byte Array
type BytesExpr struct {
ExprScanner
elements []Expr
}
func NewBytesExpr(scanner parser.Scanner, elements ...Expr) Expr {
bytes := make([]byte, 0, len(elements))
for _, expr := range elements {
if value, is := exprIsValue(expr); is {
if byteNum, is := value.(Number); is && isByteNumber(byteNum) {
bytes = append(bytes, byte(int(byteNum)))
continue
}
}
return BytesExpr{ExprScanner{scanner}, elements}
}
return NewBytes(bytes)
}
func (b BytesExpr) Eval(local Scope) (Value, error) {
bytes := make([]byte, 0)
for _, expr := range b.elements {
value, err := expr.Eval(local)
if err != nil {
return nil, WrapContext(err, b, local)
}
switch v := value.(type) {
case Number:
if !isByteNumber(v) {
return nil, WrapContext(errors.Errorf("BytesExpr.Eval: Number does not represent a byte: %v", v), b, local)
}
bytes = append(bytes, byte(v))
case String:
if err := b.handleOffset(v); err != nil {
return nil, WrapContext(err, b, local)
}
bytes = append(bytes, []byte(string(v.s))...)
case GenericSet:
if s, isString := AsString(v); isString {
if err := b.handleOffset(s); err != nil {
return nil, WrapContext(err, b, local)
}
bytes = append(bytes, []byte(string(s.s))...)
continue
}
return nil, WrapContext(errors.Errorf("BytesExpr.Eval: Set %v is not supported", expr), b, local)
default:
return nil, WrapContext(errors.Errorf("BytesExpr.Eval: %T is not supported", v), b, local)
}
}
return NewBytes(bytes), nil
}
func (b BytesExpr) handleOffset(s String) error {
if s.offset != 0 {
return errors.Errorf("BytesExpr.Eval: offsetted String is not supported: %v", s)
}
return nil
}
func (b BytesExpr) String() string {
s := strings.Builder{}
s.WriteString("<<")
for i, expr := range b.elements {
if i > 0 {
s.WriteString(", ")
}
s.WriteString(expr.String())
}
s.WriteString(">>")
return s.String()
}
func isByteNumber(n Number) bool {
return int(n) >= 0 && int(n) <= 255
}