Fix some compilation errors
This commit is contained in:
parent
98ddad8562
commit
831ae626c3
4 changed files with 115 additions and 74 deletions
25
spec/ast.txt
25
spec/ast.txt
|
@ -84,10 +84,6 @@ node BoltQualName {
|
|||
name: BoltSymbol,
|
||||
}
|
||||
|
||||
node BoltSentence > BoltSourceElement {
|
||||
tokens: Vec<BoltToken>,
|
||||
}
|
||||
|
||||
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<BoltExpression>,
|
||||
|
@ -213,16 +209,18 @@ node BoltModule > BoltDeclaration {
|
|||
elements: Vec<BoltSourceElement>,
|
||||
}
|
||||
|
||||
node BoltFunctionDeclaration > BoltDeclaration {
|
||||
node BoltFunctionBodyElement;
|
||||
|
||||
node BoltFunctionDeclaration > BoltFunctionBodyElement, BoltDeclaration {
|
||||
modifiers: BoltDeclarationModifiers,
|
||||
target: String,
|
||||
name: BoltSymbol,
|
||||
params: Vec<BoltParameter>,
|
||||
returnType: Option<BoltTypeExpression>,
|
||||
body: Vec<BoltStatement>,
|
||||
body: Vec<BoltFunctionBodyElement>,
|
||||
}
|
||||
|
||||
node BoltVariableDeclaration > BoltDeclaration {
|
||||
node BoltVariableDeclaration > BoltFunctionBodyElement, BoltDeclaration {
|
||||
modifiers: BoltDeclarationModifiers,
|
||||
bindings: BoltPattern,
|
||||
type: Option<BoltTypeExpression>,
|
||||
|
@ -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<Vec<BoltTypeParameter>>,
|
||||
fields: Vec<BoltRecordDeclarationField>,
|
||||
members: Option<Vec<BoltRecordMember>>,
|
||||
}
|
||||
|
||||
node BoltSourceElement;
|
||||
|
||||
node BoltMacroCall > BoltRecordMember, BoltStatement, BoltDeclaration, BoltExpression {
|
||||
name: BoltIdentifier,
|
||||
text: String,
|
||||
}
|
||||
|
||||
// JavaScript AST definitions
|
||||
|
||||
type JSValue = Int | String | Bool | Void;
|
||||
|
|
4
src/ast.d.ts
vendored
4
src/ast.d.ts
vendored
|
@ -583,7 +583,7 @@ export interface BoltFunctionDeclaration extends SyntaxBase<SyntaxKind.BoltFunct
|
|||
name: BoltSymbol;
|
||||
params: BoltParameter[];
|
||||
returnType: BoltTypeExpression | null;
|
||||
body: BoltStatement[];
|
||||
body: BoltFunctionBodyElement[];
|
||||
}
|
||||
|
||||
export interface BoltVariableDeclaration extends SyntaxBase<SyntaxKind.BoltVariableDeclaration> {
|
||||
|
@ -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;
|
||||
|
|
126
src/checker.ts
126
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<Type> = Object.create(null);
|
||||
private fieldTypes = new FastStringMap<string, Type>();
|
||||
|
||||
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<string, SymbolInfo>();
|
||||
|
||||
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<T, R>(iterable: Iterable<T>, 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<Type> = Object.create(null)
|
||||
protected types = new Map<Syntax, Type>();
|
||||
protected scopes = new Map<Syntax, Scope>();
|
||||
private symbols = new FastStringMap<string, Type>();
|
||||
private types = new Map<Syntax, Type>();
|
||||
private scopes = new Map<Syntax, Scope>();
|
||||
|
||||
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)
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Value> = Object.create(null);
|
||||
private symbols = FastStringMap<string, Value>();
|
||||
|
||||
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:
|
||||
|
|
Loading…
Reference in a new issue