Skip to content

Commit 339678c

Browse files
committed
change inline function behavior
1 parent 1b65efb commit 339678c

File tree

1 file changed

+82
-38
lines changed

1 file changed

+82
-38
lines changed

packages/emnapi/transformer/src/macro.ts

Lines changed: 82 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ import type {
1212
FunctionDeclaration,
1313
ArrowFunction,
1414
FunctionExpression,
15-
Expression,
1615
JSDocTagInfo,
16+
ExpressionStatement,
17+
ReturnStatement,
18+
Modifier,
19+
ConciseBody,
20+
Block,
1721
Declaration
1822
} from 'typescript'
1923

@@ -104,7 +108,7 @@ class Transform {
104108
return ts.visitEachChild(node, this.constEnumVisitor, this.ctx)
105109
}
106110

107-
expandMacro (node: CallExpression, valueDeclaration: FunctionDeclaration | ArrowFunction | FunctionExpression, type: JSDocTagType): VisitResult<Node> {
111+
expandMacro (node: CallExpression, valueDeclaration: FunctionDeclaration | ArrowFunction | FunctionExpression, type: JSDocTagType, originalNode: ExpressionStatement | ReturnStatement | CallExpression): VisitResult<Node> {
108112
const factory = this.ctx.factory
109113
const checker = this.typeChecker
110114
const cloneOptions: any = {
@@ -122,17 +126,16 @@ class Transform {
122126
preserveSymbols: true
123127
}
124128

125-
const decl = cloneNode(this.visitor(valueDeclaration) as (FunctionDeclaration | ArrowFunction), cloneOptions)
129+
const decl = cloneNode(valueDeclaration, cloneOptions)
126130
const args = node.arguments.map(a =>
127-
ts.visitEachChild(
128-
ts.visitEachChild(a, this.visitor, this.ctx),
129-
this.constEnumVisitor,
130-
this.ctx
131-
)
131+
ts.visitNode(
132+
ts.visitNode(a, this.visitor),
133+
this.constEnumVisitor
134+
) as ts.Expression
132135
)
133136
const paramNames = valueDeclaration.parameters.map(p => p.name.getText())
134137
const macroBodyVisitor: Visitor = (nodeInMacro) => {
135-
const newNode = this.constEnumVisitor(nodeInMacro)
138+
const newNode = nodeInMacro
136139
let result: VisitResult<Node> = newNode
137140

138141
if ((ts.isExpressionStatement(newNode) && ts.isCallExpression(newNode.expression)) || (ts.isReturnStatement(newNode) && newNode.expression && ts.isCallExpression(newNode.expression))) {
@@ -157,46 +160,71 @@ class Transform {
157160
return ts.visitEachChild(n, replaceIdentifierVisitor, this.ctx)
158161
}
159162
const b = ts.visitEachChild(arg.body, replaceIdentifierVisitor, this.ctx)
160-
result = type === JSDocTagType.INLINE ? b : b.statements
163+
result = b.statements
161164
}
162165
}
163166
}
164-
} else if (ts.isIdentifier(newNode)) {
167+
} else if (ts.isIdentifier(newNode)/* && !ts.isParameter(newNode.parent) */) {
165168
const sym = checker.getSymbolAtLocation(newNode)?.valueDeclaration
166169
if (sym && paramNames.includes(newNode.text)) {
167170
const index = paramNames.indexOf(newNode.text)
168-
result = this.visitor(cloneNode(args[index], cloneOptions))
171+
result = cloneNode(args[index], cloneOptions)
169172
}
170173
}
171174

172-
if (!Array.isArray(result)) {
173-
result = this.visitor(result as Node)
174-
}
175-
176175
if (Array.isArray(result)) {
177176
return result.map(n => ts.visitEachChild(n, macroBodyVisitor, this.ctx))
178177
}
179178

180179
return ts.visitEachChild(result as Node, macroBodyVisitor, this.ctx)
181180
}
182181

183-
const body = decl.body!
184-
if (ts.isBlock(body!)) {
185-
const transformedBody = ts.visitEachChild(
186-
body!,
187-
macroBodyVisitor,
188-
this.ctx
189-
)
190-
return type === JSDocTagType.INLINE ? transformedBody : transformedBody.statements
182+
if (type === JSDocTagType.INLINE) {
183+
const body = decl.body!
184+
const transformedBody = ts.visitNode(ts.visitNode(body, this.visitor), this.constEnumVisitor)
185+
const f = ts.isArrowFunction(decl)
186+
? factory.updateArrowFunction(decl, decl.modifiers, decl.typeParameters, decl.parameters, decl.type, decl.equalsGreaterThanToken, transformedBody as ConciseBody)
187+
: factory.createFunctionExpression(decl.modifiers?.filter(d => d.kind !== ts.SyntaxKind.Decorator && d.kind !== ts.SyntaxKind.ExportKeyword) as (readonly Modifier[] | undefined), decl.asteriskToken, undefined, decl.typeParameters, decl.parameters, decl.type, transformedBody as Block)
188+
if (ts.isCallExpression(originalNode)) {
189+
return factory.updateCallExpression(originalNode, factory.createParenthesizedExpression(f), originalNode.typeArguments, args)
190+
}
191+
if (ts.isExpressionStatement(originalNode)) {
192+
const callExpression = originalNode.expression as CallExpression
193+
return factory.updateExpressionStatement(originalNode,
194+
factory.updateCallExpression(callExpression, factory.createParenthesizedExpression(f), callExpression.typeArguments, args))
195+
}
196+
if (ts.isReturnStatement(originalNode)) {
197+
const callExpression = originalNode.expression as CallExpression
198+
return factory.updateReturnStatement(originalNode,
199+
factory.updateCallExpression(callExpression, factory.createParenthesizedExpression(f), callExpression.typeArguments, args))
200+
}
201+
throw new Error('unreachable')
202+
} else {
203+
const body = decl.body!
204+
if (ts.isBlock(body!)) {
205+
const transformedBody = ts.visitEachChild(
206+
ts.visitEachChild(
207+
ts.visitEachChild(
208+
body!,
209+
macroBodyVisitor,
210+
this.ctx
211+
),
212+
this.visitor,
213+
this.ctx
214+
),
215+
this.constEnumVisitor,
216+
this.ctx
217+
)
218+
return transformedBody.statements
219+
}
220+
return ts.visitNode(body, macroBodyVisitor)!
191221
}
192-
193-
return ts.visitNode(body, macroBodyVisitor)!
194222
}
195223

