From 831ae626c31cdb6c4e29d9f3744768e63bd1a554 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Sat, 23 May 2020 15:04:32 +0200 Subject: [PATCH] Fix some compilation errors --- spec/ast.txt | 25 ++++++---- src/ast.d.ts | 4 +- src/checker.ts | 126 +++++++++++++++++++++++++++++------------------ src/evaluator.ts | 34 +++++++------ 4 files changed, 115 insertions(+), 74 deletions(-) diff --git a/spec/ast.txt b/spec/ast.txt index a49dc3ef1..117f96649 100644 --- a/spec/ast.txt +++ b/spec/ast.txt @@ -84,10 +84,6 @@ node BoltQualName { name: BoltSymbol, } -node BoltSentence > BoltSourceElement { - tokens: Vec, -} - node BoltTypeExpression; node BoltReferenceTypeExpression > BoltTypeExpression { @@ -177,7 +173,7 @@ node BoltConstantExpression > BoltExpression { value: BoltValue, } -node BoltStatement > BoltSourceElement; +node BoltStatement > BoltFunctionBodyElement, BoltSourceElement; node BoltReturnStatement > BoltStatement { value: Option, @@ -213,16 +209,18 @@ node BoltModule > BoltDeclaration { elements: Vec, } -node BoltFunctionDeclaration > BoltDeclaration { +node BoltFunctionBodyElement; + +node BoltFunctionDeclaration > BoltFunctionBodyElement, BoltDeclaration { modifiers: BoltDeclarationModifiers, target: String, name: BoltSymbol, params: Vec, returnType: Option, - body: Vec, + body: Vec, } -node BoltVariableDeclaration > BoltDeclaration { +node BoltVariableDeclaration > BoltFunctionBodyElement, BoltDeclaration { modifiers: BoltDeclarationModifiers, bindings: BoltPattern, type: Option, @@ -262,7 +260,9 @@ node BoltTypeAliasDeclaration > BoltDeclaration { typeExpr: BoltTypeExpression, } -node BoltRecordDeclarationField { +node BoltRecordMember; + +node BoltRecordField > BoltRecordMember { name: BoltIdentifier, type: BoltTypeExpression, } @@ -271,11 +271,16 @@ node BoltRecordDeclaration > BoltDeclaration { modifiers: BoltDeclarationModifiers, name: BoltQualName, typeParms: Option>, - fields: Vec, + members: Option>, } node BoltSourceElement; +node BoltMacroCall > BoltRecordMember, BoltStatement, BoltDeclaration, BoltExpression { + name: BoltIdentifier, + text: String, +} + // JavaScript AST definitions type JSValue = Int | String | Bool | Void; diff --git a/src/ast.d.ts b/src/ast.d.ts index bd905b33c..694273749 100644 --- a/src/ast.d.ts +++ b/src/ast.d.ts @@ -583,7 +583,7 @@ export interface BoltFunctionDeclaration extends SyntaxBase { @@ -1403,7 +1403,7 @@ export function createBoltResumeStatement(value: BoltExpression, span?: TextSpan export function createBoltExpressionStatement(expression: BoltExpression, span?: TextSpan | null): BoltExpressionStatement; export function createBoltParameter(index: number, bindings: BoltPattern, type: BoltTypeExpression | null, defaultValue: BoltExpression | null, span?: TextSpan | null): BoltParameter; export function createBoltModule(modifiers: BoltDeclarationModifiers, name: BoltQualName, elements: BoltSourceElement[], span?: TextSpan | null): BoltModule; -export function createBoltFunctionDeclaration(modifiers: BoltDeclarationModifiers, target: string, name: BoltSymbol, params: BoltParameter[], returnType: BoltTypeExpression | null, body: BoltStatement[], span?: TextSpan | null): BoltFunctionDeclaration; +export function createBoltFunctionDeclaration(modifiers: BoltDeclarationModifiers, target: string, name: BoltSymbol, params: BoltParameter[], returnType: BoltTypeExpression | null, body: BoltFunctionBodyElement[], span?: TextSpan | null): BoltFunctionDeclaration; export function createBoltVariableDeclaration(modifiers: BoltDeclarationModifiers, bindings: BoltPattern, type: BoltTypeExpression | null, value: BoltExpression | null, span?: TextSpan | null): BoltVariableDeclaration; export function createBoltPlainImportSymbol(name: BoltQualName, span?: TextSpan | null): BoltPlainImportSymbol; export function createBoltImportDeclaration(file: string, symbols: BoltImportSymbol[], span?: TextSpan | null): BoltImportDeclaration; diff --git a/src/checker.ts b/src/checker.ts index 2c68f6743..86dff2822 100644 --- a/src/checker.ts +++ b/src/checker.ts @@ -5,6 +5,8 @@ import { SyntaxKind, BoltImportDeclaration, BoltPattern, + isBoltTypeAliasDeclaration, + BoltFunctionBodyElement, } from "./ast" import { FastStringMap, getFullTextOfQualName } from "./util" @@ -45,13 +47,13 @@ export const noneType = new PrimType(); export class RecordType { - fieldTypes: FastStringMap = Object.create(null); + private fieldTypes = new FastStringMap(); constructor( iterable: IterableIterator<[string, Type]>, ) { - for (const [name, typ] of iterable) { - this.fieldTypes[name] = typ; + for (const [name, type] of iterable) { + this.fieldTypes.set(name, type); } } @@ -60,18 +62,47 @@ export class RecordType { } getTypeOfField(name: string) { - if (name in this.fieldTypes) { - return this.fieldTypes[name] - } - throw new Error(`Field '${name}' does not exist on this record type.`) + return this.fieldTypes.get(name); } } +interface SymbolInfo { + type: Type | null; + definitions: Syntax[]; +} + export class Scope { - constructor(public origin: Syntax) { + private symbolsByLocalName = new FastStringMap(); + constructor( + public originatingNode: Syntax, + public parentScope?: Scope | null + ) { + + } + + public getSymbolNamed(name: string): SymbolInfo | null { + let currScope: Scope | null = this; + while (true) { + if (currScope.symbolsByLocalName.has(name)) { + return currScope.symbolsByLocalName.get(name); + } + currScope = currScope.parentScope; + if (currScope === null) { + break; + } + } + return null; + } + + public getTypeNamed(name: string): Type | null { + const sym = this.getSymbolNamed(name); + if (sym === null || !introducesNewType(sym.definitions[0].kind)) { + return null; + } + return sym.type!; } } @@ -87,6 +118,16 @@ function* map(iterable: Iterable, proc: (value: T) => R): IterableItera } } +function introducesNewType(kind: SyntaxKind): boolean { + return kind === SyntaxKind.BoltRecordDeclaration + || kind === SyntaxKind.BoltTypeAliasDeclaration; +} + +function introducesNewScope(kind: SyntaxKind): boolean { + return kind === SyntaxKind.BoltFunctionDeclaration + || kind === SyntaxKind.BoltSourceFile; +} + function getFullName(node: Syntax) { let out = [] let curr: Syntax | null = node; @@ -112,22 +153,19 @@ function getFullName(node: Syntax) { export class TypeChecker { - protected symbols: FastStringMap = Object.create(null) - protected types = new Map(); - protected scopes = new Map(); + private symbols = new FastStringMap(); + private types = new Map(); + private scopes = new Map(); - constructor() { - } - - protected inferTypeFromUsage(bindings: BoltPattern, body: Body) { + private inferTypeFromUsage(bindings: BoltPattern, body: BoltFunctionBodyElement[]) { return anyType; } - protected getTypeOfBody(body: Body) { + private getTypeOfBody(body: BoltFunctionBodyElement[]) { return anyType; } - protected createType(node: Syntax): Type { + private createType(node: Syntax): Type { console.error(`creating type for ${kindToString(node.kind)}`); @@ -139,11 +177,6 @@ export class TypeChecker { case SyntaxKind.BoltConstantExpression: return node.value.type; - case SyntaxKind.BoltNewTypeDeclaration: - console.log(getFullName(node.name)) - this.symbols[getFullName(node.name)] = new PrimType(); - return noneType; - case SyntaxKind.BoltExpressionStatement: return voidType; @@ -171,21 +204,29 @@ export class TypeChecker { }) return new FunctionType(paramTypes, returnType); - case SyntaxKind.BoltReferenceTypeNode: + case SyntaxKind.BoltReferenceTypeExpression: const name = getFullTextOfQualName(node.name); - const reffed = this.getTypeNamed(name); + const scope = this.getScope(node); + let reffed = scope.getTypeNamed(name); if (reffed === null) { - throw new Error(`Could not find a type named '${name}'`); + reffed = anyType; } return reffed; case SyntaxKind.BoltRecordDeclaration: - const typ = new RecordType(map(node.fields, field => ([field.name.text, this.getTypeOfNode(field.type)]))); + const fullName = getFullName(node); + let type; - this.symbols[getFullName(node)] = typ; + if (node.members === null) { + type = new PrimType(); + this.symbols.set(fullName, type); + } else { + type = new RecordType(map(node.members, member => ([field.name.text, this.getTypeOfNode(field.type)]))); + this.symbols.set(fullName, type); + } - return typ; + return type; case SyntaxKind.BoltParameter: if (node.type !== null) { @@ -200,13 +241,14 @@ export class TypeChecker { } - getTypeNamed(name: string) { - return name in this.symbols - ? this.symbols[name] - : null + public getSymbolNamed(name: string) { + if (!this.symbols.has(name)) { + return null; + } + return this.symbols.get(name); } - getTypeOfNode(node: Syntax): Type { + public getTypeOfNode(node: Syntax): Type { if (this.types.has(node)) { return this.types.get(node)! } @@ -215,15 +257,13 @@ export class TypeChecker { return newType; } - check(node: Syntax) { + public check(node: Syntax) { this.getTypeOfNode(node); switch (node.kind) { - case SyntaxKind.BoltSentence: case SyntaxKind.BoltRecordDeclaration: - case SyntaxKind.BoltNewTypeDeclaration: case SyntaxKind.BoltConstantExpression: break; @@ -267,12 +307,8 @@ export class TypeChecker { } - getImportedSymbols(node: BoltImportDeclaration) { - return [{ name: 'fac' }] - } - - getScope(node: Syntax): Scope { - while (node.kind !== SyntaxKind.BoltFunctionDeclaration && node.kind !== SyntaxKind.BoltSourceFile) { + public getScope(node: Syntax): Scope { + while (!introducesNewScope(node.kind)) { node = node.parentNode!; } if (this.scopes.has(node)) { @@ -283,7 +319,7 @@ export class TypeChecker { return scope } - protected intersectTypes(a: Type, b: Type): Type { + private intersectTypes(a: Type, b: Type): Type { if (a === noneType || b == noneType) { return noneType; } @@ -304,9 +340,5 @@ export class TypeChecker { return noneType; } - // getMapperForNode(target: string, node: Syntax): Mapper { - // return this.getScope(node).getMapper(target) - // } - } diff --git a/src/evaluator.ts b/src/evaluator.ts index 78563f20a..e9d876456 100644 --- a/src/evaluator.ts +++ b/src/evaluator.ts @@ -1,5 +1,5 @@ -import { Syntax, SyntaxKind, Expr, isNode } from "./ast" +import { Syntax, SyntaxKind, Expr, isNode, BoltQualName } from "./ast" import { TypeChecker, Type, RecordType, PrimType, boolType } from "./checker" import { FastStringMap } from "./util" @@ -65,28 +65,32 @@ export class RecordWrapper extends RecordValue { } +function getDeclarationPath(node: BoltQualName) { + return [...node.modulePath.map(id => id.text), node.name.text]; +} + class Environment { - private symbols: FastStringMap = Object.create(null); + private symbols = FastStringMap(); constructor(public parentEnv: Environment | null = null) { } - setValue(name: string, value: Value) { + public setValue(name: string, value: Value) { if (name in this.symbols) { throw new Error(`A variable with the name '${name}' already exists.`); } this.symbols[name] = value; } - updateValue(name: string, newValue: Value) { + public updateValue(name: string, newValue: Value) { if (!(name in this.symbols)) { throw new Error(`Trying to update a variable '${name}' that has not been declared.`); } } - lookup(name: string) { + public lookup(name: string) { let curr = this as Environment; while (true) { if (name in curr.symbols) { @@ -136,26 +140,26 @@ export class Evaluator { } } - eval(node: Syntax, env: Environment = new Environment()): Value { + public eval(node: Syntax, env: Environment = new Environment()): Value { switch (node.kind) { - case SyntaxKind.SourceFile: - case SyntaxKind.Module: + case SyntaxKind.BoltSourceFile: + case SyntaxKind.BoltModule: for (const element of node.elements) { this.eval(element, env); } break; - case SyntaxKind.RefExpr: - return env.lookup(node.name.fullText); + case SyntaxKind.BoltReferenceTypeExpression: + // FIXME + return env.lookup(node.name.name.text); - case SyntaxKind.NewTypeDecl: - case SyntaxKind.RecordDecl: - case SyntaxKind.FuncDecl: + case SyntaxKind.BoltRecordDeclaration: + case SyntaxKind.BoltFunctionDeclaration: break; - case SyntaxKind.MatchExpr: + case SyntaxKind.BoltMatchExpression: const value = this.eval(node.value, env); for (const [pattern, result] of node.arms) { if (this.match(value, pattern)) { @@ -164,7 +168,7 @@ export class Evaluator { } return new PrimValue(this.checker.getTypeNamed('Void')!, null); - case SyntaxKind.ConstExpr: + case SyntaxKind.BoltConstantExpression: return new PrimValue(this.checker.getTypeOfNode(node), node.value) default: