From d0aed2405fe5f013fc4c714f86eff3391bde4445 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Sun, 24 May 2020 22:23:18 +0200 Subject: [PATCH] Some minor fixes and extensions to parser and type checker --- src/ast.d.ts | 264 ++++++++++++++++++++------------------ src/bin/bolt.ts | 23 +++- src/checker.ts | 10 +- src/common.ts | 2 + src/emitter.ts | 9 ++ src/foreign/js/parser.ts | 3 +- src/foreign/js/scanner.ts | 4 +- src/parser.ts | 25 +++- src/scanner.ts | 2 + 9 files changed, 198 insertions(+), 144 deletions(-) diff --git a/src/ast.d.ts b/src/ast.d.ts index 2c0d996d8..817745b48 100644 --- a/src/ast.d.ts +++ b/src/ast.d.ts @@ -21,131 +21,132 @@ export const enum SyntaxKind { BoltExMark = 26, BoltLtSign = 27, BoltVBar = 28, - BoltQuoteKeyword = 30, - BoltFnKeyword = 31, - BoltForeignKeyword = 32, - BoltForKeyword = 33, - BoltLetKeyword = 34, - BoltReturnKeyword = 35, - BoltLoopKeyword = 36, - BoltYieldKeyword = 37, - BoltMatchKeyword = 38, - BoltImportKeyword = 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, - BoltReferenceTypeExpression = 55, - BoltFunctionTypeExpression = 56, - BoltTypeParameter = 57, - BoltBindPattern = 59, - BoltTypePattern = 60, - BoltExpressionPattern = 61, - BoltTuplePatternElement = 62, - BoltTuplePattern = 63, - BoltRecordFieldPattern = 64, - BoltRecordPattern = 65, - BoltQuoteExpression = 67, - BoltReferenceExpression = 68, - BoltMemberExpression = 69, - BoltFunctionExpression = 70, - BoltCallExpression = 71, - BoltYieldExpression = 72, - BoltMatchArm = 73, - BoltMatchExpression = 74, - BoltCase = 75, - BoltCaseExpression = 76, - BoltBlockExpression = 77, - BoltConstantExpression = 78, - BoltReturnStatement = 80, - BoltConditionalCase = 81, - BoltConditionalStatement = 82, - BoltResumeStatement = 83, - BoltExpressionStatement = 84, - BoltParameter = 85, - BoltModule = 89, - BoltFunctionDeclaration = 91, - BoltVariableDeclaration = 92, - BoltPlainImportSymbol = 94, - BoltImportDeclaration = 95, - BoltTraitDeclaration = 96, - BoltImplDeclaration = 97, - BoltTypeAliasDeclaration = 98, - BoltRecordField = 100, - BoltRecordDeclaration = 101, - BoltMacroCall = 103, - JSOperator = 106, - JSIdentifier = 107, - JSString = 108, - JSInteger = 109, - JSFromKeyword = 110, - JSReturnKeyword = 111, - JSTryKeyword = 112, - JSFinallyKeyword = 113, - JSCatchKeyword = 114, - JSImportKeyword = 115, - JSAsKeyword = 116, - JSConstKeyword = 117, - JSLetKeyword = 118, - JSExportKeyword = 119, - JSFunctionKeyword = 120, - JSWhileKeyword = 121, - JSForKeyword = 122, - JSCloseBrace = 123, - JSCloseBracket = 124, - JSCloseParen = 125, - JSOpenBrace = 126, - JSOpenBracket = 127, - JSOpenParen = 128, - JSSemi = 129, - JSComma = 130, - JSDot = 131, - JSDotDotDot = 132, - JSMulOp = 133, - JSAddOp = 134, - JSDivOp = 135, - JSSubOp = 136, - JSLtOp = 137, - JSGtOp = 138, - JSBOrOp = 139, - JSBXorOp = 140, - JSBAndOp = 141, - JSBNotOp = 142, - JSNotOp = 143, - JSBindPattern = 145, - JSConstantExpression = 147, - JSMemberExpression = 148, - JSCallExpression = 149, - JSBinaryExpression = 150, - JSUnaryExpression = 151, - JSNewExpression = 152, - JSSequenceExpression = 153, - JSConditionalExpression = 154, - JSLiteralExpression = 156, - JSReferenceExpression = 157, - JSCatchBlock = 161, - JSTryCatchStatement = 162, - JSExpressionStatement = 163, - JSConditionalCase = 164, - JSConditionalStatement = 165, - JSReturnStatement = 166, - JSParameter = 167, - JSImportStarBinding = 171, - JSImportAsBinding = 172, - JSImportDeclaration = 173, - JSFunctionDeclaration = 174, - JSArrowFunctionDeclaration = 175, - JSLetDeclaration = 176, - JSSourceFile = 177, + BoltWhereKeyword = 30, + BoltQuoteKeyword = 31, + BoltFnKeyword = 32, + BoltForeignKeyword = 33, + BoltForKeyword = 34, + BoltLetKeyword = 35, + BoltReturnKeyword = 36, + BoltLoopKeyword = 37, + BoltYieldKeyword = 38, + BoltMatchKeyword = 39, + BoltImportKeyword = 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, + BoltReferenceTypeExpression = 56, + BoltFunctionTypeExpression = 57, + BoltTypeParameter = 58, + BoltBindPattern = 60, + BoltTypePattern = 61, + BoltExpressionPattern = 62, + BoltTuplePatternElement = 63, + BoltTuplePattern = 64, + BoltRecordFieldPattern = 65, + BoltRecordPattern = 66, + BoltQuoteExpression = 68, + BoltReferenceExpression = 69, + BoltMemberExpression = 70, + BoltFunctionExpression = 71, + BoltCallExpression = 72, + BoltYieldExpression = 73, + BoltMatchArm = 74, + BoltMatchExpression = 75, + BoltCase = 76, + BoltCaseExpression = 77, + BoltBlockExpression = 78, + BoltConstantExpression = 79, + BoltReturnStatement = 81, + BoltConditionalCase = 82, + BoltConditionalStatement = 83, + BoltResumeStatement = 84, + BoltExpressionStatement = 85, + BoltParameter = 86, + BoltModule = 90, + BoltFunctionDeclaration = 92, + BoltVariableDeclaration = 93, + BoltPlainImportSymbol = 95, + BoltImportDeclaration = 96, + BoltTraitDeclaration = 97, + BoltImplDeclaration = 98, + BoltTypeAliasDeclaration = 99, + BoltRecordField = 101, + BoltRecordDeclaration = 102, + BoltMacroCall = 104, + JSOperator = 107, + JSIdentifier = 108, + JSString = 109, + JSInteger = 110, + JSFromKeyword = 111, + JSReturnKeyword = 112, + JSTryKeyword = 113, + JSFinallyKeyword = 114, + JSCatchKeyword = 115, + JSImportKeyword = 116, + JSAsKeyword = 117, + JSConstKeyword = 118, + JSLetKeyword = 119, + JSExportKeyword = 120, + JSFunctionKeyword = 121, + JSWhileKeyword = 122, + JSForKeyword = 123, + JSCloseBrace = 124, + JSCloseBracket = 125, + JSCloseParen = 126, + JSOpenBrace = 127, + JSOpenBracket = 128, + JSOpenParen = 129, + JSSemi = 130, + JSComma = 131, + JSDot = 132, + JSDotDotDot = 133, + JSMulOp = 134, + JSAddOp = 135, + JSDivOp = 136, + JSSubOp = 137, + JSLtOp = 138, + JSGtOp = 139, + JSBOrOp = 140, + JSBXorOp = 141, + JSBAndOp = 142, + JSBNotOp = 143, + JSNotOp = 144, + JSBindPattern = 146, + JSConstantExpression = 148, + JSMemberExpression = 149, + JSCallExpression = 150, + JSBinaryExpression = 151, + JSUnaryExpression = 152, + JSNewExpression = 153, + JSSequenceExpression = 154, + JSConditionalExpression = 155, + JSLiteralExpression = 157, + JSReferenceExpression = 158, + JSCatchBlock = 162, + JSTryCatchStatement = 163, + JSExpressionStatement = 164, + JSConditionalCase = 165, + JSConditionalStatement = 166, + JSReturnStatement = 167, + JSParameter = 168, + JSImportStarBinding = 172, + JSImportAsBinding = 173, + JSImportDeclaration = 174, + JSFunctionDeclaration = 175, + JSArrowFunctionDeclaration = 176, + JSLetDeclaration = 177, + JSSourceFile = 178, } @@ -195,6 +196,7 @@ export type Token | BoltExMark | BoltLtSign | BoltVBar + | BoltWhereKeyword | BoltQuoteKeyword | BoltFnKeyword | BoltForeignKeyword @@ -291,6 +293,7 @@ export type BoltToken | BoltExMark | BoltLtSign | BoltVBar + | BoltWhereKeyword | BoltQuoteKeyword | BoltFnKeyword | BoltForeignKeyword @@ -412,7 +415,8 @@ export interface BoltVBar extends SyntaxBase { } export type BoltKeyword - = BoltQuoteKeyword + = BoltWhereKeyword + | BoltQuoteKeyword | BoltFnKeyword | BoltForeignKeyword | BoltForKeyword @@ -432,6 +436,10 @@ export type BoltKeyword | BoltImplKeyword +export interface BoltWhereKeyword extends SyntaxBase { + kind: SyntaxKind.BoltWhereKeyword; +} + export interface BoltQuoteKeyword extends SyntaxBase { kind: SyntaxKind.BoltQuoteKeyword; } @@ -1294,6 +1302,7 @@ export type BoltSyntax | BoltExMark | BoltLtSign | BoltVBar + | BoltWhereKeyword | BoltQuoteKeyword | BoltFnKeyword | BoltForeignKeyword @@ -1446,6 +1455,7 @@ export type Syntax | BoltExMark | BoltLtSign | BoltVBar + | BoltWhereKeyword | BoltQuoteKeyword | BoltFnKeyword | BoltForeignKeyword @@ -1596,6 +1606,7 @@ export function createBoltGtSign(span?: TextSpan | null): BoltGtSign; export function createBoltExMark(span?: TextSpan | null): BoltExMark; export function createBoltLtSign(span?: TextSpan | null): BoltLtSign; export function createBoltVBar(span?: TextSpan | null): BoltVBar; +export function createBoltWhereKeyword(span?: TextSpan | null): BoltWhereKeyword; export function createBoltQuoteKeyword(span?: TextSpan | null): BoltQuoteKeyword; export function createBoltFnKeyword(span?: TextSpan | null): BoltFnKeyword; export function createBoltForeignKeyword(span?: TextSpan | null): BoltForeignKeyword; @@ -1749,6 +1760,7 @@ export function isBoltExMark(value: any): value is BoltExMark; export function isBoltLtSign(value: any): value is BoltLtSign; export function isBoltVBar(value: any): value is BoltVBar; export function isBoltKeyword(value: any): value is BoltKeyword; +export function isBoltWhereKeyword(value: any): value is BoltWhereKeyword; export function isBoltQuoteKeyword(value: any): value is BoltQuoteKeyword; export function isBoltFnKeyword(value: any): value is BoltFnKeyword; export function isBoltForeignKeyword(value: any): value is BoltForeignKeyword; diff --git a/src/bin/bolt.ts b/src/bin/bolt.ts index 2c767086f..27dc5f8b9 100644 --- a/src/bin/bolt.ts +++ b/src/bin/bolt.ts @@ -3,6 +3,9 @@ import "reflect-metadata" import "source-map-support/register" +import { sync as globSync } from "glob" +import * as path from "path" +import * as fs from "fs" import yargs from "yargs" import { Program } from "../program" @@ -10,9 +13,9 @@ import { parseSourceFile } from "../parser" import { BoltSourceFile} from "../ast" import { Frontend } from "../frontend" -global.debug = function (value: any) { - console.error(require('util').inspect(value, { depth: Infinity, colors: true })) -} +//global.print = function (value: any) { +// console.error(require('util').inspect(value, { depth: Infinity, colors: true })) +//} function toArray(value: T | T[]): T[] { if (Array.isArray(value)) { @@ -40,6 +43,18 @@ function flatMap(array: T[], proc: (element: T) => T[]) { return out } +function loadAllSourceFiles(filenames: string[]): BoltSourceFile[] { + const sourceFiles = []; + for (const filename of filenames) { + if (fs.statSync(filename).isDirectory()) { + for (const filepath of globSync(path.join(filename, '**/*.bolt'))) { + sourceFiles.push(parseSourceFile(filepath)); + } + } + } + return sourceFiles; +} + yargs .command( @@ -75,7 +90,7 @@ yargs , args => { - const sourceFiles = toArray(args.files as string[] | string).map(parseSourceFile); + const sourceFiles = loadAllSourceFiles(toArray(args.files as string[] | string)); const program = new Program(sourceFiles); const frontend = new Frontend(); frontend.typeCheck(program); diff --git a/src/checker.ts b/src/checker.ts index ce8a60ba4..0c3d19c50 100644 --- a/src/checker.ts +++ b/src/checker.ts @@ -54,6 +54,7 @@ import { } from "./diagnostics"; import { createAnyType, isOpaqueType, createOpaqueType, Type, createVoidType, createVariantType, isVoidType } from "./types"; import { getReturnStatementsInFunctionBody } from "./common"; +import {emit} from "./emitter"; interface SymbolInfo { declarations: BoltDeclaration[]; @@ -207,6 +208,7 @@ export class TypeChecker { for (const element of node.elements) { visitSourceElement(element); } + break; } case SyntaxKind.BoltRecordDeclaration: @@ -457,7 +459,7 @@ export class TypeChecker { { const scope = this.getScopeSurroundingNode(node); const sym = createSymbol(node); - this.addSymbol(node.name.text, scope, sym); + this.addSymbol(emit(node.name), scope, sym); break; } @@ -473,10 +475,12 @@ export class TypeChecker { } private addSymbol(name: string, scope: Scope, sym: SymbolInfo): void { + console.error(`Adding symbol ${name}`); this.symbols.set(`${name}@${(scope as any).id}`, sym); } private addTypeSymbol(name: string, scope: TypeScope, sym: TypeSymbolInfo): void { + console.error(`Adding type symbol ${name}`); this.typeSymbols.set(`${name}@${(scope as any).id}`, sym); } @@ -615,7 +619,7 @@ export class TypeChecker { scope = parentScope; } } - const sym = this.findSymbolInScopeOf(node.name.name.text, scope); + const sym = this.findSymbolInScopeOf(emit(node.name.name), scope); if (sym === null) { return null; } @@ -624,7 +628,7 @@ export class TypeChecker { public resolveTypeReferenceExpression(node: BoltReferenceTypeExpression): BoltTypeDeclaration | null { const typeScope = this.getTypeScopeSurroundingNode(node); - const typeSym = this.findSymbolInTypeScopeOf(node.name.name.text, typeScope); + const typeSym = this.findSymbolInTypeScopeOf(emit(node.name.name), typeScope); if (typeSym === null) { return null; } diff --git a/src/common.ts b/src/common.ts index 9c1f8281d..18c6f59d5 100644 --- a/src/common.ts +++ b/src/common.ts @@ -178,6 +178,8 @@ export function describeKind(kind: SyntaxKind): string { return "an integer" case SyntaxKind.BoltFnKeyword: return "'fn'" + case SyntaxKind.BoltWhereKeyword: + return "'where'"; case SyntaxKind.BoltQuoteKeyword: return "'quote'"; case SyntaxKind.BoltModKeyword: diff --git a/src/emitter.ts b/src/emitter.ts index b48e5b5e1..573dab8a8 100644 --- a/src/emitter.ts +++ b/src/emitter.ts @@ -9,6 +9,15 @@ export class Emitter { switch (node.kind) { + case SyntaxKind.BoltQualName: + if (node.modulePath !== null) { + for (const element of node.modulePath) { + out += '.' + element.text; + } + } + out += this.emit(node.name); + break; + case SyntaxKind.BoltIdentifier: case SyntaxKind.BoltOperator: out += node.text; diff --git a/src/foreign/js/parser.ts b/src/foreign/js/parser.ts index 9c139652f..1b3722106 100644 --- a/src/foreign/js/parser.ts +++ b/src/foreign/js/parser.ts @@ -1,5 +1,6 @@ -import { Stream, assertToken, setOrigNodeRange, ParseError } from "../../util" +import { Stream } from "../../util" +import { assertToken, setOrigNodeRange, ParseError } from "../../common" import { SyntaxKind, diff --git a/src/foreign/js/scanner.ts b/src/foreign/js/scanner.ts index 835368868..9d94dd76c 100644 --- a/src/foreign/js/scanner.ts +++ b/src/foreign/js/scanner.ts @@ -1,8 +1,6 @@ -import XRegExp from "xregexp" - import { TextPos, TextSpan, TextFile } from "../../text" -import { EOF, ScanError } from "../../util" +import { EOF, ScanError } from "../../common" import { JSToken, diff --git a/src/parser.ts b/src/parser.ts index 89e40bd54..3372f06d3 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1122,6 +1122,12 @@ export class Parser { body = parseForeignLanguage(target, t3.text, t3.span!.file, t3.span!.start); break; } + } else if (t3.kind !== SyntaxKind.BoltSemi) { + const expected = [ SyntaxKind.BoltBraced, SyntaxKind.BoltSemi ]; + if (returnType === null) { + expected.push(SyntaxKind.BoltRArrow); + } + throw new ParseError(t3, expected); } const result = createBoltFunctionDeclaration( @@ -1148,16 +1154,21 @@ export class Parser { assertToken(t0, SyntaxKind.BoltTraitKeyword); const t1 = tokens.get(); assertToken(t1, SyntaxKind.BoltIdentifier); - let typeParams = null + let lastToken = t1; const t2 = tokens.peek(); - if (t2.kind === SyntaxKind.BoltLtSign) { - typeParams = this.parseGenericTypeParameters(tokens); + let typeParams = null + let elements = null; + if (t2.kind === SyntaxKind.BoltLtSign || t2.kind === SyntaxKind.BoltBraced) { + if (t2.kind === SyntaxKind.BoltLtSign) { + typeParams = this.parseGenericTypeParameters(tokens); + } + const t3 = tokens.get(); + assertToken(t3, SyntaxKind.BoltBraced); + elements = this.parseSourceElements(createTokenStream(t3)); + lastToken = t3; } - const t3 = tokens.get(); - assertToken(t3, SyntaxKind.BoltBraced); - const elements = this.parseSourceElements(createTokenStream(t3)); const result = createBoltTraitDeclaration(modifiers, t1 as BoltIdentifier, typeParams, elements as BoltDeclaration[]); - setOrigNodeRange(result, firstToken, t3); + setOrigNodeRange(result, firstToken, lastToken); return result; } diff --git a/src/scanner.ts b/src/scanner.ts index c7eeaa99a..613465b23 100644 --- a/src/scanner.ts +++ b/src/scanner.ts @@ -48,6 +48,7 @@ import { createBoltVBar, createBoltColonColon, createBoltExMark, + createBoltWhereKeyword, } from "./ast" export enum PunctType { @@ -299,6 +300,7 @@ export class Scanner { case 'pub': return createBoltPubKeyword(span); case 'mod': return createBoltModKeyword(span); case 'fn': return createBoltFnKeyword(span); + case 'where': return createBoltWhereKeyword(span); case 'return': return createBoltReturnKeyword(span); case 'match': return createBoltMatchKeyword(span); case 'yield': return createBoltYieldKeyword(span);