Factor out common constructor-building logic in interpreter
This commit is contained in:
parent
dc0ddf95dd
commit
1bd4a3cdb4
|
@ -78,6 +78,22 @@ export type Unparseable<V extends Embeddable> = TopParsed<V>;
|
|||
export type Unparser<V extends Embeddable> = (v: Parsed<V>) => Value<V>;
|
||||
export type UnparserCompound<V extends Embeddable> = (v: Bindings<V>) => Value<V>;
|
||||
|
||||
function attachSchema<V extends Embeddable>(
|
||||
schema: M.Schema<V>,
|
||||
name: symbol,
|
||||
f: (input: any) => Parsed<V>,
|
||||
variant?: symbol,
|
||||
): SingleConstructor<V> {
|
||||
const g = f as SingleConstructor<V>;
|
||||
g.schema = () => ({
|
||||
schema: fromJS(schema),
|
||||
imports: {}, // TODO
|
||||
definitionName: name,
|
||||
variant,
|
||||
});
|
||||
return g;
|
||||
}
|
||||
|
||||
export class SchemaInterpreter<V extends Embeddable> {
|
||||
activeModule: M.ModulePath = [];
|
||||
unparserCache: { [key: string]: [Unparser<V>] } = {};
|
||||
|
@ -135,83 +151,62 @@ export class SchemaInterpreter<V extends Embeddable> {
|
|||
return result;
|
||||
}
|
||||
|
||||
buildConstructor(
|
||||
modulePath: M.ModulePath,
|
||||
name: symbol,
|
||||
schema: M.Schema<V>,
|
||||
ty: H.Simple,
|
||||
variant?: symbol,
|
||||
): SingleConstructor<V> {
|
||||
const flatName = M.formatModulePath([
|
||||
... modulePath, name, ... (variant === void 0 ? [] : [variant])]);
|
||||
const mkBase = (variant === void 0)
|
||||
? () => ({})
|
||||
: () => ({ _variant: variant.description! });
|
||||
switch (ty._variant) {
|
||||
case 'Field': {
|
||||
const tmp =
|
||||
ty.value._variant === 'unit'
|
||||
? { [flatName]: () => this.makeTop(modulePath, name, mkBase()) }
|
||||
: (variant === void 0
|
||||
? { [flatName]: (value: any) => value }
|
||||
: { [flatName]: (value: any) => this.makeTop(
|
||||
modulePath, name, { ... mkBase(), value }) });
|
||||
return attachSchema(schema, name, tmp[flatName], variant);
|
||||
}
|
||||
case 'Record': {
|
||||
const rec = ty.value;
|
||||
if (rec.fields.length > 1) {
|
||||
const tmp = { [flatName]: (fields: Bindings<V>) =>
|
||||
this.makeTop(modulePath, name, { ... mkBase(), ... fields }) };
|
||||
return attachSchema(schema, name, tmp[flatName], variant);
|
||||
} else {
|
||||
const tmp = { [flatName]: (field: Parsed<V>) =>
|
||||
this.makeTop(modulePath, name, {
|
||||
... mkBase(),
|
||||
[M.jsId(rec.fields[0].name.description!)]: field,
|
||||
}) };
|
||||
return attachSchema(schema, name, tmp[flatName], variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
definitionConstructor(
|
||||
modulePath: M.ModulePath,
|
||||
name: symbol,
|
||||
): DefinitionConstructors<V> {
|
||||
return this._lookup(modulePath, name, (definition, schema): DefinitionConstructors<V> => {
|
||||
function attachSchema(
|
||||
f: (input: any) => Parsed<V>,
|
||||
variant?: symbol,
|
||||
): SingleConstructor<V> {
|
||||
const g = f as SingleConstructor<V>;
|
||||
g.schema = () => ({
|
||||
schema: fromJS(schema),
|
||||
imports: {}, // TODO
|
||||
definitionName: name,
|
||||
variant,
|
||||
});
|
||||
return g;
|
||||
}
|
||||
const ty = H.definitionType(definition);
|
||||
if (ty._variant === 'union') {
|
||||
const multiple: MultipleConstructors<V> = {};
|
||||
ty.variants.forEach(v => {
|
||||
const _variant = v.label.description!;
|
||||
const flatName = M.formatModulePath([... modulePath, name, v.label]);
|
||||
switch (v.type._variant) {
|
||||
case 'Field': {
|
||||
const tmp =
|
||||
v.type.value._variant === 'unit'
|
||||
? { [flatName]: () => this.makeTop(modulePath, name, { _variant }) }
|
||||
: { [flatName]: (value: any) => this.makeTop(modulePath, name, { _variant, value }) };
|
||||
multiple[M.jsId(_variant)] = attachSchema(tmp[flatName], v.label);
|
||||
break;
|
||||
}
|
||||
case 'Record': {
|
||||
const rec = v.type.value;
|
||||
if (rec.fields.length > 1) {
|
||||
const tmp = { [flatName]: (fields: Bindings<V>) =>
|
||||
this.makeTop(modulePath, name, { _variant, ... fields }) };
|
||||
multiple[M.jsId(_variant)] = attachSchema(tmp[flatName], v.label);
|
||||
} else {
|
||||
const tmp = { [flatName]: (field: Parsed<V>) =>
|
||||
this.makeTop(modulePath, name, {
|
||||
_variant,
|
||||
[M.jsId(rec.fields[0].name.description!)]: field,
|
||||
}) };
|
||||
multiple[M.jsId(_variant)] = attachSchema(tmp[flatName], v.label);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
multiple[M.jsId(v.label.description!)] = this.buildConstructor(
|
||||
modulePath, name, schema, v.type, v.label);
|
||||
});
|
||||
return multiple;
|
||||
} else {
|
||||
const flatName = M.formatModulePath([... modulePath, name]);
|
||||
switch (ty.value._variant) {
|
||||
case 'Field': {
|
||||
const tmp =
|
||||
ty.value.value._variant === 'unit'
|
||||
? { [flatName]: () => this.makeTop(modulePath, name, {}) }
|
||||
: { [flatName]: (value: any) => value };
|
||||
return attachSchema(tmp[flatName]);
|
||||
}
|
||||
case 'Record': {
|
||||
const rec = ty.value.value;
|
||||
if (rec.fields.length > 1) {
|
||||
const tmp = { [flatName]: (fields: Bindings<V>) =>
|
||||
this.makeTop(modulePath, name, fields) };
|
||||
return attachSchema(tmp[flatName]);
|
||||
} else {
|
||||
const tmp = { [flatName]: (field: Parsed<V>) =>
|
||||
this.makeTop(modulePath, name, {
|
||||
[M.jsId(rec.fields[0].name.description!)]: field,
|
||||
}) };
|
||||
return attachSchema(tmp[flatName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.buildConstructor(modulePath, name, schema, ty.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue