bolt/src/cst.ts

848 lines
14 KiB
TypeScript
Raw Normal View History

export type TextSpan = [number, number];
export class TextPosition {
public constructor(
public offset: number,
public line: number,
public column: number,
) {
}
public clone(): TextPosition {
return new TextPosition(
this.offset,
this.line,
this.column,
);
}
public advance(text: string): void {
for (const ch of text) {
if (ch === '\n') {
this.line++;
this.column = 1;
} else {
this.column++;
}
this.offset += text.length;
}
}
}
export class TextRange {
constructor(
public start: TextPosition,
public end: TextPosition,
) {
}
public clone(): TextRange {
return new TextRange(
this.start.clone(),
this.end.clone(),
);
}
}
export class TextFile {
public constructor(
public origPath: string,
public text: string,
) {
}
}
export const enum SyntaxKind {
// Tokens
Identifier,
CustomOperator,
LParen,
RParen,
LBrace,
RBrace,
LBracket,
RBracket,
Dot,
DotDot,
Comma,
Colon,
Equals,
Integer,
StringLiteral,
LetKeyword,
PubKeyword,
MutKeyword,
ModKeyword,
ImportKeyword,
StructKeyword,
TypeKeyword,
LineFoldEnd,
BlockEnd,
BlockStart,
EndOfFile,
// Type expressions
ReferenceTypeExpression,
// Patterns
BindPattern,
TuplePattern,
// Expressions
ReferenceExpression,
TupleExpression,
NestedExpression,
ConstantExpression,
PrefixExpression,
PostfixExpression,
InfixExpression,
// Statements
ReturnStatement,
ExpressionStatement,
// Declarations
VariableDeclaration,
PrefixFuncDecl,
SuffixFuncDecl,
LetDeclaration,
StructDeclaration,
ImportDeclaration,
TypeAliasDeclaration,
// Other nodes
StructDeclarationField,
ExprBody,
BlockBody,
TypeAssert,
Param,
Module,
SourceFile,
}
export type Syntax
= SourceFile
| Param
| StructDeclarationField
| Declaration
| Statement
| Expression
| TypeExpression
| Pattern
abstract class SyntaxBase {
public abstract readonly kind: SyntaxKind;
}
abstract class TokenBase extends SyntaxBase {
private endPos: TextPosition | null = null;
constructor(
private startPos: TextPosition,
) {
super();
}
public getStartPosition(): TextPosition {
return this.startPos;
}
public getStartLine(): number {
return this.getStartPosition().line;
}
public getStartColumn(): number {
return this.getStartPosition().column;
}
public getEndPosition(): TextPosition {
if (this.endPos === null) {
const endPos = this.getStartPosition().clone();
endPos.advance(this.text);
return this.endPos = endPos;
}
return this.endPos;
}
public getEndLine(): number {
return this.getEndPosition().line;
}
public getEndColumn(): number {
return this.getEndPosition().column;
}
public abstract readonly text: string;
}
abstract class VirtualTokenBase extends TokenBase {
public get text(): string {
return '';
}
}
export class EndOfFile extends VirtualTokenBase {
public readonly kind = SyntaxKind.EndOfFile;
}
export class BlockEnd extends VirtualTokenBase {
public readonly kind = SyntaxKind.BlockEnd;
}
export class BlockStart extends VirtualTokenBase {
public readonly kind = SyntaxKind.BlockStart;
}
export class LineFoldEnd extends VirtualTokenBase {
public readonly kind = SyntaxKind.LineFoldEnd;
}
export class Integer extends TokenBase {
public readonly kind = SyntaxKind.Integer;
public constructor(
public value: bigint,
public radix: number,
private startPos: TextPosition,
) {
super(startPos);
}
public get text(): string {
switch (this.radix) {
case 16:
return '0x' + this.value.toString(16);
case 10:
return this.value.toString(10)
case 8:
return '0o' + this.value.toString(8)
case 2:
return '0b' + this.value.toString(2);
default:
throw new Error(`Radix ${this.radix} of Integer not recognised.`)
}
}
}
export class StringLiteral extends TokenBase {
public readonly kind = SyntaxKind.StringLiteral;
public constructor(
public contents: string,
private startPos: TextPosition,
) {
super(startPos);
}
public get text(): string {
let out = '"';
for (const ch of this.contents) {
const code = ch.charCodeAt(0);
if (code >= 32 && code <= 127) {
out += ch;
} else if (code <= 127) {
out += '\\x' + code.toString(16).padStart(2, '0');
} else {
out += '\\u' + code.toString(17).padStart(4, '0');
}
}
out += '"';
return out;
}
}
export class Identifier extends TokenBase {
public readonly kind = SyntaxKind.Identifier;
public constructor(
public text: string,
private startPos: TextPosition,
) {
super(startPos);
}
}
export class CustomOperator extends TokenBase {
public readonly kind = SyntaxKind.CustomOperator;
public constructor(
public text: string,
private startPos: TextPosition,
) {
super(startPos);
}
}
export class LParen extends TokenBase {
public readonly kind = SyntaxKind.LParen;
public get text(): string {
return '(';
}
}
export class RParen extends TokenBase {
public readonly kind = SyntaxKind.RParen;
public get text(): string {
return ')';
}
}
export class LBrace extends TokenBase {
public readonly kind = SyntaxKind.LBrace;
public get text(): string {
return '{';
}
}
export class RBrace extends TokenBase {
public readonly kind = SyntaxKind.RBrace;
public get text(): string {
return '}';
}
}
export class LBracket extends TokenBase {
public readonly kind = SyntaxKind.LBracket;
public get text(): string {
return '[';
}
}
export class RBracket extends TokenBase {
public readonly kind = SyntaxKind.RBracket;
public get text(): string {
return ']';
}
}
export class Dot extends TokenBase {
public readonly kind = SyntaxKind.Dot;
public get text(): string {
return '.';
}
}
export class Comma extends TokenBase {
public readonly kind = SyntaxKind.Comma;
public get text(): string {
return ',';
}
}
export class DotDot extends TokenBase {
public readonly kind = SyntaxKind.DotDot;
public get text(): string {
return '..';
}
}
export class Colon extends TokenBase {
public readonly kind = SyntaxKind.Colon;
public get text(): string {
return ':';
}
}
export class Equals extends TokenBase {
public readonly kind = SyntaxKind.Equals;
public get text(): string {
return '=';
}
}
export class StructKeyword extends TokenBase {
public readonly kind = SyntaxKind.StructKeyword;
public get text(): string {
return 'struct';
}
}
export class ModKeyword extends TokenBase {
public readonly kind = SyntaxKind.ModKeyword;
public get text(): string {
return 'mod';
}
}
export class MutKeyword extends TokenBase {
public readonly kind = SyntaxKind.MutKeyword;
public get text(): string {
return 'mut';
}
}
export class ImportKeyword extends TokenBase {
public readonly kind = SyntaxKind.ImportKeyword;
public get text(): string {
return 'import'
}
}
export class TypeKeyword extends TokenBase {
public readonly kind = SyntaxKind.TypeKeyword;
public get text(): string {
return 'type';
}
}
export class PubKeyword extends TokenBase {
public readonly kind = SyntaxKind.PubKeyword;
public get text(): string {
return 'pub';
}
}
export class LetKeyword extends TokenBase {
public readonly kind = SyntaxKind.LetKeyword;
public get text(): string {
return 'let';
}
}
export type Token
= LParen
| RParen
| LBrace
| RBrace
| LBracket
| RBracket
| Identifier
| CustomOperator
| Integer
| StringLiteral
| Comma
| Dot
| DotDot
| Colon
| Equals
| LetKeyword
| PubKeyword
| MutKeyword
| ModKeyword
| ImportKeyword
| TypeKeyword
| StructKeyword
| EndOfFile
| BlockStart
| BlockEnd
| LineFoldEnd
export type TokenKind
= Token['kind']
export class ReferenceTypeExpression extends SyntaxBase {
public readonly kind = SyntaxKind.ReferenceTypeExpression;
public constructor(
public modulePath: Array<[Identifier, Dot]>,
public name: Identifier,
) {
super();
}
}
export type TypeExpression
= ReferenceTypeExpression
export class BindPattern extends SyntaxBase {
public readonly kind = SyntaxKind.BindPattern;
public constructor(
public name: Identifier,
) {
super();
}
public get isHole(): boolean {
return this.name.text == '_';
}
}
export class TuplePattern extends SyntaxBase {
public readonly kind = SyntaxKind.TuplePattern;
public constructor(
public elements: Pattern[],
) {
super();
}
}
export type Pattern
= BindPattern
| TuplePattern
export class TupleExpression extends SyntaxBase {
public readonly kind = SyntaxKind.TupleExpression;
public constructor(
public lparen: LParen,
public elements: Expression[],
public rparen: RParen,
) {
super();
}
}
export class NestedExpression extends SyntaxBase {
public readonly kind = SyntaxKind.NestedExpression;
public constructor(
public lparen: LParen,
public expression: Expression,
public rparen: RParen,
) {
super();
}
}
export class ConstantExpression extends SyntaxBase {
public readonly kind = SyntaxKind.ConstantExpression;
public constructor(
public token: Integer | StringLiteral,
) {
super();
}
}
export class ReferenceExpression extends SyntaxBase {
public readonly kind = SyntaxKind.ReferenceExpression;
public constructor(
public modulePath: Array<[Identifier, Dot]>,
public name: Identifier
) {
super();
}
}
export class PrefixExpression extends SyntaxBase {
public readonly kind = SyntaxKind.PrefixExpression;
public constructor(
public operator: Token,
public expression: Expression,
) {
super();
}
}
export class PostfixExpression extends SyntaxBase {
public readonly kind = SyntaxKind.PostfixExpression;
public constructor(
public expression: Expression,
public operator: Token,
) {
super();
}
}
export class InfixExpression extends SyntaxBase {
public readonly kind = SyntaxKind.InfixExpression;
public constructor(
public left: Expression,
public operator: Token,
public right: Expression,
) {
super();
}
}
export type Expression
= ReferenceExpression
| ConstantExpression
| TupleExpression
| NestedExpression
| PrefixExpression
| InfixExpression
| PostfixExpression
export class ReturnStatement extends SyntaxBase {
public readonly kind = SyntaxKind.ReturnStatement;
public constructor(
public expr: Expression
) {
super();
}
}
export class ExpressionStatement extends SyntaxBase {
public readonly kind = SyntaxKind.ExpressionStatement;
public constructor(
public expresion: Expression,
) {
super();
}
}
export type Statement
= ReturnStatement
| ExpressionStatement
export class Param extends SyntaxBase {
public readonly kind = SyntaxKind.Param;
public constructor(
public pattern: Pattern,
) {
super();
}
}
export class StructDeclarationField extends SyntaxBase {
public readonly kind = SyntaxKind.StructDeclarationField;
public constructor(
public name: Identifier,
public colon: Colon,
public typeExpr: TypeExpression,
) {
super();
}
}
export class StructDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.StructDeclaration;
public constructor(
public structKeyword: StructKeyword,
public name: Identifier,
public members: StructDeclarationField[] | null,
) {
super();
}
}
export class TypeAssert extends SyntaxBase {
public readonly kind = SyntaxKind.TypeAssert;
public constructor(
public colon: Colon,
public typeExpression: TypeExpression,
) {
super();
}
}
export type Body
= ExprBody
| BlockBody
export class ExprBody extends SyntaxBase {
public readonly kind = SyntaxKind.ExprBody;
public constructor(
public equals: Equals,
public expression: Expression,
) {
super();
}
}
export type LetBodyElement
= LetDeclaration
| Statement
export class BlockBody extends SyntaxBase {
public readonly kind = SyntaxKind.BlockBody;
public constructor(
public blockStart: BlockStart,
public elements: LetBodyElement[],
) {
super();
}
}
export class LetDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.LetDeclaration;
public constructor(
public pubKeyword: PubKeyword | null,
public letKeyword: LetKeyword,
public mutKeyword: MutKeyword | null,
public pattern: Pattern,
public params: Param[],
public typeAssert: TypeAssert | null,
public body: Body | null,
) {
super();
}
}
export class ImportDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.ImportDeclaration;
public constructor(
public importKeyword: ImportKeyword,
public importSource: StringLiteral,
) {
super();
}
}
export type Declaration
= LetDeclaration
| ImportDeclaration
| StructDeclaration
export class Module extends SyntaxBase {
public readonly kind = SyntaxKind.Module;
public constructor(
public modKeyword: ModKeyword,
public name: Identifier,
public body: Body,
) {
super();
}
}
export type SourceFileElement
= Statement
| Declaration
| Module
export class SourceFile extends SyntaxBase {
public readonly kind = SyntaxKind.SourceFile;
public constructor(
public elements: SourceFileElement[]
) {
super();
}
public *getChildNodes(): Iterable<Syntax> {
for (const element in this.elements) {
yield element;
}
}
}