diff --git a/src/bind.ts b/src/bind.ts index 4a041d3..86d72a5 100644 --- a/src/bind.ts +++ b/src/bind.ts @@ -1,4 +1,11 @@ -import { Declaration, Module, Node, Statement, Table } from './types'; +import { + Declaration, + Module, + Node, + Statement, + SymbolFlags, + Table, +} from './types'; import { error } from './error'; export function bind(m: Module) { @@ -12,6 +19,7 @@ export function bind(m: Module) { statement.kind === Node.TypeAlias || statement.kind === Node.Let ) { + const isValue = isVariableDeclaration(statement.kind); const symbol = locals.get(statement.name.text); if (symbol) { const other = symbol.declarations.find( @@ -27,21 +35,25 @@ export function bind(m: Module) { ); } else { symbol.declarations.push(statement); - if ([Node.Var, Node.Let].includes(statement.kind)) { + if (isValue) { symbol.valueDeclaration ||= statement; + symbol.flags |= SymbolFlags.Value; } } } else { locals.set(statement.name.text, { declarations: [statement], - valueDeclaration: [Node.Var, Node.Let].includes(statement.kind) - ? statement - : undefined, + valueDeclaration: isValue ? statement : undefined, + flags: isValue ? SymbolFlags.Value : SymbolFlags.Type, }); } } } + function isVariableDeclaration(kind: Statement['kind']) { + return [Node.Var, Node.Let].includes(kind); + } + function hasEqualKindButNotVar( declaration: Declaration, statement: Statement, @@ -64,20 +76,9 @@ export function bind(m: Module) { } } -export enum Meaning { - Value, - Type, -} - -export function resolve(locals: Table, name: string, meaning: Meaning) { +export function resolve(locals: Table, name: string, meaning: SymbolFlags) { const symbol = locals.get(name); - if ( - symbol?.declarations.some((d) => - meaning === Meaning.Value - ? [Node.Var, Node.Let].includes(d.kind) - : d.kind === Node.TypeAlias, - ) - ) { + if (symbol && symbol.flags & meaning) { return symbol; } } diff --git a/src/check.ts b/src/check.ts index f0c1b62..41fd811 100644 --- a/src/check.ts +++ b/src/check.ts @@ -6,9 +6,10 @@ import { Expression, Identifier, TypeAlias, + SymbolFlags, } from './types'; import { error } from './error'; -import { Meaning, resolve } from './bind'; +import { resolve } from './bind'; const stringType: Type = { id: 'string' }; const numberType: Type = { id: 'number' }; @@ -51,10 +52,11 @@ export function check(module: Module) { function checkExpression(expression: Expression): Type { switch (expression.kind) { case Node.Identifier: - const resolveExpression = (meaning: Meaning) => - resolve(module.locals, expression.text, meaning); - - const symbol = resolveExpression(Meaning.Value); + const symbol = resolve( + module.locals, + expression.text, + SymbolFlags.Value, + ); if (symbol?.valueDeclaration?.kind === Node.Let) { if (symbol.valueDeclaration.pos < expression.pos) { @@ -100,7 +102,7 @@ export function check(module: Module) { case 'number': return numberType; default: - const symbol = resolve(module.locals, name.text, Meaning.Type); + const symbol = resolve(module.locals, name.text, SymbolFlags.Type); if (symbol) { return checkType( ( diff --git a/src/types.ts b/src/types.ts index eb537d1..5be2c90 100644 --- a/src/types.ts +++ b/src/types.ts @@ -116,6 +116,7 @@ export type Declaration = Var | Let | TypeAlias; // plus others, like function export type Symbol = { valueDeclaration: Declaration | undefined; declarations: Declaration[]; + flags: SymbolFlags; }; export type Table = Map; @@ -142,3 +143,9 @@ type CompilerTarget = 'es5' | 'es2015' | 'es2017' | 'es2022'; export interface CompilerOptions { target: CompilerTarget; } + +export const enum SymbolFlags { + None = 0, + Value = 1 << 1, + Type = 1 << 2, +}