Skip to content

Commit

Permalink
refactor: ReceiverKind ast node (#1515)
Browse files Browse the repository at this point in the history
Co-authored-by: verytactical <186486509+verytactical@users.noreply.github.com>
  • Loading branch information
i582 and verytactical authored Jan 26, 2025
1 parent 3590a18 commit 24db1f9
Show file tree
Hide file tree
Showing 13 changed files with 659 additions and 476 deletions.
41 changes: 24 additions & 17 deletions src/ast/ast-printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ export const ppAstReceiver: Printer<A.AstReceiver> =
({ selector, statements }) =>
(c) =>
c.concat([
c.row(`${ppAstReceiverHeader(selector)} `),
c.row(`${ppAstReceiverKind(selector)} `),
ppStatementBlock(statements)(c),
]);

Expand Down Expand Up @@ -678,17 +678,18 @@ export const ppAstFunctionAttribute = (
}
};

export const ppAstReceiverHeader = makeVisitor<A.AstReceiverKind>()({
bounce: ({ param: { name, type } }) =>
`bounced(${ppAstId(name)}: ${ppAstType(type)})`,
"internal-simple": ({ param: { name, type } }) =>
`receive(${ppAstId(name)}: ${ppAstType(type)})`,
"external-simple": ({ param: { name, type } }) =>
`external(${ppAstId(name)}: ${ppAstType(type)})`,
"internal-fallback": () => `receive()`,
"external-fallback": () => `external()`,
"internal-comment": ({ comment: { value } }) => `receive("${value}")`,
"external-comment": ({ comment: { value } }) => `external("${value}")`,
const wrap = (prefix: string, body: string) => `${prefix}(${body})`;

export const ppReceiverSubKind = makeVisitor<A.AstReceiverSubKind>()({
simple: ({ param }) => typedParameter(param),
fallback: () => "",
comment: ({ comment }) => `"${comment.value}"`,
});

export const ppAstReceiverKind = makeVisitor<A.AstReceiverKind>()({
bounce: ({ param }) => wrap("bounced", typedParameter(param)),
internal: ({ subKind }) => wrap("receive", ppReceiverSubKind(subKind)),
external: ({ subKind }) => wrap("external", ppReceiverSubKind(subKind)),
});

export const ppAstFuncId = (func: A.AstFuncId): string => func.text;
Expand Down Expand Up @@ -825,11 +826,11 @@ export const ppAstStatementDestruct: Printer<A.AstStatementDestruct> =
);
};

export const ppTypedParameter: Printer<A.AstTypedParameter> =
({ name, type }) =>
(c) => {
return c.row(`${ppAstId(name)}: ${ppAstType(type)}`);
};
const typedParameter = ({ name, type }: A.AstTypedParameter) =>
`${ppAstId(name)}: ${ppAstType(type)}`;

export const ppTypedParameter: Printer<A.AstTypedParameter> = (param) => (c) =>
c.row(typedParameter(param));

