bolt/src/cst.ts

3143 lines
60 KiB
TypeScript
Raw Normal View History

import type stream from "stream";
import path from "path"
import { assert, implementationLimitation, IndentWriter, JSONObject, JSONValue } from "./util";
2023-02-03 17:51:27 +01:00
import { isNodeWithScope, Scope } from "./scope"
import { InferContext, Kind, KindEnv, Scheme, Type, TypeEnv } from "./checker"
import { Emitter } from "./emitter";
export type TextSpan = [number, number];
2022-09-16 19:43:52 +02:00
export type Value
= bigint
| string
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,
) {
}
public getFullPath(): string {
return path.resolve(this.origPath);
}
}
export const enum SyntaxKind {
// Tokens
Identifier,
IdentifierAlt,
CustomOperator,
Assignment,
LParen,
RParen,
LBrace,
RBrace,
LBracket,
RBracket,
RArrow,
RArrowAlt,
VBar,
Dot,
DotDot,
Comma,
Colon,
Equals,
Backslash,
Integer,
StringLiteral,
LetKeyword,
PubKeyword,
MutKeyword,
ModKeyword,
ImportKeyword,
2023-02-03 17:51:27 +01:00
ClassKeyword,
InstanceKeyword,
StructKeyword,
2022-09-10 14:11:04 +02:00
EnumKeyword,
TypeKeyword,
ReturnKeyword,
MatchKeyword,
ForeignKeyword,
IfKeyword,
ElifKeyword,
ElseKeyword,
LineFoldEnd,
BlockEnd,
BlockStart,
EndOfFile,
// Type expressions
ReferenceTypeExpression,
ArrowTypeExpression,
2022-09-10 16:52:14 +02:00
VarTypeExpression,
AppTypeExpression,
NestedTypeExpression,
2022-09-16 12:43:06 +02:00
TupleTypeExpression,
// Patterns
NamedPattern,
TuplePattern,
StructPattern,
NestedPattern,
NamedTuplePattern,
LiteralPattern,
DisjunctivePattern,
// Struct expression elements
StructExpressionField,
PunnedStructExpressionField,
// Struct pattern elements
StructPatternField,
PunnedStructPatternField,
VariadicStructPatternElement,
// Expressions
MatchExpression,
MemberExpression,
CallExpression,
ReferenceExpression,
StructExpression,
TupleExpression,
NestedExpression,
ConstantExpression,
PrefixExpression,
PostfixExpression,
InfixExpression,
FunctionExpression,
// Statements
ReturnStatement,
ExpressionStatement,
IfStatement,
// If statement elements
IfStatementCase,
// Declarations
LetDeclaration,
StructDeclaration,
2022-09-10 14:11:04 +02:00
EnumDeclaration,
ImportDeclaration,
TypeDeclaration,
2023-02-03 17:51:27 +01:00
ClassDeclaration,
InstanceDeclaration,
ModuleDeclaration,
// Let declaration body members
ExprBody,
BlockBody,
// Structure declaration members
StructDeclarationField,
2022-09-10 14:11:04 +02:00
// Enum declaration elements
EnumDeclarationStructElement,
EnumDeclarationTupleElement,
// Other nodes
WrappedOperator,
MatchArm,
Initializer,
TypeAssert,
Param,
SourceFile,
2023-02-03 17:51:27 +01:00
ClassConstraint,
ClassConstraintClause,
}
export type Syntax
= SourceFile
| ModuleDeclaration
2023-02-03 17:51:27 +01:00
| ClassDeclaration
| InstanceDeclaration
| ClassConstraint
| ClassConstraintClause
| Token
| Param
| Body
| MatchArm
| WrappedOperator
| Initializer
| IfStatementCase
| StructDeclarationField
| EnumDeclarationElement
| TypeAssert
| Declaration
| Statement
| Expression
| TypeExpression
| Pattern
2022-09-07 12:45:38 +02:00
| StructExpressionElement
| StructPatternElement
function isIgnoredProperty(key: string): boolean {
return key === 'kind' || key === 'parent';
}
abstract class SyntaxBase {
public parent: Syntax | null = null;
public inferredKind?: Kind;
public inferredType?: Type;
public abstract getFirstToken(): Token;
public abstract getLastToken(): Token;
public abstract clone(): Syntax;
public getRange(): TextRange {
return new TextRange(
this.getFirstToken().getStartPosition(),
this.getLastToken().getEndPosition(),
);
}
public getSourceFile(): SourceFile {
let curr = this as any;
do {
if (curr.kind === SyntaxKind.SourceFile) {
return curr;
}
curr = curr.parent;
} while (curr != null);
throw new Error(`Could not find a SourceFile in any of the parent nodes of ${this}`);
}
public getScope(): Scope {
let curr: Syntax | null = this as any;
do {
if (isNodeWithScope(curr!)) {
if (curr.scope === undefined) {
curr.scope = new Scope(curr);
}
return curr.scope;
}
curr = curr!.parent;
} while (curr !== null);
throw new Error(`Could not find a scope for ${this}. Maybe the parent links are not set?`);
}
public getEnclosingModule(): ModuleDeclaration | SourceFile {
let curr = this.parent!;
while (curr !== null) {
if (curr.kind === SyntaxKind.SourceFile || curr.kind === SyntaxKind.ModuleDeclaration) {
return curr;
}
curr = curr.parent!;
}
throw new Error(`Unable to find an enclosing module for ${this.constructor.name}. Perhaps the parent-links are not set?`);
}
public setParents(): void {
const visit = (value: any) => {
if (value === null) {
return;
}
if (Array.isArray(value)) {
value.forEach(visit);
return;
}
if (value instanceof SyntaxBase) {
value.parent = this as any;
value.setParents();
return;
}
}
for (const key of Object.getOwnPropertyNames(this)) {
if (isIgnoredProperty(key)) {
continue;
}
visit((this as any)[key]);
}
}
public *getTokens(): Iterable<Token> {
for (const [_, value] of this.getFields()) {
yield* filter(value);
}
function* filter(value: any): Iterable<Token> {
if (isToken(value)) {
yield value;
} else if (Array.isArray(value)) {
for (const element of value) {
yield* filter(element);
}
} else if (isSyntax(value)) {
yield* value.getTokens();
}
}
}
public *getFields(): Iterable<[string, any]> {
for (const key of Object.getOwnPropertyNames(this)) {
if (!isIgnoredProperty(key)) {
yield [key, (this as any)[key]];
}
}
}
public *getChildNodes(): Iterable<Syntax> {
function* visit(value: any): Iterable<Syntax> {
if (value === null) {
return;
}
if (Array.isArray(value)) {
for (const element of value) {
yield* visit(element);
}
} else if (isSyntax(value)) {
yield value;
}
}
for (const [_key, value] of this.getFields()) {
yield* visit(value);
}
}
public emit(file: stream.Writable): void {
const emitter = new Emitter(new IndentWriter(file));
emitter.emit(this as any);
}
public toJSON(): JSONObject {
const obj: JSONObject = {};
obj['type'] = this.constructor.name;
for (const [key, value] of this.getFields()) {
if (isIgnoredProperty(key)) {
continue;
}
obj[key] = encode(value);
}
return obj;
function encode(value: any): JSONValue {
if (value === null) {
return null;
} else if (Array.isArray(value)) {
return value.map(encode);
} else if (isSyntax(value)) {
return value.toJSON();
} else {
return value;
}
}
}
public resolveModule(name: string): ModuleDeclaration | null {
const node = this as unknown as Syntax;
assert(node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.SourceFile);
for (const element of node.elements) {
if (element.kind === SyntaxKind.ModuleDeclaration && element.name.text === name) {
return element;
}
}
return null;
}
public getModulePath(): string[] {
let curr = this.parent;
const modulePath = [];
while (curr !== null) {
if (curr.kind === SyntaxKind.ModuleDeclaration) {
modulePath.unshift(curr.name.text);
}
curr = curr.parent;
}
return modulePath;
}
}
2022-09-10 16:52:14 +02:00
export function forEachChild(node: Syntax, callback: (node: Syntax) => void): void {
for (const key of Object.getOwnPropertyNames(node)) {
if (isIgnoredProperty(key)) {
continue;
}
visitField((node as any)[key]);
}
function visitField(field: any): void {
if (field === null) {
return;
}
if (Array.isArray(field)) {
for (const element of field) {
visitField(element);
}
return;
}
if (field instanceof SyntaxBase) {
callback(field as Syntax);
}
}
}
abstract class TokenBase extends SyntaxBase {
private endPos: TextPosition | null = null;
public constructor(
public startPos: TextPosition | null = null,
) {
super();
}
public getFirstToken(): Token {
throw new Error(`Trying to get the first token of an object that is a token itself.`);
}
public getLastToken(): Token {
throw new Error(`Trying to get the last token of an object that is a token itself.`);
}
public getRange(): TextRange {
return new TextRange(
this.getStartPosition(),
this.getEndPosition(),
);
}
public getStartPosition(): TextPosition {
assert(this.startPos !== null);
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;
public clone(): EndOfFile {
return new EndOfFile(this.startPos);
}
}
export class BlockEnd extends VirtualTokenBase {
public readonly kind = SyntaxKind.BlockEnd;
public clone(): BlockEnd {
return new BlockEnd(this.startPos);
}
}
export class BlockStart extends VirtualTokenBase {
public readonly kind = SyntaxKind.BlockStart;
public clone(): BlockStart {
return new BlockStart(this.startPos);
}
}
export class LineFoldEnd extends VirtualTokenBase {
public readonly kind = SyntaxKind.LineFoldEnd;
public clone(): LineFoldEnd {
return new LineFoldEnd(this.startPos);
}
}
export class Integer extends TokenBase {
public readonly kind = SyntaxKind.Integer;
public constructor(
public value: bigint,
public radix: number,
startPos: TextPosition | null = null,
) {
super(startPos);
}
2022-09-16 19:43:52 +02:00
public getValue(): Value {
return this.value;
}
public clone(): Integer {
return new Integer(
this.value,
this.radix,
this.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,
startPos: TextPosition | null = null,
) {
super(startPos);
}
2022-09-16 19:43:52 +02:00
public getValue(): Value {
return this.contents;
}
public clone(): StringLiteral {
return new StringLiteral(
this.contents,
this.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 IdentifierAlt extends TokenBase {
public readonly kind = SyntaxKind.IdentifierAlt;
public constructor(
public text: string,
startPos: TextPosition | null = null,
) {
super(startPos);
}
public clone(): IdentifierAlt {
return new IdentifierAlt(
this.text,
this.startPos
);
}
}
export class Identifier extends TokenBase {
public readonly kind = SyntaxKind.Identifier;
public constructor(
public text: string,
startPos: TextPosition | null = null,
) {
super(startPos);
}
public clone(): Identifier {
return new Identifier(
this.text,
this.startPos
);
}
}
export class CustomOperator extends TokenBase {
public readonly kind = SyntaxKind.CustomOperator;
public constructor(
public text: string,
startPos: TextPosition | null = null,
) {
super(startPos);
}
public clone(): CustomOperator {
return new CustomOperator(
this.text,
this.startPos,
);
}
}
export type ExprOperator
= CustomOperator
| VBar
export function isExprOperator(node: Syntax): node is ExprOperator {
return node.kind === SyntaxKind.CustomOperator
|| node.kind === SyntaxKind.VBar
}
export class Assignment extends TokenBase {
public readonly kind = SyntaxKind.Assignment;
public constructor(
public text: string,
startPos: TextPosition | null = null,
) {
super(startPos);
}
public clone(): Assignment {
return new Assignment(
this.text,
this.startPos
);
}
}
export class LParen extends TokenBase {
public readonly kind = SyntaxKind.LParen;
public get text(): string {
return '(';
}
public clone(): LParen {
return new LParen(this.startPos);
}
}
export class RParen extends TokenBase {
public readonly kind = SyntaxKind.RParen;
public get text(): string {
return ')';
}
public clone(): RParen {
return new RParen(this.startPos);
}
}
export class LBrace extends TokenBase {
public readonly kind = SyntaxKind.LBrace;
public get text(): string {
return '{';
}
public clone(): LBrace {
return new LBrace(this.startPos);
}
}
export class RBrace extends TokenBase {
public readonly kind = SyntaxKind.RBrace;
public get text(): string {
return '}';
}
public clone(): RBrace {
return new RBrace(this.startPos);
}
}
export class LBracket extends TokenBase {
public readonly kind = SyntaxKind.LBracket;
public get text(): string {
return '[';
}
public clone(): LBracket {
return new LBracket(this.startPos);
}
}
export class RBracket extends TokenBase {
public readonly kind = SyntaxKind.RBracket;
public get text(): string {
return ']';
}
public clone(): RBracket {
return new RBracket(this.startPos);
}
}
export class Dot extends TokenBase {
public readonly kind = SyntaxKind.Dot;
public get text(): string {
return '.';
}
public clone(): Dot {
return new Dot(this.startPos);
}
}
export class Comma extends TokenBase {
public readonly kind = SyntaxKind.Comma;
public get text(): string {
return ',';
}
public clone(): Comma {
return new Comma(this.startPos);
}
}
export class DotDot extends TokenBase {
public readonly kind = SyntaxKind.DotDot;
public get text(): string {
return '..';
}
public clone(): DotDot {
return new DotDot(this.startPos);
}
}
export class Colon extends TokenBase {
public readonly kind = SyntaxKind.Colon;
public get text(): string {
return ':';
}
public clone(): Colon {
return new Colon(this.startPos);
}
}
export class Equals extends TokenBase {
public readonly kind = SyntaxKind.Equals;
public get text(): string {
return '=';
}
public clone(): Equals {
return new Equals(this.startPos);
}
}
export class Backslash extends TokenBase {
public readonly kind = SyntaxKind.Equals;
public get text(): string {
return '\\';
}
public clone(): Backslash {
return new Backslash(this.startPos);
}
}
export class IfKeyword extends TokenBase {
public readonly kind = SyntaxKind.IfKeyword;
public get text(): string {
return 'if';
}
public clone(): IfKeyword {
return new IfKeyword(this.startPos);
}
}
export class ElseKeyword extends TokenBase {
public readonly kind = SyntaxKind.ElseKeyword;
public get text(): string {
return 'else';
}
public clone(): ElseKeyword {
return new ElseKeyword(this.startPos);
}
}
export class ElifKeyword extends TokenBase {
public readonly kind = SyntaxKind.ElifKeyword;
public get text(): string {
return 'elif';
}
public clone(): ElifKeyword {
return new ElifKeyword(this.startPos);
}
}
export class StructKeyword extends TokenBase {
public readonly kind = SyntaxKind.StructKeyword;
public get text(): string {
return 'struct';
}
public clone(): StructKeyword {
return new StructKeyword(this.startPos);
}
}
2022-09-10 14:11:04 +02:00
export class EnumKeyword extends TokenBase {
public readonly kind = SyntaxKind.EnumKeyword;
public get text(): string {
return 'enum';
}
public clone(): EnumKeyword {
return new EnumKeyword(this.startPos);
}
2022-09-10 14:11:04 +02:00
}
export class ReturnKeyword extends TokenBase {
public readonly kind = SyntaxKind.ReturnKeyword;
public get text(): string {
return 'return';
}
public clone(): ReturnKeyword {
return new ReturnKeyword(this.startPos);
}
}
export class MatchKeyword extends TokenBase {
public readonly kind = SyntaxKind.MatchKeyword;
public get text(): string {
return 'match';
}
public clone(): MatchKeyword {
return new MatchKeyword(this.startPos);
}
}
export class ForeignKeyword extends TokenBase {
public readonly kind = SyntaxKind.ForeignKeyword;
public get text(): string {
return 'foreign';
}
public clone(): ForeignKeyword {
return new ForeignKeyword(this.startPos);
}
}
export class ModKeyword extends TokenBase {
public readonly kind = SyntaxKind.ModKeyword;
public get text(): string {
return 'mod';
}
public clone(): ModKeyword {
return new ModKeyword(this.startPos);
}
}
export class MutKeyword extends TokenBase {
public readonly kind = SyntaxKind.MutKeyword;
public get text(): string {
return 'mut';
}
public clone(): MutKeyword {
return new MutKeyword(this.startPos);
}
}
export class ImportKeyword extends TokenBase {
public readonly kind = SyntaxKind.ImportKeyword;
public get text(): string {
return 'import'
}
public clone(): ImportKeyword {
return new ImportKeyword(this.startPos);
}
}
2023-02-03 17:51:27 +01:00
export class ClassKeyword extends TokenBase {
public readonly kind = SyntaxKind.ClassKeyword;
public get text(): string {
return 'trait';
}
public clone(): ClassKeyword {
return new ClassKeyword(this.startPos);
}
2023-02-03 17:51:27 +01:00
}
export class InstanceKeyword extends TokenBase {
public readonly kind = SyntaxKind.InstanceKeyword;
public get text(): string {
return 'impl';
}
public clone(): InstanceKeyword {
return new InstanceKeyword(this.startPos);
}
2023-02-03 17:51:27 +01:00
}
export class TypeKeyword extends TokenBase {
public readonly kind = SyntaxKind.TypeKeyword;
public get text(): string {
return 'type';
}
public clone(): TypeKeyword {
return new TypeKeyword(this.startPos);
}
}
export class PubKeyword extends TokenBase {
public readonly kind = SyntaxKind.PubKeyword;
public get text(): string {
return 'pub';
}
public clone(): PubKeyword {
return new PubKeyword();
}
}
export class LetKeyword extends TokenBase {
public readonly kind = SyntaxKind.LetKeyword;
public get text(): string {
return 'let';
}
public clone(): LetKeyword {
return new LetKeyword();
}
}
export class RArrow extends TokenBase {
public readonly kind = SyntaxKind.RArrow;
public get text(): string {
return '->';
}
public clone(): RArrow {
return new RArrow(this.startPos);
}
}
export class RArrowAlt extends TokenBase {
public readonly kind = SyntaxKind.RArrowAlt;
public get text(): string {
return '=>';
}
public clone(): RArrowAlt {
return new RArrowAlt(this.startPos);
}
}
export class VBar extends TokenBase {
public readonly kind = SyntaxKind.VBar;
public get text(): string {
return '|';
}
public clone(): VBar {
return new VBar(this.startPos);
}
}
export type Token
= RArrow
| RArrowAlt
| VBar
| LParen
| RParen
| LBrace
| RBrace
| LBracket
| RBracket
| Identifier
| IdentifierAlt
| CustomOperator
| Integer
| StringLiteral
| Comma
| Dot
| DotDot
| Colon
| Equals
| Backslash
| LetKeyword
| PubKeyword
| MutKeyword
| ModKeyword
| ImportKeyword
2023-02-03 17:51:27 +01:00
| ClassKeyword
| InstanceKeyword
| TypeKeyword
| StructKeyword
| ReturnKeyword
| MatchKeyword
| EndOfFile
| BlockStart
| BlockEnd
| LineFoldEnd
| Assignment
| IfKeyword
| ElseKeyword
| ElifKeyword
2022-09-10 14:11:04 +02:00
| EnumKeyword
| ForeignKeyword
export type TokenKind
= Token['kind']
export class ArrowTypeExpression extends SyntaxBase {
public readonly kind = SyntaxKind.ArrowTypeExpression;
public constructor(
public paramTypeExprs: TypeExpression[],
public returnTypeExpr: TypeExpression
) {
super();
}
public clone(): ArrowTypeExpression {
return new ArrowTypeExpression(
this.paramTypeExprs.map(te => te.clone()),
this.returnTypeExpr.clone(),
);
}
public getFirstToken(): Token {
if (this.paramTypeExprs.length > 0) {
return this.paramTypeExprs[0].getFirstToken();
}
return this.returnTypeExpr.getFirstToken();
}
public getLastToken(): Token {
return this.returnTypeExpr.getLastToken();
}
}
2022-09-16 12:43:06 +02:00
export class TupleTypeExpression extends SyntaxBase {
public readonly kind = SyntaxKind.TupleTypeExpression;
public constructor(
public lparen: LParen,
public elements: TypeExpression[],
public rparen: RParen,
) {
super();
}
public clone(): TupleTypeExpression {
return new TupleTypeExpression(
this.lparen.clone(),
this.elements.map(element => element.clone()),
this.rparen.clone(),
);
}
2022-09-16 12:43:06 +02:00
public getFirstToken(): Token {
return this.lparen;
}
public getLastToken(): Token {
return this.rparen;
}
}
export class ReferenceTypeExpression extends SyntaxBase {
public readonly kind = SyntaxKind.ReferenceTypeExpression;
public constructor(
public modulePath: Array<[IdentifierAlt, Dot]>,
public name: IdentifierAlt,
) {
super();
}
public clone(): ReferenceTypeExpression {
return new ReferenceTypeExpression(
this.modulePath.map(([name, dot]) => [name.clone(), dot.clone()]),
this.name.clone(),
);
}
public getFirstToken(): Token {
if (this.modulePath.length > 0) {
return this.modulePath[0][0];
}
return this.name;
}
public getLastToken(): Token {
return this.name;
}
}
export class AppTypeExpression extends SyntaxBase {
public readonly kind = SyntaxKind.AppTypeExpression;
public constructor(
public operator: TypeExpression,
public args: TypeExpression[],
) {
super();
}
public clone(): AppTypeExpression {
return new AppTypeExpression(
this.operator.clone(),
this.args.map(arg => arg.clone()),
);
}
public getFirstToken(): Token {
return this.operator.getFirstToken();
}
public getLastToken(): Token {
if (this.args.length > 0) {
return this.args[this.args.length-1].getLastToken();
}
return this.operator.getLastToken();
}
}
2022-09-10 16:52:14 +02:00
export class VarTypeExpression extends SyntaxBase {
public readonly kind = SyntaxKind.VarTypeExpression;
public constructor(
public name: Identifier
) {
super();
}
public clone(): VarTypeExpression {
return new VarTypeExpression( this.name.clone() );
}
2022-09-10 16:52:14 +02:00
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
return this.name;
}
}
export class NestedTypeExpression extends SyntaxBase {
public readonly kind = SyntaxKind.NestedTypeExpression;
public constructor(
public lparen: LParen,
public typeExpr: TypeExpression,
public rparen: RParen,
) {
super();
}
public clone(): NestedTypeExpression {
return new NestedTypeExpression(
this.lparen.clone(),
this.typeExpr.clone(),
this.rparen.clone(),
);
}
public getFirstToken(): Token {
return this.lparen;
}
public getLastToken(): Token {
return this.rparen;
}
}
export type TypeExpression
= ReferenceTypeExpression
| ArrowTypeExpression
2022-09-10 16:52:14 +02:00
| VarTypeExpression
| AppTypeExpression
| NestedTypeExpression
2022-09-16 12:43:06 +02:00
| TupleTypeExpression
export class NamedPattern extends SyntaxBase {
public readonly kind = SyntaxKind.NamedPattern;
public constructor(
public name: Identifier,
) {
super();
}
public clone(): NamedPattern {
return new NamedPattern( this.name.clone() );
}
public get isHole(): boolean {
return this.name.text == '_';
}
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
return this.name;
}
}
export class TuplePattern extends SyntaxBase {
public readonly kind = SyntaxKind.TuplePattern;
public constructor(
public lparen: LParen,
public elements: Pattern[],
public rparen: RParen,
) {
super();
}
public clone(): TuplePattern {
return new TuplePattern(
this.lparen.clone(),
this.elements.map(element => element.clone()),
this.rparen.clone(),
);
}
public getFirstToken(): Token {
return this.lparen;
}
public getLastToken(): Token {
return this.rparen;
}
}
export class NamedTuplePattern extends SyntaxBase {
public readonly kind = SyntaxKind.NamedTuplePattern;
public constructor(
public name: IdentifierAlt,
public elements: Pattern[],
) {
super();
}
public clone(): NamedTuplePattern {
return new NamedTuplePattern(
this.name.clone(),
this.elements.map(element => element.clone()),
);
}
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
if (this.elements.length > 0) {
return this.elements[this.elements.length-1].getLastToken();
}
return this.name;
}
}
export class StructPatternField extends SyntaxBase {
public readonly kind = SyntaxKind.StructPatternField;
public constructor(
public name: Identifier,
public equals: Equals,
public pattern: Pattern,
) {
super();
}
public clone(): StructPatternField {
return new StructPatternField(
this.name.clone(),
this.equals.clone(),
this.pattern.clone(),
);
}
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
return this.pattern.getLastToken();
}
}
export class VariadicStructPatternElement extends SyntaxBase {
public readonly kind = SyntaxKind.VariadicStructPatternElement;
public constructor(
public dotdot: DotDot,
public pattern: Pattern | null,
) {
super();
}
public clone(): VariadicStructPatternElement {
return new VariadicStructPatternElement(
this.dotdot.clone(),
this.pattern !== null ? this.pattern.clone() : null,
);
}
public getFirstToken(): Token {
return this.dotdot;
}
public getLastToken(): Token {
if (this.pattern !== null) {
return this.pattern.getLastToken();
}
return this.dotdot;
}
}
export class PunnedStructPatternField extends SyntaxBase {
public readonly kind = SyntaxKind.PunnedStructPatternField;
public constructor(
public name: Identifier,
) {
super();
}
public clone(): PunnedStructPatternField {
return new PunnedStructPatternField( this.name.clone() );
}
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
return this.name;
}
}
export type StructPatternElement
= VariadicStructPatternElement
| PunnedStructPatternField
| StructPatternField
export class StructPattern extends SyntaxBase {
public readonly kind = SyntaxKind.StructPattern;
public constructor(
public lbrace: LBrace,
2022-09-07 12:45:38 +02:00
public members: StructPatternElement[],
public rbrace: RBrace,
) {
super();
}
public clone(): StructPattern {
return new StructPattern(
this.lbrace.clone(),
this.members.map(member => member.clone()),
this.rbrace.clone(),
);
}
public getFirstToken(): Token {
return this.lbrace;
}
public getLastToken(): Token {
return this.rbrace;
}
}
export class NestedPattern extends SyntaxBase {
public readonly kind = SyntaxKind.NestedPattern;
public constructor(
public lparen: LParen,
public pattern: Pattern,
public rparen: RParen,
) {
super();
}
public clone(): NestedPattern {
return new NestedPattern(
this.lparen.clone(),
this.pattern.clone(),
this.rparen.clone(),
);
}
public getFirstToken(): Token {
return this.lparen;
}
public getLastToken(): Token {
return this.rparen;
}
}
export class DisjunctivePattern extends SyntaxBase {
public readonly kind = SyntaxKind.DisjunctivePattern;
public constructor(
public left: Pattern,
public operator: VBar,
public right: Pattern,
) {
super();
}
public clone(): DisjunctivePattern {
return new DisjunctivePattern(
this.left.clone(),
this.operator.clone(),
this.right.clone(),
);
}
public getFirstToken(): Token {
return this.left.getFirstToken();
}
public getLastToken(): Token {
return this.right.getLastToken();
}
}
export class LiteralPattern extends SyntaxBase {
public readonly kind = SyntaxKind.LiteralPattern;
public constructor(
public token: StringLiteral | Integer
) {
super();
}
public clone(): LiteralPattern {
return new LiteralPattern( this.token.clone() );
}
public getFirstToken(): Token {
return this.token;
}
public getLastToken(): Token {
return this.token;
}
}
export type Pattern
= NamedPattern
| NestedPattern
| StructPattern
| NamedTuplePattern
| TuplePattern
| DisjunctivePattern
| LiteralPattern
export class TupleExpression extends SyntaxBase {
public readonly kind = SyntaxKind.TupleExpression;
public constructor(
public lparen: LParen,
public elements: Expression[],
public rparen: RParen,
) {
super();
}
public clone(): TupleExpression {
return new TupleExpression(
this.lparen.clone(),
this.elements.map(element => element.clone()),
this.rparen.clone()
);
}
public getFirstToken(): Token {
return this.lparen;
}
public getLastToken(): Token {
return this.rparen;
}
}
export class NestedExpression extends SyntaxBase {
public readonly kind = SyntaxKind.NestedExpression;
public constructor(
public lparen: LParen,
public expression: Expression,
public rparen: RParen,
) {
super();
}
public clone(): NestedExpression {
return new NestedExpression(
this.lparen.clone(),
this.expression.clone(),
this.rparen.clone(),
);
}
public getFirstToken(): Token {
return this.lparen;
}
public getLastToken(): Token {
return this.rparen;
}
}
export class ConstantExpression extends SyntaxBase {
public readonly kind = SyntaxKind.ConstantExpression;
public constructor(
public token: Integer | StringLiteral,
) {
super();
}
public clone(): ConstantExpression {
return new ConstantExpression( this.token.clone() );
}
public getFirstToken(): Token {
return this.token;
}
public getLastToken(): Token {
return this.token;
}
}
export class CallExpression extends SyntaxBase {
public readonly kind = SyntaxKind.CallExpression;
public constructor(
public func: Expression,
public args: Expression[],
) {
super();
}
public clone(): CallExpression {
return new CallExpression(
this.func.clone(),
this.args.map(arg => arg.clone()),
);
}
public getFirstToken(): Token {
return this.func.getFirstToken();
}
public getLastToken(): Token {
if (this.args.length > 0) {
return this.args[this.args.length-1].getLastToken();
}
return this.func.getLastToken();
}
}
export class StructExpressionField extends SyntaxBase {
public readonly kind = SyntaxKind.StructExpressionField;
public constructor(
public name: Identifier,
public equals: Equals,
public expression: Expression,
) {
super();
}
public clone(): StructExpressionField {
return new StructExpressionField(
this.name.clone(),
this.equals.clone(),
this.expression.clone(),
);
}
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
return this.expression.getLastToken();
}
}
export class PunnedStructExpressionField extends SyntaxBase {
public readonly kind = SyntaxKind.PunnedStructExpressionField;
public constructor(
public name: Identifier,
) {
super();
}
public clone(): PunnedStructExpressionField {
return new PunnedStructExpressionField( this.name.clone() );
}
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
return this.name;
}
}
export type StructExpressionElement
= StructExpressionField
| PunnedStructExpressionField;
export class StructExpression extends SyntaxBase {
public readonly kind = SyntaxKind.StructExpression;
public constructor(
public lbrace: LBrace,
2022-09-07 12:45:38 +02:00
public members: StructExpressionElement[],
public rbrace: RBrace,
) {
super();
}
public clone(): StructExpression {
return new StructExpression(
this.lbrace.clone(),
this.members.map(member => member.clone()),
this.rbrace.clone(),
);
}
public getFirstToken(): Token {
return this.lbrace;
}
public getLastToken(): Token {
return this.rbrace;
}
}
export class MatchArm extends SyntaxBase {
public readonly kind = SyntaxKind.MatchArm;
public constructor(
public pattern: Pattern,
public rarrowAlt: RArrowAlt,
public expression: Expression,
) {
super();
}
public clone(): MatchArm {
return new MatchArm(
this.pattern.clone(),
this.rarrowAlt.clone(),
this.expression.clone(),
);
}
public getFirstToken(): Token {
return this.pattern.getFirstToken();
}
public getLastToken(): Token {
return this.expression.getLastToken();
}
}
export class FunctionExpression extends SyntaxBase {
public readonly kind = SyntaxKind.FunctionExpression;
public constructor(
public backslash: Backslash,
public params: Param[],
public body: Body,
) {
super();
}
public clone(): FunctionExpression {
return new FunctionExpression(
this.backslash.clone(),
this.params.map(param => param.clone()),
this.body.clone(),
);
}
public getFirstToken(): Token {
return this.backslash;
}
public getLastToken(): Token {
return this.body.getLastToken();
}
}
export class MatchExpression extends SyntaxBase {
public readonly kind = SyntaxKind.MatchExpression;
public constructor(
public matchKeyword: MatchKeyword,
public expression: Expression | null,
public arms: MatchArm[],
) {
super();
}
public clone(): MatchExpression {
return new MatchExpression(
this.matchKeyword.clone(),
this.expression !== null ? this.expression.clone() : null,
this.arms.map(arm => arm.clone()),
);
}
public getFirstToken(): Token {
return this.matchKeyword;
}
public getLastToken(): Token {
if (this.arms.length > 0) {
return this.arms[this.arms.length-1].getLastToken();
}
if (this.expression !== null) {
return this.expression.getLastToken();
}
return this.matchKeyword;
}
}
export class ReferenceExpression extends SyntaxBase {
public readonly kind = SyntaxKind.ReferenceExpression;
public constructor(
public modulePath: Array<[IdentifierAlt, Dot]>,
public name: Identifier | IdentifierAlt,
) {
super();
}
public clone(): ReferenceExpression {
return new ReferenceExpression(
this.modulePath.map(([name, dot]) => [name.clone(), dot.clone()]),
this.name.clone(),
);
}
public getFirstToken(): Token {
if (this.modulePath.length > 0) {
return this.modulePath[0][0];
}
return this.name;
}
public getLastToken(): Token {
return this.name;
}
}
export class MemberExpression extends SyntaxBase {
public readonly kind = SyntaxKind.MemberExpression;
public constructor(
public expression: Expression,
public path: [Dot, Identifier][],
) {
super();
}
public clone(): MemberExpression {
return new MemberExpression(
this.expression.clone(),
this.path.map(([dot, name]) => [dot.clone(), name.clone()]),
);
}
public getFirstToken(): Token {
return this.expression.getFirstToken();
}
public getLastToken(): Token {
return this.path[this.path.length-1][1];
}
}
export class PrefixExpression extends SyntaxBase {
public readonly kind = SyntaxKind.PrefixExpression;
public constructor(
public operator: ExprOperator,
public expression: Expression,
) {
super();
}
public clone(): PrefixExpression {
return new PrefixExpression(
this.operator.clone(),
this.expression.clone(),
);
}
public getFirstToken(): Token {
return this.operator;
}
public getLastToken(): Token {
return this.expression.getLastToken();
}
}
export class PostfixExpression extends SyntaxBase {
public readonly kind = SyntaxKind.PostfixExpression;
public constructor(
public expression: Expression,
public operator: ExprOperator,
) {
super();
}
public clone(): PostfixExpression {
return new PostfixExpression(
this.expression.clone(),
this.operator.clone(),
);
}
public getFirstToken(): Token {
return this.expression.getFirstToken();
}
public getLastToken(): Token {
return this.operator;
}
}
export class InfixExpression extends SyntaxBase {
public readonly kind = SyntaxKind.InfixExpression;
public constructor(
public left: Expression,
public operator: ExprOperator,
public right: Expression,
) {
super();
}
public clone(): InfixExpression {
return new InfixExpression(
this.left.clone(),
this.operator.clone(),
this.right.clone(),
);
}
public getFirstToken(): Token {
return this.left.getFirstToken();
}
public getLastToken(): Token {
return this.right.getLastToken();
}
}
export type Expression
= MemberExpression
| CallExpression
| StructExpression
| ReferenceExpression
| ConstantExpression
| TupleExpression
| MatchExpression
| NestedExpression
| PrefixExpression
| InfixExpression
| PostfixExpression
| FunctionExpression
export class IfStatementCase extends SyntaxBase {
public readonly kind = SyntaxKind.IfStatementCase;
public constructor(
public keyword: IfKeyword | ElseKeyword | ElifKeyword,
public test: Expression | null,
public blockStart: BlockStart,
public elements: LetBodyElement[],
) {
super();
}
public clone(): IfStatementCase {
return new IfStatementCase(
this.keyword.clone(),
this.test !== null ? this.test.clone() : null,
this.blockStart.clone(),
this.elements.map(element => element.clone()),
);
}
public getFirstToken(): Token {
return this.keyword;
}
public getLastToken(): Token {
if (this.elements.length > 0) {
return this.elements[this.elements.length-1].getLastToken();
}
return this.blockStart;
}
}
export class IfStatement extends SyntaxBase {
public readonly kind = SyntaxKind.IfStatement;
public constructor(
public cases: IfStatementCase[],
) {
super();
}
public clone(): IfStatement {
return new IfStatement(
this.cases.map(caze => caze.clone()),
);
}
public getFirstToken(): Token {
return this.cases[0].getFirstToken();
}
public getLastToken(): Token {
return this.cases[this.cases.length-1].getLastToken();
}
}
export class ReturnStatement extends SyntaxBase {
public readonly kind = SyntaxKind.ReturnStatement;
public constructor(
public returnKeyword: ReturnKeyword,
public expression: Expression | null
) {
super();
}
public clone(): ReturnStatement {
return new ReturnStatement(
this.returnKeyword.clone(),
this.expression !== null ? this.expression.clone() : null,
);
}
public getFirstToken(): Token {
return this.returnKeyword;
}
public getLastToken(): Token {
if (this.expression !== null) {
return this.expression.getLastToken();
}
return this.returnKeyword;
}
}
export class ExpressionStatement extends SyntaxBase {
public readonly kind = SyntaxKind.ExpressionStatement;
public constructor(
public expression: Expression,
) {
super();
}
public clone(): ExpressionStatement {
return new ExpressionStatement( this.expression.clone() );
}
public getFirstToken(): Token {
return this.expression.getFirstToken();
}
public getLastToken(): Token {
return this.expression.getLastToken();
}
}
export type Statement
= ReturnStatement
| ExpressionStatement
| IfStatement
export class Param extends SyntaxBase {
public readonly kind = SyntaxKind.Param;
public constructor(
public pattern: Pattern,
) {
super();
}
public clone(): Param {
return new Param(
this.pattern.clone(),
);
}
public getFirstToken(): Token {
return this.pattern.getFirstToken();
}
public getLastToken(): Token {
return this.pattern.getLastToken();
}
}
2022-09-10 14:11:04 +02:00
export class EnumDeclarationStructElement extends SyntaxBase {
public readonly kind = SyntaxKind.EnumDeclarationStructElement;
2022-09-15 16:56:02 +02:00
public scheme?: Scheme;
2022-09-10 14:11:04 +02:00
public constructor(
public name: IdentifierAlt,
public blockStart: BlockStart,
public fields: StructDeclarationField[],
2022-09-10 14:11:04 +02:00
) {
super();
}
public clone(): EnumDeclarationStructElement {
return new EnumDeclarationStructElement(
this.name.clone(),
this.blockStart.clone(),
this.fields.map(field => field.clone()),
);
}
2022-09-10 14:11:04 +02:00
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
if (this.fields.length > 0) {
return this.fields[this.fields.length-1].getLastToken();
2022-09-10 14:11:04 +02:00
}
return this.blockStart;
}
}
export class EnumDeclarationTupleElement extends SyntaxBase {
public readonly kind = SyntaxKind.EnumDeclarationTupleElement;
public constructor(
public name: IdentifierAlt,
public elements: TypeExpression[],
) {
super();
}
public clone(): EnumDeclarationElement {
return new EnumDeclarationTupleElement(
this.name.clone(),
this.elements.map(element => element.clone()),
);
}
2022-09-10 14:11:04 +02:00
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
if (this.elements.length > 0) {
return this.elements[this.elements.length-1].getLastToken();
}
return this.name;
}
}
export type EnumDeclarationElement
= EnumDeclarationStructElement
| EnumDeclarationTupleElement
export class EnumDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.EnumDeclaration;
public typeEnv?: TypeEnv;
2022-09-10 14:11:04 +02:00
public constructor(
public pubKeyword: PubKeyword | null,
public enumKeyword: EnumKeyword,
public name: IdentifierAlt,
public varExps: Identifier[],
2022-09-10 14:11:04 +02:00
public members: EnumDeclarationElement[] | null,
) {
super();
}
public clone(): EnumDeclaration {
return new EnumDeclaration(
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
this.enumKeyword.clone(),
this.name.clone(),
this.varExps.map(ve => ve.clone()),
this.members !== null ? this.members.map(member => member.clone()) : null,
);
}
2022-09-10 14:11:04 +02:00
public getFirstToken(): Token {
if (this.pubKeyword !== null) {
return this.pubKeyword;
}
return this.enumKeyword;
}
public getLastToken(): Token {
if (this.members !== null && this.members.length > 0) {
return this.members[this.members.length-1].getLastToken();
}
return this.name;
}
}
export class StructDeclarationField extends SyntaxBase {
public readonly kind = SyntaxKind.StructDeclarationField;
public constructor(
public name: Identifier,
public colon: Colon,
public typeExpr: TypeExpression,
) {
super();
}
public clone(): StructDeclarationField {
return new StructDeclarationField(
this.name.clone(),
this.colon.clone(),
this.typeExpr.clone(),
);
}
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
return this.typeExpr.getLastToken();
}
}
export class StructDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.StructDeclaration;
public typeEnv?: TypeEnv;
public constructor(
2022-09-10 14:11:04 +02:00
public pubKeyword: PubKeyword | null,
public structKeyword: StructKeyword,
2022-09-07 12:45:38 +02:00
public name: IdentifierAlt,
public varExps: Identifier[],
public fields: StructDeclarationField[] | null,
) {
super();
}
public clone(): StructDeclaration {
return new StructDeclaration(
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
this.structKeyword.clone(),
this.name.clone(),
this.varExps.map(ve => ve.clone()),
this.fields !== null ? this.fields.map(field => field.clone()) : null,
);
}
public getFirstToken(): Token {
2022-09-10 14:11:04 +02:00
if (this.pubKeyword !== null) {
return this.pubKeyword;
}
return this.structKeyword;
}
public getLastToken(): Token {
if (this.fields && this.fields.length > 0) {
return this.fields[this.fields.length-1].getLastToken();
}
return this.name;
}
}
export class TypeAssert extends SyntaxBase {
public readonly kind = SyntaxKind.TypeAssert;
public constructor(
public colon: Colon,
public typeExpression: TypeExpression,
) {
super();
}
public clone(): TypeAssert {
return new TypeAssert(
this.colon.clone(),
this.typeExpression.clone(),
);
}
public getFirstToken(): Token {
return this.colon;
}
public getLastToken(): Token {
return this.typeExpression.getLastToken();
}
}
export type Body
= ExprBody
| BlockBody
export class ExprBody extends SyntaxBase {
public readonly kind = SyntaxKind.ExprBody;
public constructor(
public equals: Equals | RArrow,
public expression: Expression,
) {
super();
}
public clone(): ExprBody {
return new ExprBody(
this.equals.clone(),
this.expression.clone(),
);
}
public getFirstToken(): Token {
return this.equals;
}
public getLastToken(): Token {
return this.expression.getLastToken();
}
}
export type LetBodyElement
= LetDeclaration
| Statement
export class BlockBody extends SyntaxBase {
public readonly kind = SyntaxKind.BlockBody;
public constructor(
public blockStart: BlockStart,
public elements: LetBodyElement[],
) {
super();
}
public clone(): BlockBody {
return new BlockBody(
this.blockStart.clone(),
this.elements.map(element => element.clone()),
);
}
public getFirstToken(): Token {
return this.blockStart;
}
public getLastToken(): Token {
if (this.elements.length > 0) {
return this.elements[this.elements.length-1].getLastToken();
}
return this.blockStart;
}
}
export class WrappedOperator extends SyntaxBase {
public readonly kind = SyntaxKind.WrappedOperator;
public constructor(
public lparen: LParen,
public operator: CustomOperator,
public rparen: RParen,
) {
super();
}
public clone(): WrappedOperator {
return new WrappedOperator(
this.lparen.clone(),
this.operator.clone(),
this.rparen.clone(),
);
}
public getFirstToken(): Token {
return this.lparen;
}
public getLastToken(): Token {
return this.rparen;
}
}
export class TypeDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.TypeDeclaration;
public typeEnv?: TypeEnv;
public constructor(
public pubKeyword: PubKeyword | null,
public typeKeyword: TypeKeyword,
public name: IdentifierAlt,
public varExps: Identifier[],
public equals: Equals,
public typeExpression: TypeExpression
) {
super();
}
public clone(): TypeDeclaration {
return new TypeDeclaration(
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
this.typeKeyword.clone(),
this.name.clone(),
this.varExps.map(ve => ve.clone()),
this.equals.clone(),
this.typeExpression.clone(),
);
}
public getFirstToken(): Token {
if (this.pubKeyword !== null) {
return this.pubKeyword;
}
return this.typeKeyword;
}
public getLastToken(): Token {
return this.typeExpression.getLastToken();
}
}
export class LetDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.LetDeclaration;
public scope?: Scope;
public typeEnv?: TypeEnv;
public activeCycle?: boolean;
public context?: InferContext;
public constructor(
public pubKeyword: PubKeyword | null,
public letKeyword: LetKeyword,
public foreignKeyword: ForeignKeyword | null,
public mutKeyword: MutKeyword | null,
public pattern: Pattern | WrappedOperator,
public params: Param[],
public typeAssert: TypeAssert | null,
public body: Body | null,
) {
super();
}
public clone(): LetDeclaration {
return new LetDeclaration(
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
this.letKeyword.clone(),
this.foreignKeyword !== null ? this.foreignKeyword.clone() : null,
this.mutKeyword !== null ? this.mutKeyword.clone() : null,
this.pattern.clone(),
this.params.map(param => param.clone()),
this.typeAssert !== null ? this.typeAssert.clone() : null,
this.body !== null ? this.body.clone() : null,
);
}
public getFirstToken(): Token {
if (this.pubKeyword !== null) {
return this.pubKeyword;
}
return this.letKeyword;
}
public getLastToken(): Token {
if (this.body !== null) {
return this.body.getLastToken();
}
if (this.typeAssert !== null) {
return this.typeAssert.getLastToken();
}
if (this.params.length > 0) {
return this.params[this.params.length-1].getLastToken();
}
return this.pattern.getLastToken();
}
}
export class ImportDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.ImportDeclaration;
public constructor(
public importKeyword: ImportKeyword,
public importSource: StringLiteral,
) {
super();
}
public clone(): ImportDeclaration {
return new ImportDeclaration(
this.importKeyword.clone(),
this.importSource.clone(),
);
}
public getFirstToken(): Token {
return this.importKeyword;
}
public getLastToken(): Token {
return this.importSource;
}
}
export type Declaration
= LetDeclaration
| ImportDeclaration
| StructDeclaration
2022-09-10 14:11:04 +02:00
| EnumDeclaration
| TypeDeclaration
export class Initializer extends SyntaxBase {
public readonly kind = SyntaxKind.Initializer;
public constructor(
public equals: Equals,
public expression: Expression
) {
super();
}
public clone(): Initializer {
return new Initializer(
this.equals.clone(),
this.expression.clone()
);
}
public getFirstToken(): Token {
return this.equals;
}
public getLastToken(): Token {
return this.expression.getLastToken();
}
}
2023-02-03 17:51:27 +01:00
export class ClassConstraint extends SyntaxBase {
public readonly kind = SyntaxKind.ClassConstraint;
public constructor(
public name: IdentifierAlt,
public types: TypeExpression[],
) {
super();
}
public clone(): ClassConstraint {
return new ClassConstraint(
this.name.clone(),
this.types.map(ty => ty.clone()),
);
}
2023-02-03 17:51:27 +01:00
public getFirstToken(): Token {
return this.name;
}
public getLastToken(): Token {
return this.types[this.types.length-1].getLastToken();
}
}
export class ClassConstraintClause extends SyntaxBase {
public readonly kind = SyntaxKind.ClassConstraintClause;
public constructor(
public constraints: ClassConstraint[],
public rarrowAlt: RArrowAlt,
) {
super();
}
public clone(): ClassConstraintClause {
return new ClassConstraintClause(
this.constraints.map(constraint => constraint.clone()),
this.rarrowAlt.clone(),
);
}
2023-02-03 17:51:27 +01:00
public getFirstToken(): Token {
if (this.constraints.length > 0) {
return this.constraints[0].getFirstToken();
}
return this.rarrowAlt;
}
public getLastToken(): Token {
return this.rarrowAlt;
}
}
export type ClassDeclarationElement
= LetDeclaration
| TypeDeclaration
export class ClassDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.ClassDeclaration;
public typeEnv?: TypeEnv;
2023-02-03 17:51:27 +01:00
public constructor(
public pubKeyword: PubKeyword | null,
public classKeyword: ClassKeyword,
public constraintClause: ClassConstraintClause | null,
public name: IdentifierAlt,
public types: VarTypeExpression[],
2023-02-03 17:51:27 +01:00
public elements: ClassDeclarationElement[],
) {
super();
}
public *getSupers(): Iterable<IdentifierAlt> {
if (this.constraintClause !== null) {
for (const constraint of this.constraintClause.constraints) {
yield constraint.name;
}
}
}
2023-02-03 17:51:27 +01:00
public lookup(element: InstanceDeclarationElement): ClassDeclarationElement | null {
switch (element.kind) {
case SyntaxKind.LetDeclaration:
implementationLimitation(element.pattern.kind === SyntaxKind.NamedPattern);
2023-02-03 17:51:27 +01:00
for (const other of this.elements) {
if (other.kind === SyntaxKind.LetDeclaration
&& other.pattern.kind === SyntaxKind.NamedPattern
2023-02-03 17:51:27 +01:00
&& other.pattern.name.text === element.pattern.name.text) {
return other;
}
}
break;
case SyntaxKind.TypeDeclaration:
for (const other of this.elements) {
if (other.kind === SyntaxKind.TypeDeclaration
&& other.name.text === element.name.text) {
return other;
}
}
break;
}
return null;
}
public *getInstances(): Iterable<InstanceDeclaration> {
let curr = this.parent!;
for (;;) {
if (!canHaveInstanceDeclaration(curr)) {
curr = curr.parent!;
}
for (const element of getElements(curr)) {
if (element.kind === SyntaxKind.InstanceDeclaration && element.name.text === this.name.text) {
yield element;
}
}
}
}
public clone(): ClassDeclaration {
return new ClassDeclaration(
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
this.classKeyword.clone(),
this.constraintClause !== null ? this.constraintClause.clone() : null,
this.name.clone(),
this.types.map(t => t.clone()),
this.elements.map(element => element.clone()),
);
}
2023-02-03 17:51:27 +01:00
public getFirstToken(): Token {
if (this.pubKeyword !== null) {
return this.pubKeyword;
}
return this.classKeyword;
}
public getLastToken(): Token {
if (this.elements.length > 0) {
return this.elements[this.elements.length-1].getLastToken();
}
if (this.types.length > 0) {
return this.types[this.types.length-1].getLastToken();
}
return this.name;
2023-02-03 17:51:27 +01:00
}
}
export type InstanceDeclarationElement
= LetDeclaration
| TypeDeclaration
export class InstanceDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.InstanceDeclaration;
public typeEnv?: TypeEnv;
2023-02-03 17:51:27 +01:00
public constructor(
public pubKeyword: PubKeyword | null,
public classKeyword: InstanceKeyword,
public constraintClause: ClassConstraintClause | null,
public name: IdentifierAlt,
public types: TypeExpression[],
2023-02-03 17:51:27 +01:00
public elements: InstanceDeclarationElement[],
) {
super();
}
public clone(): InstanceDeclaration {
return new InstanceDeclaration(
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
this.classKeyword.clone(),
this.constraintClause !== null ? this.constraintClause.clone() : null,
this.name.clone(),
this.types.map(t => t.clone()),
this.elements.map(element => element.clone()),
);
}
2023-02-03 17:51:27 +01:00
public getFirstToken(): Token {
if (this.pubKeyword !== null) {
return this.pubKeyword;
}
return this.classKeyword;
}
public getLastToken(): Token {
if (this.elements.length > 0) {
return this.elements[this.elements.length-1].getLastToken();
}
if (this.types.length > 0) {
return this.types[this.types.length-1].getLastToken();
}
return this.name;
2023-02-03 17:51:27 +01:00
}
}
export class ModuleDeclaration extends SyntaxBase {
public readonly kind = SyntaxKind.ModuleDeclaration;
public typeEnv?: TypeEnv;
2023-02-03 17:51:27 +01:00
public kindEnv?: KindEnv;
public constructor(
public pubKeyword: PubKeyword | null,
public modKeyword: ModKeyword,
public name: IdentifierAlt,
public blockStart: BlockStart,
public elements: SourceFileElement[],
) {
super();
}
public clone(): ModuleDeclaration {
return new ModuleDeclaration(
this.pubKeyword !== null ? this.pubKeyword.clone() : null,
this.modKeyword.clone(),
this.name.clone(),
this.blockStart.clone(),
this.elements.map(element => element.clone())
);
}
public getFirstToken(): Token {
if (this.pubKeyword !== null) {
return this.pubKeyword;
}
return this.modKeyword;
}
public getLastToken(): Token {
if (this.elements.length > 0) {
return this.elements[this.elements.length-1].getLastToken();
}
return this.blockStart;
}
}
export type SourceFileElement
= Statement
| Declaration
2023-02-03 17:51:27 +01:00
| ClassDeclaration
| InstanceDeclaration
| ModuleDeclaration
export class SourceFile extends SyntaxBase {
public readonly kind = SyntaxKind.SourceFile;
public scope?: Scope;
2022-09-07 12:45:38 +02:00
public typeEnv?: TypeEnv;
2023-02-03 17:51:27 +01:00
public kindEnv?: KindEnv;
public constructor(
private file: TextFile,
public elements: SourceFileElement[],
public eof: EndOfFile,
) {
super();
}
public clone(): SourceFile {
return new SourceFile(
this.file,
this.elements.map(element => element.clone()),
this.eof,
);
}
public getFirstToken(): Token {
if (this.elements.length > 0) {
return this.elements[0].getFirstToken();
}
return this.eof;
}
public getLastToken(): Token {
if (this.elements.length > 0) {
return this.elements[this.elements.length-1].getLastToken();
}
return this.eof;
}
public getFile() {
return this.file;
}
}
export function isSyntax(value: any): value is Syntax {
return typeof value === 'object'
&& value !== null
&& value instanceof SyntaxBase;
}
export function isToken(value: any): value is Token {
return typeof value === 'object'
&& value !== null
&& value instanceof TokenBase;
}
export function vistEachChild<T extends Syntax>(node: T, proc: (node: Syntax) => Syntax | undefined): Syntax {
const newArgs = [];
let changed = false;
const traverse = (value: any): any => {
if (Array.isArray(value)) {
const newElements = [];
let changed = false;
for (const element of value) {
const newElement = traverse(element);
if (newElement !== element) {
changed = true;
}
newElements.push(newElement);
}
return changed ? newElements : value;
} else if (isSyntax(value)) {
let newValue = proc(value);
if (newValue === undefined) {
newValue = value;
}
if (newValue !== value) {
changed = true;
}
return newValue;
} else {
return value;
}
}
for (const [_key, value] of node.getFields()) {
newArgs.push(traverse(value));
}
if (!changed) {
return node;
}
return new (node as any).constructor(...newArgs);
}
export function canHaveInstanceDeclaration(node: Syntax): boolean {
return node.kind === SyntaxKind.SourceFile
|| node.kind === SyntaxKind.ModuleDeclaration
|| node.kind === SyntaxKind.LetDeclaration;
}
export function getElements(node: Syntax): Iterable<Syntax> {
switch (node.kind) {
case SyntaxKind.SourceFile:
case SyntaxKind.ModuleDeclaration:
return node.elements;
case SyntaxKind.LetDeclaration:
if (node.body !== null && node.body.kind === SyntaxKind.BlockBody) {
return node.body.elements;
}
// falls through
default:
return [];
}
}