Redo schema embedded value patterns to use embedded syntax and an interface schema

This commit is contained in:
Tony Garnock-Jones 2021-06-01 16:10:04 +02:00
parent b23acdaf5a
commit 8d96743d53
11 changed files with 115 additions and 65 deletions

View File

@ -74,7 +74,7 @@ export type Pattern = (
export type SimplePattern = (
{"_variant": "any"} |
{"_variant": "atom", "atomKind": AtomKind} |
{"_variant": "embedded"} |
{"_variant": "embedded", "interface": SimplePattern} |
{"_variant": "lit", "value": _val} |
{"_variant": "seqof", "pattern": SimplePattern} |
{"_variant": "setof", "pattern": SimplePattern} |
@ -179,7 +179,7 @@ export namespace Pattern {
export namespace SimplePattern {
export function any(): SimplePattern {return {"_variant": "any"};};
export function atom(atomKind: AtomKind): SimplePattern {return {"_variant": "atom", "atomKind": atomKind};};
export function embedded(): SimplePattern {return {"_variant": "embedded"};};
export function embedded($interface: SimplePattern): SimplePattern {return {"_variant": "embedded", "interface": $interface};};
export function lit(value: _val): SimplePattern {return {"_variant": "lit", "value": value};};
export function seqof(pattern: SimplePattern): SimplePattern {return {"_variant": "seqof", "pattern": pattern};};
export function setof(pattern: SimplePattern): SimplePattern {return {"_variant": "setof", "pattern": pattern};};
@ -562,56 +562,60 @@ export function toSimplePattern(v: _val): undefined | SimplePattern {
if (_.Record.isRecord<_val, _.Tuple<_val>, _embedded>(v)) {
let _tmp3: (null) | undefined;
_tmp3 = _.is(v.label, $embedded) ? null : void 0;
if (_tmp3 !== void 0) {result = {"_variant": "embedded"};};
if (_tmp3 !== void 0) {
let _tmp4: (SimplePattern) | undefined;
_tmp4 = toSimplePattern(v[0]);
if (_tmp4 !== void 0) {result = {"_variant": "embedded", "interface": _tmp4};};
};
};
if (result === void 0) {
if (_.Record.isRecord<_val, _.Tuple<_val>, _embedded>(v)) {
let _tmp4: (null) | undefined;
_tmp4 = _.is(v.label, $lit) ? null : void 0;
if (_tmp4 !== void 0) {
let _tmp5: (_val) | undefined;
_tmp5 = v[0];
if (_tmp5 !== void 0) {result = {"_variant": "lit", "value": _tmp5};};
let _tmp5: (null) | undefined;
_tmp5 = _.is(v.label, $lit) ? null : void 0;
if (_tmp5 !== void 0) {
let _tmp6: (_val) | undefined;
_tmp6 = v[0];
if (_tmp6 !== void 0) {result = {"_variant": "lit", "value": _tmp6};};
};
};
if (result === void 0) {
if (_.Record.isRecord<_val, _.Tuple<_val>, _embedded>(v)) {
let _tmp6: (null) | undefined;
_tmp6 = _.is(v.label, $seqof) ? null : void 0;
if (_tmp6 !== void 0) {
let _tmp7: (SimplePattern) | undefined;
_tmp7 = toSimplePattern(v[0]);
if (_tmp7 !== void 0) {result = {"_variant": "seqof", "pattern": _tmp7};};
let _tmp7: (null) | undefined;
_tmp7 = _.is(v.label, $seqof) ? null : void 0;
if (_tmp7 !== void 0) {
let _tmp8: (SimplePattern) | undefined;
_tmp8 = toSimplePattern(v[0]);
if (_tmp8 !== void 0) {result = {"_variant": "seqof", "pattern": _tmp8};};
};
};
if (result === void 0) {
if (_.Record.isRecord<_val, _.Tuple<_val>, _embedded>(v)) {
let _tmp8: (null) | undefined;
_tmp8 = _.is(v.label, $setof) ? null : void 0;
if (_tmp8 !== void 0) {
let _tmp9: (SimplePattern) | undefined;
_tmp9 = toSimplePattern(v[0]);
if (_tmp9 !== void 0) {result = {"_variant": "setof", "pattern": _tmp9};};
let _tmp9: (null) | undefined;
_tmp9 = _.is(v.label, $setof) ? null : void 0;
if (_tmp9 !== void 0) {
let _tmp10: (SimplePattern) | undefined;
_tmp10 = toSimplePattern(v[0]);
if (_tmp10 !== void 0) {result = {"_variant": "setof", "pattern": _tmp10};};
};
};
if (result === void 0) {
if (_.Record.isRecord<_val, _.Tuple<_val>, _embedded>(v)) {
let _tmp10: (null) | undefined;
_tmp10 = _.is(v.label, $dictof) ? null : void 0;
if (_tmp10 !== void 0) {
let _tmp11: (SimplePattern) | undefined;
_tmp11 = toSimplePattern(v[0]);
if (_tmp11 !== void 0) {
let _tmp12: (SimplePattern) | undefined;
_tmp12 = toSimplePattern(v[1]);
if (_tmp12 !== void 0) {result = {"_variant": "dictof", "key": _tmp11, "value": _tmp12};};
let _tmp11: (null) | undefined;
_tmp11 = _.is(v.label, $dictof) ? null : void 0;
if (_tmp11 !== void 0) {
let _tmp12: (SimplePattern) | undefined;
_tmp12 = toSimplePattern(v[0]);
if (_tmp12 !== void 0) {
let _tmp13: (SimplePattern) | undefined;
_tmp13 = toSimplePattern(v[1]);
if (_tmp13 !== void 0) {result = {"_variant": "dictof", "key": _tmp12, "value": _tmp13};};
};
};
};
if (result === void 0) {
let _tmp13: (Ref) | undefined;
_tmp13 = toRef(v);
if (_tmp13 !== void 0) {result = {"_variant": "Ref", "value": _tmp13};};
let _tmp14: (Ref) | undefined;
_tmp14 = toRef(v);
if (_tmp14 !== void 0) {result = {"_variant": "Ref", "value": _tmp14};};
};
};
};
@ -626,7 +630,7 @@ export function fromSimplePattern(_v: SimplePattern): _val {
switch (_v._variant) {
case "any": {return $any;};
case "atom": {return _.Record($atom, [fromAtomKind(_v["atomKind"])]);};
case "embedded": {return _.Record($embedded, []);};
case "embedded": {return _.Record($embedded, [fromSimplePattern(_v["interface"])]);};
case "lit": {return _.Record($lit, [_v["value"]]);};
case "seqof": {return _.Record($seqof, [fromSimplePattern(_v["pattern"])]);};
case "setof": {return _.Record($setof, [fromSimplePattern(_v["pattern"])]);};

View File

@ -1,4 +1,4 @@
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, ReaderOptions, stringify, isCompound, KeyedDictionary, annotate, annotations } from '@preserves/core';
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, stringify, isCompound, KeyedDictionary, annotate, annotations, isEmbedded, GenericEmbedded, genericEmbeddedTypeDecode } from '@preserves/core';
import { Input, Pattern, Schema, Definition, CompoundPattern, SimplePattern } from './meta';
import * as M from './meta';
import { SchemaSyntaxError } from './error';
@ -46,18 +46,19 @@ function invalidPattern(name: string, item: Input, pos: Position | null): never
}
export type SchemaReaderOptions = {
name?: string | Position;
readInclude?(includePath: string): string;
};
function _readSchema(source: string, options?: ReaderOptions<never>): Array<Input> {
return new Reader<any>(source, {
... options ?? {},
includeAnnotations: true
function _readSchema(source: string, options?: SchemaReaderOptions): Array<Input> {
return new Reader<GenericEmbedded>(source, {
name: options?.name,
includeAnnotations: true,
embeddedDecode: genericEmbeddedTypeDecode,
}).readToEnd();
}
export function readSchema(source: string,
options?: ReaderOptions<never> & SchemaReaderOptions): Schema
export function readSchema(source: string, options?: SchemaReaderOptions): Schema
{
const checked = checkSchema(parseSchema(_readSchema(source, options), options ?? {}));
if (checked.ok) return checked.schema;
@ -65,8 +66,7 @@ export function readSchema(source: string,
checked.problems.map(c => ' - ' + c).join('\n'));
}
export function parseSchema(toplevelTokens: Array<Input>,
options: ReaderOptions<never> & SchemaReaderOptions): Schema
export function parseSchema(toplevelTokens: Array<Input>, options: SchemaReaderOptions): Schema
{
let version: M.Version | undefined = void 0;
let embeddedType: M.EmbeddedTypeName = M.EmbeddedTypeName.$false();
@ -224,7 +224,6 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
case 'string': return ks(M.SimplePattern.atom(M.AtomKind.String()));
case 'bytes': return ks(M.SimplePattern.atom(M.AtomKind.ByteString()));
case 'symbol': return ks(M.SimplePattern.atom(M.AtomKind.Symbol()));
case 'embedded': return ks(M.SimplePattern.embedded());
default: return ks((str[0] === '=')
? M.SimplePattern.lit(Symbol.for(str.slice(1)))
: M.SimplePattern.Ref(parseRef(str, pos)));
@ -259,6 +258,8 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
return ks(M.SimplePattern.dictof({ key: walkSimple(kp), value: walkSimple(vp) }));
} else if (isCompound(item)) {
return kf();
} else if (isEmbedded(item)) {
return ks(M.SimplePattern.embedded(walkSimple(item.embeddedValue)));
} else {
return ks(M.SimplePattern.lit(strip(item)));
}

View File

@ -1,5 +1,8 @@
(module gen-schema racket/base
(provide (all-defined-out))
(provide (except-out (all-defined-out) :parse-embedded :embedded->preserves)
(rename-out
(:parse-embedded :parse-embedded:gen-schema)
(:embedded->preserves :embedded->preserves:gen-schema)))
(define :parse-embedded values)
(define :embedded->preserves values)
(require preserves)
@ -62,7 +65,7 @@
(struct SimplePattern-setof (pattern) #:prefab)
(struct SimplePattern-seqof (pattern) #:prefab)
(struct SimplePattern-lit (value) #:prefab)
(struct SimplePattern-embedded () #:prefab)
(struct SimplePattern-embedded (interface) #:prefab)
(struct SimplePattern-atom (atomKind) #:prefab)
(struct SimplePattern-any () #:prefab)
(define (SimplePattern? p)
@ -338,7 +341,12 @@
'atom
(list (app parse-AtomKind (and $atomKind (not (== eof)))))))
(SimplePattern-atom $atomKind))
((and dest (record 'embedded (list))) (SimplePattern-embedded))
((and dest
(record
'embedded
(list
(app parse-SimplePattern (and $interface (not (== eof)))))))
(SimplePattern-embedded $interface))
((and dest (record 'lit (list $value))) (SimplePattern-lit $value))
((and dest
(record
@ -507,7 +515,8 @@
((SimplePattern-any) 'any)
((SimplePattern-atom $atomKind)
(record 'atom (list (AtomKind->preserves $atomKind))))
((SimplePattern-embedded) (record 'embedded (list)))
((SimplePattern-embedded $interface)
(record 'embedded (list (SimplePattern->preserves $interface))))
((SimplePattern-lit $value) (record 'lit (list $value)))
((SimplePattern-seqof $pattern)
(record 'seqof (list (SimplePattern->preserves $pattern))))

View File

@ -63,7 +63,7 @@
[(AtomKind-String) 'string?]
[(AtomKind-ByteString) 'bytes?]
[(AtomKind-Symbol) 'symbol?])))]
[(SimplePattern-embedded)
[(SimplePattern-embedded _interface)
`(embedded (app :parse-embedded ,(maybe-dest dest-pat-stx `(not (== eof)))))]
[(SimplePattern-lit v) (maybe-dest dest-pat-stx (literal->pattern v))]
[(SimplePattern-seqof variable-pat)

View File

@ -121,7 +121,6 @@
['string (ks (SimplePattern-atom (AtomKind-String)))]
['bytes (ks (SimplePattern-atom (AtomKind-ByteString)))]
['symbol (ks (SimplePattern-atom (AtomKind-Symbol)))]
['embedded (ks (SimplePattern-embedded))]
[(? symbol? sym)
(define str (symbol->string sym))
(if (and (> (string-length str) 0) (string=? (substring str 0 1) "="))
@ -138,6 +137,7 @@
(ks (SimplePattern-setof (walk-simple (car (set->list s)))))]
[(hash-table ((peel-annotations '...) (peel-annotations '...)) (kp vp))
(ks (SimplePattern-dictof (walk-simple kp) (walk-simple vp)))]
[(embedded interface-pat) (ks (SimplePattern-embedded (walk-simple interface-pat)))]
[(or (? list?) (? set?) (? dict?) (? record?)) (kf)]
[(strip-annotations v) (ks (SimplePattern-lit v))]))

View File

@ -41,8 +41,8 @@ SimplePattern =
; special builtins: bool, float, double, int, string, bytes, symbol
/ <atom @atomKind AtomKind>
; matches an embedded value in the input: embedded
/ <embedded>
; matches an embedded value in the input: #!p
/ <embedded @interface SimplePattern>
; =symbol, <<lit> any>, or plain non-symbol atom
/ <lit @value any>

View File

@ -78,7 +78,7 @@
(match (unwrap p)
[(SimplePattern-any) (ty-value)]
[(SimplePattern-atom _atomKind) (ty-value)]
[(SimplePattern-embedded) (ty-value)]
[(SimplePattern-embedded _interface) (ty-value)]
[(SimplePattern-lit _value) (ty-unit)]
[(SimplePattern-seqof pat) (ty-array (pattern-ty pat))]
[(SimplePattern-setof pat) (ty-set (pattern-ty pat))]

View File

@ -48,7 +48,7 @@
[(NamedSimplePattern_ n p) (pattern->unparser p (escape n))]
[(SimplePattern-any) src-stx]
[(SimplePattern-atom _) src-stx]
[(SimplePattern-embedded) `(embedded (:embedded->preserves ,src-stx))]
[(SimplePattern-embedded _interface) `(embedded (:embedded->preserves ,src-stx))]
[(SimplePattern-lit v) `',v]
[(SimplePattern-seqof variable-pat)
`(for/list [(item (in-list ,src-stx))] ,(pattern->unparser variable-pat 'item))]

View File

@ -225,10 +225,12 @@ Specifying the name of a kind of `Atom` matches that kind of atom:
AtomKindPattern = "bool" / "float" / "double" / "int" / "string" / "bytes" / "symbol"
Specifying `embedded` matches an `Embedded` value, following the
schema-wide `embeddedType`, if any:
Embedded input `Value`s are matched with embedded patterns. The
portion under the `#!` prefix is the *interface* schema for the
embedded value.[^interface-schema] The result of a match is an
instance of the schema-wide `embeddedType`, if one is supplied.
EmbeddedPattern = "embedded"
EmbeddedPattern = "#!" SimplePattern
A literal pattern may be expressed in any of three ways: non-symbol
atoms stand for themselves directly; symbols, prefixed with an equal
@ -256,6 +258,18 @@ Periods "`.`" in such symbols are special:
- `Name` refers to the definition named `Name` in the current schema.
- `Mod.Submod.Name` refers to definition `Name` in `Mod.Submod`, some other schema in the bundle.
[^interface-schema]: Embedded patterns are experimental. One
interpretation is that an embedded value denotes a reference to
some stateful actor in a potentially-distributed system, and that
the interface schema associated with an embedded value describes
the messages that may be sent to that actor.
**Examples.** `#!any` may denote a reference to an Actor able to
receive any value as a message; `#!#t`, a reference to an Actor
expecting *only* the "true" message; `#!Session`, a reference to
an Actor expecting any message matching a schema defined as
`Session` in this file.
#### Compound patterns
CompoundPattern = RecordPattern
@ -368,8 +382,8 @@ Simple patterns are as described above:
; special builtins: bool, float, double, int, string, bytes, symbol
/ <atom @atomKind AtomKind>
; matches an embedded value in the input: embedded
/ <embedded>
; matches an embedded value in the input: #!p
/ <embedded @interface SimplePattern>
; =symbol, <<lit> any>, or plain non-symbol atom
/ <lit @value any>
@ -515,7 +529,7 @@ metaschema.
SimplePattern: <or [
["any", <lit any>],
["atom", <rec <lit atom> <tuple [<named atomKind <ref [] AtomKind>>]>>],
["embedded", <rec <lit embedded> <tuple []>>],
["embedded", <rec <lit embedded> <tuple [<named interface <ref [] SimplePattern>>]>>],
["lit", <rec <lit lit> <tuple [<named value any>]>>],
["seqof", <rec <lit seqof> <tuple [<named pattern <ref [] SimplePattern>>]>>],
["setof", <rec <lit setof> <tuple [<named pattern <ref [] SimplePattern>>]>>],
@ -595,7 +609,7 @@ definitions for the metaschema.
export type SimplePattern = (
{"_variant": "any"} |
{"_variant": "atom", "atomKind": AtomKind} |
{"_variant": "embedded"} |
{"_variant": "embedded", "interface": SimplePattern} |
{"_variant": "lit", "value": _val} |
{"_variant": "seqof", "pattern": SimplePattern} |
{"_variant": "setof", "pattern": SimplePattern} |
@ -690,7 +704,7 @@ definitions for the metaschema.
(struct SimplePattern-setof (pattern) #:prefab)
(struct SimplePattern-seqof (pattern) #:prefab)
(struct SimplePattern-lit (value) #:prefab)
(struct SimplePattern-embedded () #:prefab)
(struct SimplePattern-embedded (interface) #:prefab)
(struct SimplePattern-atom (atomKind) #:prefab)
(struct SimplePattern-any () #:prefab)
@ -708,5 +722,27 @@ definitions for the metaschema.
- Should `include` accept URLs, to be able to retrieve schema from
the web?
- It'd be nice to firm up the interpretation of embedded interface
schemas. I have in mind something like the
[higher-order contracts of Dimoulas](https://www2.ccs.neu.edu/racket/pubs/dissertation-dimoulas.pdf).
Essentially, a schema *is* a contract, and embedded
pointers-to-behaviour are like closures/channels/objects/etc, which
demand higher-order contracts. Future work could pin this down
further; also, consideration of *dependent* schemas (analogous to
dependent contracts) could be of interest.
**Example.** In the following fragment, `#!Session` is the handle a
connected user uses to interact with a chatroom. In the
implementation, `Says` messages are dropped if their `who` doesn't
match the `uid` supplied in the `Join` assertion. It'd be nice to
capture that using a dependent schema, passing in the specific
`uid` value to the `Session` constructor, something like
`#!(Session uid)`.
Join = <joinedUser @uid UserId @handle #!Session>.
Session = @observeSpeech <Observe =says @observer #!Says> / Says .
Says = <says @who UserId @what string>.
<!-- Heading to visually offset the footnotes from the main document: -->
## Notes

View File

@ -5,4 +5,4 @@ ByteString
ByteString„„µ±Symbol´³lit³Symbol„„„„³
Definition´³orµµ±or´³rec´³lit³or„´³tupleµ´³tuple*µ´³named³pattern0´³refµ„³NamedAlternative„„´³named³pattern1´³refµ„³NamedAlternative„„„´³named³patternN´³seqof´³refµ„³NamedAlternative„„„„„„„„µ±and´³rec´³lit³and„´³tupleµ´³tuple*µ´³named³pattern0´³refµ„³ NamedPattern„„´³named³pattern1´³refµ„³ NamedPattern„„„´³named³patternN´³seqof´³refµ„³ NamedPattern„„„„„„„„µ±Pattern´³refµ„³Pattern„„„„³
ModulePath´³seqof´³atom³Symbol„„³ Definitions´³dictof´³atom³Symbol„´³refµ„³
Definition„„³ NamedPattern´³orµµ±named´³refµ„³NamedSimplePattern_„„µ± anonymous´³refµ„³Pattern„„„„³ SimplePattern´³orµµ±any´³lit³any„„µ±atom´³rec´³lit³atom„´³tupleµ´³named³atomKind´³refµ„³AtomKind„„„„„„µ±embedded´³rec´³lit³embedded„´³tupleµ„„„„µ±lit´³rec´³lit³lit„´³tupleµ´³named³value³any„„„„„µ±seqof´³rec´³lit³seqof„´³tupleµ´³named³pattern´³refµ„³ SimplePattern„„„„„„µ±setof´³rec´³lit³setof„´³tupleµ´³named³pattern´³refµ„³ SimplePattern„„„„„„µ±dictof´³rec´³lit³dictof„´³tupleµ´³named³key´³refµ„³ SimplePattern„„´³named³value´³refµ„³ SimplePattern„„„„„„µ±Ref´³refµ„³Ref„„„„³CompoundPattern´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label´³refµ„³ NamedPattern„„´³named³fields´³refµ„³ NamedPattern„„„„„„µ±tuple´³rec´³lit³tuple„´³tupleµ´³named³patterns´³seqof´³refµ„³ NamedPattern„„„„„„„µ±tuple*´³rec´³lit³tuple*„´³tupleµ´³named³fixed´³seqof´³refµ„³ NamedPattern„„„´³named³variable´³refµ„³NamedSimplePattern„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³refµ„³DictionaryEntries„„„„„„„„³EmbeddedTypeName´³orµµ±Ref´³refµ„³Ref„„µ±false´³lit€„„„„³NamedAlternative´³tupleµ´³named³ variantLabel´³atom³String„„´³named³pattern´³refµ„³Pattern„„„„³DictionaryEntries´³dictof³any´³refµ„³NamedSimplePattern„„³NamedSimplePattern´³orµµ±named´³refµ„³NamedSimplePattern_„„µ± anonymous´³refµ„³ SimplePattern„„„„³NamedSimplePattern_´³rec´³lit³named„´³tupleµ´³named³name´³atom³Symbol„„´³named³pattern´³refµ„³ SimplePattern„„„„„„³ embeddedType€„„
Definition„„³ NamedPattern´³orµµ±named´³refµ„³NamedSimplePattern_„„µ± anonymous´³refµ„³Pattern„„„„³ SimplePattern´³orµµ±any´³lit³any„„µ±atom´³rec´³lit³atom„´³tupleµ´³named³atomKind´³refµ„³AtomKind„„„„„„µ±embedded´³rec´³lit³embedded„´³tupleµ´³named³ interface´³refµ„³ SimplePattern„„„„„„µ±lit´³rec´³lit³lit„´³tupleµ´³named³value³any„„„„„µ±seqof´³rec´³lit³seqof„´³tupleµ´³named³pattern´³refµ„³ SimplePattern„„„„„„µ±setof´³rec´³lit³setof„´³tupleµ´³named³pattern´³refµ„³ SimplePattern„„„„„„µ±dictof´³rec´³lit³dictof„´³tupleµ´³named³key´³refµ„³ SimplePattern„„´³named³value´³refµ„³ SimplePattern„„„„„„µ±Ref´³refµ„³Ref„„„„³CompoundPattern´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label´³refµ„³ NamedPattern„„´³named³fields´³refµ„³ NamedPattern„„„„„„µ±tuple´³rec´³lit³tuple„´³tupleµ´³named³patterns´³seqof´³refµ„³ NamedPattern„„„„„„„µ±tuple*´³rec´³lit³tuple*„´³tupleµ´³named³fixed´³seqof´³refµ„³ NamedPattern„„„´³named³variable´³refµ„³NamedSimplePattern„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³refµ„³DictionaryEntries„„„„„„„„³EmbeddedTypeName´³orµµ±Ref´³refµ„³Ref„„µ±false´³lit€„„„„³NamedAlternative´³tupleµ´³named³ variantLabel´³atom³String„„´³named³pattern´³refµ„³Pattern„„„„³DictionaryEntries´³dictof³any´³refµ„³NamedSimplePattern„„³NamedSimplePattern´³orµµ±named´³refµ„³NamedSimplePattern_„„µ± anonymous´³refµ„³ SimplePattern„„„„³NamedSimplePattern_´³rec´³lit³named„´³tupleµ´³named³name´³atom³Symbol„„´³named³pattern´³refµ„³ SimplePattern„„„„„„³ embeddedType€„„

View File

@ -41,8 +41,8 @@ SimplePattern =
; special builtins: bool, float, double, int, string, bytes, symbol
/ <atom @atomKind AtomKind>
; matches an embedded value in the input: embedded
/ <embedded>
; matches an embedded value in the input: #!p
/ <embedded @interface SimplePattern>
; =symbol, <<lit> any>, or plain non-symbol atom
/ <lit @value any>