Finish namespace implementation, fix circularity

This commit is contained in:
Brian Terlson 2021-03-04 11:57:20 -08:00
Родитель 55ac2208f5
Коммит 47866d53d8
4 изменённых файлов: 69 добавлений и 88 удалений

Просмотреть файл

@ -51,6 +51,8 @@ export function createBinder(): Binder {
let currentFile: ADLSourceFile;
let parentNode: Node;
let currentNamespace: NamespaceStatementNode | undefined;
// Node where locals go.
let scope: ScopeNode;
return {
@ -100,9 +102,16 @@ export function createBinder(): Binder {
if (hasScope(node)) {
const prevScope = scope;
const prevNamespace = currentNamespace;
scope = node;
if (node.kind === SyntaxKind.NamespaceStatement) {
currentNamespace = node;
}
visitChildren(node, bindNode);
scope = prevScope;
currentNamespace = prevNamespace;
} else {
visitChildren(node, bindNode);
}
@ -137,6 +146,16 @@ export function createBinder(): Binder {
declareSymbol(getContainingSymbolTable(), statement);
}
function declareSymbol(table: SymbolTable, node: Declaration) {
const symbol = createTypeSymbol(node, node.id.sv);
node.symbol = symbol;
if (currentNamespace && node.kind !== SyntaxKind.TemplateParameterDeclaration) {
node.namespaceSymbol = currentNamespace.symbol;
}
table.set(node.id.sv, symbol);
}
function reportDuplicateSymbols(symbols: SymbolTable) {
let reported = new Set<Sym>();
let messages = new Array<string>();
@ -198,8 +217,3 @@ function createTypeSymbol(node: Node, name: string): TypeSymbol {
};
}
function declareSymbol(table: SymbolTable, node: Declaration) {
const symbol = createTypeSymbol(node, node.id.sv);
node.symbol = symbol;
table.set(node.id.sv, symbol);
}

Просмотреть файл

@ -159,7 +159,7 @@ export function createChecker(program: Program) {
return `${model.name}<${args.join(", ")}>`;
} else if ((<ModelStatementNode>model.node).templateParameters?.length > 0) {
// template
const params = (<ModelStatementNode>model.node).templateParameters.map((t) => t.sv);
const params = (<ModelStatementNode>model.node).templateParameters.map((t) => t.id.sv);
return `${model.name}<${params.join(", ")}>`;
} else {
// regular old model.
@ -184,8 +184,7 @@ export function createChecker(program: Program) {
}
function checkTypeReference(node: TypeReferenceNode): Type {
// todo: support member expressions
const sym = resolveTypeReference(node.target as IdentifierNode);
const sym = resolveTypeReference(node);
if (sym.kind === "decorator") {
throwDiagnostic("Can't put a decorator in a type", node);
}
@ -349,6 +348,9 @@ export function createChecker(program: Program) {
namespaces: new Map(),
});
const links = getSymbolLinks(node.symbol!);
links.type = type;
for (const statement of node.statements.map(getTypeForNode)) {
switch (statement.kind) {
case "Model":
@ -363,25 +365,19 @@ export function createChecker(program: Program) {
}
}
const links = getSymbolLinks(node.symbol!);
links.type = type;
return type;
}
function getParentNamespaceType(
node: ModelStatementNode | NamespaceStatementNode | OperationStatementNode
) {
switch (node.kind) {
case SyntaxKind.ModelStatement:
case SyntaxKind.NamespaceStatement:
case SyntaxKind.OperationStatement:
return node.parent && node.parent.kind === SyntaxKind.NamespaceStatement
? (getTypeForNode(node.parent) as NamespaceType)
: undefined;
default:
return undefined;
): NamespaceType | undefined {
if (!node.namespaceSymbol) return undefined;
const symbolLinks = getSymbolLinks(node.namespaceSymbol);
if (!symbolLinks.type) {
throwDiagnostic("Parent namespace isn't typed yet, please file a bug.", node);
}
return symbolLinks.type as NamespaceType;
}
function checkOperation(node: OperationStatementNode): OperationType {
@ -424,64 +420,6 @@ export function createChecker(program: Program) {
return s.id;
}
function getMemberExpressionPath(node: MemberExpressionNode): string {
// Recursively build the rest of the path, back to front
const pathBefore =
node.base.kind === SyntaxKind.MemberExpression
? getMemberExpressionPath(node.base)
: node.base.sv;
return pathBefore + "." + node.id.sv;
}
function checkMemberExpression(node: MemberExpressionNode) {
const binding = resolveMember(node);
if (binding) {
if (binding.kind === "decorator") {
return {};
} else {
return getTypeForNode(binding.node);
}
} else {
throwDiagnostic(`Cannot resolve identifier '${getMemberExpressionPath(node)}'`, node);
}
}
function resolveMember(node: MemberExpressionNode): any {
let result: Sym | undefined = undefined;
// Navigate down the member expression and then resolve on the way
// back up because the 'base' pointers are stored in reverse
if (node.base.kind === SyntaxKind.MemberExpression) {
result = resolveMember(node.base);
} else {
// The last 'base' in the chain will be an identifier, so
// resolve it first and then resolve all remaining member
// expressions with respect to its scope
result = resolveIdentifier(node.base);
}
if (result) {
// Previous segment was resolved, was it a namespace?
if (result.kind === "type") {
if (result.node.kind === SyntaxKind.NamespaceStatement) {
return resolveIdentifierInScope(node.id, result.node);
} else {
throwDiagnostic(
`Cannot resolve '${node.id.sv}' in non-namespace node ${result.node.kind}`,
node
);
}
} else {
throwDiagnostic(`Unexpectedly resolved '${node.id.sv}' to a decorator symbol`, node);
}
} else {
// Let checkMemberExpression report on the inability to
// resolve the member expression
return undefined;
}
}
function resolveIdentifierInScope(node: IdentifierNode, scope: { locals?: SymbolTable }) {
return (<any>scope).locals.get(node.sv);
}
@ -509,9 +447,39 @@ export function createChecker(program: Program) {
return binding;
}
function resolveTypeReference(node: IdentifierNode): DecoratorSymbol | TypeSymbol {
// TODO: Support for member expressions
return resolveIdentifier(node);
function resolveTypeReference(node: ReferenceExpression): DecoratorSymbol | TypeSymbol {
if (node.kind === SyntaxKind.TypeReference) {
return resolveTypeReference(node.target);
}
if (node.kind === SyntaxKind.MemberExpression) {
const base = resolveTypeReference(node.base);
if (base.kind === "type" && base.node.kind === SyntaxKind.NamespaceStatement) {
const symbol = resolveIdentifierInScope(node.id, base.node);
if (!symbol) {
throwDiagnostic(
`Namespace doesn't have member ${node.id.sv}`, node
)
}
return symbol;
} else if (base.kind === "decorator") {
throwDiagnostic(
`Cannot resolve '${node.id.sv}' in decorator`,
node
);
} else {
throwDiagnostic(
`Cannot resolve '${node.id.sv}' in non-namespace node ${base.node.kind}`,
node
);
}
}
if (node.kind === SyntaxKind.Identifier) {
return resolveIdentifier(node);
}
throwDiagnostic("Unknown reference node type", node);
}
function checkStringLiteral(str: StringLiteralNode): StringLiteralType {

Просмотреть файл

@ -191,6 +191,7 @@ export type Statement =
export interface DeclarationNode {
symbol?: TypeSymbol; // tracks the symbol assigned to this declaration
namespaceSymbol?: TypeSymbol; // tracks the namespace this declaration is in
}
export type Declaration =
@ -257,14 +258,12 @@ export interface NamespaceStatementNode extends BaseNode, DeclarationNode {
decorators: Array<DecoratorExpressionNode>;
}
export interface OperationStatementNode extends BaseNode {
export interface OperationStatementNode extends BaseNode, DeclarationNode {
kind: SyntaxKind.OperationStatement;
id: IdentifierNode;
parameters: ModelExpressionNode;
returnType: Expression;
decorators: Array<DecoratorExpressionNode>;
symbol: TypeSymbol;
}
@ -336,14 +335,14 @@ export interface IntersectionExpressionNode extends BaseNode {
export interface TypeReferenceNode extends BaseNode {
kind: SyntaxKind.TypeReference;
target: Expression;
target: ReferenceExpression;
arguments: Array<Expression>;
}
export interface TemplateParameterDeclarationNode extends BaseNode {
kind: SyntaxKind.TemplateParameterDeclaration;
id: IdentifierNode;
symbol: TypeSymbol;
symbol?: TypeSymbol;
}
/**

Просмотреть файл

@ -202,7 +202,7 @@ function dumpAST(astNode: any) {
const replacer = function (this: any, key: string, value: any) {
return key == "kind" ? SyntaxKind[value] : value;
};
console.log(JSON.stringify(astNode, replacer, 4));
//console.log(JSON.stringify(astNode, replacer, 4));
}
function shorten(code: string) {