-
Notifications
You must be signed in to change notification settings - Fork 12
/
translate.cue
86 lines (75 loc) · 3.09 KB
/
translate.cue
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 thema
import "list"
// Translate takes a resource, a lineage, and a rule for deciding a target
// schema version. The resource is iteratively transformed through the lineage's
// list of schemas, starting at the version the resource is valid against, and
// continuing until the target schema version is reached.
//
// The out values are the resource in final translated form, the schema versions
// at which the translation started and ended, and any lacunae emitted during
// translation.
//
// TODO functionize
// TODO backwards-translation is not yet supported
#Translate: {
resource: lin.JoinSchema
lin: #Lineage
to: #SearchCriteria
_transl: {
init: #ValidatedResource
schemarange: [..._#vSch]
_#step: {
resource: lin.JoinSchema
v: #SchemaVersion
lacunae: [...#Lacuna]
}
// The accumulator holds the results of each translation step.
accum: list.Repeat([_#step], len(schemarange)+1)
accum: [{ resource: init.r, v: init._v, lacunae: [] }, for i, vsch in schemarange {
let lastr = accum[i-1]
v: vsch.v
if vsch.v[0] == lastr._v[0] {
// Same sequence. Translation is through implicit lens; simple unification.
// NOTE this unification drags along defaults; it's one of
// the key places where thema is maybe-sorta implicitly assuming
// its inputs are concrete resources, and won't work quite right
// with incomplete CUE structures
resource: lastr.resource.r & (#Pick & { lin: lin, v: vsch }).out
lacunae: []
}
if vsch.v[0] > lastr._v[0] {
// Crossing sequences. Translate via the explicit lens.
// Feed the lens "from" input with the resource output of the
// last translation (or init)
let lens = { from: lastr.resource } & lin.Seqs[vsch.v[0]].lens.forward
resource: lens.translated
lacunae: lens.lacunae
}
}]
out: {
from: init._v
to: accum[len(accum)-1].v
resource: accum[len(accum)-1].v
lacunae: [for step in accum if len(step.lacunae) > 0 { v: step.v, lacunae: step.lacunae }]
}
}
let rarg = (#SearchAndValidate & { resource: resource, lin: lin }).out
// FIXME Must necessarily anchor translation at the input resource's schema
// version. Nevertheless, this has an unfortunate, magical smell.
to: from: rarg._v
let cmp = (_cmpSV & { l: rarg._v, r: to.to }).out
out: {
if cmp == 0 {
(_transl & { init: rarg, schemarange: [] }).out
}
if cmp == -1 {
let lo = (_flatidx & { lin: lin, rarg._v}).fidx
let hi = (_flatidx & { lin: lin, to.to[0]}).fidx
(_transl & { init: rarg, schemarange: (_all & { lin: lin }).out[lo+1:hi]}).out
}
if cmp == 1 {
// FIXME For now, we don't support backwards translation. This must change.
_|_
}
}
}