@tabnas/proto 0.6.10 → 0.6.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-descriptor.d.ts +12 -1
- package/dist/build-descriptor.js +24 -2
- package/dist/build-descriptor.js.map +1 -1
- package/dist/build-tree.d.ts +6 -0
- package/dist/build-tree.js +333 -0
- package/dist/build-tree.js.map +1 -0
- package/dist/proto.d.ts +7 -3
- package/dist/proto.js +28 -1
- package/dist/proto.js.map +1 -1
- package/dist/translate.d.ts +1 -0
- package/dist/translate.js +954 -1094
- package/dist/translate.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/build-descriptor.ts +20 -2
- package/src/build-tree.ts +313 -0
- package/src/proto.ts +34 -3
- package/src/translate.ts +955 -1094
package/dist/translate.js
CHANGED
|
@@ -34,1128 +34,988 @@ const TRANSLATION = Object.freeze({
|
|
|
34
34
|
"reads": "tree",
|
|
35
35
|
"writes": "tree",
|
|
36
36
|
"root": "object",
|
|
37
|
-
"schema": "proto-
|
|
37
|
+
"schema": "proto-ast",
|
|
38
38
|
"render": "alchemy/render.alc",
|
|
39
|
+
"transduce": "alchemy/transduce.alc",
|
|
39
40
|
"loss": [
|
|
40
|
-
"The file is written anew from its
|
|
41
|
-
"
|
|
42
|
-
"A
|
|
43
|
-
"
|
|
44
|
-
"A map field is written as map<K, V> from the entry message the reader made for it, a group as a group block from its nested message, and a proto3 optional field's synthetic oneof is not written, since the reader makes each of them again.",
|
|
45
|
-
"A number is written as the descriptor holds it: a hexadecimal or octal field number, enum value or range bound is written in decimal, an exclusive range end as its last number or max, and a number the reader read as NaN (a digit separator, 1_0, which the lexer takes and JavaScript's Number refuses) as 0_0, which reads back as NaN.",
|
|
46
|
-
"A string literal is written between double quotes, or single quotes where its text holds a double quote and no single quote, its escapes as written, since the descriptor keeps a literal's text between its quotes; a text that holds both quotes is written between the quotes whose every occurrence in it is escaped; a backtick string holding a line break, which the descriptor keeps with its backticks and no quotes hold, is written as itself, but for a reserved name, which the reader takes only from a quoted literal or an identifier; and a text that nothing holds where it goes is refused: a control character that no literal or backtick string holds (a tab, a line break outside a backtick string, the other C0 controls), both quotes unescaped, or a backslash at its end that would escape the closing quote.",
|
|
47
|
-
"An option's value is one string to the descriptor whether the file wrote it as an identifier, a string literal or an aggregate in braces, so it is written as a string literal, as the backtick string it is where it is one, as an aggregate only where neither can hold its text (a line break, or both quotes unescaped), and as an identifier for the options descriptor.proto types as enums (optimize_for, ctype, jstype, retention, targets, idempotency_level and the features) when its text is made of identifier characters; protoc reads an enum-valued or message-valued option written as a literal as a string, and a quoted value of such an option that begins with a digit, which protoc refuses, does not read back; a value no literal or backtick string holds that is no aggregate's body, which no file's descriptor holds, is written in braces too and does not read back; and a value holding a control character that no literal, backtick string or aggregate holds is refused.",
|
|
48
|
-
"A default is written bare for a field that is not a string or bytes when its text is made of a constant's characters, and as a string literal otherwise; a quoted default of such a field whose text is made of those characters but spells no one constant, which protoc refuses, does not read back.",
|
|
49
|
-
"Reserved names are written as string literals in a proto2 or proto3 file and as identifiers in an edition file, a message's or an enum's reserved ranges in one reserved statement and its names in another, each extension range in an extensions statement of its own with its options, and each extension in an extend block of its own."
|
|
41
|
+
"The file is written anew from its tree: comments, blank lines and white space are not kept, and each declaration is written on a line of its own, a block's declarations indented two spaces deeper than the line that opens it.",
|
|
42
|
+
"An empty statement, a semicolon on its own, declares nothing and is not kept.",
|
|
43
|
+
"A scalar is kept as the text its tokens spell, run together, so white space between the tokens of one is not: a sign is written against its number, a qualified name with no space around its dots, and adjacent string literals with nothing between them.",
|
|
44
|
+
"An option's aggregate value in braces is kept as its fields, so its layout, its comments and the separators and colons between its fields are not: it is written on one line, a field holding an aggregate as name { ... } and any other as name: value."
|
|
50
45
|
]
|
|
51
46
|
}
|
|
52
47
|
}
|
|
53
48
|
`,
|
|
54
|
-
render: Object.freeze({ entry: "proto-render", source: `; Protocol Buffers' render: the
|
|
55
|
-
; back as one \`.proto\` file
|
|
56
|
-
;
|
|
57
|
-
; \`
|
|
49
|
+
render: Object.freeze({ entry: "proto-render", source: `; Protocol Buffers' render: the source-ordered tree, the schema
|
|
50
|
+
; \`proto-ast\`, written back as one \`.proto\` file, a declaration at a time
|
|
51
|
+
; as its events arrive. This is a library of definitions, each named
|
|
52
|
+
; \`proto-render-...\` but its entry point, \`proto-render\`, which a host
|
|
53
|
+
; links with its own program (alchemy's \`compile_sources\`); nothing else
|
|
58
54
|
; here is the host's to call.
|
|
59
55
|
;
|
|
60
|
-
; The
|
|
61
|
-
;
|
|
62
|
-
;
|
|
63
|
-
;
|
|
64
|
-
; source of the same schema or from a program that builds the tree. The
|
|
65
|
-
; contract is the round trip: the text it writes reads back, through this
|
|
66
|
-
; repository's reader, as the tree it was given. The tree keeps what a
|
|
67
|
-
; descriptor holds and not how the file spelled it, so the render chooses
|
|
68
|
-
; a spelling for each part, the one that reads back the same, as the
|
|
69
|
-
; manifest's loss list says:
|
|
56
|
+
; The tree is the file's declarations in source order (alchemy's
|
|
57
|
+
; docs/streaming-plan.md, section 13.1): \`{"type": "file", "body": [...]}\`,
|
|
58
|
+
; each declaration an object whose \`type\` comes first and whose other
|
|
59
|
+
; members follow in the order the statement spells them:
|
|
70
60
|
;
|
|
71
|
-
;
|
|
72
|
-
;
|
|
73
|
-
;
|
|
74
|
-
;
|
|
75
|
-
;
|
|
76
|
-
;
|
|
77
|
-
;
|
|
78
|
-
; field
|
|
79
|
-
;
|
|
80
|
-
;
|
|
81
|
-
;
|
|
82
|
-
;
|
|
83
|
-
;
|
|
84
|
-
;
|
|
85
|
-
;
|
|
86
|
-
;
|
|
87
|
-
; them, is written as a message, and the field as a field of its type.
|
|
88
|
-
; - A field is its label (none in a oneof; \`optional\` for a proto2 field
|
|
89
|
-
; the tree marks optional, and for a proto3 field the tree marks
|
|
90
|
-
; \`proto3Optional\`; nothing for the other optional fields), its type (a
|
|
91
|
-
; scalar's keyword, or the type name as written), its name, its number
|
|
92
|
-
; and its options in brackets: \`default\`, \`json_name\` and the rest.
|
|
93
|
-
; - An exclusive range end (a message's reserved and extension ranges) is
|
|
94
|
-
; written one below the tree's, or \`max\` where it is the bound \`to max\`
|
|
95
|
-
; gives (536870912, or 2147483647 under \`message_set_wire_format\`); an
|
|
96
|
-
; enum's inclusive end as it is, \`max\` for 2147483647.
|
|
97
|
-
; - A string from a string literal is kept as its text between the quotes,
|
|
98
|
-
; escapes as written, so it is written between double quotes, or single
|
|
99
|
-
; quotes where it holds a double quote and no single quote, and where it
|
|
100
|
-
; holds both, between the quotes it escapes (an escaped backslash, \`\\\\\`,
|
|
101
|
-
; escapes no quote after it). A backtick string, which the lexer reads
|
|
102
|
-
; across lines too, is kept as written, backticks and all, so one
|
|
103
|
-
; holding a line break, which no quotes hold, is written as itself. A
|
|
104
|
-
; reserved name is not: the reader takes one from a quoted literal or an
|
|
105
|
-
; identifier, and the words of a backtick string as names of their own.
|
|
106
|
-
; An option's value the reader read as an identifier, a quoted literal,
|
|
107
|
-
; a backtick string or an aggregate in braces is one string to the tree:
|
|
108
|
-
; it is written quoted, as the backtick string it is, as an aggregate
|
|
109
|
-
; (\`{...}\`) where neither can hold it (a line break, or both quotes
|
|
110
|
-
; unescaped), and as an identifier for the options descriptor.proto
|
|
111
|
-
; types as enums (\`optimize_for\`, \`ctype\`, \`jstype\`, \`retention\`,
|
|
112
|
-
; \`targets\`, \`idempotency_level\` and the features) where it is made of
|
|
113
|
-
; identifier characters; a value a program made that no literal or
|
|
114
|
-
; backtick string holds and that is no aggregate's body is written in
|
|
115
|
-
; braces too, and the reader refuses it, since alchemy cannot parse an
|
|
116
|
-
; aggregate. A default is written bare for a field that is not a string
|
|
117
|
-
; or bytes, where it is made of the characters a constant is, and as a
|
|
118
|
-
; literal otherwise. alchemy cannot read a string a character at a time,
|
|
119
|
-
; so two texts a file can hold, each refused by protoc, do not read back:
|
|
120
|
-
; a quoted value of an enum-typed option that begins with a digit, and a
|
|
121
|
-
; quoted default of a field that is not a string whose text is a
|
|
122
|
-
; constant's characters spelling no one constant.
|
|
123
|
-
; - A field or enum number the reader could not read (JavaScript's Number
|
|
124
|
-
; of \`1_0\`, the lexer's digit separator) is NaN, null in JSON, and is
|
|
125
|
-
; written \`0_0\`, which reads back the same; an option's number that is
|
|
126
|
-
; null in JSON is infinite, and is written \`1e999\`.
|
|
61
|
+
; syntax, edition value
|
|
62
|
+
; import modifier (where written), path
|
|
63
|
+
; package name
|
|
64
|
+
; option name, value
|
|
65
|
+
; message, enum visibility (where written), name, body
|
|
66
|
+
; service, oneof name, body
|
|
67
|
+
; extend extendee, body
|
|
68
|
+
; field label (where written), fieldType, name, number,
|
|
69
|
+
; options (where written)
|
|
70
|
+
; map keyType, valueType, name, number, options
|
|
71
|
+
; group label, name, number, body
|
|
72
|
+
; extensions ranges, options
|
|
73
|
+
; reserved ranges or names
|
|
74
|
+
; enumValue name, number, options
|
|
75
|
+
; rpc name, inputStream (true, where written), inputType,
|
|
76
|
+
; outputStream, outputType, body (where written)
|
|
127
77
|
;
|
|
128
|
-
;
|
|
129
|
-
;
|
|
130
|
-
;
|
|
131
|
-
;
|
|
132
|
-
;
|
|
133
|
-
;
|
|
134
|
-
; holds one, a backtick string only a line break, and an option's
|
|
135
|
-
; aggregate only the tab and line breaks between its tokens), and outside
|
|
136
|
-
; an option's value, both quotes unescaped or a backslash at the end,
|
|
137
|
-
; which would escape the closing quote.
|
|
78
|
+
; A scalar is the text the source spells, a string literal with its
|
|
79
|
+
; quotes, so each is written as it is. A range is \`from\` and, where it has
|
|
80
|
+
; one, \`to\`; an option in brackets is \`name\` and \`value\`; an option's value
|
|
81
|
+
; is its text or an aggregate's fields, each \`name\` and \`value\`, written in
|
|
82
|
+
; braces on one line, a field holding an aggregate as \`name { ... }\` and
|
|
83
|
+
; any other as \`name: value\`.
|
|
138
84
|
;
|
|
139
|
-
; The
|
|
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
|
-
def proto-
|
|
171
|
-
match
|
|
172
|
-
case
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
case
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
case
|
|
183
|
-
case
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
case
|
|
188
|
-
case
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
case
|
|
193
|
-
case
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
case
|
|
202
|
-
case
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
case ""
|
|
210
|
-
case
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
case "
|
|
215
|
-
case
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
case
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
85
|
+
; The text: each declaration on a line of its own, a block's declarations
|
|
86
|
+
; two spaces deeper than the line that opens it, and the block's closing
|
|
87
|
+
; brace on a line of its own; an empty file is no text at all. The
|
|
88
|
+
; contract is the round trip: the text reads back, through this
|
|
89
|
+
; repository's reader, as the tree it was written from. The render checks
|
|
90
|
+
; the tree's shape (each node's type, its members and their order, a body
|
|
91
|
+
; holding only what its parent's block holds) and writes each scalar as it
|
|
92
|
+
; is, so a tree the reader could not have built (a name holding a space,
|
|
93
|
+
; a type that is a keyword where it stands) is written as its members say
|
|
94
|
+
; and does not read back as itself. A root that is no file, a type, a
|
|
95
|
+
; member or a value no node of the schema has, a member out of its place
|
|
96
|
+
; or repeated, a declaration where its parent's block holds none of its
|
|
97
|
+
; kind, and a node missing what its text needs fail with
|
|
98
|
+
; TARGET_VALUE_UNREPRESENTABLE, naming what was met.
|
|
99
|
+
;
|
|
100
|
+
; The state is a stack of the containers open, innermost last: [:file key
|
|
101
|
+
; at] for the root, [:body indent parent] for a block's declarations,
|
|
102
|
+
; [:node indent kind key at begun braced] for a declaration (its line's
|
|
103
|
+
; indentation, its type, the member whose value comes next, the place of
|
|
104
|
+
; the last member written, whether its line has begun, whether its block
|
|
105
|
+
; was written), [:options count] and [:option key at] for an option list,
|
|
106
|
+
; [:aggregate count] and [:field key at] for an aggregate, [:ranges count]
|
|
107
|
+
; and [:range key at] for ranges, [:names count] for reserved names, and
|
|
108
|
+
; :done once the file has closed. Nothing grows with the file's length,
|
|
109
|
+
; only with its nesting.
|
|
110
|
+
|
|
111
|
+
def proto-render-refuse [message]
|
|
112
|
+
fail :unrepresentable (string-join "" ["the tree is not a proto file: " message])
|
|
113
|
+
|
|
114
|
+
; The place of a member in a declaration of the kind, or missing where
|
|
115
|
+
; the kind has no such member.
|
|
116
|
+
def proto-render-place [nk name]
|
|
117
|
+
match [nk name]
|
|
118
|
+
case [k "type"] 0
|
|
119
|
+
case ["syntax" "value"] 1
|
|
120
|
+
case ["edition" "value"] 1
|
|
121
|
+
case ["import" "modifier"] 1
|
|
122
|
+
case ["import" "path"] 2
|
|
123
|
+
case ["package" "name"] 1
|
|
124
|
+
case ["option" "name"] 1
|
|
125
|
+
case ["option" "value"] 2
|
|
126
|
+
case ["message" "visibility"] 1
|
|
127
|
+
case ["message" "name"] 2
|
|
128
|
+
case ["message" "body"] 3
|
|
129
|
+
case ["enum" "visibility"] 1
|
|
130
|
+
case ["enum" "name"] 2
|
|
131
|
+
case ["enum" "body"] 3
|
|
132
|
+
case ["service" "name"] 1
|
|
133
|
+
case ["service" "body"] 2
|
|
134
|
+
case ["oneof" "name"] 1
|
|
135
|
+
case ["oneof" "body"] 2
|
|
136
|
+
case ["extend" "extendee"] 1
|
|
137
|
+
case ["extend" "body"] 2
|
|
138
|
+
case ["field" "label"] 1
|
|
139
|
+
case ["field" "fieldType"] 2
|
|
140
|
+
case ["field" "name"] 3
|
|
141
|
+
case ["field" "number"] 4
|
|
142
|
+
case ["field" "options"] 5
|
|
143
|
+
case ["map" "keyType"] 1
|
|
144
|
+
case ["map" "valueType"] 2
|
|
145
|
+
case ["map" "name"] 3
|
|
146
|
+
case ["map" "number"] 4
|
|
147
|
+
case ["map" "options"] 5
|
|
148
|
+
case ["group" "label"] 1
|
|
149
|
+
case ["group" "name"] 2
|
|
150
|
+
case ["group" "number"] 3
|
|
151
|
+
case ["group" "body"] 4
|
|
152
|
+
case ["extensions" "ranges"] 1
|
|
153
|
+
case ["extensions" "options"] 2
|
|
154
|
+
case ["reserved" "ranges"] 1
|
|
155
|
+
case ["reserved" "names"] 1
|
|
156
|
+
case ["enumValue" "name"] 1
|
|
157
|
+
case ["enumValue" "number"] 2
|
|
158
|
+
case ["enumValue" "options"] 3
|
|
159
|
+
case ["rpc" "name"] 1
|
|
160
|
+
case ["rpc" "inputStream"] 2
|
|
161
|
+
case ["rpc" "inputType"] 3
|
|
162
|
+
case ["rpc" "outputStream"] 4
|
|
163
|
+
case ["rpc" "outputType"] 5
|
|
164
|
+
case ["rpc" "body"] 6
|
|
165
|
+
case _ missing
|
|
166
|
+
|
|
167
|
+
; The place a declaration's text needs reached: before its block or its
|
|
168
|
+
; options, and at its end.
|
|
169
|
+
def proto-render-needs [nk]
|
|
170
|
+
match nk
|
|
171
|
+
case "syntax" 1
|
|
172
|
+
case "edition" 1
|
|
173
|
+
case "import" 2
|
|
174
|
+
case "package" 1
|
|
175
|
+
case "option" 2
|
|
176
|
+
case "message" 2
|
|
177
|
+
case "enum" 2
|
|
178
|
+
case "service" 1
|
|
179
|
+
case "oneof" 1
|
|
180
|
+
case "extend" 1
|
|
181
|
+
case "field" 4
|
|
182
|
+
case "map" 4
|
|
183
|
+
case "group" 3
|
|
184
|
+
case "extensions" 1
|
|
185
|
+
case "reserved" 1
|
|
186
|
+
case "enumValue" 2
|
|
187
|
+
case "rpc" 5
|
|
188
|
+
case _ 0
|
|
189
|
+
|
|
190
|
+
; The member a declaration's text needs before its block or its options,
|
|
191
|
+
; named in a refusal.
|
|
192
|
+
def proto-render-needed [nk]
|
|
193
|
+
match nk
|
|
194
|
+
case "field" "number"
|
|
195
|
+
case "map" "number"
|
|
196
|
+
case "group" "number"
|
|
197
|
+
case "enumValue" "number"
|
|
198
|
+
case "extend" "extendee"
|
|
199
|
+
case "rpc" "outputType"
|
|
200
|
+
case "extensions" "ranges"
|
|
201
|
+
case "reserved" "ranges or names"
|
|
202
|
+
case "syntax" "value"
|
|
203
|
+
case "edition" "value"
|
|
204
|
+
case "import" "path"
|
|
205
|
+
case "option" "value"
|
|
206
|
+
case _ "name"
|
|
207
|
+
|
|
208
|
+
; Whether a declaration of the kind holds a block, which its text ends.
|
|
209
|
+
def proto-render-blocked [nk]
|
|
210
|
+
match nk
|
|
211
|
+
case "message" true
|
|
212
|
+
case "enum" true
|
|
213
|
+
case "service" true
|
|
214
|
+
case "oneof" true
|
|
215
|
+
case "extend" true
|
|
216
|
+
case "group" true
|
|
225
217
|
case _ false
|
|
226
218
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
case
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
case ""
|
|
243
|
-
case
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
case :number
|
|
252
|
-
match (number-class n)
|
|
253
|
-
case :finite (scalar-text csv-options n)
|
|
254
|
-
case :infinity "1e999"
|
|
255
|
-
case :negative-infinity "-1e999"
|
|
256
|
-
case :nan "0_0"
|
|
257
|
-
case :null "0_0"
|
|
258
|
-
case _ (fail :unrepresentable "the tree is not a FileDescriptorProto: a number is not one")
|
|
259
|
-
|
|
260
|
-
; The characters a literal holds as they are between double quotes, and
|
|
261
|
-
; between single quotes: none of the controls, and not that quote.
|
|
262
|
-
def proto-no-dq [[32 33] [35 1114111]]
|
|
263
|
-
|
|
264
|
-
def proto-no-sq [[32 38] [40 1114111]]
|
|
265
|
-
|
|
266
|
-
def proto-ident-chars [[48 57] [65 90] [95 95] [97 122]]
|
|
267
|
-
|
|
268
|
-
; The characters of a bare constant: a number, a signed one, an identifier.
|
|
269
|
-
def proto-bare-chars [[43 43] [45 46] [48 57] [65 90] [95 95] [97 122]]
|
|
270
|
-
|
|
271
|
-
; The characters a backtick string holds, as the lexer reads one: the
|
|
272
|
-
; line feed and the carriage return that carry it across lines, and none
|
|
273
|
-
; of the other controls.
|
|
274
|
-
def proto-in-backtick [[10 10] [13 13] [32 1114111]]
|
|
275
|
-
|
|
276
|
-
; The characters an aggregate holds: its tokens, and the tab, the line
|
|
277
|
-
; feed and the carriage return as the whitespace between them.
|
|
278
|
-
def proto-in-aggregate [[9 10] [13 13] [32 1114111]]
|
|
279
|
-
|
|
280
|
-
; Whether s is a backtick string's text as the reader keeps it, the
|
|
281
|
-
; backticks and all: the lexer reads a backtick string across lines too,
|
|
282
|
-
; a backslash escaping the character after it, and the reader keeps a
|
|
283
|
-
; constant that is not quoted as it was written. So s has a backtick at
|
|
284
|
-
; each end and none unescaped between them, no backslash before the last
|
|
285
|
-
; that would escape it, and no control but a line break.
|
|
286
|
-
def proto-backtick [s]
|
|
287
|
-
let [parts (split "\`" s)]
|
|
288
|
-
match (proto-less 2 (count parts))
|
|
289
|
-
case false false
|
|
290
|
-
case true
|
|
291
|
-
match (match (proto-at parts 0) (case "" (match (top parts) (case "" true) (case _ false))) (case _ false))
|
|
292
|
-
case false false
|
|
293
|
-
case true
|
|
294
|
-
match (chars-within proto-in-backtick s)
|
|
295
|
-
case false false
|
|
296
|
-
case true (proto-escaped-inside "\`" (proto-after "\`" (string-join "\`" (pop parts))))
|
|
297
|
-
|
|
298
|
-
; Whether text could stand between quotes q as the lexer reads them: every
|
|
299
|
-
; q in it escaped, and no backslash at its end to escape the closing one.
|
|
300
|
-
def proto-escaped-inside [q text]
|
|
301
|
-
match (proto-quotes-escaped q text)
|
|
302
|
-
case false false
|
|
303
|
-
case true
|
|
304
|
-
match (proto-open-escape text)
|
|
305
|
-
case true false
|
|
306
|
-
case false true
|
|
307
|
-
|
|
308
|
-
; Whether every quote q in s is escaped, as in the text of a literal
|
|
309
|
-
; between those quotes. The lexer reads an escape as a backslash and the
|
|
310
|
-
; character after it, so an escaped backslash (\`\\\\\`) escapes nothing
|
|
311
|
-
; after it: s is read in the runs between its escaped backslashes, found
|
|
312
|
-
; from the front as the lexer finds them, and in a run a quote is escaped
|
|
313
|
-
; where a backslash comes right before it.
|
|
314
|
-
def proto-quotes-escaped [q s]
|
|
315
|
-
match (count (filter (fn [run] (proto-bare-quote q run)) (split "\\\\\\\\" s)))
|
|
316
|
-
case 0 true
|
|
219
|
+
; Whether a block of the parent's kind holds a declaration of the kind.
|
|
220
|
+
def proto-render-holds [parent nk]
|
|
221
|
+
match [parent nk]
|
|
222
|
+
case ["file" "syntax"] true
|
|
223
|
+
case ["file" "edition"] true
|
|
224
|
+
case ["file" "import"] true
|
|
225
|
+
case ["file" "package"] true
|
|
226
|
+
case ["file" "option"] true
|
|
227
|
+
case ["file" "message"] true
|
|
228
|
+
case ["file" "enum"] true
|
|
229
|
+
case ["file" "service"] true
|
|
230
|
+
case ["file" "extend"] true
|
|
231
|
+
case ["message" k] (proto-render-in-message k)
|
|
232
|
+
case ["group" k] (proto-render-in-message k)
|
|
233
|
+
case ["enum" "option"] true
|
|
234
|
+
case ["enum" "reserved"] true
|
|
235
|
+
case ["enum" "enumValue"] true
|
|
236
|
+
case ["service" "option"] true
|
|
237
|
+
case ["service" "rpc"] true
|
|
238
|
+
case ["rpc" "option"] true
|
|
239
|
+
case ["oneof" "option"] true
|
|
240
|
+
case ["oneof" "field"] true
|
|
241
|
+
case ["oneof" "group"] true
|
|
242
|
+
case ["extend" "field"] true
|
|
317
243
|
case _ false
|
|
318
244
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
case
|
|
324
|
-
case
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
match (count pieces)
|
|
332
|
-
case 1 false
|
|
333
|
-
case _
|
|
334
|
-
match (top pieces)
|
|
335
|
-
case "" true
|
|
336
|
-
case _ false
|
|
337
|
-
|
|
338
|
-
; A literal's text between quotes that hold it, or "" where none do:
|
|
339
|
-
; double quotes where it holds no double quote, single quotes where it
|
|
340
|
-
; holds no single quote, and where it holds both, the quotes it escapes.
|
|
341
|
-
; No quotes hold a control character, both quotes unescaped, or a
|
|
342
|
-
; backslash at the end that would escape the closing quote.
|
|
343
|
-
def proto-quoted [s]
|
|
344
|
-
match (chars-within [[32 1114111]] s)
|
|
345
|
-
case false ""
|
|
346
|
-
case true
|
|
347
|
-
match (proto-open-escape s)
|
|
348
|
-
case true ""
|
|
349
|
-
case false
|
|
350
|
-
match (chars-within proto-no-dq s)
|
|
351
|
-
case true (string-join "" ["\\"" s "\\""])
|
|
352
|
-
case false
|
|
353
|
-
match (chars-within proto-no-sq s)
|
|
354
|
-
case true (string-join "" ["'" s "'"])
|
|
355
|
-
case false
|
|
356
|
-
match (proto-quotes-escaped "\\"" s)
|
|
357
|
-
case true (string-join "" ["\\"" s "\\""])
|
|
358
|
-
case false
|
|
359
|
-
match (proto-quotes-escaped "'" s)
|
|
360
|
-
case true (string-join "" ["'" s "'"])
|
|
361
|
-
case false ""
|
|
362
|
-
|
|
363
|
-
; A string literal whose text is s, as written: between quotes, or as the
|
|
364
|
-
; backtick string it is, which holds a line break no quotes hold. A text
|
|
365
|
-
; neither holds fails.
|
|
366
|
-
def proto-literal [s]
|
|
367
|
-
match (proto-quoted s)
|
|
368
|
-
case ""
|
|
369
|
-
match (proto-backtick s)
|
|
370
|
-
case true s
|
|
371
|
-
case false (fail :unrepresentable "a string holds what no literal or backtick string holds: a control character, both quotes unescaped, or a backslash that would escape the closing quote")
|
|
372
|
-
case q q
|
|
373
|
-
|
|
374
|
-
; An option's string: a literal, the backtick string it is, or the
|
|
375
|
-
; aggregate it is, whose braces hold what no literal holds (a line break,
|
|
376
|
-
; or both quotes unescaped). A control that no literal, backtick string
|
|
377
|
-
; or aggregate holds fails.
|
|
378
|
-
def proto-option-string [s]
|
|
379
|
-
match (proto-quoted s)
|
|
380
|
-
case ""
|
|
381
|
-
match (proto-backtick s)
|
|
382
|
-
case true s
|
|
383
|
-
case false
|
|
384
|
-
match (chars-within proto-in-aggregate s)
|
|
385
|
-
case true (string-join "" ["{" s "}"])
|
|
386
|
-
case false (fail :unrepresentable "an option's value holds a control character that no literal, backtick string or aggregate holds")
|
|
387
|
-
case q q
|
|
388
|
-
|
|
389
|
-
; The options descriptor.proto types as enums, whose values are identifiers.
|
|
390
|
-
def proto-enum-option [k]
|
|
391
|
-
match k
|
|
392
|
-
case "optimize_for" true
|
|
393
|
-
case "ctype" true
|
|
394
|
-
case "jstype" true
|
|
395
|
-
case "retention" true
|
|
396
|
-
case "targets" true
|
|
397
|
-
case "idempotency_level" true
|
|
398
|
-
case "features.field_presence" true
|
|
399
|
-
case "features.enum_type" true
|
|
400
|
-
case "features.repeated_field_encoding" true
|
|
401
|
-
case "features.utf8_validation" true
|
|
402
|
-
case "features.message_encoding" true
|
|
403
|
-
case "features.json_format" true
|
|
404
|
-
case "features.enforce_naming_style" true
|
|
405
|
-
case "features.default_symbol_visibility" true
|
|
406
|
-
case "features.(pb.cpp).string_type" true
|
|
407
|
-
case "features.(pb.java).utf8_validation" true
|
|
408
|
-
case "features.(pb.java).nest_in_file_class" true
|
|
409
|
-
case "features.(pb.go).api_level" true
|
|
410
|
-
case "features.(pb.go).strip_enum_prefix" true
|
|
245
|
+
def proto-render-in-message [nk]
|
|
246
|
+
match nk
|
|
247
|
+
case "option" true
|
|
248
|
+
case "field" true
|
|
249
|
+
case "map" true
|
|
250
|
+
case "group" true
|
|
251
|
+
case "oneof" true
|
|
252
|
+
case "message" true
|
|
253
|
+
case "enum" true
|
|
254
|
+
case "extend" true
|
|
255
|
+
case "extensions" true
|
|
256
|
+
case "reserved" true
|
|
411
257
|
case _ false
|
|
412
258
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
case "
|
|
418
|
-
case
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
case
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
case
|
|
427
|
-
case
|
|
428
|
-
case
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
case
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
match (
|
|
485
|
-
case
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
case "
|
|
495
|
-
case "
|
|
496
|
-
case
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
case "
|
|
506
|
-
case
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
259
|
+
; The text a member's scalar writes in a declaration of the kind, its
|
|
260
|
+
; line's indentation ahead of it where the line has not begun.
|
|
261
|
+
def proto-render-member-text [nk name value]
|
|
262
|
+
match [nk name]
|
|
263
|
+
case ["syntax" "value"] (string-join "" ["syntax = " value])
|
|
264
|
+
case ["edition" "value"] (string-join "" ["edition = " value])
|
|
265
|
+
case ["import" "modifier"] (string-join "" ["import " value " "])
|
|
266
|
+
case ["package" "name"] (string-join "" ["package " value])
|
|
267
|
+
case ["option" "name"] (string-join "" ["option " value " = "])
|
|
268
|
+
case ["option" "value"] value
|
|
269
|
+
case ["message" "visibility"] (string-join "" [value " "])
|
|
270
|
+
case ["message" "name"] (string-join "" ["message " value])
|
|
271
|
+
case ["enum" "visibility"] (string-join "" [value " "])
|
|
272
|
+
case ["enum" "name"] (string-join "" ["enum " value])
|
|
273
|
+
case ["service" "name"] (string-join "" ["service " value])
|
|
274
|
+
case ["oneof" "name"] (string-join "" ["oneof " value])
|
|
275
|
+
case ["extend" "extendee"] (string-join "" ["extend " value])
|
|
276
|
+
case ["group" "label"] (string-join "" [value " "])
|
|
277
|
+
case ["group" "name"] (string-join "" ["group " value])
|
|
278
|
+
case ["group" "number"] (string-join "" [" = " value])
|
|
279
|
+
case ["field" "label"] (string-join "" [value " "])
|
|
280
|
+
case ["field" "fieldType"] (string-join "" [value " "])
|
|
281
|
+
case ["field" "name"] value
|
|
282
|
+
case ["field" "number"] (string-join "" [" = " value])
|
|
283
|
+
case ["map" "keyType"] (string-join "" ["map<" value])
|
|
284
|
+
case ["map" "valueType"] (string-join "" [", " value "> "])
|
|
285
|
+
case ["map" "name"] value
|
|
286
|
+
case ["map" "number"] (string-join "" [" = " value])
|
|
287
|
+
case ["enumValue" "name"] value
|
|
288
|
+
case ["enumValue" "number"] (string-join "" [" = " value])
|
|
289
|
+
case ["rpc" "name"] (string-join "" ["rpc " value " ("])
|
|
290
|
+
case ["rpc" "inputStream"] "stream "
|
|
291
|
+
case ["rpc" "inputType"] (string-join "" [value ") returns ("])
|
|
292
|
+
case ["rpc" "outputStream"] "stream "
|
|
293
|
+
case ["rpc" "outputType"] (string-join "" [value ")"])
|
|
294
|
+
|
|
295
|
+
; An import's path, which begins the line where no modifier did.
|
|
296
|
+
def proto-render-path [begun value]
|
|
297
|
+
match begun
|
|
298
|
+
case true value
|
|
299
|
+
case _ (string-join "" ["import " value])
|
|
300
|
+
|
|
301
|
+
; The stack with its innermost container replaced.
|
|
302
|
+
def proto-render-put [stack ctx]
|
|
303
|
+
push ctx (pop stack)
|
|
304
|
+
|
|
305
|
+
; A scalar's value, checked: a string, or \`true\` for an rpc's stream.
|
|
306
|
+
def proto-render-value [nk name value]
|
|
307
|
+
match [name (kind value)]
|
|
308
|
+
case ["inputStream" :boolean] (if value value (proto-render-refuse "an rpc's inputStream is true or left out"))
|
|
309
|
+
case ["outputStream" :boolean] (if value value (proto-render-refuse "an rpc's outputStream is true or left out"))
|
|
310
|
+
case ["inputStream" k] (proto-render-refuse "an rpc's inputStream is true or left out")
|
|
311
|
+
case ["outputStream" k] (proto-render-refuse "an rpc's outputStream is true or left out")
|
|
312
|
+
case [n :string] value
|
|
313
|
+
case _ (proto-render-refuse (string-join "" ["a " nk "'s " name " is text"]))
|
|
314
|
+
|
|
315
|
+
; A declaration's member is about to be written: its place, checked.
|
|
316
|
+
def proto-render-placed [nk name at]
|
|
317
|
+
match (proto-render-place nk name)
|
|
318
|
+
case missing (proto-render-refuse (string-join "" ["a " nk " has no member " name]))
|
|
319
|
+
case place
|
|
320
|
+
match (compare place at)
|
|
321
|
+
case :greater place
|
|
322
|
+
case _ (proto-render-refuse (string-join "" ["a " nk "'s " name " comes after what it precedes, or twice"]))
|
|
323
|
+
|
|
324
|
+
; A declaration's type is read: its kind, held to its parent's block.
|
|
325
|
+
def proto-render-type [stack ctx value]
|
|
326
|
+
match ctx
|
|
327
|
+
case [:node indent nk key at begun braced]
|
|
328
|
+
match (top (pop stack))
|
|
329
|
+
case [:body i parent]
|
|
330
|
+
match (kind value)
|
|
331
|
+
case :string
|
|
332
|
+
match (proto-render-holds parent value)
|
|
333
|
+
case true (transition (proto-render-put stack [:node indent value "" 0 false false]) [])
|
|
334
|
+
case _ (proto-render-refuse (string-join "" ["a " parent "'s block holds no " value]))
|
|
335
|
+
case _ (proto-render-refuse "a declaration's type is text")
|
|
336
|
+
|
|
337
|
+
; A scalar member of a declaration.
|
|
338
|
+
def proto-render-node-scalar [stack ctx value]
|
|
339
|
+
match ctx
|
|
340
|
+
case [:node indent nk "type" at begun braced] (proto-render-type stack ctx value)
|
|
341
|
+
case [:node indent "" key at begun braced] (proto-render-refuse "a declaration's first member is not its type")
|
|
342
|
+
case [:node indent nk key at begun braced]
|
|
343
|
+
let [place (proto-render-placed nk key at) checked (proto-render-value nk key value)]
|
|
344
|
+
let [text (match [nk key] (case ["import" "path"] (proto-render-path begun checked)) (case _ (proto-render-member-text nk key checked)))]
|
|
345
|
+
transition (proto-render-put stack [:node indent nk "" place true braced]) [(if begun text (string-join "" [indent text]))]
|
|
346
|
+
|
|
347
|
+
; A container member of a declaration begins: a block, options in
|
|
348
|
+
; brackets, ranges, names, or an option's aggregate.
|
|
349
|
+
def proto-render-node-array [stack ctx]
|
|
350
|
+
match ctx
|
|
351
|
+
case [:node indent "" key at begun braced] (proto-render-refuse "a declaration's first member is not its type")
|
|
352
|
+
case [:node indent nk key at begun braced]
|
|
353
|
+
let [place (proto-render-placed nk key at)]
|
|
354
|
+
match key
|
|
355
|
+
case "body"
|
|
356
|
+
match (compare at (proto-render-needs nk))
|
|
357
|
+
case :less (proto-render-refuse (string-join "" ["a " nk " has a block and no " (proto-render-needed nk)]))
|
|
358
|
+
case _ (transition (push [:body (string-join "" [indent " "]) nk] (proto-render-put stack [:node indent nk "" place true true])) [" {\\n"])
|
|
359
|
+
case "options"
|
|
360
|
+
match (compare at (proto-render-needs nk))
|
|
361
|
+
case :less (proto-render-refuse (string-join "" ["a " nk " has options and no " (proto-render-needed nk)]))
|
|
362
|
+
case _ (transition (push [:options 0] (proto-render-put stack [:node indent nk "" place true braced])) [" ["])
|
|
363
|
+
case "ranges" (transition (push [:ranges 0] (proto-render-put stack [:node indent nk "" place true braced])) [(string-join "" [indent nk " "])])
|
|
364
|
+
case "names" (transition (push [:names 0] (proto-render-put stack [:node indent nk "" place true braced])) [(string-join "" [indent nk " "])])
|
|
365
|
+
case "value"
|
|
366
|
+
match nk
|
|
367
|
+
case "option" (transition (push [:aggregate 0] (proto-render-put stack [:node indent nk "" place true braced])) ["{"])
|
|
368
|
+
case _ (proto-render-refuse (string-join "" ["a " nk "'s value is text"]))
|
|
369
|
+
case _ (proto-render-refuse (string-join "" ["a " nk "'s " key " is text"]))
|
|
370
|
+
|
|
371
|
+
; A declaration ends: its terminator, once its text holds what it needs.
|
|
372
|
+
def proto-render-node-end [stack ctx]
|
|
373
|
+
match ctx
|
|
374
|
+
case [:node indent nk key at begun braced]
|
|
375
|
+
match (compare at (proto-render-needs nk))
|
|
376
|
+
case :less (proto-render-refuse (string-join "" ["a " nk " with no " (proto-render-needed nk)]))
|
|
520
377
|
case _
|
|
521
|
-
match
|
|
522
|
-
case
|
|
523
|
-
case
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
case
|
|
545
|
-
|
|
546
|
-
; ---- ranges
|
|
547
|
-
|
|
548
|
-
; The decimal digits, and the places of a number's text.
|
|
549
|
-
def proto-digits-down ["9" "8" "7" "6" "5" "4" "3" "2" "1"]
|
|
550
|
-
|
|
551
|
-
def proto-digits-up ["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"]
|
|
552
|
-
|
|
553
|
-
def proto-places [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
|
|
554
|
-
|
|
555
|
-
def proto-places-of [text]
|
|
556
|
-
filter (fn [i] (proto-less i (length text))) proto-places
|
|
557
|
-
|
|
558
|
-
; A digit after a prefix, a leading zero dropped.
|
|
559
|
-
def proto-append-digit [prefix d]
|
|
560
|
-
match [prefix d]
|
|
561
|
-
case ["" "0"] ""
|
|
562
|
-
case _ (string-join "" [prefix d])
|
|
563
|
-
|
|
564
|
-
; The decimal text of n - 1 for an integer n of at least 1, a digit a
|
|
565
|
-
; place from the left: at each place, the largest digit after which some
|
|
566
|
-
; number is still below n, which is the one whose zeros after it are.
|
|
567
|
-
; alchemy has no arithmetic, so the predecessor is found by comparison.
|
|
568
|
-
def proto-pred-pos [self places prefix n]
|
|
569
|
-
match (count places)
|
|
570
|
-
case 0
|
|
571
|
-
match prefix
|
|
572
|
-
case "" "0"
|
|
573
|
-
case _ prefix
|
|
378
|
+
match [(proto-render-blocked nk) braced]
|
|
379
|
+
case [true true] (transition (pop stack) ["\\n"])
|
|
380
|
+
case [true false] (proto-render-refuse (string-join "" ["a " nk " with no body"]))
|
|
381
|
+
case [false true] (transition (pop stack) ["\\n"])
|
|
382
|
+
case _ (transition (pop stack) [";\\n"])
|
|
383
|
+
|
|
384
|
+
; A container ends: a block's closing brace, on a line of its own; an
|
|
385
|
+
; option list's bracket; an aggregate's brace.
|
|
386
|
+
def proto-render-array-end [stack]
|
|
387
|
+
match (top stack)
|
|
388
|
+
case [:body indent parent]
|
|
389
|
+
let [rest (pop stack)]
|
|
390
|
+
match (top rest)
|
|
391
|
+
case [:node i nk key at begun braced] (transition rest [(string-join "" [i "}"])])
|
|
392
|
+
case _ (transition rest [])
|
|
393
|
+
case [:options count] (transition (pop stack) ["]"])
|
|
394
|
+
case [:aggregate count] (transition (pop stack) [" }"])
|
|
395
|
+
case [:ranges count] (transition (pop stack) [])
|
|
396
|
+
case [:names count] (transition (pop stack) [])
|
|
397
|
+
case _ (proto-render-refuse "an array where none is")
|
|
398
|
+
|
|
399
|
+
def proto-render-object-start [stack]
|
|
400
|
+
match (count stack)
|
|
401
|
+
case 0 (transition [[:file "" 0]] [])
|
|
574
402
|
case _
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
403
|
+
match (top stack)
|
|
404
|
+
case [:body indent parent] (transition (push [:node indent "" "type" -1 false false] stack) [])
|
|
405
|
+
case [:options count] (transition (push [:option "" 0] (proto-render-put stack [:options (inc count)])) [(if (equal count 0) "" ", ")])
|
|
406
|
+
case [:aggregate count] (transition (push [:field "" 0] (proto-render-put stack [:aggregate (inc count)])) [" "])
|
|
407
|
+
case [:ranges count] (transition (push [:range "" 0] (proto-render-put stack [:ranges (inc count)])) [(if (equal count 0) "" ", ")])
|
|
408
|
+
case _ (proto-render-refuse "an object where none is")
|
|
409
|
+
|
|
410
|
+
def proto-render-object-end [stack]
|
|
411
|
+
match (top stack)
|
|
412
|
+
case [:file key at]
|
|
413
|
+
match at
|
|
414
|
+
case 2 (transition [:done] [])
|
|
415
|
+
case _ (proto-render-refuse "a file with no body")
|
|
416
|
+
case [:node indent nk key at begun braced] (proto-render-node-end stack (top stack))
|
|
417
|
+
case [:option key at]
|
|
418
|
+
match at
|
|
419
|
+
case 2 (transition (pop stack) [])
|
|
420
|
+
case _ (proto-render-refuse "an option with no name or no value")
|
|
421
|
+
case [:field key at]
|
|
422
|
+
match at
|
|
423
|
+
case 2 (transition (pop stack) [])
|
|
424
|
+
case _ (proto-render-refuse "an aggregate's field with no name or no value")
|
|
425
|
+
case [:range key at]
|
|
426
|
+
match (compare at 1)
|
|
427
|
+
case :less (proto-render-refuse "a range with no from")
|
|
428
|
+
case _ (transition (pop stack) [])
|
|
429
|
+
case _ (proto-render-refuse "an object's end where none is open")
|
|
430
|
+
|
|
431
|
+
def proto-render-array-start [stack]
|
|
432
|
+
match (top stack)
|
|
433
|
+
case [:file "body" 1] (transition (push [:body "" "file"] (proto-render-put stack [:file "" 2])) [])
|
|
434
|
+
case [:node indent nk key at begun braced] (proto-render-node-array stack (top stack))
|
|
435
|
+
case [:option "value" 1] (transition (push [:aggregate 0] (proto-render-put stack [:option "" 2])) ["{"])
|
|
436
|
+
case [:field "value" 1] (transition (push [:aggregate 0] (proto-render-put stack [:field "" 2])) [" {"])
|
|
437
|
+
case _ (proto-render-refuse "an array where none is")
|
|
438
|
+
|
|
439
|
+
; A key names the member whose value follows.
|
|
440
|
+
def proto-render-key [stack name]
|
|
441
|
+
match (top stack)
|
|
442
|
+
case [:file key at] (transition (proto-render-put stack [:file name at]) [])
|
|
443
|
+
case [:node indent nk key at begun braced] (transition (proto-render-put stack [:node indent nk name at begun braced]) [])
|
|
444
|
+
case [:option key at] (transition (proto-render-put stack [:option name at]) [])
|
|
445
|
+
case [:field key at] (transition (proto-render-put stack [:field name at]) [])
|
|
446
|
+
case [:range key at] (transition (proto-render-put stack [:range name at]) [])
|
|
447
|
+
case _ (proto-render-refuse "a key outside an object")
|
|
448
|
+
|
|
449
|
+
; A text, checked.
|
|
450
|
+
def proto-render-text [value what]
|
|
451
|
+
match (kind value)
|
|
452
|
+
case :string value
|
|
453
|
+
case _ (proto-render-refuse (string-join "" [what " is text"]))
|
|
454
|
+
|
|
455
|
+
def proto-render-scalar [stack value]
|
|
456
|
+
match (top stack)
|
|
457
|
+
case [:file "type" 0]
|
|
458
|
+
match value
|
|
459
|
+
case "file" (transition (proto-render-put stack [:file "" 1]) [])
|
|
460
|
+
case _ (proto-render-refuse "the root's type is not file")
|
|
461
|
+
case [:node indent nk key at begun braced] (proto-render-node-scalar stack (top stack) value)
|
|
462
|
+
case [:option "name" 0] (transition (proto-render-put stack [:option "" 1]) [(string-join "" [(proto-render-text value "an option's name") " = "])])
|
|
463
|
+
case [:option "value" 1] (transition (proto-render-put stack [:option "" 2]) [(proto-render-text value "an option's value")])
|
|
464
|
+
case [:field "name" 0] (transition (proto-render-put stack [:field "" 1]) [(proto-render-text value "an aggregate field's name")])
|
|
465
|
+
case [:field "value" 1] (transition (proto-render-put stack [:field "" 2]) [(string-join "" [": " (proto-render-text value "an aggregate field's value")])])
|
|
466
|
+
case [:range "from" 0] (transition (proto-render-put stack [:range "" 1]) [(proto-render-text value "a range's from")])
|
|
467
|
+
case [:range "to" 1] (transition (proto-render-put stack [:range "" 2]) [(string-join "" [" to " (proto-render-text value "a range's to")])])
|
|
468
|
+
case [:names count] (transition (proto-render-put stack [:names (inc count)]) [(string-join "" [(if (equal count 0) "" ", ") (proto-render-text value "a reserved name")])])
|
|
469
|
+
case _ (proto-render-refuse "a value where none is, or a member out of its place")
|
|
470
|
+
|
|
471
|
+
def proto-render-step [stack event]
|
|
472
|
+
match (count stack)
|
|
473
|
+
case 0
|
|
474
|
+
match event
|
|
475
|
+
case object-start (proto-render-object-start stack)
|
|
476
|
+
case _ (proto-render-refuse "the root is not an object")
|
|
592
477
|
case _
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
self self (pop places) (proto-append-digit prefix (proto-at found 0)) n
|
|
596
|
-
|
|
597
|
-
def proto-pred [n]
|
|
598
|
-
match (compare n 0)
|
|
599
|
-
case :greater (proto-pred-pos proto-pred-pos (proto-places-of (proto-num n)) "" n)
|
|
600
|
-
case :equal "-1"
|
|
601
|
-
case _ (proto-pred-neg proto-pred-neg (proto-places-of (proto-num n)) "" n)
|
|
602
|
-
|
|
603
|
-
; A message's range, whose end is exclusive: \`start\`, \`start to last\` or
|
|
604
|
-
; \`start to max\`.
|
|
605
|
-
def proto-range-ex [maxv r]
|
|
606
|
-
let [s (get "start" r)]
|
|
607
|
-
let [e (get "end" r)]
|
|
608
|
-
match (compare e maxv)
|
|
609
|
-
case :equal (string-join "" [(proto-num s) " to max"])
|
|
610
|
-
case _
|
|
611
|
-
let [p (proto-pred e)]
|
|
612
|
-
match (compare (number p) s)
|
|
613
|
-
case :equal (proto-num s)
|
|
614
|
-
case _ (string-join "" [(proto-num s) " to " p])
|
|
615
|
-
|
|
616
|
-
; An enum's reserved range, whose end is inclusive.
|
|
617
|
-
def proto-range-in [r]
|
|
618
|
-
let [s (get "start" r)]
|
|
619
|
-
let [e (get "end" r)]
|
|
620
|
-
match (compare e s)
|
|
621
|
-
case :equal (proto-num s)
|
|
478
|
+
match (top stack)
|
|
479
|
+
case :done (fail :protocol-order "the events hold more after the file, which a tree's never do")
|
|
622
480
|
case _
|
|
623
|
-
match
|
|
624
|
-
case
|
|
625
|
-
case
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
;
|
|
644
|
-
;
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
;
|
|
661
|
-
|
|
662
|
-
;
|
|
663
|
-
;
|
|
664
|
-
;
|
|
665
|
-
;
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
;
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
481
|
+
match event
|
|
482
|
+
case object-start (proto-render-object-start stack)
|
|
483
|
+
case object-end (proto-render-object-end stack)
|
|
484
|
+
case array-start (proto-render-array-start stack)
|
|
485
|
+
case array-end (proto-render-array-end stack)
|
|
486
|
+
case (key name) (proto-render-key stack name)
|
|
487
|
+
case (scalar value) (proto-render-scalar stack value)
|
|
488
|
+
|
|
489
|
+
def proto-render-finish [stack]
|
|
490
|
+
match stack
|
|
491
|
+
case [:done] []
|
|
492
|
+
case [] (fail :protocol-order "the events hold no value, where a tree's hold one")
|
|
493
|
+
case _ (fail :protocol-order "the events ended inside a container, which a tree's never do")
|
|
494
|
+
|
|
495
|
+
; The render: the tree's events in, the \`.proto\` file's text out.
|
|
496
|
+
def proto-render [input]
|
|
497
|
+
join ""
|
|
498
|
+
scan-emit [] proto-render-step proto-render-finish (events input)
|
|
499
|
+
` }),
|
|
500
|
+
transduce: Object.freeze({ entry: "proto-transduce", source: `; proto's transducer part: the source-ordered tree's JSON events from the
|
|
501
|
+
; proto grammar's rule passes, for a host that reads parser events (dmog's
|
|
502
|
+
; \`translate\` and \`run --grammar proto\`). Every event is the one the walk
|
|
503
|
+
; of the tree \`parseTree\` builds gives (the schema \`proto-ast\`, alchemy's
|
|
504
|
+
; docs/streaming-plan.md section 13.1): the file's declarations in source
|
|
505
|
+
; order, each an object whose \`type\` comes first and whose other members
|
|
506
|
+
; follow in the order the statement spells them, and every scalar the
|
|
507
|
+
; text the source spells, its tokens run together. It is hand-written,
|
|
508
|
+
; since the grammar is compiled from proto-grammar/*.abnf and builds a
|
|
509
|
+
; \`{rule, src, kids}\` node per rule, which the passes do not show.
|
|
510
|
+
;
|
|
511
|
+
; The passes. The compiled grammar names a statement's alternative after
|
|
512
|
+
; the rule that dispatches it, and the dispatch pushes it: \`topLevelDef$alt4\`
|
|
513
|
+
; is a message, \`messageElement$alt12\` a field (\`proto-transduce-statement\`
|
|
514
|
+
; has the table, which proto-grammar/*.abnf's alternative order fixes, and
|
|
515
|
+
; each runtime's tests hold it to the keyword each alternative opens with).
|
|
516
|
+
; A statement's object begins at its alternative's open pass and ends at
|
|
517
|
+
; the close of the last rule its alternative is replaced with (\`$step1\`,
|
|
518
|
+
; \`$step2\`, ...), so a statement is a chain of rules that one marker
|
|
519
|
+
; spans: a close whose alternate replaces its rule hands its marker on to
|
|
520
|
+
; the rule that replaces it, as an open replaced at once does. An extend's
|
|
521
|
+
; field (\`field\`), an rpc block's option (\`optionStmt\`), an option in
|
|
522
|
+
; brackets (\`fieldOption\`) and an aggregate's field (\`messageValueEntry\`)
|
|
523
|
+
; are rules of their own, and so is each statement's value: a member is
|
|
524
|
+
; the text of the rule that holds it (\`ident\` a name, \`fieldNumber\` a
|
|
525
|
+
; number, \`fieldType\` a type, \`optionName\` an option's name, \`constant\` a
|
|
526
|
+
; value, \`strLit\` a path), every token the passes between its open and its
|
|
527
|
+
; close consumed, run together, as the grammar's node keeps its \`src\`.
|
|
528
|
+
; What the grammar inlines into the rule that leads to it is read from the
|
|
529
|
+
; tokens: an import's modifier, a message's or an enum's visibility, an
|
|
530
|
+
; rpc's \`stream\`, a body's braces, an enum value's name and its signed
|
|
531
|
+
; number, the name of an option in brackets (up to its \`=\`), the bounds of
|
|
532
|
+
; a reserved or an extensions range, a reserved name, an aggregate field's
|
|
533
|
+
; name and the string literals it runs together. An aggregate (a constant
|
|
534
|
+
; whose alternative is \`constant$alt5\`) is its fields, an array.
|
|
535
|
+
;
|
|
536
|
+
; The state is [started marks frames text carry]: whether any pass came
|
|
537
|
+
; (a source that makes none, the empty file, is an empty file at finish);
|
|
538
|
+
; a marker per open rule whose close will come, innermost last (:none,
|
|
539
|
+
; :text, :array, :statement, :file); a frame per open statement, [kind
|
|
540
|
+
; phase], the phase saying what its next token is; the text being read,
|
|
541
|
+
; [string mode] or missing, at most one at a time, whose mode says what
|
|
542
|
+
; ends it (:rule, its rule's close; :token, a token its frame reads as an
|
|
543
|
+
; end, or another member); and the marker a replaced rule hands on, or
|
|
544
|
+
; missing. Nothing grows with the document's length, only with its
|
|
545
|
+
; nesting and the text of one member, under max_metadata_bytes.
|
|
546
|
+
|
|
547
|
+
; The kind of statement a rule begins, by its name, or missing.
|
|
548
|
+
def proto-transduce-statement [name]
|
|
549
|
+
match (first-split "$alt" name)
|
|
550
|
+
case ["syntaxOrEdition" n]
|
|
551
|
+
match n
|
|
552
|
+
case "0" :syntax
|
|
553
|
+
case "1" :edition
|
|
554
|
+
case _ missing
|
|
555
|
+
case ["topLevelDef" n]
|
|
556
|
+
match n
|
|
557
|
+
case "0" :import
|
|
558
|
+
case "1" :import
|
|
559
|
+
case "2" :package
|
|
560
|
+
case "3" :option
|
|
561
|
+
case "4" :message
|
|
562
|
+
case "5" :enum
|
|
563
|
+
case "6" :service
|
|
564
|
+
case "7" :extend
|
|
565
|
+
case "8" :empty
|
|
566
|
+
case "9" :visible-message
|
|
567
|
+
case "10" :visible-enum
|
|
568
|
+
case _ missing
|
|
569
|
+
case ["messageElement" n]
|
|
570
|
+
match n
|
|
571
|
+
case "0" :enum
|
|
572
|
+
case "1" :message
|
|
573
|
+
case "2" :option
|
|
574
|
+
case "3" :oneof
|
|
575
|
+
case "4" :map
|
|
576
|
+
case "5" :extend
|
|
577
|
+
case "6" :extensions
|
|
578
|
+
case "7" :reserved
|
|
579
|
+
case "8" :empty
|
|
580
|
+
case "9" :visible-message
|
|
581
|
+
case "10" :visible-enum
|
|
582
|
+
case "11" :group
|
|
583
|
+
case "12" :field
|
|
584
|
+
case _ missing
|
|
585
|
+
case ["enumElement" n]
|
|
586
|
+
match n
|
|
587
|
+
case "0" :option
|
|
588
|
+
case "1" :reserved
|
|
589
|
+
case "2" :empty
|
|
590
|
+
case "3" :enum-value
|
|
591
|
+
case _ missing
|
|
592
|
+
case ["oneofElement" n]
|
|
593
|
+
match n
|
|
594
|
+
case "0" :option
|
|
595
|
+
case "1" :empty
|
|
596
|
+
case "2" :group
|
|
597
|
+
case "3" :oneof-field
|
|
598
|
+
case _ missing
|
|
599
|
+
case ["serviceElement" n]
|
|
600
|
+
match n
|
|
601
|
+
case "0" :option
|
|
602
|
+
case "1" :empty
|
|
603
|
+
case "2" :rpc
|
|
604
|
+
case _ missing
|
|
605
|
+
case ["field"] :field
|
|
606
|
+
case ["optionStmt"] :option
|
|
607
|
+
case ["fieldOption"] :field-option
|
|
608
|
+
case ["messageValueEntry"] :entry
|
|
609
|
+
case _ missing
|
|
610
|
+
|
|
611
|
+
; The \`type\` a statement's object holds.
|
|
612
|
+
def proto-transduce-type [kind]
|
|
613
|
+
match kind
|
|
614
|
+
case :visible-message "message"
|
|
615
|
+
case :visible-enum "enum"
|
|
616
|
+
case :oneof-field "field"
|
|
617
|
+
case :enum-value "enumValue"
|
|
618
|
+
case :syntax "syntax"
|
|
619
|
+
case :edition "edition"
|
|
620
|
+
case :import "import"
|
|
621
|
+
case :package "package"
|
|
622
|
+
case :option "option"
|
|
623
|
+
case :message "message"
|
|
624
|
+
case :enum "enum"
|
|
625
|
+
case :service "service"
|
|
626
|
+
case :extend "extend"
|
|
627
|
+
case :oneof "oneof"
|
|
628
|
+
case :map "map"
|
|
629
|
+
case :extensions "extensions"
|
|
630
|
+
case :reserved "reserved"
|
|
631
|
+
case :group "group"
|
|
632
|
+
case :field "field"
|
|
633
|
+
case :rpc "rpc"
|
|
634
|
+
|
|
635
|
+
; Whether a statement of the kind holds a body in braces.
|
|
636
|
+
def proto-transduce-has-body [kind]
|
|
637
|
+
match kind
|
|
638
|
+
case :message true
|
|
639
|
+
case :visible-message true
|
|
640
|
+
case :enum true
|
|
641
|
+
case :visible-enum true
|
|
642
|
+
case :service true
|
|
643
|
+
case :oneof true
|
|
644
|
+
case :extend true
|
|
645
|
+
case :group true
|
|
646
|
+
case :rpc true
|
|
681
647
|
case _ false
|
|
682
648
|
|
|
683
|
-
;
|
|
684
|
-
;
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
649
|
+
; The member a rule's text is in a statement of the kind: a key, :type for
|
|
650
|
+
; a map's or an rpc's type (the first or the second), :strings for the
|
|
651
|
+
; first string literal of an aggregate field's run, :options for an
|
|
652
|
+
; option list, or missing where the rule is no member of it.
|
|
653
|
+
def proto-transduce-member [kind name]
|
|
654
|
+
match [kind name]
|
|
655
|
+
case [:syntax "strLit"] "value"
|
|
656
|
+
case [:edition "strLit"] "value"
|
|
657
|
+
case [:import "strLit"] "path"
|
|
658
|
+
case [:entry "strLit"] :strings
|
|
659
|
+
case [:package "fullIdent"] "name"
|
|
660
|
+
case [:oneof-field "fullIdent"] "fieldType"
|
|
661
|
+
case [:option "optionName"] "name"
|
|
662
|
+
case [:option "constant"] "value"
|
|
663
|
+
case [:field-option "constant"] "value"
|
|
664
|
+
case [:entry "constant"] "value"
|
|
665
|
+
case [:message "ident"] "name"
|
|
666
|
+
case [:visible-message "ident"] "name"
|
|
667
|
+
case [:enum "ident"] "name"
|
|
668
|
+
case [:visible-enum "ident"] "name"
|
|
669
|
+
case [:service "ident"] "name"
|
|
670
|
+
case [:oneof "ident"] "name"
|
|
671
|
+
case [:group "ident"] "name"
|
|
672
|
+
case [:field "ident"] "name"
|
|
673
|
+
case [:oneof-field "ident"] "name"
|
|
674
|
+
case [:map "ident"] "name"
|
|
675
|
+
case [:rpc "ident"] "name"
|
|
676
|
+
case [:group "fieldNumber"] "number"
|
|
677
|
+
case [:field "fieldNumber"] "number"
|
|
678
|
+
case [:oneof-field "fieldNumber"] "number"
|
|
679
|
+
case [:map "fieldNumber"] "number"
|
|
680
|
+
case [:field "label"] "label"
|
|
681
|
+
case [:group "label"] "label"
|
|
682
|
+
case [:field "fieldType"] "fieldType"
|
|
683
|
+
case [:map "fieldType"] :type
|
|
684
|
+
case [:extend "messageType"] "extendee"
|
|
685
|
+
case [:rpc "messageType"] :type
|
|
686
|
+
case [:field "fieldOptions"] :options
|
|
687
|
+
case [:oneof-field "fieldOptions"] :options
|
|
688
|
+
case [:map "fieldOptions"] :options
|
|
689
|
+
case [:extensions "fieldOptions"] :options
|
|
690
|
+
case [:enum-value "fieldOptions"] :options
|
|
691
|
+
case _ missing
|
|
692
|
+
|
|
693
|
+
; The machine a step threads: [marks frames text carry outputs].
|
|
694
|
+
def proto-transduce-emit [m more]
|
|
695
|
+
match m
|
|
696
|
+
case [marks frames text carry outputs] [marks frames text carry (push-all more outputs)]
|
|
697
|
+
|
|
698
|
+
def proto-transduce-frame [m]
|
|
699
|
+
match m
|
|
700
|
+
case [marks frames text carry outputs]
|
|
701
|
+
match (count frames)
|
|
702
|
+
case 0 missing
|
|
703
|
+
case _ (top frames)
|
|
704
|
+
|
|
705
|
+
; The innermost frame in a new phase.
|
|
706
|
+
def proto-transduce-phase [m phase]
|
|
707
|
+
match m
|
|
708
|
+
case [marks frames text carry outputs]
|
|
709
|
+
match (top frames)
|
|
710
|
+
case [kind old] [marks (push [kind phase] (pop frames)) text carry outputs]
|
|
711
|
+
|
|
712
|
+
def proto-transduce-set-text [m text]
|
|
713
|
+
match m
|
|
714
|
+
case [marks frames old carry outputs] [marks frames text carry outputs]
|
|
715
|
+
|
|
716
|
+
; The text being read, with \`more\` written at its end.
|
|
717
|
+
def proto-transduce-write [m more]
|
|
718
|
+
match m
|
|
719
|
+
case [marks frames [s mode] carry outputs] [marks frames [(string-join "" [s more]) mode] carry outputs]
|
|
720
|
+
|
|
721
|
+
; The text ends: its scalar.
|
|
722
|
+
def proto-transduce-end-text [m]
|
|
723
|
+
match m
|
|
724
|
+
case [marks frames [s mode] carry outputs] [marks frames missing carry (push (scalar s) outputs)]
|
|
725
|
+
case _ m
|
|
726
|
+
|
|
727
|
+
; The innermost frame's pending text and the containers its phase holds
|
|
728
|
+
; open, closed: a range's bound, its object and the ranges' array, or a
|
|
729
|
+
; reserved name list's array.
|
|
730
|
+
def proto-transduce-settle [m]
|
|
731
|
+
let [ended (match m (case [marks frames [s :token] carry outputs] (proto-transduce-end-text m)) (case _ m))]
|
|
732
|
+
match (proto-transduce-frame ended)
|
|
733
|
+
case [kind :from] (proto-transduce-phase (proto-transduce-emit ended [object-end array-end]) :done)
|
|
734
|
+
case [kind :to] (proto-transduce-phase (proto-transduce-emit ended [object-end array-end]) :done)
|
|
735
|
+
case [kind :next] (proto-transduce-phase (proto-transduce-emit ended [array-end]) :done)
|
|
736
|
+
case [kind :names] (proto-transduce-phase (proto-transduce-emit ended [array-end]) :done)
|
|
737
|
+
case _ ended
|
|
738
|
+
|
|
739
|
+
; A statement begins: its frame, and the events that open its object.
|
|
740
|
+
def proto-transduce-begin [m kind]
|
|
741
|
+
match m
|
|
742
|
+
case [marks frames text carry outputs]
|
|
743
|
+
match kind
|
|
744
|
+
case :empty [marks (push [kind :start] frames) text carry outputs]
|
|
745
|
+
case :field-option [marks (push [kind :name] frames) ["" :token] carry (push-all [object-start (key "name")] outputs)]
|
|
746
|
+
case :entry [marks (push [kind :entry-name] frames) text carry (push object-start outputs)]
|
|
747
|
+
case :visible-message [marks (push [kind :visibility] frames) text carry (push-all [object-start (key "type") (scalar "message")] outputs)]
|
|
748
|
+
case :visible-enum [marks (push [kind :visibility] frames) text carry (push-all [object-start (key "type") (scalar "enum")] outputs)]
|
|
749
|
+
case :rpc [marks (push [kind :in] frames) text carry (push-all [object-start (key "type") (scalar "rpc")] outputs)]
|
|
750
|
+
case :map [marks (push [kind :key] frames) text carry (push-all [object-start (key "type") (scalar "map")] outputs)]
|
|
751
|
+
case _ [marks (push [kind :start] frames) text carry (push-all [object-start (key "type") (scalar (proto-transduce-type kind))] outputs)]
|
|
752
|
+
|
|
753
|
+
; A statement ends: its pending text and containers close, then its
|
|
754
|
+
; object.
|
|
755
|
+
def proto-transduce-finish-statement [m]
|
|
756
|
+
let [settled (proto-transduce-settle m)]
|
|
757
|
+
match settled
|
|
758
|
+
case [marks frames text carry outputs]
|
|
759
|
+
match (top frames)
|
|
760
|
+
case [:empty phase] [marks (pop frames) text carry outputs]
|
|
761
|
+
case _ [marks (pop frames) text carry (push object-end outputs)]
|
|
762
|
+
|
|
763
|
+
; A token whose text begins the frame's text.
|
|
764
|
+
def proto-transduce-begin-text [m src]
|
|
765
|
+
proto-transduce-set-text m [src :token]
|
|
766
|
+
|
|
767
|
+
; A reserved or an extensions statement's list: a range's bounds or a name.
|
|
768
|
+
def proto-transduce-list [m kind phase token]
|
|
769
|
+
let [src (get :src token)]
|
|
770
|
+
match phase
|
|
771
|
+
case :start (proto-transduce-phase m :list)
|
|
772
|
+
case :list
|
|
773
|
+
if (match [kind (get :name token) src] (case [:extensions n s] true) (case [k "#NR" s] true) (case [k n "-"] true) (case _ false))
|
|
774
|
+
proto-transduce-phase (proto-transduce-begin-text (proto-transduce-emit m [(key "ranges") array-start object-start (key "from")]) src) :from
|
|
775
|
+
proto-transduce-phase (proto-transduce-emit m [(key "names") array-start (scalar src)]) :names
|
|
776
|
+
case :next (proto-transduce-phase (proto-transduce-begin-text (proto-transduce-emit m [object-start (key "from")]) src) :from)
|
|
777
|
+
case :names
|
|
778
|
+
match src
|
|
779
|
+
case "," m
|
|
780
|
+
case ";" (proto-transduce-phase (proto-transduce-emit m [array-end]) :done)
|
|
781
|
+
case _ (proto-transduce-emit m [(scalar src)])
|
|
782
|
+
case _ m
|
|
783
|
+
|
|
784
|
+
; A token the frame reads, no rule's text being open and the frame's own
|
|
785
|
+
; text not ending at it.
|
|
786
|
+
def proto-transduce-frame-token [m token]
|
|
787
|
+
let [src (get :src token)]
|
|
788
|
+
match (proto-transduce-frame m)
|
|
789
|
+
case missing m
|
|
790
|
+
case [kind phase]
|
|
791
|
+
match [(proto-transduce-has-body kind) phase src]
|
|
792
|
+
case [true :body "}"] (proto-transduce-phase (proto-transduce-emit m [array-end]) :done)
|
|
793
|
+
case [true :body s] m
|
|
794
|
+
case [true p "{"] (proto-transduce-phase (proto-transduce-emit (proto-transduce-settle m) [(key "body") array-start]) :body)
|
|
795
|
+
case _
|
|
796
|
+
match kind
|
|
797
|
+
case :import
|
|
798
|
+
match [phase src]
|
|
799
|
+
case [:start s] (proto-transduce-phase m :keyword)
|
|
800
|
+
case [:keyword ";"] m
|
|
801
|
+
case [:keyword s] (proto-transduce-phase (proto-transduce-emit m [(key "modifier") (scalar s)]) :done)
|
|
802
|
+
case _ m
|
|
803
|
+
case :visible-message
|
|
804
|
+
match phase
|
|
805
|
+
case :visibility (proto-transduce-phase (proto-transduce-emit m [(key "visibility") (scalar src)]) :start)
|
|
806
|
+
case _ m
|
|
807
|
+
case :visible-enum
|
|
808
|
+
match phase
|
|
809
|
+
case :visibility (proto-transduce-phase (proto-transduce-emit m [(key "visibility") (scalar src)]) :start)
|
|
810
|
+
case _ m
|
|
811
|
+
case :oneof-field
|
|
812
|
+
match [phase src]
|
|
813
|
+
case [:start "."] (proto-transduce-phase m :dot)
|
|
814
|
+
case _ m
|
|
815
|
+
case :rpc
|
|
816
|
+
match [phase src]
|
|
817
|
+
case [:in "stream"] (proto-transduce-emit m [(key "inputStream") (scalar true)])
|
|
818
|
+
case [:out "stream"] (proto-transduce-emit m [(key "outputStream") (scalar true)])
|
|
819
|
+
case _ m
|
|
820
|
+
case :enum-value
|
|
821
|
+
match [phase src]
|
|
822
|
+
case [:start s] (proto-transduce-phase (proto-transduce-emit m [(key "name") (scalar s)]) :named)
|
|
823
|
+
case [:named "="] (proto-transduce-phase (proto-transduce-begin-text (proto-transduce-emit m [(key "number")]) "") :number)
|
|
824
|
+
case _ m
|
|
825
|
+
case :entry
|
|
826
|
+
match phase
|
|
827
|
+
case :entry-name (proto-transduce-phase (proto-transduce-emit m [(key "name") (scalar src)]) :colon)
|
|
828
|
+
case _ m
|
|
829
|
+
case :reserved (proto-transduce-list m kind phase token)
|
|
830
|
+
case :extensions (proto-transduce-list m kind phase token)
|
|
831
|
+
case _ m
|
|
832
|
+
|
|
833
|
+
; Whether a token ends the frame's own text: an option name's \`=\`, an
|
|
834
|
+
; enum value's \`;\`, a token other than a string literal after an
|
|
835
|
+
; aggregate field's run of them, and a range bound's \`to\`, \`,\` or \`;\`.
|
|
836
|
+
def proto-transduce-ends [phase token]
|
|
837
|
+
let [src (get :src token)]
|
|
838
|
+
match phase
|
|
839
|
+
case :name (equal src "=")
|
|
840
|
+
case :number (equal src ";")
|
|
841
|
+
case :strings (if (equal (get :name token) "#ST") false true)
|
|
842
|
+
case :from (match src (case "to" true) (case "," true) (case ";" true) (case _ false))
|
|
843
|
+
case :to (match src (case "," true) (case ";" true) (case _ false))
|
|
689
844
|
case _ false
|
|
690
845
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
def proto-entry-options [fo feats g]
|
|
751
|
-
match [(count feats) (proto-has "options" g)]
|
|
752
|
-
case [0 false] true
|
|
753
|
-
case [0 true] false
|
|
754
|
-
case [_ false] false
|
|
755
|
-
case _
|
|
756
|
-
let [o (get "options" g)]
|
|
757
|
-
match (kind o)
|
|
758
|
-
case :record
|
|
759
|
-
match (proto-same-number (count (keys o)) (count feats))
|
|
760
|
-
case true (proto-same-number (count (filter (fn [k] (proto-same-value (get k o) (get k fo))) feats)) (count feats))
|
|
761
|
-
case false false
|
|
762
|
-
case _ false
|
|
763
|
-
|
|
764
|
-
def proto-entry-field-keys ["name" "$name" "number" "label" "type" "typeName" "options"]
|
|
765
|
-
|
|
766
|
-
; Whether g is a field of an entry as the reader makes it, \`key\` 1 or
|
|
767
|
-
; \`value\` 2: optional, of a type or a type name, and with no option but
|
|
768
|
-
; the features the map field passes down.
|
|
769
|
-
def proto-entry-field [name number fo feats g]
|
|
770
|
-
match (kind g)
|
|
771
|
-
case :record
|
|
772
|
-
match [(proto-is-text name (get "name" g)) (get "label" g) (kind (get "number" g)) (proto-has "type" g) (proto-has "typeName" g) (proto-only proto-entry-field-keys g)]
|
|
773
|
-
case [true "LABEL_OPTIONAL" :number true false true]
|
|
774
|
-
match (proto-same-number (get "number" g) number)
|
|
775
|
-
case true (proto-entry-options fo feats g)
|
|
776
|
-
case false false
|
|
777
|
-
case [true "LABEL_OPTIONAL" :number false true true]
|
|
778
|
-
match (proto-same-number (get "number" g) number)
|
|
779
|
-
case true (proto-entry-options fo feats g)
|
|
780
|
-
case false false
|
|
781
|
-
case _ false
|
|
782
|
-
case _ false
|
|
783
|
-
|
|
784
|
-
def proto-entry-keys ["name" "$name" "field" "nestedType" "enumType" "oneofDecl" "extension" "options"]
|
|
785
|
-
|
|
786
|
-
; Whether the nested type n is the entry the reader makes for the map
|
|
787
|
-
; field f, so that f written as a map reads back with n as it is: n named
|
|
788
|
-
; for f by protoc's rule, with no member but its fields, its empty lists
|
|
789
|
-
; and the option \`mapEntry\` alone, and its fields \`key\` and \`value\` as the
|
|
790
|
-
; reader makes them. A message the file declares, the option \`mapEntry\`
|
|
791
|
-
; in it, is any other one, and is written as a message.
|
|
792
|
-
def proto-map-entry [f n]
|
|
793
|
-
match [(kind (get "name" f)) (kind (get "name" n))]
|
|
794
|
-
case [:string :string]
|
|
795
|
-
match [(proto-same-text (proto-entry-name (get "name" f)) (get "name" n)) (proto-only proto-entry-keys n)]
|
|
796
|
-
case [true true]
|
|
797
|
-
let [o (proto-record "options" n)]
|
|
798
|
-
match [(proto-empty "nestedType" n) (proto-empty "enumType" n) (proto-empty "oneofDecl" n) (proto-empty "extension" n) (count (keys o)) (get "mapEntry" o)]
|
|
799
|
-
case [true true true true 1 true]
|
|
800
|
-
let [kv (proto-list "field" n)]
|
|
801
|
-
match (count kv)
|
|
802
|
-
case 2
|
|
803
|
-
let [fo (proto-record "options" f)]
|
|
804
|
-
let [feats (filter proto-feature-key (keys fo))]
|
|
805
|
-
match [(proto-entry-field "key" 1 fo feats (proto-at kv 0)) (proto-entry-field "value" 2 fo feats (proto-at kv 1))]
|
|
806
|
-
case [true true] true
|
|
807
|
-
case _ false
|
|
808
|
-
case _ false
|
|
809
|
-
case _ false
|
|
810
|
-
case _ false
|
|
811
|
-
case _ false
|
|
812
|
-
|
|
813
|
-
def proto-first [v]
|
|
814
|
-
match (count v)
|
|
815
|
-
case 0 -1
|
|
816
|
-
case _ (proto-at v 0)
|
|
817
|
-
|
|
818
|
-
def proto-last [v]
|
|
819
|
-
match (count v)
|
|
820
|
-
case 0 -1
|
|
821
|
-
case _ (top v)
|
|
822
|
-
|
|
823
|
-
def proto-entry-named [f n]
|
|
824
|
-
match (proto-named (get "typeName" f) n)
|
|
825
|
-
case true (proto-map-entry f n)
|
|
826
|
-
case false false
|
|
827
|
-
|
|
828
|
-
; The nested type a field is written with, its index, or -1: a group's
|
|
829
|
-
; message, and a map field's entry. A map field is a repeated field whose
|
|
830
|
-
; type is named for a nested type that is the entry the reader would make
|
|
831
|
-
; for it (\`proto-map-entry\`).
|
|
832
|
-
def proto-attached [ns f]
|
|
833
|
-
match (get "type" f)
|
|
834
|
-
case "TYPE_GROUP" (proto-first (filter (fn [t] (proto-named (get "typeName" f) (proto-at ns t))) (indices ns)))
|
|
835
|
-
case _
|
|
836
|
-
match (get "label" f)
|
|
837
|
-
case "LABEL_REPEATED"
|
|
838
|
-
match [(proto-has "type" f) (proto-has "typeName" f) (proto-has "oneofIndex" f) (proto-has "extendee" f)]
|
|
839
|
-
case [false true false false] (proto-first (filter (fn [t] (proto-entry-named f (proto-at ns t))) (indices ns)))
|
|
840
|
-
case _ -1
|
|
841
|
-
case _ -1
|
|
842
|
-
|
|
843
|
-
; Whether a field is in a declared oneof: a proto3 \`optional\` field's
|
|
844
|
-
; oneof is synthetic, and the field is written \`optional\`.
|
|
845
|
-
def proto-in-oneof [f]
|
|
846
|
-
match (proto-has "oneofIndex" f)
|
|
847
|
-
case true
|
|
848
|
-
match (get "proto3Optional" f)
|
|
849
|
-
case true false
|
|
846
|
+
; The frame's own text, ended by a token, and what the token says next.
|
|
847
|
+
def proto-transduce-text-end [m token]
|
|
848
|
+
let [src (get :src token)]
|
|
849
|
+
let [ended (proto-transduce-end-text m)]
|
|
850
|
+
match (proto-transduce-frame ended)
|
|
851
|
+
case [kind :name] (proto-transduce-phase ended :value)
|
|
852
|
+
case [kind :number] (proto-transduce-phase ended :done)
|
|
853
|
+
case [kind :strings] (proto-transduce-phase ended :done)
|
|
854
|
+
case [kind :from]
|
|
855
|
+
match src
|
|
856
|
+
case "to" (proto-transduce-phase (proto-transduce-begin-text (proto-transduce-emit ended [(key "to")]) "") :to)
|
|
857
|
+
case "," (proto-transduce-phase (proto-transduce-emit ended [object-end]) :next)
|
|
858
|
+
case _ (proto-transduce-phase (proto-transduce-emit ended [object-end array-end]) :done)
|
|
859
|
+
case [kind :to]
|
|
860
|
+
match src
|
|
861
|
+
case "," (proto-transduce-phase (proto-transduce-emit ended [object-end]) :next)
|
|
862
|
+
case _ (proto-transduce-phase (proto-transduce-emit ended [object-end array-end]) :done)
|
|
863
|
+
case _ ended
|
|
864
|
+
|
|
865
|
+
; One token a pass consumed: written to a rule's text, or to the frame's
|
|
866
|
+
; own text unless it ends it, or read by the frame.
|
|
867
|
+
def proto-transduce-token [m token]
|
|
868
|
+
match m
|
|
869
|
+
case [marks frames [s :rule] carry outputs] (proto-transduce-write m (get :src token))
|
|
870
|
+
case [marks frames [s :token] carry outputs]
|
|
871
|
+
match (proto-transduce-frame m)
|
|
872
|
+
case [kind phase]
|
|
873
|
+
if (proto-transduce-ends phase token)
|
|
874
|
+
match phase
|
|
875
|
+
case :strings (proto-transduce-frame-token (proto-transduce-text-end m token) token)
|
|
876
|
+
case _ (proto-transduce-text-end m token)
|
|
877
|
+
proto-transduce-write m (get :src token)
|
|
878
|
+
case _ (proto-transduce-frame-token m token)
|
|
879
|
+
|
|
880
|
+
; The tokens a pass consumed, in order: at most three in this grammar,
|
|
881
|
+
; and four read, so that a fifth fails rather than vanishes.
|
|
882
|
+
def proto-transduce-tokens [m rule]
|
|
883
|
+
let [tokens (get :tokens rule)]
|
|
884
|
+
match (count tokens)
|
|
885
|
+
case 0 m
|
|
886
|
+
case 1 (proto-transduce-token m (transduce-token 0 rule))
|
|
887
|
+
case 2 (proto-transduce-token (proto-transduce-token m (transduce-token 0 rule)) (transduce-token 1 rule))
|
|
888
|
+
case 3 (proto-transduce-token (proto-transduce-token (proto-transduce-token m (transduce-token 0 rule)) (transduce-token 1 rule)) (transduce-token 2 rule))
|
|
889
|
+
case 4 (proto-transduce-token (proto-transduce-token (proto-transduce-token (proto-transduce-token m (transduce-token 0 rule)) (transduce-token 1 rule)) (transduce-token 2 rule)) (transduce-token 3 rule))
|
|
890
|
+
case _ (fail :protocol-order "a rule pass consumed more tokens than any of the proto grammar's alternates")
|
|
891
|
+
|
|
892
|
+
; The rule pushed by a pass's alternate, or "".
|
|
893
|
+
def proto-transduce-pushes [rule]
|
|
894
|
+
match (get :alt rule)
|
|
895
|
+
case missing ""
|
|
896
|
+
case alt (get :p alt)
|
|
897
|
+
|
|
898
|
+
; Whether a pass's alternate replaces its rule.
|
|
899
|
+
def proto-transduce-replaced [rule]
|
|
900
|
+
match (get :alt rule)
|
|
901
|
+
case missing false
|
|
902
|
+
case alt
|
|
903
|
+
match (get :r alt)
|
|
904
|
+
case "" false
|
|
850
905
|
case _ true
|
|
851
|
-
case false false
|
|
852
|
-
|
|
853
|
-
def proto-same-oneof [fs j k]
|
|
854
|
-
let [a (proto-at fs j)]
|
|
855
|
-
let [b (proto-at fs k)]
|
|
856
|
-
match (proto-in-oneof b)
|
|
857
|
-
case true (proto-same-number (get "oneofIndex" a) (get "oneofIndex" b))
|
|
858
|
-
case false false
|
|
859
906
|
|
|
860
|
-
; A
|
|
861
|
-
;
|
|
862
|
-
def proto-
|
|
863
|
-
match
|
|
864
|
-
case
|
|
865
|
-
case
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
case
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
case false [j]
|
|
873
|
-
case true (filter (fn [k] (proto-same-oneof fs j k)) (indices fs))
|
|
874
|
-
|
|
875
|
-
def proto-attached-of [att ks]
|
|
876
|
-
filter (fn [t] (proto-less -1 t)) (map (fn [k] (proto-at att k)) ks)
|
|
877
|
-
|
|
878
|
-
; The nested types written as messages, between two attached ones.
|
|
879
|
-
def proto-plain-nested [ns att lo hi]
|
|
880
|
-
filter
|
|
881
|
-
fn [t]
|
|
882
|
-
match (proto-member t att)
|
|
883
|
-
case true false
|
|
884
|
-
case false
|
|
885
|
-
match [(proto-less lo t) (proto-less t hi)]
|
|
886
|
-
case [true true] true
|
|
887
|
-
case _ false
|
|
888
|
-
indices ns
|
|
889
|
-
|
|
890
|
-
; The messages due before a unit: those after the nested type of the last
|
|
891
|
-
; attached field before it and before the unit's own first.
|
|
892
|
-
def proto-nested-before [indent ns bodies fs att j]
|
|
893
|
-
let [mine (proto-attached-of att (proto-unit-fields fs j))]
|
|
894
|
-
match (count mine)
|
|
895
|
-
case 0 ""
|
|
896
|
-
case _
|
|
897
|
-
let [lo (proto-last (proto-attached-of att (filter (fn [k] (proto-less k j)) (indices fs))))]
|
|
898
|
-
string-join "\\n"
|
|
899
|
-
map (fn [t] (proto-message indent (proto-at ns t) (proto-at bodies t))) (proto-plain-nested ns att lo (proto-at mine 0))
|
|
900
|
-
|
|
901
|
-
def proto-nested-after [indent ns bodies att]
|
|
902
|
-
let [lo (proto-last (filter (fn [t] (proto-less -1 t)) att))]
|
|
903
|
-
string-join "\\n"
|
|
904
|
-
map (fn [t] (proto-message indent (proto-at ns t) (proto-at bodies t))) (proto-plain-nested ns att lo 4294967296)
|
|
905
|
-
|
|
906
|
-
; The declared oneofs: all but the synthetic ones of proto3 \`optional\`.
|
|
907
|
-
def proto-declared-oneofs [m]
|
|
908
|
-
let [synthetic (map (fn [f] (get "oneofIndex" f)) (filter (fn [f] (match (get "proto3Optional" f) (case true (proto-has "oneofIndex" f)) (case _ false))) (proto-list "field" m)))]
|
|
909
|
-
filter (fn [i] (match (proto-member i synthetic) (case true false) (case false true))) (indices (proto-list "oneofDecl" m))
|
|
910
|
-
|
|
911
|
-
; The declared oneofs no field is in.
|
|
912
|
-
def proto-empty-oneofs [m]
|
|
913
|
-
let [used (map (fn [f] (get "oneofIndex" f)) (filter proto-in-oneof (proto-list "field" m)))]
|
|
914
|
-
filter (fn [i] (match (proto-member i used) (case true false) (case false true))) (proto-declared-oneofs m)
|
|
915
|
-
|
|
916
|
-
def proto-oneof-block [indent m i members]
|
|
917
|
-
let [o (proto-at (proto-list "oneofDecl" m) i)]
|
|
918
|
-
proto-block indent (string-join "" ["oneof " (proto-name "a oneof" o)])
|
|
919
|
-
proto-lines
|
|
920
|
-
vector
|
|
921
|
-
proto-option-lines (proto-deeper indent) (proto-record "options" o)
|
|
922
|
-
members
|
|
923
|
-
|
|
924
|
-
; The empty oneofs due before a unit's oneof: those after the last oneof
|
|
925
|
-
; written before it.
|
|
926
|
-
def proto-oneofs-before [indent m fs j]
|
|
927
|
-
let [f (proto-at fs j)]
|
|
928
|
-
match (proto-in-oneof f)
|
|
929
|
-
case false ""
|
|
930
|
-
case true
|
|
931
|
-
let [lo (proto-last (map (fn [k] (get "oneofIndex" (proto-at fs k))) (filter (fn [k] (match (proto-less k j) (case true (proto-in-oneof (proto-at fs k))) (case false false))) (indices fs))))]
|
|
932
|
-
string-join "\\n"
|
|
933
|
-
map
|
|
934
|
-
fn [i]
|
|
935
|
-
proto-oneof-block indent m i ""
|
|
936
|
-
filter (fn [i] (match [(proto-less lo i) (proto-less i (get "oneofIndex" f))] (case [true true] true) (case _ false))) (proto-empty-oneofs m)
|
|
937
|
-
|
|
938
|
-
def proto-oneofs-after [indent m]
|
|
939
|
-
let [lo (proto-last (map (fn [f] (get "oneofIndex" f)) (filter proto-in-oneof (proto-list "field" m))))]
|
|
940
|
-
string-join "\\n"
|
|
941
|
-
map
|
|
942
|
-
fn [i]
|
|
943
|
-
proto-oneof-block indent m i ""
|
|
944
|
-
filter (fn [i] (proto-less lo i)) (proto-empty-oneofs m)
|
|
945
|
-
|
|
946
|
-
def proto-group-block [syntax indent f body labelled]
|
|
947
|
-
proto-block indent
|
|
948
|
-
string-join ""
|
|
949
|
-
vector
|
|
950
|
-
match labelled
|
|
951
|
-
case true (proto-label syntax f)
|
|
952
|
-
case false ""
|
|
953
|
-
"group "
|
|
954
|
-
proto-text "a group" "typeName" f
|
|
955
|
-
" = "
|
|
956
|
-
proto-num (get "number" f)
|
|
957
|
-
body
|
|
958
|
-
|
|
959
|
-
def proto-map-line [indent f n]
|
|
960
|
-
let [kv (proto-list "field" n)]
|
|
961
|
-
string-join ""
|
|
962
|
-
vector
|
|
963
|
-
indent
|
|
964
|
-
"map<"
|
|
965
|
-
proto-type (proto-at kv 0)
|
|
966
|
-
", "
|
|
967
|
-
proto-type (proto-at kv 1)
|
|
968
|
-
"> "
|
|
969
|
-
proto-name "a map field" f
|
|
970
|
-
" = "
|
|
971
|
-
proto-num (get "number" f)
|
|
972
|
-
proto-field-options f
|
|
973
|
-
";"
|
|
974
|
-
|
|
975
|
-
; A field's statement: a field, a map field, or a group with its body. A
|
|
976
|
-
; group outside a oneof is written with the body the message's own were
|
|
977
|
-
; written with; one in a oneof, a level deeper, has its body written there.
|
|
978
|
-
def proto-field-statement [self syntax indent ns bodies att fs k labelled]
|
|
979
|
-
let [f (proto-at fs k)]
|
|
980
|
-
let [t (proto-at att k)]
|
|
981
|
-
match (proto-less t 0)
|
|
982
|
-
case true (proto-field-line syntax indent f labelled)
|
|
983
|
-
case false
|
|
984
|
-
match (get "type" f)
|
|
985
|
-
case "TYPE_GROUP"
|
|
986
|
-
match labelled
|
|
987
|
-
case true (proto-group-block syntax indent f (proto-at bodies t) labelled)
|
|
988
|
-
case false (proto-group-block syntax indent f (self self syntax (proto-deeper indent) (proto-at ns t)) labelled)
|
|
989
|
-
case _ (proto-map-line indent f (proto-at ns t))
|
|
990
|
-
|
|
991
|
-
def proto-unit-text [self syntax indent m ns bodies fs att j]
|
|
992
|
-
let [f (proto-at fs j)]
|
|
993
|
-
match (proto-in-oneof f)
|
|
994
|
-
case false (proto-field-statement self syntax indent ns bodies att fs j true)
|
|
995
|
-
case true
|
|
996
|
-
proto-oneof-block indent m (get "oneofIndex" f)
|
|
997
|
-
string-join "\\n"
|
|
998
|
-
map (fn [k] (proto-field-statement self syntax (proto-deeper indent) ns bodies att fs k false)) (proto-unit-fields fs j)
|
|
999
|
-
|
|
1000
|
-
def proto-unit [self syntax indent m ns bodies fs att j]
|
|
1001
|
-
match (proto-unit-start fs j)
|
|
1002
|
-
case false ""
|
|
1003
|
-
case true
|
|
1004
|
-
proto-lines
|
|
1005
|
-
vector
|
|
1006
|
-
proto-nested-before indent ns bodies fs att j
|
|
1007
|
-
proto-oneofs-before indent m fs j
|
|
1008
|
-
proto-unit-text self syntax indent m ns bodies fs att j
|
|
1009
|
-
|
|
1010
|
-
; A message's extension ranges, reserved ranges and reserved names, in the
|
|
1011
|
-
; order the tree holds them.
|
|
1012
|
-
def proto-range-key [syntax indent maxv m k]
|
|
1013
|
-
match k
|
|
1014
|
-
case "extensionRange"
|
|
1015
|
-
string-join "\\n"
|
|
1016
|
-
map
|
|
1017
|
-
fn [r]
|
|
1018
|
-
string-join "" [indent "extensions " (proto-range-ex maxv r) (proto-plain-options r) ";"]
|
|
1019
|
-
proto-list "extensionRange" m
|
|
1020
|
-
case "reservedRange" (proto-reserved-ranges indent (string-join ", " (map (fn [r] (proto-range-ex maxv r)) (proto-list "reservedRange" m))))
|
|
1021
|
-
case "reservedName" (proto-reserved-names syntax indent (proto-list "reservedName" m))
|
|
1022
|
-
case _ ""
|
|
1023
|
-
|
|
1024
|
-
; A message's body, the one definition the render recurses through, as
|
|
1025
|
-
; \`self\`. Every nested type's body is written first, a level deeper, and
|
|
1026
|
-
; the rest of the body places them: the recursion then nests a few
|
|
1027
|
-
; evaluation levels a message level, well within alchemy's bound for the
|
|
1028
|
-
; 100 levels the reader accepts, where placing a message among the fields
|
|
1029
|
-
; first would nest some twenty.
|
|
1030
|
-
def proto-message-body [self syntax indent m]
|
|
1031
|
-
let [ns (proto-list "nestedType" m)]
|
|
1032
|
-
let [bodies (map (fn [n] (self self syntax (proto-deeper indent) n)) ns)]
|
|
1033
|
-
proto-message-parts self syntax indent m ns bodies
|
|
1034
|
-
|
|
1035
|
-
def proto-message-parts [self syntax indent m ns bodies]
|
|
1036
|
-
let [fs (proto-list "field" m)]
|
|
1037
|
-
let [att (map (fn [f] (proto-attached ns f)) fs)]
|
|
1038
|
-
proto-lines
|
|
1039
|
-
vector
|
|
1040
|
-
proto-option-lines indent (proto-record "options" m)
|
|
1041
|
-
proto-lines (map (fn [j] (proto-unit self syntax indent m ns bodies fs att j)) (indices fs))
|
|
1042
|
-
proto-nested-after indent ns bodies att
|
|
1043
|
-
proto-oneofs-after indent m
|
|
1044
|
-
string-join "\\n" (map (fn [e] (proto-enum syntax indent e)) (proto-list "enumType" m))
|
|
1045
|
-
string-join "\\n" (map (fn [f] (proto-extend syntax indent f)) (proto-list "extension" m))
|
|
1046
|
-
proto-lines (map (fn [k] (proto-range-key syntax indent (proto-max m) m k)) (keys m))
|
|
1047
|
-
|
|
1048
|
-
; A message's block around its body.
|
|
1049
|
-
def proto-message [indent m body]
|
|
1050
|
-
proto-block indent (string-join "" [(proto-visibility m) "message " (proto-name "a message" m)]) body
|
|
1051
|
-
|
|
1052
|
-
; ---- enums, services, extensions
|
|
1053
|
-
|
|
1054
|
-
def proto-enum-key [syntax indent e k]
|
|
1055
|
-
match k
|
|
907
|
+
; A member's rule opens in a frame: its key, and its text or its
|
|
908
|
+
; container begun; the marker its close will act on.
|
|
909
|
+
def proto-transduce-member-open [m kind phase member rule]
|
|
910
|
+
match member
|
|
911
|
+
case :options [(proto-transduce-emit (proto-transduce-settle m) [(key "options") array-start]) :array]
|
|
912
|
+
case :strings [(proto-transduce-phase (proto-transduce-set-text (proto-transduce-emit m [(key "value")]) ["" :token]) :strings) :none]
|
|
913
|
+
case :type
|
|
914
|
+
match [kind phase]
|
|
915
|
+
case [:map :key] [(proto-transduce-set-text (proto-transduce-phase (proto-transduce-emit m [(key "keyType")]) :value) ["" :rule]) :text]
|
|
916
|
+
case [:map p] [(proto-transduce-set-text (proto-transduce-emit m [(key "valueType")]) ["" :rule]) :text]
|
|
917
|
+
case [:rpc :in] [(proto-transduce-set-text (proto-transduce-phase (proto-transduce-emit m [(key "inputType")]) :out) ["" :rule]) :text]
|
|
918
|
+
case [:rpc p] [(proto-transduce-set-text (proto-transduce-emit m [(key "outputType")]) ["" :rule]) :text]
|
|
1056
919
|
case "value"
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
case
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
case
|
|
1100
|
-
case
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
case
|
|
1105
|
-
case _
|
|
1106
|
-
|
|
1107
|
-
def proto-
|
|
1108
|
-
match
|
|
1109
|
-
case
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
proto-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
case _ (fail :
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
concat-map proto-file
|
|
1157
|
-
select root
|
|
1158
|
-
as-events (scan-emit :other proto-mark-step proto-mark-finish (events input))
|
|
920
|
+
match (proto-transduce-pushes rule)
|
|
921
|
+
case "constant$alt5" [(proto-transduce-emit m [(key "value") array-start]) :array]
|
|
922
|
+
case _ [(proto-transduce-set-text (proto-transduce-emit m [(key "value")]) ["" :rule]) :text]
|
|
923
|
+
case "fieldType"
|
|
924
|
+
match [kind phase]
|
|
925
|
+
case [:oneof-field :dot] [(proto-transduce-set-text (proto-transduce-phase (proto-transduce-emit m [(key "fieldType")]) :typed) ["." :rule]) :text]
|
|
926
|
+
case _ [(proto-transduce-set-text (proto-transduce-emit m [(key "fieldType")]) ["" :rule]) :text]
|
|
927
|
+
case name [(proto-transduce-set-text (proto-transduce-emit m [(key name)]) ["" :rule]) :text]
|
|
928
|
+
|
|
929
|
+
; A rule opens that begins no statement: a member of the innermost frame,
|
|
930
|
+
; or part of the text being read, or nothing.
|
|
931
|
+
def proto-transduce-inner-open [m rule]
|
|
932
|
+
match m
|
|
933
|
+
case [marks frames [s :rule] carry outputs] [m :none]
|
|
934
|
+
case _
|
|
935
|
+
match (proto-transduce-frame m)
|
|
936
|
+
case missing [m :none]
|
|
937
|
+
case [kind phase]
|
|
938
|
+
match (proto-transduce-member kind (get :name rule))
|
|
939
|
+
case missing [m :none]
|
|
940
|
+
case member
|
|
941
|
+
match m
|
|
942
|
+
case [marks frames [s :token] carry outputs]
|
|
943
|
+
match [member phase]
|
|
944
|
+
case [:strings :strings] [m :none]
|
|
945
|
+
case _ (proto-transduce-member-open (proto-transduce-settle m) kind phase member rule)
|
|
946
|
+
case _ (proto-transduce-member-open m kind phase member rule)
|
|
947
|
+
|
|
948
|
+
; An open pass, no marker handed on: the file, a statement, or a rule
|
|
949
|
+
; inside one.
|
|
950
|
+
def proto-transduce-fresh [m rule]
|
|
951
|
+
let [name (get :name rule)]
|
|
952
|
+
match name
|
|
953
|
+
case "__start__" [(proto-transduce-emit (match m (case [marks frames text carry outputs] [marks (push [:file :body] frames) text carry outputs])) [object-start (key "type") (scalar "file") (key "body") array-start]) :file]
|
|
954
|
+
case _
|
|
955
|
+
match (proto-transduce-statement name)
|
|
956
|
+
case missing (proto-transduce-inner-open m rule)
|
|
957
|
+
case kind [(proto-transduce-begin m kind) :statement]
|
|
958
|
+
|
|
959
|
+
; A marker's close.
|
|
960
|
+
def proto-transduce-act [m mark]
|
|
961
|
+
match mark
|
|
962
|
+
case :text (proto-transduce-end-text m)
|
|
963
|
+
case :array (proto-transduce-emit m [array-end])
|
|
964
|
+
case :statement (proto-transduce-finish-statement m)
|
|
965
|
+
case :file
|
|
966
|
+
match m
|
|
967
|
+
case [marks frames text carry outputs] [marks (pop frames) text carry (push-all [array-end object-end] outputs)]
|
|
968
|
+
case _ m
|
|
969
|
+
|
|
970
|
+
def proto-transduce-open [m rule]
|
|
971
|
+
match m
|
|
972
|
+
case [marks frames text carry outputs]
|
|
973
|
+
match carry
|
|
974
|
+
case missing
|
|
975
|
+
match (proto-transduce-fresh m rule)
|
|
976
|
+
case [opened mark]
|
|
977
|
+
let [read (proto-transduce-tokens opened rule)]
|
|
978
|
+
match read
|
|
979
|
+
case [ms fs t c os]
|
|
980
|
+
match (proto-transduce-replaced rule)
|
|
981
|
+
case true [ms fs t mark os]
|
|
982
|
+
case _ [(push mark ms) fs t missing os]
|
|
983
|
+
case mark
|
|
984
|
+
let [read (proto-transduce-tokens [marks frames text missing outputs] rule)]
|
|
985
|
+
match read
|
|
986
|
+
case [ms fs t c os]
|
|
987
|
+
match (proto-transduce-replaced rule)
|
|
988
|
+
case true [ms fs t mark os]
|
|
989
|
+
case _ [(push mark ms) fs t missing os]
|
|
990
|
+
|
|
991
|
+
def proto-transduce-close [m rule]
|
|
992
|
+
match m
|
|
993
|
+
case [marks frames text carry outputs]
|
|
994
|
+
let [mark (top marks)]
|
|
995
|
+
let [read (proto-transduce-tokens [(pop marks) frames text carry outputs] rule)]
|
|
996
|
+
match (proto-transduce-replaced rule)
|
|
997
|
+
case true
|
|
998
|
+
match read
|
|
999
|
+
case [ms fs t c os] [ms fs t mark os]
|
|
1000
|
+
case _ (proto-transduce-act read mark)
|
|
1001
|
+
|
|
1002
|
+
def proto-transduce-step [state pass]
|
|
1003
|
+
match state
|
|
1004
|
+
case [started marks frames text carry]
|
|
1005
|
+
let [m [marks frames text carry []]]
|
|
1006
|
+
let [next (match pass (case (open rule) (proto-transduce-open m rule)) (case (close rule) (proto-transduce-close m rule)))]
|
|
1007
|
+
match next
|
|
1008
|
+
case [ms fs t c outputs] (transition [true ms fs t c] outputs)
|
|
1009
|
+
|
|
1010
|
+
; A source that made no pass is the empty file.
|
|
1011
|
+
def proto-transduce-finish [state]
|
|
1012
|
+
match state
|
|
1013
|
+
case [false marks frames text carry] [object-start (key "type") (scalar "file") (key "body") array-start array-end object-end]
|
|
1014
|
+
case [true [] [] text carry] []
|
|
1015
|
+
case _ (fail :protocol-order "the rule passes ended inside a statement, which a file's never do")
|
|
1016
|
+
|
|
1017
|
+
def proto-transduce [input]
|
|
1018
|
+
as-events (scan-emit [false [] [] missing missing] proto-transduce-step proto-transduce-finish (parser-events input))
|
|
1159
1019
|
` })
|
|
1160
1020
|
});
|
|
1161
1021
|
function translate() {
|