From 9d28d47d6f253e388ea69cc40ec50b2a44425786 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Thu, 15 Sep 2022 16:04:49 +0200 Subject: [PATCH] Add an analysis module and integrate with type checker Fixes #34. --- src/bin/bolt-selftest.ts | 5 +- src/bin/bolt.ts | 7 +- src/checker.ts | 210 ++------------------------------------- src/cst.ts | 10 ++ 4 files changed, 29 insertions(+), 203 deletions(-) diff --git a/src/bin/bolt-selftest.ts b/src/bin/bolt-selftest.ts index b67482ae1..c8bf5719f 100644 --- a/src/bin/bolt-selftest.ts +++ b/src/bin/bolt-selftest.ts @@ -11,6 +11,7 @@ import { Checker } from "../checker"; import { TextFile } from "../cst"; import { ConsoleDiagnostics } from "../diagnostics"; import { parseSourceFile } from ".."; +import { Analyser } from "../analysis"; const projectDir = path.resolve(__dirname, '..', '..'); @@ -28,7 +29,9 @@ yargs let sourceFile = parseSourceFile(file, diagnostics); if (sourceFile !== null) { sourceFile.setParents(); - const checker = new Checker(diagnostics); + const analyser = new Analyser(); + analyser.addSourceFile(sourceFile); + const checker = new Checker(analyser, diagnostics); checker.check(sourceFile); } } diff --git a/src/bin/bolt.ts b/src/bin/bolt.ts index 4175d24d3..f558eaa27 100644 --- a/src/bin/bolt.ts +++ b/src/bin/bolt.ts @@ -11,8 +11,9 @@ import { ConsoleDiagnostics, Diagnostics, UnexpectedCharDiagnostic, UnexpectedTo import { Punctuator, ScanError, Scanner } from "../scanner" import { ParseError, Parser } from "../parser" import { Checker } from "../checker" -import { TextFile } from "../cst" +import { SourceFile, TextFile } from "../cst" import { parseSourceFile } from ".." +import { Analyser } from "../analysis" function debug(value: any) { console.error(util.inspect(value, { colors: true, depth: Infinity })); @@ -43,7 +44,9 @@ yargs process.exit(1); } //debug(sourceFile.toJSON()); - const checker = new Checker(diagnostics); + const analyser = new Analyser(); + analyser.addSourceFile(sourceFile); + const checker = new Checker(analyser, diagnostics); checker.check(sourceFile); } diff --git a/src/checker.ts b/src/checker.ts index 8867d0a92..49cab09d1 100644 --- a/src/checker.ts +++ b/src/checker.ts @@ -22,6 +22,7 @@ import { } from "./diagnostics"; import { assert, isEmpty, MultiMap } from "./util"; import { LabeledDirectedHashGraph, LabeledGraph, strongconnect } from "yagl" +import { Analyser } from "./analysis"; const MAX_TYPE_ERROR_COUNT = 5; @@ -794,6 +795,7 @@ export class Checker { private kindSolution = new KVSub(); public constructor( + private analyser: Analyser, private diagnostics: Diagnostics ) { @@ -1503,195 +1505,6 @@ export class Checker { } - private addReferencesToGraph(graph: ReferenceGraph, node: Syntax, source: LetDeclaration | SourceFile) { - - const addReference = (scope: Scope, name: string) => { - const target = scope.lookup(name); - if (target === null || target.kind === SyntaxKind.Param) { - return; - } - assert(target.kind === SyntaxKind.LetDeclaration || target.kind === SyntaxKind.SourceFile); - graph.addEdge(source, target, true); - } - - switch (node.kind) { - - case SyntaxKind.ConstantExpression: - break; - - case SyntaxKind.SourceFile: - { - for (const element of node.elements) { - this.addReferencesToGraph(graph, element, source); - } - break; - } - - case SyntaxKind.ReferenceExpression: - { - assert(node.name.modulePath.length === 0); - addReference(node.getScope(), node.name.name.text); - break; - } - - case SyntaxKind.MemberExpression: - { - this.addReferencesToGraph(graph, node.expression, source); - break; - } - - case SyntaxKind.NamedTupleExpression: - { - for (const arg of node.elements) { - this.addReferencesToGraph(graph, arg, source); - } - break; - } - - case SyntaxKind.StructExpression: - { - for (const member of node.members) { - switch (member.kind) { - case SyntaxKind.PunnedStructExpressionField: - { - addReference(node.getScope(), node.name.text); - break; - } - case SyntaxKind.StructExpressionField: - { - this.addReferencesToGraph(graph, member.expression, source); - break; - }; - } - } - break; - } - - case SyntaxKind.NestedExpression: - { - this.addReferencesToGraph(graph, node.expression, source); - break; - } - - case SyntaxKind.InfixExpression: - { - this.addReferencesToGraph(graph, node.left, source); - this.addReferencesToGraph(graph, node.right, source); - break; - } - - case SyntaxKind.CallExpression: - { - this.addReferencesToGraph(graph, node.func, source); - for (const arg of node.args) { - this.addReferencesToGraph(graph, arg, source); - } - break; - } - - case SyntaxKind.IfStatement: - { - for (const cs of node.cases) { - if (cs.test !== null) { - this.addReferencesToGraph(graph, cs.test, source); - } - for (const element of cs.elements) { - this.addReferencesToGraph(graph, element, source); - } - } - break; - } - - case SyntaxKind.ExpressionStatement: - { - this.addReferencesToGraph(graph, node.expression, source); - break; - } - - case SyntaxKind.ReturnStatement: - { - if (node.expression !== null) { - this.addReferencesToGraph(graph, node.expression, source); - } - break; - } - - case SyntaxKind.LetDeclaration: - { - graph.addVertex(node); - if (node.body !== null) { - switch (node.body.kind) { - case SyntaxKind.ExprBody: - { - this.addReferencesToGraph(graph, node.body.expression, node); - break; - } - case SyntaxKind.BlockBody: - { - for (const element of node.body.elements) { - this.addReferencesToGraph(graph, element, node); - } - break; - } - } - } - break; - } - - case SyntaxKind.TypeDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.StructDeclaration: - break; - - default: - throw new Error(`Unexpected ${node.constructor.name}`); - - } - - } - - private completeReferenceGraph(graph: ReferenceGraph, node: Syntax): void { - - switch (node.kind) { - - case SyntaxKind.SourceFile: - { - for (const element of node.elements) { - this.completeReferenceGraph(graph, element); - } - break; - } - - case SyntaxKind.LetDeclaration: - { - if (isEmpty(graph.getSourceVertices(node))) { - const source = node.parent!.getScope().node; - assert(source.kind === SyntaxKind.LetDeclaration || source.kind === SyntaxKind.SourceFile); - graph.addEdge(source, node, false); - } - if (node.body !== null && node.body.kind === SyntaxKind.BlockBody) { - for (const element of node.body.elements) { - this.completeReferenceGraph(graph, element); - } - } - break; - } - - case SyntaxKind.IfStatement: - case SyntaxKind.ReturnStatement: - case SyntaxKind.ExpressionStatement: - case SyntaxKind.TypeDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.StructDeclaration: - break; - - default: - throw new Error(`Unexpected ${node}`); - - } - - } - private initialize(node: Syntax, parentEnv: TypeEnv): void { switch (node.kind) { @@ -1858,10 +1671,6 @@ export class Checker { env.add('==', new Forall([ a ], [], new TArrow([ a, a ], this.boolType)), Symkind.Var); env.add('not', new Forall([], [], new TArrow([ this.boolType ], this.boolType)), Symkind.Var); - const graph = new LabeledDirectedHashGraph(); - this.addReferencesToGraph(graph, node, node); - this.completeReferenceGraph(graph, node); - this.initialize(node, env); this.pushContext({ @@ -1871,7 +1680,7 @@ export class Checker { returnType: null }); - const sccs = [...strongconnect(graph)]; + const sccs = [...this.analyser.getSortedDeclarations()]; for (const nodes of sccs) { @@ -1950,12 +1759,13 @@ export class Checker { const visitElements = (elements: Syntax[]) => { for (const element of elements) { if (element.kind === SyntaxKind.LetDeclaration - && isFunctionDeclarationLike(element) - && graph.hasEdge(node, element, false)) { - assert(element.pattern.kind === SyntaxKind.BindPattern); - const scheme = this.lookup(element.pattern.name.text, Symkind.Var); - assert(scheme !== null); - this.instantiate(scheme, null); + && isFunctionDeclarationLike(element)) { + if (!this.analyser.isReferencedInParentScope(element)) { + assert(element.pattern.kind === SyntaxKind.BindPattern); + const scheme = this.lookup(element.pattern.name.text, Symkind.Var); + assert(scheme !== null); + this.instantiate(scheme, null); + } } else { this.infer(element); } diff --git a/src/cst.ts b/src/cst.ts index e9bdafd83..ceb70c2f8 100644 --- a/src/cst.ts +++ b/src/cst.ts @@ -223,6 +223,16 @@ export class Scope { this.scan(node); } + public get depth(): number { + let out = 0; + let curr = this.getParent(); + while (curr !== null) { + out++; + curr = curr.getParent(); + } + return out; + } + private getParent(): Scope | null { let curr = this.node.parent; while (curr !== null) {