Convert P-expressions to preserves values

This commit is contained in:
Tony Garnock-Jones 2024-05-02 21:26:48 +02:00
parent dc61963e16
commit 64c1090938
2 changed files with 48 additions and 10 deletions

View File

@ -1,18 +1,26 @@
// Preserves-Expressions. https://preserves.dev/preserves-expressions.html // Preserves-Expressions. https://preserves.dev/preserves-expressions.html
import { ReaderBase } from './reader'; import { ReaderBase } from './reader';
import { Atom } from './values'; import { Atom, Value } from './values';
import { Position } from './annotated'; import { Position, annotate } from './annotated';
import { Record as VRecord } from './record';
import { GenericEmbedded } from './embedded';
import { fromJS } from './fromjs';
export type Expr = SimpleExpr | Punct; export type Expr = SimpleExpr | Punct;
export type SimpleExpr = Atom | Compound | Embedded; export type SimpleExpr = Atom | Compound | Embedded;
export class Punct { export class Punct {
constructor(public text: string) {} constructor(public text: string) {}
__as_preserve__(): Value { return VRecord(Symbol.for('p'), [Symbol.for(this.text)]); }
} }
export class Embedded { export class Embedded {
constructor(public expr: SimpleExpr, public annotations?: Annotations) {} constructor(public expr: SimpleExpr, public annotations?: Annotations) {}
__as_preserve__(): Value {
const v = fromJS(this.expr);
return new GenericEmbedded(this.annotations?.wrap(v) ?? v);
}
} }
export class BaseCompound<I> { export class BaseCompound<I> {
@ -33,36 +41,65 @@ export class BaseCompound<I> {
} }
return this.annotations[index]; return this.annotations[index];
} }
preservesValues(): Value[] {
return this.exprs.map((p, i) => {
const v = fromJS(p);
if (this.annotations?.[i] !== void 0) {
return this.annotations[i].wrap(v);
} else {
return v;
}
});
}
} }
export class Document extends BaseCompound<Expr> {} export class Document extends BaseCompound<Expr> {
__as_preserve__(): Value {
return this.preservesValues();
}
}
export class Annotations extends BaseCompound<SimpleExpr> {} export class Annotations extends BaseCompound<SimpleExpr> {
wrap(v: Value): Value {
return annotate(v, ... this.preservesValues());
}
}
export type CompoundVariant = 'sequence' | 'record' | 'block' | 'group' | 'set'; export type CompoundVariant = 'sequence' | 'record' | 'block' | 'group' | 'set';
export abstract class Compound extends BaseCompound<Expr> { export abstract class Compound extends BaseCompound<Expr> {
abstract get variant(): CompoundVariant; abstract get variant(): CompoundVariant;
__as_preserve__(): Value {
const vs = this.preservesValues();
switch (this.variant) {
case 'sequence': return vs;
case 'record': return VRecord(Symbol.for('r'), vs);
case 'block': return VRecord(Symbol.for('b'), vs);
case 'group': return VRecord(Symbol.for('g'), vs);
case 'set': return VRecord(Symbol.for('s'), vs);
}
}
} }
export class Sequence extends Compound { export class Sequence extends Compound {
readonly variant = 'sequence'; get variant(): CompoundVariant { return 'sequence'; }
} }
export class Record extends Compound { export class Record extends Compound {
readonly variant = 'record'; get variant(): CompoundVariant { return 'record'; }
} }
export class Block extends Compound { export class Block extends Compound {
readonly variant = 'block'; get variant(): CompoundVariant { return 'block'; }
} }
export class Group extends Compound { export class Group extends Compound {
readonly variant = 'group'; get variant(): CompoundVariant { return 'group'; }
} }
export class Set extends Compound { export class Set extends Compound {
readonly variant = 'set'; get variant(): CompoundVariant { return 'set'; }
} }
export class Reader extends ReaderBase<never> { export class Reader extends ReaderBase<never> {

View File

@ -1,4 +1,4 @@
import { Pexpr } from '../src/index'; import { Pexpr, stringify } from '../src/index';
import './test-utils'; import './test-utils';
describe('basics', () => { describe('basics', () => {
@ -6,5 +6,6 @@ describe('basics', () => {
const r = new Pexpr.Reader('#!foo\n<bar {zot ::quux}, [a; b; c;]>'); const r = new Pexpr.Reader('#!foo\n<bar {zot ::quux}, [a; b; c;]>');
const d = r.nextDocument(); const d = r.nextDocument();
console.dir(d, { depth: null }); console.dir(d, { depth: null });
console.log(stringify(d, { indent: 4 }));
}); });
}); });