diff --git a/src/analysis.ts b/src/analysis.ts index 2e4f0aab7..b0c366b13 100644 --- a/src/analysis.ts +++ b/src/analysis.ts @@ -37,6 +37,7 @@ export class Analyser { } case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: { for (const element of node.elements) { visit(element, source); diff --git a/src/checker.ts b/src/checker.ts index 62cbf81c2..7ffe4ec01 100644 --- a/src/checker.ts +++ b/src/checker.ts @@ -1103,6 +1103,7 @@ export class Checker { switch (node.kind) { case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: { for (const element of node.elements) { this.infer(element); @@ -1588,6 +1589,7 @@ export class Checker { switch (node.kind) { case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: { const env = node.typeEnv = new TypeEnv(parentEnv); for (const element of node.elements) { diff --git a/src/cst.ts b/src/cst.ts index ac855f080..54af309df 100644 --- a/src/cst.ts +++ b/src/cst.ts @@ -182,14 +182,14 @@ export const enum SyntaxKind { Initializer, TypeAssert, Param, - Module, + ModuleDeclaration, SourceFile, } export type Syntax = SourceFile - | Module + | ModuleDeclaration | Token | Param | Body @@ -220,7 +220,8 @@ function isNodeWithScope(node: Syntax): node is NodeWithScope { export const enum Symkind { Var = 1, Type = 2, - Any = Var | Type + Module = 4, + Any = Var | Type | Module } export class Scope { @@ -267,6 +268,14 @@ export class Scope { } break; } + case SyntaxKind.ModuleDeclaration: + { + this.add(node.name.text, node, Symkind.Module); + for (const element of node.elements) { + this.scan(element); + } + break; + } case SyntaxKind.ExpressionStatement: case SyntaxKind.ReturnStatement: case SyntaxKind.IfStatement: @@ -2194,15 +2203,18 @@ export class Initializer extends SyntaxBase { } -export class Module extends SyntaxBase { +export class ModuleDeclaration extends SyntaxBase { - public readonly kind = SyntaxKind.Module; + public readonly kind = SyntaxKind.ModuleDeclaration; + + public typeEnv?: TypeEnv; public constructor( public pubKeyword: PubKeyword | null, public modKeyword: ModKeyword, - public name: Identifier, - public body: Body, + public name: IdentifierAlt, + public blockStart: BlockStart, + public elements: SourceFileElement[], ) { super(); } @@ -2215,7 +2227,10 @@ export class Module extends SyntaxBase { } public getLastToken(): Token { - return this.body.getLastToken(); + if (this.elements.length > 0) { + return this.elements[this.elements.length-1].getLastToken(); + } + return this.blockStart; } } @@ -2223,7 +2238,7 @@ export class Module extends SyntaxBase { export type SourceFileElement = Statement | Declaration - | Module + | ModuleDeclaration export class SourceFile extends SyntaxBase { diff --git a/src/parser.ts b/src/parser.ts index f0468b6c1..cc5199f7e 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -59,6 +59,7 @@ import { LiteralPattern, DisjunctivePattern, TupleTypeExpression, + ModuleDeclaration, } from "./cst" import { Stream } from "./util"; @@ -954,11 +955,38 @@ export class Parser { return new ImportDeclaration(importKeyword, importSource); } + public parseModuleDeclaration(): ModuleDeclaration { + let pubKeyword = null; + let t0 = this.getToken(); + if (t0.kind === SyntaxKind.PubKeyword) { + pubKeyword = t0; + t0 = this.getToken(); + } + if (t0.kind !== SyntaxKind.ModKeyword) { + this.raiseParseError(t0, [ SyntaxKind.ModKeyword ]); + } + const name = this.expectToken(SyntaxKind.IdentifierAlt); + const blockStart = this.expectToken(SyntaxKind.BlockStart); + const elements = []; + for (;;) { + const t1 = this.peekToken(); + if (t1.kind === SyntaxKind.BlockEnd) { + this.getToken(); + break; + } + elements.push(this.parseSourceFileElement()); + } + this.expectToken(SyntaxKind.LineFoldEnd); + return new ModuleDeclaration(pubKeyword, t0, name, blockStart, elements); + } + public parseSourceFileElement(): SourceFileElement { const t0 = this.peekTokenAfterModifiers(); switch (t0.kind) { case SyntaxKind.LetKeyword: return this.parseLetDeclaration(); + case SyntaxKind.ModKeyword: + return this.parseModuleDeclaration(); case SyntaxKind.ImportKeyword: return this.parseImportDeclaration(); case SyntaxKind.StructKeyword: diff --git a/src/scanner.ts b/src/scanner.ts index 93a147905..f4babeed4 100644 --- a/src/scanner.ts +++ b/src/scanner.ts @@ -41,6 +41,7 @@ import { RArrowAlt, VBar, ForeignKeyword, + ModKeyword, } from "./cst" import { Diagnostics, UnexpectedCharDiagnostic } from "./diagnostics" import { Stream, BufferedStream, assert } from "./util"; @@ -368,6 +369,7 @@ export class Scanner extends BufferedStream { case 'enum': return new EnumKeyword(startPos); case 'match': return new MatchKeyword(startPos); case 'foreign': return new ForeignKeyword(startPos); + case 'mod': return new ModKeyword(startPos); default: if (isUpper(text[0])) { return new IdentifierAlt(text, startPos);