Fix multiple issues with symbol resolver

This commit is contained in:
Sam Vervaeck 2020-05-25 17:46:01 +02:00
parent e0566233c0
commit 828af8432e
6 changed files with 261 additions and 184 deletions

View file

@ -95,10 +95,15 @@ node BoltQualName {
name: BoltSymbol, name: BoltSymbol,
} }
node BoltModulePath {
isAbsolute: bool,
elements: Vec<BoltIdentifier>,
}
node BoltTypeExpression; node BoltTypeExpression;
node BoltReferenceTypeExpression > BoltTypeExpression { node BoltReferenceTypeExpression > BoltTypeExpression {
name: BoltQualName, path: BoltModulePath,
arguments: Option<Vec<BoltTypeExpression>>, arguments: Option<Vec<BoltTypeExpression>>,
} }
@ -144,7 +149,7 @@ node BoltRecordFieldPattern {
} }
node BoltRecordPattern > BoltPattern { node BoltRecordPattern > BoltPattern {
name: BoltQualName, name: BoltTypeExpression,
fields: Vec<BoltRecordFieldPattern>, fields: Vec<BoltRecordFieldPattern>,
} }
@ -246,7 +251,7 @@ enum BoltModifiers {
node BoltModule > BoltSourceElement { node BoltModule > BoltSourceElement {
modifiers: BoltModifiers, modifiers: BoltModifiers,
name: BoltQualName, name: Vec<BoltIdentifier>,
elements: Vec<BoltSourceElement>, elements: Vec<BoltSourceElement>,
} }

233
src/ast.d.ts vendored
View file

@ -71,111 +71,112 @@ export const enum SyntaxKind {
BoltBracketed = 53, BoltBracketed = 53,
BoltSourceFile = 54, BoltSourceFile = 54,
BoltQualName = 55, BoltQualName = 55,
BoltReferenceTypeExpression = 57, BoltModulePath = 56,
BoltFunctionTypeExpression = 58, BoltReferenceTypeExpression = 58,
BoltTypeParameter = 59, BoltFunctionTypeExpression = 59,
BoltBindPattern = 61, BoltTypeParameter = 60,
BoltTypePattern = 62, BoltBindPattern = 62,
BoltExpressionPattern = 63, BoltTypePattern = 63,
BoltTuplePatternElement = 64, BoltExpressionPattern = 64,
BoltTuplePattern = 65, BoltTuplePatternElement = 65,
BoltRecordFieldPattern = 66, BoltTuplePattern = 66,
BoltRecordPattern = 67, BoltRecordFieldPattern = 67,
BoltQuoteExpression = 69, BoltRecordPattern = 68,
BoltReferenceExpression = 70, BoltQuoteExpression = 70,
BoltMemberExpression = 71, BoltReferenceExpression = 71,
BoltFunctionExpression = 72, BoltMemberExpression = 72,
BoltCallExpression = 73, BoltFunctionExpression = 73,
BoltYieldExpression = 74, BoltCallExpression = 74,
BoltMatchArm = 75, BoltYieldExpression = 75,
BoltMatchExpression = 76, BoltMatchArm = 76,
BoltCase = 77, BoltMatchExpression = 77,
BoltCaseExpression = 78, BoltCase = 78,
BoltBlockExpression = 79, BoltCaseExpression = 79,
BoltConstantExpression = 80, BoltBlockExpression = 80,
BoltReturnStatement = 82, BoltConstantExpression = 81,
BoltConditionalCase = 83, BoltReturnStatement = 83,
BoltConditionalStatement = 84, BoltConditionalCase = 84,
BoltResumeStatement = 85, BoltConditionalStatement = 85,
BoltExpressionStatement = 86, BoltResumeStatement = 86,
BoltParameter = 87, BoltExpressionStatement = 87,
BoltModule = 91, BoltParameter = 88,
BoltFunctionDeclaration = 93, BoltModule = 92,
BoltVariableDeclaration = 94, BoltFunctionDeclaration = 94,
BoltPlainImportSymbol = 96, BoltVariableDeclaration = 95,
BoltImportDirective = 97, BoltPlainImportSymbol = 97,
BoltExportSymbol = 98, BoltImportDirective = 98,
BoltPlainExportSymbol = 99, BoltExportSymbol = 99,
BoltExportDirective = 100, BoltPlainExportSymbol = 100,
BoltTraitDeclaration = 101, BoltExportDirective = 101,
BoltImplDeclaration = 102, BoltTraitDeclaration = 102,
BoltTypeAliasDeclaration = 103, BoltImplDeclaration = 103,
BoltRecordField = 105, BoltTypeAliasDeclaration = 104,
BoltRecordDeclaration = 106, BoltRecordField = 106,
BoltMacroCall = 108, BoltRecordDeclaration = 107,
JSOperator = 111, BoltMacroCall = 109,
JSIdentifier = 112, JSOperator = 112,
JSString = 113, JSIdentifier = 113,
JSInteger = 114, JSString = 114,
JSFromKeyword = 115, JSInteger = 115,
JSReturnKeyword = 116, JSFromKeyword = 116,
JSTryKeyword = 117, JSReturnKeyword = 117,
JSFinallyKeyword = 118, JSTryKeyword = 118,
JSCatchKeyword = 119, JSFinallyKeyword = 119,
JSImportKeyword = 120, JSCatchKeyword = 120,
JSAsKeyword = 121, JSImportKeyword = 121,
JSConstKeyword = 122, JSAsKeyword = 122,
JSLetKeyword = 123, JSConstKeyword = 123,
JSExportKeyword = 124, JSLetKeyword = 124,
JSFunctionKeyword = 125, JSExportKeyword = 125,
JSWhileKeyword = 126, JSFunctionKeyword = 126,
JSForKeyword = 127, JSWhileKeyword = 127,
JSCloseBrace = 128, JSForKeyword = 128,
JSCloseBracket = 129, JSCloseBrace = 129,
JSCloseParen = 130, JSCloseBracket = 130,
JSOpenBrace = 131, JSCloseParen = 131,
JSOpenBracket = 132, JSOpenBrace = 132,
JSOpenParen = 133, JSOpenBracket = 133,
JSSemi = 134, JSOpenParen = 134,
JSComma = 135, JSSemi = 135,
JSDot = 136, JSComma = 136,
JSDotDotDot = 137, JSDot = 137,
JSMulOp = 138, JSDotDotDot = 138,
JSAddOp = 139, JSMulOp = 139,
JSDivOp = 140, JSAddOp = 140,
JSSubOp = 141, JSDivOp = 141,
JSLtOp = 142, JSSubOp = 142,
JSGtOp = 143, JSLtOp = 143,
JSBOrOp = 144, JSGtOp = 144,
JSBXorOp = 145, JSBOrOp = 145,
JSBAndOp = 146, JSBXorOp = 146,
JSBNotOp = 147, JSBAndOp = 147,
JSNotOp = 148, JSBNotOp = 148,
JSBindPattern = 150, JSNotOp = 149,
JSConstantExpression = 152, JSBindPattern = 151,
JSMemberExpression = 153, JSConstantExpression = 153,
JSCallExpression = 154, JSMemberExpression = 154,
JSBinaryExpression = 155, JSCallExpression = 155,
JSUnaryExpression = 156, JSBinaryExpression = 156,
JSNewExpression = 157, JSUnaryExpression = 157,
JSSequenceExpression = 158, JSNewExpression = 158,
JSConditionalExpression = 159, JSSequenceExpression = 159,
JSLiteralExpression = 161, JSConditionalExpression = 160,
JSReferenceExpression = 162, JSLiteralExpression = 162,
JSCatchBlock = 166, JSReferenceExpression = 163,
JSTryCatchStatement = 167, JSCatchBlock = 167,
JSExpressionStatement = 168, JSTryCatchStatement = 168,
JSConditionalCase = 169, JSExpressionStatement = 169,
JSConditionalStatement = 170, JSConditionalCase = 170,
JSReturnStatement = 171, JSConditionalStatement = 171,
JSParameter = 172, JSReturnStatement = 172,
JSImportStarBinding = 176, JSParameter = 173,
JSImportAsBinding = 177, JSImportStarBinding = 177,
JSImportDeclaration = 178, JSImportAsBinding = 178,
JSFunctionDeclaration = 179, JSImportDeclaration = 179,
JSArrowFunctionDeclaration = 180, JSFunctionDeclaration = 180,
JSLetDeclaration = 181, JSArrowFunctionDeclaration = 181,
JSSourceFile = 182, JSLetDeclaration = 182,
JSSourceFile = 183,
} }
export interface EndOfFile extends SyntaxBase<SyntaxKind.EndOfFile> { export interface EndOfFile extends SyntaxBase<SyntaxKind.EndOfFile> {
@ -563,6 +564,12 @@ export interface BoltQualName extends SyntaxBase<SyntaxKind.BoltQualName> {
name: BoltSymbol; name: BoltSymbol;
} }
export interface BoltModulePath extends SyntaxBase<SyntaxKind.BoltModulePath> {
kind: SyntaxKind.BoltModulePath;
isAbsolute: boolean;
elements: BoltIdentifier[];
}
export type BoltTypeExpression export type BoltTypeExpression
= BoltReferenceTypeExpression = BoltReferenceTypeExpression
| BoltFunctionTypeExpression | BoltFunctionTypeExpression
@ -570,7 +577,7 @@ export type BoltTypeExpression
export interface BoltReferenceTypeExpression extends SyntaxBase<SyntaxKind.BoltReferenceTypeExpression> { export interface BoltReferenceTypeExpression extends SyntaxBase<SyntaxKind.BoltReferenceTypeExpression> {
kind: SyntaxKind.BoltReferenceTypeExpression; kind: SyntaxKind.BoltReferenceTypeExpression;
name: BoltQualName; path: BoltModulePath;
arguments: BoltTypeExpression[] | null; arguments: BoltTypeExpression[] | null;
} }
@ -631,7 +638,7 @@ export interface BoltRecordFieldPattern extends SyntaxBase<SyntaxKind.BoltRecord
export interface BoltRecordPattern extends SyntaxBase<SyntaxKind.BoltRecordPattern> { export interface BoltRecordPattern extends SyntaxBase<SyntaxKind.BoltRecordPattern> {
kind: SyntaxKind.BoltRecordPattern; kind: SyntaxKind.BoltRecordPattern;
name: BoltQualName; name: BoltTypeExpression;
fields: BoltRecordFieldPattern[]; fields: BoltRecordFieldPattern[];
} }
@ -780,7 +787,7 @@ export const enum BoltModifiers {
export interface BoltModule extends SyntaxBase<SyntaxKind.BoltModule> { export interface BoltModule extends SyntaxBase<SyntaxKind.BoltModule> {
kind: SyntaxKind.BoltModule; kind: SyntaxKind.BoltModule;
modifiers: BoltModifiers; modifiers: BoltModifiers;
name: BoltQualName; name: BoltIdentifier[];
elements: BoltSourceElement[]; elements: BoltSourceElement[];
} }
@ -1362,6 +1369,7 @@ export type BoltSyntax
| BoltBracketed | BoltBracketed
| BoltSourceFile | BoltSourceFile
| BoltQualName | BoltQualName
| BoltModulePath
| BoltReferenceTypeExpression | BoltReferenceTypeExpression
| BoltFunctionTypeExpression | BoltFunctionTypeExpression
| BoltTypeParameter | BoltTypeParameter
@ -1519,6 +1527,7 @@ export type Syntax
| BoltBracketed | BoltBracketed
| BoltSourceFile | BoltSourceFile
| BoltQualName | BoltQualName
| BoltModulePath
| BoltReferenceTypeExpression | BoltReferenceTypeExpression
| BoltFunctionTypeExpression | BoltFunctionTypeExpression
| BoltTypeParameter | BoltTypeParameter
@ -1674,7 +1683,8 @@ export function createBoltBraced(text: string, span?: TextSpan | null): BoltBrac
export function createBoltBracketed(text: string, span?: TextSpan | null): BoltBracketed; export function createBoltBracketed(text: string, span?: TextSpan | null): BoltBracketed;
export function createBoltSourceFile(elements: BoltSourceElement[], package: Package, span?: TextSpan | null): BoltSourceFile; export function createBoltSourceFile(elements: BoltSourceElement[], package: Package, span?: TextSpan | null): BoltSourceFile;
export function createBoltQualName(modulePath: BoltIdentifier[] | null, name: BoltSymbol, span?: TextSpan | null): BoltQualName; export function createBoltQualName(modulePath: BoltIdentifier[] | null, name: BoltSymbol, span?: TextSpan | null): BoltQualName;
export function createBoltReferenceTypeExpression(name: BoltQualName, arguments: BoltTypeExpression[] | null, span?: TextSpan | null): BoltReferenceTypeExpression; export function createBoltModulePath(isAbsolute: boolean, elements: BoltIdentifier[], span?: TextSpan | null): BoltModulePath;
export function createBoltReferenceTypeExpression(path: BoltModulePath, arguments: BoltTypeExpression[] | null, span?: TextSpan | null): BoltReferenceTypeExpression;
export function createBoltFunctionTypeExpression(params: BoltParameter[], returnType: BoltTypeExpression | null, span?: TextSpan | null): BoltFunctionTypeExpression; export function createBoltFunctionTypeExpression(params: BoltParameter[], returnType: BoltTypeExpression | null, span?: TextSpan | null): BoltFunctionTypeExpression;
export function createBoltTypeParameter(index: number, name: BoltIdentifier, defaultType: BoltTypeExpression | null, span?: TextSpan | null): BoltTypeParameter; export function createBoltTypeParameter(index: number, name: BoltIdentifier, defaultType: BoltTypeExpression | null, span?: TextSpan | null): BoltTypeParameter;
export function createBoltBindPattern(name: BoltIdentifier, span?: TextSpan | null): BoltBindPattern; export function createBoltBindPattern(name: BoltIdentifier, span?: TextSpan | null): BoltBindPattern;
@ -1683,7 +1693,7 @@ export function createBoltExpressionPattern(expression: BoltExpression, span?: T
export function createBoltTuplePatternElement(index: number, pattern: BoltPattern, span?: TextSpan | null): BoltTuplePatternElement; export function createBoltTuplePatternElement(index: number, pattern: BoltPattern, span?: TextSpan | null): BoltTuplePatternElement;
export function createBoltTuplePattern(elements: BoltTuplePatternElement[], span?: TextSpan | null): BoltTuplePattern; export function createBoltTuplePattern(elements: BoltTuplePatternElement[], span?: TextSpan | null): BoltTuplePattern;
export function createBoltRecordFieldPattern(isRest: boolean, name: BoltIdentifier | null, pattern: BoltPattern | null, span?: TextSpan | null): BoltRecordFieldPattern; export function createBoltRecordFieldPattern(isRest: boolean, name: BoltIdentifier | null, pattern: BoltPattern | null, span?: TextSpan | null): BoltRecordFieldPattern;
export function createBoltRecordPattern(name: BoltQualName, fields: BoltRecordFieldPattern[], span?: TextSpan | null): BoltRecordPattern; export function createBoltRecordPattern(name: BoltTypeExpression, fields: BoltRecordFieldPattern[], span?: TextSpan | null): BoltRecordPattern;
export function createBoltQuoteExpression(tokens: Token[], span?: TextSpan | null): BoltQuoteExpression; export function createBoltQuoteExpression(tokens: Token[], span?: TextSpan | null): BoltQuoteExpression;
export function createBoltReferenceExpression(name: BoltQualName, span?: TextSpan | null): BoltReferenceExpression; export function createBoltReferenceExpression(name: BoltQualName, span?: TextSpan | null): BoltReferenceExpression;
export function createBoltMemberExpression(expression: BoltExpression, path: BoltIdentifier[], span?: TextSpan | null): BoltMemberExpression; export function createBoltMemberExpression(expression: BoltExpression, path: BoltIdentifier[], span?: TextSpan | null): BoltMemberExpression;
@ -1702,7 +1712,7 @@ export function createBoltConditionalStatement(cases: BoltConditionalCase[], spa
export function createBoltResumeStatement(value: BoltExpression, span?: TextSpan | null): BoltResumeStatement; export function createBoltResumeStatement(value: BoltExpression, span?: TextSpan | null): BoltResumeStatement;
export function createBoltExpressionStatement(expression: BoltExpression, span?: TextSpan | null): BoltExpressionStatement; export function createBoltExpressionStatement(expression: BoltExpression, span?: TextSpan | null): BoltExpressionStatement;
export function createBoltParameter(index: number, bindings: BoltPattern, type: BoltTypeExpression | null, defaultValue: BoltExpression | null, span?: TextSpan | null): BoltParameter; export function createBoltParameter(index: number, bindings: BoltPattern, type: BoltTypeExpression | null, defaultValue: BoltExpression | null, span?: TextSpan | null): BoltParameter;
export function createBoltModule(modifiers: BoltModifiers, name: BoltQualName, elements: BoltSourceElement[], span?: TextSpan | null): BoltModule; export function createBoltModule(modifiers: BoltModifiers, name: BoltIdentifier[], elements: BoltSourceElement[], span?: TextSpan | null): BoltModule;
export function createBoltFunctionDeclaration(modifiers: BoltModifiers, target: string, name: BoltSymbol, params: BoltParameter[], returnType: BoltTypeExpression | null, typeParams: BoltTypeParameter[] | null, body: BoltFunctionBodyElement[], span?: TextSpan | null): BoltFunctionDeclaration; export function createBoltFunctionDeclaration(modifiers: BoltModifiers, target: string, name: BoltSymbol, params: BoltParameter[], returnType: BoltTypeExpression | null, typeParams: BoltTypeParameter[] | null, body: BoltFunctionBodyElement[], span?: TextSpan | null): BoltFunctionDeclaration;
export function createBoltVariableDeclaration(modifiers: BoltModifiers, bindings: BoltPattern, type: BoltTypeExpression | null, value: BoltExpression | null, span?: TextSpan | null): BoltVariableDeclaration; export function createBoltVariableDeclaration(modifiers: BoltModifiers, bindings: BoltPattern, type: BoltTypeExpression | null, value: BoltExpression | null, span?: TextSpan | null): BoltVariableDeclaration;
export function createBoltPlainImportSymbol(name: BoltQualName, span?: TextSpan | null): BoltPlainImportSymbol; export function createBoltPlainImportSymbol(name: BoltQualName, span?: TextSpan | null): BoltPlainImportSymbol;
@ -1833,6 +1843,7 @@ export function isBoltBraced(value: any): value is BoltBraced;
export function isBoltBracketed(value: any): value is BoltBracketed; export function isBoltBracketed(value: any): value is BoltBracketed;
export function isBoltSourceFile(value: any): value is BoltSourceFile; export function isBoltSourceFile(value: any): value is BoltSourceFile;
export function isBoltQualName(value: any): value is BoltQualName; export function isBoltQualName(value: any): value is BoltQualName;
export function isBoltModulePath(value: any): value is BoltModulePath;
export function isBoltTypeExpression(value: any): value is BoltTypeExpression; export function isBoltTypeExpression(value: any): value is BoltTypeExpression;
export function isBoltReferenceTypeExpression(value: any): value is BoltReferenceTypeExpression; export function isBoltReferenceTypeExpression(value: any): value is BoltReferenceTypeExpression;
export function isBoltFunctionTypeExpression(value: any): value is BoltFunctionTypeExpression; export function isBoltFunctionTypeExpression(value: any): value is BoltFunctionTypeExpression;

View file

@ -47,7 +47,7 @@ import {
SourceFile, SourceFile,
BoltModifiers BoltModifiers
} from "./ast"; } from "./ast";
import {FastStringMap, countDigits, assert, verbose} from "./util"; import {warn, FastStringMap, countDigits, assert, verbose} from "./util";
import { import {
DiagnosticPrinter, DiagnosticPrinter,
E_TYPES_NOT_ASSIGNABLE, E_TYPES_NOT_ASSIGNABLE,
@ -87,6 +87,22 @@ class SymbolPath {
} }
function getModulePathToNode(node: BoltSyntax): string[] {
let elements = [];
while (true) {
if (node.kind === SyntaxKind.BoltModule) {
for (const element of node.name) {
elements.unshift(element.text);
}
}
if (node.parentNode === null) {
break;
}
node = node.parentNode;
}
return elements;
}
function nodeToSymbolPath(node: BoltSyntax): SymbolPath { function nodeToSymbolPath(node: BoltSyntax): SymbolPath {
switch (node.kind) { switch (node.kind) {
case SyntaxKind.BoltIdentifier: case SyntaxKind.BoltIdentifier:
@ -97,6 +113,12 @@ function nodeToSymbolPath(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 the given node.`);
} }
@ -109,8 +131,7 @@ enum SymbolKind {
} }
function* getAllSymbolKindsInMask(symbolKindMask: SymbolKind) { function* getAllSymbolKindsInMask(symbolKindMask: SymbolKind) {
const n = countDigits(symbolKindMask, 2); for (let i = 1; i <= symbolKindMask; i *= 2) {
for (let i = 1; i <= n; i++) {
if ((symbolKindMask & i) > 0) { if ((symbolKindMask & i) > 0) {
yield i; yield i;
} }
@ -233,7 +254,7 @@ export class TypeChecker {
if (self.resolveTypeReferenceExpression(node) === null) { if (self.resolveTypeReferenceExpression(node) === null) {
self.diagnostics.add({ self.diagnostics.add({
message: E_TYPE_DECLARATION_NOT_FOUND, message: E_TYPE_DECLARATION_NOT_FOUND,
args: { name: emit(node.name.name) }, args: { name: emit(node.path) },
severity: 'error', severity: 'error',
node: node, node: node,
}) })
@ -520,7 +541,8 @@ export class TypeChecker {
this.getScopeForNode(node, SymbolKind.Module) this.getScopeForNode(node, SymbolKind.Module)
); );
function addAllSymbolsToScope(node: BoltSyntax, variableScope: ScopeInfo, typeScope: ScopeInfo, moduleScope: ScopeInfo, allowDuplicates = false): void {
function addAllSymbolsToScope(node: BoltSyntax, variableScope: ScopeInfo, typeScope: ScopeInfo, moduleScope: ScopeInfo): void {
switch (node.kind) { switch (node.kind) {
@ -533,6 +555,7 @@ export class TypeChecker {
} else { } else {
const sourceFile = self.program.resolveToSourceFile(node.file.value, node) as BoltSourceFile; const sourceFile = self.program.resolveToSourceFile(node.file.value, node) as BoltSourceFile;
if (sourceFile === null) { if (sourceFile === null) {
// FIXME should be moved to checkNode()
self.diagnostics.add({ self.diagnostics.add({
severity: 'error', severity: 'error',
message: E_FILE_NOT_FOUND, message: E_FILE_NOT_FOUND,
@ -541,15 +564,24 @@ export class TypeChecker {
}); });
} else { } else {
for (const exportedNode of self.getAllExportedNodes(sourceFile)) { for (const exportedNode of self.getAllExportedNodes(sourceFile)) {
addAllSymbolsToScope(exportedNode, variableScope, typeScope, moduleScope, true); addNodeAsSymbol(exportedNode, true);
} }
} }
} }
break; break;
} }
case SyntaxKind.BoltSourceFile:
case SyntaxKind.BoltModule: case SyntaxKind.BoltModule:
{
addNodeAsSymbol(node);
// TODO check for duplicates
for (const element of node.elements) {
addAllSymbolsToScope(element, variableScope, typeScope, moduleScope);
}
break;
}
case SyntaxKind.BoltSourceFile:
{ {
for (const element of node.elements) { for (const element of node.elements) {
addAllSymbolsToScope(element, variableScope, typeScope, moduleScope); addAllSymbolsToScope(element, variableScope, typeScope, moduleScope);
@ -557,38 +589,42 @@ export class TypeChecker {
break; break;
} }
case SyntaxKind.BoltRecordDeclaration:
case SyntaxKind.BoltFunctionDeclaration: case SyntaxKind.BoltFunctionDeclaration:
{ addNodeAsSymbol(node);
const symbolName = emit(node.name);
const sym = self.lookupSymbolInScope(symbolName, variableScope, SymbolKind.Variable)
if (sym !== null) {
if (!allowDuplicates) {
throw new Error(`Symbol '${name}' is already defined.`);
}
if (sym.declarations.indexOf(node) === -1) {
throw new Error(`Different symbols imported under the same name.`);
}
} else {
self.addSymbolToScope(symbolName, node, variableScope, SymbolKind.Variable);
}
break; break;
}
function addNodeAsSymbol(node: BoltSyntax, allowDuplicates = false) {
switch (node.kind) {
case SyntaxKind.BoltModule:
checkAndAddNode(node.name[node.name.length-1].text, node, moduleScope, SymbolKind.Module);
break;
case SyntaxKind.BoltFunctionDeclaration:
checkAndAddNode(emit(node.name), node, variableScope, SymbolKind.Variable);
break;
case SyntaxKind.BoltRecordDeclaration:
checkAndAddNode(node.name.text, node, typeScope, SymbolKind.Type);
break;
} }
case SyntaxKind.BoltRecordDeclaration: function checkAndAddNode(symbolName: string, node: BoltSyntax, scope: ScopeInfo, symbolKind: SymbolKind) {
{ const sym = self.lookupSymbolInScope(symbolName, variableScope, symbolKind)
const symbolName = emit(node.name);
const sym = self.lookupSymbolInScope(symbolName, typeScope, SymbolKind.Type)
if (sym !== null) { if (sym !== null) {
if (!allowDuplicates) { if (!allowDuplicates) {
throw new Error(`Symbol '${name}' is already defined.`); throw new Error(`Symbol '${symbolName}' is already defined.`);
} }
if (sym.declarations.indexOf(node) === -1) { if (sym.declarations.indexOf(node) === -1) {
throw new Error(`Different symbols imported under the same name.`); throw new Error(`Different symbols imported under the same name.`);
} }
} else {
self.addSymbolToScope(node.name.text, node, typeScope, SymbolKind.Type);
} }
break; self.addSymbolToScope(symbolName, node, scope, symbolKind);
} }
} }
@ -604,23 +640,30 @@ export class TypeChecker {
return nodes; return nodes;
function visit(node: BoltSyntax) { function visit(node: BoltSyntax) {
if (isBoltDeclaration(node) || isBoltTypeDeclaration(node)) {
if ((node.modifiers & BoltModifiers.IsPublic) > 0) {
nodes.push(node);
}
}
switch (node.kind) { switch (node.kind) {
case SyntaxKind.BoltFunctionDeclaration: case SyntaxKind.BoltFunctionDeclaration:
case SyntaxKind.BoltRecordDeclaration: case SyntaxKind.BoltRecordDeclaration:
case SyntaxKind.BoltTypeAliasDeclaration: case SyntaxKind.BoltTypeAliasDeclaration:
nodes.push(node); case SyntaxKind.BoltVariableDeclaration:
if ((node.modifiers & BoltModifiers.IsPublic) > 0) {
nodes.push(node);
}
break; break;
case SyntaxKind.BoltModule:
case SyntaxKind.BoltSourceFile: case SyntaxKind.BoltSourceFile:
for (const element of node.elements) { for (const element of node.elements) {
visit(element); visit(element);
} }
break; break;
case SyntaxKind.BoltModule:
if ((node.modifiers & BoltModifiers.IsPublic) > 0) {
nodes.push(node);
}
break;
} }
} }
@ -628,13 +671,14 @@ export class TypeChecker {
private resolveReferenceExpression(node: BoltReferenceExpression): BoltDeclaration | null { private resolveReferenceExpression(node: BoltReferenceExpression): BoltDeclaration | null {
const symbolPath = nodeToSymbolPath(node.name) const symbolPath = nodeToSymbolPath(node.name)
return this.resolveSymbolPath(symbolPath, node, SymbolKind.Variable); const scope = this.getScopeForNode(node, SymbolKind.Variable);
return this.resolveSymbolPath(symbolPath, scope, SymbolKind.Variable) as BoltDeclaration;
} }
private resolveTypeReferenceExpression(node: BoltReferenceTypeExpression): BoltTypeDeclaration | null { private resolveTypeReferenceExpression(node: BoltReferenceTypeExpression): BoltTypeDeclaration | null {
const symbolPath = nodeToSymbolPath(node.name); const symbolPath = nodeToSymbolPath(node.path);
const scope = this.getScopeForNode(node, SymbolKind.Type); const scope = this.getScopeForNode(node, SymbolKind.Type);
return this.resolveSymbolPath(symbolPath, scope, SymbolKind.Type); return this.resolveSymbolPath(symbolPath, scope, SymbolKind.Type) as BoltTypeDeclaration;
} }
public addSymbol(name: string, node: BoltSyntax, kind: SymbolKind): void { public addSymbol(name: string, node: BoltSyntax, kind: SymbolKind): void {
@ -643,10 +687,22 @@ export class TypeChecker {
} }
public addSymbolToScope(name: string, node: BoltSyntax, scope: ScopeInfo, symbolKindMask: SymbolKind): void { public addSymbolToScope(name: string, node: BoltSyntax, scope: ScopeInfo, symbolKindMask: SymbolKind): void {
verbose(`Adding symbol ${name} in scope #${scope.id}`); //let message = `Adding symbol ${name} in scope #${scope.id}`;
//const modulePath = getModulePathToNode(scope.declaration);
//if (modulePath.length > 0) {
// message += ` of module ${modulePath.join('::')} in file ${scope.declaration.span!.file.origPath}`;
//} else {
// message += ` of file ${scope.declaration.span!.file.origPath}`;
//}
//verbose(message);
const sym = { kind: symbolKindMask, declarations: [ node ] } as SymbolInfo; const sym = { kind: symbolKindMask, declarations: [ node ] } as SymbolInfo;
for (const symbolKind of getAllSymbolKindsInMask(symbolKindMask)) { for (const symbolKind of getAllSymbolKindsInMask(symbolKindMask)) {
this.symbols.set(`${symbolKind}:${name}:${scope.id}`, sym); const key = `${symbolKind}:${name}:${scope.id}`;
if (this.symbols.has(key)) {
warn(`Warninig: silently skipping introduction of duplicate symbol '${name}'`);
} else {
this.symbols.set(key, sym);
}
} }
} }
@ -772,6 +828,7 @@ export class TypeChecker {
shouldSearchParentScopes = true; shouldSearchParentScopes = true;
break; break;
} }
// FIXME it should be possible to directly get the scope of a symbol
currScope = this.getScopeForNode(sym.declarations[0], SymbolKind.Module); currScope = this.getScopeForNode(sym.declarations[0], SymbolKind.Module);
} }

View file

@ -9,6 +9,10 @@ export class Emitter {
switch (node.kind) { switch (node.kind) {
case SyntaxKind.BoltModulePath:
out += node.elements.map(el => el.text).join('::');
break;
case SyntaxKind.BoltQualName: case SyntaxKind.BoltQualName:
if (node.modulePath !== null) { if (node.modulePath !== null) {
for (const element of node.modulePath) { for (const element of node.modulePath) {

View file

@ -77,7 +77,8 @@ import {
BoltMacroCall, BoltMacroCall,
createBoltMacroCall, createBoltMacroCall,
createBoltMemberExpression, createBoltMemberExpression,
BoltSourceFileModifiers, createBoltModulePath,
BoltModulePath,
} from "./ast" } from "./ast"
import { parseForeignLanguage } from "./foreign" import { parseForeignLanguage } from "./foreign"
@ -193,29 +194,25 @@ export class Parser {
return (this as any)['parse' + kindToString(kind).substring('Bolt'.length)](tokens); return (this as any)['parse' + kindToString(kind).substring('Bolt'.length)](tokens);
} }
public parseNamespacePath(tokens: BoltTokenStream): BoltQualName { public parseNamespacePath(tokens: BoltTokenStream): BoltModulePath {
let modulePath = null; let isAbsolute = false;
let elements = [];
if (tokens.peek(2).kind === SyntaxKind.BoltColonColon) { while (true) {
modulePath = []; const t1 = tokens.get();
while (true) { assertToken(t1, SyntaxKind.BoltIdentifier);
modulePath.push(tokens.get() as BoltIdentifier) elements.push(t1 as BoltIdentifier)
tokens.get(); const t2 = tokens.peek();
const t0 = tokens.peek(2); if (t2.kind !== SyntaxKind.BoltColonColon) {
if (t0.kind !== SyntaxKind.BoltColonColon) { break;
break;
}
} }
tokens.get();
} }
const name = tokens.get(); const result = createBoltModulePath(isAbsolute, elements);
assertToken(name, SyntaxKind.BoltIdentifier); setOrigNodeRange(result, elements[0], elements[elements.length-1]);
const startNode = modulePath !== null ? modulePath[0] : name; return result;
const endNode = name;
const node = createBoltQualName(modulePath, name as BoltIdentifier, null);
setOrigNodeRange(node, startNode, endNode);
return node;
} }
public parseQualName(tokens: BoltTokenStream): BoltQualName { public parseQualName(tokens: BoltTokenStream): BoltQualName {
@ -253,7 +250,7 @@ export class Parser {
public parseRecordPattern(tokens: BoltTokenStream): BoltRecordPattern { public parseRecordPattern(tokens: BoltTokenStream): BoltRecordPattern {
const name = this.parseNamespacePath(tokens); const name = this.parseTypeExpression(tokens);
const t1 = tokens.get(); const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltBraced); assertToken(t1, SyntaxKind.BoltBraced);
@ -384,11 +381,11 @@ export class Parser {
public parseReferenceTypeExpression(tokens: BoltTokenStream): BoltReferenceTypeExpression { public parseReferenceTypeExpression(tokens: BoltTokenStream): BoltReferenceTypeExpression {
const name = this.parseNamespacePath(tokens) const path = this.parseNamespacePath(tokens)
const t1 = tokens.peek(); const t1 = tokens.peek();
let typeArgs: BoltTypeExpression[] | null = null; let typeArgs: BoltTypeExpression[] | null = null;
let lastToken: BoltToken = path.elements[path.elements.length-1];
if (t1.kind === SyntaxKind.BoltLtSign) { if (t1.kind === SyntaxKind.BoltLtSign) {
typeArgs = []; typeArgs = [];
@ -409,10 +406,11 @@ export class Parser {
} }
const t4 = tokens.get(); const t4 = tokens.get();
assertToken(t4, SyntaxKind.BoltGtSign); assertToken(t4, SyntaxKind.BoltGtSign);
lastToken = t4;
} }
const node = createBoltReferenceTypeExpression(name, typeArgs); const node = createBoltReferenceTypeExpression(path, typeArgs);
setOrigNodeRange(node, name, name); setOrigNodeRange(node, path.elements[0], lastToken);
return node; return node;
} }
@ -836,9 +834,7 @@ export class Parser {
t0 = tokens.get(); t0 = tokens.get();
} }
if (t0.kind !== SyntaxKind.BoltStructKeyword) { assertToken(t0, SyntaxKind.BoltStructKeyword);
throw new ParseError(t0, [SyntaxKind.BoltStructKeyword])
}
const t1 = tokens.get(); const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltIdentifier); assertToken(t1, SyntaxKind.BoltIdentifier);
@ -925,15 +921,15 @@ export class Parser {
let t0 = tokens.get(); let t0 = tokens.get();
const firstToken = t0; const firstToken = t0;
if (t0.kind === SyntaxKind.BoltPubKeyword) { if (t0.kind === SyntaxKind.BoltPubKeyword) {
tokens.get();
modifiers |= BoltModifiers.IsPublic; modifiers |= BoltModifiers.IsPublic;
t0 = tokens.peek(); t0 = tokens.get();
} }
if (t0.kind !== SyntaxKind.BoltModKeyword) { if (t0.kind !== SyntaxKind.BoltModKeyword) {
throw new ParseError(t0, [SyntaxKind.BoltModKeyword]) throw new ParseError(t0, [SyntaxKind.BoltModKeyword])
} }
// FIXME should fail to parse absolute paths
const name = this.parseNamespacePath(tokens); const name = this.parseNamespacePath(tokens);
const t1 = tokens.get(); const t1 = tokens.get();
@ -942,7 +938,7 @@ export class Parser {
} }
const sentences = this.parseSourceElements(createTokenStream(t1)); const sentences = this.parseSourceElements(createTokenStream(t1));
const node = createBoltModule(modifiers, name, sentences); const node = createBoltModule(modifiers, name.elements, sentences);
setOrigNodeRange(node, firstToken, t1); setOrigNodeRange(node, firstToken, t1);
return node; return node;
} }

View file

@ -190,6 +190,10 @@ export function verbose(message: string) {
console.error(chalk.gray('[') + chalk.magenta('verb') + ' ' + chalk.gray(moment().format(DATETIME_FORMAT) + ']') + ' ' + message); console.error(chalk.gray('[') + chalk.magenta('verb') + ' ' + chalk.gray(moment().format(DATETIME_FORMAT) + ']') + ' ' + message);
} }
export function warn(message: string) {
console.error(chalk.gray('[') + chalk.red('warn') + ' ' + chalk.gray(moment().format(DATETIME_FORMAT) + ']') + ' ' + message);
}
export function upsearchSync(filename: string, startDir = '.') { export function upsearchSync(filename: string, startDir = '.') {
let currDir = startDir; let currDir = startDir;
while (true) { while (true) {