Re-write the type checker to be more robust

This commit is contained in:
Sam Vervaeck 2020-05-24 11:17:56 +02:00
parent 9ef9ef82d6
commit def4adba40
8 changed files with 483 additions and 215 deletions

View file

@ -42,6 +42,7 @@ node BoltColon > BoltToken;
node BoltDot > BoltToken;
node BoltDotDot > BoltToken;
node BoltRArrow > BoltToken;
node BoltRArrowAlt > BoltToken;
node BoltLArrow > BoltToken;
node BoltEqSign > BoltToken;
node BoltGtSign > BoltToken;

252
src/ast.d.ts vendored
View file

@ -13,127 +13,128 @@ export const enum SyntaxKind {
BoltDot = 15,
BoltDotDot = 16,
BoltRArrow = 17,
BoltLArrow = 18,
BoltEqSign = 19,
BoltGtSign = 20,
BoltLtSign = 21,
BoltFnKeyword = 23,
BoltForeignKeyword = 24,
BoltForKeyword = 25,
BoltLetKeyword = 26,
BoltReturnKeyword = 27,
BoltLoopKeyword = 28,
BoltYieldKeyword = 29,
BoltMatchKeyword = 30,
BoltImportKeyword = 31,
BoltPubKeyword = 32,
BoltModKeyword = 33,
BoltMutKeyword = 34,
BoltEnumKeyword = 35,
BoltStructKeyword = 36,
BoltTypeKeyword = 37,
BoltTraitKeyword = 38,
BoltImplKeyword = 39,
BoltParenthesized = 41,
BoltBraced = 42,
BoltBracketed = 43,
BoltSourceFile = 44,
BoltQualName = 45,
BoltReferenceTypeExpression = 47,
BoltTypeParameter = 48,
BoltBindPattern = 50,
BoltTypePattern = 51,
BoltExpressionPattern = 52,
BoltTuplePatternElement = 53,
BoltTuplePattern = 54,
BoltRecordPatternField = 55,
BoltRecordPattern = 56,
BoltReferenceExpression = 58,
BoltCallExpression = 59,
BoltYieldExpression = 60,
BoltMatchArm = 61,
BoltMatchExpression = 62,
BoltCase = 63,
BoltCaseExpression = 64,
BoltBlockExpression = 65,
BoltConstantExpression = 66,
BoltReturnStatement = 68,
BoltResumeStatement = 69,
BoltExpressionStatement = 70,
BoltParameter = 71,
BoltModule = 75,
BoltFunctionDeclaration = 77,
BoltVariableDeclaration = 78,
BoltPlainImportSymbol = 80,
BoltImportDeclaration = 81,
BoltTraitDeclaration = 82,
BoltImplDeclaration = 83,
BoltTypeAliasDeclaration = 84,
BoltRecordField = 86,
BoltRecordDeclaration = 87,
BoltMacroCall = 89,
JSOperator = 92,
JSIdentifier = 93,
JSString = 94,
JSInteger = 95,
JSFromKeyword = 96,
JSReturnKeyword = 97,
JSTryKeyword = 98,
JSFinallyKeyword = 99,
JSCatchKeyword = 100,
JSImportKeyword = 101,
JSAsKeyword = 102,
JSConstKeyword = 103,
JSLetKeyword = 104,
JSExportKeyword = 105,
JSFunctionKeyword = 106,
JSWhileKeyword = 107,
JSForKeyword = 108,
JSCloseBrace = 109,
JSCloseBracket = 110,
JSCloseParen = 111,
JSOpenBrace = 112,
JSOpenBracket = 113,
JSOpenParen = 114,
JSSemi = 115,
JSComma = 116,
JSDot = 117,
JSDotDotDot = 118,
JSMulOp = 119,
JSAddOp = 120,
JSDivOp = 121,
JSSubOp = 122,
JSLtOp = 123,
JSGtOp = 124,
JSBOrOp = 125,
JSBXorOp = 126,
JSBAndOp = 127,
JSBNotOp = 128,
JSNotOp = 129,
JSBindPattern = 131,
JSConstantExpression = 133,
JSMemberExpression = 134,
JSCallExpression = 135,
JSBinaryExpression = 136,
JSUnaryExpression = 137,
JSNewExpression = 138,
JSSequenceExpression = 139,
JSConditionalExpression = 140,
JSLiteralExpression = 142,
JSReferenceExpression = 143,
JSCatchBlock = 146,
JSTryCatchStatement = 147,
JSExpressionStatement = 148,
JSConditionalStatement = 149,
JSReturnStatement = 150,
JSParameter = 151,
JSImportStarBinding = 155,
JSImportAsBinding = 156,
JSImportDeclaration = 157,
JSFunctionDeclaration = 158,
JSArrowFunctionDeclaration = 159,
JSLetDeclaration = 160,
JSSourceFile = 161,
BoltRArrowAlt = 18,
BoltLArrow = 19,
BoltEqSign = 20,
BoltGtSign = 21,
BoltLtSign = 22,
BoltFnKeyword = 24,
BoltForeignKeyword = 25,
BoltForKeyword = 26,
BoltLetKeyword = 27,
BoltReturnKeyword = 28,
BoltLoopKeyword = 29,
BoltYieldKeyword = 30,
BoltMatchKeyword = 31,
BoltImportKeyword = 32,
BoltPubKeyword = 33,
BoltModKeyword = 34,
BoltMutKeyword = 35,
BoltEnumKeyword = 36,
BoltStructKeyword = 37,
BoltTypeKeyword = 38,
BoltTraitKeyword = 39,
BoltImplKeyword = 40,
BoltParenthesized = 42,
BoltBraced = 43,
BoltBracketed = 44,
BoltSourceFile = 45,
BoltQualName = 46,
BoltReferenceTypeExpression = 48,
BoltTypeParameter = 49,
BoltBindPattern = 51,
BoltTypePattern = 52,
BoltExpressionPattern = 53,
BoltTuplePatternElement = 54,
BoltTuplePattern = 55,
BoltRecordPatternField = 56,
BoltRecordPattern = 57,
BoltReferenceExpression = 59,
BoltCallExpression = 60,
BoltYieldExpression = 61,
BoltMatchArm = 62,
BoltMatchExpression = 63,
BoltCase = 64,
BoltCaseExpression = 65,
BoltBlockExpression = 66,
BoltConstantExpression = 67,
BoltReturnStatement = 69,
BoltResumeStatement = 70,
BoltExpressionStatement = 71,
BoltParameter = 72,
BoltModule = 76,
BoltFunctionDeclaration = 78,
BoltVariableDeclaration = 79,
BoltPlainImportSymbol = 81,
BoltImportDeclaration = 82,
BoltTraitDeclaration = 83,
BoltImplDeclaration = 84,
BoltTypeAliasDeclaration = 85,
BoltRecordField = 87,
BoltRecordDeclaration = 88,
BoltMacroCall = 90,
JSOperator = 93,
JSIdentifier = 94,
JSString = 95,
JSInteger = 96,
JSFromKeyword = 97,
JSReturnKeyword = 98,
JSTryKeyword = 99,
JSFinallyKeyword = 100,
JSCatchKeyword = 101,
JSImportKeyword = 102,
JSAsKeyword = 103,
JSConstKeyword = 104,
JSLetKeyword = 105,
JSExportKeyword = 106,
JSFunctionKeyword = 107,
JSWhileKeyword = 108,
JSForKeyword = 109,
JSCloseBrace = 110,
JSCloseBracket = 111,
JSCloseParen = 112,
JSOpenBrace = 113,
JSOpenBracket = 114,
JSOpenParen = 115,
JSSemi = 116,
JSComma = 117,
JSDot = 118,
JSDotDotDot = 119,
JSMulOp = 120,
JSAddOp = 121,
JSDivOp = 122,
JSSubOp = 123,
JSLtOp = 124,
JSGtOp = 125,
JSBOrOp = 126,
JSBXorOp = 127,
JSBAndOp = 128,
JSBNotOp = 129,
JSNotOp = 130,
JSBindPattern = 132,
JSConstantExpression = 134,
JSMemberExpression = 135,
JSCallExpression = 136,
JSBinaryExpression = 137,
JSUnaryExpression = 138,
JSNewExpression = 139,
JSSequenceExpression = 140,
JSConditionalExpression = 141,
JSLiteralExpression = 143,
JSReferenceExpression = 144,
JSCatchBlock = 147,
JSTryCatchStatement = 148,
JSExpressionStatement = 149,
JSConditionalStatement = 150,
JSReturnStatement = 151,
JSParameter = 152,
JSImportStarBinding = 156,
JSImportAsBinding = 157,
JSImportDeclaration = 158,
JSFunctionDeclaration = 159,
JSArrowFunctionDeclaration = 160,
JSLetDeclaration = 161,
JSSourceFile = 162,
}
@ -175,6 +176,7 @@ export type BoltToken
| BoltDot
| BoltDotDot
| BoltRArrow
| BoltRArrowAlt
| BoltLArrow
| BoltEqSign
| BoltGtSign
@ -255,6 +257,10 @@ export interface BoltRArrow extends SyntaxBase<SyntaxKind.BoltRArrow> {
kind: SyntaxKind.BoltRArrow;
}
export interface BoltRArrowAlt extends SyntaxBase<SyntaxKind.BoltRArrowAlt> {
kind: SyntaxKind.BoltRArrowAlt;
}
export interface BoltLArrow extends SyntaxBase<SyntaxKind.BoltLArrow> {
kind: SyntaxKind.BoltLArrow;
}
@ -1085,6 +1091,7 @@ export type BoltSyntax
| BoltDot
| BoltDotDot
| BoltRArrow
| BoltRArrowAlt
| BoltLArrow
| BoltEqSign
| BoltGtSign
@ -1225,6 +1232,7 @@ export type Syntax
| BoltDot
| BoltDotDot
| BoltRArrow
| BoltRArrowAlt
| BoltLArrow
| BoltEqSign
| BoltGtSign
@ -1363,6 +1371,7 @@ export function createBoltColon(span?: TextSpan | null): BoltColon;
export function createBoltDot(span?: TextSpan | null): BoltDot;
export function createBoltDotDot(span?: TextSpan | null): BoltDotDot;
export function createBoltRArrow(span?: TextSpan | null): BoltRArrow;
export function createBoltRArrowAlt(span?: TextSpan | null): BoltRArrowAlt;
export function createBoltLArrow(span?: TextSpan | null): BoltLArrow;
export function createBoltEqSign(span?: TextSpan | null): BoltEqSign;
export function createBoltGtSign(span?: TextSpan | null): BoltGtSign;
@ -1500,6 +1509,7 @@ export function isBoltColon(value: any): value is BoltColon;
export function isBoltDot(value: any): value is BoltDot;
export function isBoltDotDot(value: any): value is BoltDotDot;
export function isBoltRArrow(value: any): value is BoltRArrow;
export function isBoltRArrowAlt(value: any): value is BoltRArrowAlt;
export function isBoltLArrow(value: any): value is BoltLArrow;
export function isBoltEqSign(value: any): value is BoltEqSign;
export function isBoltGtSign(value: any): value is BoltGtSign;

