Implement nested namespace parsing, rename some core types

This commit is contained in:
David Wilson 2021-02-10 16:14:19 -08:00 коммит произвёл Brian Terlson
Родитель d617fe3000
Коммит 55ac2208f5
10 изменённых файлов: 244 добавлений и 115 удалений

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

@ -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 @@
&emsp;&emsp;&emsp;<a name="Statement-zi_5hwi0"></a>*[ImportStatement](#ImportStatement)*
&emsp;&emsp;&emsp;<a name="Statement-ngbc4m7o"></a>*[ModelStatement](#ModelStatement)*
&emsp;&emsp;&emsp;<a name="Statement-_ljtj5og"></a>*[NamespaceStatement](#NamespaceStatement)*
&emsp;&emsp;&emsp;<a name="Statement-qlyu8ssa"></a>*[OperationStatement](#OperationStatement)*
&emsp;&emsp;&emsp;<a name="Statement-sg2sawim"></a>`` ; ``
&emsp;&emsp;<a name="ImportStatement"></a>*ImportStatement* **:**
@ -206,19 +207,10 @@
&emsp;&emsp;&emsp;<a name="ModelSpreadProperty-r9kkoml-"></a>`` ... ``&emsp;*[ReferenceExpression](#ReferenceExpression)*
&emsp;&emsp;<a name="NamespaceStatement"></a>*NamespaceStatement* **:**
&emsp;&emsp;&emsp;<a name="NamespaceStatement-lllfloam"></a>*[DecoratorList](#DecoratorList)*<sub>opt</sub>&emsp;`` namespace ``&emsp;*[Identifier](#Identifier)*&emsp;`` { ``&emsp;*[NamespaceBody](#NamespaceBody)*<sub>opt</sub>&emsp;`` } ``
&emsp;&emsp;&emsp;<a name="NamespaceStatement-lrsdvje0"></a>*[DecoratorList](#DecoratorList)*<sub>opt</sub>&emsp;`` namespace ``&emsp;*[IdentifierOrMemberExpression](#IdentifierOrMemberExpression)*&emsp;`` { ``&emsp;*[StatementList](#StatementList)*<sub>opt</sub>&emsp;`` } ``
&emsp;&emsp;<a name="NamespaceBody"></a>*NamespaceBody* **:**
&emsp;&emsp;&emsp;<a name="NamespaceBody-ihomezph"></a>*[NamespacePropertyList](#NamespacePropertyList)*&emsp;`` , ``<sub>opt</sub>
&emsp;&emsp;&emsp;<a name="NamespaceBody-srhr2gdj"></a>*[NamespacePropertyList](#NamespacePropertyList)*&emsp;`` ; ``<sub>opt</sub>
&emsp;&emsp;<a name="NamespacePropertyList"></a>*NamespacePropertyList* **:**
&emsp;&emsp;&emsp;<a name="NamespacePropertyList-feggpj5t"></a>*[NamespaceProperty](#NamespaceProperty)*
&emsp;&emsp;&emsp;<a name="NamespacePropertyList-8g_wmadx"></a>*[NamespacePropertyList](#NamespacePropertyList)*&emsp;`` , ``&emsp;*[NamespaceProperty](#NamespaceProperty)*
&emsp;&emsp;&emsp;<a name="NamespacePropertyList-isnpt3gn"></a>*[NamespacePropertyList](#NamespacePropertyList)*&emsp;`` ; ``&emsp;*[NamespaceProperty](#NamespaceProperty)*
&emsp;&emsp;<a name="NamespaceProperty"></a>*NamespaceProperty* **:**
&emsp;&emsp;&emsp;<a name="NamespaceProperty-vbdf9viv"></a>*[DecoratorList](#DecoratorList)*<sub>opt</sub>&emsp;`` op ``&emsp;*[Identifier](#Identifier)*&emsp;`` ( ``&emsp;*[ModelPropertyList](#ModelPropertyList)*<sub>opt</sub>&emsp;`` ) ``&emsp;`` : ``&emsp;*[Expression](#Expression)*
&emsp;&emsp;<a name="OperationStatement"></a>*OperationStatement* **:**
&emsp;&emsp;&emsp;<a name="OperationStatement-fic4qgph"></a>*[DecoratorList](#DecoratorList)*<sub>opt</sub>&emsp;`` op ``&emsp;*[Identifier](#Identifier)*&emsp;`` ( ``&emsp;*[ModelPropertyList](#ModelPropertyList)*<sub>opt</sub>&emsp;`` ) ``&emsp;`` : ``&emsp;*[Expression](#Expression)*&emsp;`` ; ``
&emsp;&emsp;<a name="Expression"></a>*Expression* **:**
&emsp;&emsp;&emsp;<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): {}; } }",
]);
});