diff --git a/implementations/javascript/packages/schema/src/meta.ts b/implementations/javascript/packages/schema/src/meta.ts
index acae08f..8d45e21 100644
--- a/implementations/javascript/packages/schema/src/meta.ts
+++ b/implementations/javascript/packages/schema/src/meta.ts
@@ -95,7 +95,6 @@ export function anonymousSimplePattern(p: M.SimplePattern): M.NamedPattern {
export function namelike(x: Input): string | undefined {
if (typeof x === 'string') return x;
if (typeof x === 'symbol') return x.description!;
- if (typeof x === 'number') return '' + x;
- if (typeof x === 'boolean') return '' + x;
+ if (typeof x === 'boolean') return x ? 'true' : 'false';
return void 0;
}
diff --git a/implementations/javascript/packages/schema/src/reader.ts b/implementations/javascript/packages/schema/src/reader.ts
index 7017ff7..ae66eb2 100644
--- a/implementations/javascript/packages/schema/src/reader.ts
+++ b/implementations/javascript/packages/schema/src/reader.ts
@@ -161,7 +161,12 @@ function parseDefinition(name: symbol, pos: Position | null, body: Array)
p.value._variant === 'lit')
{
const s = M.namelike(p.value.value);
- if (s !== void 0) return M.NamedAlternative({ variantLabel: s, pattern: p });
+ if (s !== void 0) {
+ if (M.isValidToken(s)) {
+ return M.NamedAlternative({ variantLabel: s, pattern: p });
+ }
+ throw new SchemaSyntaxError(preserves`Invalid name ${s} inferred for alternative: ${input}`, pos);
+ }
}
throw new SchemaSyntaxError(preserves`Name missing for alternative: ${input}`, pos);
}
@@ -338,11 +343,11 @@ function parsePattern(name: symbol, body0: Array): Pattern {
return (b: Input) => {
let name = findName(b);
if (name === false) {
- if (literalName !== void 0 &&
- typeof literalName === 'symbol' &&
- M.isValidToken(literalName.description!))
- {
- name = literalName;
+ if (literalName !== void 0) {
+ const s = M.namelike(literalName);
+ if (s !== void 0 && M.isValidToken(s)) {
+ name = Symbol.for(s);
+ }
}
}
if (name === false) {
diff --git a/implementations/racket/preserves/preserves-schema/reader.rkt b/implementations/racket/preserves/preserves-schema/reader.rkt
index ba9101a..2ecffcf 100644
--- a/implementations/racket/preserves/preserves-schema/reader.rkt
+++ b/implementations/racket/preserves/preserves-schema/reader.rkt
@@ -80,9 +80,8 @@
(define (namelike v)
(match v
- [(? string? s) (string->symbol s)]
[(? symbol? s) s]
- [(? number? n) (string->symbol (number->string n))]
+ [(? string? s) (string->symbol s)]
[(? boolean? b) (if b 'true 'false)]
[_ #f]))
@@ -194,9 +193,9 @@
values
(lambda () (error 'parse-simple-dsl "Compound patterns not accepted here: ~a" (input->string stx)))))
- (define ((maybe-named* knamed kanonymous recur [literal-name #f]) b)
+ (define ((maybe-named* knamed kanonymous recur [literal-name '#:none]) b)
(define n (or (find-name b)
- (and (valid-id? literal-name) literal-name)))
+ (let ((n (namelike literal-name))) (and (valid-id? n) n))))
(if n
(let ((p (parse-simple-dsl
b
diff --git a/preserves-schema.md b/preserves-schema.md
index e4a20fb..c616533 100644
--- a/preserves-schema.md
+++ b/preserves-schema.md
@@ -4,9 +4,11 @@ title: "Preserves Schema"
---
Tony Garnock-Jones
-October 2023. Version 0.3.3.
+October 2023. Version 0.3.4.
[abnf]: https://tools.ietf.org/html/rfc7405
+ [identifierlike]: #sufficiently-identifierlike-values
+ [valid identifier]: #identifiers-and-capitalization-conventions
This document proposes a Schema language for the
[Preserves data model](./preserves.html).
@@ -210,8 +212,9 @@ a member of a tagged union type).
A variant name can either be given explicitly as `@name` or
inferred.[^variant-names-unlike-binding-names] It can only be inferred
from the label of a record pattern, from the name of a reference to
-another definition, or from the text of a "sufficiently identifierlike"
-literal pattern - one that matches a string, symbol, number or boolean:
+another definition, or from the text of a "[sufficiently
+identifierlike][identifierlike]" literal pattern - one that matches a
+string, symbol or boolean:
AltPattern = "@" id Pattern
/ "<" id PatternSequence ">"
@@ -405,8 +408,10 @@ fixed-position patterns.
A dictionary pattern matches specific literal keys in an input
dictionary. If no explicit name is given for a particular
-`NamedSimplePattern`, but the key for the pattern is a symbol, then
-that symbol is used as the name for that dictionary entry.
+`NamedSimplePattern`, but the key for the pattern is "[sufficiently
+identifierlike][identifierlike]" (a string, symbol or boolean), then a
+symbol formed from that key is used as the name for that dictionary
+entry.
DictionaryPattern = "{" *(value ":" NamedSimplePattern) "}"
@@ -423,6 +428,29 @@ the given name in the overall record type for a definition. The type
of value contained in the field will correspond to the `Pattern` or
`SimplePattern` given.
+### "Sufficiently Identifierlike" Values
+
+In some places in a schema, names can be inferred from some nearby
+literal pattern element. In an `OrPattern`, variant names can be
+inferred; in a `DictionaryPattern`, names for dictionary entries can be
+inferred.
+
+The rules are simple: if the literal pattern would match a specific
+symbol or string, then that specific value is converted to a symbol and
+used as the name. If the pattern would match `#t`, the name will be
+`true`; if it would match `#f`, the name will be `false`.
+
+For example, in the following grammar, the names for the variants of
+`Example1` are the symbols `foo` and `bar` and `false`, and the names
+for the two fields in `Example2` are `example` and `|testing strings|`.
+Note that `|testing strings|` is a symbol whose name contains a space,
+which will be rejected because it is not a [valid identifier][].
+
+```preserves-schema
+Example1 = =foo / "bar" / #f .
+Example2 = { "testing strings": int, example: string } .
+```
+
## Semantics
Having covered concrete syntax, we now give semantics for the schema