View file

@ -23,7 +23,25 @@
* Note that the `pub`-keyword is not present on `MyType1`.
*/
import {Syntax, SyntaxKind, BoltReferenceExpression, BoltDeclaration, BoltSourceFile, BoltSyntax, BoltReferenceTypeExpression, BoltTypeDeclaration, BoltExpression, BoltFunctionDeclaration, BoltFunctionBodyElement, kindToString, createBoltReferenceTypeExpression, createBoltIdentifier} from "./ast";
import {
Syntax,
SyntaxKind,
BoltReferenceExpression,
BoltDeclaration,
BoltSourceFile,
BoltSyntax,
BoltReferenceTypeExpression,
BoltTypeDeclaration,
BoltExpression,
BoltFunctionDeclaration,
BoltFunctionBodyElement,
kindToString,
BoltStatement,
BoltTypeExpression,
BoltSourceElement,
isBoltStatement,
isBoltDeclaration
} from "./ast";
import {FastStringMap, memoize, assert} from "./util";
import {
DiagnosticPrinter,
@ -34,7 +52,8 @@ import {
E_DECLARATION_NOT_FOUND,
E_INVALID_ARGUMENTS
} from "./diagnostics";
import {createAnyType, isOpaqueType, createOpaqueType, Type} from "./types";
import { createAnyType, isOpaqueType, createOpaqueType, Type, createVoidType, createVariantType, isVoidType } from "./types";
import { getReturnStatementsInFunctionBody } from "./common";
interface SymbolInfo {
declarations: BoltDeclaration[];
@ -78,64 +97,63 @@ export class TypeChecker {
public checkSourceFile(node: BoltSourceFile): void {
const refExps = node.findAllChildrenOfKind(SyntaxKind.BoltReferenceExpression);
for (const refExp of refExps) {
if (this.resolveReferenceExpression(refExp) === null) {
this.diagnostics.add({
const self = this;
for (const element of node.elements) {
visitSourceElement(element);
}
function visitExpression(node: BoltExpression) {
switch (node.kind) {
case SyntaxKind.BoltReferenceExpression:
{
if (self.resolveReferenceExpression(node) === null) {
self.diagnostics.add({
message: E_DECLARATION_NOT_FOUND,
args: { name: refExp.name.name.text },
args: { name: node.name.name.text },
severity: 'error',
node: refExp,
node: node,
})
}
break;
}
const typeRefExps = node.findAllChildrenOfKind(SyntaxKind.BoltReferenceTypeExpression);
for (const typeRefExp of typeRefExps) {
if (this.resolveTypeReferenceExpression(typeRefExp) === null) {
this.diagnostics.add({
message: E_TYPE_DECLARATION_NOT_FOUND,
args: { name: typeRefExp.name.name.text },
severity: 'error',
node: typeRefExp,
})
}
}
case SyntaxKind.BoltCallExpression:
{
const callExps = node.findAllChildrenOfKind(SyntaxKind.BoltCallExpression);
for (const callExp of callExps) {
const fnDecls = this.getAllFunctionsInExpression(callExp.operator);
const fnDecls = self.getAllFunctionsInExpression(node.operator);
for (const fnDecl of fnDecls) {
if (fnDecl.params.length > callExp.operands.length) {
this.diagnostics.add({
message: E_TOO_FEW_ARGUMENTS_FOR_FUNCTION_CALL,
args: { expected: fnDecl.params.length, actual: callExp.operands.length },
severity: 'error',
node: callExp,
})
}
if (fnDecl.params.length > node.operands.length) {
if (fnDecl.params.length < callExp.operands.length) {
this.diagnostics.add({
message: E_TOO_MANY_ARGUMENTS_FOR_FUNCTION_CALL,
args: { expected: fnDecl.params.length, actual: callExp.operands.length },
self.diagnostics.add({
message: E_TOO_FEW_ARGUMENTS_FOR_FUNCTION_CALL,
args: { expected: fnDecl.params.length, actual: node.operands.length },
severity: 'error',
node: callExp,
})
}
node: node,
});
} else if (fnDecl.params.length < node.operands.length) {
self.diagnostics.add({
message: E_TOO_MANY_ARGUMENTS_FOR_FUNCTION_CALL,
args: { expected: fnDecl.params.length, actual: node.operands.length },
severity: 'error',
node: node,
});
} else {
const paramCount = fnDecl.params.length;
for (let i = 0; i < paramCount; i++) {
const arg = callExp.operands[i];
const arg = node.operands[i];
const param = fnDecl.params[i];
let argType = this.getTypeOfNode(arg);
let paramType = this.getTypeOfNode(param);
if (!this.isTypeAssignableTo(argType, paramType)) {
this.diagnostics.add({
let argType = self.getTypeOfNode(arg);
let paramType = self.getTypeOfNode(param);
if (!self.isTypeAssignableTo(argType, paramType)) {
self.diagnostics.add({
message: E_INVALID_ARGUMENTS,
severity: 'error',
args: { name: fnDecl.name.text },
@ -148,6 +166,156 @@ export class TypeChecker {
}
break;
}
default:
throw new Error(`Unknown node of type ${kindToString(node.kind)}.`);
}
}
function visitTypeExpressionn(node: BoltTypeExpression) {
switch (node.kind) {
case SyntaxKind.BoltReferenceTypeExpression:
{
if (self.resolveTypeReferenceExpression(node) === null) {
self.diagnostics.add({
message: E_TYPE_DECLARATION_NOT_FOUND,
args: { name: node.name.name.text },
severity: 'error',
node: node,
})
}
break;
}
default:
throw new Error(`Unknown node of type ${kindToString(node.kind)}.`);
}
}
function visitDeclaration(node: BoltDeclaration) {
switch (node.kind) {
case SyntaxKind.BoltRecordDeclaration:
{
if (node.members !== null) {
for (const member of node.members) {
if (member.kind === SyntaxKind.BoltRecordField) {
visitTypeExpressionn(member.type);
}
}
}
break;
}
case SyntaxKind.BoltFunctionDeclaration:
{
let fnReturnType: Type = createAnyType();
if (node.returnType !== null) {
fnReturnType = self.getTypeOfNode(node.returnType);
}
if (node.body !== null) {
const returnStmts = getReturnStatementsInFunctionBody(node.body)
const validReturnTypes: Type[] = [];
for (const returnStmt of returnStmts) {
if (returnStmt.value === null) {
if (!isVoidType(fnReturnType)) {
self.diagnostics.add({
message: E_MUST_RETURN_A_VALUE,
node: returnStmt,
severity: 'error',
});
}
} else {
checkExpressionMatchesType(returnStmt.value, fnReturnType);
}
//const returnType = self.getTypeOfNode(returnStmt);
//if (!self.isTypeAssignableTo(fnReturnType, returnType)) {
//self.diagnostics.add({
//severity: 'error',
//node: returnStmt.value !== null ? returnStmt.value : returnStmt,
//args: { left: fnReturnType, right: returnType },
//message: E_TYPES_NOT_ASSIGNABLE,
//});
//} else {
//validReturnTypes.push(returnType);
//}
}
}
// TODO Sort the return types and find the largest types, eliminating types that fall under other types.
// Next, add the resulting types as type hints to `fnReturnType`.
break;
}
default:
throw new Error(`Unknown node of type ${kindToString(node.kind)}.`);
}
}
function checkExpressionMatchesType(node: BoltExpression, expectedType: Type) {
switch (node.kind) {
case SyntaxKind.BoltMatchExpression:
{
for (const matchArm of node.arms) {
checkExpressionMatchesType(matchArm.body, expectedType);
}
break;
}
default:
{
const actualType = self.getTypeOfNode(node);
if (!self.isTypeAssignableTo(expectedType, actualType)) {
self.diagnostics.add({
severity: 'error',
message: E_TYPES_NOT_ASSIGNABLE,
args: { left: expectedType, right: actualType },
node,
});
}
break;
}
}
}
function visitStatement(node: BoltStatement) {
switch (node.kind) {
case SyntaxKind.BoltExpressionStatement:
// TODO check for values that should be unwrapped
visitExpression(node.expression);
break;
case SyntaxKind.BoltReturnStatement:
if (node.value !== null) {
visitExpression(node.value);
}
break;
default:
throw new Error(`Unknown node of type ${kindToString(node.kind)}.`);
}
}
function visitSourceElement(node: BoltSourceElement) {
if (isBoltStatement(node)) {
visitStatement(node);
} else if (isBoltDeclaration(node)) {
visitDeclaration(node);
} else {
throw new Error(`Unknown node of kind ${kindToString(node)}`);
}
}
}
private resolveType(name: string, node: BoltSyntax): Type | null {
@ -185,6 +353,13 @@ export class TypeChecker {
}
return type;
}
case SyntaxKind.BoltReturnStatement:
{
if (node.value === null) {
return createVoidType();
}
return this.getTypeOfNode(node.value)
}
case SyntaxKind.BoltConstantExpression:
{
let type;
@ -200,6 +375,10 @@ export class TypeChecker {
assert(type !== null);
return type;
}
case SyntaxKind.BoltMatchExpression:
{
return createVariantType(...node.arms.map(arm => this.getTypeOfNode(arm.body)));
}
default:
throw new Error(`Could not derive type of node ${kindToString(node.kind)}.`);
}

View file

@ -7,7 +7,7 @@ import {
export type BoltFunctionBody = BoltFunctionBodyElement[];
export function getAllReturnStatements(body: BoltFunctionBody): BoltReturnStatement[] {
export function getReturnStatementsInFunctionBody(body: BoltFunctionBody): BoltReturnStatement[] {
const results: BoltReturnStatement[] = [];

View file

@ -59,6 +59,11 @@ import {
createBoltSourceFile,
BoltRecordField,
setParents,
BoltMatchExpression,
createBoltMatchArm,
BoltMatchArm,
createBoltMatchExpression,
createBoltExpressionPattern,
} from "./ast"
import { parseForeignLanguage } from "./foreign"
@ -81,6 +86,13 @@ export function isModifierKeyword(kind: SyntaxKind) {
|| kind === SyntaxKind.BoltForeignKeyword;
}
function assertNoTokens(tokens: BoltTokenStream) {
const t0 = tokens.peek(1);
if (t0.kind !== SyntaxKind.EndOfFile) {
throw new ParseError(t0, [SyntaxKind.EndOfFile]);
}
}
const KIND_EXPRESSION_T0 = [
SyntaxKind.BoltStringLiteral,
SyntaxKind.BoltIntegerLiteral,
@ -156,13 +168,6 @@ export class Parser {
]
]);
protected assertEmpty(tokens: BoltTokenStream) {
const t0 = tokens.peek(1);
if (t0.kind !== SyntaxKind.EndOfFile) {
throw new ParseError(t0, [SyntaxKind.EndOfFile]);
}
}
public parse(kind: SyntaxKind, tokens: BoltTokenStream): BoltSyntax {
return (this as any)['parse' + kindToString(kind).substring('Bolt'.length)](tokens);
}
@ -204,6 +209,17 @@ export class Parser {
const t0 = tokens.peek(1);
if (t0.kind === SyntaxKind.BoltIdentifier) {
return this.parseBindPattern(tokens);
} else if (t0.kind === SyntaxKind.BoltOperator && t0.text === '^') {
tokens.get();
const refExpr = this.parseReferenceExpression(tokens);
const result = createBoltExpressionPattern(refExpr);
setOrigNodeRange(result, t0, refExpr);
return result;
} else if (KIND_EXPRESSION_T0.indexOf(t0.kind) !== -1) {
const expr = this.parseExpression(tokens);
const result = createBoltExpressionPattern(expr);
setOrigNodeRange(result, expr, expr);
return result;
} else {
throw new ParseError(t0, [SyntaxKind.BoltIdentifier])
}
@ -328,9 +344,43 @@ export class Parser {
return node;
}
public parseMatchExpression(tokens: BoltTokenStream): BoltMatchExpression {
const t0 = tokens.get();
assertToken(t0, SyntaxKind.BoltMatchKeyword);
const expr = this.parseExpression(tokens);
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltBraced);
const innerTokens = createTokenStream(t1);
const matchArms: BoltMatchArm[] = [];
while (true) {
const t2 = innerTokens.peek();
if (t2.kind === SyntaxKind.EndOfFile) {
break;
}
const pattern = this.parsePattern(innerTokens);
const t3 = innerTokens.get();
assertToken(t3, SyntaxKind.BoltRArrowAlt);
const expression = this.parseExpression(innerTokens);
const arm = createBoltMatchArm(pattern, expression);
setOrigNodeRange(arm, pattern, expression);
matchArms.push(arm);
const t4 = tokens.peek();
if (t4.kind === SyntaxKind.EndOfFile) {
break;
}
assertToken(t4, SyntaxKind.BoltComma);
tokens.get();
}
const result = createBoltMatchExpression(expr, matchArms);
setOrigNodeRange(result, t0, t1);
return result;
}
protected parsePrimitiveExpression(tokens: BoltTokenStream): BoltExpression {
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.BoltIntegerLiteral || t0.kind === SyntaxKind.BoltStringLiteral) {
if (t0.kind === SyntaxKind.BoltMatchKeyword) {
return this.parseMatchExpression(tokens);
} else if (t0.kind === SyntaxKind.BoltIntegerLiteral || t0.kind === SyntaxKind.BoltStringLiteral) {
return this.parseConstantExpression(tokens);
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
return this.parseReferenceExpression(tokens);
@ -714,7 +764,7 @@ export class Parser {
tokens.get();
const innerTokens = createTokenStream(t0);
const param = this.parseParameter(innerTokens, i++)
this.assertEmpty(innerTokens);
assertNoTokens(innerTokens);
return param
} else {
throw new ParseError(t0, [SyntaxKind.BoltIdentifier, SyntaxKind.BoltParenthesized])
@ -794,7 +844,7 @@ export class Parser {
tokens.get();
switch (target) {
case "Bolt":
body = this.parseStatements(tokens);
body = this.parseStatements(createTokenStream(t3));
break;
default:
body = parseForeignLanguage(target, t3.text, t3.span!.file, t3.span!.start);
@ -870,8 +920,7 @@ export class Parser {
let t0 = tokens.peek(1);
let i = 1;
if (t0.kind === SyntaxKind.BoltPubKeyword) {
i += 1;
t0 = tokens.peek(i);
t0 = tokens.peek(++i);
if (t0.kind !== SyntaxKind.BoltForeignKeyword) {
if (KIND_DECLARATION_KEYWORD.indexOf(t0.kind) === -1) {
throw new ParseError(t0, KIND_DECLARATION_KEYWORD);
@ -918,8 +967,8 @@ export class Parser {
}
if (t0.kind === SyntaxKind.BoltForeignKeyword) {
mustBeFunctionOrVariable = true;
i++;
t0 = tokens.peek(++i);
i += 2;
t0 = tokens.peek(i);
}
if (mustBeFunctionOrVariable
&& t0.kind !== SyntaxKind.BoltStructKeyword
@ -1015,11 +1064,11 @@ export class Parser {
const operator = this.parsePrimitiveExpression(tokens)
const t2 = tokens.get();
if (t2.kind === SyntaxKind.EndOfFile) {
const t2 = tokens.peek();
if (t2.kind !== SyntaxKind.BoltParenthesized) {
return operator;
}
assertToken(t2, SyntaxKind.BoltParenthesized);
tokens.get();
const args: BoltExpression[] = []
const innerTokens = createTokenStream(t2);
@ -1197,4 +1246,4 @@ export function parseSourceFile(filepath: string): BoltSourceFile {
setParents(sourceFile);
return sourceFile;
}
;

View file

@ -11,9 +11,8 @@ import {
setParents,
SyntaxKind,
BoltToken,
BoltSentence,
createBoltRArrowAlt,
createEndOfFile,
createBoltSentence,
createBoltIdentifier,
createBoltRArrow,
createBoltOperator,
@ -39,16 +38,14 @@ import {
createBoltFnKeyword,
createBoltLArrow,
createBoltDotDot,
createJSIdentifier,
JSToken,
createBoltLtSign,
createBoltGtSign,
createBoltModKeyword,
createBoltTypeKeyword,
createBoltForKeyword,
createBoltTraitDeclaration,
createBoltTraitKeyword,
createBoltImplKeyword,
createBoltMatchKeyword,
} from "./ast"
export enum PunctType {
@ -297,6 +294,7 @@ export class Scanner {
case 'mod': return createBoltModKeyword(span);
case 'fn': return createBoltFnKeyword(span);
case 'return': return createBoltReturnKeyword(span);
case 'match': return createBoltMatchKeyword(span);
case 'yield': return createBoltYieldKeyword(span);
case 'for': return createBoltForKeyword(span);
case 'trait': return createBoltTraitKeyword(span);
@ -318,6 +316,7 @@ export class Scanner {
switch (text) {
case '->': return createBoltRArrow(span);
case '=>': return createBoltRArrowAlt(span);
case '<-': return createBoltLArrow(span);
case '<': return createBoltLtSign(span);
case '>': return createBoltGtSign(span);

View file

@ -98,6 +98,10 @@ export class VariantType extends TypeBase {
}
export function createVariantType(...elementTypes: Type[]): VariantType {
return new VariantType(elementTypes);
}
export function isVariantType(value: any): value is VariantType {
return value instanceof VariantType;
}
@ -140,6 +144,30 @@ export class TupleType extends TypeBase {
}
export function createTupleType(...elementTypes: Type[]) {
return new TupleType(elementTypes);
}
export function isTupleType(value: any): value is TupleType {
return value.kind === TypeKind.TupleType;
}
export function createVoidType() {
return createTupleType();
}
export function isVoidType(value: any) {
return isTupleType(value) && value.elementTypes.length === 0;
}
export function narrowType(outer: Type, inner: Type): Type {
if (isAnyType(outer) || isNeverType(inner)) {
return inner;
}
// TODO cover the other cases
return outer;
}
export function intersectTypes(a: Type, b: Type): Type {
if (isNeverType(a) || isNeverType(b)) {
return new NeverType();

View file

@ -351,6 +351,8 @@ export function describeKind(kind: SyntaxKind): string {
return "'for'";
case SyntaxKind.JSTryKeyword:
return "'try'";
case SyntaxKind.BoltRArrowAlt:
return "'=>'";
default:
throw new Error(`failed to describe ${kindToString(kind)}`)
}