diff --git a/implementations/javascript/packages/schema/src/compiler.ts b/implementations/javascript/packages/schema/src/compiler.ts index d61f040..8d82244 100644 --- a/implementations/javascript/packages/schema/src/compiler.ts +++ b/implementations/javascript/packages/schema/src/compiler.ts @@ -3,8 +3,7 @@ import * as M from "./meta"; import { CompilerOptions, ModuleContext } from "./compiler/context"; import { block, brackets, Formatter, Item, parens, seq } from "./compiler/block"; import { typeForDefinition } from "./compiler/gentype"; -// import { decoderFor } from "./compiler/decoder"; -import { converterForDefinition } from "./compiler/genconverter"; +import { converterForDefinition, converterForSimple } from "./compiler/genconverter"; import { EMPTY_TYPE, renderType } from "./compiler/type"; import { genConstructor } from "./compiler/genctor"; @@ -20,13 +19,13 @@ export function compile(env: M.Environment, schema: M.Schema, options: CompilerO mod.defineType(`export type _val = _.Value<_ptr>;`); mod.defineFunction(ctx => - seq(`export const _decodePtr = `, + seq(`export const _toPtr = `, (pointerName._variant === 'false' ? '() => { throw new _.DecodeError("Pointers forbidden"); }' - : seq(`(d: _.TypedDecoder<_ptr>) => `, ctx.block(() => [ - seq(`let result`), - seq(`/* TODO */`), - // ... decoderFor(ctx, pointerName, 'result'), + : seq(`(v: _val) => `, ctx.block(() => [ + seq(`let result: undefined | _ptr`), + ... converterForSimple( + ctx, M.SimplePattern.Ref(pointerName.value), 'v', 'result'), seq(`return result`)]))), `;`)); @@ -66,14 +65,6 @@ export function compile(env: M.Environment, schema: M.Schema, options: CompilerO ctx.block(() => [seq(`let result: undefined | `, name.description!), ... converterForDefinition(ctx, def, 'v', 'result'), seq(`return result`)]))); - - // mod.defineFunction(ctx => - // seq(`export function decode${name.description!}`, - // `(d: _.TypedDecoder<_ptr>): undefined | `, name.description!, - // ctx.block(() => [seq(`let result: undefined | `, name.description!), - // seq(`/* TODO */`), - // // ... decoderFor(ctx, def, 'result'), - // seq(`return result`)]))); } const f = new Formatter(); diff --git a/implementations/javascript/packages/schema/src/compiler/genconverter.ts b/implementations/javascript/packages/schema/src/compiler/genconverter.ts index 4f2ac53..43631ea 100644 --- a/implementations/javascript/packages/schema/src/compiler/genconverter.ts +++ b/implementations/javascript/packages/schema/src/compiler/genconverter.ts @@ -173,7 +173,7 @@ function converterFor( } } -function converterForSimple( +export function converterForSimple( ctx: FunctionContext, p: M.SimplePattern, src: string, @@ -202,7 +202,7 @@ function converterForSimple( (_p) => [`${dest} = to${p.value.name.description!}(${src})`], (modId, modPath,_p) => { ctx.mod.imports.add([modId, modPath]); - return [`${dest} = ${modId}.decode${p.value.name.description!}(${src})`]; + return [`${dest} = ${modId}.to${p.value.name.description!}(${src})`]; }); case 'pointer': return [`${dest} = _toPtr(${src})`]; diff --git a/implementations/javascript/packages/schema/src/compiler/gendecoder.ts b/implementations/javascript/packages/schema/src/compiler/gendecoder.ts deleted file mode 100644 index 8878336..0000000 --- a/implementations/javascript/packages/schema/src/compiler/gendecoder.ts +++ /dev/null @@ -1,209 +0,0 @@ -/* -import { FunctionContext } from "./context"; -import * as M from '../meta'; -import { anglebrackets, block, brackets, Item, opseq, parens, seq } from "./block"; -import { typeFor } from './type'; -import { refPosition } from "../reader"; - -function decodeCompound(ctx: FunctionContext, - p: M.Pattern, - kFail: () => Item[], - kAcc: (temp: string) => Item[]): Item -{ - const t = ctx.gentemp(); - return seq(`while (!d.closeCompound()) `, ctx.block(() => [ - seq(`${t} = void 0`), - ... decoderFor(ctx, p, t), - seq(`if (${t} === void 0) `, block(... kFail(), seq(`break`))), - ... kAcc(t)])); -} - -function decoderForTuple(ctx: FunctionContext, - tuplePattern: M.Pattern, - ps: M.Pattern[], - dest: string, - recordFields: boolean, - variablePattern: M.Pattern | undefined): Item[] -{ - const temps = ctx.gentemps(ps.length); - - function loop(i: number): Item[] { - if (i < ps.length) { - return [... decoderFor(ctx, ps[i], temps[i]), - seq(`if (${temps[i]} !== void 0) `, ctx.block(() => loop(i + 1)))]; - } else { - if (variablePattern === void 0) { - return [seq(`if (d.closeCompound()) ${dest} = `, brackets(... temps), - ` as `, typeFor(ctx.mod, tuplePattern))]; - } else { - return [block( - seq(`let vN: `, typeFor(ctx.mod, tuplePattern), - ` | undefined = `, brackets(... temps)), - decodeCompound(ctx, - variablePattern, - () => [`vN = void 0`], - (t) => [`vN.push(${t})`]), - seq(`${dest} = vN`))]; - } - } - } - - return recordFields - ? loop(0) - : [seq(`if (d.openSequence()) `, ctx.block(() => loop(0)))]; -} - -export function decoderFor(ctx: FunctionContext, p: M.Definition, dest: string, recordFields = false): Item[] -{ - switch (p.label) { - case M.$atom: - switch (p[0]) { - case M.$Boolean: return [`${dest} = d.nextBoolean()`]; - case M.$Float: return [`${dest} = d.nextFloat()`]; - case M.$Double: return [`${dest} = d.nextDouble()`]; - case M.$SignedInteger: return [`${dest} = d.nextSignedInteger()`]; - case M.$String: return [`${dest} = d.nextString()`]; - case M.$ByteString: return [`${dest} = d.nextByteString()`]; - case M.$Symbol: return [`${dest} = d.nextSymbol()`]; - } - case M.$lit: { - let n: string; - switch (typeof p[0]) { - case 'boolean': n = `d.nextBoolean()`; break; - case 'string': n = `d.nextString()`; break; - case 'number': n = `d.nextSignedInteger()`; break; - case 'symbol': n = `d.nextSymbol()`; break; - default: n = `d.next()`; break; - } - return [`${dest} = _.asLiteral(${n}, ${ctx.mod.literal(p[0])})`]; - } - case M.$ref: - return M.lookup(refPosition(p), p, ctx.mod.env, - (_p) => [`${dest} = decode${p[1].description!}(d)`], - (p) => decoderFor(ctx, p, dest), - (modId, modPath,_p) => { - ctx.mod.imports.add([modId, modPath]); - return [`${dest} = ${modId}.decode${p[1].description!}(d)`]; - }); - case M.$or: { - const alts = p[0]; - const recs = alts.map(p => ctx.mod.derefPattern(p)); - if (recs.length > 1 && recs.every(pp => pp.label === M.$rec)) { - // Hoist the record check up. - // This is pretty hacky. If we lift the level of - // discourse a little, we can do this - // automatically and generically... - return [seq(`if (d.openRecord()) `, ctx.block(() => { - const label = ctx.gentemp(); - const mark = ctx.gentemp(); - function loop(i: number): Item[] { - const alt = recs[i]; - if (alt.label !== M.$rec) throw new Error("Internal error"); // avoid a cast - return [ - seq(`if (`, predicateFor(ctx, label, M.unname(alt[0])), `) `, ctx.block(() => { - const fs = ctx.gentemp(); - return [...decoderFor(ctx, M.unname(alt[1]), fs, true), - seq(`if (${fs} !== void 0) ${dest} = _.Record`, - anglebrackets(typeFor(ctx.mod, M.unname(alt[0])), - typeFor(ctx.mod, M.unname(alt[1]))), - parens(seq(label, ` as any`), - seq(fs, ` as any`)))]; - })), - ... (i < recs.length - 1) - ? [seq(`if (${dest} === void 0) `, - ctx.block(() => [`d.restoreMark(${mark})`, ... loop(i + 1)]))] - : [], - ]; - } - return [seq(`${label} = d.next()`), - seq(`${mark} = d.mark()`), - ... loop(0)]; - }))]; - } else { - switch (alts.length) { - case 0: return []; // assume dest is already void 0 - case 1: return decoderFor(ctx, alts[0][1], dest); - default: { - const mark = ctx.gentemp(); - function loop(i: number): Item[] { - return [ - ... decoderFor(ctx, alts[i][1], dest), - ... (i < alts.length - 1) - ? [seq(`if (${dest} === void 0) `, ctx.block(() => - [`d.restoreMark(${mark})`, ... loop(i + 1)]))] - : [], - ]; - } - return [`${mark} = d.mark()`, ... loop(0)]; - } - } - } - } - case M.$and: - switch (p[0].length) { - case 0: return [`${dest} = d.next()`]; - case 1: return decoderFor(ctx, M.unname(p[0][0]), dest); - default: { - const [pp0, ... ppN] = p[0]; - return [...decoderFor(ctx, M.unname(pp0), dest), - seq(`if (!`, opseq('true', ' && ', - ... ppN.map(pp => - predicateFor(ctx, dest, M.unname(pp)))), - `) ${dest} = void 0`)]; - } - } - case M.$pointer: - return [`${dest} = _decodePtr(d)`]; - case M.$rec: - // assume dest is already void 0 - return [seq(`if (d.openRecord()) `, ctx.block(() => { - const label = ctx.gentemp(); - return [...decoderFor(ctx, M.unname(p[0]), label), - seq(`if (${label} !== void 0) `, ctx.block(() => { - const fs = ctx.gentemp(); - return [...decoderFor(ctx, M.unname(p[1]), fs, true), - seq(`if (${fs} !== void 0) ${dest} = _.Record`, - anglebrackets(typeFor(ctx.mod, M.unname(p[0])), - typeFor(ctx.mod, M.unname(p[1]))), - parens(seq(label, ` as any`), - seq(fs, ` as any`)))]; - }))]; - }))]; - case M.$tuple: - // assume dest is already void 0 - return decoderForTuple(ctx, p, p[0].map(M.unname), dest, recordFields, void 0); - case M.$tuple_STAR_: - // assume dest is already void 0 - return decoderForTuple(ctx, p, p[0].map(M.unname), dest, recordFields, M.unname(p[1])); - case M.$setof: - // assume dest is already void 0 - return [seq(`if (d.openSet()) `, ctx.block(() => [ - seq(`let r: `, typeFor(ctx.mod, p), ` | undefined = new _.KeyedSet()`), - decodeCompound(ctx, - p[0], - () => [`r = void 0`], - (t) => [`r.add(${t})`]), - `${dest} = r`]))]; - case M.$dictof: - // assume dest is already void 0 - return [seq(`if (d.openDictionary()) `, ctx.block(() => [ - seq(`let r: `, typeFor(ctx.mod, p), ` | undefined = new _.KeyedDictionary()`), - seq(`while (!d.closeCompound()) `, ctx.block(() => [ - seq(`let K: undefined | `, typeFor(ctx.mod, p[0]), ` = void 0`), - ... decoderFor(ctx, p[0], 'K'), - seq(`if (K === void 0) { r = void 0; break; }`), - seq(`let V: undefined | `, typeFor(ctx.mod, p[1]), ` = void 0`), - ... decoderFor(ctx, p[1], 'V'), - seq(`if (V === void 0) { r = void 0; break; }`), - seq(`r.set(K, V)`)])), - seq(`${dest} = r`)]))]; - case M.$dict: - return [seq(`${dest} = d.next()`), - seq(`if (${dest} !== void 0 && !(`, predicateFor(ctx, dest, p), - `)) ${dest} = void 0`)]; - default: - ((_p: never) => {})(p); - throw new Error("Unreachable"); - } -} -*/ diff --git a/implementations/javascript/packages/schema/src/gen/schema.ts b/implementations/javascript/packages/schema/src/gen/schema.ts index a9c020f..d96dc13 100644 --- a/implementations/javascript/packages/schema/src/gen/schema.ts +++ b/implementations/javascript/packages/schema/src/gen/schema.ts @@ -106,7 +106,7 @@ export type Ref = {"module": ModulePath, "name": symbol}; export type ModulePath = Array; -export const _decodePtr = () => { throw new _.DecodeError("Pointers forbidden"); }; +export const _toPtr = () => { throw new _.DecodeError("Pointers forbidden"); }; export function Schema(version: Version, pointer: PointerName, definitions: Definitions): Schema {return {version, pointer, definitions};}