builtin.gno
3.25 Kb · 81 lines
1package governor
2
3// The governor's own kinds act on the governor, and take it as an argument.
4//
5// They cannot hold one. A kind is a value in that governor's own registry, so a
6// back-pointer is a reference cycle — and the VM refuses to finalize it:
7//
8// unexpected unreal object: type=*gnolang.HeapItemValue ... isNewReal=true
9//
10// Every test passed and the realm's own filetests wrote their storage; the
11// panic came afterwards, at persistence, which is the one place a cycle shows
12// up and the reason it survived being reasoned about. So the built-ins are
13// stateless values and the engine hands them the governor at the moment it
14// dispatches.
15//
16// The three methods mirror Kind's, minus the realm token: a built-in acts on
17// the registry rather than on the world, so it has no use for a sub-realm and
18// is never given one.
19type builtin interface {
20 Name() string
21 describe(g *Governor, payload string) string
22 check(g *Governor, payload string) error
23 run(g *Governor, dispatch Dispatch, payload string) error
24}
25
26// asBuiltin reports whether a kind is one of the governor's own.
27//
28// A type assertion rather than a name check. The reserved prefix says what a
29// kind is CALLED and Offer refuses it, but the dispatch has to be decided by
30// what a kind IS — a nominal check is the one thing an impostor cannot satisfy,
31// which is the same argument grc20's IsCanonicalTeller makes.
32func asBuiltin(k Kind) (builtin, bool) {
33 b, ok := k.(builtin)
34 return b, ok
35}
36
37// The Kind side of a built-in, so it satisfies the interface the registry
38// stores. Reached only through the engine, which checks asBuiltin first.
39func (k adoptKind) Describe(payload string) string { return "" }
40func (k adoptKind) Check(payload string) error { return errBuiltinNeedsEngine }
41func (k adoptKind) Do(_ int, rlm realm, payload string) error {
42 return errBuiltinNeedsEngine
43}
44
45func (k retireKind) Describe(payload string) string { return "" }
46func (k retireKind) Check(payload string) error { return errBuiltinNeedsEngine }
47func (k retireKind) Do(_ int, rlm realm, payload string) error {
48 return errBuiltinNeedsEngine
49}
50
51func (k rulesKind) Describe(payload string) string { return "" }
52func (k rulesKind) Check(payload string) error { return errBuiltinNeedsEngine }
53func (k rulesKind) Do(_ int, rlm realm, payload string) error {
54 return errBuiltinNeedsEngine
55}
56
57func (k batchKind) Describe(payload string) string { return "" }
58func (k batchKind) Check(payload string) error { return errBuiltinNeedsEngine }
59func (k batchKind) Do(_ int, rlm realm, payload string) error {
60 return errBuiltinNeedsEngine
61}
62
63// errBuiltinNeedsEngine is what these return if anything ever reaches them the
64// ordinary way. Unreachable through the engine, and an error rather than a
65// panic because a kind returning one is a proposal that fails cleanly.
66var errBuiltinNeedsEngine = govErr("a built-in kind has to be run by the governor that owns it")
67
68// checkKind and describeKind route to whichever half a kind has.
69func (g *Governor) checkKind(k Kind, payload string) error {
70 if b, ok := asBuiltin(k); ok {
71 return b.check(g, payload)
72 }
73 return k.Check(payload)
74}
75
76func (g *Governor) describeKind(k Kind, payload string) string {
77 if b, ok := asBuiltin(k); ok {
78 return b.describe(g, payload)
79 }
80 return k.Describe(payload)
81}