/
interpreter.go
109 lines (98 loc) · 2.29 KB
/
interpreter.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
package apk
import (
"encoding/base64"
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/jonjohnsonjr/dagdotdev/internal/explore/lexer"
)
func evalBytes(j string, b []byte) ([]byte, string, error) {
quote := false // this is a hack, we should be lexing properly instead
l := lexer.Lex(j, j)
item := l.NextItem()
// Test the first thing to see if it's expected to be JSON.
var v interface{} = b
if item.Typ == lexer.ItemAccessor || item.Typ == lexer.ItemIndex {
if err := json.Unmarshal(json.RawMessage(b), &v); err != nil {
return nil, "", fmt.Errorf("unmarshal: %w", err)
}
}
for {
if item.Typ == lexer.ItemEOF {
break
}
switch item.Typ {
case lexer.ItemError:
return nil, "", fmt.Errorf("lexer.ItemError: %s", item.Val)
case lexer.ItemAccessor:
quote = true
vv, ok := v.(map[string]interface{})
if !ok {
return nil, "", fmt.Errorf("eval: access %s", item.Val)
}
v = vv[item.Val]
case lexer.ItemIndex:
vv, ok := v.([]interface{})
if !ok {
return nil, "", fmt.Errorf("eval: index %s", item.Val)
}
idx, err := strconv.Atoi(item.Val)
if err != nil {
return nil, "", fmt.Errorf("atoi: %w", err)
}
v = vv[idx]
case lexer.ItemSentinel:
val := strings.TrimSpace(item.Val)
if val == "base64 -d" {
s, err := toString(v)
if err != nil {
return nil, "", err
}
v, err = base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, "", fmt.Errorf("base64 -d: %w", err)
}
} else if val == `awk '{print $1"="}'` {
s, err := toString(v)
if err != nil {
return nil, "", err
}
v = s + "="
} else if val == `awk '{print $1"=="}'` {
s, err := toString(v)
if err != nil {
return nil, "", err
}
v = s + "=="
}
}
item = l.NextItem()
}
b, err := toBytes(v)
if err != nil {
return nil, "", err
}
if quote {
j = "jq -r '" + j + "'"
}
return b, j, nil
}
func toString(v interface{}) (string, error) {
switch vv := v.(type) {
case string:
return vv, nil
case []byte:
return string(vv), nil
}
return "", fmt.Errorf("cannot convert %T to string", v)
}
func toBytes(v interface{}) ([]byte, error) {
switch vv := v.(type) {
case string:
return []byte(vv), nil
case []byte:
return vv, nil
}
return nil, fmt.Errorf("cannot convert %T to bytes", v)
}