Major update to code and type checker
This commit is contained in:
parent
884be8f9ec
commit
c2d101c25c
14 changed files with 1641 additions and 778 deletions
|
@ -2,7 +2,8 @@
|
||||||
node EndOfFile > BoltToken, JSToken;
|
node EndOfFile > BoltToken, JSToken;
|
||||||
node Token;
|
node Token;
|
||||||
node SourceFile;
|
node SourceFile;
|
||||||
node FunctionBody;
|
node FunctionBodyElement;
|
||||||
|
node ReturnStatement;
|
||||||
|
|
||||||
// Bolt language AST definitions
|
// Bolt language AST definitions
|
||||||
|
|
||||||
|
@ -217,7 +218,7 @@ node BoltConstantExpression > BoltExpression {
|
||||||
|
|
||||||
node BoltStatement > BoltSyntax, BoltFunctionBodyElement, BoltSourceElement;
|
node BoltStatement > BoltSyntax, BoltFunctionBodyElement, BoltSourceElement;
|
||||||
|
|
||||||
node BoltReturnStatement > BoltStatement {
|
node BoltReturnStatement > ReturnStatement, BoltStatement {
|
||||||
value: Option<BoltExpression>,
|
value: Option<BoltExpression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +263,7 @@ node BoltModule > BoltSyntax, BoltSourceElement {
|
||||||
|
|
||||||
node BoltDeclarationLike;
|
node BoltDeclarationLike;
|
||||||
|
|
||||||
node BoltFunctionBodyElement;
|
node BoltFunctionBodyElement > FunctionBodyElement;
|
||||||
|
|
||||||
node BoltFunctionDeclaration > BoltFunctionBodyElement, BoltDeclaration, BoltDeclarationLike {
|
node BoltFunctionDeclaration > BoltFunctionBodyElement, BoltDeclaration, BoltDeclarationLike {
|
||||||
modifiers: BoltModifiers,
|
modifiers: BoltModifiers,
|
||||||
|
@ -467,9 +468,9 @@ node JSReferenceExpression > JSExpression {
|
||||||
|
|
||||||
node JSSourceElement;
|
node JSSourceElement;
|
||||||
|
|
||||||
node JSFunctionBodyElement;
|
node JSFunctionBodyElement > FunctionBodyElement;
|
||||||
|
|
||||||
node JSStatement > JSSourceElement, JSFunctionBodyElement;
|
node JSStatement > JSSyntax, JSSourceElement, JSFunctionBodyElement;
|
||||||
|
|
||||||
node JSCatchBlock > JSSyntax {
|
node JSCatchBlock > JSSyntax {
|
||||||
bindings: Option<JSPattern>,
|
bindings: Option<JSPattern>,
|
||||||
|
@ -495,7 +496,7 @@ node JSConditionalStatement > JSStatement {
|
||||||
cases: Vec<JSConditionalCase>,
|
cases: Vec<JSConditionalCase>,
|
||||||
}
|
}
|
||||||
|
|
||||||
node JSReturnStatement > JSStatement {
|
node JSReturnStatement > ReturnStatement, JSStatement {
|
||||||
value: Option<JSExpression>,
|
value: Option<JSExpression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
344
src/ast.d.ts
vendored
344
src/ast.d.ts
vendored
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import { Type } from "./types"
|
import { TypeRef } from "./types"
|
||||||
import { Diagnostic } from "./diagnostics"
|
import { Diagnostic } from "./diagnostics"
|
||||||
import { Package } from "./common"
|
import { Package } from "./common"
|
||||||
import { TextSpan } from "./text"
|
import { TextSpan } from "./text"
|
||||||
|
@ -13,7 +13,7 @@ export function isSyntax(value: any): value is Syntax;
|
||||||
interface SyntaxBase {
|
interface SyntaxBase {
|
||||||
id: number;
|
id: number;
|
||||||
kind: SyntaxKind;
|
kind: SyntaxKind;
|
||||||
type?: Type;
|
type?: TypeRef;
|
||||||
errors: Diagnostic[]
|
errors: Diagnostic[]
|
||||||
parentNode: Syntax | null;
|
parentNode: Syntax | null;
|
||||||
span: TextSpan | null;
|
span: TextSpan | null;
|
||||||
|
@ -30,7 +30,6 @@ export type ResolveSyntaxKind<K extends SyntaxKind> = Extract<Syntax, { kind: K
|
||||||
export class NodeVisitor {
|
export class NodeVisitor {
|
||||||
public visit(node: Syntax): void;
|
public visit(node: Syntax): void;
|
||||||
protected visitEndOfFile?(node: EndOfFile): void;
|
protected visitEndOfFile?(node: EndOfFile): void;
|
||||||
protected visitFunctionBody?(node: FunctionBody): void;
|
|
||||||
protected visitBoltStringLiteral?(node: BoltStringLiteral): void;
|
protected visitBoltStringLiteral?(node: BoltStringLiteral): void;
|
||||||
protected visitBoltIntegerLiteral?(node: BoltIntegerLiteral): void;
|
protected visitBoltIntegerLiteral?(node: BoltIntegerLiteral): void;
|
||||||
protected visitBoltIdentifier?(node: BoltIdentifier): void;
|
protected visitBoltIdentifier?(node: BoltIdentifier): void;
|
||||||
|
@ -187,158 +186,157 @@ export class NodeVisitor {
|
||||||
|
|
||||||
export const enum SyntaxKind {
|
export const enum SyntaxKind {
|
||||||
EndOfFile = 0,
|
EndOfFile = 0,
|
||||||
FunctionBody = 3,
|
BoltStringLiteral = 7,
|
||||||
BoltStringLiteral = 6,
|
BoltIntegerLiteral = 8,
|
||||||
BoltIntegerLiteral = 7,
|
BoltIdentifier = 10,
|
||||||
BoltIdentifier = 9,
|
BoltOperator = 12,
|
||||||
BoltOperator = 11,
|
BoltAssignment = 13,
|
||||||
BoltAssignment = 12,
|
BoltComma = 14,
|
||||||
BoltComma = 13,
|
BoltSemi = 15,
|
||||||
BoltSemi = 14,
|
BoltColon = 16,
|
||||||
BoltColon = 15,
|
BoltColonColon = 17,
|
||||||
BoltColonColon = 16,
|
BoltDot = 18,
|
||||||
BoltDot = 17,
|
BoltDotDot = 19,
|
||||||
BoltDotDot = 18,
|
BoltRArrow = 20,
|
||||||
BoltRArrow = 19,
|
BoltRArrowAlt = 21,
|
||||||
BoltRArrowAlt = 20,
|
BoltLArrow = 22,
|
||||||
BoltLArrow = 21,
|
BoltEqSign = 23,
|
||||||
BoltEqSign = 22,
|
BoltGtSign = 24,
|
||||||
BoltGtSign = 23,
|
BoltExMark = 25,
|
||||||
BoltExMark = 24,
|
BoltLtSign = 26,
|
||||||
BoltLtSign = 25,
|
BoltVBar = 27,
|
||||||
BoltVBar = 26,
|
BoltWhereKeyword = 29,
|
||||||
BoltWhereKeyword = 28,
|
BoltQuoteKeyword = 30,
|
||||||
BoltQuoteKeyword = 29,
|
BoltFnKeyword = 31,
|
||||||
BoltFnKeyword = 30,
|
BoltForeignKeyword = 32,
|
||||||
BoltForeignKeyword = 31,
|
BoltForKeyword = 33,
|
||||||
BoltForKeyword = 32,
|
BoltLetKeyword = 34,
|
||||||
BoltLetKeyword = 33,
|
BoltReturnKeyword = 35,
|
||||||
BoltReturnKeyword = 34,
|
BoltLoopKeyword = 36,
|
||||||
BoltLoopKeyword = 35,
|
BoltYieldKeyword = 37,
|
||||||
BoltYieldKeyword = 36,
|
BoltMatchKeyword = 38,
|
||||||
BoltMatchKeyword = 37,
|
BoltImportKeyword = 39,
|
||||||
BoltImportKeyword = 38,
|
BoltExportKeyword = 40,
|
||||||
BoltExportKeyword = 39,
|
BoltPubKeyword = 41,
|
||||||
BoltPubKeyword = 40,
|
BoltModKeyword = 42,
|
||||||
BoltModKeyword = 41,
|
BoltMutKeyword = 43,
|
||||||
BoltMutKeyword = 42,
|
BoltEnumKeyword = 44,
|
||||||
BoltEnumKeyword = 43,
|
BoltStructKeyword = 45,
|
||||||
BoltStructKeyword = 44,
|
BoltTypeKeyword = 46,
|
||||||
BoltTypeKeyword = 45,
|
BoltTraitKeyword = 47,
|
||||||
BoltTraitKeyword = 46,
|
BoltImplKeyword = 48,
|
||||||
BoltImplKeyword = 47,
|
BoltParenthesized = 50,
|
||||||
BoltParenthesized = 49,
|
BoltBraced = 51,
|
||||||
BoltBraced = 50,
|
BoltBracketed = 52,
|
||||||
BoltBracketed = 51,
|
BoltSourceFile = 53,
|
||||||
BoltSourceFile = 52,
|
BoltQualName = 54,
|
||||||
BoltQualName = 53,
|
BoltTypeOfExpression = 56,
|
||||||
BoltTypeOfExpression = 55,
|
BoltReferenceTypeExpression = 57,
|
||||||
BoltReferenceTypeExpression = 56,
|
BoltFunctionTypeExpression = 58,
|
||||||
BoltFunctionTypeExpression = 57,
|
BoltLiftedTypeExpression = 59,
|
||||||
BoltLiftedTypeExpression = 58,
|
BoltTypeParameter = 60,
|
||||||
BoltTypeParameter = 59,
|
BoltBindPattern = 62,
|
||||||
BoltBindPattern = 61,
|
BoltTypePattern = 63,
|
||||||
BoltTypePattern = 62,
|
BoltExpressionPattern = 64,
|
||||||
BoltExpressionPattern = 63,
|
BoltTuplePatternElement = 65,
|
||||||
BoltTuplePatternElement = 64,
|
BoltTuplePattern = 66,
|
||||||
BoltTuplePattern = 65,
|
BoltRecordFieldPattern = 67,
|
||||||
BoltRecordFieldPattern = 66,
|
BoltRecordPattern = 68,
|
||||||
BoltRecordPattern = 67,
|
BoltQuoteExpression = 70,
|
||||||
BoltQuoteExpression = 69,
|
BoltTupleExpression = 71,
|
||||||
BoltTupleExpression = 70,
|
BoltReferenceExpression = 72,
|
||||||
BoltReferenceExpression = 71,
|
BoltMemberExpression = 73,
|
||||||
BoltMemberExpression = 72,
|
BoltFunctionExpression = 74,
|
||||||
BoltFunctionExpression = 73,
|
BoltCallExpression = 75,
|
||||||
BoltCallExpression = 74,
|
BoltYieldExpression = 76,
|
||||||
BoltYieldExpression = 75,
|
BoltMatchArm = 77,
|
||||||
BoltMatchArm = 76,
|
BoltMatchExpression = 78,
|
||||||
BoltMatchExpression = 77,
|
BoltCase = 79,
|
||||||
BoltCase = 78,
|
BoltCaseExpression = 80,
|
||||||
BoltCaseExpression = 79,
|
BoltBlockExpression = 81,
|
||||||
BoltBlockExpression = 80,
|
BoltConstantExpression = 82,
|
||||||
BoltConstantExpression = 81,
|
BoltReturnStatement = 84,
|
||||||
BoltReturnStatement = 83,
|
BoltConditionalCase = 85,
|
||||||
BoltConditionalCase = 84,
|
BoltConditionalStatement = 86,
|
||||||
BoltConditionalStatement = 85,
|
BoltResumeStatement = 87,
|
||||||
BoltResumeStatement = 86,
|
BoltExpressionStatement = 88,
|
||||||
BoltExpressionStatement = 87,
|
BoltParameter = 89,
|
||||||
BoltParameter = 88,
|
BoltModule = 93,
|
||||||
BoltModule = 92,
|
BoltFunctionDeclaration = 96,
|
||||||
BoltFunctionDeclaration = 95,
|
BoltVariableDeclaration = 97,
|
||||||
BoltVariableDeclaration = 96,
|
BoltPlainImportSymbol = 99,
|
||||||
BoltPlainImportSymbol = 98,
|
BoltImportDirective = 100,
|
||||||
BoltImportDirective = 99,
|
BoltExportSymbol = 101,
|
||||||
BoltExportSymbol = 100,
|
BoltPlainExportSymbol = 102,
|
||||||
BoltPlainExportSymbol = 101,
|
BoltExportDirective = 103,
|
||||||
BoltExportDirective = 102,
|
BoltTraitDeclaration = 104,
|
||||||
BoltTraitDeclaration = 103,
|
BoltImplDeclaration = 105,
|
||||||
BoltImplDeclaration = 104,
|
BoltTypeAliasDeclaration = 106,
|
||||||
BoltTypeAliasDeclaration = 105,
|
BoltRecordField = 108,
|
||||||
BoltRecordField = 107,
|
BoltRecordDeclaration = 109,
|
||||||
BoltRecordDeclaration = 108,
|
BoltMacroCall = 111,
|
||||||
BoltMacroCall = 110,
|
JSIdentifier = 115,
|
||||||
JSIdentifier = 114,
|
JSString = 116,
|
||||||
JSString = 115,
|
JSInteger = 117,
|
||||||
JSInteger = 116,
|
JSFromKeyword = 118,
|
||||||
JSFromKeyword = 117,
|
JSReturnKeyword = 119,
|
||||||
JSReturnKeyword = 118,
|
JSTryKeyword = 120,
|
||||||
JSTryKeyword = 119,
|
JSFinallyKeyword = 121,
|
||||||
JSFinallyKeyword = 120,
|
JSCatchKeyword = 122,
|
||||||
JSCatchKeyword = 121,
|
JSImportKeyword = 123,
|
||||||
JSImportKeyword = 122,
|
JSAsKeyword = 124,
|
||||||
JSAsKeyword = 123,
|
JSConstKeyword = 125,
|
||||||
JSConstKeyword = 124,
|
JSLetKeyword = 126,
|
||||||
JSLetKeyword = 125,
|
JSExportKeyword = 127,
|
||||||
JSExportKeyword = 126,
|
JSFunctionKeyword = 128,
|
||||||
JSFunctionKeyword = 127,
|
JSWhileKeyword = 129,
|
||||||
JSWhileKeyword = 128,
|
JSForKeyword = 130,
|
||||||
JSForKeyword = 129,
|
JSCloseBrace = 132,
|
||||||
JSCloseBrace = 131,
|
JSCloseBracket = 133,
|
||||||
JSCloseBracket = 132,
|
JSCloseParen = 134,
|
||||||
JSCloseParen = 133,
|
JSOpenBrace = 135,
|
||||||
JSOpenBrace = 134,
|
JSOpenBracket = 136,
|
||||||
JSOpenBracket = 135,
|
JSOpenParen = 137,
|
||||||
JSOpenParen = 136,
|
JSSemi = 138,
|
||||||
JSSemi = 137,
|
JSComma = 139,
|
||||||
JSComma = 138,
|
JSDot = 140,
|
||||||
JSDot = 139,
|
JSDotDotDot = 141,
|
||||||
JSDotDotDot = 140,
|
JSMulOp = 142,
|
||||||
JSMulOp = 141,
|
JSAddOp = 143,
|
||||||
JSAddOp = 142,
|
JSDivOp = 144,
|
||||||
JSDivOp = 143,
|
JSSubOp = 145,
|
||||||
JSSubOp = 144,
|
JSLtOp = 146,
|
||||||
JSLtOp = 145,
|
JSGtOp = 147,
|
||||||
JSGtOp = 146,
|
JSBOrOp = 148,
|
||||||
JSBOrOp = 147,
|
JSBXorOp = 149,
|
||||||
JSBXorOp = 148,
|
JSBAndOp = 150,
|
||||||
JSBAndOp = 149,
|
JSBNotOp = 151,
|
||||||
JSBNotOp = 150,
|
JSNotOp = 152,
|
||||||
JSNotOp = 151,
|
JSBindPattern = 154,
|
||||||
JSBindPattern = 153,
|
JSConstantExpression = 156,
|
||||||
JSConstantExpression = 155,
|
JSMemberExpression = 157,
|
||||||
JSMemberExpression = 156,
|
JSCallExpression = 158,
|
||||||
JSCallExpression = 157,
|
JSBinaryExpression = 159,
|
||||||
JSBinaryExpression = 158,
|
JSUnaryExpression = 160,
|
||||||
JSUnaryExpression = 159,
|
JSNewExpression = 161,
|
||||||
JSNewExpression = 160,
|
JSSequenceExpression = 162,
|
||||||
JSSequenceExpression = 161,
|
JSConditionalExpression = 163,
|
||||||
JSConditionalExpression = 162,
|
JSLiteralExpression = 164,
|
||||||
JSLiteralExpression = 163,
|
JSReferenceExpression = 165,
|
||||||
JSReferenceExpression = 164,
|
JSCatchBlock = 169,
|
||||||
JSCatchBlock = 168,
|
JSTryCatchStatement = 170,
|
||||||
JSTryCatchStatement = 169,
|
JSExpressionStatement = 171,
|
||||||
JSExpressionStatement = 170,
|
JSConditionalCase = 172,
|
||||||
JSConditionalCase = 171,
|
JSConditionalStatement = 173,
|
||||||
JSConditionalStatement = 172,
|
JSReturnStatement = 174,
|
||||||
JSReturnStatement = 173,
|
JSParameter = 175,
|
||||||
JSParameter = 174,
|
JSImportStarBinding = 179,
|
||||||
JSImportStarBinding = 178,
|
JSImportAsBinding = 180,
|
||||||
JSImportAsBinding = 179,
|
JSImportDeclaration = 181,
|
||||||
JSImportDeclaration = 180,
|
JSFunctionDeclaration = 182,
|
||||||
JSFunctionDeclaration = 181,
|
JSArrowFunctionDeclaration = 183,
|
||||||
JSArrowFunctionDeclaration = 182,
|
JSLetDeclaration = 184,
|
||||||
JSLetDeclaration = 183,
|
JSSourceFile = 185,
|
||||||
JSSourceFile = 184,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EndOfFile extends SyntaxBase {
|
export interface EndOfFile extends SyntaxBase {
|
||||||
|
@ -479,20 +477,26 @@ export type SourceFile
|
||||||
| JSSourceFile
|
| JSSourceFile
|
||||||
|
|
||||||
|
|
||||||
export interface FunctionBody extends SyntaxBase {
|
export type FunctionBodyElement
|
||||||
kind: SyntaxKind.FunctionBody;
|
= JSFunctionDeclaration
|
||||||
parentNode: FunctionBodyParent;
|
| JSArrowFunctionDeclaration
|
||||||
getChildNodes(): IterableIterator<FunctionBodyChild>
|
| JSLetDeclaration
|
||||||
}
|
| JSExpressionStatement
|
||||||
|
| JSConditionalStatement
|
||||||
|
| JSReturnStatement
|
||||||
|
| BoltFunctionDeclaration
|
||||||
|
| BoltVariableDeclaration
|
||||||
|
| BoltReturnStatement
|
||||||
|
| BoltConditionalStatement
|
||||||
|
| BoltResumeStatement
|
||||||
|
| BoltExpressionStatement
|
||||||
|
| BoltMacroCall
|
||||||
|
|
||||||
export type FunctionBodyParent
|
|
||||||
= never
|
|
||||||
|
|
||||||
export type FunctionBodyAnyParent
|
export type ReturnStatement
|
||||||
= never
|
= BoltReturnStatement
|
||||||
|
| JSReturnStatement
|
||||||
|
|
||||||
export type FunctionBodyChild
|
|
||||||
= never
|
|
||||||
|
|
||||||
export type BoltSyntax
|
export type BoltSyntax
|
||||||
= BoltSourceFile
|
= BoltSourceFile
|
||||||
|
@ -4980,6 +4984,9 @@ export type JSSyntax
|
||||||
| JSFunctionDeclaration
|
| JSFunctionDeclaration
|
||||||
| JSArrowFunctionDeclaration
|
| JSArrowFunctionDeclaration
|
||||||
| JSLetDeclaration
|
| JSLetDeclaration
|
||||||
|
| JSExpressionStatement
|
||||||
|
| JSConditionalStatement
|
||||||
|
| JSReturnStatement
|
||||||
| JSConstantExpression
|
| JSConstantExpression
|
||||||
| JSMemberExpression
|
| JSMemberExpression
|
||||||
| JSCallExpression
|
| JSCallExpression
|
||||||
|
@ -8015,7 +8022,6 @@ export type JSSourceFileChild
|
||||||
|
|
||||||
export type Syntax
|
export type Syntax
|
||||||
= EndOfFile
|
= EndOfFile
|
||||||
| FunctionBody
|
|
||||||
| BoltStringLiteral
|
| BoltStringLiteral
|
||||||
| BoltIntegerLiteral
|
| BoltIntegerLiteral
|
||||||
| BoltIdentifier
|
| BoltIdentifier
|
||||||
|
@ -8172,7 +8178,6 @@ export type Syntax
|
||||||
export function kindToString(kind: SyntaxKind): string;
|
export function kindToString(kind: SyntaxKind): string;
|
||||||
|
|
||||||
export function createEndOfFile(span?: TextSpan | null): EndOfFile;
|
export function createEndOfFile(span?: TextSpan | null): EndOfFile;
|
||||||
export function createFunctionBody(span?: TextSpan | null): FunctionBody;
|
|
||||||
export function createBoltStringLiteral(value: string, span?: TextSpan | null): BoltStringLiteral;
|
export function createBoltStringLiteral(value: string, span?: TextSpan | null): BoltStringLiteral;
|
||||||
export function createBoltIntegerLiteral(value: bigint, span?: TextSpan | null): BoltIntegerLiteral;
|
export function createBoltIntegerLiteral(value: bigint, span?: TextSpan | null): BoltIntegerLiteral;
|
||||||
export function createBoltIdentifier(text: string, span?: TextSpan | null): BoltIdentifier;
|
export function createBoltIdentifier(text: string, span?: TextSpan | null): BoltIdentifier;
|
||||||
|
@ -8328,7 +8333,8 @@ export function createJSSourceFile(elements: JSSourceElement[], span?: TextSpan
|
||||||
export function isEndOfFile(value: any): value is EndOfFile;
|
export function isEndOfFile(value: any): value is EndOfFile;
|
||||||
export function isToken(value: any): value is Token;
|
export function isToken(value: any): value is Token;
|
||||||
export function isSourceFile(value: any): value is SourceFile;
|
export function isSourceFile(value: any): value is SourceFile;
|
||||||
export function isFunctionBody(value: any): value is FunctionBody;
|
export function isFunctionBodyElement(value: any): value is FunctionBodyElement;
|
||||||
|
export function isReturnStatement(value: any): value is ReturnStatement;
|
||||||
export function isBoltSyntax(value: any): value is BoltSyntax;
|
export function isBoltSyntax(value: any): value is BoltSyntax;
|
||||||
export function isBoltToken(value: any): value is BoltToken;
|
export function isBoltToken(value: any): value is BoltToken;
|
||||||
export function isBoltStringLiteral(value: any): value is BoltStringLiteral;
|
export function isBoltStringLiteral(value: any): value is BoltStringLiteral;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { BoltImportDirective, Syntax, BoltParameter, BoltReferenceExpression, BoltReferenceTypeExpression, BoltSourceFile, BoltCallExpression, BoltReturnKeyword, BoltReturnStatement, SyntaxKind, NodeVisitor, BoltSyntax, BoltIdentifier } from "./ast";
|
import { BoltImportDirective, Syntax, BoltParameter, BoltReferenceExpression, BoltReferenceTypeExpression, BoltSourceFile, BoltCallExpression, BoltReturnKeyword, BoltReturnStatement, SyntaxKind, NodeVisitor, BoltSyntax, BoltIdentifier } from "./ast";
|
||||||
import { Program } from "./program";
|
import { Program } from "./program";
|
||||||
import { DiagnosticPrinter, E_FILE_NOT_FOUND, E_TYPES_NOT_ASSIGNABLE, E_DECLARATION_NOT_FOUND, E_TYPE_DECLARATION_NOT_FOUND, E_MUST_RETURN_A_VALUE, E_MAY_NOT_RETURN_A_VALUE } from "./diagnostics";
|
import { DiagnosticPrinter, E_FILE_NOT_FOUND, E_TYPE_MISMATCH, E_DECLARATION_NOT_FOUND, E_TYPE_DECLARATION_NOT_FOUND, E_MUST_RETURN_A_VALUE, E_MAY_NOT_RETURN_A_VALUE } from "./diagnostics";
|
||||||
import { getSymbolPathFromNode } from "./resolver"
|
import { convertNodeToSymbolPath } from "./resolver"
|
||||||
import { inject } from "./ioc";
|
import { inject } from "./ioc";
|
||||||
import { SymbolResolver, ScopeType } from "./resolver";
|
import { SymbolResolver, ScopeType } from "./resolver";
|
||||||
import { assert, every } from "./util";
|
import { assert, every } from "./util";
|
||||||
|
@ -103,7 +103,7 @@ export class CheckReferences extends NodeVisitor {
|
||||||
this.checkBoltModulePath(node.name, node.name.modulePath);
|
this.checkBoltModulePath(node.name, node.name.modulePath);
|
||||||
const scope = this.resolver.getScopeSurroundingNode(node, ScopeType.Variable);
|
const scope = this.resolver.getScopeSurroundingNode(node, ScopeType.Variable);
|
||||||
assert(scope !== null);
|
assert(scope !== null);
|
||||||
const resolvedSym = this.resolver.resolveSymbolPath(getSymbolPathFromNode(node), scope!);
|
const resolvedSym = this.resolver.resolveSymbolPath(convertNodeToSymbolPath(node), scope!);
|
||||||
if (resolvedSym === null) {
|
if (resolvedSym === null) {
|
||||||
this.diagnostics.add({
|
this.diagnostics.add({
|
||||||
message: E_DECLARATION_NOT_FOUND,
|
message: E_DECLARATION_NOT_FOUND,
|
||||||
|
@ -117,7 +117,7 @@ export class CheckReferences extends NodeVisitor {
|
||||||
protected visitBoltReferenceTypeExpression(node: BoltReferenceTypeExpression) {
|
protected visitBoltReferenceTypeExpression(node: BoltReferenceTypeExpression) {
|
||||||
const scope = this.resolver.getScopeSurroundingNode(node, ScopeType.Type);
|
const scope = this.resolver.getScopeSurroundingNode(node, ScopeType.Type);
|
||||||
assert(scope !== null);
|
assert(scope !== null);
|
||||||
const symbolPath = getSymbolPathFromNode(node.name);
|
const symbolPath = convertNodeToSymbolPath(node.name);
|
||||||
const resolvedSym = this.resolver.resolveSymbolPath(symbolPath, scope!);
|
const resolvedSym = this.resolver.resolveSymbolPath(symbolPath, scope!);
|
||||||
if (resolvedSym === null) {
|
if (resolvedSym === null) {
|
||||||
this.diagnostics.add({
|
this.diagnostics.add({
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {FastStringMap, enumerate, escapeChar, assert} from "./util";
|
||||||
import {TextSpan, TextPos, TextFile} from "./text";
|
import {TextSpan, TextPos, TextFile} from "./text";
|
||||||
import {Scanner} from "./scanner";
|
import {Scanner} from "./scanner";
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
|
import { convertNodeToSymbolPath } from "./resolver";
|
||||||
|
|
||||||
export function getSourceFile(node: Syntax) {
|
export function getSourceFile(node: Syntax) {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -249,6 +250,23 @@ export function isExported(node: Syntax) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getFullyQualifiedPathToNode(node: Syntax) {
|
||||||
|
const symbolPath = convertNodeToSymbolPath(node);
|
||||||
|
while (true) {
|
||||||
|
const parentNode = node.parentNode;
|
||||||
|
if (parentNode === null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = parentNode;
|
||||||
|
if (node.kind === SyntaxKind.BoltModule) {
|
||||||
|
for (const element of node.name) {
|
||||||
|
symbolPath.modulePath.unshift(element.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return symbolPath;
|
||||||
|
}
|
||||||
|
|
||||||
export function describeKind(kind: SyntaxKind): string {
|
export function describeKind(kind: SyntaxKind): string {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SyntaxKind.BoltImportKeyword:
|
case SyntaxKind.BoltImportKeyword:
|
||||||
|
@ -388,3 +406,39 @@ export function describeKind(kind: SyntaxKind): string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function *getAllReturnStatementsInFunctionBody(body: FunctionBody): IterableIterator<ReturnStatement> {
|
||||||
|
for (const element of body) {
|
||||||
|
switch (element.kind) {
|
||||||
|
case SyntaxKind.BoltReturnStatement:
|
||||||
|
case SyntaxKind.JSReturnStatement:
|
||||||
|
{
|
||||||
|
yield element;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SyntaxKind.BoltConditionalStatement:
|
||||||
|
{
|
||||||
|
for (const caseNode of element.cases) {
|
||||||
|
yield* getAllReturnStatementsInFunctionBody(caseNode.body);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SyntaxKind.JSTryCatchStatement:
|
||||||
|
{
|
||||||
|
yield* getAllReturnStatementsInFunctionBody(element.tryBlock)
|
||||||
|
if (element.catchBlock !== null) {
|
||||||
|
yield* getAllReturnStatementsInFunctionBody(element.catchBlock.elements)
|
||||||
|
}
|
||||||
|
if (element.finalBlock !== null) {
|
||||||
|
yield* getAllReturnStatementsInFunctionBody(element.finalBlock)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SyntaxKind.JSExpressionStatement:
|
||||||
|
case SyntaxKind.BoltExpressionStatement:
|
||||||
|
case SyntaxKind.JSImportDeclaration:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`I did not know how to find return statements in ${kindToString(element.kind)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const E_FIELD_NOT_PRESENT = "Field '{name}' is not present."
|
||||||
export const E_FIELD_MUST_BE_BOOLEAN = "Field '{name}' must be a either 'true' or 'false'."
|
export const E_FIELD_MUST_BE_BOOLEAN = "Field '{name}' must be a either 'true' or 'false'."
|
||||||
export const E_TYPE_DECLARATION_NOT_FOUND = "A type declaration named '{name}' was not found."
|
export const E_TYPE_DECLARATION_NOT_FOUND = "A type declaration named '{name}' was not found."
|
||||||
export const E_DECLARATION_NOT_FOUND = "Reference to an undefined declaration '{name}'.";
|
export const E_DECLARATION_NOT_FOUND = "Reference to an undefined declaration '{name}'.";
|
||||||
export const E_TYPES_NOT_ASSIGNABLE = "Types {left} and {right} are not assignable.";
|
export const E_TYPE_MISMATCH = "Types {left} and {right} are not semantically equivalent.";
|
||||||
export const E_TOO_FEW_ARGUMENTS_FOR_FUNCTION_CALL = "Too few arguments for function call. Expected {expected} but got {actual}.";
|
export const E_TOO_FEW_ARGUMENTS_FOR_FUNCTION_CALL = "Too few arguments for function call. Expected {expected} but got {actual}.";
|
||||||
export const E_TOO_MANY_ARGUMENTS_FOR_FUNCTION_CALL = "Too many arguments for function call. Expected {expected} but got {actual}.";
|
export const E_TOO_MANY_ARGUMENTS_FOR_FUNCTION_CALL = "Too many arguments for function call. Expected {expected} but got {actual}.";
|
||||||
export const E_CANDIDATE_FUNCTION_REQUIRES_THIS_PARAMETER = "Candidate function requires this parameter."
|
export const E_CANDIDATE_FUNCTION_REQUIRES_THIS_PARAMETER = "Candidate function requires this parameter."
|
||||||
|
@ -24,6 +24,7 @@ export const E_TYPES_MISSING_MEMBER = "Not all types resolve to a record with th
|
||||||
export const E_NODE_DOES_NOT_CONTAIN_MEMBER = "This node does not contain the the member '{name}'."
|
export const E_NODE_DOES_NOT_CONTAIN_MEMBER = "This node does not contain the the member '{name}'."
|
||||||
export const E_MAY_NOT_RETURN_BECAUSE_TYPE_RESOLVES_TO_VOID = "May not return a value because the function's return type resolves to '()'"
|
export const E_MAY_NOT_RETURN_BECAUSE_TYPE_RESOLVES_TO_VOID = "May not return a value because the function's return type resolves to '()'"
|
||||||
export const E_MUST_RETURN_BECAUSE_TYPE_DOES_NOT_RESOLVE_TO_VOID = "Must return a value because the function's return type does not resolve to '()'"
|
export const E_MUST_RETURN_BECAUSE_TYPE_DOES_NOT_RESOLVE_TO_VOID = "Must return a value because the function's return type does not resolve to '()'"
|
||||||
|
export const E_ARGUMENT_TYPE_NOT_ASSIGNABLE = "This argument's type is not assignable to the function's parameter type."
|
||||||
|
|
||||||
const BOLT_HARD_ERRORS = process.env['BOLT_HARD_ERRORS']
|
const BOLT_HARD_ERRORS = process.env['BOLT_HARD_ERRORS']
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ export class Evaluator {
|
||||||
case SyntaxKind.BoltTypePattern:
|
case SyntaxKind.BoltTypePattern:
|
||||||
{
|
{
|
||||||
const expectedType = this.checker.getTypeOfNode(node.type);
|
const expectedType = this.checker.getTypeOfNode(node.type);
|
||||||
if (!this.checker.isTypeAssignableTo(expectedType, this.checker.getTypeOfValue(value))) {
|
if (!this.checker.isTypeAssignableTo(expectedType, this.checker.createTypeForValue(value))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -98,6 +98,7 @@ export class Frontend {
|
||||||
for (const sourceFile of program.getAllSourceFiles()) {
|
for (const sourceFile of program.getAllSourceFiles()) {
|
||||||
checker.registerSourceFile(sourceFile);
|
checker.registerSourceFile(sourceFile);
|
||||||
}
|
}
|
||||||
|
checker.solve(program.getAllSourceFiles());
|
||||||
for (const pkg of program.getAllPackages()) {
|
for (const pkg of program.getAllPackages()) {
|
||||||
if (!pkg.isDependency) {
|
if (!pkg.isDependency) {
|
||||||
for (const sourceFile of pkg.getAllSourceFiles()) {
|
for (const sourceFile of pkg.getAllSourceFiles()) {
|
||||||
|
|
|
@ -9,25 +9,49 @@ const GLOBAL_SCOPE_ID = 'global';
|
||||||
export class SymbolPath {
|
export class SymbolPath {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private parents: string[],
|
public modulePath: string[],
|
||||||
public isAbsolute: boolean,
|
public isAbsolute: boolean,
|
||||||
public name: string
|
public name: string
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasParents(): boolean {
|
public encode(): string {
|
||||||
return this.parents.length > 0;
|
let out = '';
|
||||||
|
if (this.isAbsolute) {
|
||||||
|
out += '::'
|
||||||
|
}
|
||||||
|
for (const element of this.modulePath) {
|
||||||
|
out += element + '::'
|
||||||
|
}
|
||||||
|
out += this.name;
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getParents() {
|
public hasModulePath(): boolean {
|
||||||
return this.parents;
|
return this.modulePath.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getModulePath() {
|
||||||
|
return this.modulePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSymbolPathFromNode(node: BoltSyntax): SymbolPath {
|
export function convertNodeToSymbolPath(node: Syntax): SymbolPath {
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
case SyntaxKind.BoltRecordDeclaration:
|
||||||
|
return new SymbolPath(
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
node.name.text,
|
||||||
|
);
|
||||||
|
case SyntaxKind.BoltFunctionDeclaration:
|
||||||
|
return new SymbolPath(
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
emitNode(node.name),
|
||||||
|
);
|
||||||
case SyntaxKind.BoltReferenceExpression:
|
case SyntaxKind.BoltReferenceExpression:
|
||||||
return new SymbolPath(
|
return new SymbolPath(
|
||||||
node.name.modulePath.map(id => id.text),
|
node.name.modulePath.map(id => id.text),
|
||||||
|
@ -42,14 +66,8 @@ export function getSymbolPathFromNode(node: BoltSyntax): SymbolPath {
|
||||||
return new SymbolPath([], false, name);
|
return new SymbolPath([], false, name);
|
||||||
}
|
}
|
||||||
return new SymbolPath(node.modulePath.map(id => id.text), false, name);
|
return new SymbolPath(node.modulePath.map(id => id.text), false, name);
|
||||||
//case SyntaxKind.BoltModulePath:
|
|
||||||
// return new SymbolPath(
|
|
||||||
// node.elements.slice(0, -1).map(el => el.text),
|
|
||||||
// node.isAbsolute,
|
|
||||||
// node.elements[node.elements.length-1].text
|
|
||||||
// );
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Could not extract a symbol path from the given node.`);
|
throw new Error(`Could not extract a symbol path from node ${kindToString(node.kind)}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +406,7 @@ export class SymbolResolver {
|
||||||
for (const scopeType of getAllSymbolKinds()) {
|
for (const scopeType of getAllSymbolKinds()) {
|
||||||
const scope = this.getScopeForNode(importDir, scopeType);
|
const scope = this.getScopeForNode(importDir, scopeType);
|
||||||
assert(scope !== null);
|
assert(scope !== null);
|
||||||
const exported = this.resolveSymbolPath(getSymbolPathFromNode(importSymbol), scope!);
|
const exported = this.resolveSymbolPath(convertNodeToSymbolPath(importSymbol), scope!);
|
||||||
if (exported !== null) {
|
if (exported !== null) {
|
||||||
for (const decl of exported.declarations) {
|
for (const decl of exported.declarations) {
|
||||||
scope!.addNodeAsSymbol(this.strategy.getSymbolName(decl), decl);
|
scope!.addNodeAsSymbol(this.strategy.getSymbolName(decl), decl);
|
||||||
|
@ -491,16 +509,17 @@ export class SymbolResolver {
|
||||||
return scope.getSymbol(this.strategy.getSymbolName(node));
|
return scope.getSymbol(this.strategy.getSymbolName(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
public resolveGlobalSymbol(name: string, kind: ScopeType) {
|
public resolveGlobalSymbol(path: SymbolPath, kind: ScopeType) {
|
||||||
const symbolPath = new SymbolPath([], true, name);
|
|
||||||
for (const sourceFile of this.program.getAllGloballyDeclaredSourceFiles()) {
|
for (const sourceFile of this.program.getAllGloballyDeclaredSourceFiles()) {
|
||||||
const scope = this.getScopeForNode(sourceFile, kind);
|
const scope = this.getScopeForNode(sourceFile, kind);
|
||||||
if (scope === null) {
|
assert(scope !== null);
|
||||||
|
const modScope = this.resolveModulePath(path.getModulePath(), scope!);
|
||||||
|
if (modScope === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const sym = scope.getLocalSymbol(name);
|
const sym = modScope?.getLocalSymbol(path.name)
|
||||||
if (sym !== null) {
|
if (sym !== null) {
|
||||||
return sym
|
return sym;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -508,7 +527,7 @@ export class SymbolResolver {
|
||||||
|
|
||||||
public resolveSymbolPath(path: SymbolPath, scope: Scope): SymbolInfo | null {
|
public resolveSymbolPath(path: SymbolPath, scope: Scope): SymbolInfo | null {
|
||||||
|
|
||||||
if (path.hasParents()) {
|
if (path.hasModulePath()) {
|
||||||
|
|
||||||
if (path.isAbsolute) {
|
if (path.isAbsolute) {
|
||||||
|
|
||||||
|
@ -517,7 +536,7 @@ export class SymbolResolver {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Perform the acutal module resolution.
|
// Perform the acutal module resolution.
|
||||||
const resolvedScope = this.resolveModulePath(path.getParents(), scope);
|
const resolvedScope = this.resolveModulePath(path.getModulePath(), scope);
|
||||||
|
|
||||||
// Failing to find any module means that we cannot continue, because
|
// Failing to find any module means that we cannot continue, because
|
||||||
// it does not make sense to get the symbol of a non-existent module.
|
// it does not make sense to get the symbol of a non-existent module.
|
||||||
|
@ -533,7 +552,11 @@ export class SymbolResolver {
|
||||||
// Once we've handled any module path that might have been present,
|
// Once we've handled any module path that might have been present,
|
||||||
// we resolve the actual symbol using a helper method.
|
// we resolve the actual symbol using a helper method.
|
||||||
|
|
||||||
return scope.getSymbol(path.name);
|
const sym = scope.getSymbol(path.name);
|
||||||
|
if (sym !== null) {
|
||||||
|
return sym
|
||||||
|
}
|
||||||
|
return this.resolveGlobalSymbol(path, scope.kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
18
src/test/types.ts
Normal file
18
src/test/types.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
import { assert } from "chai"
|
||||||
|
import { AnyType, simplifyType, UnionType } from "../types"
|
||||||
|
import { createBoltIdentifier } from "../ast";
|
||||||
|
import { type } from "os";
|
||||||
|
|
||||||
|
describe('a function that merges two equivalent types', () => {
|
||||||
|
|
||||||
|
it('can merge two any types', () =>{
|
||||||
|
const type1 = new AnyType;
|
||||||
|
type1.node = createBoltIdentifier('a');
|
||||||
|
const type2 = new AnyType;
|
||||||
|
type2.node = createBoltIdentifier('b');
|
||||||
|
const types = new UnionType([type1 type2]);
|
||||||
|
mergeTypes(types);
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
|
@ -18,7 +18,7 @@ const nodeProto = {
|
||||||
|
|
||||||
*getChildNodes() {
|
*getChildNodes() {
|
||||||
for (const key of Object.keys(this)) {
|
for (const key of Object.keys(this)) {
|
||||||
if (key === 'span' || key === 'parentNode') {
|
if (key === 'span' || key === 'parentNode' || key === 'type') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const value = this[key];
|
const value = this[key];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import { Type } from "./types"
|
import { TypeRef } from "./types"
|
||||||
import { Diagnostic } from "./diagnostics"
|
import { Diagnostic } from "./diagnostics"
|
||||||
import { Package } from "./common"
|
import { Package } from "./common"
|
||||||
import { TextSpan } from "./text"
|
import { TextSpan } from "./text"
|
||||||
|
@ -13,7 +13,7 @@ export function isSyntax(value: any): value is Syntax;
|
||||||
interface SyntaxBase {
|
interface SyntaxBase {
|
||||||
id: number;
|
id: number;
|
||||||
kind: SyntaxKind;
|
kind: SyntaxKind;
|
||||||
type?: Type;
|
type?: TypeRef;
|
||||||
errors: Diagnostic[]
|
errors: Diagnostic[]
|
||||||
parentNode: Syntax | null;
|
parentNode: Syntax | null;
|
||||||
span: TextSpan | null;
|
span: TextSpan | null;
|
||||||
|
|
|
@ -58,7 +58,7 @@ export function generateAST(decls: Declaration[]) {
|
||||||
jsFile.write(`index: ${decl.index},\n`);
|
jsFile.write(`index: ${decl.index},\n`);
|
||||||
jsFile.write(`parents: [`);
|
jsFile.write(`parents: [`);
|
||||||
for (const parentName of getParentChain(decl.name)) {
|
for (const parentName of getParentChain(decl.name)) {
|
||||||
jsFile.write(`'${decl.name}', `)
|
jsFile.write(`'${parentName}', `)
|
||||||
}
|
}
|
||||||
jsFile.write(`'Syntax'],\n`);
|
jsFile.write(`'Syntax'],\n`);
|
||||||
jsFile.write(`fields: new Map([\n`);
|
jsFile.write(`fields: new Map([\n`);
|
||||||
|
@ -359,7 +359,7 @@ export function generateAST(decls: Declaration[]) {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
function *getParentChain(nodeName: string) {
|
function *getParentChain(nodeName: string): IterableIterator<string> {
|
||||||
const stack = [ nodeName ];
|
const stack = [ nodeName ];
|
||||||
while (stack.length > 0) {
|
while (stack.length > 0) {
|
||||||
const nodeDecl = getDeclarationNamed(stack.pop()!) as NodeDeclaration;
|
const nodeDecl = getDeclarationNamed(stack.pop()!) as NodeDeclaration;
|
||||||
|
|
1653
src/types.ts
1653
src/types.ts
File diff suppressed because it is too large
Load diff
144
src/util.ts
144
src/util.ts
|
@ -6,6 +6,7 @@ import * as os from "os"
|
||||||
import moment from "moment"
|
import moment from "moment"
|
||||||
import chalk from "chalk"
|
import chalk from "chalk"
|
||||||
import { LOG_DATETIME_FORMAT } from "./constants"
|
import { LOG_DATETIME_FORMAT } from "./constants"
|
||||||
|
import { E_CANDIDATE_FUNCTION_REQUIRES_THIS_PARAMETER } from "./diagnostics"
|
||||||
|
|
||||||
export function isPowerOf(x: number, n: number):boolean {
|
export function isPowerOf(x: number, n: number):boolean {
|
||||||
const a = Math.log(x) / Math.log(n);
|
const a = Math.log(x) / Math.log(n);
|
||||||
|
@ -39,6 +40,53 @@ export function every<T>(iterator: Iterator<T>, pred: (value: T) => boolean): bo
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* filter<T>(iterator: Iterator<T>, pred: (value: T) => boolean): IterableIterator<T> {
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = iterator.next();
|
||||||
|
if (done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pred(value)) {
|
||||||
|
yield value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* map<T, R>(iterator: Iterator<T>, func: (value: T) => R): IterableIterator<R> {
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = iterator.next();
|
||||||
|
if (done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
yield func(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* flatMap<T, R>(iterator: Iterator<T>, func: (value: T) => IterableIterator<R>): IterableIterator<R> {
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = iterator.next();
|
||||||
|
if (done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (const element of func(value)) {
|
||||||
|
yield element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function comparator<T>(pred: (a: T, b: T) => boolean): (a: T, b: T) => number {
|
||||||
|
return function (a, b) {
|
||||||
|
if (pred(a, b)) {
|
||||||
|
return 1;
|
||||||
|
} else if (pred(b, a)) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function assert(test: boolean): void {
|
export function assert(test: boolean): void {
|
||||||
if (!test) {
|
if (!test) {
|
||||||
throw new Error(`Invariant violation: an internal sanity check failed.`);
|
throw new Error(`Invariant violation: an internal sanity check failed.`);
|
||||||
|
@ -131,6 +179,102 @@ export function prettyPrint(value: any): string {
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TransparentProxy<T> = T & { updateHandle(value: T): void }
|
||||||
|
|
||||||
|
export function createTransparentProxy<T extends object>(value: T): TransparentProxy<T> {
|
||||||
|
const handlerObject = {
|
||||||
|
__HANDLE: value,
|
||||||
|
__IS_HANDLE: true,
|
||||||
|
updateHandle(newValue: T) {
|
||||||
|
if (newValue.__IS_HANDLE) {
|
||||||
|
newValue = newValue.__HANDLE;
|
||||||
|
}
|
||||||
|
value = newValue;
|
||||||
|
handlerObject.__HANDLE = newValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new Proxy<any>({}, {
|
||||||
|
getPrototypeOf(target: T): object | null {
|
||||||
|
return Reflect.getPrototypeOf(value);
|
||||||
|
},
|
||||||
|
setPrototypeOf(target: T, v: any): boolean {
|
||||||
|
return Reflect.setPrototypeOf(value, v);
|
||||||
|
},
|
||||||
|
isExtensible(target: T): boolean {
|
||||||
|
return Reflect.isExtensible(value);
|
||||||
|
},
|
||||||
|
preventExtensions(target: T): boolean {
|
||||||
|
return Reflect.preventExtensions(value);
|
||||||
|
},
|
||||||
|
getOwnPropertyDescriptor(target: T, p: PropertyKey): PropertyDescriptor | undefined {
|
||||||
|
return Reflect.getOwnPropertyDescriptor(value, p);
|
||||||
|
},
|
||||||
|
has(target: T, p: PropertyKey): boolean {
|
||||||
|
return Reflect.has(value, p);
|
||||||
|
},
|
||||||
|
get(target: T, p: PropertyKey, receiver: any): any {
|
||||||
|
if (hasOwnProperty(handlerObject, p)) {
|
||||||
|
return Reflect.get(handlerObject, p);
|
||||||
|
}
|
||||||
|
return Reflect.get(value, p, receiver)
|
||||||
|
},
|
||||||
|
set(target: T, p: PropertyKey, value: any, receiver: any): boolean {
|
||||||
|
return Reflect.set(value, p, value);
|
||||||
|
},
|
||||||
|
deleteProperty(target: T, p: PropertyKey): boolean {
|
||||||
|
return Reflect.deleteProperty(value, p);
|
||||||
|
},
|
||||||
|
defineProperty(target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean {
|
||||||
|
return Reflect.defineProperty(value, p, attributes);
|
||||||
|
},
|
||||||
|
enumerate(target: T): PropertyKey[] {
|
||||||
|
return [...Reflect.enumerate(value)];
|
||||||
|
},
|
||||||
|
ownKeys(target: T): PropertyKey[] {
|
||||||
|
return Reflect.ownKeys(value);
|
||||||
|
},
|
||||||
|
apply(target: T, thisArg: any, argArray?: any): any {
|
||||||
|
return Reflect.apply(value as any, thisArg, argArray);
|
||||||
|
},
|
||||||
|
construct(target: T, argArray: any, newTarget?: any): object {
|
||||||
|
return Reflect.construct(value as any, argArray, newTarget);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getKeyTag = Symbol('get key of object');
|
||||||
|
|
||||||
|
function getKey(value: any): string {
|
||||||
|
if (typeof(value) === 'string') {
|
||||||
|
return value;
|
||||||
|
} else if (typeof(value) === 'number') {
|
||||||
|
return value.toString();
|
||||||
|
} else if (isObjectLike(value) && hasOwnProperty(value, getKeyTag)) {
|
||||||
|
return value[getKeyTag]();
|
||||||
|
} else {
|
||||||
|
throw new Error(`Could not calculate a key for ${value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FastMultiMap<K, V> {
|
||||||
|
|
||||||
|
private mapping = Object.create(null);
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.mapping = Object.create(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public add(key: K, value: V) {
|
||||||
|
const keyStr = getKey(key);
|
||||||
|
if (keyStr in this.mapping) {
|
||||||
|
this.mapping[keyStr].push(keyStr);
|
||||||
|
} else {
|
||||||
|
this.mapping[keyStr] = [ value ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class FastStringMap<K extends PropertyKey, V> {
|
export class FastStringMap<K extends PropertyKey, V> {
|
||||||
|
|
||||||
private mapping = Object.create(null);
|
private mapping = Object.create(null);
|
||||||
|
|
Loading…
Reference in a new issue