196-
getDeclarationIfMacroCall (node: Expression): { valueDeclaration: Declaration | undefined; type: JSDocTagType } {
224+
getDeclarationIfMacroCall (node: CallExpression): { valueDeclaration: Declaration | undefined; type: JSDocTagType } {
197225
if (!this.test) {
198-
let t = JSDocTagType.INLINE
199-
if (ts.isCallExpression(node) && ((ts.isNonNullExpression(node.expression) && ts.isIdentifier(node.expression.expression)) || ts.isIdentifier(node.expression))) {
226+
let t = JSDocTagType.MACRO
227+
if (((ts.isNonNullExpression(node.expression) && ts.isIdentifier(node.expression.expression)) || ts.isIdentifier(node.expression))) {
200228
const identifier = ts.isNonNullExpression(node.expression) ? node.expression.expression : node.expression as Identifier
201229
const type = this.typeChecker.getTypeAtLocation(identifier)
202230
const sym = type.getSymbol()
@@ -213,36 +241,52 @@ class Transform {
213241
}
214242
return { valueDeclaration: undefined, type: t }
215243
} else {
216-
if (ts.isCallExpression(node) &&
217-
ts.isNonNullExpression(node.expression) &&
244+
if (ts.isNonNullExpression(node.expression) &&
218245
ts.isIdentifier(node.expression.expression) &&
219246
this.testMacroName(node.expression.expression.text)
220247
) {
221248
const type = this.typeChecker.getTypeAtLocation(node.expression.expression)
222249
const sym = type.getSymbol()
223250
if (sym) {
224-
return { valueDeclaration: sym.valueDeclaration, type: JSDocTagType.INLINE }
251+
return { valueDeclaration: sym.valueDeclaration, type: JSDocTagType.MACRO }
225252
}
226253
}
227-
return { valueDeclaration: undefined, type: JSDocTagType.INLINE }
254+
return { valueDeclaration: undefined, type: JSDocTagType.MACRO }
228255
}
229256
}
230257

231258
visitor (n: Node): VisitResult<Node> {
232259
// const factory = this.ctx.factory
233260
// const checker = this.typeChecker
234261

235-
if ((ts.isExpressionStatement(n) || ts.isReturnStatement(n)) && n.expression) {
262+
if (((ts.isFunctionDeclaration(n) && n.name) || ((ts.isArrowFunction(n) || ts.isFunctionExpression(n)) && n.parent && ts.isVariableDeclaration(n.parent) && ts.isIdentifier(n.parent.name)))) {
263+
const type = this.typeChecker.getTypeAtLocation(ts.isFunctionDeclaration(n) ? n.name! : ((n.parent as ts.VariableDeclaration).name as Identifier))
264+
const sym = type.getSymbol()
265+
const someFn = (info: JSDocTagInfo): boolean => {
266+
if (info.name === JSDocTagType.INLINE || info.name === JSDocTagType.MACRO) {
267+
return true
268+
}
269+
return false
270+
}
271+
if (sym?.getJsDocTags(this.typeChecker).reverse().some(someFn)) {
272+
return n
273+
}
274+
}
275+
276+
if ((ts.isExpressionStatement(n) || ts.isReturnStatement(n)) && n.expression && ts.isCallExpression(n.expression)) {
236277
const { valueDeclaration, type } = this.getDeclarationIfMacroCall(n.expression)
237278
if (valueDeclaration && (ts.isFunctionDeclaration(valueDeclaration) || ts.isArrowFunction(valueDeclaration) || ts.isFunctionExpression(valueDeclaration)) && valueDeclaration.body) {
238-
return this.expandMacro(n.expression as CallExpression, valueDeclaration, type)
279+
return this.expandMacro(n.expression, valueDeclaration, type, n)
239280
}
240281
}
241282

242-
if (ts.isExpression(n)) {
283+
if (ts.isCallExpression(n)) {
243284
const { valueDeclaration, type } = this.getDeclarationIfMacroCall(n)
244-
if (valueDeclaration && ts.isArrowFunction(valueDeclaration) && ts.isExpression(valueDeclaration.body)) {
245-
return this.expandMacro(n as CallExpression, valueDeclaration, type)
285+
if (valueDeclaration && (
286+
(ts.isArrowFunction(valueDeclaration) && ts.isExpression(valueDeclaration.body)) ||
287+
((ts.isFunctionDeclaration(valueDeclaration) || ts.isArrowFunction(valueDeclaration) || ts.isFunctionExpression(valueDeclaration)) && valueDeclaration.body && type === JSDocTagType.INLINE)
288+
)) {
289+
return this.expandMacro(n, valueDeclaration, type, n)
246290
}
247291
}
248292

0 commit comments

Comments
 (0)