Implement nested namespace parsing, rename some core types
This commit is contained in:
Родитель
d617fe3000
Коммит
55ac2208f5
|
@ -10,6 +10,8 @@ import {
|
|||
SourceLocation,
|
||||
Sym,
|
||||
Declaration,
|
||||
OperationStatementNode,
|
||||
ScopeNode,
|
||||
} from "./types.js";
|
||||
|
||||
export class SymbolTable extends Map<string, Sym> {
|
||||
|
@ -50,8 +52,7 @@ export function createBinder(): Binder {
|
|||
let parentNode: Node;
|
||||
|
||||
// Node where locals go.
|
||||
let scope: Node;
|
||||
|
||||
let scope: ScopeNode;
|
||||
return {
|
||||
bindSourceFile,
|
||||
};
|
||||
|
@ -63,6 +64,7 @@ export function createBinder(): Binder {
|
|||
) {
|
||||
currentFile = sourceFile;
|
||||
bindNode(sourceFile.ast);
|
||||
reportDuplicateSymbols(currentFile.symbols);
|
||||
|
||||
// everything is global
|
||||
if (globalScope) {
|
||||
|
@ -80,13 +82,16 @@ export function createBinder(): Binder {
|
|||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ModelStatement:
|
||||
bindModelStatement(<any>node);
|
||||
bindModelStatement(node);
|
||||
break;
|
||||
case SyntaxKind.NamespaceStatement:
|
||||
bindNamespaceStatement(<any>node);
|
||||
bindNamespaceStatement(node);
|
||||
break;
|
||||
case SyntaxKind.OperationStatement:
|
||||
bindOperationStatement(node);
|
||||
break;
|
||||
case SyntaxKind.TemplateParameterDeclaration:
|
||||
bindTemplateParameterDeclaration(<any>node);
|
||||
bindTemplateParameterDeclaration(node);
|
||||
}
|
||||
|
||||
const prevParent = parentNode;
|
||||
|
@ -106,25 +111,33 @@ export function createBinder(): Binder {
|
|||
parentNode = prevParent;
|
||||
}
|
||||
|
||||
function getContainingSymbolTable() {
|
||||
return scope ? scope.locals! : currentFile.symbols;
|
||||
}
|
||||
|
||||
function bindTemplateParameterDeclaration(node: TemplateParameterDeclarationNode) {
|
||||
(<ModelStatementNode>scope).locals!.set(node.sv, {
|
||||
kind: "type",
|
||||
node: node,
|
||||
name: node.sv,
|
||||
});
|
||||
declareSymbol(getContainingSymbolTable(), node);
|
||||
}
|
||||
|
||||
function bindModelStatement(node: ModelStatementNode) {
|
||||
declareSymbol(currentFile.symbols, node);
|
||||
// initialize locals for type parameters.
|
||||
declareSymbol(getContainingSymbolTable(), node);
|
||||
|
||||
// Initialize locals for type parameters
|
||||
node.locals = new SymbolTable();
|
||||
}
|
||||
|
||||
function bindNamespaceStatement(statement: NamespaceStatementNode) {
|
||||
declareSymbol(currentFile.symbols, statement);
|
||||
declareSymbol(getContainingSymbolTable(), statement);
|
||||
|
||||
// Initialize locals for namespace members
|
||||
statement.locals = new SymbolTable();
|
||||
}
|
||||
|
||||
function reportDuplicateSymbols(globalSymbols: SymbolTable) {
|
||||
function bindOperationStatement(statement: OperationStatementNode) {
|
||||
declareSymbol(getContainingSymbolTable(), statement);
|
||||
}
|
||||
|
||||
function reportDuplicateSymbols(symbols: SymbolTable) {
|
||||
let reported = new Set<Sym>();
|
||||
let messages = new Array<string>();
|
||||
|
||||
|
@ -132,10 +145,17 @@ export function createBinder(): Binder {
|
|||
report(symbol);
|
||||
}
|
||||
|
||||
for (const symbol of globalSymbols.duplicates) {
|
||||
for (const symbol of symbols.duplicates) {
|
||||
report(symbol);
|
||||
}
|
||||
|
||||
// Check symbols that have their own scopes
|
||||
for (const [_, symbol] of symbols) {
|
||||
if (symbol.kind === "type" && hasScope(symbol.node) && symbol.node.locals) {
|
||||
reportDuplicateSymbols(symbol.node.locals);
|
||||
}
|
||||
}
|
||||
|
||||
if (messages.length > 0) {
|
||||
// TODO: We're now reporting all duplicates up to the binding of the first file
|
||||
// that introduced one, but still bailing the compilation rather than
|
||||
|
@ -145,6 +165,7 @@ export function createBinder(): Binder {
|
|||
// That said, decorators are entered into the global symbol table before
|
||||
// any source file is bound and therefore this will include all duplicate
|
||||
// decorator implementations.
|
||||
|
||||
throw new DiagnosticError(messages.join("\n"));
|
||||
}
|
||||
|
||||
|
@ -158,10 +179,12 @@ export function createBinder(): Binder {
|
|||
}
|
||||
}
|
||||
|
||||
function hasScope(node: Node) {
|
||||
function hasScope(node: Node): node is ScopeNode {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ModelStatement:
|
||||
return true;
|
||||
case SyntaxKind.NamespaceStatement:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { SymbolTable } from "./binder.js";
|
||||
import { throwDiagnostic } from "./diagnostics.js";
|
||||
import { ADLSourceFile, Program } from "./program.js";
|
||||
import {
|
||||
|
@ -5,10 +6,10 @@ import {
|
|||
BooleanLiteralNode,
|
||||
BooleanLiteralType,
|
||||
IdentifierNode,
|
||||
NamespacePropertyNode,
|
||||
OperationStatementNode,
|
||||
NamespaceStatementNode,
|
||||
Namespace,
|
||||
NamespaceProperty,
|
||||
NamespaceType,
|
||||
OperationType,
|
||||
IntersectionExpressionNode,
|
||||
LiteralNode,
|
||||
LiteralType,
|
||||
|
@ -34,6 +35,8 @@ import {
|
|||
DecoratorSymbol,
|
||||
TypeSymbol,
|
||||
SymbolLinks,
|
||||
MemberExpressionNode,
|
||||
Sym,
|
||||
} from "./types.js";
|
||||
|
||||
/**
|
||||
|
@ -85,7 +88,7 @@ export function createChecker(program: Program) {
|
|||
checkProgram,
|
||||
getLiteralType,
|
||||
getTypeName,
|
||||
checkNamespaceProperty,
|
||||
checkOperation,
|
||||
};
|
||||
|
||||
function getTypeForNode(node: Node): Type {
|
||||
|
@ -98,8 +101,8 @@ export function createChecker(program: Program) {
|
|||
return checkModelProperty(node);
|
||||
case SyntaxKind.NamespaceStatement:
|
||||
return checkNamespace(node);
|
||||
case SyntaxKind.NamespaceProperty:
|
||||
return checkNamespaceProperty(node);
|
||||
case SyntaxKind.OperationStatement:
|
||||
return checkOperation(node);
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return checkNumericLiteral(node);
|
||||
case SyntaxKind.BooleanLiteral:
|
||||
|
@ -140,9 +143,16 @@ export function createChecker(program: Program) {
|
|||
return "(unnamed type)";
|
||||
}
|
||||
|
||||
function getNamespaceString(type: ModelType | NamespaceType | OperationType): string | undefined {
|
||||
return type.namespace
|
||||
? `${getNamespaceString(type.namespace) || ""}${type.namespace.name}.`
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function getModelName(model: ModelType) {
|
||||
let modelName: string | undefined = model.name;
|
||||
if ((<ModelStatementNode>model.node).assignment) {
|
||||
return model.name;
|
||||
// Just use the existing modelName
|
||||
} else if (model.templateArguments && model.templateArguments.length > 0) {
|
||||
// template instantiation
|
||||
const args = model.templateArguments.map(getTypeName);
|
||||
|
@ -155,6 +165,8 @@ export function createChecker(program: Program) {
|
|||
// regular old model.
|
||||
return model.name || "(anonymous model)";
|
||||
}
|
||||
|
||||
return (getNamespaceString(model) || "") + modelName;
|
||||
}
|
||||
|
||||
function checkTemplateParameterDeclaration(node: TemplateParameterDeclarationNode): Type {
|
||||
|
@ -327,16 +339,28 @@ export function createChecker(program: Program) {
|
|||
}
|
||||
|
||||
function checkNamespace(node: NamespaceStatementNode) {
|
||||
const type: Namespace = createType({
|
||||
const type: NamespaceType = createType({
|
||||
kind: "Namespace",
|
||||
name: node.id.sv,
|
||||
namespace: getParentNamespaceType(node),
|
||||
node: node,
|
||||
properties: new Map(),
|
||||
parameters: node.parameters ? <ModelType>getTypeForNode(node.parameters) : undefined,
|
||||
models: new Map(),
|
||||
operations: new Map(),
|
||||
namespaces: new Map(),
|
||||
});
|
||||
|
||||
for (const prop of node.properties) {
|
||||
type.properties.set(prop.id.sv, checkNamespaceProperty(prop));
|
||||
for (const statement of node.statements.map(getTypeForNode)) {
|
||||
switch (statement.kind) {
|
||||
case "Model":
|
||||
type.models.set(statement.name, statement as ModelType);
|
||||
break;
|
||||
case "Operation":
|
||||
type.operations.set(statement.name, statement as OperationType);
|
||||
break;
|
||||
case "Namespace":
|
||||
type.namespaces.set(statement.name, statement as NamespaceType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const links = getSymbolLinks(node.symbol!);
|
||||
|
@ -345,13 +369,29 @@ export function createChecker(program: Program) {
|
|||
return type;
|
||||
}
|
||||
|
||||
function checkNamespaceProperty(prop: NamespacePropertyNode): NamespaceProperty {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
function checkOperation(node: OperationStatementNode): OperationType {
|
||||
return createType({
|
||||
kind: "NamespaceProperty",
|
||||
name: prop.id.sv,
|
||||
node: prop,
|
||||
parameters: <ModelType>getTypeForNode(prop.parameters),
|
||||
returnType: getTypeForNode(prop.returnType),
|
||||
kind: "Operation",
|
||||
name: node.id.sv,
|
||||
namespace: getParentNamespaceType(node),
|
||||
node: node,
|
||||
parameters: <ModelType>getTypeForNode(node.parameters),
|
||||
returnType: getTypeForNode(node.returnType),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -384,13 +424,75 @@ export function createChecker(program: Program) {
|
|||
return s.id;
|
||||
}
|
||||
|
||||
function resolveIdentifier(node: IdentifierNode): DecoratorSymbol | TypeSymbol {
|
||||
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);
|
||||
}
|
||||
|
||||
function resolveIdentifier(node: IdentifierNode) {
|
||||
let scope: Node | undefined = node.parent;
|
||||
let binding;
|
||||
|
||||
while (scope) {
|
||||
if ("locals" in scope) {
|
||||
binding = (<any>scope).locals.get(node.sv);
|
||||
binding = resolveIdentifierInScope(node, scope);
|
||||
if (binding) break;
|
||||
}
|
||||
scope = scope.parent;
|
||||
|
|
|
@ -38,7 +38,9 @@ export function parse(code: string | Types.SourceFile) {
|
|||
case Token.ModelKeyword:
|
||||
return parseModelStatement(decorators);
|
||||
case Token.NamespaceKeyword:
|
||||
return parseInterfaceStatement(decorators);
|
||||
return parseNamespaceStatement(decorators);
|
||||
case Token.OpKeyword:
|
||||
return parseOperationStatement(decorators);
|
||||
case Token.Semicolon:
|
||||
if (decorators.length > 0) {
|
||||
error("Cannot decorate an empty statement");
|
||||
|
@ -63,7 +65,7 @@ export function parse(code: string | Types.SourceFile) {
|
|||
return decorators;
|
||||
}
|
||||
|
||||
function parseInterfaceStatement(
|
||||
function parseNamespaceStatement(
|
||||
decorators: Array<Types.DecoratorExpressionNode>
|
||||
): Types.NamespaceStatementNode {
|
||||
const pos = tokenPos();
|
||||
|
@ -87,15 +89,11 @@ export function parse(code: string | Types.SourceFile) {
|
|||
}
|
||||
|
||||
parseExpected(Token.OpenBrace);
|
||||
const properties: Array<Types.NamespacePropertyNode> = [];
|
||||
|
||||
do {
|
||||
if (token() == Token.CloseBrace) {
|
||||
break;
|
||||
const statements: Array<Types.Statement> = [];
|
||||
while (token() !== Token.CloseBrace) {
|
||||
statements.push(parseStatement());
|
||||
}
|
||||
const memberDecorators = parseDecoratorList();
|
||||
properties.push(parseNamespaceProperty(memberDecorators));
|
||||
} while (parseOptional(Token.Comma) || parseOptional(Token.Semicolon));
|
||||
|
||||
parseExpected(Token.CloseBrace);
|
||||
|
||||
|
@ -105,15 +103,15 @@ export function parse(code: string | Types.SourceFile) {
|
|||
decorators,
|
||||
id,
|
||||
parameters,
|
||||
properties,
|
||||
statements,
|
||||
},
|
||||
pos
|
||||
);
|
||||
}
|
||||
|
||||
function parseNamespaceProperty(
|
||||
function parseOperationStatement(
|
||||
decorators: Array<Types.DecoratorExpressionNode>
|
||||
): Types.NamespacePropertyNode {
|
||||
): Types.OperationStatementNode {
|
||||
const pos = tokenPos();
|
||||
parseExpected(Token.OpKeyword);
|
||||
const id = parseIdentifier();
|
||||
|
@ -137,9 +135,10 @@ export function parse(code: string | Types.SourceFile) {
|
|||
parseExpected(Token.Colon);
|
||||
const returnType = parseExpression();
|
||||
|
||||
parseExpected(Token.Semicolon);
|
||||
return finishNode(
|
||||
{
|
||||
kind: Types.SyntaxKind.NamespaceProperty,
|
||||
kind: Types.SyntaxKind.OperationStatement,
|
||||
id,
|
||||
parameters,
|
||||
returnType,
|
||||
|
@ -218,7 +217,7 @@ export function parse(code: string | Types.SourceFile) {
|
|||
const param = finishNode(
|
||||
{
|
||||
kind: Types.SyntaxKind.TemplateParameterDeclaration,
|
||||
sv: id.sv,
|
||||
id: id,
|
||||
} as const,
|
||||
pos
|
||||
);
|
||||
|
@ -734,7 +733,7 @@ export function visitChildren<T>(node: Types.Node, cb: NodeCb<T>): T | undefined
|
|||
return visitNode(cb, node.target) || visitEach(cb, node.arguments);
|
||||
case Types.SyntaxKind.ImportStatement:
|
||||
return visitNode(cb, node.id) || visitEach(cb, node.as);
|
||||
case Types.SyntaxKind.NamespaceProperty:
|
||||
case Types.SyntaxKind.OperationStatement:
|
||||
return (
|
||||
visitEach(cb, node.decorators) ||
|
||||
visitNode(cb, node.id) ||
|
||||
|
@ -743,10 +742,7 @@ export function visitChildren<T>(node: Types.Node, cb: NodeCb<T>): T | undefined
|
|||
);
|
||||
case Types.SyntaxKind.NamespaceStatement:
|
||||
return (
|
||||
visitEach(cb, node.decorators) ||
|
||||
visitNode(cb, node.id) ||
|
||||
visitNode(cb, node.parameters) ||
|
||||
visitEach(cb, node.properties)
|
||||
visitEach(cb, node.decorators) || visitNode(cb, node.id) || visitEach(cb, node.statements)
|
||||
);
|
||||
case Types.SyntaxKind.IntersectionExpression:
|
||||
return visitEach(cb, node.options);
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
ADLScriptNode,
|
||||
DecoratorExpressionNode,
|
||||
IdentifierNode,
|
||||
Namespace,
|
||||
NamespaceType,
|
||||
LiteralType,
|
||||
ModelStatementNode,
|
||||
ModelType,
|
||||
|
@ -32,7 +32,7 @@ export interface Program {
|
|||
checker?: ReturnType<typeof createChecker>;
|
||||
evalAdlScript(adlScript: string, filePath?: string): void;
|
||||
onBuild(cb: (program: Program) => void): void;
|
||||
executeInterfaceDecorators(type: Namespace): void;
|
||||
executeNamespaceDecorators(type: NamespaceType): void;
|
||||
executeModelDecorators(type: ModelType): void;
|
||||
executeDecorators(type: Type): void;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export interface ADLSourceFile extends SourceFile {
|
|||
ast: ADLScriptNode;
|
||||
symbols: SymbolTable;
|
||||
models: Array<ModelType>;
|
||||
interfaces: Array<Namespace>;
|
||||
interfaces: Array<NamespaceType>;
|
||||
}
|
||||
|
||||
export async function compile(rootDir: string, options?: CompilerOptions) {
|
||||
|
@ -54,7 +54,7 @@ export async function compile(rootDir: string, options?: CompilerOptions) {
|
|||
typeCache: new MultiKeyMap(),
|
||||
literalTypes: new Map(),
|
||||
evalAdlScript,
|
||||
executeInterfaceDecorators,
|
||||
executeNamespaceDecorators,
|
||||
executeModelDecorators,
|
||||
executeDecorators,
|
||||
onBuild(cb) {
|
||||
|
@ -79,14 +79,22 @@ export async function compile(rootDir: string, options?: CompilerOptions) {
|
|||
* does type checking.
|
||||
*/
|
||||
|
||||
function executeInterfaceDecorators(type: Namespace) {
|
||||
function executeNamespaceDecorators(type: NamespaceType) {
|
||||
const stmt = type.node;
|
||||
|
||||
for (const dec of stmt.decorators) {
|
||||
executeDecorator(dec, program, type);
|
||||
}
|
||||
|
||||
for (const [name, propType] of type.properties) {
|
||||
for (const [_, modelType] of type.models) {
|
||||
executeModelDecorators(modelType);
|
||||
}
|
||||
|
||||
for (const [_, namespaceType] of type.namespaces) {
|
||||
executeNamespaceDecorators(namespaceType);
|
||||
}
|
||||
|
||||
for (const [_, propType] of type.operations) {
|
||||
for (const dec of propType.node.decorators) {
|
||||
executeDecorator(dec, program, propType);
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ export type Type =
|
|||
| ModelType
|
||||
| ModelTypeProperty
|
||||
| TemplateParameterType
|
||||
| Namespace
|
||||
| NamespaceProperty
|
||||
| NamespaceType
|
||||
| OperationType
|
||||
| StringLiteralType
|
||||
| NumericLiteralType
|
||||
| BooleanLiteralType
|
||||
|
@ -26,6 +26,7 @@ export type Type =
|
|||
export interface ModelType extends BaseType {
|
||||
kind: "Model";
|
||||
name: string;
|
||||
namespace?: NamespaceType;
|
||||
properties: Map<string, ModelTypeProperty>;
|
||||
baseModels: Array<ModelType>;
|
||||
templateArguments?: Array<Type>;
|
||||
|
@ -44,20 +45,23 @@ export interface ModelTypeProperty {
|
|||
optional: boolean;
|
||||
}
|
||||
|
||||
export interface NamespaceProperty {
|
||||
kind: "NamespaceProperty";
|
||||
node: NamespacePropertyNode;
|
||||
export interface OperationType {
|
||||
kind: "Operation";
|
||||
node: OperationStatementNode;
|
||||
name: string;
|
||||
namespace?: NamespaceType;
|
||||
parameters?: ModelType;
|
||||
returnType: Type;
|
||||
}
|
||||
|
||||
export interface Namespace extends BaseType {
|
||||
export interface NamespaceType extends BaseType {
|
||||
kind: "Namespace";
|
||||
name: string;
|
||||
namespace?: NamespaceType;
|
||||
node: NamespaceStatementNode;
|
||||
properties: Map<string, NamespaceProperty>;
|
||||
parameters?: ModelType;
|
||||
models: Map<string, ModelType>;
|
||||
operations: Map<string, OperationType>;
|
||||
namespaces: Map<string, NamespaceType>;
|
||||
}
|
||||
|
||||
export type LiteralType = StringLiteralType | NumericLiteralType | BooleanLiteralType;
|
||||
|
@ -139,7 +143,7 @@ export enum SyntaxKind {
|
|||
DecoratorExpression,
|
||||
MemberExpression,
|
||||
NamespaceStatement,
|
||||
NamespaceProperty,
|
||||
OperationStatement,
|
||||
ModelStatement,
|
||||
ModelExpression,
|
||||
ModelProperty,
|
||||
|
@ -164,7 +168,7 @@ export type Node =
|
|||
| ADLScriptNode
|
||||
| TemplateParameterDeclarationNode
|
||||
| ModelPropertyNode
|
||||
| NamespacePropertyNode
|
||||
| OperationStatementNode
|
||||
| NamedImportNode
|
||||
| ModelPropertyNode
|
||||
| ModelSpreadPropertyNode
|
||||
|
@ -179,7 +183,11 @@ export interface ADLScriptNode extends BaseNode {
|
|||
file: SourceFile;
|
||||
}
|
||||
|
||||
export type Statement = ImportStatementNode | ModelStatementNode | NamespaceStatementNode;
|
||||
export type Statement =
|
||||
| ImportStatementNode
|
||||
| ModelStatementNode
|
||||
| NamespaceStatementNode
|
||||
| OperationStatementNode;
|
||||
|
||||
export interface DeclarationNode {
|
||||
symbol?: TypeSymbol; // tracks the symbol assigned to this declaration
|
||||
|
@ -187,7 +195,13 @@ export interface DeclarationNode {
|
|||
|
||||
export type Declaration =
|
||||
| ModelStatementNode
|
||||
| NamespaceStatementNode;
|
||||
| NamespaceStatementNode
|
||||
| OperationStatementNode
|
||||
| TemplateParameterDeclarationNode;
|
||||
|
||||
export type ScopeNode =
|
||||
| NamespaceStatementNode
|
||||
| ModelStatementNode
|
||||
|
||||
export interface ImportStatementNode extends BaseNode {
|
||||
kind: SyntaxKind.ImportStatement;
|
||||
|
@ -238,17 +252,19 @@ export interface MemberExpressionNode extends BaseNode {
|
|||
export interface NamespaceStatementNode extends BaseNode, DeclarationNode {
|
||||
kind: SyntaxKind.NamespaceStatement;
|
||||
id: IdentifierNode;
|
||||
parameters?: ModelExpressionNode;
|
||||
properties: Array<NamespacePropertyNode>;
|
||||
statements: Array<Statement>;
|
||||
locals?: SymbolTable;
|
||||
decorators: Array<DecoratorExpressionNode>;
|
||||
}
|
||||
|
||||
export interface NamespacePropertyNode extends BaseNode {
|
||||
kind: SyntaxKind.NamespaceProperty;
|
||||
export interface OperationStatementNode extends BaseNode {
|
||||
kind: SyntaxKind.OperationStatement;
|
||||
id: IdentifierNode;
|
||||
parameters: ModelExpressionNode;
|
||||
returnType: Expression;
|
||||
decorators: Array<DecoratorExpressionNode>;
|
||||
|
||||
symbol: TypeSymbol;
|
||||
}
|
||||
|
||||
|
||||
|
@ -326,7 +342,8 @@ export interface TypeReferenceNode extends BaseNode {
|
|||
|
||||
export interface TemplateParameterDeclarationNode extends BaseNode {
|
||||
kind: SyntaxKind.TemplateParameterDeclaration;
|
||||
sv: string;
|
||||
id: IdentifierNode;
|
||||
symbol: TypeSymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -174,6 +174,7 @@ Statement :
|
|||
ImportStatement
|
||||
ModelStatement
|
||||
NamespaceStatement
|
||||
OperationStatement
|
||||
`;`
|
||||
|
||||
ImportStatement :
|
||||
|
@ -220,19 +221,10 @@ ModelSpreadProperty :
|
|||
`...` ReferenceExpression
|
||||
|
||||
NamespaceStatement:
|
||||
DecoratorList? `namespace` Identifier `{` NamespaceBody? `}`
|
||||
DecoratorList? `namespace` IdentifierOrMemberExpression `{` StatementList? `}`
|
||||
|
||||
NamespaceBody :
|
||||
NamespacePropertyList `,`?
|
||||
NamespacePropertyList `;`?
|
||||
|
||||
NamespacePropertyList :
|
||||
NamespaceProperty
|
||||
NamespacePropertyList `,` NamespaceProperty
|
||||
NamespacePropertyList `;` NamespaceProperty
|
||||
|
||||
NamespaceProperty :
|
||||
DecoratorList? `op` Identifier `(` ModelPropertyList? `)` `:` Expression
|
||||
OperationStatement :
|
||||
DecoratorList? `op` Identifier `(` ModelPropertyList? `)` `:` Expression `;`
|
||||
|
||||
Expression :
|
||||
UnionExpressionOrHigher
|
||||
|
|
|
@ -160,6 +160,7 @@
|
|||
   <a name="Statement-zi_5hwi0"></a>*[ImportStatement](#ImportStatement)*
|
||||
   <a name="Statement-ngbc4m7o"></a>*[ModelStatement](#ModelStatement)*
|
||||
   <a name="Statement-_ljtj5og"></a>*[NamespaceStatement](#NamespaceStatement)*
|
||||
   <a name="Statement-qlyu8ssa"></a>*[OperationStatement](#OperationStatement)*
|
||||
   <a name="Statement-sg2sawim"></a>`` ; ``
|
||||
|
||||
  <a name="ImportStatement"></a>*ImportStatement* **:**
|
||||
|
@ -206,19 +207,10 @@
|
|||
   <a name="ModelSpreadProperty-r9kkoml-"></a>`` ... `` *[ReferenceExpression](#ReferenceExpression)*
|
||||
|
||||
  <a name="NamespaceStatement"></a>*NamespaceStatement* **:**
|
||||
   <a name="NamespaceStatement-lllfloam"></a>*[DecoratorList](#DecoratorList)*<sub>opt</sub> `` namespace `` *[Identifier](#Identifier)* `` { `` *[NamespaceBody](#NamespaceBody)*<sub>opt</sub> `` } ``
|
||||
   <a name="NamespaceStatement-lrsdvje0"></a>*[DecoratorList](#DecoratorList)*<sub>opt</sub> `` namespace `` *[IdentifierOrMemberExpression](#IdentifierOrMemberExpression)* `` { `` *[StatementList](#StatementList)*<sub>opt</sub> `` } ``
|
||||
|
||||
  <a name="NamespaceBody"></a>*NamespaceBody* **:**
|
||||
   <a name="NamespaceBody-ihomezph"></a>*[NamespacePropertyList](#NamespacePropertyList)* `` , ``<sub>opt</sub>
|
||||
   <a name="NamespaceBody-srhr2gdj"></a>*[NamespacePropertyList](#NamespacePropertyList)* `` ; ``<sub>opt</sub>
|
||||
|
||||
  <a name="NamespacePropertyList"></a>*NamespacePropertyList* **:**
|
||||
   <a name="NamespacePropertyList-feggpj5t"></a>*[NamespaceProperty](#NamespaceProperty)*
|
||||
   <a name="NamespacePropertyList-8g_wmadx"></a>*[NamespacePropertyList](#NamespacePropertyList)* `` , `` *[NamespaceProperty](#NamespaceProperty)*
|
||||
   <a name="NamespacePropertyList-isnpt3gn"></a>*[NamespacePropertyList](#NamespacePropertyList)* `` ; `` *[NamespaceProperty](#NamespaceProperty)*
|
||||
|
||||
  <a name="NamespaceProperty"></a>*NamespaceProperty* **:**
|
||||
   <a name="NamespaceProperty-vbdf9viv"></a>*[DecoratorList](#DecoratorList)*<sub>opt</sub> `` op `` *[Identifier](#Identifier)* `` ( `` *[ModelPropertyList](#ModelPropertyList)*<sub>opt</sub> `` ) `` `` : `` *[Expression](#Expression)*
|
||||
  <a name="OperationStatement"></a>*OperationStatement* **:**
|
||||
   <a name="OperationStatement-fic4qgph"></a>*[DecoratorList](#DecoratorList)*<sub>opt</sub> `` op `` *[Identifier](#Identifier)* `` ( `` *[ModelPropertyList](#ModelPropertyList)*<sub>opt</sub> `` ) `` `` : `` *[Expression](#Expression)* `` ; ``
|
||||
|
||||
  <a name="Expression"></a>*Expression* **:**
|
||||
   <a name="Expression-otzlm2nv"></a>*[UnionExpressionOrHigher](#UnionExpressionOrHigher)*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Program } from "../compiler/program";
|
||||
import { ModelTypeProperty, Namespace, Type } from "../compiler/types";
|
||||
import { ModelTypeProperty, NamespaceType, Type } from "../compiler/types";
|
||||
|
||||
const docs = new Map<Type, string>();
|
||||
|
||||
|
@ -178,7 +178,7 @@ function mapFilterOut(
|
|||
const listProperties = new Set<Type>();
|
||||
|
||||
export function list(program: Program, target: Type) {
|
||||
if (target.kind === "NamespaceProperty" || target.kind === "ModelProperty") {
|
||||
if (target.kind === "Operation" || target.kind === "ModelProperty") {
|
||||
listProperties.add(target);
|
||||
} else {
|
||||
throw new Error("The @list decorator can only be applied to interface or model properties.");
|
||||
|
@ -195,7 +195,7 @@ const tagProperties = new Map<Type, string[]>();
|
|||
// Set a tag on an operation or namespace. There can be multiple tags on either an
|
||||
// operation or namespace.
|
||||
export function tag(program: Program, target: Type, tag: string) {
|
||||
if (target.kind === "NamespaceProperty" || target.kind === "Namespace") {
|
||||
if (target.kind === "Operation" || target.kind === "Namespace") {
|
||||
const tags = tagProperties.get(target);
|
||||
if (tags) {
|
||||
tags.push(tag);
|
||||
|
@ -215,7 +215,7 @@ export function getTags(target: Type): string[] {
|
|||
// Merge the tags for a operation with the tags that are on the namespace it resides within.
|
||||
//
|
||||
// TODO: (JC) We'll need to update this for nested namespaces
|
||||
export function getAllTags(namespace: Namespace, target: Type): string[] | undefined {
|
||||
export function getAllTags(namespace: NamespaceType, target: Type): string[] | undefined {
|
||||
const tags = new Set<string>();
|
||||
|
||||
for (const t of getTags(namespace)) {
|
||||
|
|
|
@ -75,7 +75,7 @@ interface OperationRoute {
|
|||
const operationRoutes = new Map<Type, OperationRoute>();
|
||||
|
||||
function setOperationRoute(entity: Type, verb: OperationRoute) {
|
||||
if (entity.kind === "NamespaceProperty") {
|
||||
if (entity.kind === "Operation") {
|
||||
if (!operationRoutes.has(entity)) {
|
||||
operationRoutes.set(entity, verb);
|
||||
} else {
|
||||
|
|
|
@ -110,7 +110,7 @@ describe("syntax", () => {
|
|||
});
|
||||
|
||||
describe("tuple model expressions", () => {
|
||||
parseEach(['namespace A { op b(param: [number, string]): [1, "hi"] }']);
|
||||
parseEach(['namespace A { op b(param: [number, string]): [1, "hi"]; }']);
|
||||
});
|
||||
|
||||
describe("array expressions", () => {
|
||||
|
@ -136,13 +136,12 @@ describe("syntax", () => {
|
|||
describe("namespace statements", () => {
|
||||
parseEach([
|
||||
"namespace Store {}",
|
||||
"namespace Store { op read(): int32 }",
|
||||
"namespace Store { op read(): int32, op write(v: int32): {} }",
|
||||
"namespace Store { op read(): int32; op write(v: int32): {} }",
|
||||
"@foo namespace Store { @dec op read():number, @dec op write(n: number): {} }",
|
||||
"namespace Store { op read(): int32; }",
|
||||
"namespace Store { op read(): int32; op write(v: int32): {}; }",
|
||||
"namespace Store { op read(): int32; op write(v: int32): {}; }",
|
||||
"@foo namespace Store { @dec op read(): number; @dec op write(n: number): {}; }",
|
||||
"@foo @bar namespace Store { @foo @bar op read(): number; }",
|
||||
"namespace Store(apiKey: string, otherArg: number) { }",
|
||||
"namespace Store(... apiKeys, x: string) { op foo(... A, b: string, ...C, d: number): void }",
|
||||
"namespace Store { namespace Read { op read(): int32; } namespace Write { op write(v: int32): {}; } }",
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче