@@ -265,10 +265,66 @@ KDL does not specify any restrictions on what implementations might do with
265
265
these annotations. They are free to ignore them, or use them to make decisions
266
266
about how to interpret a value.
267
267
268
- Additionally, the following type annotations MAY be recognized by KDL parsers
269
- and, if used, SHOULD interpret these types as follows :
268
+ # ## Suffix Type Annotation
269
+
270
+ When a ({{value}}) is a ({{number}}), it's possible to attach the type
271
+ annotation as a "suffix", instead of prepending it between `(` and `)`. This
272
+ makes it possible to, for example, write `10px`, `10.5%`, `512GiB`, etc., which
273
+ are equivalent to `(px)10`, `(%)5`, and `(GiB)512`, respectively.
274
+
275
+ An implementation that finds BOTH a parenthesized and a suffix
276
+ ({{type-annotation}}) on the same ({{number}}) MUST yield a syntax error.
277
+
278
+ Suffixes MUST BE plain ({{identifier-string}})s. No other ({{string}}) is
279
+ acceptable.
280
+
281
+ There are two kinds of ({{suffix-type-annotation}}) available :
282
+ ({{bare-suffix-type-annotation}})s and ({{explicit-suffix-type-annotation}}).
283
+
284
+ # ### Bare Suffix Type Annotation
285
+
286
+ When a ({{value}}) is a decimal ({{number}}) WITHOUT exponential syntax (`1e+5`
287
+ etc) (and ONLY a decimal), it's possible to attach the type annotation as a
288
+ suffix directly to the number, without any additional syntax.
289
+
290
+ They also come with some additional rules (like only being available for
291
+ decimals), in order to prevent potential ambiguity or footguns with the syntax.
292
+ This is generally acceptable, as type annotations in particular tend to be
293
+ application-defined and limited in scope, rather than arbitrary user data. In
294
+ designing this feature, it was determined that the value for various real-world
295
+ DSLs outweighed the complexity of the following rules.
296
+
297
+ As such, to remove ambiguity, the suffix ({{identifier-string}}) MUST NOT start
298
+ with any of the following patterns, all of which MUST yield syntax errors :
270
299
271
- # ## Reserved Type Annotations for Numbers Without Decimals:
300
+ * `.`, `,`, or `_`
301
+ * `[a-zA-Z][0-9_]` (to disambiguate all non-decimals, with breathing room)
302
+ * `[eE][+-]?[0-9]` (to disambiguate exponentials)
303
+ * `[xX][a-fA-F]` (to disambiguate hexadecimals)
304
+
305
+ All other ({{identifier-string}})s can be safely appended to decimal numbers, so
306
+ long as the decimal does not include an exponential component.
307
+
308
+ If the desired suffix would violate any of the above rules, either regular
309
+ parenthetical ({{type-annotation}})s, or ({{explicit-suffix-type-annotation}})s
310
+ may be used.
311
+
312
+ # ### Explicit Suffix Type Annotation
313
+
314
+ Any ({{number}}) may have a `#` attached to it, followed by any valid
315
+ ({{identifier-string}}). This is an explicit ({{suffix-type-annotation}}) syntax
316
+ without any of the relatively complex requirements of
317
+ ({{bare-suffix-type-annotation}}), which can be a useful escape hatch. For
318
+ example : ` 10.0#u8` is invalid syntax without the `#` prefix.
319
+
320
+ Note again that, unlike ({{bare-suffix-type-annotation}})s, Explicit Suffixes
321
+ may be used with ALL ({{number}}) formats (hexadecimal, decimal, octal, and
322
+ binary). For example, `0x1234#u16` is valid.
323
+
324
+ # ## Reserved Type Annotations for Numbers Without Decimals
325
+
326
+ Additionally, the following type annotations MAY be recognized by KDL parsers
327
+ and, if used, SHOULD interpret these types as follows.
272
328
273
329
Signed integers of various sizes (the number is the bit size) :
274
330
@@ -335,6 +391,7 @@ IEEE 754-2008 decimal floating point numbers
335
391
336
392
~~~kdl
337
393
node (u8)123
394
+ node 123#i64
338
395
node prop=(regex).*
339
396
(published)date "1970-01-01"
340
397
(contributor)person name="Foo McBar"
@@ -1013,12 +1070,26 @@ multi-line-raw-string-body :=
1013
1070
// Numbers
1014
1071
number := keyword-number | hex | octal | binary | decimal
1015
1072
1016
- decimal := sign? integer ('.' integer)? exponent?
1073
+ decimal := sign? integer ('.' integer)? (
1074
+ // NOTE : This grammar does not explicitly guard against having both
1075
+ // parenthesized and type suffixes.
1076
+ bare-type-suffix |
1077
+ explicit-type-suffix |
1078
+ (exponent explicit-type-suffix?)
1079
+ )?
1017
1080
exponent := ('e' | 'E') sign? integer
1018
1081
integer := digit (digit | '_')*
1019
1082
digit := [0-9]
1020
1083
sign := '+' | '-'
1021
1084
1085
+ bare-type-suffix := bare-type-suffix-initial identifier-char*
1086
+ bare-type-suffix-initial := identifier-char
1087
+ - ' .' - ',' - '_'
1088
+ - ([a-zA-Z] [0-9_])
1089
+ - (('e' | 'E') sign? digit)
1090
+ - (('x' | 'X') [a-fA-F])
1091
+ explicit-type-suffix := '#' identifier-string
1092
+
1022
1093
hex := sign? '0x' hex-digit (hex-digit | '_')*
1023
1094
octal := sign? '0o' [0-7] [0-7_]*
1024
1095
binary := sign? '0b' ('0' | '1') ('0' | '1' | '_')*
0 commit comments