export const ppAstStatementBlock: Printer<A.AstStatementBlock> =
({ statements }) =>
Expand Down Expand Up @@ -891,6 +892,12 @@ export const ppAstNode: Printer<A.AstNode> = makeVisitor<A.AstNode>()({
destruct_end: () => {
throw new Error("Not implemented");
},
simple: exprNode(ppReceiverSubKind),
fallback: exprNode(ppReceiverSubKind),
comment: exprNode(ppReceiverSubKind),
bounce: exprNode(ppAstReceiverKind),
internal: exprNode(ppAstReceiverKind),
external: exprNode(ppAstReceiverKind),

module: ppAstModule,
struct_decl: ppAstStruct,
Expand Down
76 changes: 49 additions & 27 deletions src/ast/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,33 +668,53 @@ export type AstTypedParameter = {
loc: SrcInfo;
};

export type AstReceiverSimple = {
kind: "simple";
param: AstTypedParameter;
id: number;
};

export type AstReceiverFallback = {
kind: "fallback";
id: number;
};

export type AstReceiverComment = {
kind: "comment";
comment: AstString;
id: number;
};

export type AstReceiverSubKind =
| AstReceiverSimple
| AstReceiverFallback
| AstReceiverComment;

export type AstReceiverInternal = {
kind: "internal";
subKind: AstReceiverSubKind;
id: number;
loc: SrcInfo;
};

export type AstReceiverExternal = {
kind: "external";
subKind: AstReceiverSubKind;
id: number;
loc: SrcInfo;
};

export type AstReceiverBounce = {
kind: "bounce";
param: AstTypedParameter;
id: number;
loc: SrcInfo;
};

export type AstReceiverKind =
| {
kind: "internal-simple";
param: AstTypedParameter;
}
| {
kind: "internal-fallback";
}
| {
kind: "internal-comment";
comment: AstString;
}
| {
kind: "bounce";
param: AstTypedParameter;
}
| {
kind: "external-simple";
param: AstTypedParameter;
}
| {
kind: "external-fallback";
}
| {
kind: "external-comment";
comment: AstString;
};
| AstReceiverInternal
| AstReceiverExternal
| AstReceiverBounce;

export type AstNode =
| AstFuncId
Expand All @@ -718,4 +738,6 @@ export type AstNode =
| AstReceiver
| AstImport
| AstConstantDef
| AstConstantDecl;
| AstConstantDecl
| AstReceiverKind
| AstReceiverSubKind;
41 changes: 23 additions & 18 deletions src/ast/compare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -849,26 +849,31 @@ export class AstComparator {
kind1: A.AstReceiverKind,
kind2: A.AstReceiverKind,
): boolean {
if (kind1.kind !== kind2.kind) {
return false;
}
if (
(kind1.kind === "internal-simple" &&
kind2.kind === "internal-simple") ||
(kind1.kind === "bounce" && kind2.kind === "bounce") ||
(kind1.kind === "external-simple" &&
kind2.kind === "external-simple")
) {
if (kind1.kind === "bounce" && kind2.kind === "bounce") {
return this.compare(kind1.param, kind2.param);
}
if (
(kind1.kind === "internal-comment" &&
kind2.kind === "internal-comment") ||
(kind1.kind === "external-comment" &&
kind2.kind === "external-comment")
) {
return this.compare(kind1.comment, kind2.comment);
if (kind1.kind === "internal" && kind2.kind === "internal") {
return this.compareReceiverSubKinds(kind1.subKind, kind2.subKind);
}
return true;
if (kind1.kind === "external" && kind2.kind === "external") {
return this.compareReceiverSubKinds(kind1.subKind, kind2.subKind);
}
return false;
}

private compareReceiverSubKinds(
subKind1: A.AstReceiverSubKind,
subKind2: A.AstReceiverSubKind,
): boolean {
if (subKind1.kind === "simple" && subKind2.kind === "simple") {
return this.compare(subKind1.param, subKind2.param);
}
if (subKind1.kind === "comment" && subKind2.kind === "comment") {
return this.compare(subKind1.comment, subKind2.comment);
}
if (subKind1.kind === "fallback" && subKind2.kind === "fallback") {
return true;
}
return false;
}
}
41 changes: 41 additions & 0 deletions src/ast/getAstSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,47 @@ export const getAstSchema = (
statements,
loc: toSrcInfo(loc),
}),
ReceiverSimple: (param: A.AstTypedParameter): A.AstReceiverSimple =>
createNode<A.AstReceiverSimple>({
kind: "simple",
param,
}),
ReceiverFallback: (): A.AstReceiverFallback =>
createNode<A.AstReceiverFallback>({
kind: "fallback",
}),
ReceiverComment: (comment: A.AstString): A.AstReceiverComment =>
createNode<A.AstReceiverComment>({
kind: "comment",
comment,
}),
ReceiverInternal: (
subKind: A.AstReceiverSubKind,
loc: Loc,
): A.AstReceiverInternal =>
createNode<A.AstReceiverInternal>({
kind: "internal",
subKind,
loc: toSrcInfo(loc),
}),
ReceiverExternal: (
subKind: A.AstReceiverSubKind,
loc: Loc,
): A.AstReceiverExternal =>
createNode<A.AstReceiverExternal>({
kind: "external",
subKind,
loc: toSrcInfo(loc),
}),
ReceiverBounce: (
param: A.AstTypedParameter,
loc: Loc,
): A.AstReceiverBounce =>
createNode<A.AstReceiverBounce>({
kind: "bounce",
param,
loc: toSrcInfo(loc),
}),
ContractInit: (
params: A.AstTypedParameter[],
statements: A.AstStatement[],
Expand Down
15 changes: 15 additions & 0 deletions src/ast/iterators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,21 @@ export function traverse(node: AstNode, callback: (node: AstNode) => void) {
traverse(e, callback);
});
break;
case "bounce":
traverse(node.param, callback);
break;
case "internal":
case "external":
traverse(node.subKind, callback);
break;
case "fallback":
break;
case "comment":
traverse(node.comment, callback);
break;
case "simple":
traverse(node.param, callback);
break;
case "contract_init":
node.params.forEach((e) => {
traverse(e, callback);
Expand Down
20 changes: 13 additions & 7 deletions src/grammar/next/__snapshots__/grammar.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -974,43 +974,49 @@ exports[`grammar should parse block-statements 1`] = `

exports[`grammar should parse case-35 1`] = `
{
"id": 7,
"id": 9,
"imports": [],
"items": [
{
"attributes": [],
"declarations": [
{
"id": 5,
"id": 7,
"kind": "receiver",
"loc": external() {
acceptMessage();
},
"selector": {
"kind": "external-fallback",
"id": 3,
"kind": "external",
"loc": external,
"subKind": {
"id": 2,
"kind": "fallback",
},
},
"statements": [
{
"expression": {
"args": [],
"function": {
"id": 2,
"id": 4,
"kind": "id",
"loc": acceptMessage,
"text": "acceptMessage",
},
"id": 3,
"id": 5,
"kind": "static_call",
"loc": acceptMessage(),
},
"id": 4,
"id": 6,
"kind": "statement_expression",
"loc": acceptMessage();,
},
],
},
],
"id": 6,
"id": 8,
"kind": "contract",
"loc": contract ReceiveTestContract {
external() {
Expand Down
4 changes: 2 additions & 2 deletions src/grammar/next/grammar.gg
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ FunctionAttribute = name:(

GetAttribute = "get" methodId:("(" @expression ")")?;

Receiver = type:receiverType "(" param:receiverParam ")" body:statements;
Receiver = type:ReceiverType "(" param:receiverParam ")" body:statements;
// "bounced" cannot be a reserved word because there a 'bounced' field in stdlib's 'Context' structure
receiverType = "bounced" / keyword<"receive"> / keyword<"external">;
ReceiverType = name:("bounced" / keyword<"receive"> / keyword<"external">);
receiverParam = @(Parameter / StringLiteral)?;

assembly = #$assemblySequence;
Expand Down
11 changes: 7 additions & 4 deletions src/grammar/next/grammar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export namespace $ast {
}>;
export type Receiver = $.Located<{
readonly $: "Receiver";
readonly type: receiverType;
readonly type: ReceiverType;
readonly param: receiverParam;
readonly body: statements;
}>;
Expand Down Expand Up @@ -152,7 +152,10 @@ export namespace $ast {
readonly $: "GetAttribute";
readonly methodId: expression | undefined;
}>;
export type receiverType = "bounced" | keyword<"receive"> | keyword<"external">;
export type ReceiverType = $.Located<{
readonly $: "ReceiverType";
readonly name: "bounced" | keyword<"receive"> | keyword<"external">;
}>;
export type Parameter = $.Located<{
readonly $: "Parameter";
readonly name: Id;
Expand Down Expand Up @@ -410,7 +413,7 @@ export const Contract: $.Parser<$ast.Contract> = $.loc($.field($.pure("Contract"
export const Trait: $.Parser<$ast.Trait> = $.loc($.field($.pure("Trait"), "$", $.field($.star($.lazy(() => ContractAttribute)), "attributes", $.right($.lazy(() => keyword($.str("trait"))), $.field($.lazy(() => Id), "name", $.field($.opt($.lazy(() => inheritedTraits)), "traits", $.right($.str("{"), $.field($.star($.lazy(() => traitItemDecl)), "declarations", $.right($.str("}"), $.eps)))))))));
export const moduleItem: $.Parser<$ast.moduleItem> = $.alt(PrimitiveTypeDecl, $.alt($Function, $.alt(AsmFunction, $.alt(NativeFunctionDecl, $.alt(Constant, $.alt(StructDecl, $.alt(MessageDecl, $.alt(Contract, Trait))))))));
export const ContractInit: $.Parser<$ast.ContractInit> = $.loc($.field($.pure("ContractInit"), "$", $.right($.str("init"), $.field($.lazy(() => parameterList($.lazy(() => Parameter))), "parameters", $.field($.lazy(() => statements), "body", $.eps)))));
export const Receiver: $.Parser<$ast.Receiver> = $.loc($.field($.pure("Receiver"), "$", $.field($.lazy(() => receiverType), "type", $.right($.str("("), $.field($.lazy(() => receiverParam), "param", $.right($.str(")"), $.field($.lazy(() => statements), "body", $.eps)))))));
export const Receiver: $.Parser<$ast.Receiver> = $.loc($.field($.pure("Receiver"), "$", $.field($.lazy(() => ReceiverType), "type", $.right($.str("("), $.field($.lazy(() => receiverParam), "param", $.right($.str(")"), $.field($.lazy(() => statements), "body", $.eps)))))));
export const FieldDecl: $.Parser<$ast.FieldDecl> = $.loc($.field($.pure("FieldDecl"), "$", $.field($.lazy(() => Id), "name", $.field($.lazy(() => ascription), "type", $.field($.opt($.lazy(() => asType)), "as", $.field($.opt($.right($.str("="), $.lazy(() => expression))), "expression", $.eps))))));
export const semicolon: $.Parser<$ast.semicolon> = $.alt($.str(";"), $.lookPos($.str("}")));
export const storageVar: $.Parser<$ast.storageVar> = $.left(FieldDecl, semicolon);
Expand All @@ -432,7 +435,7 @@ export const inheritedTraits: $.Parser<$ast.inheritedTraits> = $.right(keyword($
export const ContractAttribute: $.Parser<$ast.ContractAttribute> = $.loc($.field($.pure("ContractAttribute"), "$", $.right($.str("@interface"), $.right($.str("("), $.field($.lazy(() => StringLiteral), "name", $.right($.str(")"), $.eps))))));
export const FunctionAttribute: $.Parser<$ast.FunctionAttribute> = $.loc($.field($.pure("FunctionAttribute"), "$", $.field($.alt($.lazy(() => GetAttribute), $.alt(keyword($.str("mutates")), $.alt(keyword($.str("extends")), $.alt(keyword($.str("virtual")), $.alt(keyword($.str("override")), $.alt(keyword($.str("inline")), keyword($.str("abstract")))))))), "name", $.eps)));
export const GetAttribute: $.Parser<$ast.GetAttribute> = $.loc($.field($.pure("GetAttribute"), "$", $.right($.str("get"), $.field($.opt($.right($.str("("), $.left($.lazy(() => expression), $.str(")")))), "methodId", $.eps))));
export const receiverType: $.Parser<$ast.receiverType> = $.alt($.str("bounced"), $.alt(keyword($.str("receive")), keyword($.str("external"))));
export const ReceiverType: $.Parser<$ast.ReceiverType> = $.loc($.field($.pure("ReceiverType"), "$", $.field($.alt($.str("bounced"), $.alt(keyword($.str("receive")), keyword($.str("external")))), "name", $.eps)));
export const Parameter: $.Parser<$ast.Parameter> = $.loc($.field($.pure("Parameter"), "$", $.field(Id, "name", $.field($.lazy(() => ascription), "type", $.eps))));
export const StringLiteral: $.Parser<$ast.StringLiteral> = $.loc($.field($.pure("StringLiteral"), "$", $.field($.lex($.right($.str("\""), $.left($.stry($.star($.alt($.regex<"\"" | "\\">("^\"\\\\", $.negateExps([$.ExpString("\""), $.ExpString("\\")])), $.right($.str("\\"), $.lazy(() => escapeChar))))), $.str("\"")))), "value", $.eps)));
export const receiverParam: $.Parser<$ast.receiverParam> = $.opt($.alt(Parameter, StringLiteral));
Expand Down
Loading

0 comments on commit 24db1f9

Please sign in to comment.