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 Token;
|
||||
node SourceFile;
|
||||
node FunctionBody;
|
||||
node FunctionBodyElement;
|
||||
node ReturnStatement;
|
||||
|
||||
// Bolt language AST definitions
|
||||
|
||||
|
@ -217,7 +218,7 @@ node BoltConstantExpression > BoltExpression {
|
|||
|
||||
node BoltStatement > BoltSyntax, BoltFunctionBodyElement, BoltSourceElement;
|
||||
|
||||
node BoltReturnStatement > BoltStatement {
|
||||
node BoltReturnStatement > ReturnStatement, BoltStatement {
|
||||
value: Option<BoltExpression>,
|
||||
}
|
||||
|
||||
|
@ -262,7 +263,7 @@ node BoltModule > BoltSyntax, BoltSourceElement {
|
|||
|
||||
node BoltDeclarationLike;
|
||||
|
||||
node BoltFunctionBodyElement;
|
||||
node BoltFunctionBodyElement > FunctionBodyElement;
|
||||
|
||||
node BoltFunctionDeclaration > BoltFunctionBodyElement, BoltDeclaration, BoltDeclarationLike {
|
||||
modifiers: BoltModifiers,
|
||||
|
@ -467,9 +468,9 @@ node JSReferenceExpression > JSExpression {
|
|||
|
||||
node JSSourceElement;
|
||||
|
||||
node JSFunctionBodyElement;
|
||||
node JSFunctionBodyElement > FunctionBodyElement;
|
||||
|
||||
node JSStatement > JSSourceElement, JSFunctionBodyElement;
|
||||
node JSStatement > JSSyntax, JSSourceElement, JSFunctionBodyElement;
|
||||
|
||||
node JSCatchBlock > JSSyntax {
|
||||
bindings: Option<JSPattern>,
|
||||
|
@ -495,7 +496,7 @@ node JSConditionalStatement > JSStatement {
|
|||
cases: Vec<JSConditionalCase>,
|
||||
}
|
||||
|
||||
node JSReturnStatement > JSStatement {
|
||||
node JSReturnStatement > ReturnStatement, JSStatement {
|
||||
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 { Package } from "./common"
|
||||
import { TextSpan } from "./text"
|
||||
|
@ -13,7 +13,7 @@ export function isSyntax(value: any): value is Syntax;
|
|||
interface SyntaxBase {
|
||||
id: number;
|
||||
kind: SyntaxKind;
|
||||
type?: Type;
|
||||
type?: TypeRef;
|
||||
errors: Diagnostic[]
|
||||
parentNode: Syntax | null;
|
||||
span: TextSpan | null;
|
||||
|
@ -30,7 +30,6 @@ export type ResolveSyntaxKind<K extends SyntaxKind> = Extract<Syntax, { kind: K
|
|||
export class NodeVisitor {
|
||||
public visit(node: Syntax): void;
|
||||
protected visitEndOfFile?(node: EndOfFile): void;
|
||||
protected visitFunctionBody?(node: FunctionBody): void;
|
||||
protected visitBoltStringLiteral?(node: BoltStringLiteral): void;
|
||||
protected visitBoltIntegerLiteral?(node: BoltIntegerLiteral): void;
|
||||
protected visitBoltIdentifier?(node: BoltIdentifier): void;
|
||||
|
@ -187,158 +186,157 @@ export class NodeVisitor {
|
|||
|
||||
export const enum SyntaxKind {
|
||||
EndOfFile = 0,
|
||||
FunctionBody = 3,
|
||||
BoltStringLiteral = 6,
|
||||
BoltIntegerLiteral = 7,
|
||||
BoltIdentifier = 9,
|
||||
BoltOperator = 11,
|
||||
BoltAssignment = 12,
|
||||
BoltComma = 13,
|
||||
BoltSemi = 14,
|
||||
BoltColon = 15,
|
||||
BoltColonColon = 16,
|
||||
BoltDot = 17,
|
||||
BoltDotDot = 18,
|
||||
BoltRArrow = 19,
|
||||
BoltRArrowAlt = 20,
|
||||
BoltLArrow = 21,
|
||||
BoltEqSign = 22,
|
||||
BoltGtSign = 23,
|
||||
BoltExMark = 24,
|
||||
BoltLtSign = 25,
|
||||
BoltVBar = 26,
|
||||
BoltWhereKeyword = 28,
|
||||
BoltQuoteKeyword = 29,
|
||||
BoltFnKeyword = 30,
|
||||
BoltForeignKeyword = 31,
|
||||
BoltForKeyword = 32,
|
||||
BoltLetKeyword = 33,
|
||||
BoltReturnKeyword = 34,
|
||||
BoltLoopKeyword = 35,
|
||||
BoltYieldKeyword = 36,
|
||||
BoltMatchKeyword = 37,
|
||||
BoltImportKeyword = 38,
|
||||
BoltExportKeyword = 39,
|
||||
BoltPubKeyword = 40,
|
||||
BoltModKeyword = 41,
|
||||
BoltMutKeyword = 42,
|
||||
BoltEnumKeyword = 43,
|
||||
BoltStructKeyword = 44,
|
||||
BoltTypeKeyword = 45,
|
||||
BoltTraitKeyword = 46,
|
||||
BoltImplKeyword = 47,
|
||||
BoltParenthesized = 49,
|
||||
BoltBraced = 50,
|
||||
BoltBracketed = 51,
|
||||
BoltSourceFile = 52,
|
||||
BoltQualName = 53,
|
||||
BoltTypeOfExpression = 55,
|
||||
BoltReferenceTypeExpression = 56,
|
||||
BoltFunctionTypeExpression = 57,
|
||||
BoltLiftedTypeExpression = 58,
|
||||
BoltTypeParameter = 59,
|
||||
BoltBindPattern = 61,
|
||||
BoltTypePattern = 62,
|
||||
BoltExpressionPattern = 63,
|
||||
BoltTuplePatternElement = 64,
|
||||
BoltTuplePattern = 65,
|
||||
BoltRecordFieldPattern = 66,
|
||||
BoltRecordPattern = 67,
|
||||
BoltQuoteExpression = 69,
|
||||
BoltTupleExpression = 70,
|
||||
BoltReferenceExpression = 71,
|
||||
BoltMemberExpression = 72,
|
||||
BoltFunctionExpression = 73,
|
||||
BoltCallExpression = 74,
|
||||
BoltYieldExpression = 75,
|
||||
BoltMatchArm = 76,
|
||||
BoltMatchExpression = 77,
|
||||
BoltCase = 78,
|
||||
BoltCaseExpression = 79,
|
||||
BoltBlockExpression = 80,
|
||||
BoltConstantExpression = 81,
|
||||
BoltReturnStatement = 83,
|
||||
BoltConditionalCase = 84,
|
||||
BoltConditionalStatement = 85,
|
||||
BoltResumeStatement = 86,
|
||||
BoltExpressionStatement = 87,
|
||||
BoltParameter = 88,
|
||||
BoltModule = 92,
|
||||
BoltFunctionDeclaration = 95,
|
||||
BoltVariableDeclaration = 96,
|
||||
BoltPlainImportSymbol = 98,
|
||||
BoltImportDirective = 99,
|
||||
BoltExportSymbol = 100,
|
||||
BoltPlainExportSymbol = 101,
|
||||
BoltExportDirective = 102,
|
||||
BoltTraitDeclaration = 103,
|
||||
BoltImplDeclaration = 104,
|
||||
BoltTypeAliasDeclaration = 105,
|
||||
BoltRecordField = 107,
|
||||
BoltRecordDeclaration = 108,
|
||||
BoltMacroCall = 110,
|
||||
JSIdentifier = 114,
|
||||
JSString = 115,
|
||||
JSInteger = 116,
|
||||
JSFromKeyword = 117,
|
||||
JSReturnKeyword = 118,
|
||||
JSTryKeyword = 119,
|
||||
JSFinallyKeyword = 120,
|
||||
JSCatchKeyword = 121,
|
||||
JSImportKeyword = 122,
|
||||
JSAsKeyword = 123,
|
||||
JSConstKeyword = 124,
|
||||
JSLetKeyword = 125,
|
||||
JSExportKeyword = 126,
|
||||
JSFunctionKeyword = 127,
|
||||
JSWhileKeyword = 128,
|
||||
JSForKeyword = 129,
|
||||
JSCloseBrace = 131,
|
||||
JSCloseBracket = 132,
|
||||
JSCloseParen = 133,
|
||||
JSOpenBrace = 134,
|
||||
JSOpenBracket = 135,
|
||||
JSOpenParen = 136,
|
||||
JSSemi = 137,
|
||||
JSComma = 138,
|
||||
JSDot = 139,
|
||||
JSDotDotDot = 140,
|
||||
JSMulOp = 141,
|
||||
JSAddOp = 142,
|
||||
JSDivOp = 143,
|
||||
JSSubOp = 144,
|
||||
JSLtOp = 145,
|
||||
JSGtOp = 146,
|
||||
JSBOrOp = 147,
|
||||
JSBXorOp = 148,
|
||||
JSBAndOp = 149,
|
||||
JSBNotOp = 150,
|
||||
JSNotOp = 151,
|
||||
JSBindPattern = 153,
|
||||
JSConstantExpression = 155,
|
||||
JSMemberExpression = 156,
|
||||
JSCallExpression = 157,
|
||||
JSBinaryExpression = 158,
|
||||
JSUnaryExpression = 159,
|
||||
JSNewExpression = 160,
|
||||
JSSequenceExpression = 161,
|
||||
JSConditionalExpression = 162,
|
||||
JSLiteralExpression = 163,
|
||||
JSReferenceExpression = 164,
|
||||
JSCatchBlock = 168,
|
||||
JSTryCatchStatement = 169,
|
||||
JSExpressionStatement = 170,
|
||||
JSConditionalCase = 171,
|
||||
JSConditionalStatement = 172,
|
||||
JSReturnStatement = 173,
|
||||
JSParameter = 174,
|
||||
JSImportStarBinding = 178,
|
||||
JSImportAsBinding = 179,
|
||||
JSImportDeclaration = 180,
|
||||
JSFunctionDeclaration = 181,
|
||||
JSArrowFunctionDeclaration = 182,
|
||||
JSLetDeclaration = 183,
|
||||
JSSourceFile = 184,
|
||||
BoltStringLiteral = 7,
|
||||
BoltIntegerLiteral = 8,
|
||||
BoltIdentifier = 10,
|
||||
BoltOperator = 12,
|
||||
BoltAssignment = 13,
|
||||
BoltComma = 14,
|
||||
BoltSemi = 15,
|
||||
BoltColon = 16,
|
||||
BoltColonColon = 17,
|
||||
BoltDot = 18,
|
||||
BoltDotDot = 19,
|
||||
BoltRArrow = 20,
|
||||
BoltRArrowAlt = 21,
|
||||
BoltLArrow = 22,
|
||||
BoltEqSign = 23,
|
||||
BoltGtSign = 24,
|
||||
BoltExMark = 25,
|
||||
BoltLtSign = 26,
|
||||
BoltVBar = 27,
|
||||
BoltWhereKeyword = 29,
|
||||
BoltQuoteKeyword = 30,
|
||||
BoltFnKeyword = 31,
|
||||
BoltForeignKeyword = 32,
|
||||
BoltForKeyword = 33,
|
||||
BoltLetKeyword = 34,
|
||||
BoltReturnKeyword = 35,
|
||||
BoltLoopKeyword = 36,
|
||||
BoltYieldKeyword = 37,
|
||||
BoltMatchKeyword = 38,
|
||||
BoltImportKeyword = 39,
|
||||
BoltExportKeyword = 40,
|
||||
BoltPubKeyword = 41,
|
||||
BoltModKeyword = 42,
|
||||
BoltMutKeyword = 43,
|
||||
BoltEnumKeyword = 44,
|
||||
BoltStructKeyword = 45,
|
||||
BoltTypeKeyword = 46,
|
||||
BoltTraitKeyword = 47,
|
||||
BoltImplKeyword = 48,
|
||||
BoltParenthesized = 50,
|
||||
BoltBraced = 51,
|
||||
BoltBracketed = 52,
|
||||
BoltSourceFile = 53,
|
||||
BoltQualName = 54,
|
||||
BoltTypeOfExpression = 56,
|
||||
BoltReferenceTypeExpression = 57,
|
||||
BoltFunctionTypeExpression = 58,
|
||||
BoltLiftedTypeExpression = 59,
|
||||
BoltTypeParameter = 60,
|
||||
BoltBindPattern = 62,
|
||||
BoltTypePattern = 63,
|
||||
BoltExpressionPattern = 64,
|
||||
BoltTuplePatternElement = 65,
|
||||
BoltTuplePattern = 66,
|
||||
BoltRecordFieldPattern = 67,
|
||||
BoltRecordPattern = 68,
|
||||
BoltQuoteExpression = 70,
|
||||
BoltTupleExpression = 71,
|
||||
BoltReferenceExpression = 72,
|
||||
BoltMemberExpression = 73,
|
||||
BoltFunctionExpression = 74,
|
||||
BoltCallExpression = 75,
|
||||
BoltYieldExpression = 76,
|
||||
BoltMatchArm = 77,
|
||||
BoltMatchExpression = 78,
|
||||
BoltCase = 79,
|
||||
BoltCaseExpression = 80,
|
||||
BoltBlockExpression = 81,
|
||||
BoltConstantExpression = 82,
|
||||
BoltReturnStatement = 84,
|
||||
BoltConditionalCase = 85,
|
||||
BoltConditionalStatement = 86,
|
||||
BoltResumeStatement = 87,
|
||||
BoltExpressionStatement = 88,
|
||||
BoltParameter = 89,
|
||||
BoltModule = 93,
|
||||
BoltFunctionDeclaration = 96,
|
||||
BoltVariableDeclaration = 97,
|
||||
BoltPlainImportSymbol = 99,
|
||||
BoltImportDirective = 100,
|
||||
BoltExportSymbol = 101,
|
||||
BoltPlainExportSymbol = 102,
|
||||
BoltExportDirective = 103,
|
||||
BoltTraitDeclaration = 104,
|
||||
BoltImplDeclaration = 105,
|
||||
BoltTypeAliasDeclaration = 106,
|
||||
BoltRecordField = 108,
|
||||
BoltRecordDeclaration = 109,
|
||||
BoltMacroCall = 111,
|
||||
JSIdentifier = 115,
|
||||
JSString = 116,
|
||||
JSInteger = 117,
|
||||
JSFromKeyword = 118,
|
||||
JSReturnKeyword = 119,
|
||||
JSTryKeyword = 120,
|
||||
JSFinallyKeyword = 121,
|
||||
JSCatchKeyword = 122,
|
||||
JSImportKeyword = 123,
|
||||
JSAsKeyword = 124,
|
||||
JSConstKeyword = 125,
|
||||
JSLetKeyword = 126,
|
||||
JSExportKeyword = 127,
|
||||
JSFunctionKeyword = 128,
|
||||
JSWhileKeyword = 129,
|
||||
JSForKeyword = 130,
|
||||
JSCloseBrace = 132,
|
||||
JSCloseBracket = 133,
|
||||
JSCloseParen = 134,
|
||||
JSOpenBrace = 135,
|
||||
JSOpenBracket = 136,
|
||||
JSOpenParen = 137,
|
||||
JSSemi = 138,
|
||||
JSComma = 139,
|
||||
JSDot = 140,
|
||||
JSDotDotDot = 141,
|
||||
JSMulOp = 142,
|
||||
JSAddOp = 143,
|
||||
JSDivOp = 144,
|
||||
JSSubOp = 145,
|
||||
JSLtOp = 146,
|
||||
JSGtOp = 147,
|
||||
JSBOrOp = 148,
|
||||
JSBXorOp = 149,
|
||||
JSBAndOp = 150,
|
||||
JSBNotOp = 151,
|
||||
JSNotOp = 152,
|
||||
JSBindPattern = 154,
|
||||
JSConstantExpression = 156,
|
||||
JSMemberExpression = 157,
|
||||
JSCallExpression = 158,
|
||||
JSBinaryExpression = 159,
|
||||
JSUnaryExpression = 160,
|
||||
JSNewExpression = 161,
|
||||
JSSequenceExpression = 162,
|
||||
JSConditionalExpression = 163,
|
||||
JSLiteralExpression = 164,
|
||||
JSReferenceExpression = 165,
|
||||
JSCatchBlock = 169,
|
||||
JSTryCatchStatement = 170,
|
||||
JSExpressionStatement = 171,
|
||||
JSConditionalCase = 172,
|
||||
JSConditionalStatement = 173,
|
||||
JSReturnStatement = 174,
|
||||
JSParameter = 175,
|
||||
JSImportStarBinding = 179,
|
||||
JSImportAsBinding = 180,
|
||||
JSImportDeclaration = 181,
|
||||
JSFunctionDeclaration = 182,
|
||||
JSArrowFunctionDeclaration = 183,
|
||||
JSLetDeclaration = 184,
|
||||
JSSourceFile = 185,
|
||||
}
|
||||
|
||||
export interface EndOfFile extends SyntaxBase {
|
||||
|
@ -479,20 +477,26 @@ export type SourceFile
|
|||
| JSSourceFile
|
||||
|
||||
|
||||
export interface FunctionBody extends SyntaxBase {
|
||||
kind: SyntaxKind.FunctionBody;
|
||||
parentNode: FunctionBodyParent;
|
||||
getChildNodes(): IterableIterator<FunctionBodyChild>
|
||||
}
|
||||
export type FunctionBodyElement
|
||||
= JSFunctionDeclaration
|
||||
| JSArrowFunctionDeclaration
|
||||
| JSLetDeclaration
|
||||
| JSExpressionStatement
|
||||
| JSConditionalStatement
|
||||
| JSReturnStatement
|
||||
| BoltFunctionDeclaration
|
||||
| BoltVariableDeclaration
|
||||
| BoltReturnStatement
|
||||
| BoltConditionalStatement
|
||||
| BoltResumeStatement
|
||||
| BoltExpressionStatement
|
||||
| BoltMacroCall
|
||||
|
||||
export type FunctionBodyParent
|
||||
= never
|
||||
|
||||
export type FunctionBodyAnyParent
|
||||
= never
|
||||
export type ReturnStatement
|
||||
= BoltReturnStatement
|
||||
| JSReturnStatement
|
||||
|
||||
export type FunctionBodyChild
|
||||
= never
|
||||
|
||||
export type BoltSyntax
|
||||
= BoltSourceFile
|
||||
|
@ -4980,6 +4984,9 @@ export type JSSyntax
|
|||
| JSFunctionDeclaration
|
||||
| JSArrowFunctionDeclaration
|
||||
| JSLetDeclaration
|
||||
| JSExpressionStatement
|
||||
| JSConditionalStatement
|
||||
| JSReturnStatement
|
||||
| JSConstantExpression
|
||||
| JSMemberExpression
|
||||
| JSCallExpression
|
||||
|
@ -8015,7 +8022,6 @@ export type JSSourceFileChild
|
|||
|
||||
export type Syntax
|
||||
= EndOfFile
|
||||
| FunctionBody
|
||||
| BoltStringLiteral
|
||||
| BoltIntegerLiteral
|
||||
| BoltIdentifier
|
||||
|
@ -8172,7 +8178,6 @@ export type Syntax
|
|||
export function kindToString(kind: SyntaxKind): string;
|
||||
|
||||
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 createBoltIntegerLiteral(value: bigint, span?: TextSpan | null): BoltIntegerLiteral;
|
||||
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 isToken(value: any): value is Token;
|
||||
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 isBoltToken(value: any): value is BoltToken;
|
||||
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 { 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 { getSymbolPathFromNode } from "./resolver"
|
||||
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 { convertNodeToSymbolPath } from "./resolver"
|
||||
import { inject } from "./ioc";
|
||||
import { SymbolResolver, ScopeType } from "./resolver";
|
||||
import { assert, every } from "./util";
|
||||
|
@ -103,7 +103,7 @@ export class CheckReferences extends NodeVisitor {
|
|||
this.checkBoltModulePath(node.name, node.name.modulePath);
|
||||
const scope = this.resolver.getScopeSurroundingNode(node, ScopeType.Variable);
|
||||
assert(scope !== null);
|
||||
const resolvedSym = this.resolver.resolveSymbolPath(getSymbolPathFromNode(node), scope!);
|
||||
const resolvedSym = this.resolver.resolveSymbolPath(convertNodeToSymbolPath(node), scope!);
|
||||
if (resolvedSym === null) {
|
||||
this.diagnostics.add({
|
||||
message: E_DECLARATION_NOT_FOUND,
|
||||
|
@ -117,7 +117,7 @@ export class CheckReferences extends NodeVisitor {
|
|||
protected visitBoltReferenceTypeExpression(node: BoltReferenceTypeExpression) {
|
||||
const scope = this.resolver.getScopeSurroundingNode(node, ScopeType.Type);
|
||||
assert(scope !== null);
|
||||
const symbolPath = getSymbolPathFromNode(node.name);
|
||||
const symbolPath = convertNodeToSymbolPath(node.name);
|
||||
const resolvedSym = this.resolver.resolveSymbolPath(symbolPath, scope!);
|
||||
if (resolvedSym === null) {
|
||||
this.diagnostics.add({
|
||||
|
|
|
@ -19,6 +19,7 @@ import {FastStringMap, enumerate, escapeChar, assert} from "./util";
|
|||
import {TextSpan, TextPos, TextFile} from "./text";
|
||||
import {Scanner} from "./scanner";
|
||||
import * as path from "path"
|
||||
import { convertNodeToSymbolPath } from "./resolver";
|
||||
|
||||
export function getSourceFile(node: Syntax) {
|
||||
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 {
|
||||
switch (kind) {
|
||||
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_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_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_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."
|
||||
|
@ -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_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_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']
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ export class Evaluator {
|
|||
case SyntaxKind.BoltTypePattern:
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -98,6 +98,7 @@ export class Frontend {
|
|||
for (const sourceFile of program.getAllSourceFiles()) {
|
||||
checker.registerSourceFile(sourceFile);
|
||||
}
|
||||
checker.solve(program.getAllSourceFiles());
|
||||
for (const pkg of program.getAllPackages()) {
|
||||
if (!pkg.isDependency) {
|
||||
for (const sourceFile of pkg.getAllSourceFiles()) {
|
||||
|
|
|
@ -9,25 +9,49 @@ const GLOBAL_SCOPE_ID = 'global';
|
|||
export class SymbolPath {
|
||||
|
||||
constructor(
|
||||
private parents: string[],
|
||||
public modulePath: string[],
|
||||
public isAbsolute: boolean,
|
||||
public name: string
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
public hasParents(): boolean {
|
||||
return this.parents.length > 0;
|
||||
public encode(): string {
|
||||
let out = '';
|
||||
if (this.isAbsolute) {
|
||||
out += '::'
|
||||
}
|
||||
for (const element of this.modulePath) {
|
||||
out += element + '::'
|
||||
}
|
||||
out += this.name;
|
||||
return out;
|
||||
}
|
||||
|
||||
public getParents() {
|
||||
return this.parents;
|
||||
public hasModulePath(): boolean {
|
||||
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) {
|
||||
case SyntaxKind.BoltRecordDeclaration:
|
||||
return new SymbolPath(
|
||||
[],
|
||||
false,
|
||||
node.name.text,
|
||||
);
|
||||
case SyntaxKind.BoltFunctionDeclaration:
|
||||
return new SymbolPath(
|
||||
[],
|
||||
false,
|
||||
emitNode(node.name),
|
||||
);
|
||||
case SyntaxKind.BoltReferenceExpression:
|
||||
return new SymbolPath(
|
||||
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(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:
|
||||
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()) {
|
||||
const scope = this.getScopeForNode(importDir, scopeType);
|
||||
assert(scope !== null);
|
||||
const exported = this.resolveSymbolPath(getSymbolPathFromNode(importSymbol), scope!);
|
||||
const exported = this.resolveSymbolPath(convertNodeToSymbolPath(importSymbol), scope!);
|
||||
if (exported !== null) {
|
||||
for (const decl of exported.declarations) {
|
||||
scope!.addNodeAsSymbol(this.strategy.getSymbolName(decl), decl);
|
||||
|
@ -491,16 +509,17 @@ export class SymbolResolver {
|
|||
return scope.getSymbol(this.strategy.getSymbolName(node));
|
||||
}
|
||||
|
||||
public resolveGlobalSymbol(name: string, kind: ScopeType) {
|
||||
const symbolPath = new SymbolPath([], true, name);
|
||||
public resolveGlobalSymbol(path: SymbolPath, kind: ScopeType) {
|
||||
for (const sourceFile of this.program.getAllGloballyDeclaredSourceFiles()) {
|
||||
const scope = this.getScopeForNode(sourceFile, kind);
|
||||
if (scope === null) {
|
||||
assert(scope !== null);
|
||||
const modScope = this.resolveModulePath(path.getModulePath(), scope!);
|
||||
if (modScope === null) {
|
||||
continue;
|
||||
}
|
||||
const sym = scope.getLocalSymbol(name);
|
||||
const sym = modScope?.getLocalSymbol(path.name)
|
||||
if (sym !== null) {
|
||||
return sym
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -508,7 +527,7 @@ export class SymbolResolver {
|
|||
|
||||
public resolveSymbolPath(path: SymbolPath, scope: Scope): SymbolInfo | null {
|
||||
|
||||
if (path.hasParents()) {
|
||||
if (path.hasModulePath()) {
|
||||
|
||||
if (path.isAbsolute) {
|
||||
|
||||
|
@ -517,7 +536,7 @@ export class SymbolResolver {
|
|||
} else {
|
||||
|
||||
// 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
|
||||
// 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,
|
||||
// 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() {
|
||||
for (const key of Object.keys(this)) {
|
||||
if (key === 'span' || key === 'parentNode') {
|
||||
if (key === 'span' || key === 'parentNode' || key === 'type') {
|
||||
continue
|
||||
}
|
||||
const value = this[key];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
import { Type } from "./types"
|
||||
import { TypeRef } from "./types"
|
||||
import { Diagnostic } from "./diagnostics"
|
||||
import { Package } from "./common"
|
||||
import { TextSpan } from "./text"
|
||||
|
@ -13,7 +13,7 @@ export function isSyntax(value: any): value is Syntax;
|
|||
interface SyntaxBase {
|
||||
id: number;
|
||||
kind: SyntaxKind;
|
||||
type?: Type;
|
||||
type?: TypeRef;
|
||||
errors: Diagnostic[]
|
||||
parentNode: Syntax | null;
|
||||
span: TextSpan | null;
|
||||
|
|
|
@ -58,7 +58,7 @@ export function generateAST(decls: Declaration[]) {
|
|||
jsFile.write(`index: ${decl.index},\n`);
|
||||
jsFile.write(`parents: [`);
|
||||
for (const parentName of getParentChain(decl.name)) {
|
||||
jsFile.write(`'${decl.name}', `)
|
||||
jsFile.write(`'${parentName}', `)
|
||||
}
|
||||
jsFile.write(`'Syntax'],\n`);
|
||||
jsFile.write(`fields: new Map([\n`);
|
||||
|
@ -359,7 +359,7 @@ export function generateAST(decls: Declaration[]) {
|
|||
return children;
|
||||
}
|
||||
|
||||
function *getParentChain(nodeName: string) {
|
||||
function *getParentChain(nodeName: string): IterableIterator<string> {
|
||||
const stack = [ nodeName ];
|
||||
while (stack.length > 0) {
|
||||
const nodeDecl = getDeclarationNamed(stack.pop()!) as NodeDeclaration;
|
||||
|
|
1755
src/types.ts
1755
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 chalk from "chalk"
|
||||
import { LOG_DATETIME_FORMAT } from "./constants"
|
||||
import { E_CANDIDATE_FUNCTION_REQUIRES_THIS_PARAMETER } from "./diagnostics"
|
||||
|
||||
export function isPowerOf(x: number, n: number):boolean {
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
if (!test) {
|
||||
throw new Error(`Invariant violation: an internal sanity check failed.`);
|
||||
|
@ -131,6 +179,102 @@ export function prettyPrint(value: any): string {
|
|||
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> {
|
||||
|
||||
private mapping = Object.create(null);
|
||||
|
|
Loading…
Reference in a new issue