From 4d14e95557ca8d82d0b0be6941681ea50eb71968 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 25 May 2022 06:52:44 +0300 Subject: [PATCH] Replace `OperationInstanceNode` with `OperationSignature` types --- packages/compiler/core/binder.ts | 6 +- packages/compiler/core/checker.ts | 52 ++++--------- packages/compiler/core/parser.ts | 78 ++++++++------------ packages/compiler/core/types.ts | 22 +++--- packages/compiler/formatter/print/printer.ts | 57 ++++++-------- 5 files changed, 79 insertions(+), 136 deletions(-) diff --git a/packages/compiler/core/binder.ts b/packages/compiler/core/binder.ts index 8e7efa796bd..3d127993bf6 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 f0956557827..ed3c54ea25b 100644 --- a/packages/compiler/core/checker.ts +++ b/packages/compiler/core/checker.ts @@ -51,7 +51,6 @@ import { NodeFlags, NumericLiteralNode, NumericLiteralType, - OperationInstanceNode, OperationStatementNode, OperationType, ProjectionArithmeticExpressionNode, @@ -379,8 +378,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: @@ -471,7 +468,6 @@ export function createChecker(program: Program): Checker { | AliasStatementNode | InterfaceStatementNode | OperationStatementNode - | OperationInstanceNode | UnionStatementNode ): number { return node.symbol!.id!; @@ -499,7 +495,6 @@ export function createChecker(program: Program): Checker { | ModelStatementNode | InterfaceStatementNode | OperationStatementNode - | OperationInstanceNode | UnionStatementNode | AliasStatementNode; const links = getSymbolLinks(node.symbol); @@ -688,7 +683,6 @@ export function createChecker(program: Program): Checker { | AliasStatementNode | InterfaceStatementNode | OperationStatementNode - | OperationInstanceNode | UnionStatementNode; if (decl.templateParameters.length === 0) { if (args.length > 0) { @@ -779,7 +773,6 @@ export function createChecker(program: Program): Checker { | AliasStatementNode | InterfaceStatementNode | OperationStatementNode - | OperationInstanceNode | UnionStatementNode, args: Type[] ): Type { @@ -969,7 +962,6 @@ export function createChecker(program: Program): Checker { | ModelStatementNode | NamespaceStatementNode | OperationStatementNode - | OperationInstanceNode | EnumStatementNode | InterfaceStatementNode | UnionStatementNode @@ -983,7 +975,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 || @@ -998,7 +989,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 ) { @@ -1034,7 +1025,7 @@ export function createChecker(program: Program): Checker { } function checkOperation( - node: OperationStatementNode | OperationInstanceNode, + node: OperationStatementNode, parentInterface?: InterfaceType ): OperationType | ErrorType { const links = getSymbolLinks(node.symbol); @@ -1046,44 +1037,27 @@ export function createChecker(program: Program): Checker { 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 === "Reference") { // 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); 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({ @@ -1093,7 +1067,7 @@ export function createChecker(program: Program): Checker { node, parameters, returnType, - decorators, // TODO: Concatenate base operation decorators recursively! + decorators, interface: parentInterface, }); @@ -1120,7 +1094,7 @@ export function createChecker(program: Program): Checker { } function checkOperationIs( - operation: OperationInstanceNode, + operation: OperationStatementNode, opReference: TypeReferenceNode | undefined ): OperationType | undefined { if (!opReference) return undefined; diff --git a/packages/compiler/core/parser.ts b/packages/compiler/core/parser.ts index 21f7e1f0c20..fcaaa5219c0 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,50 @@ 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(); // 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: "Declaration", parameters, returnType, - decorators, - ...finishNode(pos), }; } else { parseExpected(Token.Colon); const opReference = parseReferenceExpression(); - parseExpected(Token.Semicolon); - return { - kind: SyntaxKind.OperationInstance, - id, - templateParameters, + signature = { + kind: "Reference", baseOperation: opReference, - decorators, - ...finishNode(pos), }; } + + return { + kind: SyntaxKind.OperationStatement, + id, + templateParameters, + signature, + decorators, + ...finishNode(pos), + }; } function parseOperationParameters(): ModelExpressionNode { @@ -2178,15 +2163,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 === "Declaration" + ? 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 025af49dcbc..164d9bc2ae3 100644 --- a/packages/compiler/core/types.ts +++ b/packages/compiler/core/types.ts @@ -206,7 +206,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; @@ -388,7 +388,6 @@ export enum SyntaxKind { NamespaceStatement, UsingStatement, OperationStatement, - OperationInstance, ModelStatement, ModelExpression, ModelProperty, @@ -502,7 +501,6 @@ export type Node = | ModelPropertyNode | UnionVariantNode | OperationStatementNode - | OperationInstanceNode | EnumMemberNode | ModelSpreadPropertyNode | DecoratorExpressionNode @@ -553,7 +551,6 @@ export type Statement = | EnumStatementNode | AliasStatementNode | OperationStatementNode - | OperationInstanceNode | EmptyStatementNode | InvalidStatementNode | ProjectionStatementNode; @@ -568,7 +565,6 @@ export type Declaration = | UnionStatementNode | NamespaceStatementNode | OperationStatementNode - | OperationInstanceNode | TemplateParameterDeclarationNode | ProjectionStatementNode | ProjectionParameterDeclarationNode @@ -672,16 +668,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: "Declaration"; 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: "Reference"; 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 04c8d354681..304288cd4ce 100644 --- a/packages/compiler/formatter/print/printer.ts +++ b/packages/compiler/formatter/print/printer.ts @@ -23,7 +23,6 @@ import { Node, NodeFlags, NumericLiteralNode, - OperationInstanceNode, OperationStatementNode, Statement, StringLiteralNode, @@ -86,8 +85,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: @@ -817,7 +814,9 @@ function isModelExpressionInBlock(path: AstPath) { switch (parent?.kind) { case SyntaxKind.OperationStatement: - return parent.parameters !== path.getNode(); + return ( + parent.signature.kind === "Declaration" && parent.signature.parameters !== path.getNode() + ); default: return true; } @@ -866,35 +865,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 === "Declaration") { + return [ + decorators, + inInterface ? "" : "op ", + path.call(print, "id"), + "(", + path.call(print, "parameters"), + "): ", + path.call(print, "returnType"), + `;`, + ]; + } else { + return [ + decorators, + inInterface ? "" : "op ", + path.call(print, "id"), + path.call(print, "baseOperation"), + `;`, + ]; + } } export function printStatementSequence(