parent
83226621e3
commit
9d28d47d6f
4 changed files with 29 additions and 203 deletions
|
@ -11,6 +11,7 @@ import { Checker } from "../checker";
|
||||||
import { TextFile } from "../cst";
|
import { TextFile } from "../cst";
|
||||||
import { ConsoleDiagnostics } from "../diagnostics";
|
import { ConsoleDiagnostics } from "../diagnostics";
|
||||||
import { parseSourceFile } from "..";
|
import { parseSourceFile } from "..";
|
||||||
|
import { Analyser } from "../analysis";
|
||||||
|
|
||||||
const projectDir = path.resolve(__dirname, '..', '..');
|
const projectDir = path.resolve(__dirname, '..', '..');
|
||||||
|
|
||||||
|
@ -28,7 +29,9 @@ yargs
|
||||||
let sourceFile = parseSourceFile(file, diagnostics);
|
let sourceFile = parseSourceFile(file, diagnostics);
|
||||||
if (sourceFile !== null) {
|
if (sourceFile !== null) {
|
||||||
sourceFile.setParents();
|
sourceFile.setParents();
|
||||||
const checker = new Checker(diagnostics);
|
const analyser = new Analyser();
|
||||||
|
analyser.addSourceFile(sourceFile);
|
||||||
|
const checker = new Checker(analyser, diagnostics);
|
||||||
checker.check(sourceFile);
|
checker.check(sourceFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,9 @@ import { ConsoleDiagnostics, Diagnostics, UnexpectedCharDiagnostic, UnexpectedTo
|
||||||
import { Punctuator, ScanError, Scanner } from "../scanner"
|
import { Punctuator, ScanError, Scanner } from "../scanner"
|
||||||
import { ParseError, Parser } from "../parser"
|
import { ParseError, Parser } from "../parser"
|
||||||
import { Checker } from "../checker"
|
import { Checker } from "../checker"
|
||||||
import { TextFile } from "../cst"
|
import { SourceFile, TextFile } from "../cst"
|
||||||
import { parseSourceFile } from ".."
|
import { parseSourceFile } from ".."
|
||||||
|
import { Analyser } from "../analysis"
|
||||||
|
|
||||||
function debug(value: any) {
|
function debug(value: any) {
|
||||||
console.error(util.inspect(value, { colors: true, depth: Infinity }));
|
console.error(util.inspect(value, { colors: true, depth: Infinity }));
|
||||||
|
@ -43,7 +44,9 @@ yargs
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
//debug(sourceFile.toJSON());
|
//debug(sourceFile.toJSON());
|
||||||
const checker = new Checker(diagnostics);
|
const analyser = new Analyser();
|
||||||
|
analyser.addSourceFile(sourceFile);
|
||||||
|
const checker = new Checker(analyser, diagnostics);
|
||||||
checker.check(sourceFile);
|
checker.check(sourceFile);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
202
src/checker.ts
202
src/checker.ts
|
@ -22,6 +22,7 @@ import {
|
||||||
} from "./diagnostics";
|
} from "./diagnostics";
|
||||||
import { assert, isEmpty, MultiMap } from "./util";
|
import { assert, isEmpty, MultiMap } from "./util";
|
||||||
import { LabeledDirectedHashGraph, LabeledGraph, strongconnect } from "yagl"
|
import { LabeledDirectedHashGraph, LabeledGraph, strongconnect } from "yagl"
|
||||||
|
import { Analyser } from "./analysis";
|
||||||
|
|
||||||
const MAX_TYPE_ERROR_COUNT = 5;
|
const MAX_TYPE_ERROR_COUNT = 5;
|
||||||
|
|
||||||
|
@ -794,6 +795,7 @@ export class Checker {
|
||||||
private kindSolution = new KVSub();
|
private kindSolution = new KVSub();
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
|
private analyser: Analyser,
|
||||||
private diagnostics: Diagnostics
|
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 {
|
private initialize(node: Syntax, parentEnv: TypeEnv): void {
|
||||||
|
|
||||||
switch (node.kind) {
|
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('==', new Forall([ a ], [], new TArrow([ a, a ], this.boolType)), Symkind.Var);
|
||||||
env.add('not', new Forall([], [], new TArrow([ this.boolType ], this.boolType)), Symkind.Var);
|
env.add('not', new Forall([], [], new TArrow([ this.boolType ], this.boolType)), Symkind.Var);
|
||||||
|
|
||||||
const graph = new LabeledDirectedHashGraph<NodeWithBindings, boolean>();
|
|
||||||
this.addReferencesToGraph(graph, node, node);
|
|
||||||
this.completeReferenceGraph(graph, node);
|
|
||||||
|
|
||||||
this.initialize(node, env);
|
this.initialize(node, env);
|
||||||
|
|
||||||
this.pushContext({
|
this.pushContext({
|
||||||
|
@ -1871,7 +1680,7 @@ export class Checker {
|
||||||
returnType: null
|
returnType: null
|
||||||
});
|
});
|
||||||
|
|
||||||
const sccs = [...strongconnect(graph)];
|
const sccs = [...this.analyser.getSortedDeclarations()];
|
||||||
|
|
||||||
for (const nodes of sccs) {
|
for (const nodes of sccs) {
|
||||||
|
|
||||||
|
@ -1950,12 +1759,13 @@ export class Checker {
|
||||||
const visitElements = (elements: Syntax[]) => {
|
const visitElements = (elements: Syntax[]) => {
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
if (element.kind === SyntaxKind.LetDeclaration
|
if (element.kind === SyntaxKind.LetDeclaration
|
||||||
&& isFunctionDeclarationLike(element)
|
&& isFunctionDeclarationLike(element)) {
|
||||||
&& graph.hasEdge(node, element, false)) {
|
if (!this.analyser.isReferencedInParentScope(element)) {
|
||||||
assert(element.pattern.kind === SyntaxKind.BindPattern);
|
assert(element.pattern.kind === SyntaxKind.BindPattern);
|
||||||
const scheme = this.lookup(element.pattern.name.text, Symkind.Var);
|
const scheme = this.lookup(element.pattern.name.text, Symkind.Var);
|
||||||
assert(scheme !== null);
|
assert(scheme !== null);
|
||||||
this.instantiate(scheme, null);
|
this.instantiate(scheme, null);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.infer(element);
|
this.infer(element);
|
||||||
}
|
}
|
||||||
|
|
10
src/cst.ts
10
src/cst.ts
|
@ -223,6 +223,16 @@ export class Scope {
|
||||||
this.scan(node);
|
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 {
|
private getParent(): Scope | null {
|
||||||
let curr = this.node.parent;
|
let curr = this.node.parent;
|
||||||
while (curr !== null) {
|
while (curr !== null) {
|
||||||
|
|
Loading…
Reference in a new issue