1/* 2 * Copyright (c) 2022-2025 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 { global } from './static/global'; 17import { factory } from './factory/nodeFactory'; 18import { 19 Es2pandaClassDefinitionModifiers, 20 Es2pandaImportKinds, 21 Es2pandaModifierFlags, 22 Es2pandaVariableDeclaratorFlag, 23} from '../generated/Es2pandaEnums'; 24import { AstNode } from './peers/AstNode'; 25import { 26 isBlockStatement, 27 isConditionalExpression, 28 isTSInterfaceBody, 29 isTSInterfaceDeclaration, 30 isClassDeclaration, 31 isClassDefinition, 32 isTSAsExpression, 33 isETSImportDeclaration, 34 ImportSource, 35 isScriptFunction, 36 FunctionSignature, 37 Property, 38 isClassProperty, 39 isImportDeclaration, 40 isObjectExpression, 41 ObjectExpression, 42 isProperty, 43 Expression, 44 isETSNewClassInstanceExpression, 45 isTemplateLiteral, 46 isBlockExpression, 47 isReturnStatement, 48 isArrayExpression, 49 isTryStatement, 50 isBinaryExpression, 51 isForInStatement, 52 isForUpdateStatement, 53 isForOfStatement, 54 isTSTypeAliasDeclaration, 55 isETSFunctionType, 56} from '../generated'; 57import { 58 isEtsScript, 59 isCallExpression, 60 isFunctionDeclaration, 61 isExpressionStatement, 62 isStructDeclaration, 63 isMethodDefinition, 64 // isScriptFunction, 65 isMemberExpression, 66 isIfStatement, 67 isVariableDeclaration, 68 isVariableDeclarator, 69 isArrowFunctionExpression, 70 isAssignmentExpression, 71 isEtsParameterExpression, 72} from './factory/nodeTests'; 73import { classDefinitionFlags } from './utilities/public'; 74import { Es2pandaAstNodeType } from '../Es2pandaEnums'; 75 76type Visitor = (node: AstNode) => AstNode; 77 78export interface StructVariableMetadata { 79 name: string; 80 properties: string[]; 81 modifiers: Es2pandaModifierFlags; 82 hasStateManagementType?: boolean; 83} 84 85export class StructInfo { 86 metadata: Record<string, StructVariableMetadata> = {}; 87 initializeBody: AstNode[] = []; 88 updateBody: AstNode[] = []; 89 isReusable: boolean = false; 90 toRecordBody: Property[] = []; 91} 92 93export class GlobalInfo { 94 private _structCollection: Set<string>; 95 private static instance: GlobalInfo; 96 private _structMap: Map<string, StructInfo>; 97 98 private constructor() { 99 this._structCollection = new Set(); 100 this._structMap = new Map(); 101 } 102 103 public static getInfoInstance(): GlobalInfo { 104 if (!this.instance) { 105 this.instance = new GlobalInfo(); 106 } 107 return this.instance; 108 } 109 110 public add(str: string): void { 111 this._structCollection.add(str); 112 } 113 114 public getStructCollection(): Set<string> { 115 return this._structCollection; 116 } 117 118 public getStructInfo(structName: string): StructInfo { 119 const structInfo = this._structMap.get(structName); 120 if (!structInfo) { 121 return new StructInfo(); 122 } 123 return structInfo; 124 } 125 126 public setStructInfo(structName: string, info: StructInfo): void { 127 this._structMap.set(structName, info); 128 } 129 130 public reset(): void { 131 this._structMap.clear(); 132 this._structCollection.clear(); 133 } 134} 135 136// TODO: rethink (remove as) 137function nodeVisitor<T extends AstNode | undefined>(node: T, visitor: Visitor): T { 138 if (node === undefined) { 139 return node; 140 } 141 return visitor(node) as T; 142} 143 144// TODO: rethink (remove as) 145function nodesVisitor<T extends AstNode, TIn extends readonly T[] | undefined>( 146 nodes: TIn, 147 visitor: Visitor 148): T[] | TIn { 149 if (nodes === undefined) { 150 return nodes; 151 } 152 return nodes.map((node) => visitor(node) as T); 153} 154 155let updated: boolean = false; 156 157export function visitEachChild(node: AstNode, visitor: Visitor): AstNode { 158 updated = false; 159 let script: AstNode = node; 160 script = visitETSModule(script, visitor); 161 script = visitDeclaration(script, visitor); 162 script = visitDefinition(script, visitor); 163 script = visitDefinitionBody(script, visitor); 164 script = visitStatement(script, visitor); 165 script = visitForLoopStatement(script, visitor); 166 script = visitOuterExpression(script, visitor); 167 script = visitInnerExpression(script, visitor); 168 script = visitTrivialExpression(script, visitor); 169 script = visitLiteral(script, visitor); 170 // TODO 171 return visitWithoutUpdate(script, visitor); 172} 173 174function visitOuterExpression(node: AstNode, visitor: Visitor): AstNode { 175 if (updated) { 176 return node; 177 } else if (isBlockExpression(node)) { 178 updated = true; 179 return factory.updateBlockExpression(node, nodesVisitor(node.statements, visitor)); 180 } else if (isCallExpression(node)) { 181 updated = true; 182 const call = factory.updateCallExpression( 183 node, 184 nodeVisitor(node.expression, visitor), 185 nodesVisitor(node.typeArguments, visitor), 186 nodesVisitor(node.arguments, visitor) 187 ); 188 if (!!node.trailingBlock) { 189 call.setTralingBlock(nodeVisitor(node.trailingBlock, visitor)); 190 } 191 return call; 192 } else if (isArrowFunctionExpression(node)) { 193 updated = true; 194 return factory.updateArrowFunction(node, nodeVisitor(node.scriptFunction, visitor)); 195 } else if (isAssignmentExpression(node)) { 196 updated = true; 197 return factory.updateAssignmentExpression( 198 node, 199 nodeVisitor(node.left as Expression, visitor), 200 node.operatorType, 201 nodeVisitor(node.right as Expression, visitor) 202 ); 203 } else if (isETSNewClassInstanceExpression(node)) { 204 updated = true; 205 return factory.updateETSNewClassInstanceExpression( 206 node, 207 node.getTypeRef, 208 nodesVisitor(node.getArguments, visitor) 209 ); 210 } 211 if (isArrayExpression(node)) { 212 updated = true; 213 return factory.updateArrayExpression(node, nodesVisitor(node.elements, visitor)); 214 } 215 return node; 216} 217 218function visitInnerExpression(node: AstNode, visitor: Visitor): AstNode { 219 if (updated) { 220 return node; 221 } 222 if (isMemberExpression(node)) { 223 updated = true; 224 return factory.updateMemberExpression( 225 node, 226 nodeVisitor(node.object, visitor), 227 nodeVisitor(node.property, visitor), 228 node.kind, 229 node.computed, 230 node.optional 231 ); 232 } 233 if (isConditionalExpression(node)) { 234 updated = true; 235 return factory.updateConditionalExpression( 236 node, 237 nodeVisitor(node.test, visitor), 238 nodeVisitor(node.consequent, visitor), 239 nodeVisitor(node.alternate, visitor) 240 ); 241 } 242 if (isTSAsExpression(node)) { 243 updated = true; 244 return factory.updateTSAsExpression( 245 node, 246 nodeVisitor(node.expr, visitor), 247 nodeVisitor(node.typeAnnotation, visitor), 248 node.isConst 249 ); 250 } 251 if (isObjectExpression(node)) { 252 updated = true; 253 return factory.updateObjectExpression( 254 node, 255 Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, 256 nodesVisitor(node.properties as Property[], visitor), 257 false 258 ); 259 } 260 if (isProperty(node)) { 261 updated = true; 262 return factory.updateProperty(node, node.key, nodeVisitor(node.value, visitor)); 263 } 264 // TODO 265 return node; 266} 267 268function visitTrivialExpression(node: AstNode, visitor: Visitor): AstNode { 269 if (updated) { 270 return node; 271 } 272 if (isBinaryExpression(node)) { 273 updated = true; 274 return factory.updateBinaryExpression( 275 node, 276 nodeVisitor(node.left, visitor), 277 nodeVisitor(node.right, visitor), 278 node.operatorType 279 ); 280 } 281 // TODO 282 return node; 283} 284 285function visitDeclaration(node: AstNode, visitor: Visitor): AstNode { 286 if (updated) { 287 return node; 288 } else if (isFunctionDeclaration(node)) { 289 updated = true; 290 return factory.updateFunctionDeclaration( 291 node, 292 nodeVisitor(node.scriptFunction, visitor), 293 node.isAnon, 294 node.annotations 295 ); 296 } else if (isClassDeclaration(node)) { 297 updated = true; 298 return factory.updateClassDeclaration(node, nodeVisitor(node.definition, visitor)); 299 } else if (isStructDeclaration(node)) { 300 updated = true; 301 return factory.updateStructDeclaration(node, nodeVisitor(node.definition, visitor)); 302 } else if (isTSInterfaceDeclaration(node)) { 303 updated = true; 304 return factory.updateInterfaceDeclaration( 305 node, 306 nodesVisitor(node.extends, visitor), 307 nodeVisitor(node.id, visitor), 308 nodeVisitor(node.typeParams, visitor), 309 nodeVisitor(node.body, visitor), 310 node.isStatic, 311 // TODO: how do I get it? 312 true 313 ); 314 } else if (isVariableDeclaration(node)) { 315 updated = true; 316 return factory.updateVariableDeclaration( 317 node, 318 0, 319 node.declarationKind, 320 nodesVisitor(node.declarators, visitor) 321 ); 322 } else if (isTSTypeAliasDeclaration(node)) { 323 updated = true; 324 return factory.updateTSTypeAliasDeclaration( 325 node, 326 node.id, 327 nodeVisitor(node.typeParams, visitor), 328 nodeVisitor(node.typeAnnotation, visitor) 329 ); 330 } 331 // TODO 332 return node; 333} 334 335function visitDefinition(node: AstNode, visitor: Visitor): AstNode { 336 if (updated) { 337 return node; 338 } 339 if (isClassDefinition(node)) { 340 updated = true; 341 return factory.updateClassDefinition( 342 node, 343 node.ident, 344 node.typeParams, 345 node.superTypeParams, 346 node.implements, 347 undefined, 348 node.super, 349 nodesVisitor(node.body, visitor), 350 node.modifiers, 351 classDefinitionFlags(node) 352 ); 353 } 354 if (isMethodDefinition(node)) { 355 updated = true; 356 return factory.updateMethodDefinition( 357 node, 358 node.kind, 359 node.name, 360 nodeVisitor(node.scriptFunction, visitor), 361 node.modifiers, 362 false 363 ); 364 } 365 if (isTSInterfaceBody(node)) { 366 updated = true; 367 return factory.updateInterfaceBody(node, nodesVisitor(node.body, visitor)); 368 } 369 if (isVariableDeclarator(node)) { 370 updated = true; 371 return factory.updateVariableDeclarator( 372 node, 373 global.generatedEs2panda._VariableDeclaratorFlag(global.context, node.peer), 374 nodeVisitor(node.name, visitor), 375 nodeVisitor(node.initializer, visitor) 376 ); 377 } 378 return node; 379} 380 381function visitStatement(node: AstNode, visitor: Visitor): AstNode { 382 if (updated) { 383 return node; 384 } 385 if (isBlockStatement(node)) { 386 updated = true; 387 return factory.updateBlock(node, nodesVisitor(node.statements, visitor)); 388 } 389 if (isExpressionStatement(node)) { 390 updated = true; 391 return factory.updateExpressionStatement(node, nodeVisitor(node.expression, visitor)); 392 } 393 if (isIfStatement(node)) { 394 updated = true; 395 return factory.updateIfStatement( 396 node, 397 nodeVisitor(node.test, visitor), 398 nodeVisitor(node.consequent, visitor), 399 nodeVisitor(node.alternate, visitor) 400 ); 401 } 402 if (isReturnStatement(node)) { 403 updated = true; 404 return factory.updateReturnStatement(node, nodeVisitor(node.argument, visitor)); 405 } 406 if (isTryStatement(node)) { 407 updated = true; 408 return factory.updateTryStatement( 409 node, 410 nodeVisitor(node.block, visitor), 411 nodesVisitor(node.catchClauses, visitor), 412 nodeVisitor(node.finallyBlock, visitor), 413 [], 414 [] 415 ); 416 } 417 // TODO 418 return node; 419} 420 421function visitForLoopStatement(node: AstNode, visitor: Visitor): AstNode { 422 if (updated) { 423 return node; 424 } 425 if (isForUpdateStatement(node)) { 426 updated = true; 427 return factory.updateForUpdateStatement( 428 node, 429 nodeVisitor(node.init, visitor), 430 nodeVisitor(node.test, visitor), 431 nodeVisitor(node.update, visitor), 432 nodeVisitor(node.body, visitor) 433 ); 434 } 435 if (isForInStatement(node)) { 436 updated = true; 437 return factory.updateForInStatement( 438 node, 439 nodeVisitor(node.left, visitor), 440 nodeVisitor(node.right, visitor), 441 nodeVisitor(node.body, visitor) 442 ); 443 } 444 if (isForOfStatement(node)) { 445 updated = true; 446 return factory.updateForOfStatement( 447 node, 448 nodeVisitor(node.left, visitor), 449 nodeVisitor(node.right, visitor), 450 nodeVisitor(node.body, visitor), 451 node.isAwait 452 ); 453 } 454 return node; 455} 456 457function visitETSModule(node: AstNode, visitor: Visitor): AstNode { 458 if (updated) { 459 return node; 460 } 461 if (isEtsScript(node)) { 462 updated = true; 463 return factory.updateEtsScript(node, nodesVisitor(node.statements, visitor)); 464 } 465 return node; 466} 467 468function visitDefinitionBody(node: AstNode, visitor: Visitor): AstNode { 469 if (updated) { 470 return node; 471 } 472 if (isScriptFunction(node)) { 473 updated = true; 474 return factory.updateScriptFunction( 475 node, 476 nodeVisitor(node.body, visitor), 477 factory.createFunctionSignature( 478 nodeVisitor(node.typeParams, visitor), 479 nodesVisitor(node.params, visitor), 480 nodeVisitor(node.returnTypeAnnotation, visitor), 481 node.hasReceiver 482 ), 483 node.flags, 484 node.modifiers 485 ); 486 } 487 if (isClassProperty(node)) { 488 updated = true; 489 return factory.updateClassProperty( 490 node, 491 node.key, 492 nodeVisitor(node.value, visitor), 493 node.typeAnnotation, 494 node.modifiers, 495 node.isComputed 496 ); 497 } 498 // TODO 499 return node; 500} 501 502function visitLiteral(node: AstNode, visitor: Visitor): AstNode { 503 if (updated) { 504 return node; 505 } 506 if (isTemplateLiteral(node)) { 507 updated = true; 508 return factory.updateTemplateLiteral( 509 node, 510 nodesVisitor(node.quasis, visitor), 511 nodesVisitor(node.expressions, visitor), 512 node.multilineString 513 ); 514 } 515 return node; 516} 517 518// TODO: apply this to all nodes that does not require updating 519function visitWithoutUpdate<T extends AstNode>(node: T, visitor: Visitor): T { 520 if (updated) { 521 return node; 522 } 523 if (isImportDeclaration(node)) { 524 nodesVisitor(node.specifiers, visitor); 525 } 526 if (isETSFunctionType(node)) { 527 nodesVisitor(node.params, visitor); 528 } 529 if (isEtsParameterExpression(node)) { 530 nodeVisitor(node.type, visitor); 531 } 532 return node; 533} 534