Major update to code and type checker

This commit is contained in:
Sam Vervaeck 2020-05-29 18:44:58 +02:00
parent 884be8f9ec
commit c2d101c25c
14 changed files with 1641 additions and 778 deletions

View file

@ -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
View file

@ -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;

View file

@ -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({

View file

@ -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)}`);
}
}
}

View file

@ -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']

View file

@ -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;

View file

@ -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()) {

View file

@ -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
View 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);
})
})

View file

@ -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];

View file

@ -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;

View file

@ -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;

File diff suppressed because it is too large Load diff

View file

@ -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);