Improved field declaration parsing

This commit is contained in:
Tony Garnock-Jones 2021-01-15 14:22:44 +01:00
parent 71cde3daba
commit ed12c1c69c
3 changed files with 21 additions and 30 deletions

View File

@ -87,16 +87,22 @@ export const spawn: Pattern<SpawnStatement> & { headerExpr: Pattern<Expr> } =
}); });
export interface FieldDeclarationStatement extends FacetAction { export interface FieldDeclarationStatement extends FacetAction {
member: Expr; target: Expr;
expr?: Expr; property: { name: Identifier } | { expr: Expr };
init?: Expr;
} }
// Principal: Dataspace, but only for implementation reasons, so really Facet // Principal: Dataspace, but only for implementation reasons, so really Facet
export const fieldDeclarationStatement: Pattern<FieldDeclarationStatement> = export const fieldDeclarationStatement: Pattern<FieldDeclarationStatement> =
facetAction(o => seq(atom('field'), facetAction(o => {
bind(o, 'member', expr(atom('='))), const prop = alt(seq(atom('.'), map(identifier, name => o.property = {name})),
option(seq(atom('='), bind(o, 'expr', expr()))), seq(group('[', map(expr(), expr => o.property = {expr}))));
statementBoundary)); return seq(atom('field'),
bind(o, 'target', expr(seq(prop, alt(atom('='), statementBoundary)))),
prop,
option(seq(atom('='), bind(o, 'init', expr()))),
statementBoundary);
});
export interface AssertionEndpointStatement extends FacetAction { export interface AssertionEndpointStatement extends FacetAction {
isDynamic: boolean, isDynamic: boolean,

View File

@ -51,29 +51,13 @@ export function main(argv: string[]) {
expandFacetAction( expandFacetAction(
G.fieldDeclarationStatement, G.fieldDeclarationStatement,
s => { s => {
function isArrayProp(): [S.Substitution, S.Substitution] | null { const prop = ('name' in s.property)
if (s.member.length === 0) return null; ? [ { start: s.property.name.start,
const x = s.member[s.member.length - 1]; end: s.property.name.end,
if (!S.isGroup(x)) return null; type: S.TokenType.STRING,
if (x.start.text !== '[') return null; text: JSON.stringify(s.property.name.text) } ]
return [s.member.slice(0, s.member.length - 1), x.items]; : s.property.expr;
} return macro.template()`declareField(${s.target}, ${prop}, ${s.init ?? 'void 0'});`;
function isSimpleProp(): [S.Substitution, S.Substitution] | null {
if (s.member.length < 2) return null;
const r = S.value<G.Identifier>(o => S.seq(S.atom('.'), S.bind(o, 'value', G.identifier)))(
new ArrayList(s.member, s.member.length - 2));
if (r === null) return null;
const id = r[0];
return [s.member.slice(0, s.member.length - 2),
[ { start: id.start,
end: id.end,
type: S.TokenType.STRING,
text: JSON.stringify(id.text) } ]];
}
const [obj, prop] = isArrayProp()
?? isSimpleProp()
?? ["__SYNDICATE__.INVALID_PROPERTY_SYNTAX", "''"];
return macro.template()`declareField(${obj}, ${prop}, ${s.expr ?? 'void 0'});`;
}); });
expandFacetAction( expandFacetAction(
G.assertionEndpointStatement, G.assertionEndpointStatement,

View File

@ -11,7 +11,8 @@ export type Pattern<T> = (i: List<Item>) => PatternResult<T>;
export const noItems = new ArrayList<Item>([]); export const noItems = new ArrayList<Item>([]);
export const fail: Pattern<never> = _i => null; export const fail: Pattern<never> = _i => null;
export const succeed: Pattern<void> = i => [void 0, i]; export function succeed<T>(t: T): Pattern<T> { return i => [t, i]; }
export const discard: Pattern<void> = _i => [void 0, noItems]; export const discard: Pattern<void> = _i => [void 0, noItems];
export const rest: Pattern<Items> = i => [i.toArray(), noItems]; export const rest: Pattern<Items> = i => [i.toArray(), noItems];
export const end: Pattern<void> = i => atEnd(i) ? [void 0, noItems] : null; export const end: Pattern<void> = i => atEnd(i) ? [void 0, noItems] : null;