idlize
102 строки · 3.6 Кб
1/*
2* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16import * as ts from 'typescript';
17import { ScopedVisitor } from './ScopedVisitor';
18import {
19FunctionKind,
20Tracer,
21parameterStateName as localStateName,
22PositionalIdTracker,
23runtimeIdentifier,
24RuntimeNames,
25isMemoKind,
26getSymbolByNode,
27getDeclarationsByNode,
28isStableClass,
29} from "./util"
30
31export class ThisTransformer extends ScopedVisitor<boolean> {
32constructor(
33public tracer: Tracer,
34public typechecker: ts.TypeChecker,
35public sourceFile: ts.SourceFile,
36public positionalIdTracker: PositionalIdTracker,
37public functionTable: Map<ts.SignatureDeclarationBase, FunctionKind>,
38ctx: ts.TransformationContext
39) {
40super(functionTable, ctx)
41}
42
43transformThisUse(node: ts.ThisExpression): ts.PropertyAccessExpression {
44const newName = localStateName("this")
45return ts.factory.createPropertyAccessExpression(
46ts.factory.createIdentifier(newName),
47runtimeIdentifier(RuntimeNames.VALUE)
48)
49}
50
51override withFunctionScope<T>(kind: FunctionKind, isInMemoMethod: boolean, body: ()=>T): T {
52let result: T
53this.functionScopes.push(kind, isInMemoMethod)
54result = body()
55this.functionScopes.pop()
56return result
57}
58
59isThisExpression(node: ts.Node): node is ts.ThisExpression {
60return node.kind == ts.SyntaxKind.ThisKeyword
61}
62
63isInMemoMethod(): boolean {
64return this.functionScopes.peek()?.data ?? false
65}
66
67isStableClass(node: ts.ThisExpression): boolean {
68const declarations = getDeclarationsByNode(this.typechecker, node)
69const firstDeclaration = declarations[0]
70if (!firstDeclaration) return false
71if (!ts.isClassDeclaration(firstDeclaration)) return false
72return isStableClass(this.sourceFile, firstDeclaration)
73}
74
75visitor(node: ts.Node): ts.Node {
76if (ts.isArrowFunction(node)) {
77return this.withFunctionScope(this.currentKind(), this.isInMemoMethod(), () => {
78return this.visitEachChild(node)
79})
80} else if (ts.isFunctionDeclaration(node)) {
81return this.withFunctionScope(this.currentKind(), false, () => {
82return this.visitEachChild(node)
83})
84} else if (ts.isMethodDeclaration(node)) {
85const kind = this.declarationKind(node)
86const isInMemoMethod = this.isInMemoMethod() || isMemoKind(kind)
87const transformedWithChildren = this.withFunctionScope(kind, isInMemoMethod, ()=>{
88return this.visitEachChild(node)
89})
90return transformedWithChildren
91
92} else if (this.isThisExpression(node)) {
93if (!this.isStableClass(node) && this.isInMemoMethod()) {
94const transformed = node.parent ?
95this.transformThisUse(node) :
96node
97return this.visitEachChild(transformed)
98}
99}
100return this.visitEachChild(node)
101}
102}
103