From 7b59ff3fe3c10d7e9af7ddec2631c1e409475f80 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Thu, 19 May 2022 18:02:33 +0300 Subject: [PATCH 01/20] Add support for operation templates and operation signature reuse --- packages/compiler/core/binder.ts | 6 +- packages/compiler/core/checker.ts | 178 +++++++++++++++---- packages/compiler/core/messages.ts | 6 + packages/compiler/core/parser.ts | 55 ++++-- packages/compiler/core/types.ts | 16 +- packages/compiler/formatter/print/printer.ts | 22 +++ packages/compiler/test/checker/operations.ts | 42 ++++- 7 files changed, 277 insertions(+), 48 deletions(-) diff --git a/packages/compiler/core/binder.ts b/packages/compiler/core/binder.ts index 3d127993bf..8e7efa796b 100644 --- a/packages/compiler/core/binder.ts +++ b/packages/compiler/core/binder.ts @@ -10,6 +10,7 @@ import { ModelStatementNode, NamespaceStatementNode, Node, + OperationInstanceNode, OperationStatementNode, ProjectionLambdaExpressionNode, ProjectionLambdaParameterDeclarationNode, @@ -202,6 +203,9 @@ export function createBinder(program: Program, options: BinderOptions = {}): Bin case SyntaxKind.OperationStatement: bindOperationStatement(node); break; + case SyntaxKind.OperationInstance: + bindOperationStatement(node); + break; case SyntaxKind.TemplateParameterDeclaration: bindTemplateParameterDeclaration(node); break; @@ -386,7 +390,7 @@ export function createBinder(program: Program, options: BinderOptions = {}): Bin (currentFile.usings as UsingStatementNode[]).push(statement); } - function bindOperationStatement(statement: OperationStatementNode) { + function bindOperationStatement(statement: OperationStatementNode | OperationInstanceNode) { if (scope.kind !== SyntaxKind.InterfaceStatement) { declareSymbol(statement, SymbolFlags.Operation); } diff --git a/packages/compiler/core/checker.ts b/packages/compiler/core/checker.ts index 2a2f7423f9..4d3f133d37 100644 --- a/packages/compiler/core/checker.ts +++ b/packages/compiler/core/checker.ts @@ -55,6 +55,7 @@ import { NodeFlags, NumericLiteralNode, NumericLiteralType, + OperationInstanceNode, OperationStatementNode, OperationType, ProjectionArithmeticExpressionNode, @@ -382,6 +383,8 @@ export function createChecker(program: Program): Checker { return checkNamespace(node); case SyntaxKind.OperationStatement: return checkOperation(node); + case SyntaxKind.OperationInstance: + return checkOperation(node); case SyntaxKind.NumericLiteral: return checkNumericLiteral(node); case SyntaxKind.BooleanLiteral: @@ -467,7 +470,13 @@ export function createChecker(program: Program): Checker { * Return a fully qualified id of node */ function getNodeSymId( - node: ModelStatementNode | AliasStatementNode | InterfaceStatementNode | UnionStatementNode + node: + | ModelStatementNode + | AliasStatementNode + | InterfaceStatementNode + | OperationStatementNode + | OperationInstanceNode + | UnionStatementNode ): number { return node.symbol!.id!; } @@ -493,6 +502,8 @@ export function createChecker(program: Program): Checker { const parentNode = node.parent! as | ModelStatementNode | InterfaceStatementNode + | OperationStatementNode + | OperationInstanceNode | UnionStatementNode | AliasStatementNode; const links = getSymbolLinks(node.symbol); @@ -679,12 +690,18 @@ export function createChecker(program: Program): Checker { const args = checkTypeReferenceArgs(node); if ( sym.flags & - (SymbolFlags.Model | SymbolFlags.Alias | SymbolFlags.Interface | SymbolFlags.Union) + (SymbolFlags.Model | + SymbolFlags.Alias | + SymbolFlags.Interface | + SymbolFlags.Operation | + SymbolFlags.Union) ) { const decl = sym.declarations[0] as | ModelStatementNode | AliasStatementNode | InterfaceStatementNode + | OperationStatementNode + | OperationInstanceNode | UnionStatementNode; if (decl.templateParameters.length === 0) { if (args.length > 0) { @@ -707,6 +724,8 @@ export function createChecker(program: Program): Checker { ? checkAlias(decl as AliasStatementNode) : sym.flags & SymbolFlags.Interface ? checkInterface(decl as InterfaceStatementNode) + : sym.flags & SymbolFlags.Operation + ? checkOperation(decl as OperationStatementNode) : checkUnion(decl as UnionStatementNode); } } else { @@ -720,6 +739,8 @@ export function createChecker(program: Program): Checker { ? checkAlias(decl as AliasStatementNode) : sym.flags & SymbolFlags.Interface ? checkInterface(decl as InterfaceStatementNode) + : sym.flags & SymbolFlags.Operation + ? checkOperation(decl as OperationStatementNode) : checkUnion(decl as UnionStatementNode); } @@ -770,6 +791,8 @@ export function createChecker(program: Program): Checker { | ModelStatementNode | AliasStatementNode | InterfaceStatementNode + | OperationStatementNode + | OperationInstanceNode | UnionStatementNode, args: Type[] ): Type { @@ -959,6 +982,7 @@ export function createChecker(program: Program): Checker { | ModelStatementNode | NamespaceStatementNode | OperationStatementNode + | OperationInstanceNode | EnumStatementNode | InterfaceStatementNode | UnionStatementNode @@ -972,6 +996,7 @@ export function createChecker(program: Program): Checker { if ( parent.kind === SyntaxKind.ModelStatement || parent.kind === SyntaxKind.OperationStatement || + parent.kind === SyntaxKind.OperationInstance || parent.kind === SyntaxKind.EnumStatement || parent.kind === SyntaxKind.InterfaceStatement || parent.kind === SyntaxKind.UnionStatement || @@ -986,7 +1011,7 @@ export function createChecker(program: Program): Checker { } if ( - node.kind === SyntaxKind.OperationStatement && + (node.kind === SyntaxKind.OperationStatement || node.kind === SyntaxKind.OperationInstance) && node.parent && node.parent.kind === SyntaxKind.InterfaceStatement ) { @@ -1022,35 +1047,130 @@ export function createChecker(program: Program): Checker { } function checkOperation( - node: OperationStatementNode, + node: OperationStatementNode | OperationInstanceNode, parentInterface?: InterfaceType - ): OperationType { + ): OperationType | ErrorType { + const links = getSymbolLinks(node.symbol); + const instantiatingThisTemplate = instantiatingTemplate === node; + if (links.declaredType && !instantiatingThisTemplate) { + // we're not instantiating this operation and we've already checked it + return links.declaredType as OperationType; + } + const namespace = getParentNamespaceType(node); const name = node.id.sv; const decorators = checkDecorators(node); - const type: OperationType = createType({ + + // Is this a definition or instance? + let parameters: ModelType, returnType: Type; + if (node.kind === SyntaxKind.OperationInstance) { + // Attempt to resolve the operation + const baseOperation = checkOperationIs(node, node.baseOperation); + if (!baseOperation) { + // TODO: Are the proper diagnostics written already? + return errorType; + } + + // Reference the same return type and create the parameters type + returnType = baseOperation.returnType; + parameters = createType({ + kind: "Model", + name: "", + node: baseOperation.parameters.node, // TODO: This seems bad! + properties: new Map(), + namespace: getParentNamespaceType(node), + decorators: [], + derivedModels: [], + }); + + // Copy parameters of the base operation + for (const prop of baseOperation.parameters.properties.values()) { + console.log("copying param:", prop.name, (prop.type as any).kind); + // Don't use the same property, clone it and finish it to execute the decorators again + parameters.properties.set( + prop.name, + finishType({ + ...prop, + }) + ); + } + } else { + parameters = getTypeForNode(node.parameters) as ModelType; + returnType = getTypeForNode(node.returnType); + } + + const operationType: OperationType = createType({ kind: "Operation", name, namespace, node, - parameters: getTypeForNode(node.parameters) as ModelType, - returnType: getTypeForNode(node.returnType), - decorators, + parameters, + returnType, + decorators, // TODO: Concatenate base operation decorators recursively! interface: parentInterface, }); - type.parameters.namespace = namespace; + operationType.parameters.namespace = namespace; if (node.parent!.kind === SyntaxKind.InterfaceStatement) { - if (shouldCreateTypeForTemplate(node.parent!)) { - finishType(type); + if (shouldCreateTypeForTemplate(node.parent!) || shouldCreateTypeForTemplate(node)) { + finishType(operationType); } } else { - finishType(type); - namespace?.operations.set(name, type); + if (shouldCreateTypeForTemplate(node)) { + finishType(operationType); + } + + namespace?.operations.set(name, operationType); } - return type; + if (!instantiatingThisTemplate) { + links.declaredType = operationType; + links.instantiations = new TypeInstantiationMap(); + } + + return operationType; + } + + function checkOperationIs( + operation: OperationInstanceNode, + opReference: TypeReferenceNode | undefined + ): OperationType | undefined { + if (!opReference) return undefined; + + // Ensure that we don't end up with a circular reference to the same operation + const opSymId = getNodeSymId(operation); + pendingResolutions.add(opSymId); + + const target = resolveTypeReference(opReference); + if (target === undefined) { + return undefined; + } + + // Did we encounter a circular operation reference? + if (pendingResolutions.has(getNodeSymId(target.declarations[0] as any))) { + if (!isInstantiatingTemplateType()) { + reportDiagnostic(program, { + code: "circular-base-type", + format: { typeName: (target.declarations[0] as any).id.sv }, + target: target, + }); + } + + return undefined; + } + + // Resolve the base operation type + const baseOperation = checkTypeReferenceSymbol(target, opReference); + pendingResolutions.delete(opSymId); + + // Was the wrong type referenced? + if (baseOperation.kind !== "Operation") { + program.reportDiagnostic(createDiagnostic({ code: "is-operation", target: opReference })); + return; + } + + return baseOperation; } function getGlobalNamespaceType() { @@ -2070,11 +2190,7 @@ export function createChecker(program: Program): Checker { interfaceType.operations.set(k, v); } - if ( - (instantiatingThisTemplate && - templateInstantiation.every((t) => t.kind !== "TemplateParameter")) || - node.templateParameters.length === 0 - ) { + if (shouldCreateTypeForTemplate(node)) { finishType(interfaceType); } @@ -2094,17 +2210,19 @@ export function createChecker(program: Program): Checker { ) { for (const opNode of node.operations) { const opType = checkOperation(opNode, interfaceType); - if (members.has(opType.name)) { - program.reportDiagnostic( - createDiagnostic({ - code: "interface-duplicate", - format: { name: opType.name }, - target: opNode, - }) - ); - continue; + if (opType.kind === "Operation") { + if (members.has(opType.name)) { + program.reportDiagnostic( + createDiagnostic({ + code: "interface-duplicate", + format: { name: opType.name }, + target: opNode, + }) + ); + continue; + } + members.set(opType.name, opType); } - members.set(opType.name, opType); } } diff --git a/packages/compiler/core/messages.ts b/packages/compiler/core/messages.ts index c54c0f6d65..60bfe6039a 100644 --- a/packages/compiler/core/messages.ts +++ b/packages/compiler/core/messages.ts @@ -287,6 +287,12 @@ const diagnostics = { default: "Model `is` must specify another model.", }, }, + "is-operation": { + severity: "error", + messages: { + default: "Operation can only reuse the signature of another operation.", + }, + }, "spread-model": { severity: "error", messages: { diff --git a/packages/compiler/core/parser.ts b/packages/compiler/core/parser.ts index 27368514a3..21f7e1f0c2 100644 --- a/packages/compiler/core/parser.ts +++ b/packages/compiler/core/parser.ts @@ -44,6 +44,7 @@ import { Node, NodeFlags, NumericLiteralNode, + OperationInstanceNode, OperationStatementNode, ProjectionBlockExpressionNode, ProjectionEnumSelectorNode, @@ -552,6 +553,7 @@ export function parse(code: string | SourceFile, options: ParseOptions = {}): Ca return { kind: SyntaxKind.OperationStatement, id, + templateParameters: [], parameters, returnType, decorators, @@ -611,24 +613,44 @@ export function parse(code: string | SourceFile, options: ParseOptions = {}): Ca function parseOperationStatement( pos: number, decorators: DecoratorExpressionNode[] - ): OperationStatementNode { + ): OperationStatementNode | OperationInstanceNode { parseExpected(Token.OpKeyword); const id = parseIdentifier(); - const parameters = parseOperationParameters(); - parseExpected(Token.Colon); + const templateParameters = parseTemplateParameterList(); - const returnType = parseExpression(); - parseExpected(Token.Semicolon); + // Check if we're parsing a declaration or reuse of another operation + if (token() === Token.OpenParen) { + const parameters = parseOperationParameters(); + parseExpected(Token.Colon); + const returnType = parseExpression(); - return { - kind: SyntaxKind.OperationStatement, - id, - parameters, - returnType, - decorators, - ...finishNode(pos), - }; + parseExpected(Token.Semicolon); + + return { + kind: SyntaxKind.OperationStatement, + id, + templateParameters, + parameters, + returnType, + decorators, + ...finishNode(pos), + }; + } else { + parseExpected(Token.Colon); + const opReference = parseReferenceExpression(); + + parseExpected(Token.Semicolon); + + return { + kind: SyntaxKind.OperationInstance, + id, + templateParameters, + baseOperation: opReference, + decorators, + ...finishNode(pos), + }; + } } function parseOperationParameters(): ModelExpressionNode { @@ -2157,8 +2179,15 @@ export function visitChildren(node: Node, cb: NodeCallback): T | undefined visitEach(cb, node.decorators) || visitNode(cb, node.id) || visitNode(cb, node.parameters) || + visitEach(cb, node.templateParameters) || visitNode(cb, node.returnType) ); + case SyntaxKind.OperationInstance: + return ( + visitEach(cb, node.decorators) || + visitNode(cb, node.id) || + visitNode(cb, node.baseOperation) + ); case SyntaxKind.NamespaceStatement: return ( visitEach(cb, node.decorators) || diff --git a/packages/compiler/core/types.ts b/packages/compiler/core/types.ts index 823b2f18ab..6c32fef42b 100644 --- a/packages/compiler/core/types.ts +++ b/packages/compiler/core/types.ts @@ -209,9 +209,9 @@ export interface EnumMemberType extends BaseType, DecoratedType { value?: string | number; } -export interface OperationType extends BaseType, DecoratedType { +export interface OperationType extends BaseType, DecoratedType, TemplatedType { kind: "Operation"; - node: OperationStatementNode; + node: OperationStatementNode | OperationInstanceNode; name: string; namespace?: NamespaceType; interface?: InterfaceType; @@ -393,6 +393,7 @@ export enum SyntaxKind { NamespaceStatement, UsingStatement, OperationStatement, + OperationInstance, ModelStatement, ModelExpression, ModelProperty, @@ -506,6 +507,7 @@ export type Node = | ModelPropertyNode | UnionVariantNode | OperationStatementNode + | OperationInstanceNode | EnumMemberNode | ModelSpreadPropertyNode | DecoratorExpressionNode @@ -556,6 +558,7 @@ export type Statement = | EnumStatementNode | AliasStatementNode | OperationStatementNode + | OperationInstanceNode | EmptyStatementNode | InvalidStatementNode | ProjectionStatementNode; @@ -570,6 +573,7 @@ export type Declaration = | UnionStatementNode | NamespaceStatementNode | OperationStatementNode + | OperationInstanceNode | TemplateParameterDeclarationNode | ProjectionStatementNode | ProjectionParameterDeclarationNode @@ -673,13 +677,19 @@ export interface UsingStatementNode extends BaseNode { readonly name: IdentifierNode | MemberExpressionNode; } -export interface OperationStatementNode extends BaseNode, DeclarationNode { +export interface OperationStatementNode extends BaseNode, DeclarationNode, TemplateDeclarationNode { readonly kind: SyntaxKind.OperationStatement; readonly parameters: ModelExpressionNode; readonly returnType: Expression; readonly decorators: readonly DecoratorExpressionNode[]; } +export interface OperationInstanceNode extends BaseNode, DeclarationNode, TemplateDeclarationNode { + readonly kind: SyntaxKind.OperationInstance; + readonly baseOperation: TypeReferenceNode; + readonly decorators: readonly DecoratorExpressionNode[]; +} + export interface ModelStatementNode extends BaseNode, DeclarationNode, TemplateDeclarationNode { readonly kind: SyntaxKind.ModelStatement; readonly properties: readonly (ModelPropertyNode | ModelSpreadPropertyNode)[]; diff --git a/packages/compiler/formatter/print/printer.ts b/packages/compiler/formatter/print/printer.ts index 39665a4135..04c8d35468 100644 --- a/packages/compiler/formatter/print/printer.ts +++ b/packages/compiler/formatter/print/printer.ts @@ -23,6 +23,7 @@ import { Node, NodeFlags, NumericLiteralNode, + OperationInstanceNode, OperationStatementNode, Statement, StringLiteralNode, @@ -85,6 +86,8 @@ export function printNode( return [`using `, path.call(print, "name"), `;`]; case SyntaxKind.OperationStatement: return printOperationStatement(path as AstPath, options, print); + case SyntaxKind.OperationInstance: + return printOperationInstance(path as AstPath, options, print); case SyntaxKind.NamespaceStatement: return printNamespaceStatement(path as AstPath, options, print); case SyntaxKind.ModelStatement: @@ -875,6 +878,25 @@ export function printOperationStatement( ]; } +export function printOperationInstance( + path: AstPath, + options: CadlPrettierOptions, + print: PrettierChildPrint +) { + const inInterface = (path.getParentNode()?.kind as any) === SyntaxKind.InterfaceStatement; + const { decorators } = printDecorators(path as AstPath, options, print, { + tryInline: true, + }); + + return [ + decorators, + inInterface ? "" : "op ", + path.call(print, "id"), + path.call(print, "baseOperation"), + `;`, + ]; +} + export function printStatementSequence( path: AstPath, options: CadlPrettierOptions, diff --git a/packages/compiler/test/checker/operations.ts b/packages/compiler/test/checker/operations.ts index 8ba0217f1f..184b78cfcd 100644 --- a/packages/compiler/test/checker/operations.ts +++ b/packages/compiler/test/checker/operations.ts @@ -1,6 +1,6 @@ import { strictEqual } from "assert"; import { IntrinsicType, OperationType } from "../../core/types.js"; -import { createTestHost, TestHost } from "../../testing/index.js"; +import { createTestHost, expectDiagnostics, TestHost } from "../../testing/index.js"; describe("cadl: operations", () => { let testHost: TestHost; @@ -21,4 +21,44 @@ describe("cadl: operations", () => { strictEqual(foo.returnType.kind, "Intrinsic"); strictEqual((foo.returnType as IntrinsicType).name, "void"); }); + + it.only("can be templated", async () => { + testHost.addCadlFile( + "main.cadl", + `@test op foo(name: TString, payload: TPayload): boolean; + + @test + op newFoo: foo;` + ); + + const [result, diagnostics] = await testHost.compileAndDiagnose("./main.cadl"); + expectDiagnostics(diagnostics, []); + + const { newFoo } = result as { newFoo: OperationType }; + strictEqual(newFoo.parameters.properties.size, 2); + const props = Array.from(newFoo.parameters.properties.values()); + + strictEqual(props[0].name, "name"); + strictEqual(props[1].name, "payload"); + }); + + it.only("can reuse operation instances", async () => { + testHost.addCadlFile( + "main.cadl", + `@test op foo(name: TString, payload: TPayload): boolean; + + op newFooBase: foo; + op newFoo: newFooBase;` + ); + + const [result, diagnostics] = await testHost.compileAndDiagnose("./main.cadl"); + expectDiagnostics(diagnostics, []); + + const { newFoo } = result as { newFoo: OperationType }; + strictEqual(newFoo.parameters.properties.size, 2); + const props = Array.from(newFoo.parameters.properties.values()); + + strictEqual(props[0].name, "name"); + strictEqual(props[1].name, "payload"); + }); }); From ea13b9450bc4f89423f8d477af8cd098dfb8a078 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 06:52:44 +0300 Subject: [PATCH 02/20] Replace `OperationInstanceNode` with `OperationSignature` types --- packages/compiler/core/binder.ts | 6 +- packages/compiler/core/checker.ts | 79 +++++-------- packages/compiler/core/parser.ts | 87 ++++++-------- packages/compiler/core/types.ts | 22 ++-- packages/compiler/formatter/print/printer.ts | 61 +++++----- packages/compiler/test/checker/operations.ts | 115 +++++++++++++++++-- packages/compiler/test/test-parser.ts | 1 + 7 files changed, 214 insertions(+), 157 deletions(-) diff --git a/packages/compiler/core/binder.ts b/packages/compiler/core/binder.ts index 8e7efa796b..3d127993bf 100644 --- a/packages/compiler/core/binder.ts +++ b/packages/compiler/core/binder.ts @@ -10,7 +10,6 @@ import { ModelStatementNode, NamespaceStatementNode, Node, - OperationInstanceNode, OperationStatementNode, ProjectionLambdaExpressionNode, ProjectionLambdaParameterDeclarationNode, @@ -203,9 +202,6 @@ export function createBinder(program: Program, options: BinderOptions = {}): Bin case SyntaxKind.OperationStatement: bindOperationStatement(node); break; - case SyntaxKind.OperationInstance: - bindOperationStatement(node); - break; case SyntaxKind.TemplateParameterDeclaration: bindTemplateParameterDeclaration(node); break; @@ -390,7 +386,7 @@ export function createBinder(program: Program, options: BinderOptions = {}): Bin (currentFile.usings as UsingStatementNode[]).push(statement); } - function bindOperationStatement(statement: OperationStatementNode | OperationInstanceNode) { + function bindOperationStatement(statement: OperationStatementNode) { if (scope.kind !== SyntaxKind.InterfaceStatement) { declareSymbol(statement, SymbolFlags.Operation); } diff --git a/packages/compiler/core/checker.ts b/packages/compiler/core/checker.ts index 4d3f133d37..fdf988f678 100644 --- a/packages/compiler/core/checker.ts +++ b/packages/compiler/core/checker.ts @@ -55,7 +55,6 @@ import { NodeFlags, NumericLiteralNode, NumericLiteralType, - OperationInstanceNode, OperationStatementNode, OperationType, ProjectionArithmeticExpressionNode, @@ -383,8 +382,6 @@ export function createChecker(program: Program): Checker { return checkNamespace(node); case SyntaxKind.OperationStatement: return checkOperation(node); - case SyntaxKind.OperationInstance: - return checkOperation(node); case SyntaxKind.NumericLiteral: return checkNumericLiteral(node); case SyntaxKind.BooleanLiteral: @@ -475,7 +472,6 @@ export function createChecker(program: Program): Checker { | AliasStatementNode | InterfaceStatementNode | OperationStatementNode - | OperationInstanceNode | UnionStatementNode ): number { return node.symbol!.id!; @@ -503,7 +499,6 @@ export function createChecker(program: Program): Checker { | ModelStatementNode | InterfaceStatementNode | OperationStatementNode - | OperationInstanceNode | UnionStatementNode | AliasStatementNode; const links = getSymbolLinks(node.symbol); @@ -701,7 +696,6 @@ export function createChecker(program: Program): Checker { | AliasStatementNode | InterfaceStatementNode | OperationStatementNode - | OperationInstanceNode | UnionStatementNode; if (decl.templateParameters.length === 0) { if (args.length > 0) { @@ -792,7 +786,6 @@ export function createChecker(program: Program): Checker { | AliasStatementNode | InterfaceStatementNode | OperationStatementNode - | OperationInstanceNode | UnionStatementNode, args: Type[] ): Type { @@ -982,7 +975,6 @@ export function createChecker(program: Program): Checker { | ModelStatementNode | NamespaceStatementNode | OperationStatementNode - | OperationInstanceNode | EnumStatementNode | InterfaceStatementNode | UnionStatementNode @@ -996,7 +988,6 @@ export function createChecker(program: Program): Checker { if ( parent.kind === SyntaxKind.ModelStatement || parent.kind === SyntaxKind.OperationStatement || - parent.kind === SyntaxKind.OperationInstance || parent.kind === SyntaxKind.EnumStatement || parent.kind === SyntaxKind.InterfaceStatement || parent.kind === SyntaxKind.UnionStatement || @@ -1011,7 +1002,7 @@ export function createChecker(program: Program): Checker { } if ( - (node.kind === SyntaxKind.OperationStatement || node.kind === SyntaxKind.OperationInstance) && + node.kind === SyntaxKind.OperationStatement && node.parent && node.parent.kind === SyntaxKind.InterfaceStatement ) { @@ -1047,56 +1038,42 @@ export function createChecker(program: Program): Checker { } function checkOperation( - node: OperationStatementNode | OperationInstanceNode, + node: OperationStatementNode, parentInterface?: InterfaceType ): OperationType | ErrorType { - const links = getSymbolLinks(node.symbol); + // Operations defined in interfaces aren't bound to symbols + const links = !parentInterface ? getSymbolLinks(node.symbol) : undefined; const instantiatingThisTemplate = instantiatingTemplate === node; - if (links.declaredType && !instantiatingThisTemplate) { - // we're not instantiating this operation and we've already checked it - return links.declaredType as OperationType; + if (links) { + if (links.declaredType && !instantiatingThisTemplate) { + // we're not instantiating this operation and we've already checked it + return links.declaredType as OperationType; + } } const namespace = getParentNamespaceType(node); const name = node.id.sv; - const decorators = checkDecorators(node); + let decorators = checkDecorators(node); - // Is this a definition or instance? + // Is this a definition or reference? let parameters: ModelType, returnType: Type; - if (node.kind === SyntaxKind.OperationInstance) { + if (node.signature.kind === "OperationReference") { // Attempt to resolve the operation - const baseOperation = checkOperationIs(node, node.baseOperation); + const baseOperation = checkOperationIs(node, node.signature.baseOperation); if (!baseOperation) { - // TODO: Are the proper diagnostics written already? return errorType; } // Reference the same return type and create the parameters type + parameters = cloneType(baseOperation.parameters); + parameters.node = { ...parameters.node, parent: node }; returnType = baseOperation.returnType; - parameters = createType({ - kind: "Model", - name: "", - node: baseOperation.parameters.node, // TODO: This seems bad! - properties: new Map(), - namespace: getParentNamespaceType(node), - decorators: [], - derivedModels: [], - }); - // Copy parameters of the base operation - for (const prop of baseOperation.parameters.properties.values()) { - console.log("copying param:", prop.name, (prop.type as any).kind); - // Don't use the same property, clone it and finish it to execute the decorators again - parameters.properties.set( - prop.name, - finishType({ - ...prop, - }) - ); - } + // Copy decorators from the base operation, inserting the base decorators first + decorators = [...baseOperation.decorators, ...decorators]; } else { - parameters = getTypeForNode(node.parameters) as ModelType; - returnType = getTypeForNode(node.returnType); + parameters = getTypeForNode(node.signature.parameters) as ModelType; + returnType = getTypeForNode(node.signature.returnType); } const operationType: OperationType = createType({ @@ -1106,14 +1083,14 @@ export function createChecker(program: Program): Checker { node, parameters, returnType, - decorators, // TODO: Concatenate base operation decorators recursively! + decorators, interface: parentInterface, }); operationType.parameters.namespace = namespace; if (node.parent!.kind === SyntaxKind.InterfaceStatement) { - if (shouldCreateTypeForTemplate(node.parent!) || shouldCreateTypeForTemplate(node)) { + if (shouldCreateTypeForTemplate(node.parent!) && shouldCreateTypeForTemplate(node)) { finishType(operationType); } } else { @@ -1124,7 +1101,7 @@ export function createChecker(program: Program): Checker { namespace?.operations.set(name, operationType); } - if (!instantiatingThisTemplate) { + if (links && !instantiatingThisTemplate) { links.declaredType = operationType; links.instantiations = new TypeInstantiationMap(); } @@ -1133,14 +1110,16 @@ export function createChecker(program: Program): Checker { } function checkOperationIs( - operation: OperationInstanceNode, + operation: OperationStatementNode, opReference: TypeReferenceNode | undefined ): OperationType | undefined { if (!opReference) return undefined; // Ensure that we don't end up with a circular reference to the same operation - const opSymId = getNodeSymId(operation); - pendingResolutions.add(opSymId); + const opSymId = operation.symbol ? getNodeSymId(operation) : undefined; + if (opSymId) { + pendingResolutions.add(opSymId); + } const target = resolveTypeReference(opReference); if (target === undefined) { @@ -1162,7 +1141,9 @@ export function createChecker(program: Program): Checker { // Resolve the base operation type const baseOperation = checkTypeReferenceSymbol(target, opReference); - pendingResolutions.delete(opSymId); + if (opSymId) { + pendingResolutions.delete(opSymId); + } // Was the wrong type referenced? if (baseOperation.kind !== "Operation") { diff --git a/packages/compiler/core/parser.ts b/packages/compiler/core/parser.ts index 21f7e1f0c2..cfbd2c5dfc 100644 --- a/packages/compiler/core/parser.ts +++ b/packages/compiler/core/parser.ts @@ -44,7 +44,7 @@ import { Node, NodeFlags, NumericLiteralNode, - OperationInstanceNode, + OperationSignature, OperationStatementNode, ProjectionBlockExpressionNode, ProjectionEnumSelectorNode, @@ -509,7 +509,9 @@ export function parse(code: string | SourceFile, options: ParseOptions = {}): Ca nextToken(); } - const operations = parseList(ListKind.InterfaceMembers, parseInterfaceMember); + const operations = parseList(ListKind.InterfaceMembers, (pos, decorators) => + parseOperationStatement(pos, decorators, true) + ); return { kind: SyntaxKind.InterfaceStatement, @@ -539,28 +541,6 @@ export function parse(code: string | SourceFile, options: ParseOptions = {}): Ca return list; } - function parseInterfaceMember( - pos: number, - decorators: DecoratorExpressionNode[] - ): OperationStatementNode { - parseOptional(Token.OpKeyword); - - const id = parseIdentifier(); - const parameters = parseOperationParameters(); - parseExpected(Token.Colon); - - const returnType = parseExpression(); - return { - kind: SyntaxKind.OperationStatement, - id, - templateParameters: [], - parameters, - returnType, - decorators, - ...finishNode(pos), - }; - } - function parseUnionStatement( pos: number, decorators: DecoratorExpressionNode[] @@ -612,45 +592,53 @@ export function parse(code: string | SourceFile, options: ParseOptions = {}): Ca function parseOperationStatement( pos: number, - decorators: DecoratorExpressionNode[] - ): OperationStatementNode | OperationInstanceNode { - parseExpected(Token.OpKeyword); + decorators: DecoratorExpressionNode[], + inInterface?: boolean + ): OperationStatementNode { + if (inInterface) { + parseOptional(Token.OpKeyword); + } else { + parseExpected(Token.OpKeyword); + } const id = parseIdentifier(); - const templateParameters = parseTemplateParameterList(); + const templateParameters = inInterface ? [] : parseTemplateParameterList(); // Check if we're parsing a declaration or reuse of another operation + let signature: OperationSignature; if (token() === Token.OpenParen) { const parameters = parseOperationParameters(); parseExpected(Token.Colon); const returnType = parseExpression(); - parseExpected(Token.Semicolon); - - return { - kind: SyntaxKind.OperationStatement, - id, - templateParameters, + signature = { + kind: "OperationDeclaration", parameters, returnType, - decorators, - ...finishNode(pos), }; } else { parseExpected(Token.Colon); const opReference = parseReferenceExpression(); - parseExpected(Token.Semicolon); - - return { - kind: SyntaxKind.OperationInstance, - id, - templateParameters, + signature = { + kind: "OperationReference", baseOperation: opReference, - decorators, - ...finishNode(pos), }; } + + // The interface parser handles semicolon parsing between statements + if (!inInterface) { + parseExpected(Token.Semicolon); + } + + return { + kind: SyntaxKind.OperationStatement, + id, + templateParameters, + signature, + decorators, + ...finishNode(pos), + }; } function parseOperationParameters(): ModelExpressionNode { @@ -2178,15 +2166,10 @@ export function visitChildren(node: Node, cb: NodeCallback): T | undefined return ( visitEach(cb, node.decorators) || visitNode(cb, node.id) || - visitNode(cb, node.parameters) || visitEach(cb, node.templateParameters) || - visitNode(cb, node.returnType) - ); - case SyntaxKind.OperationInstance: - return ( - visitEach(cb, node.decorators) || - visitNode(cb, node.id) || - visitNode(cb, node.baseOperation) + (node.signature.kind === "OperationDeclaration" + ? visitNode(cb, node.signature.parameters) || visitNode(cb, node.signature.returnType) + : visitNode(cb, node.signature.baseOperation)) ); case SyntaxKind.NamespaceStatement: return ( diff --git a/packages/compiler/core/types.ts b/packages/compiler/core/types.ts index 6c32fef42b..cf34c4bd14 100644 --- a/packages/compiler/core/types.ts +++ b/packages/compiler/core/types.ts @@ -211,7 +211,7 @@ export interface EnumMemberType extends BaseType, DecoratedType { export interface OperationType extends BaseType, DecoratedType, TemplatedType { kind: "Operation"; - node: OperationStatementNode | OperationInstanceNode; + node: OperationStatementNode; name: string; namespace?: NamespaceType; interface?: InterfaceType; @@ -393,7 +393,6 @@ export enum SyntaxKind { NamespaceStatement, UsingStatement, OperationStatement, - OperationInstance, ModelStatement, ModelExpression, ModelProperty, @@ -507,7 +506,6 @@ export type Node = | ModelPropertyNode | UnionVariantNode | OperationStatementNode - | OperationInstanceNode | EnumMemberNode | ModelSpreadPropertyNode | DecoratorExpressionNode @@ -558,7 +556,6 @@ export type Statement = | EnumStatementNode | AliasStatementNode | OperationStatementNode - | OperationInstanceNode | EmptyStatementNode | InvalidStatementNode | ProjectionStatementNode; @@ -573,7 +570,6 @@ export type Declaration = | UnionStatementNode | NamespaceStatementNode | OperationStatementNode - | OperationInstanceNode | TemplateParameterDeclarationNode | ProjectionStatementNode | ProjectionParameterDeclarationNode @@ -677,16 +673,22 @@ export interface UsingStatementNode extends BaseNode { readonly name: IdentifierNode | MemberExpressionNode; } -export interface OperationStatementNode extends BaseNode, DeclarationNode, TemplateDeclarationNode { - readonly kind: SyntaxKind.OperationStatement; +export interface OperationSignatureDeclaration { + readonly kind: "OperationDeclaration"; readonly parameters: ModelExpressionNode; readonly returnType: Expression; - readonly decorators: readonly DecoratorExpressionNode[]; } -export interface OperationInstanceNode extends BaseNode, DeclarationNode, TemplateDeclarationNode { - readonly kind: SyntaxKind.OperationInstance; +export interface OperationSignatureReference { + readonly kind: "OperationReference"; readonly baseOperation: TypeReferenceNode; +} + +export type OperationSignature = OperationSignatureDeclaration | OperationSignatureReference; + +export interface OperationStatementNode extends BaseNode, DeclarationNode, TemplateDeclarationNode { + readonly kind: SyntaxKind.OperationStatement; + readonly signature: OperationSignature; readonly decorators: readonly DecoratorExpressionNode[]; } diff --git a/packages/compiler/formatter/print/printer.ts b/packages/compiler/formatter/print/printer.ts index 04c8d35468..125970a88c 100644 --- a/packages/compiler/formatter/print/printer.ts +++ b/packages/compiler/formatter/print/printer.ts @@ -23,7 +23,7 @@ import { Node, NodeFlags, NumericLiteralNode, - OperationInstanceNode, + OperationSignature, OperationStatementNode, Statement, StringLiteralNode, @@ -86,8 +86,6 @@ export function printNode( return [`using `, path.call(print, "name"), `;`]; case SyntaxKind.OperationStatement: return printOperationStatement(path as AstPath, options, print); - case SyntaxKind.OperationInstance: - return printOperationInstance(path as AstPath, options, print); case SyntaxKind.NamespaceStatement: return printNamespaceStatement(path as AstPath, options, print); case SyntaxKind.ModelStatement: @@ -813,10 +811,13 @@ function isStringSafeToUnquote(id: StringLiteralNode, options: CadlPrettierOptio } function isModelExpressionInBlock(path: AstPath) { - const parent: Node | null = path.getParentNode() as any; + // The parent can either be a regular Node or an OperationSignature because + // the printer has to walk through `OperationSignatureNode.signature` which + // isn't a node itself. + const parent: Node | OperationSignature | null = path.getParentNode() as any; switch (parent?.kind) { - case SyntaxKind.OperationStatement: + case "OperationDeclaration": return parent.parameters !== path.getNode(); default: return true; @@ -866,35 +867,27 @@ export function printOperationStatement( tryInline: true, }); - return [ - decorators, - inInterface ? "" : "op ", - path.call(print, "id"), - "(", - path.call(print, "parameters"), - "): ", - path.call(print, "returnType"), - `;`, - ]; -} - -export function printOperationInstance( - path: AstPath, - options: CadlPrettierOptions, - print: PrettierChildPrint -) { - const inInterface = (path.getParentNode()?.kind as any) === SyntaxKind.InterfaceStatement; - const { decorators } = printDecorators(path as AstPath, options, print, { - tryInline: true, - }); - - return [ - decorators, - inInterface ? "" : "op ", - path.call(print, "id"), - path.call(print, "baseOperation"), - `;`, - ]; + const opKind = path.getNode()!.signature.kind; + if (opKind === "OperationDeclaration") { + return [ + decorators, + inInterface ? "" : "op ", + path.call(print, "id"), + "(", + path.call(print, "signature", "parameters"), + "): ", + path.call(print, "signature", "returnType"), + `;`, + ]; + } else { + return [ + decorators, + inInterface ? "" : "op ", + path.call(print, "id"), + path.call(print, "signature", "baseOperation"), + `;`, + ]; + } } export function printStatementSequence( diff --git a/packages/compiler/test/checker/operations.ts b/packages/compiler/test/checker/operations.ts index 184b78cfcd..a5bf9af81e 100644 --- a/packages/compiler/test/checker/operations.ts +++ b/packages/compiler/test/checker/operations.ts @@ -1,5 +1,5 @@ -import { strictEqual } from "assert"; -import { IntrinsicType, OperationType } from "../../core/types.js"; +import { ok, strictEqual } from "assert"; +import { DecoratorContext, IntrinsicType, OperationType, Type } from "../../core/types.js"; import { createTestHost, expectDiagnostics, TestHost } from "../../testing/index.js"; describe("cadl: operations", () => { @@ -22,10 +22,10 @@ describe("cadl: operations", () => { strictEqual((foo.returnType as IntrinsicType).name, "void"); }); - it.only("can be templated", async () => { + it("can be templated and referenced to define other operations", async () => { testHost.addCadlFile( "main.cadl", - `@test op foo(name: TString, payload: TPayload): boolean; + `op foo(name: TName, payload: TPayload): boolean; @test op newFoo: foo;` @@ -39,15 +39,18 @@ describe("cadl: operations", () => { const props = Array.from(newFoo.parameters.properties.values()); strictEqual(props[0].name, "name"); + strictEqual(props[0].type.kind, "Model"); strictEqual(props[1].name, "payload"); + strictEqual(props[1].type.kind, "Model"); }); - it.only("can reuse operation instances", async () => { + it("can be defined based on other operation references", async () => { testHost.addCadlFile( "main.cadl", - `@test op foo(name: TString, payload: TPayload): boolean; + `op foo(name: TName, payload: TPayload): boolean; + op newFooBase: foo; - op newFooBase: foo; + @test op newFoo: newFooBase;` ); @@ -59,6 +62,104 @@ describe("cadl: operations", () => { const props = Array.from(newFoo.parameters.properties.values()); strictEqual(props[0].name, "name"); + strictEqual(props[0].type.kind, "Model"); strictEqual(props[1].name, "payload"); + strictEqual(props[1].type.kind, "Model"); + }); + + it("can reference an operation when being defined in an interface", async () => { + testHost.addCadlFile( + "main.cadl", + `op foo(name: TName, payload: TPayload): boolean; + + interface Test { + @test + newFoo: foo; + }` + ); + + const [result, diagnostics] = await testHost.compileAndDiagnose("./main.cadl"); + expectDiagnostics(diagnostics, []); + + const { newFoo } = result as { newFoo: OperationType }; + strictEqual(newFoo.parameters.properties.size, 2); + const props = Array.from(newFoo.parameters.properties.values()); + + strictEqual(props[0].name, "name"); + strictEqual(props[0].type.kind, "Model"); + strictEqual(props[1].name, "payload"); + strictEqual(props[1].type.kind, "Model"); + }); + + it("applies the decorators of the referenced operation and its transitive references", async () => { + const alphaTargets = new Map(); + const betaTargets = new Set(); + const kappaTargets = new Set(); + + testHost.addJsFile("test.js", { + $alpha(context: DecoratorContext, target: Type, param: Type) { + alphaTargets.set(target, param); + }, + + $beta(context: DecoratorContext, target: Type) { + betaTargets.add(target); + }, + + $kappa(context: DecoratorContext, target: Type) { + kappaTargets.add(target); + }, + }); + + testHost.addCadlFile( + "main.cadl", + ` + import "./test.js"; + @alpha(TPayload) + op foo(name: TName, payload: TPayload): boolean; + + @beta + op newFooBase: foo; + + @test + @kappa + op newFoo: newFooBase;` + ); + + const [result, diagnostics] = await testHost.compileAndDiagnose("./main.cadl"); + expectDiagnostics(diagnostics, []); + + const { newFoo } = result as { newFoo: OperationType }; + strictEqual(newFoo.parameters.properties.size, 2); + + // Check that the decorators were applied correctly to `newFoo` + strictEqual(alphaTargets.get(newFoo)?.kind, "Model"); + ok(betaTargets.has(newFoo)); + ok(kappaTargets.has(newFoo)); + }); + + it("prevents the definition of a templated operation in an interface", async () => { + testHost.addCadlFile( + "main.cadl", + ` + interface Test { + getResource(name: string): TResource; + }` + ); + + const [_, diagnostics] = await testHost.compileAndDiagnose("./main.cadl"); + expectDiagnostics(diagnostics, [ + { + code: "token-expected", + message: `':' expected.`, + }, + { + code: "token-expected", + message: `';' expected.`, + }, + { + code: "unknown-identifier", + message: `Unknown identifier TResource`, + }, + ]); }); }); diff --git a/packages/compiler/test/test-parser.ts b/packages/compiler/test/test-parser.ts index 9c0498bc8b..bc0bc6fcef 100644 --- a/packages/compiler/test/test-parser.ts +++ b/packages/compiler/test/test-parser.ts @@ -638,6 +638,7 @@ function dynamicVisitChildren(node: Node, cb: (key: string, child: any) => void) for (const [key, value] of Object.entries(node)) { switch (key) { case "parent": + case "signature": // OperationStatementNode.signature doesn't have a node type case "parseDiagnostics": return; } From 96072e5b543343cbff6538ba106a5bcde46a382d Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 15:20:38 +0300 Subject: [PATCH 03/20] Add Rush change file --- .../compiler/operation-templates_2022-05-25-12-20.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@cadl-lang/compiler/operation-templates_2022-05-25-12-20.json diff --git a/common/changes/@cadl-lang/compiler/operation-templates_2022-05-25-12-20.json b/common/changes/@cadl-lang/compiler/operation-templates_2022-05-25-12-20.json new file mode 100644 index 0000000000..cd052661b5 --- /dev/null +++ b/common/changes/@cadl-lang/compiler/operation-templates_2022-05-25-12-20.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@cadl-lang/compiler", + "comment": "Add support for operation templates and operation signature reuse", + "type": "minor" + } + ], + "packageName": "@cadl-lang/compiler" +} \ No newline at end of file From 0b4307f32d813ee7d4efa6f7be16a703998b30b3 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 16:09:10 +0300 Subject: [PATCH 04/20] Skip templated operations when scanning for operation routes --- .../rest/operation-templates_2022-05-25-13-10.json | 10 ++++++++++ packages/rest/src/route.ts | 6 ++++++ 2 files changed, 16 insertions(+) create mode 100644 common/changes/@cadl-lang/rest/operation-templates_2022-05-25-13-10.json diff --git a/common/changes/@cadl-lang/rest/operation-templates_2022-05-25-13-10.json b/common/changes/@cadl-lang/rest/operation-templates_2022-05-25-13-10.json new file mode 100644 index 0000000000..80738c0baf --- /dev/null +++ b/common/changes/@cadl-lang/rest/operation-templates_2022-05-25-13-10.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@cadl-lang/rest", + "comment": "Skip templated operations when scanning for operation routes", + "type": "patch" + } + ], + "packageName": "@cadl-lang/rest" +} \ No newline at end of file diff --git a/packages/rest/src/route.ts b/packages/rest/src/route.ts index e87f2edc04..b2672b39eb 100644 --- a/packages/rest/src/route.ts +++ b/packages/rest/src/route.ts @@ -418,9 +418,15 @@ function buildRoutes( continue; } + // Skip templated operations + if (op.templateArguments && op.templateArguments.length > 0) { + continue; + } + const route = getPathForOperation(program, diagnostics, op, parentFragments, options); const verb = getVerbForOperation(program, diagnostics, op, route.parameters); const responses = diagnostics.pipe(getResponsesForOperation(program, op)); + operations.push({ path: route.path, pathFragment: route.pathFragment, From 48b7c6b31c93ec19a1565011ed99a94dd34ed6e1 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 16:10:31 +0300 Subject: [PATCH 05/20] Add operation signatures sample --- packages/samples/signatures/main.cadl | 1 + packages/samples/signatures/signatures.cadl | 24 ++++++ .../test/output/signatures/openapi.json | 79 +++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 packages/samples/signatures/main.cadl create mode 100644 packages/samples/signatures/signatures.cadl create mode 100644 packages/samples/test/output/signatures/openapi.json diff --git a/packages/samples/signatures/main.cadl b/packages/samples/signatures/main.cadl new file mode 100644 index 0000000000..96ca9b4e07 --- /dev/null +++ b/packages/samples/signatures/main.cadl @@ -0,0 +1 @@ +import "./signatures.cadl"; diff --git a/packages/samples/signatures/signatures.cadl b/packages/samples/signatures/signatures.cadl new file mode 100644 index 0000000000..9fc4406790 --- /dev/null +++ b/packages/samples/signatures/signatures.cadl @@ -0,0 +1,24 @@ +import "@cadl-lang/rest"; + +using Cadl.Http; + +@error +model ErrorDetails { + code: int32; + message: string; +} + +model CodeSignAccount { + name: string; +} + +@get +op ResourceReadBase(@path name: string): TResource | TError; + +@doc("Reads an instance of the {name} resource.", T) +op ResourceRead: ResourceReadBase; + +@route("codeSignAccounts") +interface CodeSignAccounts { + get: ResourceRead; +} diff --git a/packages/samples/test/output/signatures/openapi.json b/packages/samples/test/output/signatures/openapi.json new file mode 100644 index 0000000000..60bf727ed3 --- /dev/null +++ b/packages/samples/test/output/signatures/openapi.json @@ -0,0 +1,79 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "(title)", + "version": "0000-00-00" + }, + "tags": [], + "paths": { + "/codeSignAccounts/{name}": { + "get": { + "operationId": "CodeSignAccounts_get", + "description": "Reads an instance of the CodeSignAccount resource.", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CodeSignAccount" + } + } + } + }, + "default": { + "description": "An unexpected error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDetails" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "CodeSignAccount": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "ErrorDetails": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + }, + "required": [ + "code", + "message" + ] + } + } + } +} From 4fa104cb0077bb950d1ac2e12bdec6c49fa13b6a Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 16:18:05 +0300 Subject: [PATCH 06/20] Fix formatter output for templated operation references --- packages/compiler/formatter/print/printer.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/compiler/formatter/print/printer.ts b/packages/compiler/formatter/print/printer.ts index 125970a88c..7b74af2d98 100644 --- a/packages/compiler/formatter/print/printer.ts +++ b/packages/compiler/formatter/print/printer.ts @@ -863,6 +863,7 @@ export function printOperationStatement( print: PrettierChildPrint ) { const inInterface = (path.getParentNode()?.kind as any) === SyntaxKind.InterfaceStatement; + const templateParams = printTemplateParameters(path, options, print, "templateParameters"); const { decorators } = printDecorators(path as AstPath, options, print, { tryInline: true, }); @@ -873,6 +874,7 @@ export function printOperationStatement( decorators, inInterface ? "" : "op ", path.call(print, "id"), + templateParams, "(", path.call(print, "signature", "parameters"), "): ", @@ -884,6 +886,8 @@ export function printOperationStatement( decorators, inInterface ? "" : "op ", path.call(print, "id"), + templateParams, + ": ", path.call(print, "signature", "baseOperation"), `;`, ]; From 539e4fe7fa7a0eefb53be43d9be0f39ca223517c Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 16:27:26 +0300 Subject: [PATCH 07/20] Create a scope for operation statements to bind template parameters --- packages/compiler/core/binder.ts | 2 ++ packages/compiler/test/checker/operations.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/compiler/core/binder.ts b/packages/compiler/core/binder.ts index 3d127993bf..80e10bce88 100644 --- a/packages/compiler/core/binder.ts +++ b/packages/compiler/core/binder.ts @@ -389,6 +389,7 @@ export function createBinder(program: Program, options: BinderOptions = {}): Bin function bindOperationStatement(statement: OperationStatementNode) { if (scope.kind !== SyntaxKind.InterfaceStatement) { declareSymbol(statement, SymbolFlags.Operation); + statement.locals = new SymbolTable(); } } @@ -451,6 +452,7 @@ function hasScope(node: Node): node is ScopeNode { case SyntaxKind.AliasStatement: case SyntaxKind.CadlScript: case SyntaxKind.InterfaceStatement: + case SyntaxKind.OperationStatement: case SyntaxKind.UnionStatement: case SyntaxKind.Projection: case SyntaxKind.ProjectionLambdaExpression: diff --git a/packages/compiler/test/checker/operations.ts b/packages/compiler/test/checker/operations.ts index a5bf9af81e..2426b7e8fb 100644 --- a/packages/compiler/test/checker/operations.ts +++ b/packages/compiler/test/checker/operations.ts @@ -48,7 +48,7 @@ describe("cadl: operations", () => { testHost.addCadlFile( "main.cadl", `op foo(name: TName, payload: TPayload): boolean; - op newFooBase: foo; + op newFooBase: foo; @test op newFoo: newFooBase;` @@ -118,7 +118,7 @@ describe("cadl: operations", () => { op foo(name: TName, payload: TPayload): boolean; @beta - op newFooBase: foo; + op newFooBase: foo; @test @kappa From 2f3dc0b1145cb3390a2608d8591b20dc23320d5e Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 16:28:24 +0300 Subject: [PATCH 08/20] Add another operation signature to the signatures sample --- packages/samples/signatures/signatures.cadl | 9 ++++- .../test/output/signatures/openapi.json | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/packages/samples/signatures/signatures.cadl b/packages/samples/signatures/signatures.cadl index 9fc4406790..646d934f15 100644 --- a/packages/samples/signatures/signatures.cadl +++ b/packages/samples/signatures/signatures.cadl @@ -13,12 +13,17 @@ model CodeSignAccount { } @get +@doc("Reads an instance of the {name} resource.", TResource) op ResourceReadBase(@path name: string): TResource | TError; +op ResourceRead: ResourceReadBase; -@doc("Reads an instance of the {name} resource.", T) -op ResourceRead: ResourceReadBase; +@post +@doc("Reads an instance of the {name} resource.", TResource) +op ResourceCreateBase(@body resource: TResource): TResource | TError; +op ResourceCreate: ResourceCreateBase; @route("codeSignAccounts") interface CodeSignAccounts { get: ResourceRead; + create: ResourceCreate; } diff --git a/packages/samples/test/output/signatures/openapi.json b/packages/samples/test/output/signatures/openapi.json index 60bf727ed3..4fa8fa41cb 100644 --- a/packages/samples/test/output/signatures/openapi.json +++ b/packages/samples/test/output/signatures/openapi.json @@ -43,6 +43,44 @@ } } } + }, + "/codeSignAccounts": { + "post": { + "operationId": "CodeSignAccounts_create", + "description": "Reads an instance of the CodeSignAccount resource.", + "parameters": [], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CodeSignAccount" + } + } + } + }, + "default": { + "description": "An unexpected error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDetails" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CodeSignAccount" + } + } + } + } + } } }, "components": { From c7e9ed62a5b0c2eade70c21510a05a217af5d151 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 17:14:06 +0300 Subject: [PATCH 09/20] Add an example of operation signatures used in a templated interface --- packages/samples/signatures/signatures.cadl | 13 +++ .../test/output/signatures/openapi.json | 88 +++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/packages/samples/signatures/signatures.cadl b/packages/samples/signatures/signatures.cadl index 646d934f15..9a40605a67 100644 --- a/packages/samples/signatures/signatures.cadl +++ b/packages/samples/signatures/signatures.cadl @@ -12,6 +12,10 @@ model CodeSignAccount { name: string; } +model AccountProfile { + value: int32; +} + @get @doc("Reads an instance of the {name} resource.", TResource) op ResourceReadBase(@path name: string): TResource | TError; @@ -27,3 +31,12 @@ interface CodeSignAccounts { get: ResourceRead; create: ResourceCreate; } + +interface ResourceOperations { + get: ResourceRead; + create: ResourceCreate; +} + +@route("accountProfiles") +interface AccountProfiles extends ResourceOperations { +} diff --git a/packages/samples/test/output/signatures/openapi.json b/packages/samples/test/output/signatures/openapi.json index 4fa8fa41cb..1fa73d844f 100644 --- a/packages/samples/test/output/signatures/openapi.json +++ b/packages/samples/test/output/signatures/openapi.json @@ -81,6 +81,82 @@ } } } + }, + "/accountProfiles/{name}": { + "get": { + "operationId": "AccountProfiles_get", + "description": "Reads an instance of the AccountProfile resource.", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountProfile" + } + } + } + }, + "default": { + "description": "An unexpected error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDetails" + } + } + } + } + } + } + }, + "/accountProfiles": { + "post": { + "operationId": "AccountProfiles_create", + "description": "Reads an instance of the AccountProfile resource.", + "parameters": [], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountProfile" + } + } + } + }, + "default": { + "description": "An unexpected error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDetails" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountProfile" + } + } + } + } + } } }, "components": { @@ -111,6 +187,18 @@ "code", "message" ] + }, + "AccountProfile": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "value" + ] } } } From 868ce0c04711cd399307bdf500842c27f19dd175 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 17:22:42 +0300 Subject: [PATCH 10/20] Update language grammar specification for new syntax --- docs/spec.html | 310 +++++++++++++++++--------------- packages/spec/src/spec.emu.html | 14 +- 2 files changed, 177 insertions(+), 147 deletions(-) diff --git a/docs/spec.html b/docs/spec.html index 3d2273749c..1ac2b95b0d 100644 --- a/docs/spec.html +++ b/docs/spec.html @@ -1255,7 +1255,7 @@ }); let sdoMap = JSON.parse(`{}`); -let biblio = JSON.parse(`{"refsByClause":{"lexical-grammar":["_ref_0","_ref_1","_ref_2","_ref_3","_ref_4","_ref_5","_ref_6","_ref_7","_ref_8","_ref_9","_ref_10","_ref_11","_ref_12","_ref_13","_ref_14","_ref_15","_ref_16","_ref_17","_ref_18","_ref_19","_ref_20","_ref_21","_ref_22","_ref_23","_ref_24","_ref_25","_ref_26","_ref_27","_ref_28","_ref_29","_ref_30","_ref_31","_ref_32","_ref_33","_ref_34","_ref_35","_ref_36","_ref_37","_ref_38","_ref_39","_ref_40","_ref_41","_ref_42","_ref_43","_ref_44","_ref_45","_ref_46","_ref_47","_ref_48","_ref_49","_ref_50","_ref_51","_ref_52","_ref_53","_ref_54","_ref_55","_ref_56","_ref_57","_ref_58","_ref_59","_ref_60","_ref_61","_ref_62","_ref_63","_ref_64","_ref_65","_ref_66","_ref_67","_ref_68","_ref_69"],"syntactic-grammar":["_ref_70","_ref_71","_ref_72","_ref_73","_ref_74","_ref_75","_ref_76","_ref_77","_ref_78","_ref_79","_ref_80","_ref_81","_ref_82","_ref_83","_ref_84","_ref_85","_ref_86","_ref_87","_ref_88","_ref_89","_ref_90","_ref_91","_ref_92","_ref_93","_ref_94","_ref_95","_ref_96","_ref_97","_ref_98","_ref_99","_ref_100","_ref_101","_ref_102","_ref_103","_ref_104","_ref_105","_ref_106","_ref_107","_ref_108","_ref_109","_ref_110","_ref_111","_ref_112","_ref_113","_ref_114","_ref_115","_ref_116","_ref_117","_ref_118","_ref_119","_ref_120","_ref_121","_ref_122","_ref_123","_ref_124","_ref_125","_ref_126","_ref_127","_ref_128","_ref_129","_ref_130","_ref_131","_ref_132","_ref_133","_ref_134","_ref_135","_ref_136","_ref_137","_ref_138","_ref_139","_ref_140","_ref_141","_ref_142","_ref_143","_ref_144","_ref_145","_ref_146","_ref_147","_ref_148","_ref_149","_ref_150","_ref_151","_ref_152","_ref_153","_ref_154","_ref_155","_ref_156","_ref_157","_ref_158","_ref_159","_ref_160","_ref_161","_ref_162","_ref_163","_ref_164","_ref_165","_ref_166","_ref_167","_ref_168","_ref_169","_ref_170","_ref_171","_ref_172","_ref_173","_ref_174","_ref_175","_ref_176","_ref_177","_ref_178","_ref_179","_ref_180","_ref_181","_ref_182","_ref_183","_ref_184","_ref_185","_ref_186","_ref_187","_ref_188","_ref_189","_ref_190","_ref_191","_ref_192","_ref_193","_ref_194","_ref_195","_ref_196","_ref_197","_ref_198","_ref_199","_ref_200","_ref_201","_ref_202","_ref_203","_ref_204","_ref_205","_ref_206","_ref_207","_ref_208","_ref_209","_ref_210","_ref_211","_ref_212","_ref_213","_ref_214","_ref_215","_ref_216","_ref_217","_ref_218","_ref_219","_ref_220","_ref_221","_ref_222","_ref_223","_ref_224","_ref_225","_ref_226","_ref_227","_ref_228","_ref_229","_ref_230","_ref_231","_ref_232","_ref_233","_ref_234","_ref_235","_ref_236","_ref_237","_ref_238","_ref_239","_ref_240","_ref_241","_ref_242","_ref_243","_ref_244","_ref_245","_ref_246","_ref_247","_ref_248","_ref_249","_ref_250","_ref_251","_ref_252","_ref_253","_ref_254","_ref_255","_ref_256","_ref_257","_ref_258","_ref_259","_ref_260","_ref_261","_ref_262","_ref_263","_ref_264","_ref_265","_ref_266","_ref_267","_ref_268","_ref_269","_ref_270","_ref_271","_ref_272","_ref_273","_ref_274","_ref_275","_ref_276","_ref_277","_ref_278","_ref_279","_ref_280","_ref_281","_ref_282","_ref_283","_ref_284","_ref_285","_ref_286","_ref_287","_ref_288","_ref_289","_ref_290","_ref_291","_ref_292","_ref_293","_ref_294","_ref_295","_ref_296","_ref_297","_ref_298","_ref_299","_ref_300","_ref_301","_ref_302","_ref_303","_ref_304","_ref_305"]},"entries":[{"type":"clause","id":"intro","titleHTML":"Introduction","number":""},{"type":"production","id":"prod-SourceCharacter","name":"SourceCharacter","referencingIds":["_ref_49","_ref_53","_ref_64","_ref_65","_ref_69"]},{"type":"production","id":"prod-InputElement","name":"InputElement"},{"type":"production","id":"prod-Token","name":"Token","referencingIds":["_ref_0"]},{"type":"production","id":"prod-Trivia","name":"Trivia","referencingIds":["_ref_1"]},{"type":"production","id":"prod-Keyword","name":"Keyword","referencingIds":["_ref_2","_ref_11"]},{"type":"production","id":"prod-Identifier","name":"Identifier","referencingIds":["_ref_3","_ref_89","_ref_103","_ref_109","_ref_116","_ref_120","_ref_127","_ref_133","_ref_143","_ref_150","_ref_156","_ref_159","_ref_161","_ref_166","_ref_191","_ref_193","_ref_213","_ref_258","_ref_260","_ref_266","_ref_268","_ref_269","_ref_295"]},{"type":"production","id":"prod-IdentifierName","name":"IdentifierName","referencingIds":["_ref_10","_ref_13"]},{"type":"production","id":"prod-IdentifierStart","name":"IdentifierStart","referencingIds":["_ref_12"]},{"type":"production","id":"prod-IdentifierContinue","name":"IdentifierContinue","referencingIds":["_ref_14","_ref_15"]},{"type":"production","id":"prod-AsciiLetter","name":"AsciiLetter","referencingIds":["_ref_17"]},{"type":"production","id":"prod-BooleanLiteral","name":"BooleanLiteral","referencingIds":["_ref_9","_ref_184"]},{"type":"production","id":"prod-NumericLiteral","name":"NumericLiteral","referencingIds":["_ref_4","_ref_149","_ref_185"]},{"type":"production","id":"prod-DecimalLiteral","name":"DecimalLiteral","referencingIds":["_ref_19"]},{"type":"production","id":"prod-DecimalIntegerLiteral","name":"DecimalIntegerLiteral","referencingIds":["_ref_22","_ref_25","_ref_33"]},{"type":"production","id":"prod-DecimalDigits","name":"DecimalDigits","referencingIds":["_ref_23","_ref_27","_ref_28","_ref_29","_ref_31","_ref_34","_ref_35","_ref_36"]},{"type":"production","id":"prod-DecimalDigit","name":"DecimalDigit","referencingIds":["_ref_16","_ref_18","_ref_30","_ref_32"]},{"type":"production","id":"prod-ExponentPart","name":"ExponentPart","referencingIds":["_ref_24","_ref_26"]},{"type":"production","id":"prod-DecimalIntegerInteger","name":"DecimalIntegerInteger"},{"type":"production","id":"prod-HexIntegerLiteral","name":"HexIntegerLiteral","referencingIds":["_ref_20"]},{"type":"production","id":"prod-HexDigits","name":"HexDigits","referencingIds":["_ref_37","_ref_39"]},{"type":"production","id":"prod-HexDigit","name":"HexDigit","referencingIds":["_ref_38","_ref_40"]},{"type":"production","id":"prod-BinaryIntegerLiteral","name":"BinaryIntegerLiteral","referencingIds":["_ref_21"]},{"type":"production","id":"prod-BinaryDigits","name":"BinaryDigits","referencingIds":["_ref_41","_ref_43"]},{"type":"production","id":"prod-BinaryDigit","name":"BinaryDigit","referencingIds":["_ref_42","_ref_44"]},{"type":"production","id":"prod-StringLiteral","name":"StringLiteral","referencingIds":["_ref_5","_ref_77","_ref_106","_ref_130","_ref_146","_ref_148","_ref_183","_ref_298"]},{"type":"production","id":"prod-StringCharacters","name":"StringCharacters","referencingIds":["_ref_45","_ref_48"]},{"type":"production","id":"prod-StringCharacter","name":"StringCharacter","referencingIds":["_ref_47"]},{"type":"production","id":"prod-TripleQuotedStringCharacters","name":"TripleQuotedStringCharacters","referencingIds":["_ref_46","_ref_52"]},{"type":"production","id":"prod-TripleQuotedStringCharacter","name":"TripleQuotedStringCharacter","referencingIds":["_ref_51"]},{"type":"production","id":"prod-EscapeCharacter","name":"EscapeCharacter","referencingIds":["_ref_50","_ref_54"]},{"type":"production","id":"prod-Punctuator","name":"Punctuator","referencingIds":["_ref_6"]},{"type":"production","id":"prod-WhiteSpace","name":"WhiteSpace","referencingIds":["_ref_8"]},{"type":"production","id":"prod-Comment","name":"Comment","referencingIds":["_ref_7"]},{"type":"production","id":"prod-MultiLineComment","name":"MultiLineComment","referencingIds":["_ref_55"]},{"type":"production","id":"prod-MultiLineCommentChars","name":"MultiLineCommentChars","referencingIds":["_ref_57","_ref_59","_ref_62"]},{"type":"production","id":"prod-PostAsteriskCommentChars","name":"PostAsteriskCommentChars","referencingIds":["_ref_60","_ref_63"]},{"type":"production","id":"prod-MultiLineNotAsteriskChar","name":"MultiLineNotAsteriskChar","referencingIds":["_ref_58"]},{"type":"production","id":"prod-MultiLineNotForwardSlashOrAsteriskChar","name":"MultiLineNotForwardSlashOrAsteriskChar","referencingIds":["_ref_61"]},{"type":"production","id":"prod-SingleLineComment","name":"SingleLineComment","referencingIds":["_ref_56"]},{"type":"production","id":"prod-SingleLineCommentChars","name":"SingleLineCommentChars","referencingIds":["_ref_66","_ref_68"]},{"type":"production","id":"prod-SingleLineCommentChar","name":"SingleLineCommentChar","referencingIds":["_ref_67"]},{"type":"clause","id":"lexical-grammar","titleHTML":"Lexical Grammar","number":"1"},{"type":"production","id":"prod-CadlScriptItemList","name":"CadlScriptItemList","referencingIds":["_ref_70"]},{"type":"production","id":"prod-CadlScriptItem","name":"CadlScriptItem","referencingIds":["_ref_71"]},{"type":"production","id":"prod-BlocklessNamespaceStatement","name":"BlocklessNamespaceStatement","referencingIds":["_ref_72"]},{"type":"production","id":"prod-ImportStatement","name":"ImportStatement","referencingIds":["_ref_73"]},{"type":"production","id":"prod-StatementList","name":"StatementList","referencingIds":["_ref_78","_ref_164"]},{"type":"production","id":"prod-Statement","name":"Statement","referencingIds":["_ref_74","_ref_79"]},{"type":"production","id":"prod-UsingStatement","name":"UsingStatement","referencingIds":["_ref_84"]},{"type":"production","id":"prod-ModelStatement","name":"ModelStatement","referencingIds":["_ref_80"]},{"type":"production","id":"prod-ModelHeritage","name":"ModelHeritage","referencingIds":["_ref_90"]},{"type":"production","id":"prod-ModelBody","name":"ModelBody","referencingIds":["_ref_91","_ref_197"]},{"type":"production","id":"prod-ModelPropertyList","name":"ModelPropertyList","referencingIds":["_ref_94","_ref_95","_ref_97","_ref_99","_ref_117","_ref_167"]},{"type":"production","id":"prod-ModelProperty","name":"ModelProperty","referencingIds":["_ref_96","_ref_98","_ref_100"]},{"type":"production","id":"prod-ModelSpreadProperty","name":"ModelSpreadProperty","referencingIds":["_ref_101"]},{"type":"production","id":"prod-InterfaceStatement","name":"InterfaceStatement","referencingIds":["_ref_81"]},{"type":"production","id":"prod-InterfaceHeritage","name":"InterfaceHeritage","referencingIds":["_ref_110"]},{"type":"production","id":"prod-InterfaceMemberList","name":"InterfaceMemberList","referencingIds":["_ref_112","_ref_114"]},{"type":"production","id":"prod-InterfaceMember","name":"InterfaceMember","referencingIds":["_ref_113","_ref_115"]},{"type":"production","id":"prod-UnionStatement","name":"UnionStatement"},{"type":"production","id":"prod-UnionBody","name":"UnionBody","referencingIds":["_ref_121"]},{"type":"production","id":"prod-UnionVariantList","name":"UnionVariantList","referencingIds":["_ref_122","_ref_124"]},{"type":"production","id":"prod-UnionVariant","name":"UnionVariant","referencingIds":["_ref_123","_ref_125"]},{"type":"production","id":"prod-EnumStatement","name":"EnumStatement","referencingIds":["_ref_85"]},{"type":"production","id":"prod-EnumBody","name":"EnumBody","referencingIds":["_ref_134"]},{"type":"production","id":"prod-EnumMemberList","name":"EnumMemberList","referencingIds":["_ref_135","_ref_136","_ref_138","_ref_140"]},{"type":"production","id":"prod-EnumMember","name":"EnumMember","referencingIds":["_ref_137","_ref_139","_ref_141"]},{"type":"production","id":"prod-EnumMemberValue","name":"EnumMemberValue","referencingIds":["_ref_144","_ref_147"]},{"type":"production","id":"prod-AliasStatement","name":"AliasStatement","referencingIds":["_ref_86"]},{"type":"production","id":"prod-TemplateParameterList","name":"TemplateParameterList","referencingIds":["_ref_152","_ref_154"]},{"type":"production","id":"prod-TemplateParameter","name":"TemplateParameter","referencingIds":["_ref_153","_ref_155"]},{"type":"production","id":"prod-TemplateParameterDefault","name":"TemplateParameterDefault","referencingIds":["_ref_157"]},{"type":"production","id":"prod-IdentifierList","name":"IdentifierList","referencingIds":["_ref_160","_ref_214","_ref_305"]},{"type":"production","id":"prod-NamespaceStatement","name":"NamespaceStatement","referencingIds":["_ref_82"]},{"type":"production","id":"prod-OperationStatement","name":"OperationStatement","referencingIds":["_ref_83"]},{"type":"production","id":"prod-Expression","name":"Expression","referencingIds":["_ref_104","_ref_107","_ref_118","_ref_128","_ref_131","_ref_151","_ref_158","_ref_168","_ref_196","_ref_199","_ref_201"]},{"type":"production","id":"prod-UnionExpressionOrHigher","name":"UnionExpressionOrHigher","referencingIds":["_ref_169","_ref_171"]},{"type":"production","id":"prod-IntersectionExpressionOrHigher","name":"IntersectionExpressionOrHigher","referencingIds":["_ref_170","_ref_172","_ref_174"]},{"type":"production","id":"prod-ArrayExpressionOrHigher","name":"ArrayExpressionOrHigher","referencingIds":["_ref_173","_ref_175","_ref_177"]},{"type":"production","id":"prod-PrimaryExpression","name":"PrimaryExpression","referencingIds":["_ref_176"]},{"type":"production","id":"prod-Literal","name":"Literal","referencingIds":["_ref_178","_ref_272"]},{"type":"production","id":"prod-ReferenceExpression","name":"ReferenceExpression","referencingIds":["_ref_92","_ref_93","_ref_108","_ref_179","_ref_188","_ref_190","_ref_212"]},{"type":"production","id":"prod-ReferenceExpressionList","name":"ReferenceExpressionList","referencingIds":["_ref_111","_ref_189"]},{"type":"production","id":"prod-IdentifierOrMemberExpression","name":"IdentifierOrMemberExpression","referencingIds":["_ref_76","_ref_87","_ref_163","_ref_186","_ref_192","_ref_204","_ref_263"]},{"type":"production","id":"prod-TemplateArguments","name":"TemplateArguments","referencingIds":["_ref_187"]},{"type":"production","id":"prod-ProjectionArguments","name":"ProjectionArguments"},{"type":"production","id":"prod-ParenthesizedExpression","name":"ParenthesizedExpression","referencingIds":["_ref_180"]},{"type":"production","id":"prod-ModelExpression","name":"ModelExpression","referencingIds":["_ref_181"]},{"type":"production","id":"prod-TupleExpression","name":"TupleExpression","referencingIds":["_ref_182"]},{"type":"production","id":"prod-ExpressionList","name":"ExpressionList","referencingIds":["_ref_194","_ref_195","_ref_198","_ref_200","_ref_206"]},{"type":"production","id":"prod-DecoratorList","name":"DecoratorList","referencingIds":["_ref_75","_ref_88","_ref_102","_ref_105","_ref_119","_ref_126","_ref_129","_ref_132","_ref_142","_ref_145","_ref_162","_ref_165","_ref_202","_ref_294","_ref_297"]},{"type":"production","id":"prod-Decorator","name":"Decorator","referencingIds":["_ref_203"]},{"type":"production","id":"prod-DecoratorArguments","name":"DecoratorArguments","referencingIds":["_ref_205"]},{"type":"production","id":"prod-ProjectionStatement","name":"ProjectionStatement"},{"type":"production","id":"prod-ProjectionSelector","name":"ProjectionSelector","referencingIds":["_ref_207"]},{"type":"production","id":"prod-ProjectionDirection","name":"ProjectionDirection","referencingIds":["_ref_208"]},{"type":"production","id":"prod-ProjectionTag","name":"ProjectionTag","referencingIds":["_ref_209"]},{"type":"production","id":"prod-ProjectionParameters","name":"ProjectionParameters","referencingIds":["_ref_210"]},{"type":"production","id":"prod-ProjectionBody","name":"ProjectionBody","referencingIds":["_ref_211"]},{"type":"production","id":"prod-ProjectionStatementList","name":"ProjectionStatementList","referencingIds":["_ref_215","_ref_217"]},{"type":"production","id":"prod-ProjectionStatementItem","name":"ProjectionStatementItem","referencingIds":["_ref_216","_ref_218"]},{"type":"production","id":"prod-ProjectionExpression","name":"ProjectionExpression","referencingIds":["_ref_221","_ref_277","_ref_279","_ref_280","_ref_281","_ref_283","_ref_296","_ref_299","_ref_300"]},{"type":"production","id":"prod-ProjectionReturnExpression","name":"ProjectionReturnExpression","referencingIds":["_ref_219"]},{"type":"production","id":"prod-ProjectionLogicalOrExpression","name":"ProjectionLogicalOrExpression","referencingIds":["_ref_220","_ref_223"]},{"type":"production","id":"prod-ProjectionLogicalAndExpression","name":"ProjectionLogicalAndExpression","referencingIds":["_ref_222","_ref_224","_ref_226"]},{"type":"production","id":"prod-ProjectionEqualityExpression","name":"ProjectionEqualityExpression","referencingIds":["_ref_229","_ref_231"]},{"type":"production","id":"prod-ProjectionRelationalExpression","name":"ProjectionRelationalExpression","referencingIds":["_ref_225","_ref_227","_ref_228","_ref_230","_ref_232","_ref_234","_ref_236","_ref_238","_ref_240"]},{"type":"production","id":"prod-ProjectionAdditiveExpression","name":"ProjectionAdditiveExpression","referencingIds":["_ref_233","_ref_235","_ref_237","_ref_239","_ref_241","_ref_243","_ref_245"]},{"type":"production","id":"prod-ProjectionMultiplicativeExpression","name":"ProjectionMultiplicativeExpression","referencingIds":["_ref_242","_ref_244","_ref_246","_ref_248","_ref_250"]},{"type":"production","id":"prod-ProjectionUnaryExpression","name":"ProjectionUnaryExpression","referencingIds":["_ref_247","_ref_249","_ref_251","_ref_253"]},{"type":"production","id":"prod-ProjectionCallExpression","name":"ProjectionCallExpression","referencingIds":["_ref_252","_ref_255","_ref_257","_ref_259"]},{"type":"production","id":"prod-ProjectionCallArguments","name":"ProjectionCallArguments","referencingIds":["_ref_256"]},{"type":"production","id":"prod-ProjectionDecoratorReferenceExpression","name":"ProjectionDecoratorReferenceExpression","referencingIds":["_ref_254"]},{"type":"production","id":"prod-ProjectionMemberExpression","name":"ProjectionMemberExpression","referencingIds":["_ref_262","_ref_265","_ref_267"]},{"type":"production","id":"prod-ProjectionPrimaryExpression","name":"ProjectionPrimaryExpression","referencingIds":["_ref_264"]},{"type":"production","id":"prod-CoverProjectionParenthesizedExpressionAndLambdaParameterList","name":"CoverProjectionParenthesizedExpressionAndLambdaParameterList","referencingIds":["_ref_275","_ref_302"]},{"type":"production","id":"prod-ProjectionExpressionList","name":"ProjectionExpressionList","referencingIds":["_ref_261","_ref_276","_ref_278","_ref_301","_ref_304"]},{"type":"production","id":"prod-ProjectionIfExpression","name":"ProjectionIfExpression","referencingIds":["_ref_270","_ref_284"]},{"type":"production","id":"prod-ProjectionModelExpression","name":"ProjectionModelExpression","referencingIds":["_ref_273"]},{"type":"production","id":"prod-ProjectionModelBody","name":"ProjectionModelBody","referencingIds":["_ref_285"]},{"type":"production","id":"prod-ProjectionModelPropertyList","name":"ProjectionModelPropertyList","referencingIds":["_ref_286","_ref_287","_ref_289","_ref_291"]},{"type":"production","id":"prod-ProjectionModelProperty","name":"ProjectionModelProperty","referencingIds":["_ref_288","_ref_290","_ref_292"]},{"type":"production","id":"prod-ProjectionModelSpreadProperty","name":"ProjectionModelSpreadProperty","referencingIds":["_ref_293"]},{"type":"production","id":"prod-ProjectionTupleExpression","name":"ProjectionTupleExpression","referencingIds":["_ref_274"]},{"type":"production","id":"prod-ProjectionLambdaExpression","name":"ProjectionLambdaExpression","referencingIds":["_ref_271"]},{"type":"production","id":"prod-ProjectionBlockExpression","name":"ProjectionBlockExpression","referencingIds":["_ref_282","_ref_303"]},{"type":"production","id":"prod-LambdaParameters","name":"LambdaParameters"},{"type":"clause","id":"syntactic-grammar","titleHTML":"Syntactic Grammar","number":"2"}]}`); +let biblio = JSON.parse(`{"refsByClause":{"lexical-grammar":["_ref_0","_ref_1","_ref_2","_ref_3","_ref_4","_ref_5","_ref_6","_ref_7","_ref_8","_ref_9","_ref_10","_ref_11","_ref_12","_ref_13","_ref_14","_ref_15","_ref_16","_ref_17","_ref_18","_ref_19","_ref_20","_ref_21","_ref_22","_ref_23","_ref_24","_ref_25","_ref_26","_ref_27","_ref_28","_ref_29","_ref_30","_ref_31","_ref_32","_ref_33","_ref_34","_ref_35","_ref_36","_ref_37","_ref_38","_ref_39","_ref_40","_ref_41","_ref_42","_ref_43","_ref_44","_ref_45","_ref_46","_ref_47","_ref_48","_ref_49","_ref_50","_ref_51","_ref_52","_ref_53","_ref_54","_ref_55","_ref_56","_ref_57","_ref_58","_ref_59","_ref_60","_ref_61","_ref_62","_ref_63","_ref_64","_ref_65","_ref_66","_ref_67","_ref_68","_ref_69"],"syntactic-grammar":["_ref_70","_ref_71","_ref_72","_ref_73","_ref_74","_ref_75","_ref_76","_ref_77","_ref_78","_ref_79","_ref_80","_ref_81","_ref_82","_ref_83","_ref_84","_ref_85","_ref_86","_ref_87","_ref_88","_ref_89","_ref_90","_ref_91","_ref_92","_ref_93","_ref_94","_ref_95","_ref_96","_ref_97","_ref_98","_ref_99","_ref_100","_ref_101","_ref_102","_ref_103","_ref_104","_ref_105","_ref_106","_ref_107","_ref_108","_ref_109","_ref_110","_ref_111","_ref_112","_ref_113","_ref_114","_ref_115","_ref_116","_ref_117","_ref_118","_ref_119","_ref_120","_ref_121","_ref_122","_ref_123","_ref_124","_ref_125","_ref_126","_ref_127","_ref_128","_ref_129","_ref_130","_ref_131","_ref_132","_ref_133","_ref_134","_ref_135","_ref_136","_ref_137","_ref_138","_ref_139","_ref_140","_ref_141","_ref_142","_ref_143","_ref_144","_ref_145","_ref_146","_ref_147","_ref_148","_ref_149","_ref_150","_ref_151","_ref_152","_ref_153","_ref_154","_ref_155","_ref_156","_ref_157","_ref_158","_ref_159","_ref_160","_ref_161","_ref_162","_ref_163","_ref_164","_ref_165","_ref_166","_ref_167","_ref_168","_ref_169","_ref_170","_ref_171","_ref_172","_ref_173","_ref_174","_ref_175","_ref_176","_ref_177","_ref_178","_ref_179","_ref_180","_ref_181","_ref_182","_ref_183","_ref_184","_ref_185","_ref_186","_ref_187","_ref_188","_ref_189","_ref_190","_ref_191","_ref_192","_ref_193","_ref_194","_ref_195","_ref_196","_ref_197","_ref_198","_ref_199","_ref_200","_ref_201","_ref_202","_ref_203","_ref_204","_ref_205","_ref_206","_ref_207","_ref_208","_ref_209","_ref_210","_ref_211","_ref_212","_ref_213","_ref_214","_ref_215","_ref_216","_ref_217","_ref_218","_ref_219","_ref_220","_ref_221","_ref_222","_ref_223","_ref_224","_ref_225","_ref_226","_ref_227","_ref_228","_ref_229","_ref_230","_ref_231","_ref_232","_ref_233","_ref_234","_ref_235","_ref_236","_ref_237","_ref_238","_ref_239","_ref_240","_ref_241","_ref_242","_ref_243","_ref_244","_ref_245","_ref_246","_ref_247","_ref_248","_ref_249","_ref_250","_ref_251","_ref_252","_ref_253","_ref_254","_ref_255","_ref_256","_ref_257","_ref_258","_ref_259","_ref_260","_ref_261","_ref_262","_ref_263","_ref_264","_ref_265","_ref_266","_ref_267","_ref_268","_ref_269","_ref_270","_ref_271","_ref_272","_ref_273","_ref_274","_ref_275","_ref_276","_ref_277","_ref_278","_ref_279","_ref_280","_ref_281","_ref_282","_ref_283","_ref_284","_ref_285","_ref_286","_ref_287","_ref_288","_ref_289","_ref_290","_ref_291","_ref_292","_ref_293","_ref_294","_ref_295","_ref_296","_ref_297","_ref_298","_ref_299","_ref_300","_ref_301","_ref_302","_ref_303","_ref_304","_ref_305","_ref_306","_ref_307","_ref_308","_ref_309","_ref_310"]},"entries":[{"type":"clause","id":"intro","titleHTML":"Introduction","number":""},{"type":"production","id":"prod-SourceCharacter","name":"SourceCharacter","referencingIds":["_ref_49","_ref_53","_ref_64","_ref_65","_ref_69"]},{"type":"production","id":"prod-InputElement","name":"InputElement"},{"type":"production","id":"prod-Token","name":"Token","referencingIds":["_ref_0"]},{"type":"production","id":"prod-Trivia","name":"Trivia","referencingIds":["_ref_1"]},{"type":"production","id":"prod-Keyword","name":"Keyword","referencingIds":["_ref_2","_ref_11"]},{"type":"production","id":"prod-Identifier","name":"Identifier","referencingIds":["_ref_3","_ref_89","_ref_103","_ref_109","_ref_116","_ref_120","_ref_127","_ref_133","_ref_143","_ref_150","_ref_156","_ref_159","_ref_161","_ref_171","_ref_196","_ref_198","_ref_218","_ref_263","_ref_265","_ref_271","_ref_273","_ref_274","_ref_300"]},{"type":"production","id":"prod-IdentifierName","name":"IdentifierName","referencingIds":["_ref_10","_ref_13"]},{"type":"production","id":"prod-IdentifierStart","name":"IdentifierStart","referencingIds":["_ref_12"]},{"type":"production","id":"prod-IdentifierContinue","name":"IdentifierContinue","referencingIds":["_ref_14","_ref_15"]},{"type":"production","id":"prod-AsciiLetter","name":"AsciiLetter","referencingIds":["_ref_17"]},{"type":"production","id":"prod-BooleanLiteral","name":"BooleanLiteral","referencingIds":["_ref_9","_ref_189"]},{"type":"production","id":"prod-NumericLiteral","name":"NumericLiteral","referencingIds":["_ref_4","_ref_149","_ref_190"]},{"type":"production","id":"prod-DecimalLiteral","name":"DecimalLiteral","referencingIds":["_ref_19"]},{"type":"production","id":"prod-DecimalIntegerLiteral","name":"DecimalIntegerLiteral","referencingIds":["_ref_22","_ref_25","_ref_33"]},{"type":"production","id":"prod-DecimalDigits","name":"DecimalDigits","referencingIds":["_ref_23","_ref_27","_ref_28","_ref_29","_ref_31","_ref_34","_ref_35","_ref_36"]},{"type":"production","id":"prod-DecimalDigit","name":"DecimalDigit","referencingIds":["_ref_16","_ref_18","_ref_30","_ref_32"]},{"type":"production","id":"prod-ExponentPart","name":"ExponentPart","referencingIds":["_ref_24","_ref_26"]},{"type":"production","id":"prod-DecimalIntegerInteger","name":"DecimalIntegerInteger"},{"type":"production","id":"prod-HexIntegerLiteral","name":"HexIntegerLiteral","referencingIds":["_ref_20"]},{"type":"production","id":"prod-HexDigits","name":"HexDigits","referencingIds":["_ref_37","_ref_39"]},{"type":"production","id":"prod-HexDigit","name":"HexDigit","referencingIds":["_ref_38","_ref_40"]},{"type":"production","id":"prod-BinaryIntegerLiteral","name":"BinaryIntegerLiteral","referencingIds":["_ref_21"]},{"type":"production","id":"prod-BinaryDigits","name":"BinaryDigits","referencingIds":["_ref_41","_ref_43"]},{"type":"production","id":"prod-BinaryDigit","name":"BinaryDigit","referencingIds":["_ref_42","_ref_44"]},{"type":"production","id":"prod-StringLiteral","name":"StringLiteral","referencingIds":["_ref_5","_ref_77","_ref_106","_ref_130","_ref_146","_ref_148","_ref_188","_ref_303"]},{"type":"production","id":"prod-StringCharacters","name":"StringCharacters","referencingIds":["_ref_45","_ref_48"]},{"type":"production","id":"prod-StringCharacter","name":"StringCharacter","referencingIds":["_ref_47"]},{"type":"production","id":"prod-TripleQuotedStringCharacters","name":"TripleQuotedStringCharacters","referencingIds":["_ref_46","_ref_52"]},{"type":"production","id":"prod-TripleQuotedStringCharacter","name":"TripleQuotedStringCharacter","referencingIds":["_ref_51"]},{"type":"production","id":"prod-EscapeCharacter","name":"EscapeCharacter","referencingIds":["_ref_50","_ref_54"]},{"type":"production","id":"prod-Punctuator","name":"Punctuator","referencingIds":["_ref_6"]},{"type":"production","id":"prod-WhiteSpace","name":"WhiteSpace","referencingIds":["_ref_8"]},{"type":"production","id":"prod-Comment","name":"Comment","referencingIds":["_ref_7"]},{"type":"production","id":"prod-MultiLineComment","name":"MultiLineComment","referencingIds":["_ref_55"]},{"type":"production","id":"prod-MultiLineCommentChars","name":"MultiLineCommentChars","referencingIds":["_ref_57","_ref_59","_ref_62"]},{"type":"production","id":"prod-PostAsteriskCommentChars","name":"PostAsteriskCommentChars","referencingIds":["_ref_60","_ref_63"]},{"type":"production","id":"prod-MultiLineNotAsteriskChar","name":"MultiLineNotAsteriskChar","referencingIds":["_ref_58"]},{"type":"production","id":"prod-MultiLineNotForwardSlashOrAsteriskChar","name":"MultiLineNotForwardSlashOrAsteriskChar","referencingIds":["_ref_61"]},{"type":"production","id":"prod-SingleLineComment","name":"SingleLineComment","referencingIds":["_ref_56"]},{"type":"production","id":"prod-SingleLineCommentChars","name":"SingleLineCommentChars","referencingIds":["_ref_66","_ref_68"]},{"type":"production","id":"prod-SingleLineCommentChar","name":"SingleLineCommentChar","referencingIds":["_ref_67"]},{"type":"clause","id":"lexical-grammar","titleHTML":"Lexical Grammar","number":"1"},{"type":"production","id":"prod-CadlScriptItemList","name":"CadlScriptItemList","referencingIds":["_ref_70"]},{"type":"production","id":"prod-CadlScriptItem","name":"CadlScriptItem","referencingIds":["_ref_71"]},{"type":"production","id":"prod-BlocklessNamespaceStatement","name":"BlocklessNamespaceStatement","referencingIds":["_ref_72"]},{"type":"production","id":"prod-ImportStatement","name":"ImportStatement","referencingIds":["_ref_73"]},{"type":"production","id":"prod-StatementList","name":"StatementList","referencingIds":["_ref_78","_ref_164"]},{"type":"production","id":"prod-Statement","name":"Statement","referencingIds":["_ref_74","_ref_79"]},{"type":"production","id":"prod-UsingStatement","name":"UsingStatement","referencingIds":["_ref_84"]},{"type":"production","id":"prod-ModelStatement","name":"ModelStatement","referencingIds":["_ref_80"]},{"type":"production","id":"prod-ModelHeritage","name":"ModelHeritage","referencingIds":["_ref_90"]},{"type":"production","id":"prod-ModelBody","name":"ModelBody","referencingIds":["_ref_91","_ref_202"]},{"type":"production","id":"prod-ModelPropertyList","name":"ModelPropertyList","referencingIds":["_ref_94","_ref_95","_ref_97","_ref_99","_ref_117","_ref_165"]},{"type":"production","id":"prod-ModelProperty","name":"ModelProperty","referencingIds":["_ref_96","_ref_98","_ref_100"]},{"type":"production","id":"prod-ModelSpreadProperty","name":"ModelSpreadProperty","referencingIds":["_ref_101"]},{"type":"production","id":"prod-InterfaceStatement","name":"InterfaceStatement","referencingIds":["_ref_81"]},{"type":"production","id":"prod-InterfaceHeritage","name":"InterfaceHeritage","referencingIds":["_ref_110"]},{"type":"production","id":"prod-InterfaceMemberList","name":"InterfaceMemberList","referencingIds":["_ref_112","_ref_114"]},{"type":"production","id":"prod-InterfaceMember","name":"InterfaceMember","referencingIds":["_ref_113","_ref_115"]},{"type":"production","id":"prod-UnionStatement","name":"UnionStatement"},{"type":"production","id":"prod-UnionBody","name":"UnionBody","referencingIds":["_ref_121"]},{"type":"production","id":"prod-UnionVariantList","name":"UnionVariantList","referencingIds":["_ref_122","_ref_124"]},{"type":"production","id":"prod-UnionVariant","name":"UnionVariant","referencingIds":["_ref_123","_ref_125"]},{"type":"production","id":"prod-EnumStatement","name":"EnumStatement","referencingIds":["_ref_85"]},{"type":"production","id":"prod-EnumBody","name":"EnumBody","referencingIds":["_ref_134"]},{"type":"production","id":"prod-EnumMemberList","name":"EnumMemberList","referencingIds":["_ref_135","_ref_136","_ref_138","_ref_140"]},{"type":"production","id":"prod-EnumMember","name":"EnumMember","referencingIds":["_ref_137","_ref_139","_ref_141"]},{"type":"production","id":"prod-EnumMemberValue","name":"EnumMemberValue","referencingIds":["_ref_144","_ref_147"]},{"type":"production","id":"prod-AliasStatement","name":"AliasStatement","referencingIds":["_ref_86"]},{"type":"production","id":"prod-TemplateParameterList","name":"TemplateParameterList","referencingIds":["_ref_152","_ref_154"]},{"type":"production","id":"prod-TemplateParameter","name":"TemplateParameter","referencingIds":["_ref_153","_ref_155"]},{"type":"production","id":"prod-TemplateParameterDefault","name":"TemplateParameterDefault","referencingIds":["_ref_157"]},{"type":"production","id":"prod-IdentifierList","name":"IdentifierList","referencingIds":["_ref_160","_ref_219","_ref_310"]},{"type":"production","id":"prod-NamespaceStatement","name":"NamespaceStatement","referencingIds":["_ref_82"]},{"type":"production","id":"prod-OperationSignatureDeclaration","name":"OperationSignatureDeclaration","referencingIds":["_ref_168"]},{"type":"production","id":"prod-OperationSignatureReference","name":"OperationSignatureReference","referencingIds":["_ref_169"]},{"type":"production","id":"prod-OperationSignature","name":"OperationSignature","referencingIds":["_ref_173"]},{"type":"production","id":"prod-OperationStatement","name":"OperationStatement","referencingIds":["_ref_83"]},{"type":"production","id":"prod-Expression","name":"Expression","referencingIds":["_ref_104","_ref_107","_ref_118","_ref_128","_ref_131","_ref_151","_ref_158","_ref_166","_ref_201","_ref_204","_ref_206"]},{"type":"production","id":"prod-UnionExpressionOrHigher","name":"UnionExpressionOrHigher","referencingIds":["_ref_174","_ref_176"]},{"type":"production","id":"prod-IntersectionExpressionOrHigher","name":"IntersectionExpressionOrHigher","referencingIds":["_ref_175","_ref_177","_ref_179"]},{"type":"production","id":"prod-ArrayExpressionOrHigher","name":"ArrayExpressionOrHigher","referencingIds":["_ref_178","_ref_180","_ref_182"]},{"type":"production","id":"prod-PrimaryExpression","name":"PrimaryExpression","referencingIds":["_ref_181"]},{"type":"production","id":"prod-Literal","name":"Literal","referencingIds":["_ref_183","_ref_277"]},{"type":"production","id":"prod-ReferenceExpression","name":"ReferenceExpression","referencingIds":["_ref_92","_ref_93","_ref_108","_ref_167","_ref_184","_ref_193","_ref_195","_ref_217"]},{"type":"production","id":"prod-ReferenceExpressionList","name":"ReferenceExpressionList","referencingIds":["_ref_111","_ref_194"]},{"type":"production","id":"prod-IdentifierOrMemberExpression","name":"IdentifierOrMemberExpression","referencingIds":["_ref_76","_ref_87","_ref_163","_ref_191","_ref_197","_ref_209","_ref_268"]},{"type":"production","id":"prod-TemplateArguments","name":"TemplateArguments","referencingIds":["_ref_172","_ref_192"]},{"type":"production","id":"prod-ProjectionArguments","name":"ProjectionArguments"},{"type":"production","id":"prod-ParenthesizedExpression","name":"ParenthesizedExpression","referencingIds":["_ref_185"]},{"type":"production","id":"prod-ModelExpression","name":"ModelExpression","referencingIds":["_ref_186"]},{"type":"production","id":"prod-TupleExpression","name":"TupleExpression","referencingIds":["_ref_187"]},{"type":"production","id":"prod-ExpressionList","name":"ExpressionList","referencingIds":["_ref_199","_ref_200","_ref_203","_ref_205","_ref_211"]},{"type":"production","id":"prod-DecoratorList","name":"DecoratorList","referencingIds":["_ref_75","_ref_88","_ref_102","_ref_105","_ref_119","_ref_126","_ref_129","_ref_132","_ref_142","_ref_145","_ref_162","_ref_170","_ref_207","_ref_299","_ref_302"]},{"type":"production","id":"prod-Decorator","name":"Decorator","referencingIds":["_ref_208"]},{"type":"production","id":"prod-DecoratorArguments","name":"DecoratorArguments","referencingIds":["_ref_210"]},{"type":"production","id":"prod-ProjectionStatement","name":"ProjectionStatement"},{"type":"production","id":"prod-ProjectionSelector","name":"ProjectionSelector","referencingIds":["_ref_212"]},{"type":"production","id":"prod-ProjectionDirection","name":"ProjectionDirection","referencingIds":["_ref_213"]},{"type":"production","id":"prod-ProjectionTag","name":"ProjectionTag","referencingIds":["_ref_214"]},{"type":"production","id":"prod-ProjectionParameters","name":"ProjectionParameters","referencingIds":["_ref_215"]},{"type":"production","id":"prod-ProjectionBody","name":"ProjectionBody","referencingIds":["_ref_216"]},{"type":"production","id":"prod-ProjectionStatementList","name":"ProjectionStatementList","referencingIds":["_ref_220","_ref_222"]},{"type":"production","id":"prod-ProjectionStatementItem","name":"ProjectionStatementItem","referencingIds":["_ref_221","_ref_223"]},{"type":"production","id":"prod-ProjectionExpression","name":"ProjectionExpression","referencingIds":["_ref_226","_ref_282","_ref_284","_ref_285","_ref_286","_ref_288","_ref_301","_ref_304","_ref_305"]},{"type":"production","id":"prod-ProjectionReturnExpression","name":"ProjectionReturnExpression","referencingIds":["_ref_224"]},{"type":"production","id":"prod-ProjectionLogicalOrExpression","name":"ProjectionLogicalOrExpression","referencingIds":["_ref_225","_ref_228"]},{"type":"production","id":"prod-ProjectionLogicalAndExpression","name":"ProjectionLogicalAndExpression","referencingIds":["_ref_227","_ref_229","_ref_231"]},{"type":"production","id":"prod-ProjectionEqualityExpression","name":"ProjectionEqualityExpression","referencingIds":["_ref_234","_ref_236"]},{"type":"production","id":"prod-ProjectionRelationalExpression","name":"ProjectionRelationalExpression","referencingIds":["_ref_230","_ref_232","_ref_233","_ref_235","_ref_237","_ref_239","_ref_241","_ref_243","_ref_245"]},{"type":"production","id":"prod-ProjectionAdditiveExpression","name":"ProjectionAdditiveExpression","referencingIds":["_ref_238","_ref_240","_ref_242","_ref_244","_ref_246","_ref_248","_ref_250"]},{"type":"production","id":"prod-ProjectionMultiplicativeExpression","name":"ProjectionMultiplicativeExpression","referencingIds":["_ref_247","_ref_249","_ref_251","_ref_253","_ref_255"]},{"type":"production","id":"prod-ProjectionUnaryExpression","name":"ProjectionUnaryExpression","referencingIds":["_ref_252","_ref_254","_ref_256","_ref_258"]},{"type":"production","id":"prod-ProjectionCallExpression","name":"ProjectionCallExpression","referencingIds":["_ref_257","_ref_260","_ref_262","_ref_264"]},{"type":"production","id":"prod-ProjectionCallArguments","name":"ProjectionCallArguments","referencingIds":["_ref_261"]},{"type":"production","id":"prod-ProjectionDecoratorReferenceExpression","name":"ProjectionDecoratorReferenceExpression","referencingIds":["_ref_259"]},{"type":"production","id":"prod-ProjectionMemberExpression","name":"ProjectionMemberExpression","referencingIds":["_ref_267","_ref_270","_ref_272"]},{"type":"production","id":"prod-ProjectionPrimaryExpression","name":"ProjectionPrimaryExpression","referencingIds":["_ref_269"]},{"type":"production","id":"prod-CoverProjectionParenthesizedExpressionAndLambdaParameterList","name":"CoverProjectionParenthesizedExpressionAndLambdaParameterList","referencingIds":["_ref_280","_ref_307"]},{"type":"production","id":"prod-ProjectionExpressionList","name":"ProjectionExpressionList","referencingIds":["_ref_266","_ref_281","_ref_283","_ref_306","_ref_309"]},{"type":"production","id":"prod-ProjectionIfExpression","name":"ProjectionIfExpression","referencingIds":["_ref_275","_ref_289"]},{"type":"production","id":"prod-ProjectionModelExpression","name":"ProjectionModelExpression","referencingIds":["_ref_278"]},{"type":"production","id":"prod-ProjectionModelBody","name":"ProjectionModelBody","referencingIds":["_ref_290"]},{"type":"production","id":"prod-ProjectionModelPropertyList","name":"ProjectionModelPropertyList","referencingIds":["_ref_291","_ref_292","_ref_294","_ref_296"]},{"type":"production","id":"prod-ProjectionModelProperty","name":"ProjectionModelProperty","referencingIds":["_ref_293","_ref_295","_ref_297"]},{"type":"production","id":"prod-ProjectionModelSpreadProperty","name":"ProjectionModelSpreadProperty","referencingIds":["_ref_298"]},{"type":"production","id":"prod-ProjectionTupleExpression","name":"ProjectionTupleExpression","referencingIds":["_ref_279"]},{"type":"production","id":"prod-ProjectionLambdaExpression","name":"ProjectionLambdaExpression","referencingIds":["_ref_276"]},{"type":"production","id":"prod-ProjectionBlockExpression","name":"ProjectionBlockExpression","referencingIds":["_ref_287","_ref_308"]},{"type":"production","id":"prod-LambdaParameters","name":"LambdaParameters"},{"type":"clause","id":"syntactic-grammar","titleHTML":"Syntactic Grammar","number":"2"}]}`); ;let usesMultipage = false