-
Notifications
You must be signed in to change notification settings - Fork 14
/
format.go
272 lines (245 loc) · 7.33 KB
/
format.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
// Copyright (c) 2014, Kevin Walsh. All rights reserved.
//
// 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 auth
// This file implements Format() functions for pretty-printing elements.
// When printed with format verb %v, the "verbose" long form is used.
// When printed with format verb %s, the "short" elided form is used.
// When printed with other verbs, the output format is unspecified.
import (
"encoding/base64"
"fmt"
)
// ElisionCutoff is the maximum length a String or Byte can be without being elided.
var ElisionCutoff int = 32
// ElisionLength is the number of characters to show in an elided String or Byte.
var ElisionLength int = 24
// Format outputs a pretty-printed Prin.
func (p Prin) Format(out fmt.State, verb rune) {
fmt.Fprintf(out, "%s(", p.Type)
p.KeyHash.Format(out, verb)
fmt.Fprint(out, ")")
p.Ext.Format(out, verb)
}
// Format outputs a pretty-printed PrinTail.
func (p PrinTail) Format(out fmt.State, verb rune) {
fmt.Fprintf(out, "ext")
p.Ext.Format(out, verb)
}
// Format outputs a pretty-printed PrinExt.
func (e PrinExt) Format(out fmt.State, verb rune) {
formatNameAndArg(out, e.Name, e.Arg, verb)
}
// formatNameAndArg outputs a pretty-printed name and argument list using short
// or long formats.
func formatNameAndArg(out fmt.State, name string, arg []Term, verb rune) {
fmt.Fprintf(out, "%s(", name)
for i, a := range arg {
if i > 0 {
fmt.Fprint(out, ", ")
}
a.Format(out, verb)
}
fmt.Fprint(out, ")")
}
// Format outputs a pretty-printed SubPrin.
func (p SubPrin) Format(out fmt.State, verb rune) {
for _, e := range p {
fmt.Fprint(out, ".")
e.Format(out, verb)
}
}
// Format outputs a pretty-printed Str.
func (t Str) Format(out fmt.State, verb rune) {
if verb == 's' && len(string(t)) > ElisionCutoff {
fmt.Fprintf(out, "%q...", string(t)[:ElisionLength])
} else {
fmt.Fprintf(out, "%q", string(t))
}
}
// Format outputs a pretty-printed Bytes.
func (t Bytes) Format(out fmt.State, verb rune) {
if out.Flag('#') {
// use alternate format: base64w
s := base64.URLEncoding.EncodeToString([]byte(t))
if verb == 's' && len(string(t)) > ElisionCutoff {
fmt.Fprintf(out, "{%s...}", s[:ElisionLength])
} else {
fmt.Fprintf(out, "{%s}", s)
}
} else {
// use default format: hex
if verb == 's' && len(string(t)) > ElisionCutoff {
fmt.Fprintf(out, "[%02x...]", []byte(t)[:ElisionLength])
} else {
fmt.Fprintf(out, "[%02x]", []byte(t))
}
}
}
// Format outputs a pretty-printed Int.
func (t Int) Format(out fmt.State, verb rune) {
fmt.Fprintf(out, "%d", int64(t))
}
// Format outputs a pretty-printed TermVar.
func (t TermVar) Format(out fmt.State, verb rune) {
fmt.Fprint(out, string(t))
}
// Format outputs a pretty-printed Pred.
func (f Pred) Format(out fmt.State, verb rune) {
formatNameAndArg(out, f.Name, f.Arg, verb)
}
// Format outputs a pretty-printed Const.
func (f Const) Format(out fmt.State, verb rune) {
if f == true {
fmt.Fprint(out, "true")
} else {
fmt.Fprint(out, "false")
}
}
// Format outputs a pretty-printed Not.
func (f Not) Format(out fmt.State, verb rune) {
fmt.Fprint(out, "not ")
formatFormWithParens(out, precedenceHigh, true, f.Negand, verb)
}
// Format outputs a pretty-printed And.
func (f And) Format(out fmt.State, verb rune) {
if len(f.Conjunct) == 0 {
fmt.Fprint(out, "true")
} else if len(f.Conjunct) == 1 {
f.Conjunct[0].Format(out, verb)
} else {
n := len(f.Conjunct)
for i, e := range f.Conjunct {
if i > 0 {
fmt.Fprint(out, " and ")
}
formatFormWithParens(out, precedenceAnd, i == n-1, e, verb)
}
}
}
// Format outputs a pretty-printed Or.
func (f Or) Format(out fmt.State, verb rune) {
if len(f.Disjunct) == 0 {
fmt.Fprint(out, "false")
} else if len(f.Disjunct) == 1 {
f.Disjunct[0].Format(out, verb)
} else {
n := len(f.Disjunct)
for i, e := range f.Disjunct {
if i > 0 {
fmt.Fprint(out, " or ")
}
formatFormWithParens(out, precedenceOr, i == n-1, e, verb)
}
}
}
// Format outputs a pretty-printed Implies.
func (f Implies) Format(out fmt.State, verb rune) {
formatFormWithParens(out, precedenceLow+1, false, f.Antecedent, verb)
fmt.Fprint(out, " implies ")
formatFormWithParens(out, precedenceLow, true, f.Consequent, verb)
}
// Format outputs a pretty-printed Speaksfor.
func (f Speaksfor) Format(out fmt.State, verb rune) {
f.Delegate.Format(out, verb)
fmt.Fprint(out, " speaksfor ")
f.Delegator.Format(out, verb)
}
// Format outputs a pretty-printed Says.
func (f Says) Format(out fmt.State, verb rune) {
f.Speaker.Format(out, verb)
if f.Commences() {
fmt.Fprintf(out, " from %d", *f.Time)
}
if f.Expires() {
fmt.Fprintf(out, " until %d", *f.Expiration)
}
fmt.Fprint(out, " says ")
f.Message.Format(out, verb)
}
// Format outputs a pretty-printed Forall.
func (f Forall) Format(out fmt.State, verb rune) {
fmt.Fprintf(out, "forall %s: ", f.Var)
f.Body.Format(out, verb)
}
// Format outputs a pretty-printed Exists.
func (f Exists) Format(out fmt.State, verb rune) {
fmt.Fprintf(out, "exists %s: ", f.Var)
f.Body.Format(out, verb)
}
const (
precedenceLow = iota // lowest: implies, says, right speaksfor, right forall, right exists
precedenceOr
precedenceAnd
precedenceHigh // not, true, false, Pred, left speaksfor, left forall, left exists
)
// precedence returns an integer indicating the relative precedence of f.
func precedence(f Form, right bool) int {
switch f := f.(type) {
case Says, Speaksfor, Forall, Exists, *Says, *Speaksfor, *Forall, *Exists:
if right {
return precedenceHigh
}
return precedenceLow
case Implies, *Implies:
return precedenceLow
case Or:
if len(f.Disjunct) == 0 {
return precedenceHigh // Or{} == false
} else if len(f.Disjunct) == 1 {
return precedence(f.Disjunct[0], right) // Or{f} == f
} else {
return precedenceOr
}
case *Or:
if len(f.Disjunct) == 0 {
return precedenceHigh // Or{} == false
} else if len(f.Disjunct) == 1 {
return precedence(f.Disjunct[0], right) // Or{f} == f
} else {
return precedenceOr
}
case And:
if len(f.Conjunct) == 0 {
return precedenceHigh // And{} == true
} else if len(f.Conjunct) == 1 {
return precedence(f.Conjunct[0], right) // And{f} == f
} else {
return precedenceAnd
}
case *And:
if len(f.Conjunct) == 0 {
return precedenceHigh // And{} == true
} else if len(f.Conjunct) == 1 {
return precedence(f.Conjunct[0], right) // And{f} == f
} else {
return precedenceAnd
}
case Not, Pred, Const, *Not, *Pred, *Const:
return precedenceHigh
default:
panic("not reached")
}
}
// formatFormWithParens outputs either f or (f), depending on how level compares
// to the precedence of f and whether f appears on the right side of a binary
// operator.
func formatFormWithParens(out fmt.State, level int, right bool, f Form, verb rune) {
if level > precedence(f, right) {
fmt.Fprint(out, "(")
f.Format(out, verb)
fmt.Fprint(out, ")")
} else {
f.Format(out, verb)
}
}