Allow "sufficiently identifierlike" values in dictionaries too

This commit is contained in:
Tony Garnock-Jones 2023-11-03 10:31:44 +01:00
parent 071566b1e1
commit 2e84614b3b
4 changed files with 48 additions and 17 deletions

View File

@ -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;
}

View File

@ -161,7 +161,12 @@ function parseDefinition(name: symbol, pos: Position | null, body: Array<Input>)
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<Input>): 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) {

View File

@ -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

View File

@ -4,9 +4,11 @@ title: "Preserves Schema"
---
Tony Garnock-Jones <tonyg@leastfixedpoint.com>
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