@ton-community/tlb-parser
Version:
Parse TLB syntax into TypeScript objects
254 lines (198 loc) • 6.18 kB
text/typescript
export abstract class ASTRootBase {
// If the `parent` field is `null` it means that we've reached the root node.
// only `Program` has `parent` as null.
// All other nodes have valid node parents.
// We define `parent` while building the tree
// in the intermediate represtantation.
parent!: ASTBase | null;
// Node locations, start with `{ 1, 1 }`
locations!: {
readonly line: number;
readonly column: number;
};
// Attributes of this node, required for `walk` function, don't use directly.
static readonly _attributes: string[] = [];
}
export abstract class ASTBase extends ASTRootBase {
override readonly parent!: ASTBase;
}
export class Program extends ASTRootBase {
static override readonly _attributes: string[] = ['declarations'];
override readonly parent: null = null;
constructor(readonly declarations: Declaration[]) {
super();
}
}
export class Declaration extends ASTBase {
static override readonly _attributes: string[] = ['constructorDef', 'fields', 'combinator'];
constructor(
readonly constructorDef: Constructor,
readonly fields: FieldDefinition[],
readonly combinator: Combinator,
) {
super();
}
}
export class Constructor extends ASTBase {
constructor(
readonly name: string,
readonly tag: string | null,
) {
super();
}
getTagType(): 'binary' | 'hex' | null {
if (this.tag === null) {
return null;
}
return this.tag.startsWith('$') ? 'binary' : 'hex';
}
}
// Fields
// ------
export type FieldDefinition = FieldBuiltinDef | FieldCurlyExprDef | FieldAnonymousDef | FieldNamedDef | FieldExprDef;
export abstract class Field extends ASTBase {}
export const FieldBuiltinType = ['#', 'Type'] as const;
export class FieldBuiltinDef extends Field {
constructor(
readonly name: string,
readonly type: (typeof FieldBuiltinType)[number],
) {
super();
}
}
export class FieldCurlyExprDef extends Field {
static override readonly _attributes: string[] = ['expr'];
constructor(readonly expr: Expression) {
super();
}
}
// TODO: I am not sure that `name` is allowed. Maybe it can only be `_`
// See https://github.com/ton-blockchain/ton/issues/540
export class FieldAnonymousDef extends Field {
static override readonly _attributes: string[] = ['fields'];
constructor(
readonly name: string | null,
readonly isRef: boolean,
readonly fields: FieldDefinition[],
) {
super();
}
}
export class FieldNamedDef extends Field {
static override readonly _attributes: string[] = ['expr'];
constructor(
readonly name: string,
readonly expr: CondExpr | TypeExpr,
) {
super();
}
}
export class FieldExprDef extends Field {
static override readonly _attributes: string[] = ['expr'];
constructor(readonly expr: CondExpr) {
super();
}
}
// Combinators
// -----------
export class Combinator extends ASTBase {
static override readonly _attributes: string[] = ['args'];
constructor(
readonly name: string,
readonly args: TypeExpr[],
) {
super();
}
}
// Expressions
// -----------
export abstract class Expression extends ASTBase {}
// TODO: add validation that `dotExpr` cannot be set without `condExpr`
export class CondExpr extends Expression {
static override readonly _attributes: string[] = ['left', 'condExpr'];
constructor(
readonly left: TypeExpr,
readonly dotExpr: number | null,
readonly condExpr: TypeExpr,
) {
super();
}
}
export const CompareOperator = ['<=', '>=', '!=', '=', '<', '>'] as const;
export class CompareExpr extends Expression {
static override readonly _attributes: string[] = ['left', 'right'];
constructor(
readonly left: SimpleExpr,
readonly op: (typeof CompareOperator)[number],
readonly right: SimpleExpr,
) {
super();
}
}
// TypeExpr
export type TypeExpr = CellRefExpr | BuiltinExpr | CombinatorExpr | SimpleExpr;
export class CellRefExpr extends Expression {
static override readonly _attributes: string[] = ['expr'];
constructor(readonly expr: Expression) {
super();
}
}
export class BuiltinExpr extends Expression {}
export const BuiltinOneArgOperators = ['#<=', '#<', '##'] as const;
export class BuiltinOneArgExpr extends BuiltinExpr {
static override readonly _attributes: string[] = ['arg'];
constructor(
readonly name: (typeof BuiltinOneArgOperators)[number],
readonly arg: Reference,
) {
super();
}
}
export const BuiltinZeroArgsOperators = ['#'] as const;
export class BuiltinZeroArgs extends BuiltinExpr {
constructor(readonly name: (typeof BuiltinZeroArgsOperators)[number]) {
super();
}
}
export class CombinatorExpr extends Expression {
static override readonly _attributes: string[] = ['args'];
constructor(
readonly name: string,
readonly args: TypeExpr[],
) {
super();
}
}
// SimpleExpr
export type SimpleExpr = NegateExpr | MathExpr | Reference;
export const MathOperator = ['*', '+'] as const;
export class MathExpr extends Expression {
static override readonly _attributes: string[] = ['left', 'right'];
// TODO: narrower type for `left` and `right`?
// TODO: use `SimpleExpr` and `number`?
constructor(
readonly left: SimpleExpr,
readonly op: (typeof MathOperator)[number],
readonly right: SimpleExpr,
) {
super();
}
}
export class NegateExpr extends Expression {
static override readonly _attributes: string[] = ['expr'];
constructor(readonly expr: Expression) {
super();
}
}
export class RefExpr extends Expression {}
export type Reference = NameExpr | NumberExpr;
export class NameExpr extends RefExpr {
constructor(readonly name: string) {
super();
}
}
export class NumberExpr extends RefExpr {
constructor(readonly num: number) {
super();
}
}